diff --git a/p2p/discover/table.go b/p2p/discover/table.go index b119f855dc..289f591217 100644 --- a/p2p/discover/table.go +++ b/p2p/discover/table.go @@ -513,12 +513,9 @@ func (tab *Table) handleAddNode(req addNodeOp) bool { } b := tab.bucket(req.node.ID()) - n, wasUpdated := tab.bumpInBucket(b, req.node.Node, req.isInbound) + n, _ := tab.bumpInBucket(b, req.node.Node, req.isInbound) if n != nil { // Already in bucket. - if wasUpdated { - n.isValidatedLive = false - } return false } if len(b.entries) >= bucketSize { @@ -627,7 +624,9 @@ func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) } // Check if there is an endpoint update and validate against IP limits. - if newRecord.IPAddr() != b.entries[i].IPAddr() { + ipchanged := newRecord.IPAddr() != n.IPAddr() + portchanged := newRecord.UDP() != n.UDP() + if ipchanged { tab.removeIP(b, n.IP()) if !tab.addIP(b, newRecord.IP()) { // It doesn't fit with the limit, put the previous record back. @@ -636,8 +635,15 @@ func (tab *Table) bumpInBucket(b *bucket, newRecord *enode.Node, isInbound bool) } } + // Apply update. n.Node = newRecord - return n, true + + // Endpoint changes cause the node to be considered unverified. + if ipchanged || portchanged { + tab.revalidation.nodeEndpointChanged(tab, n) + return n, true + } + return n, false } func (tab *Table) handleTrackRequest(op trackRequestOp) { diff --git a/p2p/discover/table_reval.go b/p2p/discover/table_reval.go index c5160131f9..d02733f492 100644 --- a/p2p/discover/table_reval.go +++ b/p2p/discover/table_reval.go @@ -65,6 +65,12 @@ func (tr *tableRevalidation) nodeRemoved(n *node) { n.revalList.remove(n) } +// nodeEndpointChanged is called when a change in IP or port is detected. +func (tr *tableRevalidation) nodeEndpointChanged(tab *Table, n *node) { + n.isValidatedLive = false + tr.moveToList(&tr.fast, n, tab.cfg.Clock.Now(), &tab.rand) +} + // run performs node revalidation. // It returns the next time it should be invoked, which is used in the Table main loop // to schedule a timer. However, run can be called at any time. @@ -146,11 +152,11 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons defer tab.mutex.Unlock() if !resp.didRespond { - // Revalidation failed. n.livenessChecks /= 3 if n.livenessChecks <= 0 { tab.deleteInBucket(b, n.ID()) } else { + tab.log.Debug("Node revalidation failed", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList.name) tr.moveToList(&tr.fast, n, now, &tab.rand) } return @@ -159,22 +165,15 @@ func (tr *tableRevalidation) handleResponse(tab *Table, resp revalidationRespons // The node responded. n.livenessChecks++ n.isValidatedLive = true + tab.log.Debug("Node revalidated", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList.name) var endpointChanged bool if resp.newRecord != nil { _, endpointChanged = tab.bumpInBucket(b, resp.newRecord, false) - if endpointChanged { - // If the node changed its advertised endpoint, the updated ENR is not served - // until it has been revalidated. - n.isValidatedLive = false - } } - tab.log.Debug("Revalidated node", "b", b.index, "id", n.ID(), "checks", n.livenessChecks, "q", n.revalList) - - // Move node over to slow queue after first validation. + + // Node moves to slow list if it passed and hasn't changed. if !endpointChanged { tr.moveToList(&tr.slow, n, now, &tab.rand) - } else { - tr.moveToList(&tr.fast, n, now, &tab.rand) } }