Initial commit.
This commit is contained in:
parent
e2b3f0dadb
commit
94a9c51d8a
|
@ -113,7 +113,7 @@ proc addBootstrapNode(node: BeaconNode, bootstrapNode: BootstrapAddr) =
|
||||||
|
|
||||||
proc useBootstrapFile(node: BeaconNode, bootstrapFile: string) =
|
proc useBootstrapFile(node: BeaconNode, bootstrapFile: string) =
|
||||||
for ln in lines(bootstrapFile):
|
for ln in lines(bootstrapFile):
|
||||||
node.addBootstrapNode BootstrapAddr.init(string ln)
|
node.addBootstrapNode BootstrapAddr.initAddress(string ln)
|
||||||
|
|
||||||
proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async.} =
|
proc init*(T: type BeaconNode, conf: BeaconNodeConf): Future[BeaconNode] {.async.} =
|
||||||
new result
|
new result
|
||||||
|
@ -756,6 +756,8 @@ proc run*(node: BeaconNode) =
|
||||||
addTimer(second) do (p: pointer):
|
addTimer(second) do (p: pointer):
|
||||||
asyncCheck node.onSecond(second)
|
asyncCheck node.onSecond(second)
|
||||||
|
|
||||||
|
asyncCheck node.network.backendLoop()
|
||||||
|
|
||||||
runForever()
|
runForever()
|
||||||
|
|
||||||
var gPidFile: string
|
var gPidFile: string
|
||||||
|
@ -973,10 +975,7 @@ when isMainModule:
|
||||||
|
|
||||||
let bootstrapFile = config.outputBootstrapFile.string
|
let bootstrapFile = config.outputBootstrapFile.string
|
||||||
if bootstrapFile.len > 0:
|
if bootstrapFile.len > 0:
|
||||||
let bootstrapAddrLine = when networkBackend != rlpxBackend:
|
let bootstrapAddrLine = $bootstrapAddress
|
||||||
$bootstrapAddress.addresses[0] & "/p2p/" & bootstrapAddress.peer.pretty
|
|
||||||
else:
|
|
||||||
$bootstrapAddress
|
|
||||||
writeFile(bootstrapFile, bootstrapAddrLine)
|
writeFile(bootstrapFile, bootstrapAddrLine)
|
||||||
echo "Wrote ", bootstrapFile
|
echo "Wrote ", bootstrapFile
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,7 @@ else:
|
||||||
|
|
||||||
else:
|
else:
|
||||||
import
|
import
|
||||||
libp2p/daemon/daemonapi, libp2p_daemon_backend
|
libp2p/daemon/daemonapi, libp2p/multiaddress, libp2p_daemon_backend
|
||||||
|
|
||||||
export
|
export
|
||||||
libp2p_daemon_backend
|
libp2p_daemon_backend
|
||||||
|
@ -154,19 +154,16 @@ else:
|
||||||
networkKeyFilename = "privkey.protobuf"
|
networkKeyFilename = "privkey.protobuf"
|
||||||
|
|
||||||
type
|
type
|
||||||
BootstrapAddr* = PeerInfo
|
BootstrapAddr* = MultiAddress
|
||||||
Eth2NodeIdentity* = PeerInfo
|
Eth2NodeIdentity* = KeyPair
|
||||||
|
|
||||||
proc init*(T: type BootstrapAddr, str: string): T =
|
proc initAddress*(T: type BootstrapAddr, str: string): T =
|
||||||
# TODO: The code below is quite awkward.
|
let address = MultiAddress.init(str)
|
||||||
# How do we parse a PeerInfo object out of a bootstrap MultiAddress string such as:
|
if IPFS.match(address) and matchPartial(multiaddress.TCP, address):
|
||||||
# /ip4/10.20.30.40/tcp/9100/p2p/16Uiu2HAmEAmp4FdpPzypKwTMmsbCdnUafDvXZCpFrUDbYJZNk7hX
|
result = address
|
||||||
var parts = str.split("/p2p/")
|
|
||||||
if parts.len == 2:
|
|
||||||
result.peer = PeerID.init(parts[1])
|
|
||||||
result.addresses.add MultiAddress.init(parts[0])
|
|
||||||
else:
|
else:
|
||||||
raise newException(ValueError, "Invalid bootstrap multi-address")
|
raise newException(MultiAddressError,
|
||||||
|
"Invalid bootstrap node multi-address")
|
||||||
|
|
||||||
proc ensureNetworkIdFile(conf: BeaconNodeConf): string =
|
proc ensureNetworkIdFile(conf: BeaconNodeConf): string =
|
||||||
result = conf.dataDir / networkKeyFilename
|
result = conf.dataDir / networkKeyFilename
|
||||||
|
@ -176,13 +173,17 @@ else:
|
||||||
writeFile(result, pk.getBytes)
|
writeFile(result, pk.getBytes)
|
||||||
|
|
||||||
proc getPersistentNetIdentity*(conf: BeaconNodeConf): Eth2NodeIdentity =
|
proc getPersistentNetIdentity*(conf: BeaconNodeConf): Eth2NodeIdentity =
|
||||||
# Using waitFor here is reasonable, because this proc is needed only
|
let privateKeyFile = conf.dataDir / networkKeyFilename
|
||||||
# prior to connecting to the network. The RLPx alternative reads from
|
var privKey: PrivateKey
|
||||||
# file and it's much easier to use if it's not async.
|
if not fileExists(privateKeyFile):
|
||||||
# TODO: revisit in the future when we have our own Lib2P2 implementation.
|
createDir conf.dataDir.string
|
||||||
let daemon = waitFor newDaemonApi(id = conf.ensureNetworkIdFile)
|
privKey = PrivateKey.random(Secp256k1)
|
||||||
result = waitFor daemon.identity()
|
writeFile(privateKeyFile, privKey.getBytes())
|
||||||
waitFor daemon.close()
|
else:
|
||||||
|
let strdata = readFile(privateKeyFile)
|
||||||
|
privKey = PrivateKey.init(cast[seq[byte]](strdata))
|
||||||
|
|
||||||
|
result = KeyPair(seckey: privKey, pubkey: privKey.getKey())
|
||||||
|
|
||||||
template tcpEndPoint(address, port): auto =
|
template tcpEndPoint(address, port): auto =
|
||||||
MultiAddress.init(address, Protocol.IPPROTO_TCP, port)
|
MultiAddress.init(address, Protocol.IPPROTO_TCP, port)
|
||||||
|
@ -191,8 +192,7 @@ else:
|
||||||
|
|
||||||
proc allMultiAddresses(nodes: seq[BootstrapAddr]): seq[string] =
|
proc allMultiAddresses(nodes: seq[BootstrapAddr]): seq[string] =
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
for a in node.addresses:
|
result.add $node
|
||||||
result.add $a & "/ipfs/" & node.peer.pretty()
|
|
||||||
|
|
||||||
proc createEth2Node*(conf: BeaconNodeConf,
|
proc createEth2Node*(conf: BeaconNodeConf,
|
||||||
bootstrapNodes: seq[BootstrapAddr]): Future[Eth2Node] {.async.} =
|
bootstrapNodes: seq[BootstrapAddr]): Future[Eth2Node] {.async.} =
|
||||||
|
@ -219,10 +219,11 @@ else:
|
||||||
bootstrapNodes = allMultiAddresses(bootstrapNodes),
|
bootstrapNodes = allMultiAddresses(bootstrapNodes),
|
||||||
peersRequired = 1)
|
peersRequired = 1)
|
||||||
|
|
||||||
info "Daemon started"
|
|
||||||
|
|
||||||
mainDaemon = await daemonFut
|
mainDaemon = await daemonFut
|
||||||
|
|
||||||
|
info "LibP2P daemon started"
|
||||||
|
|
||||||
proc closeDaemon() {.noconv.} =
|
proc closeDaemon() {.noconv.} =
|
||||||
info "Shutting down the LibP2P daemon"
|
info "Shutting down the LibP2P daemon"
|
||||||
waitFor mainDaemon.close()
|
waitFor mainDaemon.close()
|
||||||
|
@ -232,33 +233,24 @@ else:
|
||||||
|
|
||||||
proc getPersistenBootstrapAddr*(conf: BeaconNodeConf,
|
proc getPersistenBootstrapAddr*(conf: BeaconNodeConf,
|
||||||
ip: IpAddress, port: Port): BootstrapAddr =
|
ip: IpAddress, port: Port): BootstrapAddr =
|
||||||
result = getPersistentNetIdentity(conf)
|
let pair = getPersistentNetIdentity(conf)
|
||||||
result.addresses = @[tcpEndPoint(ip, port)]
|
let pidma = MultiAddress.init(multiCodec("p2p"), PeerID.init(pair.pubkey))
|
||||||
|
result = tcpEndPoint(ip, port) & pidma
|
||||||
|
|
||||||
proc isSameNode*(bootstrapNode: BootstrapAddr, id: Eth2NodeIdentity): bool =
|
proc isSameNode*(bootstrapNode: BootstrapAddr, id: Eth2NodeIdentity): bool =
|
||||||
bootstrapNode.peer == id.peer
|
if IPFS.match(bootstrapNode):
|
||||||
|
let pid1 = PeerID.init(bootstrapNode[2].protoAddress())
|
||||||
|
let pid2 = PeerID.init(id.pubkey)
|
||||||
|
result = (pid1 == pid2)
|
||||||
|
|
||||||
proc shortForm*(id: Eth2NodeIdentity): string =
|
proc shortForm*(id: Eth2NodeIdentity): string =
|
||||||
# TODO: Make this shorter
|
$PeerID.init(id.pubkey)
|
||||||
$id
|
|
||||||
|
|
||||||
proc connectToNetwork*(node: Eth2Node, bootstrapNodes: seq[PeerInfo]) {.async.} =
|
proc connectToNetwork*(node: Eth2Node,
|
||||||
# TODO: perhaps we should do these in parallel
|
bootstrapNodes: seq[MultiAddress]) {.async.} =
|
||||||
var connected = false
|
## go-libp2p-daemon will perform connection to the network automatically,
|
||||||
for bootstrapNode in bootstrapNodes:
|
## we just need to follow it.
|
||||||
try:
|
discard
|
||||||
await node.daemon.connect(bootstrapNode.peer, bootstrapNode.addresses)
|
|
||||||
var peer = node.getPeer(bootstrapNode.peer)
|
|
||||||
peer.wasDialed = true
|
|
||||||
await initializeConnection(peer)
|
|
||||||
connected = true
|
|
||||||
except CatchableError as err:
|
|
||||||
error "Failed to connect to bootstrap node",
|
|
||||||
node = bootstrapNode, err = err.msg
|
|
||||||
|
|
||||||
if bootstrapNodes.len > 0 and connected == false:
|
|
||||||
fatal "Failed to connect to any bootstrap node. Quitting."
|
|
||||||
quit 1
|
|
||||||
|
|
||||||
proc saveConnectionAddressFile*(node: Eth2Node, filename: string) =
|
proc saveConnectionAddressFile*(node: Eth2Node, filename: string) =
|
||||||
let id = waitFor node.daemon.identity()
|
let id = waitFor node.daemon.identity()
|
||||||
|
|
|
@ -470,6 +470,9 @@ proc init*[MsgType](T: type Responder[MsgType],
|
||||||
peer: Peer, stream: P2PStream): T =
|
peer: Peer, stream: P2PStream): T =
|
||||||
T(UntypedResponder(peer: peer, stream: stream))
|
T(UntypedResponder(peer: peer, stream: stream))
|
||||||
|
|
||||||
|
proc backendLoop*(node: Eth2Node) {.async.} =
|
||||||
|
discard
|
||||||
|
|
||||||
import
|
import
|
||||||
typetraits
|
typetraits
|
||||||
|
|
||||||
|
|
|
@ -470,6 +470,40 @@ proc init*[MsgType](T: type Responder[MsgType],
|
||||||
peer: Peer, stream: P2PStream): T =
|
peer: Peer, stream: P2PStream): T =
|
||||||
T(UntypedResponder(peer: peer, stream: stream))
|
T(UntypedResponder(peer: peer, stream: stream))
|
||||||
|
|
||||||
|
proc backendLoop*(node: Eth2Node) {.async.} =
|
||||||
|
var peerFuts = newSeq[Future[void]]()
|
||||||
|
var peerStore = newSeq[tuple[peer: Peer, future: Future[void]]]()
|
||||||
|
while true:
|
||||||
|
var list = await node.daemon.listPeers()
|
||||||
|
debug "Daemon's peer list", count = len(list)
|
||||||
|
|
||||||
|
peerFuts.setLen(0)
|
||||||
|
peerStore.setLen(0)
|
||||||
|
|
||||||
|
for item in list:
|
||||||
|
var peerCheck = node.peers.getOrDefault(item.peer)
|
||||||
|
if isNil(peerCheck):
|
||||||
|
var peer = node.getPeer(item.peer)
|
||||||
|
info "Handshaking with new peer", peer
|
||||||
|
let fut = initializeConnection(peer)
|
||||||
|
peerStore.add((peer, fut))
|
||||||
|
peerFuts.add(fut)
|
||||||
|
|
||||||
|
await allFutures(peerFuts)
|
||||||
|
|
||||||
|
for item in peerFuts:
|
||||||
|
var peer: Peer
|
||||||
|
for storeItem in peerStore:
|
||||||
|
if item == storeItem.future:
|
||||||
|
peer = storeItem.peer
|
||||||
|
break
|
||||||
|
if item.finished():
|
||||||
|
info "Handshake with peer succeeded", peer
|
||||||
|
elif item.failed():
|
||||||
|
info "Handshake with peer failed", peer, error = item.error.msg
|
||||||
|
|
||||||
|
await sleepAsync(1.seconds)
|
||||||
|
|
||||||
import
|
import
|
||||||
typetraits
|
typetraits
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 88b79e230005d8301c3ae950abdbf8ad55e37f19
|
Subproject commit 173c7b4a86e6d75a69577166526b0f5840c45003
|
|
@ -1 +1 @@
|
||||||
Subproject commit f3fc763895986e96d53349e0696c897303104765
|
Subproject commit 1c16eb5d69a9fb8e9577d68d3fb97843a40d31a4
|
|
@ -1 +1 @@
|
||||||
Subproject commit ae60eef4e8413e49fb0dbcae9a343fb479509fa0
|
Subproject commit 448a03ed4bd5837e18a3c50e10c6e31d25a6c9e5
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7bc29e747004b8aa7988eab537029ecab73dcb45
|
Subproject commit 37fc46111489bc521731b59f52f42b6327fa7829
|
Loading…
Reference in New Issue