@@ -998,10 +998,29 @@ proc removePeer(network: EthereumNode, peer: Peer) =
998998 if observer.protocols.len == 0 or peer.supports (observer.protocols):
999999 observer.onPeerDisconnected (peer)
10001000
1001+ proc selectCapsByLatestVersion (peer: Peer ): seq [ProtocolInfo ] =
1002+ # Avoid using multiple capability handshake when connecting to a peer.
1003+ # Use only the latest capability version. e.g. choose eth/69 over eth/68.
1004+ # But other capabilities with different name is okay. e.g. snap/1
1005+
1006+ # From the spec:
1007+ # https://github.com/ethereum/devp2p/blob/bc76b9809a30e6dc5c8dcda996273f0f9bcf7108/rlpx.md#message-id-based-multiplexing
1008+ # "...If multiple versions are shared of the same (equal name) capability, the numerically highest wins, others are ignored."
1009+ var map: Table [string , ProtocolInfo ]
1010+ for proto in peer.dispatcher.activeProtocols:
1011+ map.withValue (proto.capability.name, val) do :
1012+ if proto.capability.version > val.capability.version:
1013+ val[] = proto
1014+ do :
1015+ map[proto.capability.name] = proto
1016+
1017+ for proto in map.values:
1018+ result .add proto
1019+
10011020proc callDisconnectHandlers (
10021021 peer: Peer , reason: DisconnectionReason
10031022): Future [void ] {.async : (raises: []).} =
1004- let futures = peer.dispatcher.activeProtocols
1023+ let futures = peer.selectCapsByLatestVersion ()
10051024 .filterIt (it.onPeerDisconnected != nil )
10061025 .mapIt (it.onPeerDisconnected (peer, reason))
10071026
@@ -1102,7 +1121,7 @@ proc postHelloSteps(
11021121 # the network and to yield on their `nextMsg` waits.
11031122 #
11041123
1105- let handshakes = peer.dispatcher.activeProtocols
1124+ let handshakes = peer.selectCapsByLatestVersion ()
11061125 .filterIt (it.onPeerConnected != nil )
11071126 .mapIt (it.onPeerConnected (peer))
11081127
0 commit comments