Skip to content

Commit 3dc1fed

Browse files
committed
peer: Do not send inventory before version
For inbound peers, their version message is read, and the version is marked as known, before our local peer ever publishes the version message. This could result in a protocol messaging race where other messages (and in particular, notifying inventory) may be published prior to our version ever being sent. While here, remove unused versionSent field from the peer. The new HandshakeCompleted tracking is strictly better (while it is allowed to send a peer messages before we have read their version, whether those messages follow the negotiation protocol version won't be known until after the fact).
1 parent 33c9cff commit 3dc1fed

File tree

1 file changed

+32
-7
lines changed

1 file changed

+32
-7
lines changed

peer/peer.go

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -482,10 +482,10 @@ type Peer struct {
482482
userAgent string
483483
services wire.ServiceFlag
484484
versionKnown bool
485+
handshakeCompleted bool
485486
advertisedProtoVer uint32 // protocol version advertised by remote
486487
protocolVersion uint32 // negotiated protocol version
487488
sendHeadersPreferred bool // peer sent a sendheaders message
488-
versionSent bool
489489
verAckReceived bool
490490

491491
knownInventory *lru.Set[wire.InvVect]
@@ -705,6 +705,18 @@ func (p *Peer) VersionKnown() bool {
705705
return versionKnown
706706
}
707707

708+
// HandshakeCompleted returns whether initial version messages were sent and
709+
// received.
710+
//
711+
// This function is safe for concurrent access.
712+
func (p *Peer) HandshakeCompleted() bool {
713+
p.flagsMtx.Lock()
714+
handshakeCompleted := p.handshakeCompleted
715+
p.flagsMtx.Unlock()
716+
717+
return handshakeCompleted
718+
}
719+
708720
// VerAckReceived returns whether or not a verack message was received by the
709721
// peer.
710722
//
@@ -1652,7 +1664,7 @@ out:
16521664

16531665
case iv := <-p.outputInvChan:
16541666
// No handshake? They'll find out soon enough.
1655-
if p.VersionKnown() {
1667+
if p.HandshakeCompleted() {
16561668
invSendQueue = append(invSendQueue, iv)
16571669
}
16581670

@@ -2080,9 +2092,6 @@ func (p *Peer) writeLocalVersionMsg() error {
20802092
return err
20812093
}
20822094

2083-
p.flagsMtx.Lock()
2084-
p.versionSent = true
2085-
p.flagsMtx.Unlock()
20862095
return nil
20872096
}
20882097

@@ -2094,7 +2103,15 @@ func (p *Peer) negotiateInboundProtocol() error {
20942103
return err
20952104
}
20962105

2097-
return p.writeLocalVersionMsg()
2106+
if err := p.writeLocalVersionMsg(); err != nil {
2107+
return err
2108+
}
2109+
2110+
p.flagsMtx.Lock()
2111+
p.handshakeCompleted = true
2112+
p.flagsMtx.Unlock()
2113+
2114+
return nil
20982115
}
20992116

21002117
// negotiateOutboundProtocol sends our version message then waits to receive a
@@ -2105,7 +2122,15 @@ func (p *Peer) negotiateOutboundProtocol() error {
21052122
return err
21062123
}
21072124

2108-
return p.readRemoteVersionMsg()
2125+
if err := p.readRemoteVersionMsg(); err != nil {
2126+
return err
2127+
}
2128+
2129+
p.flagsMtx.Lock()
2130+
p.handshakeCompleted = true
2131+
p.flagsMtx.Unlock()
2132+
2133+
return nil
21092134
}
21102135

21112136
// start begins processing input and output messages.

0 commit comments

Comments
 (0)