From 50d3ca26ceaadc30782e08e51b507a584b25ad71 Mon Sep 17 00:00:00 2001 From: Zahary Karadjov Date: Wed, 12 Jun 2019 15:23:05 +0300 Subject: [PATCH] [LibP2P] Persistent network key for the bootstrap node --- beacon_chain/eth2_network.nim | 23 ++++++++++++++++------- beacon_chain/libp2p_backend.nim | 15 ++++++++------- beacon_chain/libp2p_spec_backend.nim | 15 ++++++++------- tests/test_peer_connection.nim | 16 ++++++++++++++-- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/beacon_chain/eth2_network.nim b/beacon_chain/eth2_network.nim index 7f660b4352..80da0c98bf 100644 --- a/beacon_chain/eth2_network.nim +++ b/beacon_chain/eth2_network.nim @@ -118,8 +118,8 @@ when networkBackend == rlpxBackend: else: import - random, - libp2p/daemon/daemonapi, eth/async_utils, + os, random, std_shims/io, + libp2p/crypto/crypto, libp2p/daemon/daemonapi, eth/async_utils, ssz when networkBackend == libp2pSpecBackend: @@ -136,6 +136,9 @@ else: BootstrapAddr* = PeerInfo Eth2NodeIdentity* = PeerInfo + const + networkKeyFilename = "privkey.protobuf" + proc writeValue*(writer: var JsonWriter, value: PeerID) {.inline.} = writer.writeValue value.pretty @@ -151,20 +154,26 @@ else: proc init*(T: type BootstrapAddr, str: string): T = Json.decode(str, PeerInfo) - proc createEth2Node*(conf: BeaconNodeConf): Future[Eth2Node] {.async.} = - var node = new Eth2Node - await node.init() - return node + proc ensureNetworkIdFile(conf: BeaconNodeConf): string = + result = conf.dataDir / networkKeyFilename + if not fileExists(result): + createDir conf.dataDir.string + let pk = PrivateKey.random(Ed25519) + writeFile(result, pk.getBytes) proc getPersistentNetIdentity*(conf: BeaconNodeConf): Eth2NodeIdentity = # Using waitFor here is reasonable, because this proc is needed only # prior to connecting to the network. The RLPx alternative reads from # file and it's much easier to use if it's not async. # TODO: revisit in the future when we have our own Lib2P2 implementation. - let daemon = waitFor newDaemonApi() + let daemon = waitFor newDaemonApi(id = conf.ensureNetworkIdFile) result = waitFor daemon.identity() waitFor daemon.close() + proc createEth2Node*(conf: BeaconNodeConf): Future[Eth2Node] {.async.} = + var daemon = await newDaemonApi({PSGossipSub}, id = conf.ensureNetworkIdFile) + return await Eth2Node.init(daemon) + proc getPersistenBootstrapAddr*(conf: BeaconNodeConf, ip: IpAddress, port: Port): BootstrapAddr = # TODO what about the ports? diff --git a/beacon_chain/libp2p_backend.nim b/beacon_chain/libp2p_backend.nim index ac2bf3efc6..254b0258c6 100644 --- a/beacon_chain/libp2p_backend.nim +++ b/beacon_chain/libp2p_backend.nim @@ -91,19 +91,20 @@ include libp2p_backends_common include eth/p2p/p2p_backends_helpers include eth/p2p/p2p_tracing -proc init*(node: Eth2Node) {.async.} = - node.daemon = await newDaemonApi({PSGossipSub}) - node.daemon.userData = node - init node.peers +proc init*(T: type Eth2Node, daemon: DaemonAPI): Future[T] {.async.} = + new result + result.daemon = daemon + result.daemon.userData = result + init result.peers - newSeq node.protocolStates, allProtocols.len + newSeq result.protocolStates, allProtocols.len for proto in allProtocols: if proto.networkStateInitializer != nil: - node.protocolStates[proto.index] = proto.networkStateInitializer(node) + result.protocolStates[proto.index] = proto.networkStateInitializer(result) for msg in proto.messages: if msg.libp2pProtocol.len > 0: - await node.daemon.addHandler(@[msg.libp2pProtocol], msg.thunk) + await daemon.addHandler(@[msg.libp2pProtocol], msg.thunk) proc readMsg(stream: P2PStream, MsgType: type, deadline: Future[void]): Future[Option[MsgType]] {.async.} = diff --git a/beacon_chain/libp2p_spec_backend.nim b/beacon_chain/libp2p_spec_backend.nim index eca716db79..cb17794e6c 100644 --- a/beacon_chain/libp2p_spec_backend.nim +++ b/beacon_chain/libp2p_spec_backend.nim @@ -160,17 +160,18 @@ include eth/p2p/p2p_tracing proc handleConnectingBeaconChainPeer(daemon: DaemonAPI, stream: P2PStream) {.async, gcsafe.} -proc init*(node: Eth2Node) {.async.} = - node.daemon = await newDaemonApi({PSGossipSub}) - node.daemon.userData = node - init node.peers +proc init*(T: type Eth2Node, daemon: DaemonAPI): Future[Eth2Node] {.async.} = + new result + result.daemon = daemon + result.daemon.userData = result + result.peers = initTable[PeerID, Peer]() - newSeq node.protocolStates, allProtocols.len + newSeq result.protocolStates, allProtocols.len for proto in allProtocols: if proto.networkStateInitializer != nil: - node.protocolStates[proto.index] = proto.networkStateInitializer(node) + result.protocolStates[proto.index] = proto.networkStateInitializer(result) - await node.daemon.addHandler(@[beaconChainProtocol], handleConnectingBeaconChainPeer) + await daemon.addHandler(@[beaconChainProtocol], handleConnectingBeaconChainPeer) proc init*(T: type Peer, network: Eth2Node, id: PeerID): Peer = new result diff --git a/tests/test_peer_connection.nim b/tests/test_peer_connection.nim index d5d923c29e..5de2b3d82e 100644 --- a/tests/test_peer_connection.nim +++ b/tests/test_peer_connection.nim @@ -13,12 +13,24 @@ asyncTest "connect two nodes": var c1 = BeaconNodeConf.defaults c1.dataDir = OutDir(tempDir / "node-1") + + var n1PersistentAddress = c1.getPersistenBootstrapAddr( + parseIpAddress("127.0.0.1"), Port 50000) + var n1 = await createEth2Node(c1) - var n1Address = getPersistenBootstrapAddr(c1, parseIpAddress("127.0.0.1"), Port 50000) + var n1ActualAddress = await n1.daemon.identity() + + echo "persistent: ", n1PersistentAddress + echo "actual:", n1ActualAddress + doAssert n1PersistentAddress == n1ActualAddress + + echo "Node 1 address: ", n1PersistentAddress + echo "Press any key to continue" + discard stdin.readLine() var c2 = BeaconNodeConf.defaults c2.dataDir = OutDir(tempDir / "node-2") var n2 = await createEth2Node(c2) - await n2.connectToNetwork(bootstrapNodes = @[n1Address]) + await n2.connectToNetwork(bootstrapNodes = @[n1ActualAddress])