Skip to content

Commit c73b654

Browse files
fjlkaralabe
authored andcommitted
p2p/discover: move bond logic from table to transport (#17048)
* p2p/discover: move bond logic from table to transport This commit moves node endpoint verification (bonding) from the table to the UDP transport implementation. Previously, adding a node to the table entailed pinging the node if needed. With this change, the ping-back logic is embedded in the packet handler at a lower level. It is easy to verify that the basic protocol is unchanged: we still require a valid pong reply from the node before findnode is accepted. The node database tracked the time of last ping sent to the node and time of last valid pong received from the node. Node endpoints are considered verified when a valid pong is received and the time of last pong was called 'bond time'. The time of last ping sent was unused. In this commit, the last ping database entry is repurposed to mean last ping _received_. This entry is now used to track whether the node needs to be pinged back. The other big change is how nodes are added to the table. We used to add nodes in Table.bond, which ran when a remote node pinged us or when we encountered the node in a neighbors reply. The transport now adds to the table directly after the endpoint is verified through ping. To ensure that the Table can't be filled just by pinging the node repeatedly, we retain the isInitDone check. During init, only nodes from neighbors replies are added. * p2p/discover: reduce findnode failure counter on success * p2p/discover: remove unused parameter of loadSeedNodes * p2p/discover: improve ping-back check and comments * p2p/discover: add neighbors reply nodes always, not just during init
1 parent 9da128d commit c73b654

File tree

6 files changed

+147
-245
lines changed

6 files changed

+147
-245
lines changed

p2p/discover/database.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ var (
4242
nodeDBNilNodeID = NodeID{} // Special node ID to use as a nil element.
4343
nodeDBNodeExpiration = 24 * time.Hour // Time after which an unseen node should be dropped.
4444
nodeDBCleanupCycle = time.Hour // Time period for running the expiration task.
45+
nodeDBVersion = 5
4546
)
4647

4748
// nodeDB stores all nodes we know about.
@@ -257,7 +258,7 @@ func (db *nodeDB) expireNodes() error {
257258
}
258259
// Skip the node if not expired yet (and not self)
259260
if !bytes.Equal(id[:], db.self[:]) {
260-
if seen := db.bondTime(id); seen.After(threshold) {
261+
if seen := db.lastPongReceived(id); seen.After(threshold) {
261262
continue
262263
}
263264
}
@@ -267,29 +268,28 @@ func (db *nodeDB) expireNodes() error {
267268
return nil
268269
}
269270

270-
// lastPing retrieves the time of the last ping packet send to a remote node,
271-
// requesting binding.
272-
func (db *nodeDB) lastPing(id NodeID) time.Time {
271+
// lastPingReceived retrieves the time of the last ping packet sent by the remote node.
272+
func (db *nodeDB) lastPingReceived(id NodeID) time.Time {
273273
return time.Unix(db.fetchInt64(makeKey(id, nodeDBDiscoverPing)), 0)
274274
}
275275

276-
// updateLastPing updates the last time we tried contacting a remote node.
277-
func (db *nodeDB) updateLastPing(id NodeID, instance time.Time) error {
276+
// updateLastPing updates the last time remote node pinged us.
277+
func (db *nodeDB) updateLastPingReceived(id NodeID, instance time.Time) error {
278278
return db.storeInt64(makeKey(id, nodeDBDiscoverPing), instance.Unix())
279279
}
280280

281-
// bondTime retrieves the time of the last successful pong from remote node.
282-
func (db *nodeDB) bondTime(id NodeID) time.Time {
281+
// lastPongReceived retrieves the time of the last successful pong from remote node.
282+
func (db *nodeDB) lastPongReceived(id NodeID) time.Time {
283283
return time.Unix(db.fetchInt64(makeKey(id, nodeDBDiscoverPong)), 0)
284284
}
285285

286286
// hasBond reports whether the given node is considered bonded.
287287
func (db *nodeDB) hasBond(id NodeID) bool {
288-
return time.Since(db.bondTime(id)) < nodeDBNodeExpiration
288+
return time.Since(db.lastPongReceived(id)) < nodeDBNodeExpiration
289289
}
290290

291-
// updateBondTime updates the last pong time of a node.
292-
func (db *nodeDB) updateBondTime(id NodeID, instance time.Time) error {
291+
// updateLastPongReceived updates the last pong time of a node.
292+
func (db *nodeDB) updateLastPongReceived(id NodeID, instance time.Time) error {
293293
return db.storeInt64(makeKey(id, nodeDBDiscoverPong), instance.Unix())
294294
}
295295

@@ -332,7 +332,7 @@ seek:
332332
if n.ID == db.self {
333333
continue seek
334334
}
335-
if now.Sub(db.bondTime(n.ID)) > maxAge {
335+
if now.Sub(db.lastPongReceived(n.ID)) > maxAge {
336336
continue seek
337337
}
338338
for i := range nodes {

p2p/discover/database_test.go

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ var nodeDBInt64Tests = []struct {
7979
}
8080

8181
func TestNodeDBInt64(t *testing.T) {
82-
db, _ := newNodeDB("", Version, NodeID{})
82+
db, _ := newNodeDB("", nodeDBVersion, NodeID{})
8383
defer db.close()
8484

8585
tests := nodeDBInt64Tests
@@ -111,27 +111,27 @@ func TestNodeDBFetchStore(t *testing.T) {
111111
inst := time.Now()
112112
num := 314
113113

114-
db, _ := newNodeDB("", Version, NodeID{})
114+
db, _ := newNodeDB("", nodeDBVersion, NodeID{})
115115
defer db.close()
116116

117117
// Check fetch/store operations on a node ping object
118-
if stored := db.lastPing(node.ID); stored.Unix() != 0 {
118+
if stored := db.lastPingReceived(node.ID); stored.Unix() != 0 {
119119
t.Errorf("ping: non-existing object: %v", stored)
120120
}
121-
if err := db.updateLastPing(node.ID, inst); err != nil {
121+
if err := db.updateLastPingReceived(node.ID, inst); err != nil {
122122
t.Errorf("ping: failed to update: %v", err)
123123
}
124-
if stored := db.lastPing(node.ID); stored.Unix() != inst.Unix() {
124+
if stored := db.lastPingReceived(node.ID); stored.Unix() != inst.Unix() {
125125
t.Errorf("ping: value mismatch: have %v, want %v", stored, inst)
126126
}
127127
// Check fetch/store operations on a node pong object
128-
if stored := db.bondTime(node.ID); stored.Unix() != 0 {
128+
if stored := db.lastPongReceived(node.ID); stored.Unix() != 0 {
129129
t.Errorf("pong: non-existing object: %v", stored)
130130
}
131-
if err := db.updateBondTime(node.ID, inst); err != nil {
131+
if err := db.updateLastPongReceived(node.ID, inst); err != nil {
132132
t.Errorf("pong: failed to update: %v", err)
133133
}
134-
if stored := db.bondTime(node.ID); stored.Unix() != inst.Unix() {
134+
if stored := db.lastPongReceived(node.ID); stored.Unix() != inst.Unix() {
135135
t.Errorf("pong: value mismatch: have %v, want %v", stored, inst)
136136
}
137137
// Check fetch/store operations on a node findnode-failure object
@@ -216,15 +216,15 @@ var nodeDBSeedQueryNodes = []struct {
216216
}
217217

218218
func TestNodeDBSeedQuery(t *testing.T) {
219-
db, _ := newNodeDB("", Version, nodeDBSeedQueryNodes[1].node.ID)
219+
db, _ := newNodeDB("", nodeDBVersion, nodeDBSeedQueryNodes[1].node.ID)
220220
defer db.close()
221221

222222
// Insert a batch of nodes for querying
223223
for i, seed := range nodeDBSeedQueryNodes {
224224
if err := db.updateNode(seed.node); err != nil {
225225
t.Fatalf("node %d: failed to insert: %v", i, err)
226226
}
227-
if err := db.updateBondTime(seed.node.ID, seed.pong); err != nil {
227+
if err := db.updateLastPongReceived(seed.node.ID, seed.pong); err != nil {
228228
t.Fatalf("node %d: failed to insert bondTime: %v", i, err)
229229
}
230230
}
@@ -267,7 +267,7 @@ func TestNodeDBPersistency(t *testing.T) {
267267
)
268268

269269
// Create a persistent database and store some values
270-
db, err := newNodeDB(filepath.Join(root, "database"), Version, NodeID{})
270+
db, err := newNodeDB(filepath.Join(root, "database"), nodeDBVersion, NodeID{})
271271
if err != nil {
272272
t.Fatalf("failed to create persistent database: %v", err)
273273
}
@@ -277,7 +277,7 @@ func TestNodeDBPersistency(t *testing.T) {
277277
db.close()
278278

279279
// Reopen the database and check the value
280-
db, err = newNodeDB(filepath.Join(root, "database"), Version, NodeID{})
280+
db, err = newNodeDB(filepath.Join(root, "database"), nodeDBVersion, NodeID{})
281281
if err != nil {
282282
t.Fatalf("failed to open persistent database: %v", err)
283283
}
@@ -287,7 +287,7 @@ func TestNodeDBPersistency(t *testing.T) {
287287
db.close()
288288

289289
// Change the database version and check flush
290-
db, err = newNodeDB(filepath.Join(root, "database"), Version+1, NodeID{})
290+
db, err = newNodeDB(filepath.Join(root, "database"), nodeDBVersion+1, NodeID{})
291291
if err != nil {
292292
t.Fatalf("failed to open persistent database: %v", err)
293293
}
@@ -324,15 +324,15 @@ var nodeDBExpirationNodes = []struct {
324324
}
325325

326326
func TestNodeDBExpiration(t *testing.T) {
327-
db, _ := newNodeDB("", Version, NodeID{})
327+
db, _ := newNodeDB("", nodeDBVersion, NodeID{})
328328
defer db.close()
329329

330330
// Add all the test nodes and set their last pong time
331331
for i, seed := range nodeDBExpirationNodes {
332332
if err := db.updateNode(seed.node); err != nil {
333333
t.Fatalf("node %d: failed to insert: %v", i, err)
334334
}
335-
if err := db.updateBondTime(seed.node.ID, seed.pong); err != nil {
335+
if err := db.updateLastPongReceived(seed.node.ID, seed.pong); err != nil {
336336
t.Fatalf("node %d: failed to update bondTime: %v", i, err)
337337
}
338338
}
@@ -357,15 +357,15 @@ func TestNodeDBSelfExpiration(t *testing.T) {
357357
break
358358
}
359359
}
360-
db, _ := newNodeDB("", Version, self)
360+
db, _ := newNodeDB("", nodeDBVersion, self)
361361
defer db.close()
362362

363363
// Add all the test nodes and set their last pong time
364364
for i, seed := range nodeDBExpirationNodes {
365365
if err := db.updateNode(seed.node); err != nil {
366366
t.Fatalf("node %d: failed to insert: %v", i, err)
367367
}
368-
if err := db.updateBondTime(seed.node.ID, seed.pong); err != nil {
368+
if err := db.updateLastPongReceived(seed.node.ID, seed.pong); err != nil {
369369
t.Fatalf("node %d: failed to update bondTime: %v", i, err)
370370
}
371371
}

0 commit comments

Comments
 (0)