From e493c84b2a5e6299427ce4b46cc46a8964f95ffa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oskar=20Thor=C3=A9n?= Date: Mon, 20 Jul 2020 12:40:35 +0800 Subject: [PATCH] Add basic example usage for Waku v2 (#52) * Make Waku node async and gcsafe, hacky ...but the nimbus people are doing it! * Add skeleton example usage * Rename example to basic2 and add to Makefile * Sketch out basic example and qualify imports etc Loading config to start with. Quite messy with imports/ambiguous identifiers/qualified names. Probably a better way with exports (hide implementation details) and fully qualified names by default? * Example usage run, public run function * Sketch out API usage * Example basic RPC client usage * waitFor run to compile * Remove run and gsync markers; adjust example --- Makefile | 4 +++ examples/v2/basic2.nim | 51 ++++++++++++++++++++++++++++++++++++++ waku.nimble | 5 ++++ waku/node/v2/config.nim | 13 +++++----- waku/node/v2/wakunode2.nim | 15 ++++++----- 5 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 examples/v2/basic2.nim diff --git a/Makefile b/Makefile index d8f058e1a..a26aa51cc 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,10 @@ wakutest2: echo -e $(BUILD_MSG) "build/$@" && \ $(ENV_SCRIPT) nim wakutest2 $(NIM_PARAMS) waku.nims +wakuexample2: + echo -e $(BUILD_MSG) "build/$@" && \ + $(ENV_SCRIPT) nim wakuexample2 $(NIM_PARAMS) waku.nims + # symlink waku.nims: ln -s waku.nimble $@ diff --git a/examples/v2/basic2.nim b/examples/v2/basic2.nim new file mode 100644 index 000000000..90e7c3760 --- /dev/null +++ b/examples/v2/basic2.nim @@ -0,0 +1,51 @@ +# Here's an example of how you would start a Waku node, subscribe to topics, and +# publish to them + +import confutils, chronicles, chronos, os + +import libp2p/crypto/crypto +import libp2p/crypto/secp +import eth/keys +import json_rpc/[rpcclient, rpcserver] + +import ../../waku/node/v2/config +import ../../waku/node/v2/wakunode2 + +# Loads the config in `waku/node/v2/config.nim` +let conf = WakuNodeConf.load() + +# Start the node +# Running this should give you output like this: +# INF Listening on tid=5719 full=/ip4/127.0.0.1/tcp/60000/p2p/16Uiu2HAmNiAqr1cwhyntotP9fiSDyBvfKtB4ZiaDsrkipSCoKCB4 +# TODO Run this in background +# See https://github.com/status-im/nim-waku/pull/59 +proc runBackground(conf: WakuNodeConf) {.async.} = + run(conf) + runForever() + +discard runBackground(conf) + +# To do more operations on this node, we can do this in two ways: +# - We can use the Nim Node API, which is currently not exposed +# - We can use JSON RPC + +# TODO Subscribe and publish to topic via Node API +# Requires https://github.com/status-im/nim-waku/issues/53 + +# Here's how to do it with JSON RPC + +# Get RPC call signatures in Nim +from strutils import rsplit +template sourceDir: string = currentSourcePath.parentDir().parentDir().rsplit(DirSep, 1)[0] +const sigWakuPath = sourceDir / "waku" / "node" / "v2" / "rpc" / "wakucallsigs.nim" + +createRpcSigs(RpcHttpClient, sigWakuPath) + +# Create RPC Client and connect to it +var node = newRpcHttpClient() +waitfor node.connect("localhost", Port(8547)) + +# TODO Do something with res +var res = waitFor node.wakuSubscribe("apptopic") + +# TODO Use publish as well diff --git a/waku.nimble b/waku.nimble index 8f3176ba8..ed3c967e7 100644 --- a/waku.nimble +++ b/waku.nimble @@ -64,3 +64,8 @@ task wakunode2, "Build Experimental Waku cli": task wakusim2, "Build Experimental Waku simulation tools": buildBinary "quicksim2", "waku/node/v2/", "-d:chronicles_log_level=DEBUG" buildBinary "start_network2", "waku/node/v2/", "-d:chronicles_log_level=TRACE" + +task wakuexample2, "Build example Waku usage": + let name = "basic2" + buildBinary name, "examples/v2/", "-d:chronicles_log_level=DEBUG" + exec "build/" & name diff --git a/waku/node/v2/config.nim b/waku/node/v2/config.nim index d9faad87a..dd749162d 100644 --- a/waku/node/v2/config.nim +++ b/waku/node/v2/config.nim @@ -2,7 +2,8 @@ import confutils/defs, chronicles, chronos, libp2p/crypto/crypto, libp2p/crypto/secp, - nimcrypto/utils + nimcrypto/utils, + eth/keys type Fleet* = enum @@ -88,8 +89,8 @@ type # NOTE: Signature is different here, we return PrivateKey and not KeyPair nodekey* {. desc: "P2P node private key as hex.", - defaultValue: PrivateKey.random(Secp256k1, keys.newRng()[]).tryGet() - name: "nodekey" }: PrivateKey + defaultValue: crypto.PrivateKey.random(Secp256k1, keys.newRng()[]).tryGet() + name: "nodekey" }: crypto.PrivateKey # TODO: Add nodekey file option bootnodeOnly* {. @@ -137,15 +138,15 @@ type # - mailserver functionality # NOTE: Keys are different in nim-libp2p -proc parseCmdArg*(T: type PrivateKey, p: TaintedString): T = +proc parseCmdArg*(T: type crypto.PrivateKey, p: TaintedString): T = try: let key = SkPrivateKey.init(utils.fromHex(p)).tryGet() # XXX: Here at the moment - result = PrivateKey(scheme: Secp256k1, skkey: key) + result = crypto.PrivateKey(scheme: Secp256k1, skkey: key) except CatchableError as e: raise newException(ConfigurationError, "Invalid private key") -proc completeCmdArg*(T: type PrivateKey, val: TaintedString): seq[string] = +proc completeCmdArg*(T: type crypto.PrivateKey, val: TaintedString): seq[string] = return @[] proc parseCmdArg*(T: type IpAddress, p: TaintedString): T = diff --git a/waku/node/v2/wakunode2.nim b/waku/node/v2/wakunode2.nim index da20f9482..5ace51d28 100644 --- a/waku/node/v2/wakunode2.nim +++ b/waku/node/v2/wakunode2.nim @@ -63,7 +63,7 @@ proc connectToNodes(p: WakuProto, nodes: openArray[string]) = # NOTE: Looks almost identical to beacon_chain/eth2_network.nim proc setupNat(conf: WakuNodeConf): tuple[ip: IpAddress, tcpPort: Port, - udpPort: Port] = + udpPort: Port] {.gcsafe.} = # defaults result.ip = globalListeningAddr result.tcpPort = Port(conf.tcpPort + conf.portsShift) @@ -92,9 +92,11 @@ proc setupNat(conf: WakuNodeConf): tuple[ip: IpAddress, let extIP = getExternalIP(nat) if extIP.isSome: result.ip = extIP.get() - let extPorts = redirectPorts(tcpPort = result.tcpPort, - udpPort = result.udpPort, - description = clientId) + # XXX: GC safety danger zone! See NBC eth2_network.nim + let extPorts = ({.gcsafe.}: + redirectPorts(tcpPort = result.tcpPort, + udpPort = result.udpPort, + description = clientId)) if extPorts.isSome: (result.tcpPort, result.udpPort) = extPorts.get() @@ -109,13 +111,14 @@ proc newWakuProto(switch: Switch): WakuProto = wakuproto.handler = handle return wakuproto -proc run(config: WakuNodeConf) = +proc run*(config: WakuNodeConf) = info "libp2p support WIP" if config.logLevel != LogLevel.NONE: setLogLevel(config.logLevel) + # TODO Clean up host and announced IP a la eth2_network.nim let # External TCP and UDP ports (ip, tcpPort, udpPort) = setupNat(config) @@ -131,7 +134,7 @@ proc run(config: WakuNodeConf) = nodekey = config.nodekey seckey = nodekey pubkey = seckey.getKey.get() - keys = KeyPair(seckey: seckey, pubkey: pubkey) + keys = crypto.KeyPair(seckey: seckey, pubkey: pubkey) peerInfo = PeerInfo.init(nodekey)