Skip to content

Commit

Permalink
[LibP2P] Persistent network key for the bootstrap node
Browse files Browse the repository at this point in the history
  • Loading branch information
zah committed Jun 12, 2019
1 parent ecbb53d commit 50d3ca2
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 23 deletions.
23 changes: 16 additions & 7 deletions beacon_chain/eth2_network.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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

Expand All @@ -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?
Expand Down
15 changes: 8 additions & 7 deletions beacon_chain/libp2p_backend.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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.} =
Expand Down
15 changes: 8 additions & 7 deletions beacon_chain/libp2p_spec_backend.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
16 changes: 14 additions & 2 deletions tests/test_peer_connection.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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])

0 comments on commit 50d3ca2

Please sign in to comment.