From f8bdec88c9afa1559208f67a5ccb9cfebeece1da Mon Sep 17 00:00:00 2001 From: kdeme Date: Tue, 11 Jun 2019 12:46:26 +0200 Subject: [PATCH] Rework duplicate connections check and fix #36 --- eth/p2p.nim | 8 +++----- eth/p2p/peer_pool.nim | 23 +++++++++-------------- eth/p2p/rlpx.nim | 10 ++++++++++ 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/eth/p2p.nim b/eth/p2p.nim index 705d590..8055d7a 100644 --- a/eth/p2p.nim +++ b/eth/p2p.nim @@ -70,12 +70,10 @@ proc processIncoming(server: StreamServer, yield peerfut if not peerfut.failed: let peer = peerfut.read() + trace "Connection established (incoming)", peer if node.peerPool != nil: - if not node.peerPool.addPeer(peer): - # In case an outgoing connection was added in the meanwhile or a - # malicious peer opens multiple connections - debug "Disconnecting peer (incoming)", reason = AlreadyConnected - await peer.disconnect(AlreadyConnected) + node.peerPool.connectingNodes.excl(peer.remote) + node.peerPool.addPeer(peer) proc listeningAddress*(node: EthereumNode): ENode = return initENode(node.keys.pubKey, node.address) diff --git a/eth/p2p/peer_pool.nim b/eth/p2p/peer_pool.nim index 328fdab..ce3f86c 100644 --- a/eth/p2p/peer_pool.nim +++ b/eth/p2p/peer_pool.nim @@ -107,24 +107,19 @@ proc getRandomBootnode(p: PeerPool): Option[Node] = if p.discovery.bootstrapNodes.len != 0: result = option(p.discovery.bootstrapNodes.rand()) -proc addPeer*(pool: PeerPool, peer: Peer): bool = - if peer.remote notin pool.connectedNodes: - pool.connectedNodes[peer.remote] = peer - for o in pool.observers.values: - if not o.onPeerConnected.isNil: - if o.protocol.isNil or peer.supports(o.protocol): - o.onPeerConnected(peer) - return true - else: return false +proc addPeer*(pool: PeerPool, peer: Peer) = + doAssert(peer.remote notin pool.connectedNodes) + pool.connectedNodes[peer.remote] = peer + for o in pool.observers.values: + if not o.onPeerConnected.isNil: + if o.protocol.isNil or peer.supports(o.protocol): + o.onPeerConnected(peer) proc connectToNode*(p: PeerPool, n: Node) {.async.} = let peer = await p.connect(n) if not peer.isNil: - trace "Connection established", peer - if not p.addPeer(peer): - # In case an incoming connection was added in the meanwhile - trace "Disconnecting peer (outgoing)", reason = AlreadyConnected - await peer.disconnect(AlreadyConnected) + trace "Connection established (outgoing)", peer + p.addPeer(peer) proc connectToNodes(p: PeerPool, nodes: seq[Node]) {.async.} = for node in nodes: diff --git a/eth/p2p/rlpx.nim b/eth/p2p/rlpx.nim index 0acf941..051a564 100644 --- a/eth/p2p/rlpx.nim +++ b/eth/p2p/rlpx.nim @@ -1480,6 +1480,16 @@ proc rlpxAccept*(node: EthereumNode, udpPort: remote.port) result.remote = newNode(initEnode(handshake.remoteHPubkey, address)) + # In case there is an outgoing connection started with this peer we give + # precedence to that one and we disconnect here with `AlreadyConnected` + if result.remote in node.peerPool.connectedNodes or + result.remote in node.peerPool.connectingNodes: + trace "Duplicate connection in rlpxAccept" + raisePeerDisconnected("Peer already connecting or connected", + AlreadyConnected) + + node.peerPool.connectingNodes.incl(result.remote) + await postHelloSteps(result, response) ok = true except PeerDisconnected as e: