p2p/enode: use unix timestamp as base ENR sequence number (#19903)
This PR ensures that wiping all data associated with a node (apart from its nodekey) will not generate already used sequence number for the ENRs, since all remote nodes would reject them until they out-number the previously published largest one. The big complication with this scheme is that every local update to the ENR can potentially bump the sequence number by one. In order to ensure that local updates do not outrun the clock, the sequence number is a millisecond-precision timestamp, and updates are throttled to occur at most once per millisecond. Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
@ -49,32 +49,39 @@ func TestLocalNode(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// This test checks that the sequence number is persisted between restarts.
|
||||
func TestLocalNodeSeqPersist(t *testing.T) {
|
||||
timestamp := nowMilliseconds()
|
||||
|
||||
ln, db := newLocalNodeForTesting()
|
||||
defer db.Close()
|
||||
|
||||
if s := ln.Node().Seq(); s != 1 {
|
||||
t.Fatalf("wrong initial seq %d, want 1", s)
|
||||
initialSeq := ln.Node().Seq()
|
||||
if initialSeq < timestamp {
|
||||
t.Fatalf("wrong initial seq %d, want at least %d", initialSeq, timestamp)
|
||||
}
|
||||
|
||||
ln.Set(enr.WithEntry("x", uint(1)))
|
||||
if s := ln.Node().Seq(); s != 2 {
|
||||
t.Fatalf("wrong seq %d after set, want 2", s)
|
||||
if s := ln.Node().Seq(); s != initialSeq+1 {
|
||||
t.Fatalf("wrong seq %d after set, want %d", s, initialSeq+1)
|
||||
}
|
||||
|
||||
// Create a new instance, it should reload the sequence number.
|
||||
// The number increases just after that because a new record is
|
||||
// created without the "x" entry.
|
||||
ln2 := NewLocalNode(db, ln.key)
|
||||
if s := ln2.Node().Seq(); s != 3 {
|
||||
t.Fatalf("wrong seq %d on new instance, want 3", s)
|
||||
if s := ln2.Node().Seq(); s != initialSeq+2 {
|
||||
t.Fatalf("wrong seq %d on new instance, want %d", s, initialSeq+2)
|
||||
}
|
||||
|
||||
finalSeq := ln2.Node().Seq()
|
||||
|
||||
// Create a new instance with a different node key on the same database.
|
||||
// This should reset the sequence number.
|
||||
key, _ := crypto.GenerateKey()
|
||||
ln3 := NewLocalNode(db, key)
|
||||
if s := ln3.Node().Seq(); s != 1 {
|
||||
t.Fatalf("wrong seq %d on instance with changed key, want 1", s)
|
||||
if s := ln3.Node().Seq(); s < finalSeq {
|
||||
t.Fatalf("wrong seq %d on instance with changed key, want >= %d", s, finalSeq)
|
||||
}
|
||||
}
|
||||
|
||||
@ -91,20 +98,20 @@ func TestLocalNodeEndpoint(t *testing.T) {
|
||||
// Nothing is set initially.
|
||||
assert.Equal(t, net.IP(nil), ln.Node().IP())
|
||||
assert.Equal(t, 0, ln.Node().UDP())
|
||||
assert.Equal(t, uint64(1), ln.Node().Seq())
|
||||
initialSeq := ln.Node().Seq()
|
||||
|
||||
// Set up fallback address.
|
||||
ln.SetFallbackIP(fallback.IP)
|
||||
ln.SetFallbackUDP(fallback.Port)
|
||||
assert.Equal(t, fallback.IP, ln.Node().IP())
|
||||
assert.Equal(t, fallback.Port, ln.Node().UDP())
|
||||
assert.Equal(t, uint64(2), ln.Node().Seq())
|
||||
assert.Equal(t, initialSeq+1, ln.Node().Seq())
|
||||
|
||||
// Add endpoint statements from random hosts.
|
||||
for i := 0; i < iptrackMinStatements; i++ {
|
||||
assert.Equal(t, fallback.IP, ln.Node().IP())
|
||||
assert.Equal(t, fallback.Port, ln.Node().UDP())
|
||||
assert.Equal(t, uint64(2), ln.Node().Seq())
|
||||
assert.Equal(t, initialSeq+1, ln.Node().Seq())
|
||||
|
||||
from := &net.UDPAddr{IP: make(net.IP, 4), Port: 90}
|
||||
rand.Read(from.IP)
|
||||
@ -112,11 +119,11 @@ func TestLocalNodeEndpoint(t *testing.T) {
|
||||
}
|
||||
assert.Equal(t, predicted.IP, ln.Node().IP())
|
||||
assert.Equal(t, predicted.Port, ln.Node().UDP())
|
||||
assert.Equal(t, uint64(3), ln.Node().Seq())
|
||||
assert.Equal(t, initialSeq+2, ln.Node().Seq())
|
||||
|
||||
// Static IP overrides prediction.
|
||||
ln.SetStaticIP(staticIP)
|
||||
assert.Equal(t, staticIP, ln.Node().IP())
|
||||
assert.Equal(t, fallback.Port, ln.Node().UDP())
|
||||
assert.Equal(t, uint64(4), ln.Node().Seq())
|
||||
assert.Equal(t, initialSeq+3, ln.Node().Seq())
|
||||
}
|
||||
|
Reference in New Issue
Block a user