Skip to content

Commit

Permalink
fix: a deadlock caused by bsc protocol handeshake timeout (#1484)
Browse files Browse the repository at this point in the history
  • Loading branch information
brilliant-lx authored Apr 19, 2023
1 parent cbbe7de commit 2db1088
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 6 deletions.
2 changes: 1 addition & 1 deletion eth/handler_bsc.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (h *bscHandler) RunPeer(peer *bsc.Peer, hand bsc.Handler) error {
ps.lock.Lock()
if wait, ok := ps.bscWait[id]; ok {
delete(ps.bscWait, id)
wait <- peer
wait <- nil
}
ps.lock.Unlock()
return err
Expand Down
25 changes: 21 additions & 4 deletions eth/peerset.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const (
// extensionWaitTimeout is the maximum allowed time for the extension wait to
// complete before dropping the connection as malicious.
extensionWaitTimeout = 10 * time.Second
tryWaitTimeout = 100 * time.Millisecond
)

// peerSet represents the collection of active peers currently participating in
Expand Down Expand Up @@ -402,10 +403,26 @@ func (ps *peerSet) waitBscExtension(peer *eth.Peer) (*bsc.Peer, error) {
return peer, nil

case <-time.After(extensionWaitTimeout):
ps.lock.Lock()
delete(ps.bscWait, id)
ps.lock.Unlock()
return nil, errPeerWaitTimeout
// could be deadlock, so we use TryLock to avoid it.
if ps.lock.TryLock() {
delete(ps.bscWait, id)
ps.lock.Unlock()
return nil, errPeerWaitTimeout
}
// if TryLock failed, we wait for a while and try again.
for {
select {
case <-wait:
// discard the peer, even though the peer arrived.
return nil, errPeerWaitTimeout
case <-time.After(tryWaitTimeout):
if ps.lock.TryLock() {
delete(ps.bscWait, id)
ps.lock.Unlock()
return nil, errPeerWaitTimeout
}
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion p2p/peer.go
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ func (p *Peer) startProtocols(writeStart <-chan struct{}, writeErr chan<- error)
p.log.Trace(fmt.Sprintf("Protocol %s/%d returned", proto.Name, proto.Version))
err = errProtocolReturned
} else if !errors.Is(err, io.EOF) {
p.log.Trace(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err)
p.log.Warn(fmt.Sprintf("Protocol %s/%d failed", proto.Name, proto.Version), "err", err)
}
p.protoErr <- err
}()
Expand Down

0 comments on commit 2db1088

Please sign in to comment.