@@ -39,7 +39,6 @@ type tableRevalidation struct {
3939type revalidationResponse struct {
4040 n * node
4141 newRecord * enode.Node
42- list * revalidationList
4342 didRespond bool
4443}
4544
@@ -60,34 +59,35 @@ func (tr *tableRevalidation) nodeAdded(tab *Table, n *node) {
6059
6160// nodeRemoved is called when a node was removed from the table.
6261func (tr * tableRevalidation ) nodeRemoved (n * node ) {
63- if ! tr . fast . remove ( n ) {
64- tr . slow . remove ( n )
62+ if n . revalList == nil {
63+ panic ( fmt . Errorf ( "removed node %v has nil revalList" , n . ID ()) )
6564 }
65+ n .revalList .remove (n )
6666}
6767
6868// run performs node revalidation.
6969// It returns the next time it should be invoked, which is used in the Table main loop
7070// to schedule a timer. However, run can be called at any time.
7171func (tr * tableRevalidation ) run (tab * Table , now mclock.AbsTime ) (nextTime mclock.AbsTime ) {
7272 if n := tr .fast .get (now , & tab .rand , tr .activeReq ); n != nil {
73- tr .startRequest (tab , & tr . fast , n )
73+ tr .startRequest (tab , n )
7474 tr .fast .schedule (now , & tab .rand )
7575 }
7676 if n := tr .slow .get (now , & tab .rand , tr .activeReq ); n != nil {
77- tr .startRequest (tab , & tr . slow , n )
77+ tr .startRequest (tab , n )
7878 tr .slow .schedule (now , & tab .rand )
7979 }
8080
8181 return min (tr .fast .nextTime , tr .slow .nextTime )
8282}
8383
8484// startRequest spawns a revalidation request for node n.
85- func (tr * tableRevalidation ) startRequest (tab * Table , list * revalidationList , n * node ) {
85+ func (tr * tableRevalidation ) startRequest (tab * Table , n * node ) {
8686 if _ , ok := tr .activeReq [n .ID ()]; ok {
87- panic (fmt .Errorf ("duplicate startRequest (list %q, node %v)" , list . name , n .ID ()))
87+ panic (fmt .Errorf ("duplicate startRequest (node %v)" , n .ID ()))
8888 }
8989 tr .activeReq [n .ID ()] = struct {}{}
90- resp := revalidationResponse {n : n , list : list }
90+ resp := revalidationResponse {n : n }
9191
9292 // Fetch the node while holding lock.
9393 tab .mutex .Lock ()
@@ -120,11 +120,28 @@ func (tab *Table) doRevalidate(resp revalidationResponse, node *enode.Node) {
120120
121121// handleResponse processes the result of a revalidation request.
122122func (tr * tableRevalidation ) handleResponse (tab * Table , resp revalidationResponse ) {
123- now := tab .cfg .Clock .Now ()
124- n := resp .n
125- b := tab .bucket (n .ID ())
123+ var (
124+ now = tab .cfg .Clock .Now ()
125+ n = resp .n
126+ b = tab .bucket (n .ID ())
127+ )
126128 delete (tr .activeReq , n .ID ())
127129
130+ // If the node was removed from the table while getting checked, we need to stop
131+ // processing here to avoid re-adding it.
132+ if n .revalList == nil {
133+ return
134+ }
135+
136+ // Store potential seeds in database.
137+ // This is done via defer to avoid holding Table lock while writing to DB.
138+ defer func () {
139+ if n .isValidatedLive && n .livenessChecks > 5 {
140+ tab .db .UpdateNode (resp .n .Node )
141+ }
142+ }()
143+
144+ // Remaining logic needs access to Table internals.
128145 tab .mutex .Lock ()
129146 defer tab .mutex .Unlock ()
130147
@@ -134,7 +151,7 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons
134151 if n .livenessChecks <= 0 {
135152 tab .deleteInBucket (b , n .ID ())
136153 } else {
137- tr .moveToList (& tr .fast , resp . list , n , now , & tab .rand )
154+ tr .moveToList (& tr .fast , n , now , & tab .rand )
138155 }
139156 return
140157 }
@@ -151,27 +168,23 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons
151168 n .isValidatedLive = false
152169 }
153170 }
154- tab .log .Debug ("Revalidated node" , "b" , b .index , "id" , n .ID (), "checks" , n .livenessChecks , "q" , resp . list . name )
171+ tab .log .Debug ("Revalidated node" , "b" , b .index , "id" , n .ID (), "checks" , n .livenessChecks , "q" , n . revalList )
155172
156173 // Move node over to slow queue after first validation.
157174 if ! endpointChanged {
158- tr .moveToList (& tr .slow , resp . list , n , now , & tab .rand )
175+ tr .moveToList (& tr .slow , n , now , & tab .rand )
159176 } else {
160- tr .moveToList (& tr .fast , resp .list , n , now , & tab .rand )
161- }
162-
163- // Store potential seeds in database.
164- if n .isValidatedLive && n .livenessChecks > 5 {
165- tab .db .UpdateNode (resp .n .Node )
177+ tr .moveToList (& tr .fast , n , now , & tab .rand )
166178 }
167179}
168180
169- func (tr * tableRevalidation ) moveToList (dest , source * revalidationList , n * node , now mclock.AbsTime , rand randomSource ) {
170- if source == dest {
181+ // moveToList ensures n is in the 'dest' list.
182+ func (tr * tableRevalidation ) moveToList (dest * revalidationList , n * node , now mclock.AbsTime , rand randomSource ) {
183+ if n .revalList == dest {
171184 return
172185 }
173- if ! source . remove ( n ) {
174- panic ( fmt . Errorf ( "moveToList(%q -> %q): node %v not in source list" , source . name , dest . name , n . ID ()) )
186+ if n . revalList != nil {
187+ n . revalList . remove ( n )
175188 }
176189 dest .push (n , now , rand )
177190}
@@ -208,16 +221,23 @@ func (list *revalidationList) push(n *node, now mclock.AbsTime, rand randomSourc
208221 if list .nextTime == never {
209222 list .schedule (now , rand )
210223 }
224+ n .revalList = list
211225}
212226
213- func (list * revalidationList ) remove (n * node ) bool {
227+ func (list * revalidationList ) remove (n * node ) {
214228 i := slices .Index (list .nodes , n )
215229 if i == - 1 {
216- return false
230+ panic ( fmt . Errorf ( "node %v not found in list" , n . ID ()))
217231 }
218232 list .nodes = slices .Delete (list .nodes , i , i + 1 )
219233 if len (list .nodes ) == 0 {
220234 list .nextTime = never
221235 }
222- return true
236+ n .revalList = nil
237+ }
238+
239+ func (list * revalidationList ) contains (id enode.ID ) bool {
240+ return slices .ContainsFunc (list .nodes , func (n * node ) bool {
241+ return n .ID () == id
242+ })
223243}
0 commit comments