p2p/discover: fix race in test

This commit is contained in:
Felix Lange 2024-05-14 13:18:47 +02:00
parent 9faae76660
commit 008ff21cdf
3 changed files with 22 additions and 18 deletions

View file

@ -79,7 +79,7 @@ type Table struct {
refreshReq chan chan struct{}
revalResponseCh chan revalidationResponse
addNodeCh chan addNodeOp
addNodeHandled chan struct{}
addNodeHandled chan bool
trackRequestCh chan trackRequestOp
initDone chan struct{}
closeReq chan struct{}
@ -128,7 +128,7 @@ func newTable(t transport, db *enode.DB, cfg Config) (*Table, error) {
refreshReq: make(chan chan struct{}),
revalResponseCh: make(chan revalidationResponse),
addNodeCh: make(chan addNodeOp),
addNodeHandled: make(chan struct{}),
addNodeHandled: make(chan bool),
trackRequestCh: make(chan trackRequestOp),
initDone: make(chan struct{}),
closeReq: make(chan struct{}),
@ -304,12 +304,13 @@ func (tab *Table) len() (n int) {
// list.
//
// The caller must not hold tab.mutex.
func (tab *Table) addFoundNode(n *node) {
func (tab *Table) addFoundNode(n *node) bool {
op := addNodeOp{node: n, isInbound: false}
select {
case tab.addNodeCh <- op:
<-tab.addNodeHandled
return <-tab.addNodeHandled
case <-tab.closeReq:
return false
}
}
@ -321,12 +322,13 @@ func (tab *Table) addFoundNode(n *node) {
// repeatedly.
//
// The caller must not hold tab.mutex.
func (tab *Table) addInboundNode(n *node) {
func (tab *Table) addInboundNode(n *node) bool {
op := addNodeOp{node: n, isInbound: true}
select {
case tab.addNodeCh <- op:
<-tab.addNodeHandled
return <-tab.addNodeHandled
case <-tab.closeReq:
return false
}
}
@ -370,9 +372,9 @@ loop:
case op := <-tab.addNodeCh:
tab.mutex.Lock()
tab.handleAddNode(op)
ok := tab.handleAddNode(op)
tab.mutex.Unlock()
tab.addNodeHandled <- struct{}{}
tab.addNodeHandled <- ok
case op := <-tab.trackRequestCh:
tab.handleTrackRequest(op)
@ -495,35 +497,36 @@ func (tab *Table) removeIP(b *bucket, ip net.IP) {
// handleAddNode adds the node in the request to the table, if there is space.
// The caller must hold tab.mutex.
func (tab *Table) handleAddNode(req addNodeOp) {
func (tab *Table) handleAddNode(req addNodeOp) bool {
if req.node.ID() == tab.self().ID() {
return
return false
}
// For nodes from inbound contact, there is an additional safety measure: if the table
// is still initializing the node is not added.
if req.isInbound && !tab.isInitDone() {
return
return false
}
b := tab.bucket(req.node.ID())
if tab.bumpInBucket(b, req.node.Node) {
// Already in bucket, update record.
return
return false
}
if len(b.entries) >= bucketSize {
// Bucket full, maybe add as replacement.
tab.addReplacement(b, req.node)
return
return false
}
if !tab.addIP(b, req.node.IP()) {
// Can't add: IP limit reached.
return
return false
}
// Add to bucket.
b.entries = append(b.entries, req.node)
b.replacements = deleteNode(b.replacements, req.node)
tab.nodeAdded(b, req.node)
return true
}
// addReplacement adds n to the replacement cache of bucket b.
@ -573,7 +576,7 @@ func (tab *Table) nodeRemoved(b *bucket, n *node) {
func (tab *Table) deleteInBucket(b *bucket, id enode.ID) *node {
index := slices.IndexFunc(b.entries, func(e *node) bool { return e.ID() == id })
if index == -1 {
// Entry has been removed already, don't replace it.
// Entry has been removed already.
return nil
}

View file

@ -63,10 +63,10 @@ func testPingReplace(t *testing.T, newNodeIsResponding, lastInBucketIsResponding
<-tab.initDone
// Fill up the sender's bucket.
tab.mutex.Lock()
replacementNodeKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
replacementNode := wrapNode(enode.NewV4(&replacementNodeKey.PublicKey, net.IP{127, 0, 0, 1}, 99, 99))
last := fillBucket(tab, replacementNode.ID())
tab.mutex.Lock()
nodeEvents := newNodeEventRecorder(128)
tab.nodeAddedHook = nodeEvents.nodeAdded
tab.nodeRemovedHook = nodeEvents.nodeRemoved

View file

@ -104,8 +104,9 @@ func fillBucket(tab *Table, id enode.ID) (last *node) {
b := tab.bucket(id)
for len(b.entries) < bucketSize {
node := nodeAtDistance(tab.self().ID(), ld, intIP(ld))
b.entries = append(b.entries, node)
tab.nodeAdded(b, node)
if !tab.addFoundNode(node) {
panic("node not added")
}
}
return b.entries[bucketSize-1]
}