2020-08-26 12:20:04 +00:00
|
|
|
import
|
2020-09-01 02:09:54 +00:00
|
|
|
confutils, chronicles, chronos, stew/byteutils, stew/shims/net as stewNet,
|
2020-08-27 02:44:52 +00:00
|
|
|
eth/[keys, p2p],
|
2020-11-17 09:34:53 +00:00
|
|
|
../../waku/v1/protocol/waku_protocol,
|
|
|
|
../../waku/v1/node/waku_helpers,
|
|
|
|
../../waku/common/utils/nat,
|
2020-08-26 12:20:04 +00:00
|
|
|
./config_example
|
|
|
|
|
|
|
|
## This is a simple Waku v1 example to show the Waku v1 API usage.
|
|
|
|
|
|
|
|
const clientId = "Waku example v1"
|
|
|
|
|
2022-09-07 15:31:27 +00:00
|
|
|
proc run(config: WakuNodeConf, rng: ref HmacDrbgContext) =
|
2020-08-26 12:20:04 +00:00
|
|
|
# Set up the address according to NAT information.
|
2021-03-26 09:52:04 +00:00
|
|
|
let (ipExt, tcpPortExt, udpPortExt) = setupNat(config.nat, clientId,
|
2020-09-01 02:09:54 +00:00
|
|
|
Port(config.tcpPort + config.portsShift),
|
|
|
|
Port(config.udpPort + config.portsShift))
|
|
|
|
# TODO: EthereumNode should have a better split of binding address and
|
|
|
|
# external address. Also, can't have different ports as it stands now.
|
2021-03-26 09:52:04 +00:00
|
|
|
let address = if ipExt.isNone():
|
|
|
|
Address(ip: parseIpAddress("0.0.0.0"),
|
|
|
|
tcpPort: Port(config.tcpPort + config.portsShift),
|
|
|
|
udpPort: Port(config.udpPort + config.portsShift))
|
|
|
|
else:
|
|
|
|
Address(ip: ipExt.get(),
|
|
|
|
tcpPort: Port(config.tcpPort + config.portsShift),
|
|
|
|
udpPort: Port(config.udpPort + config.portsShift))
|
2020-08-26 12:20:04 +00:00
|
|
|
|
2021-03-26 09:52:04 +00:00
|
|
|
# Create Ethereum Node
|
|
|
|
var node = newEthereumNode(config.nodekey, # Node identifier
|
|
|
|
address, # Address reachable for incoming requests
|
|
|
|
NetworkId(1), # Network Id, only applicable for ETH protocol
|
|
|
|
clientId, # Client id string
|
|
|
|
addAllCapabilities = false, # Disable default all RLPx capabilities
|
2022-09-07 15:31:27 +00:00
|
|
|
bindUdpPort = address.udpPort, # Assume same as external
|
|
|
|
bindTcpPort = address.tcpPort, # Assume same as external
|
2021-03-26 09:52:04 +00:00
|
|
|
rng = rng)
|
|
|
|
|
|
|
|
node.addCapability Waku # Enable only the Waku protocol.
|
|
|
|
|
|
|
|
# Set up the Waku configuration.
|
|
|
|
let wakuConfig = WakuConfig(powRequirement: 0.002,
|
|
|
|
bloom: some(fullBloom()), # Full bloom filter
|
|
|
|
isLightNode: false, # Full node
|
|
|
|
maxMsgSize: waku_protocol.defaultMaxMsgSize,
|
|
|
|
topics: none(seq[waku_protocol.Topic]) # empty topic interest
|
|
|
|
)
|
|
|
|
node.configureWaku(wakuConfig)
|
|
|
|
|
|
|
|
# Optionally direct connect to a set of nodes.
|
|
|
|
if config.staticnodes.len > 0:
|
|
|
|
connectToNodes(node, config.staticnodes)
|
|
|
|
|
|
|
|
# Connect to the network, which will make the node start listening and/or
|
|
|
|
# connect to bootnodes, and/or start discovery.
|
|
|
|
# This will block until first connection is made, which in this case can only
|
|
|
|
# happen if we directly connect to nodes (step above) or if an incoming
|
|
|
|
# connection occurs, which is why we use a callback to exit on errors instead of
|
|
|
|
# using `await`.
|
|
|
|
# TODO: This looks a bit awkward and the API should perhaps be altered here.
|
2022-09-07 15:31:27 +00:00
|
|
|
let connectedFut = node.connectToNetwork(
|
2021-03-26 09:52:04 +00:00
|
|
|
true, # Enable listening
|
|
|
|
false # Disable discovery (only discovery v4 is currently supported)
|
|
|
|
)
|
|
|
|
connectedFut.callback = proc(data: pointer) {.gcsafe.} =
|
|
|
|
{.gcsafe.}:
|
|
|
|
if connectedFut.failed:
|
|
|
|
fatal "connectToNetwork failed", msg = connectedFut.readError.msg
|
|
|
|
quit(1)
|
|
|
|
|
|
|
|
# Using a hardcoded symmetric key for encryption of the payload for the sake of
|
|
|
|
# simplicity.
|
|
|
|
var symKey: SymKey
|
|
|
|
symKey[31] = 1
|
|
|
|
# Asymmetric keypair to sign the payload.
|
|
|
|
let signKeyPair = KeyPair.random(rng[])
|
|
|
|
|
|
|
|
# Code to be executed on receival of a message on filter.
|
|
|
|
proc handler(msg: ReceivedMessage) =
|
|
|
|
if msg.decoded.src.isSome():
|
|
|
|
echo "Received message from ", $msg.decoded.src.get(), ": ",
|
|
|
|
string.fromBytes(msg.decoded.payload)
|
|
|
|
|
|
|
|
# Create and subscribe filter with above handler.
|
|
|
|
let
|
|
|
|
topic = [byte 0, 0, 0, 0]
|
|
|
|
filter = initFilter(symKey = some(symKey), topics = @[topic])
|
|
|
|
discard node.subscribeFilter(filter, handler)
|
|
|
|
|
|
|
|
# Repeat the posting of a message every 5 seconds.
|
|
|
|
# https://github.com/nim-lang/Nim/issues/17369
|
|
|
|
var repeatMessage: proc(udata: pointer) {.gcsafe, raises: [Defect].}
|
|
|
|
repeatMessage = proc(udata: pointer) =
|
|
|
|
{.gcsafe.}:
|
|
|
|
# Post a waku message on the network, encrypted with provided symmetric key,
|
|
|
|
# signed with asymmetric key, on topic and with ttl of 30 seconds.
|
|
|
|
let posted = node.postMessage(
|
|
|
|
symKey = some(symKey), src = some(signKeyPair.seckey),
|
|
|
|
ttl = 30, topic = topic, payload = @[byte 0x48, 0x65, 0x6C, 0x6C, 0x6F])
|
|
|
|
|
|
|
|
if posted: echo "Posted message as ", $signKeyPair.pubkey
|
|
|
|
else: echo "Posting message failed."
|
|
|
|
|
|
|
|
discard setTimer(Moment.fromNow(5.seconds), repeatMessage)
|
2020-08-26 12:20:04 +00:00
|
|
|
discard setTimer(Moment.fromNow(5.seconds), repeatMessage)
|
|
|
|
|
2021-03-26 09:52:04 +00:00
|
|
|
runForever()
|
|
|
|
|
|
|
|
when isMainModule:
|
|
|
|
let
|
|
|
|
rng = keys.newRng()
|
|
|
|
conf = WakuNodeConf.load()
|
|
|
|
run(conf, rng)
|