Generic re-style with nph 0.5.1 (#2396)

This commit is contained in:
Ivan FB 2024-03-16 00:08:47 +01:00 committed by GitHub
parent dde94d4b52
commit cf6298ca1f
343 changed files with 17273 additions and 14393 deletions

View File

@ -10,18 +10,29 @@ else:
{.push raises: [].}
import std/[strformat, strutils, times, options, random]
import confutils, chronicles, chronos, stew/shims/net as stewNet,
eth/keys, bearssl, stew/[byteutils, results],
import
confutils,
chronicles,
chronos,
stew/shims/net as stewNet,
eth/keys,
bearssl,
stew/[byteutils, results],
metrics,
metrics/chronos_httpserver
import libp2p/[switch, # manage transports, a single entry point for dialing and listening
import
libp2p/[
switch, # manage transports, a single entry point for dialing and listening
crypto/crypto, # cryptographic functions
stream/connection, # create and close stream read / write connections
multiaddress, # encode different addressing schemes. For example, /ip4/7.7.7.7/tcp/6543 means it is using IPv4 protocol and TCP
peerinfo, # manage the information of a peer, such as peer ID and public / private key
multiaddress,
# encode different addressing schemes. For example, /ip4/7.7.7.7/tcp/6543 means it is using IPv4 protocol and TCP
peerinfo,
# manage the information of a peer, such as peer ID and public / private key
peerid, # Implement how peers interact
protobuf/minprotobuf, # message serialisation/deserialisation from and to protobufs
nameresolving/dnsresolver]# define DNS resolution
nameresolving/dnsresolver,
] # define DNS resolution
import
../../waku/waku_core,
../../waku/waku_lightpush/common,
@ -37,13 +48,11 @@ import
../../waku/common/utils/nat,
./config_chat2
import
libp2p/protocols/pubsub/rpc/messages,
libp2p/protocols/pubsub/pubsub
import
../../waku/waku_rln_relay
import libp2p/protocols/pubsub/rpc/messages, libp2p/protocols/pubsub/pubsub
import ../../waku/waku_rln_relay
const Help = """
const Help =
"""
Commands: /[?|help|connect|nick|exit]
help: Prints this help
connect: dials a remote peer
@ -128,15 +137,21 @@ proc getChatLine(c: Chat, msg:WakuMessage): Result[string, string]=
# No payload encoding/encryption from Waku
let
pb = Chat2Message.init(msg.payload)
chatLine = if pb.isOk: pb[].toString()
else: string.fromBytes(msg.payload)
chatLine =
if pb.isOk:
pb[].toString()
else:
string.fromBytes(msg.payload)
return ok(chatline)
proc printReceivedMessage(c: Chat, msg: WakuMessage) =
let
pb = Chat2Message.init(msg.payload)
chatLine = if pb.isOk: pb[].toString()
else: string.fromBytes(msg.payload)
chatLine =
if pb.isOk:
pb[].toString()
else:
string.fromBytes(msg.payload)
try:
echo &"{chatLine}"
except ValueError:
@ -145,8 +160,8 @@ proc printReceivedMessage(c: Chat, msg: WakuMessage) =
c.prompt = false
showChatPrompt(c)
trace "Printing message", topic=DefaultPubsubTopic, chatLine,
contentTopic = msg.contentTopic
trace "Printing message",
topic = DefaultPubsubTopic, chatLine, contentTopic = msg.contentTopic
proc readNick(transp: StreamTransport): Future[string] {.async.} =
# Chat prompt
@ -154,8 +169,9 @@ proc readNick(transp: StreamTransport): Future[string] {.async.} =
stdout.flushFile()
return await transp.readLine()
proc startMetricsServer(serverIp: IpAddress, serverPort: Port): Result[MetricsHttpServerRef, string] =
proc startMetricsServer(
serverIp: IpAddress, serverPort: Port
): Result[MetricsHttpServerRef, string] =
info "Starting metrics HTTP server", serverIp = $serverIp, serverPort = $serverPort
let metricsServerRes = MetricsHttpServerRef.new($serverIp, serverPort)
@ -171,20 +187,22 @@ proc startMetricsServer(serverIp: IpAddress, serverPort: Port): Result[MetricsHt
info "Metrics HTTP server started", serverIp = $serverIp, serverPort = $serverPort
ok(metricsServerRes.value)
proc publish(c: Chat, line: string) =
# First create a Chat2Message protobuf with this line of text
let time = getTime().toUnix()
let chat2pb = Chat2Message(timestamp: time,
nick: c.nick,
payload: line.toBytes()).encode()
let chat2pb =
Chat2Message(timestamp: time, nick: c.nick, payload: line.toBytes()).encode()
## @TODO: error handling on failure
proc handler(response: PushResponse) {.gcsafe, closure.} =
trace "lightpush response received", response = response
var message = WakuMessage(payload: chat2pb.buffer,
contentTopic: c.contentTopic, version: 0, timestamp: getNanosecondTime(time))
var message = WakuMessage(
payload: chat2pb.buffer,
contentTopic: c.contentTopic,
version: 0,
timestamp: getNanosecondTime(time),
)
if not isNil(c.node.wakuRlnRelay):
# for future version when we support more than one rln protected content topic,
# we should check the message content topic as well
@ -201,7 +219,8 @@ proc publish(c: Chat, line: string) =
# TODO move it to log after dogfooding
let msgEpoch = fromEpoch(proof.epoch)
if fromEpoch(c.node.wakuRlnRelay.lastEpoch) == msgEpoch:
echo "--rln epoch: ", msgEpoch, " ⚠️ message rate violation! you are spamming the network!"
echo "--rln epoch: ",
msgEpoch, " ⚠️ message rate violation! you are spamming the network!"
else:
echo "--rln epoch: ", msgEpoch
# update the last epoch
@ -259,19 +278,21 @@ proc writeAndPrint(c: Chat) {.async.} =
let address = await c.transp.readLine()
if address.len > 0:
await c.connectToNodes(@[address])
elif line.startsWith("/nick"):
# Set a new nickname
c.nick = await readNick(c.transp)
echo "You are now known as " & c.nick
elif line.startsWith("/exit"):
if not c.node.wakuFilterLegacy.isNil():
echo "unsubscribing from content filters..."
let peerOpt = c.node.peerManager.selectPeer(WakuLegacyFilterCodec)
if peerOpt.isSome():
await c.node.legacyFilterUnsubscribe(pubsubTopic=some(DefaultPubsubTopic), contentTopics=c.contentTopic, peer=peerOpt.get())
await c.node.legacyFilterUnsubscribe(
pubsubTopic = some(DefaultPubsubTopic),
contentTopics = c.contentTopic,
peer = peerOpt.get(),
)
echo "quitting..."
@ -307,21 +328,28 @@ proc readInput(wfd: AsyncFD) {.thread, raises: [Defect, CatchableError].} =
let line = stdin.readLine()
discard waitFor transp.write(line & "\r\n")
{.pop.} # @TODO confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError
{.pop.}
# @TODO confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError
proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
let
transp = fromPipe(rfd)
conf = Chat2Conf.load()
nodekey = if conf.nodekey.isSome(): conf.nodekey.get()
else: PrivateKey.random(Secp256k1, rng[]).tryGet()
nodekey =
if conf.nodekey.isSome():
conf.nodekey.get()
else:
PrivateKey.random(Secp256k1, rng[]).tryGet()
# set log level
if conf.logLevel != LogLevel.NONE:
setLogLevel(conf.logLevel)
let natRes = setupNat(conf.nat, clientId,
let natRes = setupNat(
conf.nat,
clientId,
Port(uint16(conf.tcpPort) + conf.portsShift),
Port(uint16(conf.udpPort) + conf.portsShift))
Port(uint16(conf.udpPort) + conf.portsShift),
)
if natRes.isErr():
raise newException(ValueError, "setupNat error " & natRes.error)
@ -335,17 +363,25 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
if recordRes.isErr():
error "failed to create enr record", error = recordRes.error
quit(QuitFailure)
else: recordRes.get()
else:
recordRes.get()
let node = block:
var builder = WakuNodeBuilder.init()
builder.withNodeKey(nodeKey)
builder.withRecord(record)
builder.withNetworkConfigurationDetails(conf.listenAddress, Port(uint16(conf.tcpPort) + conf.portsShift),
extIp, extTcpPort,
builder
.withNetworkConfigurationDetails(
conf.listenAddress,
Port(uint16(conf.tcpPort) + conf.portsShift),
extIp,
extTcpPort,
wsBindPort = Port(uint16(conf.websocketPort) + conf.portsShift),
wsEnabled = conf.websocketSupport,
wssEnabled = conf.websocketSecureSupport).tryGet()
wssEnabled = conf.websocketSecureSupport,
)
.tryGet()
builder.build().tryGet()
await node.start()
@ -361,14 +397,16 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
let nick = await readNick(transp)
echo "Welcome, " & nick & "!"
var chat = Chat(node: node,
var chat = Chat(
node: node,
transp: transp,
subscribed: true,
connected: false,
started: true,
nick: nick,
prompt: false,
contentTopic: conf.contentTopic)
contentTopic: conf.contentTopic,
)
if conf.staticnodes.len > 0:
echo "Connecting to static peers..."
@ -381,11 +419,14 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
echo "Connecting to " & $conf.fleet & " fleet using DNS discovery..."
if conf.fleet == Fleet.test:
dnsDiscoveryUrl = some("enrtree://AO47IDOLBKH72HIZZOXQP6NMRESAN7CHYWIBNXDXWRJRZWLODKII6@test.wakuv2.nodes.status.im")
dnsDiscoveryUrl = some(
"enrtree://AO47IDOLBKH72HIZZOXQP6NMRESAN7CHYWIBNXDXWRJRZWLODKII6@test.wakuv2.nodes.status.im"
)
else:
# Connect to prod by default
dnsDiscoveryUrl = some("enrtree://ANEDLO25QVUGJOUTQFRYKWX6P4Z4GKVESBMHML7DZ6YK4LGS5FC5O@prod.wakuv2.nodes.status.im")
dnsDiscoveryUrl = some(
"enrtree://ANEDLO25QVUGJOUTQFRYKWX6P4Z4GKVESBMHML7DZ6YK4LGS5FC5O@prod.wakuv2.nodes.status.im"
)
elif conf.dnsDiscovery and conf.dnsDiscoveryUrl != "":
# No pre-selected fleet. Discover nodes via DNS using user config
debug "Discovering nodes using Waku DNS discovery", url = conf.dnsDiscoveryUrl
@ -405,8 +446,7 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
let resolved = await dnsResolver.resolveTxt(domain)
return resolved[0] # Use only first answer
var wakuDnsDiscovery = WakuDnsDiscovery.init(dnsDiscoveryUrl.get(),
resolver)
var wakuDnsDiscovery = WakuDnsDiscovery.init(dnsDiscoveryUrl.get(), resolver)
if wakuDnsDiscovery.isOk:
let discoveredPeers = wakuDnsDiscovery.get().findPeers()
if discoveredPeers.isOk:
@ -432,7 +472,6 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
storenode = some(peerInfo.value)
else:
error "Incorrect conf.storenode", error = peerInfo.error
elif discoveredNodes.len > 0:
echo "Store enabled, but no store nodes configured. Choosing one at random from discovered peers"
storenode = some(discoveredNodes[rand(0 .. len(discoveredNodes) - 1)])
@ -448,8 +487,11 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
for msg in response.messages:
let
pb = Chat2Message.init(msg.payload)
chatLine = if pb.isOk: pb[].toString()
else: string.fromBytes(msg.payload)
chatLine =
if pb.isOk:
pb[].toString()
else:
string.fromBytes(msg.payload)
echo &"{chatLine}"
info "Hit store handler"
@ -476,19 +518,22 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
await node.mountFilterClient()
node.peerManager.addServicePeer(peerInfo.value, WakuLegacyFilterCodec)
proc filterHandler(pubsubTopic: PubsubTopic, msg: WakuMessage) {.async, gcsafe, closure.} =
proc filterHandler(
pubsubTopic: PubsubTopic, msg: WakuMessage
) {.async, gcsafe, closure.} =
trace "Hit filter handler", contentTopic = msg.contentTopic
chat.printReceivedMessage(msg)
await node.legacyFilterSubscribe(pubsubTopic=some(DefaultPubsubTopic),
await node.legacyFilterSubscribe(
pubsubTopic = some(DefaultPubsubTopic),
contentTopics = chat.contentTopic,
filterHandler,
peerInfo.value)
peerInfo.value,
)
# TODO: Here to support FilterV2 relevant subscription, but still
# Legacy Filter is concurrent to V2 untill legacy filter will be removed
else:
error "Filter not mounted. Couldn't parse conf.filternode",
error = peerInfo.error
error "Filter not mounted. Couldn't parse conf.filternode", error = peerInfo.error
# Subscribe to a topic, if relay is mounted
if conf.relay:
@ -524,7 +569,7 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
rlnRelayCredPath: conf.rlnRelayCredPath,
rlnRelayCredPassword: conf.rlnRelayCredPassword,
rlnRelayUserMessageLimit: conf.rlnRelayUserMessageLimit,
rlnEpochSizeSec: conf.rlnEpochSizeSec
rlnEpochSizeSec: conf.rlnEpochSizeSec,
)
else:
let rlnConf = WakuRlnConfig(
@ -534,16 +579,16 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress),
rlnRelayCredPath: conf.rlnRelayCredPath,
rlnRelayCredPassword: conf.rlnRelayCredPassword,
rlnEpochSizeSec: conf.rlnEpochSizeSec
rlnEpochSizeSec: conf.rlnEpochSizeSec,
)
waitFor node.mountRlnRelay(rlnConf,
spamHandler=some(spamHandler))
waitFor node.mountRlnRelay(rlnConf, spamHandler = some(spamHandler))
let membershipIndex = node.wakuRlnRelay.groupManager.membershipIndex.get()
let identityCredential = node.wakuRlnRelay.groupManager.idCredentials.get()
echo "your membership index is: ", membershipIndex
echo "your rln identity commitment key is: ", identityCredential.idCommitment.inHex()
echo "your rln identity commitment key is: ",
identityCredential.idCommitment.inHex()
else:
info "WakuRLNRelay is disabled"
echo "WakuRLNRelay is disabled, please enable it by passing in the --rln-relay flag"
@ -552,11 +597,9 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
if conf.metricsServer:
let metricsServer = startMetricsServer(
conf.metricsServerAddress,
Port(conf.metricsServerPort + conf.portsShift)
conf.metricsServerAddress, Port(conf.metricsServerPort + conf.portsShift)
)
await chat.readWriteLoop()
if conf.keepAlive:
@ -578,7 +621,6 @@ proc main(rng: ref HmacDrbgContext) {.async.} =
except ConfigurationError as e:
raise e
when isMainModule: # isMainModule = true when the module is compiled as the main file
let rng = crypto.newRng()
try:

View File

@ -1,254 +1,268 @@
import
chronicles, chronos,
confutils, confutils/defs, confutils/std/net,
chronicles,
chronos,
confutils,
confutils/defs,
confutils/std/net,
eth/keys,
libp2p/crypto/crypto,
libp2p/crypto/secp,
nimcrypto/utils,
std/strutils,
regex
import
../../../waku/waku_core
import ../../../waku/waku_core
type
Fleet* = enum
none
prod
test
EthRpcUrl = distinct string
Chat2Conf* = object
## General node config
Chat2Conf* = object ## General node config
logLevel* {.
desc: "Sets the log level."
defaultValue: LogLevel.INFO
name: "log-level" }: LogLevel
desc: "Sets the log level.", defaultValue: LogLevel.INFO, name: "log-level"
.}: LogLevel
nodekey* {.
desc: "P2P node private key as 64 char hex string.",
name: "nodekey" }: Option[crypto.PrivateKey]
nodekey* {.desc: "P2P node private key as 64 char hex string.", name: "nodekey".}:
Option[crypto.PrivateKey]
listenAddress* {.
defaultValue: defaultListenAddress(config)
desc: "Listening address for the LibP2P traffic."
name: "listen-address"}: IpAddress
defaultValue: defaultListenAddress(config),
desc: "Listening address for the LibP2P traffic.",
name: "listen-address"
.}: IpAddress
tcpPort* {.
desc: "TCP listening port."
defaultValue: 60000
name: "tcp-port" }: Port
tcpPort* {.desc: "TCP listening port.", defaultValue: 60000, name: "tcp-port".}:
Port
udpPort* {.
desc: "UDP listening port."
defaultValue: 60000
name: "udp-port" }: Port
udpPort* {.desc: "UDP listening port.", defaultValue: 60000, name: "udp-port".}:
Port
portsShift* {.
desc: "Add a shift to all port numbers."
defaultValue: 0
name: "ports-shift" }: uint16
desc: "Add a shift to all port numbers.", defaultValue: 0, name: "ports-shift"
.}: uint16
nat* {.
desc: "Specify method to use for determining public address. " &
"Must be one of: any, none, upnp, pmp, extip:<IP>."
defaultValue: "any" }: string
desc:
"Specify method to use for determining public address. " &
"Must be one of: any, none, upnp, pmp, extip:<IP>.",
defaultValue: "any"
.}: string
## Persistence config
dbPath* {.
desc: "The database path for peristent storage",
defaultValue: ""
name: "db-path" }: string
desc: "The database path for peristent storage", defaultValue: "", name: "db-path"
.}: string
persistPeers* {.
desc: "Enable peer persistence: true|false",
defaultValue: false
name: "persist-peers" }: bool
defaultValue: false,
name: "persist-peers"
.}: bool
persistMessages* {.
desc: "Enable message persistence: true|false",
defaultValue: false
name: "persist-messages" }: bool
defaultValue: false,
name: "persist-messages"
.}: bool
## Relay config
relay* {.
desc: "Enable relay protocol: true|false",
defaultValue: true
name: "relay" }: bool
desc: "Enable relay protocol: true|false", defaultValue: true, name: "relay"
.}: bool
staticnodes* {.
desc: "Peer multiaddr to directly connect with. Argument may be repeated."
name: "staticnode" }: seq[string]
desc: "Peer multiaddr to directly connect with. Argument may be repeated.",
name: "staticnode"
.}: seq[string]
keepAlive* {.
desc: "Enable keep-alive for idle connections: true|false",
defaultValue: false
name: "keep-alive" }: bool
defaultValue: false,
name: "keep-alive"
.}: bool
topics* {.
desc: "Default topics to subscribe to (space separated list)."
defaultValue: "/waku/2/default-waku/proto"
name: "topics" .}: string
desc: "Default topics to subscribe to (space separated list).",
defaultValue: "/waku/2/default-waku/proto",
name: "topics"
.}: string
## Store config
store* {.
desc: "Enable store protocol: true|false",
defaultValue: true
name: "store" }: bool
desc: "Enable store protocol: true|false", defaultValue: true, name: "store"
.}: bool
storenode* {.
desc: "Peer multiaddr to query for storage.",
defaultValue: ""
name: "storenode" }: string
desc: "Peer multiaddr to query for storage.", defaultValue: "", name: "storenode"
.}: string
## Filter config
filter* {.
desc: "Enable filter protocol: true|false",
defaultValue: false
name: "filter" }: bool
desc: "Enable filter protocol: true|false", defaultValue: false, name: "filter"
.}: bool
filternode* {.
desc: "Peer multiaddr to request content filtering of messages.",
defaultValue: ""
name: "filternode" }: string
defaultValue: "",
name: "filternode"
.}: string
## Lightpush config
lightpush* {.
desc: "Enable lightpush protocol: true|false",
defaultValue: false
name: "lightpush" }: bool
defaultValue: false,
name: "lightpush"
.}: bool
lightpushnode* {.
desc: "Peer multiaddr to request lightpush of published messages.",
defaultValue: ""
name: "lightpushnode" }: string
defaultValue: "",
name: "lightpushnode"
.}: string
## Metrics config
metricsServer* {.
desc: "Enable the metrics server: true|false"
defaultValue: false
name: "metrics-server" }: bool
desc: "Enable the metrics server: true|false",
defaultValue: false,
name: "metrics-server"
.}: bool
metricsServerAddress* {.
desc: "Listening address of the metrics server."
defaultValue: parseIpAddress("127.0.0.1")
name: "metrics-server-address" }: IpAddress
desc: "Listening address of the metrics server.",
defaultValue: parseIpAddress("127.0.0.1"),
name: "metrics-server-address"
.}: IpAddress
metricsServerPort* {.
desc: "Listening HTTP port of the metrics server."
defaultValue: 8008
name: "metrics-server-port" }: uint16
desc: "Listening HTTP port of the metrics server.",
defaultValue: 8008,
name: "metrics-server-port"
.}: uint16
metricsLogging* {.
desc: "Enable metrics logging: true|false"
defaultValue: true
name: "metrics-logging" }: bool
desc: "Enable metrics logging: true|false",
defaultValue: true,
name: "metrics-logging"
.}: bool
## DNS discovery config
dnsDiscovery* {.
desc: "Enable discovering nodes via DNS"
defaultValue: false
name: "dns-discovery" }: bool
desc: "Enable discovering nodes via DNS",
defaultValue: false,
name: "dns-discovery"
.}: bool
dnsDiscoveryUrl* {.
desc: "URL for DNS node list in format 'enrtree://<key>@<fqdn>'",
defaultValue: ""
name: "dns-discovery-url" }: string
defaultValue: "",
name: "dns-discovery-url"
.}: string
dnsDiscoveryNameServers* {.
desc: "DNS name server IPs to query. Argument may be repeated."
defaultValue: @[parseIpAddress("1.1.1.1"), parseIpAddress("1.0.0.1")]
name: "dns-discovery-name-server" }: seq[IpAddress]
desc: "DNS name server IPs to query. Argument may be repeated.",
defaultValue: @[parseIpAddress("1.1.1.1"), parseIpAddress("1.0.0.1")],
name: "dns-discovery-name-server"
.}: seq[IpAddress]
## Chat2 configuration
fleet* {.
desc: "Select the fleet to connect to. This sets the DNS discovery URL to the selected fleet."
defaultValue: Fleet.prod
name: "fleet" }: Fleet
desc:
"Select the fleet to connect to. This sets the DNS discovery URL to the selected fleet.",
defaultValue: Fleet.prod,
name: "fleet"
.}: Fleet
contentTopic* {.
desc: "Content topic for chat messages."
defaultValue: "/toy-chat/2/huilong/proto"
name: "content-topic" }: string
desc: "Content topic for chat messages.",
defaultValue: "/toy-chat/2/huilong/proto",
name: "content-topic"
.}: string
## Websocket Configuration
websocketSupport* {.
desc: "Enable websocket: true|false",
defaultValue: false
name: "websocket-support"}: bool
defaultValue: false,
name: "websocket-support"
.}: bool
websocketPort* {.
desc: "WebSocket listening port."
defaultValue: 8000
name: "websocket-port" }: Port
desc: "WebSocket listening port.", defaultValue: 8000, name: "websocket-port"
.}: Port
websocketSecureSupport* {.
desc: "WebSocket Secure Support."
defaultValue: false
name: "websocket-secure-support" }: bool
desc: "WebSocket Secure Support.",
defaultValue: false,
name: "websocket-secure-support"
.}: bool
## rln-relay configuration
rlnRelay* {.
desc: "Enable spam protection through rln-relay: true|false",
defaultValue: false
name: "rln-relay" }: bool
defaultValue: false,
name: "rln-relay"
.}: bool
rlnRelayCredPath* {.
desc: "The path for peristing rln-relay credential",
defaultValue: ""
name: "rln-relay-cred-path" }: string
defaultValue: "",
name: "rln-relay-cred-path"
.}: string
rlnRelayCredIndex* {.
desc: "the index of the onchain commitment to use",
name: "rln-relay-cred-index" }: Option[uint]
desc: "the index of the onchain commitment to use", name: "rln-relay-cred-index"
.}: Option[uint]
rlnRelayDynamic* {.
desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false",
defaultValue: false
name: "rln-relay-dynamic" }: bool
defaultValue: false,
name: "rln-relay-dynamic"
.}: bool
rlnRelayIdKey* {.
desc: "Rln relay identity secret key as a Hex string",
defaultValue: ""
name: "rln-relay-id-key" }: string
defaultValue: "",
name: "rln-relay-id-key"
.}: string
rlnRelayIdCommitmentKey* {.
desc: "Rln relay identity commitment key as a Hex string",
defaultValue: ""
name: "rln-relay-id-commitment-key" }: string
defaultValue: "",
name: "rln-relay-id-commitment-key"
.}: string
rlnRelayEthClientAddress* {.
desc: "HTTP address of an Ethereum testnet client e.g., http://localhost:8540/",
defaultValue: "http://localhost:8540/"
name: "rln-relay-eth-client-address" }: EthRpcUrl
defaultValue: "http://localhost:8540/",
name: "rln-relay-eth-client-address"
.}: EthRpcUrl
rlnRelayEthContractAddress* {.
desc: "Address of membership contract on an Ethereum testnet",
defaultValue: ""
name: "rln-relay-eth-contract-address" }: string
defaultValue: "",
name: "rln-relay-eth-contract-address"
.}: string
rlnRelayCredPassword* {.
desc: "Password for encrypting RLN credentials",
defaultValue: ""
name: "rln-relay-cred-password" }: string
defaultValue: "",
name: "rln-relay-cred-password"
.}: string
rlnRelayUserMessageLimit* {.
desc: "Set a user message limit for the rln membership registration. Must be a positive integer. Default is 1.",
desc:
"Set a user message limit for the rln membership registration. Must be a positive integer. Default is 1.",
defaultValue: 1,
name: "rln-relay-user-message-limit" .}: uint64
name: "rln-relay-user-message-limit"
.}: uint64
rlnEpochSizeSec* {.
desc: "Epoch size in seconds used to rate limit RLN memberships. Default is 1 second.",
defaultValue: 1
name: "rln-relay-epoch-sec" .}: uint64
desc:
"Epoch size in seconds used to rate limit RLN memberships. Default is 1 second.",
defaultValue: 1,
name: "rln-relay-epoch-sec"
.}: uint64
# NOTE: Keys are different in nim-libp2p
proc parseCmdArg*(T: type crypto.PrivateKey, p: string): T =
@ -300,10 +314,14 @@ proc parseCmdArg*(T: type EthRpcUrl, s: string): T =
## https://url:port/path?query
## disallowed patterns:
## any valid/invalid ws or wss url
var httpPattern = re2"^(https?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*"
var wsPattern = re2"^(wss?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*"
var httpPattern =
re2"^(https?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*"
var wsPattern =
re2"^(wss?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*"
if regex.match(s, wsPattern):
raise newException(ValueError, "Websocket RPC URL is not supported, Please use an HTTP URL")
raise newException(
ValueError, "Websocket RPC URL is not supported, Please use an HTTP URL"
)
if not regex.match(s, httpPattern):
raise newException(ValueError, "Invalid HTTP RPC URL")
return EthRpcUrl(s)

View File

@ -5,8 +5,13 @@ else:
import
std/[tables, times, strutils, hashes, sequtils],
chronos, confutils, chronicles, chronicles/topics_registry, chronos/streams/tlsstream,
metrics, metrics/chronos_httpserver,
chronos,
confutils,
chronicles,
chronicles/topics_registry,
chronos/streams/tlsstream,
metrics,
metrics/chronos_httpserver,
stew/byteutils,
eth/net/nat,
json_rpc/rpcserver,
@ -27,7 +32,8 @@ import
# Common cli config
./config_chat2bridge
declarePublicCounter chat2_mb_transfers, "Number of messages transferred between chat2 and Matterbridge", ["type"]
declarePublicCounter chat2_mb_transfers,
"Number of messages transferred between chat2 and Matterbridge", ["type"]
declarePublicCounter chat2_mb_dropped, "Number of messages dropped", ["reason"]
logScope:
@ -37,8 +43,7 @@ logScope:
# Default values #
##################
const
DeduplQSize = 20 # Maximum number of seen messages to keep in deduplication queue
const DeduplQSize = 20 # Maximum number of seen messages to keep in deduplication queue
#########
# Types #
@ -71,19 +76,21 @@ proc containsOrAdd(sequence: var seq[Hash], hash: Hash): bool =
return false
proc toWakuMessage(cmb: Chat2MatterBridge, jsonNode: JsonNode): WakuMessage {.raises: [Defect, KeyError]} =
proc toWakuMessage(
cmb: Chat2MatterBridge, jsonNode: JsonNode
): WakuMessage {.raises: [Defect, KeyError].} =
# Translates a Matterbridge API JSON response to a Waku v2 message
let msgFields = jsonNode.getFields()
# @TODO error handling here - verify expected fields
let chat2pb = Chat2Message(timestamp: getTime().toUnix(), # @TODO use provided timestamp
let chat2pb = Chat2Message(
timestamp: getTime().toUnix(), # @TODO use provided timestamp
nick: msgFields["username"].getStr(),
payload: msgFields["text"].getStr().toBytes()).encode()
payload: msgFields["text"].getStr().toBytes(),
).encode()
WakuMessage(payload: chat2pb.buffer,
contentTopic: cmb.contentTopic,
version: 0)
WakuMessage(payload: chat2pb.buffer, contentTopic: cmb.contentTopic, version: 0)
proc toChat2(cmb: Chat2MatterBridge, jsonNode: JsonNode) {.async.} =
let msg = cmb.toWakuMessage(jsonNode)
@ -100,7 +107,9 @@ proc toChat2(cmb: Chat2MatterBridge, jsonNode: JsonNode) {.async.} =
(await cmb.nodev2.publish(some(DefaultPubsubTopic), msg)).isOkOr:
error "failed to publish message", error = error
proc toMatterbridge(cmb: Chat2MatterBridge, msg: WakuMessage) {.gcsafe, raises: [Exception].} =
proc toMatterbridge(
cmb: Chat2MatterBridge, msg: WakuMessage
) {.gcsafe, raises: [Exception].} =
if cmb.seen.containsOrAdd(msg.payload.hash()):
# This is a duplicate message. Return.
chat2_mb_dropped.inc(labelValues = ["duplicate"])
@ -119,8 +128,9 @@ proc toMatterbridge(cmb: Chat2MatterBridge, msg: WakuMessage) {.gcsafe, raises:
assert chat2Msg.isOk
let postRes = cmb.mbClient.postMessage(text = string.fromBytes(chat2Msg[].payload),
username = chat2Msg[].nick)
let postRes = cmb.mbClient.postMessage(
text = string.fromBytes(chat2Msg[].payload), username = chat2Msg[].nick
)
if postRes.isErr() or (postRes[] == false):
chat2_mb_dropped.inc(labelValues = ["duplicate"])
@ -142,20 +152,23 @@ proc pollMatterbridge(cmb: Chat2MatterBridge, handler: MbMessageHandler) {.async
##############
# Public API #
##############
proc new*(T: type Chat2MatterBridge,
proc new*(
T: type Chat2MatterBridge,
# Matterbridge initialisation
mbHostUri: string,
mbGateway: string,
# NodeV2 initialisation
nodev2Key: crypto.PrivateKey,
nodev2BindIp: IpAddress, nodev2BindPort: Port,
nodev2ExtIp = none[IpAddress](), nodev2ExtPort = none[Port](),
contentTopic: string): T
{.raises: [Defect, ValueError, KeyError, TLSStreamProtocolError, IOError, LPError].} =
nodev2BindIp: IpAddress,
nodev2BindPort: Port,
nodev2ExtIp = none[IpAddress](),
nodev2ExtPort = none[Port](),
contentTopic: string,
): T {.
raises: [Defect, ValueError, KeyError, TLSStreamProtocolError, IOError, LPError]
.} =
# Setup Matterbridge
let
mbClient = MatterbridgeClient.new(mbHostUri, mbGateway)
let mbClient = MatterbridgeClient.new(mbHostUri, mbGateway)
# Let's verify the Matterbridge configuration before continuing
let clientHealth = mbClient.isHealthy()
@ -169,14 +182,20 @@ proc new*(T: type Chat2MatterBridge,
let nodev2 = block:
var builder = WakuNodeBuilder.init()
builder.withNodeKey(nodev2Key)
builder.withNetworkConfigurationDetails(nodev2BindIp, nodev2BindPort, nodev2ExtIp, nodev2ExtPort).tryGet()
builder
.withNetworkConfigurationDetails(
nodev2BindIp, nodev2BindPort, nodev2ExtIp, nodev2ExtPort
)
.tryGet()
builder.build().tryGet()
return Chat2MatterBridge(mbClient: mbClient,
return Chat2MatterBridge(
mbClient: mbClient,
nodev2: nodev2,
running: false,
pollPeriod: chronos.seconds(1),
contentTopic: contentTopic)
contentTopic: contentTopic,
)
proc start*(cmb: Chat2MatterBridge) {.async.} =
info "Starting Chat2MatterBridge"
@ -203,7 +222,9 @@ proc start*(cmb: Chat2MatterBridge) {.async.} =
# Bridging
# Handle messages on Waku v2 and bridge to Matterbridge
proc relayHandler(pubsubTopic: PubsubTopic, msg: WakuMessage): Future[void] {.async.} =
proc relayHandler(
pubsubTopic: PubsubTopic, msg: WakuMessage
): Future[void] {.async.} =
trace "Bridging message from Chat2 to Matterbridge", msg = msg
try:
cmb.toMatterbridge(msg)
@ -219,11 +240,10 @@ proc stop*(cmb: Chat2MatterBridge) {.async: (raises: [Exception]).} =
await cmb.nodev2.stop()
{.pop.} # @TODO confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError
{.pop.}
# @TODO confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError
when isMainModule:
import
../../../waku/common/utils/nat,
../../waku/waku_api/message_cache
import ../../../waku/common/utils/nat, ../../waku/waku_api/message_cache
let
rng = newRng()
@ -232,9 +252,12 @@ when isMainModule:
if conf.logLevel != LogLevel.NONE:
setLogLevel(conf.logLevel)
let natRes = setupNat(conf.nat, clientId,
let natRes = setupNat(
conf.nat,
clientId,
Port(uint16(conf.libp2pTcpPort) + conf.portsShift),
Port(uint16(conf.udpPort) + conf.portsShift))
Port(uint16(conf.udpPort) + conf.portsShift),
)
if natRes.isErr():
error "Error in setupNat", error = natRes.error
@ -243,19 +266,22 @@ when isMainModule:
(nodev2ExtIp, nodev2ExtPort, _) = natRes.get()
## The following heuristic assumes that, in absence of manual
## config, the external port is the same as the bind port.
extPort = if nodev2ExtIp.isSome() and nodev2ExtPort.isNone():
extPort =
if nodev2ExtIp.isSome() and nodev2ExtPort.isNone():
some(Port(uint16(conf.libp2pTcpPort) + conf.portsShift))
else:
nodev2ExtPort
let
bridge = Chat2Matterbridge.new(
let bridge = Chat2Matterbridge.new(
mbHostUri = "http://" & $initTAddress(conf.mbHostAddress, Port(conf.mbHostPort)),
mbGateway = conf.mbGateway,
nodev2Key = conf.nodekey,
nodev2BindIp = conf.listenAddress, nodev2BindPort = Port(uint16(conf.libp2pTcpPort) + conf.portsShift),
nodev2ExtIp = nodev2ExtIp, nodev2ExtPort = extPort,
contentTopic = conf.contentTopic)
nodev2BindIp = conf.listenAddress,
nodev2BindPort = Port(uint16(conf.libp2pTcpPort) + conf.portsShift),
nodev2ExtIp = nodev2ExtIp,
nodev2ExtPort = extPort,
contentTopic = conf.contentTopic,
)
waitFor bridge.start()
@ -284,7 +310,9 @@ when isMainModule:
let filterPeer = parsePeerInfo(conf.filternode)
if filterPeer.isOk():
bridge.nodev2.peerManager.addServicePeer(filterPeer.value, WakuLegacyFilterCodec)
bridge.nodev2.peerManager.addServicePeer(filterPeer.value, WakuFilterSubscribeCodec)
bridge.nodev2.peerManager.addServicePeer(
filterPeer.value, WakuFilterSubscribeCodec
)
else:
error "Error parsing conf.filternode", error = filterPeer.error

View File

@ -1,118 +1,125 @@
import
confutils, confutils/defs, confutils/std/net, chronicles, chronos,
confutils,
confutils/defs,
confutils/std/net,
chronicles,
chronos,
libp2p/crypto/[crypto, secp],
eth/keys
type
Chat2MatterbridgeConf* = object
type Chat2MatterbridgeConf* = object
logLevel* {.
desc: "Sets the log level"
defaultValue: LogLevel.INFO
name: "log-level" .}: LogLevel
desc: "Sets the log level", defaultValue: LogLevel.INFO, name: "log-level"
.}: LogLevel
listenAddress* {.
defaultValue: defaultListenAddress(config)
desc: "Listening address for the LibP2P traffic"
name: "listen-address"}: IpAddress
defaultValue: defaultListenAddress(config),
desc: "Listening address for the LibP2P traffic",
name: "listen-address"
.}: IpAddress
libp2pTcpPort* {.
desc: "Libp2p TCP listening port (for Waku v2)"
defaultValue: 9000
name: "libp2p-tcp-port" .}: uint16
desc: "Libp2p TCP listening port (for Waku v2)",
defaultValue: 9000,
name: "libp2p-tcp-port"
.}: uint16
udpPort* {.
desc: "UDP listening port"
defaultValue: 9000
name: "udp-port" .}: uint16
udpPort* {.desc: "UDP listening port", defaultValue: 9000, name: "udp-port".}: uint16
portsShift* {.
desc: "Add a shift to all default port numbers"
defaultValue: 0
name: "ports-shift" .}: uint16
desc: "Add a shift to all default port numbers",
defaultValue: 0,
name: "ports-shift"
.}: uint16
nat* {.
desc: "Specify method to use for determining public address. " &
"Must be one of: any, none, upnp, pmp, extip:<IP>"
defaultValue: "any" .}: string
desc:
"Specify method to use for determining public address. " &
"Must be one of: any, none, upnp, pmp, extip:<IP>",
defaultValue: "any"
.}: string
metricsServer* {.
desc: "Enable the metrics server"
defaultValue: false
name: "metrics-server" .}: bool
desc: "Enable the metrics server", defaultValue: false, name: "metrics-server"
.}: bool
metricsServerAddress* {.
desc: "Listening address of the metrics server"
defaultValue: parseIpAddress("127.0.0.1")
name: "metrics-server-address" }: IpAddress
desc: "Listening address of the metrics server",
defaultValue: parseIpAddress("127.0.0.1"),
name: "metrics-server-address"
.}: IpAddress
metricsServerPort* {.
desc: "Listening HTTP port of the metrics server"
defaultValue: 8008
name: "metrics-server-port" .}: uint16
desc: "Listening HTTP port of the metrics server",
defaultValue: 8008,
name: "metrics-server-port"
.}: uint16
### Waku v2 options
staticnodes* {.
desc: "Multiaddr of peer to directly connect with. Argument may be repeated"
name: "staticnode" }: seq[string]
desc: "Multiaddr of peer to directly connect with. Argument may be repeated",
name: "staticnode"
.}: seq[string]
nodekey* {.
desc: "P2P node private key as hex"
defaultValue: crypto.PrivateKey.random(Secp256k1, newRng()[]).tryGet()
name: "nodekey" }: crypto.PrivateKey
desc: "P2P node private key as hex",
defaultValue: crypto.PrivateKey.random(Secp256k1, newRng()[]).tryGet(),
name: "nodekey"
.}: crypto.PrivateKey
topics* {.
desc: "Default topics to subscribe to (space separated list)"
defaultValue: "/waku/2/default-waku/proto"
name: "topics" .}: string
desc: "Default topics to subscribe to (space separated list)",
defaultValue: "/waku/2/default-waku/proto",
name: "topics"
.}: string
store* {.
desc: "Flag whether to start store protocol",
defaultValue: true
name: "store" }: bool
desc: "Flag whether to start store protocol", defaultValue: true, name: "store"
.}: bool
filter* {.
desc: "Flag whether to start filter protocol",
defaultValue: false
name: "filter" }: bool
desc: "Flag whether to start filter protocol", defaultValue: false, name: "filter"
.}: bool
relay* {.
desc: "Flag whether to start relay protocol",
defaultValue: true
name: "relay" }: bool
desc: "Flag whether to start relay protocol", defaultValue: true, name: "relay"
.}: bool
storenode* {.
desc: "Multiaddr of peer to connect with for waku store protocol"
defaultValue: ""
name: "storenode" }: string
desc: "Multiaddr of peer to connect with for waku store protocol",
defaultValue: "",
name: "storenode"
.}: string
filternode* {.
desc: "Multiaddr of peer to connect with for waku filter protocol"
defaultValue: ""
name: "filternode" }: string
desc: "Multiaddr of peer to connect with for waku filter protocol",
defaultValue: "",
name: "filternode"
.}: string
# Matterbridge options
mbHostAddress* {.
desc: "Listening address of the Matterbridge host",
defaultValue: parseIpAddress("127.0.0.1")
name: "mb-host-address" }: IpAddress
defaultValue: parseIpAddress("127.0.0.1"),
name: "mb-host-address"
.}: IpAddress
mbHostPort* {.
desc: "Listening port of the Matterbridge host",
defaultValue: 4242
name: "mb-host-port" }: uint16
defaultValue: 4242,
name: "mb-host-port"
.}: uint16
mbGateway* {.
desc: "Matterbridge gateway"
defaultValue: "gateway1"
name: "mb-gateway" }: string
desc: "Matterbridge gateway", defaultValue: "gateway1", name: "mb-gateway"
.}: string
## Chat2 options
contentTopic* {.
desc: "Content topic to bridge chat messages to."
defaultValue: "/toy-chat/2/huilong/proto"
name: "content-topic" }: string
desc: "Content topic to bridge chat messages to.",
defaultValue: "/toy-chat/2/huilong/proto",
name: "content-topic"
.}: string
proc parseCmdArg*(T: type keys.KeyPair, p: string): T =
try:

View File

@ -44,18 +44,21 @@ const AvgPingWindow = 10.0
const git_version* {.strdefine.} = "n/a"
proc setDiscoveredPeersCapabilities(
routingTableNodes: seq[Node]) =
proc setDiscoveredPeersCapabilities(routingTableNodes: seq[Node]) =
for capability in @[Relay, Store, Filter, Lightpush]:
let nOfNodesWithCapability = routingTableNodes.countIt(it.record.supportsCapability(capability))
info "capabilities as per ENR waku flag", capability=capability, amount=nOfNodesWithCapability
networkmonitor_peer_type_as_per_enr.set(int64(nOfNodesWithCapability), labelValues = [$capability])
let nOfNodesWithCapability =
routingTableNodes.countIt(it.record.supportsCapability(capability))
info "capabilities as per ENR waku flag",
capability = capability, amount = nOfNodesWithCapability
networkmonitor_peer_type_as_per_enr.set(
int64(nOfNodesWithCapability), labelValues = [$capability]
)
proc analyzePeer(
customPeerInfo: CustomPeerInfoRef,
peerInfo: RemotePeerInfo,
node: WakuNode,
timeout: chronos.Duration
timeout: chronos.Duration,
): Future[Result[string, string]] {.async.} =
var pingDelay: chronos.Duration
@ -64,7 +67,6 @@ proc analyzePeer(
let conn = await node.switch.dial(peerInfo.peerId, peerInfo.addrs, PingCodec)
pingDelay = await node.libp2pPing.ping(conn)
return ok()
except CatchableError:
var msg = getCurrentExceptionMsg()
if msg == "Future operation cancelled!":
@ -88,16 +90,23 @@ proc analyzePeer(
customPeerInfo.avgPingDuration = pingDelay
# TODO: check why the calculation ends up losing precision
customPeerInfo.avgPingDuration = int64((float64(customPeerInfo.avgPingDuration.millis) * (AvgPingWindow - 1.0) + float64(pingDelay.millis)) / AvgPingWindow).millis
customPeerInfo.avgPingDuration = int64(
(
float64(customPeerInfo.avgPingDuration.millis) * (AvgPingWindow - 1.0) +
float64(pingDelay.millis)
) / AvgPingWindow
).millis
customPeerInfo.lastPingDuration = pingDelay
return ok(customPeerInfo.peerId)
proc shouldReconnect(customPeerInfo: CustomPeerInfoRef): bool =
let reconnetIntervalCheck = getTime().toUnix() >= customPeerInfo.lastTimeConnected + ReconnectTime
let reconnetIntervalCheck =
getTime().toUnix() >= customPeerInfo.lastTimeConnected + ReconnectTime
var retriesCheck = customPeerInfo.retries < MaxConnectionRetries
if not retriesCheck and getTime().toUnix() >= customPeerInfo.lastTimeConnected + ResetRetriesAfter:
if not retriesCheck and
getTime().toUnix() >= customPeerInfo.lastTimeConnected + ResetRetriesAfter:
customPeerInfo.retries = 0
retriesCheck = true
info "resetting retries counter", peerId = customPeerInfo.peerId
@ -105,12 +114,13 @@ proc shouldReconnect(customPeerInfo: CustomPeerInfoRef): bool =
return reconnetIntervalCheck and retriesCheck
# TODO: Split in discover, connect
proc setConnectedPeersMetrics(discoveredNodes: seq[Node],
proc setConnectedPeersMetrics(
discoveredNodes: seq[Node],
node: WakuNode,
timeout: chronos.Duration,
restClient: RestClientRef,
allPeers: CustomPeersTableRef) {.async.} =
allPeers: CustomPeersTableRef,
) {.async.} =
let currentTime = getTime().toUnix()
var newPeers = 0
@ -132,7 +142,7 @@ proc setConnectedPeersMetrics(discoveredNodes: seq[Node],
let peerRes = toRemotePeerInfo(discNode.record)
let peerInfo = peerRes.valueOr():
let peerInfo = peerRes.valueOr:
warn "error converting record to remote peer info", record = discNode.record
continue
@ -162,7 +172,8 @@ proc setConnectedPeersMetrics(discoveredNodes: seq[Node],
# try to ping the peer
if shouldReconnect(customPeerInfo):
if customPeerInfo.retries > 0:
warn "trying to dial failed peer again", peerId=peerId, retry=customPeerInfo.retries
warn "trying to dial failed peer again",
peerId = peerId, retry = customPeerInfo.retries
analyzeFuts.add(analyzePeer(customPeerInfo, peerInfo, node, timeout))
# Wait for all connection attempts to finish
@ -170,11 +181,11 @@ proc setConnectedPeersMetrics(discoveredNodes: seq[Node],
for peerIdFut in analyzedPeers:
let peerIdRes = await peerIdFut
let peerIdStr = peerIdRes.valueOr():
let peerIdStr = peerIdRes.valueOr:
continue
successfulConnections += 1
let peerId = PeerId.init(peerIdStr).valueOr():
let peerId = PeerId.init(peerIdStr).valueOr:
warn "failed to parse peerId", peerId = peerIdStr
continue
var customPeerInfo = allPeers[peerIdStr]
@ -208,7 +219,8 @@ proc updateMetrics(allPeersRef: CustomPeersTableRef) {.gcsafe.} =
allProtocols[protocol] = allProtocols.mgetOrPut(protocol, 0) + 1
# store available user-agents in the network
allAgentStrings[peerInfo.userAgent] = allAgentStrings.mgetOrPut(peerInfo.userAgent, 0) + 1
allAgentStrings[peerInfo.userAgent] =
allAgentStrings.mgetOrPut(peerInfo.userAgent, 0) + 1
if peerInfo.country != "":
countries[peerInfo.country] = countries.mgetOrPut(peerInfo.country, 0) + 1
@ -222,22 +234,29 @@ proc updateMetrics(allPeersRef: CustomPeersTableRef) {.gcsafe.} =
# update count on each protocol
for protocol in allProtocols.keys():
let countOfProtocols = allProtocols.mgetOrPut(protocol, 0)
networkmonitor_peer_type_as_per_protocol.set(int64(countOfProtocols), labelValues = [protocol])
info "supported protocols in the network", protocol=protocol, count=countOfProtocols
networkmonitor_peer_type_as_per_protocol.set(
int64(countOfProtocols), labelValues = [protocol]
)
info "supported protocols in the network",
protocol = protocol, count = countOfProtocols
# update count on each user-agent
for userAgent in allAgentStrings.keys():
let countOfUserAgent = allAgentStrings.mgetOrPut(userAgent, 0)
networkmonitor_peer_user_agents.set(int64(countOfUserAgent), labelValues = [userAgent])
info "user agents participating in the network", userAgent=userAgent, count=countOfUserAgent
networkmonitor_peer_user_agents.set(
int64(countOfUserAgent), labelValues = [userAgent]
)
info "user agents participating in the network",
userAgent = userAgent, count = countOfUserAgent
for country in countries.keys():
let peerCount = countries.mgetOrPut(country, 0)
networkmonitor_peer_country_count.set(int64(peerCount), labelValues = [country])
info "number of peers per country", country = country, count = peerCount
proc populateInfoFromIp(allPeersRef: CustomPeersTableRef,
restClient: RestClientRef) {.async.} =
proc populateInfoFromIp(
allPeersRef: CustomPeersTableRef, restClient: RestClientRef
) {.async.} =
for peer in allPeersRef.keys():
if allPeersRef[peer].country != "" and allPeersRef[peer].city != "":
continue
@ -260,12 +279,13 @@ proc populateInfoFromIp(allPeersRef: CustomPeersTableRef,
# TODO: Split in discovery, connections, and ip2location
# crawls the network discovering peers and trying to connect to them
# metrics are processed and exposed
proc crawlNetwork(node: WakuNode,
proc crawlNetwork(
node: WakuNode,
wakuDiscv5: WakuDiscoveryV5,
restClient: RestClientRef,
conf: NetworkMonitorConf,
allPeersRef: CustomPeersTableRef) {.async.} =
allPeersRef: CustomPeersTableRef,
) {.async.} =
let crawlInterval = conf.refreshInterval * 1000
while true:
let startTime = Moment.now()
@ -281,7 +301,9 @@ proc crawlNetwork(node: WakuNode,
# tries to connect to all newly discovered nodes
# and populates metrics related to peers we could connect
# note random discovered nodes can be already known
await setConnectedPeersMetrics(discoveredNodes, node, conf.timeout, restClient, allPeersRef)
await setConnectedPeersMetrics(
discoveredNodes, node, conf.timeout, restClient, allPeersRef
)
updateMetrics(allPeersRef)
@ -303,7 +325,9 @@ proc crawlNetwork(node: WakuNode,
await sleepAsync(crawlInterval.millis - elapsed.millis)
proc retrieveDynamicBootstrapNodes(dnsDiscovery: bool, dnsDiscoveryUrl: string, dnsDiscoveryNameServers: seq[IpAddress]): Result[seq[RemotePeerInfo], string] =
proc retrieveDynamicBootstrapNodes(
dnsDiscovery: bool, dnsDiscoveryUrl: string, dnsDiscoveryNameServers: seq[IpAddress]
): Result[seq[RemotePeerInfo], string] =
if dnsDiscovery and dnsDiscoveryUrl != "":
# DNS discovery
debug "Discovering nodes using Waku DNS discovery", url = dnsDiscoveryUrl
@ -321,18 +345,23 @@ proc retrieveDynamicBootstrapNodes(dnsDiscovery: bool, dnsDiscoveryUrl: string,
var wakuDnsDiscovery = WakuDnsDiscovery.init(dnsDiscoveryUrl, resolver)
if wakuDnsDiscovery.isOk():
return wakuDnsDiscovery.get().findPeers()
.mapErr(proc (e: cstring): string = $e)
return wakuDnsDiscovery.get().findPeers().mapErr(
proc(e: cstring): string =
$e
)
else:
warn "Failed to init Waku DNS discovery"
debug "No method for retrieving dynamic bootstrap nodes specified."
ok(newSeq[RemotePeerInfo]()) # Return an empty seq by default
proc getBootstrapFromDiscDns(conf: NetworkMonitorConf): Result[seq[enr.Record], string] =
proc getBootstrapFromDiscDns(
conf: NetworkMonitorConf
): Result[seq[enr.Record], string] =
try:
let dnsNameServers = @[parseIpAddress("1.1.1.1"), parseIpAddress("1.0.0.1")]
let dynamicBootstrapNodesRes = retrieveDynamicBootstrapNodes(true, conf.dnsDiscoveryUrl, dnsNameServers)
let dynamicBootstrapNodesRes =
retrieveDynamicBootstrapNodes(true, conf.dnsDiscoveryUrl, dnsNameServers)
if not dynamicBootstrapNodesRes.isOk():
error("failed discovering peers from DNS")
let dynamicBootstrapNodes = dynamicBootstrapNodesRes.get()
@ -345,19 +374,25 @@ proc getBootstrapFromDiscDns(conf: NetworkMonitorConf): Result[seq[enr.Record],
let
enr = n.enr.get()
tenrRes = enr.toTypedRecord()
if tenrRes.isOk() and (tenrRes.get().udp.isSome() or tenrRes.get().udp6.isSome()):
if tenrRes.isOk() and (
tenrRes.get().udp.isSome() or tenrRes.get().udp6.isSome()
):
discv5BootstrapEnrs.add(enr)
return ok(discv5BootstrapEnrs)
except CatchableError:
error("failed discovering peers from DNS")
proc initAndStartApp(conf: NetworkMonitorConf): Result[(WakuNode, WakuDiscoveryV5), string] =
let bindIp = try:
proc initAndStartApp(
conf: NetworkMonitorConf
): Result[(WakuNode, WakuDiscoveryV5), string] =
let bindIp =
try:
parseIpAddress("0.0.0.0")
except CatchableError:
return err("could not start node: " & getCurrentExceptionMsg())
let extIp = try:
let extIp =
try:
parseIpAddress("127.0.0.1")
except CatchableError:
return err("could not start node: " & getCurrentExceptionMsg())
@ -368,14 +403,14 @@ proc initAndStartApp(conf: NetworkMonitorConf): Result[(WakuNode, WakuDiscoveryV
key = crypto.PrivateKey.random(Secp256k1, rng[])[]
nodeTcpPort = Port(60000)
nodeUdpPort = Port(9000)
flags = CapabilitiesBitfield.init(lightpush = false, filter = false, store = false, relay = true)
flags = CapabilitiesBitfield.init(
lightpush = false, filter = false, store = false, relay = true
)
var builder = EnrBuilder.init(key)
builder.withIpAddressAndPorts(
ipAddr = some(extIp),
tcpPort = some(nodeTcpPort),
udpPort = some(nodeUdpPort),
ipAddr = some(extIp), tcpPort = some(nodeTcpPort), udpPort = some(nodeUdpPort)
)
builder.withWakuCapabilities(flags)
let addShardedTopics = builder.withShardedTopics(conf.pubsubTopics)
@ -387,15 +422,14 @@ proc initAndStartApp(conf: NetworkMonitorConf): Result[(WakuNode, WakuDiscoveryV
let record =
if recordRes.isErr():
return err("cannot build record: " & $recordRes.error)
else: recordRes.get()
else:
recordRes.get()
var nodeBuilder = WakuNodeBuilder.init()
nodeBuilder.withNodeKey(key)
nodeBuilder.withRecord(record)
nodeBuilder.withPeerManagerConfig(
maxRelayPeers = none(int),
shardAware = true)
nodeBuilder.withPeerManagerConfig(maxRelayPeers = none(int), shardAware = true)
let res = nodeBuilder.withNetworkConfigurationDetails(bindIp, nodeTcpPort)
if res.isErr():
return err("node building error" & $res.error)
@ -404,7 +438,8 @@ proc initAndStartApp(conf: NetworkMonitorConf): Result[(WakuNode, WakuDiscoveryV
let node =
if nodeRes.isErr():
return err("node building error" & $res.error)
else: nodeRes.get()
else:
nodeRes.get()
var discv5BootstrapEnrsRes = getBootstrapFromDiscDns(conf)
if discv5BootstrapEnrsRes.isErr():
@ -422,7 +457,7 @@ proc initAndStartApp(conf: NetworkMonitorConf): Result[(WakuNode, WakuDiscoveryV
port: nodeUdpPort,
privateKey: keys.PrivateKey(key.skkey),
bootstrapRecords: discv5BootstrapEnrs,
autoupdateRecord: false
autoupdateRecord: false,
)
let wakuDiscv5 = WakuDiscoveryV5.new(node.rng, discv5Conf, some(record))
@ -434,15 +469,17 @@ proc initAndStartApp(conf: NetworkMonitorConf): Result[(WakuNode, WakuDiscoveryV
ok((node, wakuDiscv5))
proc startRestApiServer(conf: NetworkMonitorConf,
proc startRestApiServer(
conf: NetworkMonitorConf,
allPeersInfo: CustomPeersTableRef,
numMessagesPerContentTopic: ContentTopicMessageTableRef
numMessagesPerContentTopic: ContentTopicMessageTableRef,
): Result[void, string] =
try:
let serverAddress = initTAddress(conf.metricsRestAddress & ":" & $conf.metricsRestPort)
let serverAddress =
initTAddress(conf.metricsRestAddress & ":" & $conf.metricsRestPort)
proc validate(pattern: string, value: string): int =
if pattern.startsWith("{") and pattern.endsWith("}"): 0
else: 1
if pattern.startsWith("{") and pattern.endsWith("}"): 0 else: 1
var router = RestRouter.init(validate)
router.installHandler(allPeersInfo, numMessagesPerContentTopic)
var sres = RestServerRef.new(router, serverAddress)
@ -454,12 +491,15 @@ proc startRestApiServer(conf: NetworkMonitorConf,
# handles rx of messages over a topic (see subscribe)
# counts the number of messages per content topic
proc subscribeAndHandleMessages(node: WakuNode,
proc subscribeAndHandleMessages(
node: WakuNode,
pubsubTopic: PubsubTopic,
msgPerContentTopic: ContentTopicMessageTableRef) =
msgPerContentTopic: ContentTopicMessageTableRef,
) =
# handle function
proc handler(pubsubTopic: PubsubTopic, msg: WakuMessage): Future[void] {.async, gcsafe.} =
proc handler(
pubsubTopic: PubsubTopic, msg: WakuMessage
): Future[void] {.async, gcsafe.} =
trace "rx message", pubsubTopic = pubsubTopic, contentTopic = msg.contentTopic
# If we reach a table limit size, remove c topics with the least messages.
@ -509,7 +549,8 @@ when isMainModule:
# start metrics server
if conf.metricsServer:
let res = startMetricsServer(conf.metricsServerAddress, Port(conf.metricsServerPort))
let res =
startMetricsServer(conf.metricsServerAddress, Port(conf.metricsServerPort))
if res.isErr():
error "could not start metrics server", err = res.error
quit(1)
@ -521,8 +562,8 @@ when isMainModule:
quit(1)
# create a rest client
let clientRest = RestClientRef.new(url="http://ip-api.com",
connectTimeout=ctime.seconds(2))
let clientRest =
RestClientRef.new(url = "http://ip-api.com", connectTimeout = ctime.seconds(2))
if clientRest.isErr():
error "could not start rest api client", err = res.error
quit(1)
@ -540,7 +581,6 @@ when isMainModule:
waitFor node.mountLibp2pPing()
if conf.rlnRelayEthContractAddress != "":
let rlnConf = WakuRlnConfig(
rlnRelayDynamic: conf.rlnRelayDynamic,
rlnRelayCredIndex: some(uint(0)),
@ -549,7 +589,7 @@ when isMainModule:
rlnRelayCredPath: "",
rlnRelayCredPassword: "",
rlnRelayTreePath: conf.rlnRelayTreePath,
rlnEpochSizeSec: conf.rlnEpochSizeSec
rlnEpochSizeSec: conf.rlnEpochSizeSec,
)
try:

View File

@ -10,106 +10,127 @@ import
type EthRpcUrl = distinct string
type
NetworkMonitorConf* = object
type NetworkMonitorConf* = object
logLevel* {.
desc: "Sets the log level",
defaultValue: LogLevel.INFO,
name: "log-level",
abbr: "l" .}: LogLevel
abbr: "l"
.}: LogLevel
timeout* {.
desc: "Timeout to consider that the connection failed",
defaultValue: chronos.seconds(10),
name: "timeout",
abbr: "t" }: chronos.Duration
abbr: "t"
.}: chronos.Duration
bootstrapNodes* {.
desc: "Bootstrap ENR node. Argument may be repeated.",
defaultValue: @[""],
name: "bootstrap-node",
abbr: "b" }: seq[string]
abbr: "b"
.}: seq[string]
dnsDiscoveryUrl* {.
desc: "URL for DNS node list in format 'enrtree://<key>@<fqdn>'",
defaultValue: ""
name: "dns-discovery-url" }: string
defaultValue: "",
name: "dns-discovery-url"
.}: string
pubsubTopics* {.
desc: "Default pubsub topic to subscribe to. Argument may be repeated."
name: "pubsub-topic" .}: seq[string]
desc: "Default pubsub topic to subscribe to. Argument may be repeated.",
name: "pubsub-topic"
.}: seq[string]
refreshInterval* {.
desc: "How often new peers are discovered and connected to (in seconds)",
defaultValue: 5,
name: "refresh-interval",
abbr: "r" }: int
abbr: "r"
.}: int
clusterId* {.
desc: "Cluster id that the node is running in. Node in a different cluster id is disconnected."
defaultValue: 1
name: "cluster-id" }: uint32
desc:
"Cluster id that the node is running in. Node in a different cluster id is disconnected.",
defaultValue: 1,
name: "cluster-id"
.}: uint32
rlnRelay* {.
desc: "Enable spam protection through rln-relay: true|false",
defaultValue: true
name: "rln-relay" }: bool
defaultValue: true,
name: "rln-relay"
.}: bool
rlnRelayDynamic* {.
desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false",
defaultValue: true
name: "rln-relay-dynamic" }: bool
defaultValue: true,
name: "rln-relay-dynamic"
.}: bool
rlnRelayTreePath* {.
desc: "Path to the RLN merkle tree sled db (https://github.com/spacejam/sled)",
defaultValue: ""
name: "rln-relay-tree-path" }: string
defaultValue: "",
name: "rln-relay-tree-path"
.}: string
rlnRelayEthClientAddress* {.
desc: "HTTP address of an Ethereum testnet client e.g., http://localhost:8540/",
defaultValue: "http://localhost:8540/",
name: "rln-relay-eth-client-address" }: EthRpcUrl
name: "rln-relay-eth-client-address"
.}: EthRpcUrl
rlnRelayEthContractAddress* {.
desc: "Address of membership contract on an Ethereum testnet",
defaultValue: "",
name: "rln-relay-eth-contract-address" }: string
name: "rln-relay-eth-contract-address"
.}: string
rlnEpochSizeSec* {.
desc: "Epoch size in seconds used to rate limit RLN memberships. Default is 1 second.",
defaultValue: 1
name: "rln-relay-epoch-sec" .}: uint64
desc:
"Epoch size in seconds used to rate limit RLN memberships. Default is 1 second.",
defaultValue: 1,
name: "rln-relay-epoch-sec"
.}: uint64
rlnRelayUserMessageLimit* {.
desc: "Set a user message limit for the rln membership registration. Must be a positive integer. Default is 1.",
desc:
"Set a user message limit for the rln membership registration. Must be a positive integer. Default is 1.",
defaultValue: 1,
name: "rln-relay-user-message-limit" .}: uint64
name: "rln-relay-user-message-limit"
.}: uint64
## Prometheus metrics config
metricsServer* {.
desc: "Enable the metrics server: true|false"
defaultValue: true
name: "metrics-server" }: bool
desc: "Enable the metrics server: true|false",
defaultValue: true,
name: "metrics-server"
.}: bool
metricsServerAddress* {.
desc: "Listening address of the metrics server."
defaultValue: parseIpAddress("127.0.0.1")
name: "metrics-server-address" }: IpAddress
desc: "Listening address of the metrics server.",
defaultValue: parseIpAddress("127.0.0.1"),
name: "metrics-server-address"
.}: IpAddress
metricsServerPort* {.
desc: "Listening HTTP port of the metrics server."
defaultValue: 8008
name: "metrics-server-port" }: uint16
desc: "Listening HTTP port of the metrics server.",
defaultValue: 8008,
name: "metrics-server-port"
.}: uint16
## Custom metrics rest server
metricsRestAddress* {.
desc: "Listening address of the metrics rest server.",
defaultValue: "127.0.0.1",
name: "metrics-rest-address" }: string
name: "metrics-rest-address"
.}: string
metricsRestPort* {.
desc: "Listening HTTP port of the metrics rest server.",
defaultValue: 8009,
name: "metrics-rest-port" }: uint16
name: "metrics-rest-port"
.}: uint16
proc parseCmdArg*(T: type IpAddress, p: string): T =
try:
@ -143,11 +164,15 @@ proc parseCmdArg*(T: type EthRpcUrl, s: string): T =
## https://url:port/path?query
## disallowed patterns:
## any valid/invalid ws or wss url
var httpPattern = re2"^(https?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*"
var wsPattern = re2"^(wss?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*"
var httpPattern =
re2"^(https?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*"
var wsPattern =
re2"^(wss?):\/\/((localhost)|([\w_-]+(?:(?:\.[\w_-]+)+)))(:[0-9]{1,5})?([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])*"
if regex.match(s, wsPattern):
echo "here"
raise newException(ValueError, "Websocket RPC URL is not supported, Please use an HTTP URL")
raise newException(
ValueError, "Websocket RPC URL is not supported, Please use an HTTP URL"
)
if not regex.match(s, httpPattern):
raise newException(ValueError, "Invalid HTTP RPC URL")
return EthRpcUrl(s)

View File

@ -34,24 +34,21 @@ declarePublicGauge networkmonitor_peer_type_as_per_protocol,
labels = ["protocols"]
declarePublicGauge networkmonitor_peer_user_agents,
"Number of peers with each user agent",
labels = ["user_agent"]
"Number of peers with each user agent", labels = ["user_agent"]
declarePublicHistogram networkmonitor_peer_ping,
"Histogram tracking ping durations for discovered peers",
buckets = [100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 2000.0, Inf]
buckets =
[100.0, 200.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 2000.0, Inf]
declarePublicGauge networkmonitor_peer_count,
"Number of discovered peers",
labels = ["connected"]
"Number of discovered peers", labels = ["connected"]
declarePublicGauge networkmonitor_peer_country_count,
"Number of peers per country",
labels = ["country"]
"Number of peers per country", labels = ["country"]
type
CustomPeerInfo* = object
# populated after discovery
CustomPeerInfo* = object # populated after discovery
lastTimeDiscovered*: int64
discovered*: int64
peerId*: string
@ -80,15 +77,19 @@ type
# stores the content topic and the count of rx messages
ContentTopicMessageTableRef* = TableRef[string, int]
proc installHandler*(router: var RestRouter,
proc installHandler*(
router: var RestRouter,
allPeers: CustomPeersTableRef,
numMessagesPerContentTopic: ContentTopicMessageTableRef) =
numMessagesPerContentTopic: ContentTopicMessageTableRef,
) =
router.api(MethodGet, "/allpeersinfo") do() -> RestApiResponse:
let values = toSeq(allPeers.values())
return RestApiResponse.response(values.toJson(), contentType = "application/json")
router.api(MethodGet, "/contenttopics") do() -> RestApiResponse:
# TODO: toJson() includes the hash
return RestApiResponse.response($(%numMessagesPerContentTopic), contentType="application/json")
return RestApiResponse.response(
$(%numMessagesPerContentTopic), contentType = "application/json"
)
proc startMetricsServer*(serverIp: IpAddress, serverPort: Port): Result[void, string] =
info "Starting metrics HTTP server", serverIp, serverPort
@ -96,7 +97,12 @@ proc startMetricsServer*(serverIp: IpAddress, serverPort: Port): Result[void, st
try:
startMetricsHttpServer($serverIp, serverPort)
except Exception as e:
error("Failed to start metrics HTTP server", serverIp=serverIp, serverPort=serverPort, msg=e.msg)
error(
"Failed to start metrics HTTP server",
serverIp = serverIp,
serverPort = serverPort,
msg = e.msg,
)
info "Metrics HTTP server started", serverIp, serverPort
ok()

View File

@ -12,8 +12,7 @@ import
chronos,
presto/[client, common]
type
NodeLocation* = object
type NodeLocation* = object
country*: string
city*: string
lat*: string
@ -26,8 +25,9 @@ proc flatten*[T](a: seq[seq[T]]): seq[T] =
aFlat &= subseq
return aFlat
proc decodeBytes*(t: typedesc[NodeLocation], value: openArray[byte],
contentType: Opt[ContentTypeData]): RestResult[NodeLocation] =
proc decodeBytes*(
t: typedesc[NodeLocation], value: openArray[byte], contentType: Opt[ContentTypeData]
): RestResult[NodeLocation] =
var res: string
if len(value) > 0:
res = newString(len(value))
@ -37,17 +37,21 @@ proc decodeBytes*(t: typedesc[NodeLocation], value: openArray[byte],
if $jsonContent["status"].getStr() != "success":
error "query failed", result = jsonContent
return err("query failed")
return ok(NodeLocation(
return ok(
NodeLocation(
country: jsonContent["country"].getStr(),
city: jsonContent["city"].getStr(),
lat: $jsonContent["lat"].getFloat(),
long: $jsonContent["lon"].getFloat(),
isp: jsonContent["isp"].getStr()
))
isp: jsonContent["isp"].getStr(),
)
)
except Exception:
return err("failed to get the location: " & getCurrentExceptionMsg())
proc encodeString*(value: string): RestResult[string] =
ok(value)
proc ipToLocation*(ip: string): RestResponse[NodeLocation] {.rest, endpoint: "json/{ip}", meth: MethodGet.}
proc ipToLocation*(
ip: string
): RestResponse[NodeLocation] {.rest, endpoint: "json/{ip}", meth: MethodGet.}

View File

@ -1,8 +1,4 @@
import
osproc,
os,
httpclient,
strutils
import osproc, os, httpclient, strutils
proc getPublicIP(): string =
let client = newHttpClient()
@ -15,7 +11,6 @@ proc getPublicIP(): string =
# Function to generate a self-signed certificate
proc generateSelfSignedCertificate*(certPath: string, keyPath: string): int =
# Ensure the OpenSSL is installed
if findExe("openssl") == "":
echo "OpenSSL is not installed or not in the PATH."
@ -28,7 +23,8 @@ proc generateSelfSignedCertificate*(certPath: string, keyPath: string) : int =
# Command to generate private key and cert
let
cmd = "openssl req -x509 -newkey rsa:4096 -keyout " & keyPath & " -out " & certPath &
cmd =
"openssl req -x509 -newkey rsa:4096 -keyout " & keyPath & " -out " & certPath &
" -sha256 -days 3650 -nodes -subj '/C=XX/ST=StateName/L=CityName/O=CompanyName/OU=CompanySectionName/CN=" &
publicIP & "'"
res = execCmd(cmd)
@ -39,4 +35,3 @@ proc generateSelfSignedCertificate*(certPath: string, keyPath: string) : int =
echo "Failed to generate certificate and key."
return res

View File

@ -30,52 +30,58 @@ const WebSocketPortOffset = 1000
const CertsDirectory = "./certs"
# cli flags
type
WakuCanaryConf* = object
type WakuCanaryConf* = object
address* {.
desc: "Multiaddress of the peer node to attempt to dial",
defaultValue: "",
name: "address",
abbr: "a".}: string
abbr: "a"
.}: string
timeout* {.
desc: "Timeout to consider that the connection failed",
defaultValue: chronos.seconds(10),
name: "timeout",
abbr: "t".}: chronos.Duration
abbr: "t"
.}: chronos.Duration
protocols* {.
desc: "Protocol required to be supported: store,relay,lightpush,filter (can be used multiple times)",
desc:
"Protocol required to be supported: store,relay,lightpush,filter (can be used multiple times)",
name: "protocol",
abbr: "p".}: seq[string]
abbr: "p"
.}: seq[string]
logLevel* {.
desc: "Sets the log level",
defaultValue: LogLevel.INFO,
name: "log-level",
abbr: "l".}: LogLevel
abbr: "l"
.}: LogLevel
nodePort* {.
desc: "Listening port for waku node",
defaultValue: 60000,
name: "node-port",
abbr: "np".}: uint16
abbr: "np"
.}: uint16
## websocket secure config
websocketSecureKeyPath* {.
desc: "Secure websocket key path: '/path/to/key.txt' ",
defaultValue: ""
name: "websocket-secure-key-path".}: string
defaultValue: "",
name: "websocket-secure-key-path"
.}: string
websocketSecureCertPath* {.
desc: "Secure websocket Certificate path: '/path/to/cert.txt' ",
defaultValue: ""
name: "websocket-secure-cert-path".}: string
defaultValue: "",
name: "websocket-secure-cert-path"
.}: string
ping* {.
desc: "Ping the peer node to measure latency",
defaultValue: true,
name: "ping" .}: bool
desc: "Ping the peer node to measure latency", defaultValue: true, name: "ping"
.}: bool
proc parseCmdArg*(T: type chronos.Duration, p: string): T =
try:
@ -88,17 +94,15 @@ proc completeCmdArg*(T: type chronos.Duration, val: string): seq[string] =
# checks if rawProtocols (skipping version) are supported in nodeProtocols
proc areProtocolsSupported(
rawProtocols: seq[string],
nodeProtocols: seq[string]): bool =
rawProtocols: seq[string], nodeProtocols: seq[string]
): bool =
var numOfSupportedProt: int = 0
for nodeProtocol in nodeProtocols:
for rawProtocol in rawProtocols:
let protocolTag = ProtocolsTable[rawProtocol]
if nodeProtocol.startsWith(protocolTag):
info "Supported protocol ok", expected = protocolTag,
supported = nodeProtocol
info "Supported protocol ok", expected = protocolTag, supported = nodeProtocol
numOfSupportedProt += 1
break
@ -107,12 +111,13 @@ proc areProtocolsSupported(
return false
proc pingNode(node: WakuNode, peerInfo: RemotePeerInfo): Future[void] {.async, gcsafe.} =
proc pingNode(
node: WakuNode, peerInfo: RemotePeerInfo
): Future[void] {.async, gcsafe.} =
try:
let conn = await node.switch.dial(peerInfo.peerId, peerInfo.addrs, PingCodec)
let pingDelay = await node.libp2pPing.ping(conn)
info "Peer response time (ms)", peerId = peerInfo.peerId, ping = pingDelay.millis
except CatchableError:
var msg = getCurrentExceptionMsg()
if msg == "Future operation cancelled!":
@ -124,9 +129,11 @@ proc main(rng: ref HmacDrbgContext): Future[int] {.async.} =
# create dns resolver
let
nameServers = @[
nameServers =
@[
initTAddress(parseIpAddress("1.1.1.1"), Port(53)),
initTAddress(parseIpAddress("1.0.0.1"), Port(53))]
initTAddress(parseIpAddress("1.0.0.1"), Port(53)),
]
resolver: DnsResolver = DnsResolver.new(nameServers)
if conf.logLevel != LogLevel.NONE:
@ -158,11 +165,13 @@ proc main(rng: ref HmacDrbgContext): Future[int] {.async.} =
nodeTcpPort = Port(conf.nodePort)
isWs = peer.addrs[0].contains(multiCodec("ws")).get()
isWss = peer.addrs[0].contains(multiCodec("wss")).get()
keyPath = if conf.websocketSecureKeyPath.len > 0:
keyPath =
if conf.websocketSecureKeyPath.len > 0:
conf.websocketSecureKeyPath
else:
CertsDirectory & "/key.pem"
certPath = if conf.websocketSecureCertPath.len > 0:
certPath =
if conf.websocketSecureCertPath.len > 0:
conf.websocketSecureCertPath
else:
CertsDirectory & "/cert.pem"
@ -185,10 +194,11 @@ proc main(rng: ref HmacDrbgContext): Future[int] {.async.} =
if recordRes.isErr():
error "failed to create enr record", error = recordRes.error
quit(QuitFailure)
else: recordRes.get()
else:
recordRes.get()
if isWss and (conf.websocketSecureKeyPath.len == 0 or
conf.websocketSecureCertPath.len == 0):
if isWss and
(conf.websocketSecureKeyPath.len == 0 or conf.websocketSecureCertPath.len == 0):
info "WebSocket Secure requires key and certificate. Generating them"
if not dirExists(CertsDirectory):
createDir(CertsDirectory)
@ -199,9 +209,7 @@ proc main(rng: ref HmacDrbgContext): Future[int] {.async.} =
builder.withRecord(record)
builder.withNetworkConfiguration(netConfig.tryGet())
builder.withSwitchConfiguration(
secureKey = some(keyPath),
secureCert = some(certPath),
nameResolver = resolver,
secureKey = some(keyPath), secureCert = some(certPath), nameResolver = resolver
)
let node = builder.build().tryGet()
@ -233,8 +241,8 @@ proc main(rng: ref HmacDrbgContext): Future[int] {.async.} =
if conStatus in [Connected, CanConnect]:
let nodeProtocols = lp2pPeerStore[ProtoBook][peer.peerId]
if not areProtocolsSupported(conf.protocols, nodeProtocols):
error "Not all protocols are supported", expected = conf.protocols,
supported = nodeProtocols
error "Not all protocols are supported",
expected = conf.protocols, supported = nodeProtocols
return 1
elif conStatus == CannotConnect:
error "Could not connect", peerId = peer.peerId

View File

@ -57,7 +57,6 @@ import
logScope:
topics = "wakunode app"
# Git version in git describe format (defined at compile time)
const git_version* {.strdefine.} = "n/a"
@ -78,7 +77,6 @@ type
AppResult*[T] = Result[T, string]
func node*(app: App): WakuNode =
app.node
@ -87,11 +85,9 @@ func version*(app: App): string =
## Retrieve dynamic bootstrap nodes (DNS discovery)
proc retrieveDynamicBootstrapNodes*(dnsDiscovery: bool,
dnsDiscoveryUrl: string,
dnsDiscoveryNameServers: seq[IpAddress]):
Result[seq[RemotePeerInfo], string] =
proc retrieveDynamicBootstrapNodes*(
dnsDiscovery: bool, dnsDiscoveryUrl: string, dnsDiscoveryNameServers: seq[IpAddress]
): Result[seq[RemotePeerInfo], string] =
if dnsDiscovery and dnsDiscoveryUrl != "":
# DNS discovery
debug "Discovering nodes using Waku DNS discovery", url = dnsDiscoveryUrl
@ -109,8 +105,10 @@ proc retrieveDynamicBootstrapNodes*(dnsDiscovery: bool,
var wakuDnsDiscovery = WakuDnsDiscovery.init(dnsDiscoveryUrl, resolver)
if wakuDnsDiscovery.isOk():
return wakuDnsDiscovery.get().findPeers()
.mapErr(proc (e: cstring): string = $e)
return wakuDnsDiscovery.get().findPeers().mapErr(
proc(e: cstring): string =
$e
)
else:
warn "Failed to init Waku DNS discovery"
@ -120,7 +118,6 @@ proc retrieveDynamicBootstrapNodes*(dnsDiscovery: bool,
## Initialisation
proc init*(T: type App, conf: WakuNodeConf): Result[App, string] =
var confCopy = conf
let rng = crypto.newRng()
@ -132,12 +129,15 @@ proc init*(T: type App, conf: WakuNodeConf): Result[App, string] =
confCopy.nodekey = some(keyRes.get())
debug "Retrieve dynamic bootstrap nodes"
let dynamicBootstrapNodesRes = retrieveDynamicBootstrapNodes(confCopy.dnsDiscovery,
confCopy.dnsDiscoveryUrl,
confCopy.dnsDiscoveryNameServers)
let dynamicBootstrapNodesRes = retrieveDynamicBootstrapNodes(
confCopy.dnsDiscovery, confCopy.dnsDiscoveryUrl, confCopy.dnsDiscoveryNameServers
)
if dynamicBootstrapNodesRes.isErr():
error "Retrieving dynamic bootstrap nodes failed", error = dynamicBootstrapNodesRes.error
return err("Retrieving dynamic bootstrap nodes failed: " & dynamicBootstrapNodesRes.error)
error "Retrieving dynamic bootstrap nodes failed",
error = dynamicBootstrapNodesRes.error
return err(
"Retrieving dynamic bootstrap nodes failed: " & dynamicBootstrapNodesRes.error
)
let nodeRes = setupNode(confCopy, some(rng))
if nodeRes.isErr():
@ -150,7 +150,7 @@ proc init*(T: type App, conf: WakuNodeConf): Result[App, string] =
rng: rng,
key: confCopy.nodekey.get(),
node: nodeRes.get(),
dynamicBootstrapNodes: dynamicBootstrapNodesRes.get()
dynamicBootstrapNodes: dynamicBootstrapNodesRes.get(),
)
ok(app)
@ -158,9 +158,8 @@ proc init*(T: type App, conf: WakuNodeConf): Result[App, string] =
## Setup DiscoveryV5
proc setupDiscoveryV5*(app: App): WakuDiscoveryV5 =
let dynamicBootstrapEnrs = app.dynamicBootstrapNodes
.filterIt(it.hasUdpPort())
.mapIt(it.enr.get())
let dynamicBootstrapEnrs =
app.dynamicBootstrapNodes.filterIt(it.hasUdpPort()).mapIt(it.enr.get())
var discv5BootstrapEnrs: seq[enr.Record]
@ -170,9 +169,9 @@ proc setupDiscoveryV5*(app: App): WakuDiscoveryV5 =
discv5BootstrapEnrs.add(dynamicBootstrapEnrs)
let discv5Config = DiscoveryConfig.init(app.conf.discv5TableIpLimit,
app.conf.discv5BucketIpLimit,
app.conf.discv5BitsPerHop)
let discv5Config = DiscoveryConfig.init(
app.conf.discv5TableIpLimit, app.conf.discv5BucketIpLimit, app.conf.discv5BitsPerHop
)
let discv5UdpPort = Port(uint16(app.conf.discv5UdpPort) + app.conf.portsShift)
@ -193,9 +192,9 @@ proc setupDiscoveryV5*(app: App): WakuDiscoveryV5 =
app.node.topicSubscriptionQueue,
)
proc getPorts(listenAddrs: seq[MultiAddress]):
AppResult[tuple[tcpPort, websocketPort: Option[Port]]] =
proc getPorts(
listenAddrs: seq[MultiAddress]
): AppResult[tuple[tcpPort, websocketPort: Option[Port]]] =
var tcpPort, websocketPort = none(Port)
for a in listenAddrs:
@ -212,7 +211,6 @@ proc getPorts(listenAddrs: seq[MultiAddress]):
return ok((tcpPort: tcpPort, websocketPort: websocketPort))
proc getRunningNetConfig(app: App): AppResult[NetConfig] =
var conf = app.conf
let (tcpPort, websocketPort) = getPorts(app.node.switch.peerInfo.listenAddrs).valueOr:
return err("Could not retrieve ports " & error)
@ -230,7 +228,6 @@ proc getRunningNetConfig(app: App): AppResult[NetConfig] =
return ok(netConf)
proc updateEnr(app: var App, netConf: NetConfig): AppResult[void] =
let record = enrConfiguration(app.conf, netConf, app.key).valueOr:
return err("ENR setup failed: " & error)
@ -242,9 +239,7 @@ proc updateEnr(app: var App, netConf: NetConfig): AppResult[void] =
return ok()
proc updateApp(app: var App): AppResult[void] =
if app.conf.tcpPort == Port(0) or app.conf.websocketPort == Port(0):
let netConf = getRunningNetConfig(app).valueOr:
return err("error calling updateNetConfig: " & $error)
@ -258,8 +253,8 @@ proc updateApp(app: var App): AppResult[void] =
return ok()
proc startApp*(app: var App): AppResult[void] =
let nodeRes = catch: (waitFor startNode(app.node, app.conf, app.dynamicBootstrapNodes))
let nodeRes = catch:
(waitFor startNode(app.node, app.conf, app.dynamicBootstrapNodes))
if nodeRes.isErr():
return err("exception starting node: " & nodeRes.error.msg)
@ -276,7 +271,8 @@ proc startApp*(app: var App): AppResult[void] =
if app.wakuDiscv5.isSome():
let wakuDiscv5 = app.wakuDiscv5.get()
let catchRes = catch: (waitFor wakuDiscv5.start())
let catchRes = catch:
(waitFor wakuDiscv5.start())
let startRes = catchRes.valueOr:
return err("failed to start waku discovery v5: " & catchRes.error.msg)
@ -285,38 +281,37 @@ proc startApp*(app: var App): AppResult[void] =
return ok()
## Monitoring and external interfaces
proc startRestServer(app: App,
address: IpAddress,
port: Port,
conf: WakuNodeConf):
AppResult[WakuRestServerRef] =
proc startRestServer(
app: App, address: IpAddress, port: Port, conf: WakuNodeConf
): AppResult[WakuRestServerRef] =
# Used to register api endpoints that are not currently installed as keys,
# values are holding error messages to be returned to the client
var notInstalledTab: Table[string, string] = initTable[string, string]()
let requestErrorHandler : RestRequestErrorHandler = proc (error: RestRequestError,
request: HttpRequestRef):
Future[HttpResponseRef]
{.async: (raises: [CancelledError]).} =
let requestErrorHandler: RestRequestErrorHandler = proc(
error: RestRequestError, request: HttpRequestRef
): Future[HttpResponseRef] {.async: (raises: [CancelledError]).} =
try:
case error
of RestRequestError.Invalid:
return await request.respond(Http400, "Invalid request", HttpTable.init())
of RestRequestError.NotFound:
let paths = request.rawPath.split("/")
let rootPath = if len(paths) > 1:
let rootPath =
if len(paths) > 1:
paths[1]
else:
""
notInstalledTab.withValue(rootPath, errMsg):
return await request.respond(Http404, errMsg[], HttpTable.init())
do:
return await request.respond(Http400, "Bad request initiated. Invalid path or method used.", HttpTable.init())
return await request.respond(
Http400,
"Bad request initiated. Invalid path or method used.",
HttpTable.init(),
)
of RestRequestError.InvalidContentBody:
return await request.respond(Http400, "Invalid content body", HttpTable.init())
of RestRequestError.InvalidContentType:
@ -329,14 +324,19 @@ proc startRestServer(app: App,
return defaultResponse()
let allowedOrigin = if len(conf.restAllowOrigin) > 0 :
let allowedOrigin =
if len(conf.restAllowOrigin) > 0:
some(conf.restAllowOrigin.join(","))
else:
none(string)
let server = ? newRestHttpServer(address, port,
let server =
?newRestHttpServer(
address,
port,
allowedOrigin = allowedOrigin,
requestErrorHandler = requestErrorHandler)
requestErrorHandler = requestErrorHandler,
)
## Admin REST API
if conf.restAdmin:
@ -364,58 +364,64 @@ proc startRestServer(app: App,
installRelayApiHandlers(server.router, app.node, cache)
else:
notInstalledTab["relay"] = "/relay endpoints are not available. Please check your configuration: --relay"
notInstalledTab["relay"] =
"/relay endpoints are not available. Please check your configuration: --relay"
## Filter REST API
if conf.filternode != "" and
app.node.wakuFilterClient != nil and
if conf.filternode != "" and app.node.wakuFilterClient != nil and
app.node.wakuFilterClientLegacy != nil:
let legacyFilterCache = MessageCache.init()
rest_legacy_filter_api.installLegacyFilterRestApiHandlers(server.router, app.node, legacyFilterCache)
rest_legacy_filter_api.installLegacyFilterRestApiHandlers(
server.router, app.node, legacyFilterCache
)
let filterCache = MessageCache.init()
let filterDiscoHandler =
if app.wakuDiscv5.isSome():
some(defaultDiscoveryHandler(app.wakuDiscv5.get(), Filter))
else: none(DiscoveryHandler)
else:
none(DiscoveryHandler)
rest_filter_api.installFilterRestApiHandlers(
server.router,
app.node,
filterCache,
filterDiscoHandler,
server.router, app.node, filterCache, filterDiscoHandler
)
else:
notInstalledTab["filter"] = "/filter endpoints are not available. Please check your configuration: --filternode"
notInstalledTab["filter"] =
"/filter endpoints are not available. Please check your configuration: --filternode"
## Store REST API
let storeDiscoHandler =
if app.wakuDiscv5.isSome():
some(defaultDiscoveryHandler(app.wakuDiscv5.get(), Store))
else: none(DiscoveryHandler)
else:
none(DiscoveryHandler)
installStoreApiHandlers(server.router, app.node, storeDiscoHandler)
## Light push API
if conf.lightpushnode != "" and
app.node.wakuLightpushClient != nil:
if conf.lightpushnode != "" and app.node.wakuLightpushClient != nil:
let lightDiscoHandler =
if app.wakuDiscv5.isSome():
some(defaultDiscoveryHandler(app.wakuDiscv5.get(), Lightpush))
else: none(DiscoveryHandler)
rest_lightpush_api.installLightPushRequestHandler(server.router, app.node, lightDiscoHandler)
else:
notInstalledTab["lightpush"] = "/lightpush endpoints are not available. Please check your configuration: --lightpushnode"
none(DiscoveryHandler)
rest_lightpush_api.installLightPushRequestHandler(
server.router, app.node, lightDiscoHandler
)
else:
notInstalledTab["lightpush"] =
"/lightpush endpoints are not available. Please check your configuration: --lightpushnode"
server.start()
info "Starting REST HTTP server", url = "http://" & $address & ":" & $port & "/"
ok(server)
proc startMetricsServer(serverIp: IpAddress, serverPort: Port): AppResult[MetricsHttpServerRef] =
proc startMetricsServer(
serverIp: IpAddress, serverPort: Port
): AppResult[MetricsHttpServerRef] =
info "Starting metrics HTTP server", serverIp = $serverIp, serverPort = $serverPort
let metricsServerRes = MetricsHttpServerRef.new($serverIp, serverPort)
@ -437,28 +443,34 @@ proc startMetricsLogging(): AppResult[void] =
proc setupMonitoringAndExternalInterfaces*(app: var App): AppResult[void] =
if app.conf.rest:
let startRestServerRes = startRestServer(app, app.conf.restAddress, Port(app.conf.restPort + app.conf.portsShift), app.conf)
let startRestServerRes = startRestServer(
app, app.conf.restAddress, Port(app.conf.restPort + app.conf.portsShift), app.conf
)
if startRestServerRes.isErr():
error "Starting REST server failed. Continuing in current state.", error=startRestServerRes.error
error "Starting REST server failed. Continuing in current state.",
error = startRestServerRes.error
else:
app.restServer = some(startRestServerRes.value)
if app.conf.metricsServer:
let startMetricsServerRes = startMetricsServer(app.conf.metricsServerAddress, Port(app.conf.metricsServerPort + app.conf.portsShift))
let startMetricsServerRes = startMetricsServer(
app.conf.metricsServerAddress,
Port(app.conf.metricsServerPort + app.conf.portsShift),
)
if startMetricsServerRes.isErr():
error "Starting metrics server failed. Continuing in current state.", error=startMetricsServerRes.error
error "Starting metrics server failed. Continuing in current state.",
error = startMetricsServerRes.error
else:
app.metricsServer = some(startMetricsServerRes.value)
if app.conf.metricsLogging:
let startMetricsLoggingRes = startMetricsLogging()
if startMetricsLoggingRes.isErr():
error "Starting metrics console logging failed. Continuing in current state.", error=startMetricsLoggingRes.error
error "Starting metrics console logging failed. Continuing in current state.",
error = startMetricsLoggingRes.error
ok()
# App shutdown
proc stop*(app: App): Future[void] {.async: (raises: [Exception]).} =

View File

@ -33,13 +33,13 @@ proc TheWakuNetworkConf*(T: type ClusterConf): ClusterConf =
pubsubTopics:
@[
"/waku/2/rs/1/0", "/waku/2/rs/1/1", "/waku/2/rs/1/2", "/waku/2/rs/1/3",
"/waku/2/rs/1/4", "/waku/2/rs/1/5", "/waku/2/rs/1/6", "/waku/2/rs/1/7"
"/waku/2/rs/1/4", "/waku/2/rs/1/5", "/waku/2/rs/1/6", "/waku/2/rs/1/7",
],
discv5Discovery: true,
discv5BootstrapNodes:
@[
"enr:-QESuEC1p_s3xJzAC_XlOuuNrhVUETmfhbm1wxRGis0f7DlqGSw2FM-p2Ugl_r25UHQJ3f1rIRrpzxJXSMaJe4yk1XFSAYJpZIJ2NIJpcISygI2rim11bHRpYWRkcnO4XAArNiZub2RlLTAxLmRvLWFtczMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAZ2XwAtNiZub2RlLTAxLmRvLWFtczMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQJATXRSRSUyTw_QLB6H_U3oziVQgNRgrXpK7wp2AMyNxYN0Y3CCdl-DdWRwgiMohXdha3UyDw",
"enr:-QEkuECnZ3IbVAgkOzv-QLnKC4dRKAPRY80m1-R7G8jZ7yfT3ipEfBrhKN7ARcQgQ-vg-h40AQzyvAkPYlHPaFKk6u9uAYJpZIJ2NIJpcIQiEAFDim11bHRpYWRkcnO4bgA0Ni9ub2RlLTAxLmdjLXVzLWNlbnRyYWwxLWEud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAZ2XwA2Ni9ub2RlLTAxLmdjLXVzLWNlbnRyYWwxLWEud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQMIJwesBVgUiBCi8yiXGx7RWylBQkYm1U9dvEy-neLG2YN0Y3CCdl-DdWRwgiMohXdha3UyDw",
"enr:-QEkuEDzQyIAhs-CgBHIrJqtBv3EY1uP1Psrc-y8yJKsmxW7dh3DNcq2ergMUWSFVcJNlfcgBeVsFPkgd_QopRIiCV2pAYJpZIJ2NIJpcIQI2ttrim11bHRpYWRkcnO4bgA0Ni9ub2RlLTAxLmFjLWNuLWhvbmdrb25nLWMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAZ2XwA2Ni9ub2RlLTAxLmFjLWNuLWhvbmdrb25nLWMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQJIN4qwz3v4r2Q8Bv8zZD0eqBcKw6bdLvdkV7-JLjqIj4N0Y3CCdl-DdWRwgiMohXdha3UyDw"
"enr:-QEkuEDzQyIAhs-CgBHIrJqtBv3EY1uP1Psrc-y8yJKsmxW7dh3DNcq2ergMUWSFVcJNlfcgBeVsFPkgd_QopRIiCV2pAYJpZIJ2NIJpcIQI2ttrim11bHRpYWRkcnO4bgA0Ni9ub2RlLTAxLmFjLWNuLWhvbmdrb25nLWMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAZ2XwA2Ni9ub2RlLTAxLmFjLWNuLWhvbmdrb25nLWMud2FrdS50ZXN0LnN0YXR1c2ltLm5ldAYfQN4DgnJzkwABCAAAAAEAAgADAAQABQAGAAeJc2VjcDI1NmsxoQJIN4qwz3v4r2Q8Bv8zZD0eqBcKw6bdLvdkV7-JLjqIj4N0Y3CCdl-DdWRwgiMohXdha3UyDw",
],
)

View File

@ -32,9 +32,7 @@ proc logConfig(conf: WakuNodeConf) =
lightpush = conf.lightpush,
peerExchange = conf.peerExchange
info "Configuration. Network",
cluster = conf.clusterId,
maxPeers = conf.maxRelayPeers
info "Configuration. Network", cluster = conf.clusterId, maxPeers = conf.maxRelayPeers
for shard in conf.pubsubTopics:
info "Configuration. Shards", shard = shard

View File

@ -1,11 +1,7 @@
## Example showing how a resource restricted client may
## subscribe to messages without relay
import
chronicles,
chronos,
stew/byteutils,
stew/results
import chronicles, chronos, stew/byteutils, stew/results
import
../../../waku/common/logging,
../../../waku/node/peer_manager,
@ -13,34 +9,42 @@ import
../../../waku/waku_filter_v2/client
const
FilterPeer = "/ip4/104.154.239.128/tcp/30303/p2p/16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47Rxx5hw3q4YjS" # node-01.gc-us-central1-a.wakuv2.test.statusim.net on wakuv2.test
FilterPeer =
"/ip4/104.154.239.128/tcp/30303/p2p/16Uiu2HAmJb2e28qLXxT5kZxVUUoJt72EMzNGXB47Rxx5hw3q4YjS"
# node-01.gc-us-central1-a.wakuv2.test.statusim.net on wakuv2.test
FilterPubsubTopic = PubsubTopic("/waku/2/default-waku/proto")
FilterContentTopic = ContentTopic("/examples/1/light-pubsub-example/proto")
proc unsubscribe(wfc: WakuFilterClient,
proc unsubscribe(
wfc: WakuFilterClient,
filterPeer: RemotePeerInfo,
filterPubsubTopic: PubsubTopic,
filterContentTopic: ContentTopic) {.async.} =
filterContentTopic: ContentTopic,
) {.async.} =
notice "unsubscribing from filter"
let unsubscribeRes = await wfc.unsubscribe(filterPeer, filterPubsubTopic, @[filterContentTopic])
let unsubscribeRes =
await wfc.unsubscribe(filterPeer, filterPubsubTopic, @[filterContentTopic])
if unsubscribeRes.isErr:
notice "unsubscribe request failed", err = unsubscribeRes.error
else:
notice "unsubscribe request successful"
proc messagePushHandler(pubsubTopic: PubsubTopic, message: WakuMessage)
{.async, gcsafe.} =
proc messagePushHandler(
pubsubTopic: PubsubTopic, message: WakuMessage
) {.async, gcsafe.} =
let payloadStr = string.fromBytes(message.payload)
notice "message received", payload=payloadStr,
notice "message received",
payload = payloadStr,
pubsubTopic = pubsubTopic,
contentTopic = message.contentTopic,
timestamp = message.timestamp
proc maintainSubscription(wfc: WakuFilterClient,
proc maintainSubscription(
wfc: WakuFilterClient,
filterPeer: RemotePeerInfo,
filterPubsubTopic: PubsubTopic,
filterContentTopic: ContentTopic) {.async.} =
filterContentTopic: ContentTopic,
) {.async.} =
while true:
notice "maintaining subscription"
# First use filter-ping to check if we have an active subscription
@ -49,7 +53,8 @@ proc maintainSubscription(wfc: WakuFilterClient,
# No subscription found. Let's subscribe.
notice "no subscription found. Sending subscribe request"
let subscribeRes = await wfc.subscribe(filterPeer, filterPubsubTopic, @[filterContentTopic])
let subscribeRes =
await wfc.subscribe(filterPeer, filterPubsubTopic, @[filterContentTopic])
if subscribeRes.isErr():
notice "subscribe request failed. Quitting.", err = subscribeRes.error
@ -78,7 +83,9 @@ proc setupAndSubscribe(rng: ref HmacDrbgContext) =
wfc.registerPushHandler(messagePushHandler)
# Start maintaining subscription
asyncSpawn maintainSubscription(wfc, filterPeer, FilterPubsubTopic, FilterContentTopic)
asyncSpawn maintainSubscription(
wfc, filterPeer, FilterPubsubTopic, FilterContentTopic
)
when isMainModule:
let rng = newRng()

View File

@ -1,11 +1,7 @@
## Example showing how a resource restricted client may
## use lightpush to publish messages without relay
import
chronicles,
chronos,
stew/byteutils,
stew/results
import chronicles, chronos, stew/byteutils, stew/results
import
../../../waku/common/logging,
../../../waku/node/peer_manager,
@ -13,20 +9,26 @@ import
../../../waku/waku_lightpush/client
const
LightpushPeer = "/ip4/134.209.139.210/tcp/30303/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ" # node-01.do-ams3.wakuv2.test.statusim.net on wakuv2.test
LightpushPeer =
"/ip4/134.209.139.210/tcp/30303/p2p/16Uiu2HAmPLe7Mzm8TsYUubgCAW1aJoeFScxrLj8ppHFivPo97bUZ"
# node-01.do-ams3.wakuv2.test.statusim.net on wakuv2.test
LightpushPubsubTopic = PubsubTopic("/waku/2/default-waku/proto")
LightpushContentTopic = ContentTopic("/examples/1/light-pubsub-example/proto")
proc publishMessages(wlc: WakuLightpushClient,
proc publishMessages(
wlc: WakuLightpushClient,
lightpushPeer: RemotePeerInfo,
lightpushPubsubTopic: PubsubTopic,
lightpushContentTopic: ContentTopic) {.async.} =
lightpushContentTopic: ContentTopic,
) {.async.} =
while true:
let text = "hi there i'm a lightpush publisher"
let message = WakuMessage(payload: toBytes(text), # content of the message
let message = WakuMessage(
payload: toBytes(text), # content of the message
contentTopic: lightpushContentTopic, # content topic to publish to
ephemeral: true, # tell store nodes to not store it
timestamp: getNowInNanosecondTime()) # current timestamp
timestamp: getNowInNanosecondTime(),
) # current timestamp
let wlpRes = await wlc.publish(lightpushPubsubTopic, message, lightpushPeer)
@ -49,7 +51,9 @@ proc setupAndPublish(rng: ref HmacDrbgContext) =
wlc = WakuLightpushClient.new(pm, rng)
# Start maintaining subscription
asyncSpawn publishMessages(wlc, lightpushPeer, LightpushPubsubTopic, LightpushContentTopic)
asyncSpawn publishMessages(
wlc, lightpushPeer, LightpushPubsubTopic, LightpushContentTopic
)
when isMainModule:
let rng = newRng()

View File

@ -23,8 +23,8 @@ proc now*(): Timestamp =
# An accesible bootstrap node. See wakuv2.prod fleets.status.im
const bootstrapNode = "enr:-Nm4QOdTOKZJKTUUZ4O_W932CXIET-M9NamewDnL78P5u9D" &
const bootstrapNode =
"enr:-Nm4QOdTOKZJKTUUZ4O_W932CXIET-M9NamewDnL78P5u9D" &
"OGnZlK0JFZ4k0inkfe6iY-0JAaJVovZXc575VV3njeiABgmlkgn" &
"Y0gmlwhAjS3ueKbXVsdGlhZGRyc7g6ADg2MW5vZGUtMDEuYWMtY" &
"24taG9uZ2tvbmctYy53YWt1djIucHJvZC5zdGF0dXNpbS5uZXQG" &
@ -42,7 +42,9 @@ proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} =
let
nodeKey = crypto.PrivateKey.random(Secp256k1, rng[]).get()
ip = parseIpAddress("0.0.0.0")
flags = CapabilitiesBitfield.init(lightpush = false, filter = false, store = false, relay = true)
flags = CapabilitiesBitfield.init(
lightpush = false, filter = false, store = false, relay = true
)
var enrBuilder = EnrBuilder.init(nodeKey)
@ -51,7 +53,8 @@ proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} =
if recordRes.isErr():
error "failed to create enr record", error = recordRes.error
quit(QuitFailure)
else: recordRes.get()
else:
recordRes.get()
var builder = WakuNodeBuilder.init()
builder.withNodeKey(nodeKey)
@ -90,7 +93,8 @@ proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} =
# wait for a minimum of peers to be connected, otherwise messages wont be gossiped
while true:
let numConnectedPeers = node.peerManager.peerStore[ConnectionBook].book.values().countIt(it == Connected)
let numConnectedPeers =
node.peerManager.peerStore[ConnectionBook].book.values().countIt(it == Connected)
if numConnectedPeers >= 6:
notice "publisher is ready", connectedPeers = numConnectedPeers, required = 6
break
@ -107,15 +111,21 @@ proc setupAndPublish(rng: ref HmacDrbgContext) {.async.} =
notice "publisher service started"
while true:
let text = "hi there i'm a publisher"
let message = WakuMessage(payload: toBytes(text), # content of the message
let message = WakuMessage(
payload: toBytes(text), # content of the message
contentTopic: contentTopic, # content topic to publish to
ephemeral: true, # tell store nodes to not store it
timestamp: now()) # current timestamp
timestamp: now(),
) # current timestamp
let res = await node.publish(some(pubSubTopic), message)
if res.isOk:
notice "published message", text = text, timestamp = message.timestamp, psTopic = pubSubTopic, contentTopic = contentTopic
notice "published message",
text = text,
timestamp = message.timestamp,
psTopic = pubSubTopic,
contentTopic = contentTopic
else:
error "failed to publish message", error = res.error

View File

@ -19,12 +19,12 @@ import
../../../waku/factory/builder
# An accesible bootstrap node. See wakuv2.prod fleets.status.im
const bootstrapNode = "enr:-Nm4QOdTOKZJKTUUZ4O_W932CXIET-M9NamewDnL78P5u9DOGnZl" &
const bootstrapNode =
"enr:-Nm4QOdTOKZJKTUUZ4O_W932CXIET-M9NamewDnL78P5u9DOGnZl" &
"K0JFZ4k0inkfe6iY-0JAaJVovZXc575VV3njeiABgmlkgnY0gmlwhAjS" &
"3ueKbXVsdGlhZGRyc7g6ADg2MW5vZGUtMDEuYWMtY24taG9uZ2tvbmct" &
"Yy53YWt1djIucHJvZC5zdGF0dXNpbS5uZXQGH0DeA4lzZWNwMjU2azGh" &
"Ao0C-VvfgHiXrxZi3umDiooXMGY9FvYj5_d1Q4EeS7eyg3RjcIJ2X4N1" &
"ZHCCIyiFd2FrdTIP"
"Ao0C-VvfgHiXrxZi3umDiooXMGY9FvYj5_d1Q4EeS7eyg3RjcIJ2X4N1" & "ZHCCIyiFd2FrdTIP"
# careful if running pub and sub in the same machine
const wakuPort = 50000
@ -37,7 +37,9 @@ proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} =
let
nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[]
ip = parseIpAddress("0.0.0.0")
flags = CapabilitiesBitfield.init(lightpush = false, filter = false, store = false, relay = true)
flags = CapabilitiesBitfield.init(
lightpush = false, filter = false, store = false, relay = true
)
var enrBuilder = EnrBuilder.init(nodeKey)
@ -46,7 +48,8 @@ proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} =
if recordRes.isErr():
error "failed to create enr record", error = recordRes.error
quit(QuitFailure)
else: recordRes.get()
else:
recordRes.get()
var builder = WakuNodeBuilder.init()
builder.withNodeKey(nodeKey)
@ -85,7 +88,8 @@ proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} =
# wait for a minimum of peers to be connected, otherwise messages wont be gossiped
while true:
let numConnectedPeers = node.peerManager.peerStore[ConnectionBook].book.values().countIt(it == Connected)
let numConnectedPeers =
node.peerManager.peerStore[ConnectionBook].book.values().countIt(it == Connected)
if numConnectedPeers >= 6:
notice "subscriber is ready", connectedPeers = numConnectedPeers, required = 6
break
@ -102,10 +106,12 @@ proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} =
proc handler(topic: PubsubTopic, msg: WakuMessage): Future[void] {.async, gcsafe.} =
let payloadStr = string.fromBytes(msg.payload)
if msg.contentTopic == contentTopic:
notice "message received", payload=payloadStr,
notice "message received",
payload = payloadStr,
pubsubTopic = pubsubTopic,
contentTopic = msg.contentTopic,
timestamp = msg.timestamp
node.subscribe((kind: PubsubSub, topic: pubsubTopic), some(handler))
when isMainModule:

View File

@ -30,32 +30,47 @@ type CKeyPair* = object
private_key: CFr
public_key: CG1Projective
proc drop_ffi_derive_public_key*(ptrx: ptr CReturn[CG1Projective]) {.importc: "drop_ffi_derive_public_key".}
proc drop_ffi_derive_public_key*(
ptrx: ptr CReturn[CG1Projective]
) {.importc: "drop_ffi_derive_public_key".}
proc drop_ffi_generate_random_fr*(ptrx: ptr CReturn[CFr]) {.importc: "drop_ffi_generate_random_fr".}
proc drop_ffi_generate_random_fr*(
ptrx: ptr CReturn[CFr]
) {.importc: "drop_ffi_generate_random_fr".}
proc drop_ffi_generate_stealth_commitment*(ptrx: ptr CReturn[CStealthCommitment]) {.importc: "drop_ffi_generate_stealth_commitment".}
proc drop_ffi_generate_stealth_commitment*(
ptrx: ptr CReturn[CStealthCommitment]
) {.importc: "drop_ffi_generate_stealth_commitment".}
proc drop_ffi_generate_stealth_private_key*(ptrx: ptr CReturn[CFr]) {.importc: "drop_ffi_generate_stealth_private_key".}
proc drop_ffi_generate_stealth_private_key*(
ptrx: ptr CReturn[CFr]
) {.importc: "drop_ffi_generate_stealth_private_key".}
proc drop_ffi_random_keypair*(ptrx: ptr CReturn[CKeyPair]) {.importc: "drop_ffi_random_keypair".}
proc drop_ffi_random_keypair*(
ptrx: ptr CReturn[CKeyPair]
) {.importc: "drop_ffi_random_keypair".}
proc ffi_derive_public_key*(private_key: ptr CFr): (ptr CReturn[CG1Projective]) {.importc: "ffi_derive_public_key".}
proc ffi_derive_public_key*(
private_key: ptr CFr
): (ptr CReturn[CG1Projective]) {.importc: "ffi_derive_public_key".}
proc ffi_generate_random_fr*(): (ptr CReturn[CFr]) {.importc: "ffi_generate_random_fr".}
proc ffi_generate_stealth_commitment*(viewing_public_key: ptr CG1Projective,
proc ffi_generate_stealth_commitment*(
viewing_public_key: ptr CG1Projective,
spending_public_key: ptr CG1Projective,
ephemeral_private_key: ptr CFr): (ptr CReturn[CStealthCommitment]) {.importc: "ffi_generate_stealth_commitment".}
ephemeral_private_key: ptr CFr,
): (ptr CReturn[CStealthCommitment]) {.importc: "ffi_generate_stealth_commitment".}
proc ffi_generate_stealth_private_key*(ephemeral_public_key: ptr CG1Projective,
proc ffi_generate_stealth_private_key*(
ephemeral_public_key: ptr CG1Projective,
spending_key: ptr CFr,
viewing_key: ptr CFr,
view_tag: ptr uint64): (ptr CReturn[CFr]) {.importc: "ffi_generate_stealth_private_key".}
view_tag: ptr uint64,
): (ptr CReturn[CFr]) {.importc: "ffi_generate_stealth_private_key".}
proc ffi_random_keypair*(): (ptr CReturn[CKeyPair]) {.importc: "ffi_random_keypair".}
## Nim wrappers and types for the ERC-5564-BN254 module
type FFIResult[T] = Result[T, string]
@ -64,9 +79,11 @@ type G1Projective = array[32, uint8]
type KeyPair* = object
private_key*: Fr
public_key*: G1Projective
type StealthCommitment* = object
stealth_commitment*: G1Projective
view_tag*: uint64
type PrivateKey* = Fr
type PublicKey* = G1Projective
@ -88,13 +105,18 @@ proc generateKeypair*(): FFIResult[KeyPair] =
drop_ffi_random_keypair(res_ptr)
return err("Error generating random keypair: " & $res_value.err_code)
let ret = KeyPair(private_key: res_value.value.private_key.x0, public_key: res_value.value.public_key.x0)
let ret = KeyPair(
private_key: res_value.value.private_key.x0,
public_key: res_value.value.public_key.x0,
)
drop_ffi_random_keypair(res_ptr)
return ok(ret)
proc generateStealthCommitment*(viewing_public_key: G1Projective,
proc generateStealthCommitment*(
viewing_public_key: G1Projective,
spending_public_key: G1Projective,
ephemeral_private_key: Fr): FFIResult[StealthCommitment] =
ephemeral_private_key: Fr,
): FFIResult[StealthCommitment] =
let viewing_public_key = CG1Projective(x0: viewing_public_key)
let viewing_public_key_ptr = unsafeAddr(viewing_public_key)
let spending_public_key = CG1Projective(x0: spending_public_key)
@ -102,20 +124,29 @@ proc generateStealthCommitment*(viewing_public_key: G1Projective,
let ephemeral_private_key = CFr(x0: ephemeral_private_key)
let ephemeral_private_key_ptr = unsafeAddr(ephemeral_private_key)
let res_ptr = (ffi_generate_stealth_commitment(viewing_public_key_ptr, spending_public_key_ptr, ephemeral_private_key_ptr))
let res_ptr = (
ffi_generate_stealth_commitment(
viewing_public_key_ptr, spending_public_key_ptr, ephemeral_private_key_ptr
)
)
let res_value = res_ptr[]
if res_value.err_code != 0:
drop_ffi_generate_stealth_commitment(res_ptr)
return err("Error generating stealth commitment: " & $res_value.err_code)
let ret = StealthCommitment(stealth_commitment: res_value.value.stealth_commitment.x0, view_tag: res_value.value.view_tag)
let ret = StealthCommitment(
stealth_commitment: res_value.value.stealth_commitment.x0,
view_tag: res_value.value.view_tag,
)
drop_ffi_generate_stealth_commitment(res_ptr)
return ok(ret)
proc generateStealthPrivateKey*(ephemeral_public_key: G1Projective,
proc generateStealthPrivateKey*(
ephemeral_public_key: G1Projective,
spending_key: Fr,
viewing_key: Fr,
view_tag: uint64): FFIResult[Fr] =
view_tag: uint64,
): FFIResult[Fr] =
let ephemeral_public_key = CG1Projective(x0: ephemeral_public_key)
let ephemeral_public_key_ptr = unsafeAddr(ephemeral_public_key)
let spending_key = CFr(x0: spending_key)
@ -124,7 +155,11 @@ proc generateStealthPrivateKey*(ephemeral_public_key: G1Projective,
let viewing_key_ptr = unsafeAddr(viewing_key)
let view_tag_ptr = unsafeAddr(view_tag)
let res_ptr = (ffi_generate_stealth_private_key(ephemeral_public_key_ptr, spending_key_ptr, viewing_key_ptr, view_tag_ptr))
let res_ptr = (
ffi_generate_stealth_private_key(
ephemeral_public_key_ptr, spending_key_ptr, viewing_key_ptr, view_tag_ptr
)
)
let res_value = res_ptr[]
if res_value.err_code != 0:
drop_ffi_generate_stealth_private_key(res_ptr)

View File

@ -15,19 +15,8 @@ import
libp2p/crypto/crypto
export
networks_config,
app,
logging,
options,
strutils,
os,
sequtils,
stewNet,
chronicles,
chronos,
metrics,
libbacktrace,
crypto
networks_config, app, logging, options, strutils, os, sequtils, stewNet, chronicles,
chronos, metrics, libbacktrace, crypto
proc setup*(): App =
const versionString = "version / git commit hash: " & app.git_version

View File

@ -12,9 +12,7 @@ import
./node_spec,
./wire_spec
export
wire_spec,
logging
export wire_spec, logging
type StealthCommitmentProtocol* = object
wakuApp: App
@ -22,7 +20,9 @@ type StealthCommitmentProtocol* = object
spendingKeyPair: StealthCommitmentFFI.KeyPair
viewingKeyPair: StealthCommitmentFFI.KeyPair
proc deserialize(T: type StealthCommitmentFFI.PublicKey, v: SerializedKey): Result[T, string] =
proc deserialize(
T: type StealthCommitmentFFI.PublicKey, v: SerializedKey
): Result[T, string] =
# deserialize seq[byte] into array[32, uint8]
if v.len != 32:
return err("invalid key length")
@ -31,19 +31,25 @@ proc deserialize(T: type StealthCommitmentFFI.PublicKey, v: SerializedKey): Resu
buf[i] = v[i]
return ok(buf)
proc serialize(v: StealthCommitmentFFI.PublicKey | StealthCommitmentFFI.PrivateKey): SerializedKey =
proc serialize(
v: StealthCommitmentFFI.PublicKey | StealthCommitmentFFI.PrivateKey
): SerializedKey =
# serialize array[32, uint8] into seq[byte]
var buf = newSeq[byte](v.len)
for i in 0 ..< v.len:
buf[i] = v[i]
return buf
proc sendThruWaku*(self: StealthCommitmentProtocol, msg: seq[byte]): Future[Result[void, string]] {.async.} =
proc sendThruWaku*(
self: StealthCommitmentProtocol, msg: seq[byte]
): Future[Result[void, string]] {.async.} =
let time = getTime().toUnix()
var message = WakuMessage(payload: msg,
var message = WakuMessage(
payload: msg,
contentTopic: self.contentTopic,
version: 0,
timestamp: getNanosecondTime(time))
timestamp: getNanosecondTime(time),
)
(self.wakuApp.node.wakuRlnRelay.appendRLNProof(message, float64(time))).isOkOr:
return err("could not append rate limit proof to the message: " & $error)
@ -55,28 +61,44 @@ proc sendThruWaku*(self: StealthCommitmentProtocol, msg: seq[byte]): Future[Resu
return ok()
proc sendRequest*(self: StealthCommitmentProtocol): Future[Result[void, string]] {.async.} =
let request = constructRequest(serialize(self.spendingKeyPair.publicKey), serialize(self.viewingKeyPair.publicKey)).encode()
proc sendRequest*(
self: StealthCommitmentProtocol
): Future[Result[void, string]] {.async.} =
let request = constructRequest(
serialize(self.spendingKeyPair.publicKey),
serialize(self.viewingKeyPair.publicKey),
)
.encode()
try:
(await self.sendThruWaku(request.buffer)).isOkOr:
return err("Could not send stealth commitment payload thru waku: " & $error)
except CatchableError:
return err("Could not send stealth commitment payload thru waku: " & getCurrentExceptionMsg())
return err(
"Could not send stealth commitment payload thru waku: " & getCurrentExceptionMsg()
)
return ok()
proc sendResponse*(self: StealthCommitmentProtocol, stealthCommitment: StealthCommitmentFFI.PublicKey, ephemeralPubKey: StealthCommitmentFFI.PublicKey, viewTag: uint64): Future[Result[void, string]] {.async.} =
let response = constructResponse(serialize(stealthCommitment), serialize(ephemeralPubKey), viewTag).encode()
proc sendResponse*(
self: StealthCommitmentProtocol,
stealthCommitment: StealthCommitmentFFI.PublicKey,
ephemeralPubKey: StealthCommitmentFFI.PublicKey,
viewTag: uint64,
): Future[Result[void, string]] {.async.} =
let response = constructResponse(
serialize(stealthCommitment), serialize(ephemeralPubKey), viewTag
)
.encode()
try:
(await self.sendThruWaku(response.buffer)).isOkOr:
return err("Could not send stealth commitment payload thru waku: " & $error)
except CatchableError:
return err("Could not send stealth commitment payload thru waku: " & getCurrentExceptionMsg())
return err(
"Could not send stealth commitment payload thru waku: " & getCurrentExceptionMsg()
)
return ok()
type SCPHandler* = proc(msg: WakuMessage): Future[void] {.async.}
proc getSCPHandler(self: StealthCommitmentProtocol): SCPHandler =
let handler = proc(msg: WakuMessage): Future[void] {.async.} =
let decodedRes = WakuStealthCommitmentMsg.decode(msg.payload)
if decodedRes.isErr():
@ -85,27 +107,36 @@ proc getSCPHandler(self: StealthCommitmentProtocol): SCPHandler =
if decoded.request == false:
# check if the generated stealth commitment belongs to the receiver
# if not, continue
let ephemeralPubKeyRes = deserialize(StealthCommitmentFFI.PublicKey, decoded.ephemeralPubKey.get())
let ephemeralPubKeyRes =
deserialize(StealthCommitmentFFI.PublicKey, decoded.ephemeralPubKey.get())
if ephemeralPubKeyRes.isErr():
error "could not deserialize ephemeral public key: ", err = ephemeralPubKeyRes.error()
error "could not deserialize ephemeral public key: ",
err = ephemeralPubKeyRes.error()
let ephemeralPubKey = ephemeralPubKeyRes.get()
let stealthCommitmentPrivateKeyRes = StealthCommitmentFFI.generateStealthPrivateKey(ephemeralPubKey,
let stealthCommitmentPrivateKeyRes = StealthCommitmentFFI.generateStealthPrivateKey(
ephemeralPubKey,
self.spendingKeyPair.privateKey,
self.viewingKeyPair.privateKey,
decoded.viewTag.get())
decoded.viewTag.get(),
)
if stealthCommitmentPrivateKeyRes.isErr():
info "received stealth commitment does not belong to the receiver: ", err = stealthCommitmentPrivateKeyRes.error()
info "received stealth commitment does not belong to the receiver: ",
err = stealthCommitmentPrivateKeyRes.error()
let stealthCommitmentPrivateKey = stealthCommitmentPrivateKeyRes.get()
info "received stealth commitment belongs to the receiver: ", stealthCommitmentPrivateKey, stealthCommitmentPubKey = decoded.stealthCommitment.get()
info "received stealth commitment belongs to the receiver: ",
stealthCommitmentPrivateKey,
stealthCommitmentPubKey = decoded.stealthCommitment.get()
return
# send response
# deseralize the keys
let spendingKeyRes = deserialize(StealthCommitmentFFI.PublicKey, decoded.spendingPubKey.get())
let spendingKeyRes =
deserialize(StealthCommitmentFFI.PublicKey, decoded.spendingPubKey.get())
if spendingKeyRes.isErr():
error "could not deserialize spending key: ", err = spendingKeyRes.error()
let spendingKey = spendingKeyRes.get()
let viewingKeyRes = (deserialize(StealthCommitmentFFI.PublicKey, decoded.viewingPubKey.get()))
let viewingKeyRes =
(deserialize(StealthCommitmentFFI.PublicKey, decoded.viewingPubKey.get()))
if viewingKeyRes.isErr():
error "could not deserialize viewing key: ", err = viewingKeyRes.error()
let viewingKey = viewingKeyRes.get()
@ -117,17 +148,27 @@ proc getSCPHandler(self: StealthCommitmentProtocol): SCPHandler =
error "could not generate ephemeral key pair: ", err = ephemeralKeyPairRes.error()
let ephemeralKeyPair = ephemeralKeyPairRes.get()
let stealthCommitmentRes = StealthCommitmentFFI.generateStealthCommitment(spendingKey, viewingKey, ephemeralKeyPair.privateKey)
let stealthCommitmentRes = StealthCommitmentFFI.generateStealthCommitment(
spendingKey, viewingKey, ephemeralKeyPair.privateKey
)
if stealthCommitmentRes.isErr():
error "could not generate stealth commitment: ", err = stealthCommitmentRes.error()
error "could not generate stealth commitment: ",
err = stealthCommitmentRes.error()
let stealthCommitment = stealthCommitmentRes.get()
(await self.sendResponse(stealthCommitment.stealthCommitment, ephemeralKeyPair.publicKey, stealthCommitment.viewTag)).isOkOr:
(
await self.sendResponse(
stealthCommitment.stealthCommitment, ephemeralKeyPair.publicKey,
stealthCommitment.viewTag,
)
).isOkOr:
error "could not send response: ", err = $error
return handler
proc new*(wakuApp: App, contentTopic = ContentTopic("/wakustealthcommitments/1/app/proto")): Result[StealthCommitmentProtocol, string] =
proc new*(
wakuApp: App, contentTopic = ContentTopic("/wakustealthcommitments/1/app/proto")
): Result[StealthCommitmentProtocol, string] =
let spendingKeyPair = StealthCommitmentFFI.generateKeyPair().valueOr:
return err("could not generate spending key pair: " & $error)
let viewingKeyPair = StealthCommitmentFFI.generateKeyPair().valueOr:
@ -136,11 +177,12 @@ proc new*(wakuApp: App, contentTopic = ContentTopic("/wakustealthcommitments/1/a
info "spending public key", publicKey = spendingKeyPair.publicKey
info "viewing public key", publicKey = viewingKeyPair.publicKey
let SCP = StealthCommitmentProtocol(wakuApp: wakuApp,
let SCP = StealthCommitmentProtocol(
wakuApp: wakuApp,
contentTopic: contentTopic,
spendingKeyPair: spendingKeyPair,
viewingKeyPair: viewingKeyPair)
viewingKeyPair: viewingKeyPair,
)
proc handler(topic: PubsubTopic, msg: WakuMessage): Future[void] {.async, gcsafe.} =
let scpHandler = getSCPHandler(SCP)

View File

@ -4,10 +4,7 @@ else:
{.push raises: [].}
import
stew/results,
chronicles,
./node_spec as Waku,
./stealth_commitment_protocol as SCP
stew/results, chronicles, ./node_spec as Waku, ./stealth_commitment_protocol as SCP
logScope:
topics = "waku stealthcommitments"

View File

@ -1,31 +1,16 @@
import std/[times, options]
import
confutils,
chronicles,
chronos,
stew/results
import confutils, chronicles, chronos, stew/results
import
../../waku/waku_core,
../../waku/common/protobuf
import ../../waku/waku_core, ../../waku/common/protobuf
import libp2p/protobuf/minprotobuf
export
times,
options,
confutils,
chronicles,
chronos,
results,
waku_core,
protobuf,
times, options, confutils, chronicles, chronos, results, waku_core, protobuf,
minprotobuf
type SerializedKey* = seq[byte]
type
WakuStealthCommitmentMsg* = object
type WakuStealthCommitmentMsg* = object
request*: bool
spendingPubKey*: Option[SerializedKey]
viewingPubKey*: Option[SerializedKey]
@ -42,10 +27,18 @@ proc decode*(T: type WakuStealthCommitmentMsg, buffer: seq[byte]): ProtoResult[T
msg.request = request == 1
var spendingPubKey = newSeq[byte]()
discard ?pb.getField(2, spendingPubKey)
msg.spendingPubKey = if spendingPubKey.len > 0: some(spendingPubKey) else: none(SerializedKey)
msg.spendingPubKey =
if spendingPubKey.len > 0:
some(spendingPubKey)
else:
none(SerializedKey)
var viewingPubKey = newSeq[byte]()
discard ?pb.getField(3, viewingPubKey)
msg.viewingPubKey = if viewingPubKey.len > 0: some(viewingPubKey) else: none(SerializedKey)
msg.viewingPubKey =
if viewingPubKey.len > 0:
some(viewingPubKey)
else:
none(SerializedKey)
if msg.spendingPubKey.isSome() and msg.viewingPubKey.isSome():
msg.stealthCommitment = none(SerializedKey)
@ -58,20 +51,32 @@ proc decode*(T: type WakuStealthCommitmentMsg, buffer: seq[byte]): ProtoResult[T
if msg.request == true and msg.spendingPubKey.isNone() and msg.viewingPubKey.isNone():
return err(ProtoError.RequiredFieldMissing)
var stealthCommitment = newSeq[byte]()
discard ?pb.getField(4, stealthCommitment)
msg.stealthCommitment = if stealthCommitment.len > 0: some(stealthCommitment) else: none(SerializedKey)
msg.stealthCommitment =
if stealthCommitment.len > 0:
some(stealthCommitment)
else:
none(SerializedKey)
var ephemeralPubKey = newSeq[byte]()
discard ?pb.getField(5, ephemeralPubKey)
msg.ephemeralPubKey = if ephemeralPubKey.len > 0: some(ephemeralPubKey) else: none(SerializedKey)
msg.ephemeralPubKey =
if ephemeralPubKey.len > 0:
some(ephemeralPubKey)
else:
none(SerializedKey)
var viewTag: uint64
discard ?pb.getField(6, viewTag)
msg.viewTag = if viewTag != 0: some(viewTag) else: none(uint64)
msg.viewTag =
if viewTag != 0:
some(viewTag)
else:
none(uint64)
if msg.stealthCommitment.isNone() and msg.viewTag.isNone() and msg.ephemeralPubKey.isNone():
if msg.stealthCommitment.isNone() and msg.viewTag.isNone() and
msg.ephemeralPubKey.isNone():
return err(ProtoError.RequiredFieldMissing)
if msg.stealthCommitment.isSome() and msg.viewTag.isNone():
@ -108,8 +113,21 @@ func toByteSeq*(str: string): seq[byte] {.inline.} =
## Converts a string to the corresponding byte sequence.
@(str.toOpenArrayByte(0, str.high))
proc constructRequest*(spendingPubKey: SerializedKey, viewingPubKey: SerializedKey): WakuStealthCommitmentMsg =
WakuStealthCommitmentMsg(request: true, spendingPubKey: some(spendingPubKey), viewingPubKey: some(viewingPubKey))
proc constructRequest*(
spendingPubKey: SerializedKey, viewingPubKey: SerializedKey
): WakuStealthCommitmentMsg =
WakuStealthCommitmentMsg(
request: true,
spendingPubKey: some(spendingPubKey),
viewingPubKey: some(viewingPubKey),
)
proc constructResponse*(stealthCommitment: SerializedKey, ephemeralPubKey: SerializedKey, viewTag: uint64): WakuStealthCommitmentMsg =
WakuStealthCommitmentMsg(request: false, stealthCommitment: some(stealthCommitment), ephemeralPubKey: some(ephemeralPubKey), viewTag: some(viewTag))
proc constructResponse*(
stealthCommitment: SerializedKey, ephemeralPubKey: SerializedKey, viewTag: uint64
): WakuStealthCommitmentMsg =
WakuStealthCommitmentMsg(
request: false,
stealthCommitment: some(stealthCommitment),
ephemeralPubKey: some(ephemeralPubKey),
viewTag: some(viewTag),
)

View File

@ -1,6 +1,3 @@
type
WakuCallBack* = proc(callerRet: cint,
msg: ptr cchar,
len: csize_t,
userData: pointer) {.cdecl, gcsafe, raises: [].}
type WakuCallBack* = proc(
callerRet: cint, msg: ptr cchar, len: csize_t, userData: pointer
) {.cdecl, gcsafe, raises: [].}

View File

@ -1,8 +1,6 @@
type JsonEvent* = ref object of RootObj
# https://rfc.vac.dev/spec/36/#jsonsignal-type
type JsonEvent* = ref object of RootObj # https://rfc.vac.dev/spec/36/#jsonsignal-type
eventType* {.requiresInit.}: string
method `$`*(jsonEvent: JsonEvent): string {.base.} = discard
method `$`*(jsonEvent: JsonEvent): string {.base.} =
discard
# All events should implement this

View File

@ -1,18 +1,12 @@
import
system,
std/[json,sequtils]
import
stew/[byteutils,results]
import system, std/[json, sequtils]
import stew/[byteutils, results]
import
../../waku/common/base64,
../../waku/waku_core/message,
../../waku/waku_core/message/message,
./json_base_event
type
JsonMessage* = ref object
# https://rfc.vac.dev/spec/36/#jsonmessage-type
type JsonMessage* = ref object # https://rfc.vac.dev/spec/36/#jsonmessage-type
payload*: Base64String
contentTopic*: string
version*: uint
@ -30,7 +24,7 @@ func fromJsonNode*(T: type JsonMessage, jsonContent: JsonNode): JsonMessage =
timestamp: int64(jsonContent{"timestamp"}.getBiggestInt()),
ephemeral: jsonContent{"ephemeral"}.getBool(),
meta: Base64String(jsonContent{"meta"}.getStr()),
proof: Base64String(jsonContent{"proof"}.getStr())
proof: Base64String(jsonContent{"proof"}.getStr()),
)
proc toWakuMessage*(self: JsonMessage): Result[WakuMessage, string] =
@ -43,7 +37,8 @@ proc toWakuMessage*(self: JsonMessage): Result[WakuMessage, string] =
let proof = base64.decode(self.proof).valueOr:
return err("invalid proof format: " & error)
ok(WakuMessage(
ok(
WakuMessage(
payload: payload,
meta: meta,
contentTopic: self.contentTopic,
@ -51,7 +46,8 @@ proc toWakuMessage*(self: JsonMessage): Result[WakuMessage, string] =
timestamp: self.timestamp,
ephemeral: self.ephemeral,
proof: proof,
))
)
)
proc `%`*(value: Base64String): JsonNode =
%(value.string)
@ -64,9 +60,7 @@ type JsonMessageEvent* = ref object of JsonEvent
messageHash*: WakuMessageHash
wakuMessage*: JsonMessage
proc new*(T: type JsonMessageEvent,
pubSubTopic: string,
msg: WakuMessage): T =
proc new*(T: type JsonMessageEvent, pubSubTopic: string, msg: WakuMessage): T =
# Returns a WakuMessage event as indicated in
# https://rfc.vac.dev/spec/36/#jsonmessageevent-type
@ -96,7 +90,7 @@ proc new*(T: type JsonMessageEvent,
ephemeral: msg.ephemeral,
meta: base64.encode(meta),
proof: base64.encode(proof),
)
),
)
method `$`*(jsonMessage: JsonMessageEvent): string =

View File

@ -1,13 +1,9 @@
{.pragma: exported, exportc, cdecl, raises: [].}
{.pragma: callback, cdecl, raises: [], gcsafe.}
{.passc: "-fPIC".}
import
std/[json,sequtils,times,strformat,options,atomics,strutils]
import
chronicles,
chronos
import std/[json, sequtils, times, strformat, options, atomics, strutils]
import chronicles, chronos
import
../../waku/common/base64,
../../waku/waku_core/message/message,
@ -44,7 +40,9 @@ const RET_MISSING_CALLBACK: cint = 2
### Not-exported components
proc relayEventCallback(ctx: ptr Context): WakuRelayHandler =
return proc (pubsubTopic: PubsubTopic, msg: WakuMessage): Future[system.void]{.async.} =
return proc(
pubsubTopic: PubsubTopic, msg: WakuMessage
): Future[system.void] {.async.} =
# Callback that hadles the Waku Relay events. i.e. messages or errors.
if isNil(ctx[].eventCallback):
error "eventCallback is nil"
@ -56,12 +54,14 @@ proc relayEventCallback(ctx: ptr Context): WakuRelayHandler =
try:
let event = $JsonMessageEvent.new(pubsubTopic, msg)
cast[WakuCallBack](ctx[].eventCallback)(RET_OK, unsafeAddr event[0], cast[csize_t](len(event)), ctx[].eventUserData)
cast[WakuCallBack](ctx[].eventCallback)(
RET_OK, unsafeAddr event[0], cast[csize_t](len(event)), ctx[].eventUserData
)
except Exception, CatchableError:
let msg = "Exception when calling 'eventCallBack': " &
getCurrentExceptionMsg()
cast[WakuCallBack](ctx[].eventCallback)(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), ctx[].eventUserData)
let msg = "Exception when calling 'eventCallBack': " & getCurrentExceptionMsg()
cast[WakuCallBack](ctx[].eventCallback)(
RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), ctx[].eventUserData
)
### End of not-exported components
################################################################################
@ -69,10 +69,9 @@ proc relayEventCallback(ctx: ptr Context): WakuRelayHandler =
################################################################################
### Exported procs
proc waku_new(configJson: cstring,
callback: WakuCallback,
userData: pointer): pointer
{.dynlib, exportc, cdecl.} =
proc waku_new(
configJson: cstring, callback: WakuCallback, userData: pointer
): pointer {.dynlib, exportc, cdecl.} =
## Creates a new instance of the WakuNode.
if isNil(callback):
@ -90,9 +89,8 @@ proc waku_new(configJson: cstring,
let sendReqRes = waku_thread.sendRequestToWakuThread(
ctx,
RequestType.LIFECYCLE,
NodeLifecycleRequest.createShared(
NodeLifecycleMsgType.CREATE_NODE,
configJson))
NodeLifecycleRequest.createShared(NodeLifecycleMsgType.CREATE_NODE, configJson),
)
if sendReqRes.isErr():
let msg = $sendReqRes.error
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
@ -100,10 +98,9 @@ proc waku_new(configJson: cstring,
return ctx
proc waku_destroy(ctx: ptr Context,
callback: WakuCallBack,
userData: pointer): cint {.dynlib, exportc.} =
proc waku_destroy(
ctx: ptr Context, callback: WakuCallBack, userData: pointer
): cint {.dynlib, exportc.} =
if isNil(callback):
return RET_MISSING_CALLBACK
@ -114,33 +111,38 @@ proc waku_destroy(ctx: ptr Context,
return RET_OK
proc waku_version(ctx: ptr Context,
callback: WakuCallBack,
userData: pointer): cint {.dynlib, exportc.} =
proc waku_version(
ctx: ptr Context, callback: WakuCallBack, userData: pointer
): cint {.dynlib, exportc.} =
ctx[].userData = userData
if isNil(callback):
return RET_MISSING_CALLBACK
callback(RET_OK, cast[ptr cchar](WakuNodeVersionString),
cast[csize_t](len(WakuNodeVersionString)), userData)
callback(
RET_OK,
cast[ptr cchar](WakuNodeVersionString),
cast[csize_t](len(WakuNodeVersionString)),
userData,
)
return RET_OK
proc waku_set_event_callback(ctx: ptr Context,
callback: WakuCallBack,
userData: pointer) {.dynlib, exportc.} =
proc waku_set_event_callback(
ctx: ptr Context, callback: WakuCallBack, userData: pointer
) {.dynlib, exportc.} =
ctx[].eventCallback = cast[pointer](callback)
ctx[].eventUserData = userData
proc waku_content_topic(ctx: ptr Context,
proc waku_content_topic(
ctx: ptr Context,
appName: cstring,
appVersion: cuint,
contentTopicName: cstring,
encoding: cstring,
callback: WakuCallBack,
userData: pointer): cint {.dynlib, exportc.} =
userData: pointer,
): cint {.dynlib, exportc.} =
# https://rfc.vac.dev/spec/36/#extern-char-waku_content_topicchar-applicationname-unsigned-int-applicationversion-char-contenttopicname-char-encoding
ctx[].userData = userData
@ -153,7 +155,9 @@ proc waku_content_topic(ctx: ptr Context,
let encodingStr = encoding.alloc()
let contentTopic = fmt"/{$appStr}/{appVersion}/{$ctnStr}/{$encodingStr}"
callback(RET_OK, unsafeAddr contentTopic[0], cast[csize_t](len(contentTopic)), userData)
callback(
RET_OK, unsafeAddr contentTopic[0], cast[csize_t](len(contentTopic)), userData
)
deallocShared(appStr)
deallocShared(ctnStr)
@ -161,10 +165,9 @@ proc waku_content_topic(ctx: ptr Context,
return RET_OK
proc waku_pubsub_topic(ctx: ptr Context,
topicName: cstring,
callback: WakuCallBack,
userData: pointer): cint {.dynlib, exportc, cdecl.} =
proc waku_pubsub_topic(
ctx: ptr Context, topicName: cstring, callback: WakuCallBack, userData: pointer
): cint {.dynlib, exportc, cdecl.} =
# https://rfc.vac.dev/spec/36/#extern-char-waku_pubsub_topicchar-name-char-encoding
ctx[].userData = userData
@ -175,15 +178,17 @@ proc waku_pubsub_topic(ctx: ptr Context,
let topicNameStr = topicName.alloc()
let outPubsubTopic = fmt"/waku/2/{$topicNameStr}"
callback(RET_OK, unsafeAddr outPubsubTopic[0], cast[csize_t](len(outPubsubTopic)), userData)
callback(
RET_OK, unsafeAddr outPubsubTopic[0], cast[csize_t](len(outPubsubTopic)), userData
)
deallocShared(topicNameStr)
return RET_OK
proc waku_default_pubsub_topic(ctx: ptr Context,
callback: WakuCallBack,
userData: pointer): cint {.dynlib, exportc.} =
proc waku_default_pubsub_topic(
ctx: ptr Context, callback: WakuCallBack, userData: pointer
): cint {.dynlib, exportc.} =
# https://rfc.vac.dev/spec/36/#extern-char-waku_default_pubsub_topic
ctx[].userData = userData
@ -191,18 +196,23 @@ proc waku_default_pubsub_topic(ctx: ptr Context,
if isNil(callback):
return RET_MISSING_CALLBACK
callback(RET_OK, cast[ptr cchar](DefaultPubsubTopic), cast[csize_t](len(DefaultPubsubTopic)), userData)
callback(
RET_OK,
cast[ptr cchar](DefaultPubsubTopic),
cast[csize_t](len(DefaultPubsubTopic)),
userData,
)
return RET_OK
proc waku_relay_publish(ctx: ptr Context,
proc waku_relay_publish(
ctx: ptr Context,
pubSubTopic: cstring,
jsonWakuMessage: cstring,
timeoutMs: cuint,
callback: WakuCallBack,
userData: pointer): cint
{.dynlib, exportc, cdecl.} =
userData: pointer,
): cint {.dynlib, exportc, cdecl.} =
# https://rfc.vac.dev/spec/36/#extern-char-waku_relay_publishchar-messagejson-char-pubsubtopic-int-timeoutms
ctx[].userData = userData
@ -230,7 +240,8 @@ proc waku_relay_publish(ctx: ptr Context,
let pst = pubSubTopic.alloc()
let targetPubSubTopic = if len(pst) == 0:
let targetPubSubTopic =
if len(pst) == 0:
DefaultPubsubTopic
else:
$pst
@ -238,10 +249,13 @@ proc waku_relay_publish(ctx: ptr Context,
let sendReqRes = waku_thread.sendRequestToWakuThread(
ctx,
RequestType.RELAY,
RelayRequest.createShared(RelayMsgType.PUBLISH,
RelayRequest.createShared(
RelayMsgType.PUBLISH,
PubsubTopic($pst),
WakuRelayHandler(relayEventCallback(ctx)),
wakuMessage))
wakuMessage,
),
)
deallocShared(pst)
if sendReqRes.isErr():
@ -253,36 +267,31 @@ proc waku_relay_publish(ctx: ptr Context,
callback(RET_OK, unsafeAddr msgHash[0], cast[csize_t](len(msgHash)), userData)
return RET_OK
proc waku_start(ctx: ptr Context,
callback: WakuCallBack,
userData: pointer): cint {.dynlib, exportc.} =
proc waku_start(
ctx: ptr Context, callback: WakuCallBack, userData: pointer
): cint {.dynlib, exportc.} =
ctx[].userData = userData
## TODO: handle the error
discard waku_thread.sendRequestToWakuThread(
ctx,
RequestType.LIFECYCLE,
NodeLifecycleRequest.createShared(
NodeLifecycleMsgType.START_NODE))
NodeLifecycleRequest.createShared(NodeLifecycleMsgType.START_NODE),
)
proc waku_stop(ctx: ptr Context,
callback: WakuCallBack,
userData: pointer): cint {.dynlib, exportc.} =
proc waku_stop(
ctx: ptr Context, callback: WakuCallBack, userData: pointer
): cint {.dynlib, exportc.} =
ctx[].userData = userData
## TODO: handle the error
discard waku_thread.sendRequestToWakuThread(
ctx,
RequestType.LIFECYCLE,
NodeLifecycleRequest.createShared(
NodeLifecycleMsgType.STOP_NODE))
NodeLifecycleRequest.createShared(NodeLifecycleMsgType.STOP_NODE),
)
proc waku_relay_subscribe(
ctx: ptr Context,
pubSubTopic: cstring,
callback: WakuCallBack,
userData: pointer): cint
{.dynlib, exportc.} =
ctx: ptr Context, pubSubTopic: cstring, callback: WakuCallBack, userData: pointer
): cint {.dynlib, exportc.} =
ctx[].userData = userData
let pst = pubSubTopic.alloc()
@ -290,9 +299,10 @@ proc waku_relay_subscribe(
let sendReqRes = waku_thread.sendRequestToWakuThread(
ctx,
RequestType.RELAY,
RelayRequest.createShared(RelayMsgType.SUBSCRIBE,
PubsubTopic($pst),
WakuRelayHandler(cb)))
RelayRequest.createShared(
RelayMsgType.SUBSCRIBE, PubsubTopic($pst), WakuRelayHandler(cb)
),
)
deallocShared(pst)
if sendReqRes.isErr():
@ -303,12 +313,8 @@ proc waku_relay_subscribe(
return RET_OK
proc waku_relay_unsubscribe(
ctx: ptr Context,
pubSubTopic: cstring,
callback: WakuCallBack,
userData: pointer): cint
{.dynlib, exportc.} =
ctx: ptr Context, pubSubTopic: cstring, callback: WakuCallBack, userData: pointer
): cint {.dynlib, exportc.} =
ctx[].userData = userData
let pst = pubSubTopic.alloc()
@ -316,9 +322,12 @@ proc waku_relay_unsubscribe(
let sendReqRes = waku_thread.sendRequestToWakuThread(
ctx,
RequestType.RELAY,
RelayRequest.createShared(RelayMsgType.SUBSCRIBE,
RelayRequest.createShared(
RelayMsgType.SUBSCRIBE,
PubsubTopic($pst),
WakuRelayHandler(relayEventCallback(ctx))))
WakuRelayHandler(relayEventCallback(ctx)),
),
)
deallocShared(pst)
if sendReqRes.isErr():
@ -328,22 +337,22 @@ proc waku_relay_unsubscribe(
return RET_OK
proc waku_connect(ctx: ptr Context,
proc waku_connect(
ctx: ptr Context,
peerMultiAddr: cstring,
timeoutMs: cuint,
callback: WakuCallBack,
userData: pointer): cint
{.dynlib, exportc.} =
userData: pointer,
): cint {.dynlib, exportc.} =
ctx[].userData = userData
let connRes = waku_thread.sendRequestToWakuThread(
ctx,
RequestType.PEER_MANAGER,
PeerManagementRequest.createShared(
PeerManagementMsgType.CONNECT_TO,
$peerMultiAddr,
chronos.milliseconds(timeoutMs)))
PeerManagementMsgType.CONNECT_TO, $peerMultiAddr, chronos.milliseconds(timeoutMs)
),
)
if connRes.isErr():
let msg = $connRes.error
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)
@ -351,14 +360,14 @@ proc waku_connect(ctx: ptr Context,
return RET_OK
proc waku_store_query(ctx: ptr Context,
proc waku_store_query(
ctx: ptr Context,
queryJson: cstring,
peerId: cstring,
timeoutMs: cint,
callback: WakuCallBack,
userData: pointer): cint
{.dynlib, exportc.} =
userData: pointer,
): cint {.dynlib, exportc.} =
ctx[].userData = userData
## TODO: implement the logic that make the "self" node to act as a Store client
@ -370,18 +379,16 @@ proc waku_store_query(ctx: ptr Context,
return RET_OK
proc waku_listen_addresses(ctx: ptr Context,
callback: WakuCallBack,
userData: pointer): cint
{.dynlib, exportc.} =
proc waku_listen_addresses(
ctx: ptr Context, callback: WakuCallBack, userData: pointer
): cint {.dynlib, exportc.} =
ctx[].userData = userData
let connRes = waku_thread.sendRequestToWakuThread(
ctx,
RequestType.DEBUG,
DebugNodeRequest.createShared(
DebugNodeMsgType.RETRIEVE_LISTENING_ADDRESSES))
DebugNodeRequest.createShared(DebugNodeMsgType.RETRIEVE_LISTENING_ADDRESSES),
)
if connRes.isErr():
let msg = $connRes.error
callback(RET_ERR, unsafeAddr msg[0], cast[csize_t](len(msg)), userData)

View File

@ -1,7 +1,4 @@
import
std/[json,strformat,options]
import std/[json, strformat, options]
import
libp2p/crypto/crypto,
libp2p/crypto/secp,
@ -12,10 +9,9 @@ import
../../waku/node/config,
../events/json_base_event
proc parsePrivateKey(jsonNode: JsonNode,
privateKey: var PrivateKey,
errorResp: var string): bool =
proc parsePrivateKey(
jsonNode: JsonNode, privateKey: var PrivateKey, errorResp: var string
): bool =
if not jsonNode.contains("key") or jsonNode["key"].kind == JsonNodeKind.JNull:
privateKey = PrivateKey.random(Secp256k1, newRng()[]).tryGet()
return true
@ -36,10 +32,9 @@ proc parsePrivateKey(jsonNode: JsonNode,
return true
proc parseListenAddr(jsonNode: JsonNode,
listenAddr: var IpAddress,
errorResp: var string): bool =
proc parseListenAddr(
jsonNode: JsonNode, listenAddr: var IpAddress, errorResp: var string
): bool =
if not jsonNode.contains("host"):
errorResp = "host attribute is required"
return false
@ -59,10 +54,7 @@ proc parseListenAddr(jsonNode: JsonNode,
return true
proc parsePort(jsonNode: JsonNode,
port: var int,
errorResp: var string): bool =
proc parsePort(jsonNode: JsonNode, port: var int, errorResp: var string): bool =
if not jsonNode.contains("port"):
errorResp = "port attribute is required"
return false
@ -75,10 +67,7 @@ proc parsePort(jsonNode: JsonNode,
return true
proc parseRelay(jsonNode: JsonNode,
relay: var bool,
errorResp: var string): bool =
proc parseRelay(jsonNode: JsonNode, relay: var bool, errorResp: var string): bool =
if not jsonNode.contains("relay"):
errorResp = "relay attribute is required"
return false
@ -91,7 +80,8 @@ proc parseRelay(jsonNode: JsonNode,
return true
proc parseStore(jsonNode: JsonNode,
proc parseStore(
jsonNode: JsonNode,
store: var bool,
storeNode: var string,
storeRetentionPolicy: var string,
@ -99,8 +89,8 @@ proc parseStore(jsonNode: JsonNode,
storeVacuum: var bool,
storeDbMigration: var bool,
storeMaxNumDbConnections: var int,
errorResp: var string): bool =
errorResp: var string,
): bool =
if not jsonNode.contains("store"):
## the store parameter is not required. By default is is disabled
store = false
@ -163,7 +153,8 @@ proc parseTopics(jsonNode: JsonNode, topics: var seq[string]) =
else:
topics = @["/waku/2/default-waku/proto"]
proc parseConfig*(configNodeJson: string,
proc parseConfig*(
configNodeJson: string,
privateKey: var PrivateKey,
netConfig: var NetConfig,
relay: var bool,
@ -175,8 +166,8 @@ proc parseConfig*(configNodeJson: string,
storeVacuum: var bool,
storeDbMigration: var bool,
storeMaxNumDbConnections: var int,
errorResp: var string): bool {.raises: [].} =
errorResp: var string,
): bool {.raises: [].} =
if configNodeJson.len == 0:
errorResp = "The configNodeJson is empty"
return false
@ -215,16 +206,15 @@ proc parseConfig*(configNodeJson: string,
errorResp = "Exception calling parsePort: " & getCurrentExceptionMsg()
return false
let natRes = setupNat("any", clientId,
Port(uint16(port)),
Port(uint16(port)))
let natRes = setupNat("any", clientId, Port(uint16(port)), Port(uint16(port)))
if natRes.isErr():
errorResp = "failed to setup NAT: " & $natRes.error
return false
let (extIp, extTcpPort, _) = natRes.get()
let extPort = if extIp.isSome() and extTcpPort.isNone():
let extPort =
if extIp.isSome() and extTcpPort.isNone():
some(Port(uint16(port)))
else:
extTcpPort
@ -246,18 +236,17 @@ proc parseConfig*(configNodeJson: string,
# store
try:
if not parseStore(jsonNode, store, storeNode, storeRetentionPolicy, storeDbUrl,
storeVacuum, storeDbMigration, storeMaxNumDbConnections, errorResp):
if not parseStore(
jsonNode, store, storeNode, storeRetentionPolicy, storeDbUrl, storeVacuum,
storeDbMigration, storeMaxNumDbConnections, errorResp,
):
return false
except Exception, KeyError:
errorResp = "Exception calling parseStore: " & getCurrentExceptionMsg()
return false
let wakuFlags = CapabilitiesBitfield.init(
lightpush = false,
filter = false,
store = false,
relay = relay
lightpush = false, filter = false, store = false, relay = relay
)
let netConfigRes = NetConfig.init(
@ -265,7 +254,8 @@ proc parseConfig*(configNodeJson: string,
bindPort = Port(uint16(port)),
extIp = extIp,
extPort = extPort,
wakuFlags = some(wakuFlags))
wakuFlags = some(wakuFlags),
)
if netConfigRes.isErr():
errorResp = "Error creating NetConfig: " & $netConfigRes.error

View File

@ -1,26 +1,14 @@
import std/[options, sequtils, strutils, json]
import chronicles, chronos, stew/results, stew/shims/net
import ../../../../waku/node/waku_node, ../../../alloc
import
std/[options,sequtils,strutils,json]
import
chronicles,
chronos,
stew/results,
stew/shims/net
import
../../../../waku/node/waku_node,
../../../alloc
type
DebugNodeMsgType* = enum
type DebugNodeMsgType* = enum
RETRIEVE_LISTENING_ADDRESSES
type
DebugNodeRequest* = object
type DebugNodeRequest* = object
operation: DebugNodeMsgType
proc createShared*(T: type DebugNodeRequest,
op: DebugNodeMsgType): ptr type T =
proc createShared*(T: type DebugNodeRequest, op: DebugNodeMsgType): ptr type T =
var ret = createShared(T)
ret[].operation = op
return ret
@ -31,14 +19,14 @@ proc destroyShared(self: ptr DebugNodeRequest) =
proc getMultiaddresses(node: WakuNode): seq[string] =
return node.info().listenAddresses
proc process*(self: ptr DebugNodeRequest,
node: WakuNode): Future[Result[string, string]] {.async.} =
proc process*(
self: ptr DebugNodeRequest, node: WakuNode
): Future[Result[string, string]] {.async.} =
defer:
destroyShared(self)
defer: destroyShared(self)
case self.operation:
case self.operation
of RETRIEVE_LISTENING_ADDRESSES:
return ok($(%*node.getMultiaddresses()))
return err("unsupported operation in DebugNodeRequest")

View File

@ -1,11 +1,5 @@
import
std/options
import
chronos,
chronicles,
stew/results,
stew/shims/net
import std/options
import chronos, chronicles, stew/results, stew/shims/net
import
../../../../waku/common/enr/builder,
../../../../waku/waku_enr/capabilities,
@ -28,21 +22,18 @@ import
../../../alloc,
../../config
type
NodeLifecycleMsgType* = enum
type NodeLifecycleMsgType* = enum
CREATE_NODE
START_NODE
STOP_NODE
type
NodeLifecycleRequest* = object
type NodeLifecycleRequest* = object
operation: NodeLifecycleMsgType
configJson: cstring ## Only used in 'CREATE_NODE' operation
proc createShared*(T: type NodeLifecycleRequest,
op: NodeLifecycleMsgType,
configJson: cstring = ""): ptr type T =
proc createShared*(
T: type NodeLifecycleRequest, op: NodeLifecycleMsgType, configJson: cstring = ""
): ptr type T =
var ret = createShared(T)
ret[].operation = op
ret[].configJson = configJson.alloc()
@ -52,14 +43,15 @@ proc destroyShared(self: ptr NodeLifecycleRequest) =
deallocShared(self[].configJson)
deallocShared(self)
proc configureStore(node: WakuNode,
proc configureStore(
node: WakuNode,
storeNode: string,
storeRetentionPolicy: string,
storeDbUrl: string,
storeVacuum: bool,
storeDbMigration: bool,
storeMaxNumDbConnections: int):
Future[Result[void, string]] {.async.} =
storeMaxNumDbConnections: int,
): Future[Result[void, string]] {.async.} =
## This snippet is extracted/duplicated from the app.nim file
var onFatalErrorAction = proc(msg: string) {.gcsafe, closure.} =
@ -70,11 +62,10 @@ proc configureStore(node: WakuNode,
discard
# Archive setup
let archiveDriverRes = await ArchiveDriver.new(storeDbUrl,
storeVacuum,
storeDbMigration,
storeMaxNumDbConnections,
onFatalErrorAction)
let archiveDriverRes = await ArchiveDriver.new(
storeDbUrl, storeVacuum, storeDbMigration, storeMaxNumDbConnections,
onFatalErrorAction,
)
if archiveDriverRes.isErr():
return err("failed to setup archive driver: " & archiveDriverRes.error)
@ -82,8 +73,7 @@ proc configureStore(node: WakuNode,
if retPolicyRes.isErr():
return err("failed to create retention policy: " & retPolicyRes.error)
let mountArcRes = node.mountArchive(archiveDriverRes.get(),
retPolicyRes.get())
let mountArcRes = node.mountArchive(archiveDriverRes.get(), retPolicyRes.get())
if mountArcRes.isErr():
return err("failed to mount waku archive protocol: " & mountArcRes.error)
@ -103,12 +93,9 @@ proc configureStore(node: WakuNode,
return ok()
proc createNode(configJson: cstring):
Future[Result[WakuNode, string]] {.async.} =
proc createNode(configJson: cstring): Future[Result[WakuNode, string]] {.async.} =
var privateKey: PrivateKey
var netConfig = NetConfig.init(parseIpAddress("127.0.0.1"),
Port(60000'u16)).value
var netConfig = NetConfig.init(parseIpAddress("127.0.0.1"), Port(60000'u16)).value
## relay
var relay: bool
var topics = @[""]
@ -125,7 +112,8 @@ proc createNode(configJson: cstring):
var errorResp: string
try:
if not parseConfig($configJson,
if not parseConfig(
$configJson,
privateKey,
netConfig,
relay,
@ -137,7 +125,8 @@ proc createNode(configJson: cstring):
storeVacuum,
storeDbMigration,
storeMaxNumDbConnections,
errorResp):
errorResp,
):
return err(errorResp)
except Exception:
return err("exception calling parseConfig: " & getCurrentExceptionMsg())
@ -145,9 +134,7 @@ proc createNode(configJson: cstring):
var enrBuilder = EnrBuilder.init(privateKey)
enrBuilder.withIpAddressAndPorts(
netConfig.enrIp,
netConfig.enrPort,
netConfig.discv5UdpPort
netConfig.enrIp, netConfig.enrPort, netConfig.discv5UdpPort
)
if netConfig.wakuFlags.isSome():
@ -165,8 +152,8 @@ proc createNode(configJson: cstring):
if recordRes.isErr():
let msg = "Error building enr record: " & $recordRes.error
return err(msg)
else: recordRes.get()
else:
recordRes.get()
## TODO: make the next const configurable from 'configJson'.
const MAX_CONNECTIONS = 50.int
@ -176,9 +163,7 @@ proc createNode(configJson: cstring):
builder.withNodeKey(privateKey)
builder.withRecord(record)
builder.withNetworkConfiguration(netConfig)
builder.withSwitchConfiguration(
maxConnections = some(MAX_CONNECTIONS)
)
builder.withSwitchConfiguration(maxConnections = some(MAX_CONNECTIONS))
let wakuNodeRes = builder.build()
if wakuNodeRes.isErr():
@ -192,32 +177,31 @@ proc createNode(configJson: cstring):
newNode.peerManager.start()
if store:
(await newNode.configureStore(storeNode,
storeRetentionPolicy,
storeDbUrl,
storeVacuum,
storeDbMigration,
storeMaxNumDbConnections)).isOkOr:
(
await newNode.configureStore(
storeNode, storeRetentionPolicy, storeDbUrl, storeVacuum, storeDbMigration,
storeMaxNumDbConnections,
)
).isOkOr:
return err("error configuring store: " & $error)
return ok(newNode)
proc process*(self: ptr NodeLifecycleRequest,
node: ptr WakuNode): Future[Result[string, string]] {.async.} =
proc process*(
self: ptr NodeLifecycleRequest, node: ptr WakuNode
): Future[Result[string, string]] {.async.} =
defer:
destroyShared(self)
defer: destroyShared(self)
case self.operation:
case self.operation
of CREATE_NODE:
let newNodeRes = await createNode(self.configJson)
if newNodeRes.isErr():
return err(newNodeRes.error)
node[] = newNodeRes.get()
of START_NODE:
await node[].start()
of STOP_NODE:
try:
await node[].stop()

View File

@ -1,30 +1,21 @@
import std/[options, sequtils, strutils]
import chronicles, chronos, stew/results, stew/shims/net
import ../../../../waku/node/waku_node, ../../../alloc
import
std/[options,sequtils,strutils]
import
chronicles,
chronos,
stew/results,
stew/shims/net
import
../../../../waku/node/waku_node,
../../../alloc
type
PeerManagementMsgType* = enum
type PeerManagementMsgType* = enum
CONNECT_TO
type
PeerManagementRequest* = object
type PeerManagementRequest* = object
operation: PeerManagementMsgType
peerMultiAddr: cstring
dialTimeout: Duration
proc createShared*(T: type PeerManagementRequest,
proc createShared*(
T: type PeerManagementRequest,
op: PeerManagementMsgType,
peerMultiAddr: string,
dialTimeout: Duration): ptr type T =
dialTimeout: Duration,
): ptr type T =
var ret = createShared(T)
ret[].operation = op
ret[].peerMultiAddr = peerMultiAddr.alloc()
@ -35,10 +26,9 @@ proc destroyShared(self: ptr PeerManagementRequest) =
deallocShared(self[].peerMultiAddr)
deallocShared(self)
proc connectTo(node: WakuNode,
peerMultiAddr: string,
dialTimeout: Duration): Result[void, string] =
proc connectTo(
node: WakuNode, peerMultiAddr: string, dialTimeout: Duration
): Result[void, string] =
let peers = (peerMultiAddr).split(",").mapIt(strip(it))
# TODO: the dialTimeout is not being used at all!
@ -52,13 +42,13 @@ proc connectTo(node: WakuNode,
return ok()
proc process*(self: ptr PeerManagementRequest,
node: WakuNode): Future[Result[string, string]] {.async.} =
defer: destroyShared(self)
case self.operation:
proc process*(
self: ptr PeerManagementRequest, node: WakuNode
): Future[Result[string, string]] {.async.} =
defer:
destroyShared(self)
case self.operation
of CONNECT_TO:
let ret = node.connectTo($self[].peerMultiAddr, self[].dialTimeout)
if ret.isErr():

View File

@ -1,12 +1,5 @@
import
std/[options,sequtils,strutils]
import
chronicles,
chronos,
stew/byteutils,
stew/results,
stew/shims/net
import std/[options, sequtils, strutils]
import chronicles, chronos, stew/byteutils, stew/results, stew/shims/net
import
../../../../../waku/waku_core/message/message,
../../../../../waku/node/waku_node,
@ -16,14 +9,12 @@ import
../../../../../waku/waku_relay/protocol,
../../../../alloc
type
RelayMsgType* = enum
type RelayMsgType* = enum
SUBSCRIBE
UNSUBSCRIBE
PUBLISH
type
ThreadSafeWakuMessage* = object
type ThreadSafeWakuMessage* = object
payload: SharedSeq[byte]
contentTopic: cstring
meta: SharedSeq[byte]
@ -33,19 +24,19 @@ type
when defined(rln):
proof: SharedSeq[byte]
type
RelayRequest* = object
type RelayRequest* = object
operation: RelayMsgType
pubsubTopic: cstring
relayEventCallback: WakuRelayHandler # not used in 'PUBLISH' requests
message: ThreadSafeWakuMessage # only used in 'PUBLISH' requests
proc createShared*(T: type RelayRequest,
proc createShared*(
T: type RelayRequest,
op: RelayMsgType,
pubsubTopic: PubsubTopic,
relayEventCallback: WakuRelayHandler = nil,
m = WakuMessage()): ptr type T =
m = WakuMessage(),
): ptr type T =
var ret = createShared(T)
ret[].operation = op
ret[].pubsubTopic = pubsubTopic.alloc()
@ -87,33 +78,29 @@ proc toWakuMessage(m: ThreadSafeWakuMessage): WakuMessage =
return wakuMessage
proc process*(self: ptr RelayRequest,
node: ptr WakuNode): Future[Result[string, string]] {.async.} =
defer: destroyShared(self)
proc process*(
self: ptr RelayRequest, node: ptr WakuNode
): Future[Result[string, string]] {.async.} =
defer:
destroyShared(self)
if node.wakuRelay.isNil():
return err("Operation not supported without Waku Relay enabled.")
case self.operation:
case self.operation
of SUBSCRIBE:
# TO DO: properly perform 'subscribe'
discard node.wakuRelay.subscribe($self.pubsubTopic, self.relayEventCallback)
of UNSUBSCRIBE:
# TODO: properly perform 'unsubscribe'
node.wakuRelay.unsubscribeAll($self.pubsubTopic)
of PUBLISH:
let msg = self.message.toWakuMessage()
let pubsubTopic = $self.pubsubTopic
let numPeers = await node.wakuRelay.publish(pubsubTopic,
msg)
let numPeers = await node.wakuRelay.publish(pubsubTopic, msg)
if numPeers == 0:
return err("Message not sent because no peers found.")
elif numPeers > 0:
let msgHash = computeMessageHash(pubSubTopic, msg).to0xHex
return ok(msgHash)

View File

@ -1,10 +1,5 @@
import
std/[options,sequtils,strutils]
import
chronos,
stew/results,
stew/shims/net
import std/[options, sequtils, strutils]
import chronos, stew/results, stew/shims/net
import
../../../../../waku/node/waku_node,
../../../../../waku/waku_archive/driver/builder,
@ -14,36 +9,34 @@ import
../../../../alloc,
../../../../callback
type
StoreReqType* = enum
type StoreReqType* = enum
REMOTE_QUERY ## to perform a query to another Store node
LOCAL_QUERY ## to retrieve the data from 'self' node
type
StoreQueryRequest* = object
type StoreQueryRequest* = object
queryJson: cstring
peerAddr: cstring
timeoutMs: cint
storeCallback: WakuCallBack
type
StoreRequest* = object
type StoreRequest* = object
operation: StoreReqType
storeReq: pointer
proc createShared*(T: type StoreRequest,
operation: StoreReqType,
request: pointer): ptr type T =
proc createShared*(
T: type StoreRequest, operation: StoreReqType, request: pointer
): ptr type T =
var ret = createShared(T)
ret[].request = request
return ret
proc createShared*(T: type StoreQueryRequest,
proc createShared*(
T: type StoreQueryRequest,
queryJson: cstring,
peerAddr: cstring,
timeoutMs: cint,
storeCallback: WakuCallBack = nil): ptr type T =
storeCallback: WakuCallBack = nil,
): ptr type T =
var ret = createShared(T)
ret[].timeoutMs = timeoutMs
ret[].queryJson = queryJson.alloc()
@ -56,16 +49,19 @@ proc destroyShared(self: ptr StoreQueryRequest) =
deallocShared(self[].peerAddr)
deallocShared(self)
proc process(self: ptr StoreQueryRequest,
node: ptr WakuNode): Future[Result[string, string]] {.async.} =
defer: destroyShared(self)
proc process(
self: ptr StoreQueryRequest, node: ptr WakuNode
): Future[Result[string, string]] {.async.} =
defer:
destroyShared(self)
proc process*(self: ptr StoreRequest,
node: ptr WakuNode): Future[Result[string, string]] {.async.} =
proc process*(
self: ptr StoreRequest, node: ptr WakuNode
): Future[Result[string, string]] {.async.} =
defer:
deallocShared(self)
defer: deallocShared(self)
case self.operation:
case self.operation
of REMOTE_QUERY:
return await cast[ptr StoreQueryRequest](self[].storeReq).process(node)
of LOCAL_QUERY:

View File

@ -1,13 +1,9 @@
## This file contains the base message request type that will be handled.
## The requests are created by the main thread and processed by
## the Waku Thread.
import
std/json,
stew/results
import
chronos
import std/json, stew/results
import chronos
import
../../../waku/node/waku_node,
./requests/node_lifecycle_request,
@ -16,33 +12,31 @@ import
./requests/protocols/store_request,
./requests/debug_node_request
type
RequestType* {.pure.} = enum
LIFECYCLE,
PEER_MANAGER,
RELAY,
STORE,
DEBUG,
type RequestType* {.pure.} = enum
LIFECYCLE
PEER_MANAGER
RELAY
STORE
DEBUG
type
InterThreadRequest* = object
type InterThreadRequest* = object
reqType: RequestType
reqContent: pointer
proc createShared*(T: type InterThreadRequest,
reqType: RequestType,
reqContent: pointer): ptr type T =
proc createShared*(
T: type InterThreadRequest, reqType: RequestType, reqContent: pointer
): ptr type T =
var ret = createShared(T)
ret[].reqType = reqType
ret[].reqContent = reqContent
return ret
proc process*(T: type InterThreadRequest,
request: ptr InterThreadRequest,
node: ptr WakuNode):
Future[Result[string, string]] {.async.} =
proc process*(
T: type InterThreadRequest, request: ptr InterThreadRequest, node: ptr WakuNode
): Future[Result[string, string]] {.async.} =
## Processes the request and deallocates its memory
defer: deallocShared(request)
defer:
deallocShared(request)
echo "Request received: " & $request[].reqType

View File

@ -1,26 +1,21 @@
## This file contains the base message response type that will be handled.
## The response will be created from the Waku Thread and processed in
## the main thread.
import
std/json,
stew/results
import
../../alloc
import std/json, stew/results
import ../../alloc
type
ResponseType {.pure.} = enum
OK,
ERR,
type ResponseType {.pure.} = enum
OK
ERR
type
InterThreadResponse* = object
type InterThreadResponse* = object
respType: ResponseType
content: cstring
proc createShared*(T: type InterThreadResponse,
res: Result[string, string]): ptr type T =
proc createShared*(
T: type InterThreadResponse, res: Result[string, string]
): ptr type T =
## Converts a `Result[string, string]` into a `ptr InterThreadResponse`
## so that it can be transfered to another thread in a safe way.
@ -35,9 +30,9 @@ proc createShared*(T: type InterThreadResponse,
ret[].content = res.error.alloc()
return ret
proc process*(T: type InterThreadResponse,
resp: ptr InterThreadResponse):
Result[string, string] =
proc process*(
T: type InterThreadResponse, resp: ptr InterThreadResponse
): Result[string, string] =
## Converts the received `ptr InterThreadResponse` into a
## `Result[string, string]`. Notice that the response is expected to be
## allocated from the Waku Thread and deallocated by the main thread.

View File

@ -1,10 +1,8 @@
{.pragma: exported, exportc, cdecl, raises: [].}
{.pragma: callback, cdecl, raises: [], gcsafe.}
{.passc: "-fPIC".}
import
std/[json,sequtils,times,strformat,options,atomics,strutils,os]
import std/[json, sequtils, times, strformat, options, atomics, strutils, os]
import
chronicles,
chronos,
@ -18,8 +16,7 @@ import
./inter_thread_communication/waku_thread_request,
./inter_thread_communication/waku_thread_response
type
Context* = object
type Context* = object
thread: Thread[(ptr Context)]
reqChannel: ChannelSPSCSingle[ptr InterThreadRequest]
reqSignal: ThreadSignalPtr
@ -40,7 +37,8 @@ var initialized: Atomic[bool]
proc waku_init() =
if not initialized.exchange(true):
NimMain() # Every Nim library needs to call `NimMain` once exactly
when declared(setupForeignThreadGc): setupForeignThreadGc()
when declared(setupForeignThreadGc):
setupForeignThreadGc()
when declared(nimGC_setStackBottom):
var locals {.volatile, noinit.}: pointer
locals = addr(locals)
@ -59,8 +57,7 @@ proc run(ctx: ptr Context) {.thread.} =
waitFor ctx.reqSignal.wait()
let recvOk = ctx.reqChannel.tryRecv(request)
if recvOk == true:
let resultResponse =
waitFor InterThreadRequest.process(request, addr node)
let resultResponse = waitFor InterThreadRequest.process(request, addr node)
## Converting a `Result` into a thread-safe transferable response type
let threadSafeResp = InterThreadResponse.createShared(resultResponse)
@ -106,10 +103,9 @@ proc stopWakuThread*(ctx: ptr Context): Result[void, string] =
freeShared(ctx)
return ok()
proc sendRequestToWakuThread*(ctx: ptr Context,
reqType: RequestType,
reqContent: pointer): Result[string, string] =
proc sendRequestToWakuThread*(
ctx: ptr Context, reqType: RequestType, reqContent: pointer
): Result[string, string] =
let req = InterThreadRequest.createShared(reqType, reqContent)
## Sending the request

View File

@ -1,4 +1,5 @@
const ContentScriptVersion_1* = """
const ContentScriptVersion_1* =
"""
CREATE TABLE IF NOT EXISTS messages (
pubsubTopic VARCHAR NOT NULL,
contentTopic VARCHAR NOT NULL,

View File

@ -1,4 +1,5 @@
const ContentScriptVersion_2* = """
const ContentScriptVersion_2* =
"""
ALTER TABLE IF EXISTS messages_backup RENAME TO messages;
ALTER TABLE messages RENAME TO messages_backup;
ALTER TABLE messages_backup DROP CONSTRAINT messageIndex;

View File

@ -1,37 +1,22 @@
import content_script_version_1, content_script_version_2
import
content_script_version_1,
content_script_version_2
type
MigrationScript* = object
type MigrationScript* = object
version*: int
scriptContent*: string
proc init*(T: type MigrationScript,
targetVersion: int,
scriptContent: string): T =
proc init*(T: type MigrationScript, targetVersion: int, scriptContent: string): T =
return MigrationScript(targetVersion: targetVersion, scriptContent: scriptContent)
return MigrationScript(
targetVersion: targetVersion,
scriptContent: scriptContent)
const PgMigrationScripts* = @[
MigrationScript(
version: 1,
scriptContent: ContentScriptVersion_1),
MigrationScript(
version: 2,
scriptContent: ContentScriptVersion_2)
const PgMigrationScripts* =
@[
MigrationScript(version: 1, scriptContent: ContentScriptVersion_1),
MigrationScript(version: 2, scriptContent: ContentScriptVersion_2),
]
proc getMigrationScripts*(currentVersion: int64,
targetVersion: int64): seq[string] =
proc getMigrationScripts*(currentVersion: int64, targetVersion: int64): seq[string] =
var ret = newSeq[string]()
var v = currentVersion
while v < targetVersion:
ret.add(PgMigrationScripts[v].scriptContent)
v.inc()
return ret

View File

@ -24,8 +24,7 @@ when os == "Linux" and
# GitHub only supports container actions on Linux
# and we need to start a postgress database in a docker container
defined(postgres):
import
./waku_archive/test_driver_postgres_query, ./waku_archive/test_driver_postgres
import ./waku_archive/test_driver_postgres_query, ./waku_archive/test_driver_postgres
# Waku store test suite
import

View File

@ -1,16 +1,11 @@
{.used.}
import
std/strutils,
stew/[results, byteutils],
testutils/unittests
import
../../waku/common/base64
import std/strutils, stew/[results, byteutils], testutils/unittests
import ../../waku/common/base64
suite "Waku Common - stew base64 wrapper":
const TestData = @[
const TestData =
@[
# Test vectors from RFC 4648
# See: https://datatracker.ietf.org/doc/html/rfc4648#section-10
("", Base64String("")),
@ -24,11 +19,10 @@ suite "Waku Common - stew base64 wrapper":
# Custom test vectors
("\x01", Base64String("AQ==")),
("\x13", Base64String("Ew==")),
("\x01\x02\x03\x04", Base64String("AQIDBA=="))
("\x01\x02\x03\x04", Base64String("AQIDBA==")),
]
for (plaintext, encoded) in TestData:
test "encode into base64 (" & escape(plaintext) & " -> \"" & string(encoded) & "\")":
## Given
let data = plaintext
@ -40,7 +34,6 @@ suite "Waku Common - stew base64 wrapper":
check:
encodedData == encoded
test "decode from base64 (\"" & string(encoded) & "\" -> " & escape(plaintext) & ")":
## Given
let data = encoded
@ -55,4 +48,3 @@ suite "Waku Common - stew base64 wrapper":
let decoded = decodedRes.tryGet()
check:
decoded == toBytes(plaintext)

View File

@ -15,31 +15,28 @@ import
type ConfResult[T] = Result[T, string]
type TestConf = object
configFile* {.
desc: "Configuration file path"
name: "config-file" }: Option[InputFile]
configFile* {.desc: "Configuration file path", name: "config-file".}:
Option[InputFile]
testFile* {.
desc: "Configuration test file path"
name: "test-file" }: Option[InputFile]
testFile* {.desc: "Configuration test file path", name: "test-file".}:
Option[InputFile]
listenAddress* {.
defaultValue: parseIpAddress("127.0.0.1"),
desc: "Listening address",
name: "listen-address"}: IpAddress
name: "listen-address"
.}: IpAddress
tcpPort* {.
desc: "TCP listening port",
defaultValue: 60000,
name: "tcp-port" }: Port
tcpPort* {.desc: "TCP listening port", defaultValue: 60000, name: "tcp-port".}: Port
{.push warning[ProveInit]: off.}
proc load*(T: type TestConf, prefix: string): ConfResult[T] =
try:
let conf = TestConf.load(
secondarySources = proc (conf: TestConf, sources: auto)
{.gcsafe, raises: [ConfigurationError].} =
secondarySources = proc(
conf: TestConf, sources: auto
) {.gcsafe, raises: [ConfigurationError].} =
sources.addConfigFile(Envvar, InputFile(prefix))
)
ok(conf)

View File

@ -1,17 +1,9 @@
{.used.}
import
std/options,
stew/results,
stew/shims/net,
testutils/unittests
import
../../waku/common/enr,
../testlib/wakucore
import std/options, stew/results, stew/shims/net, testutils/unittests
import ../../waku/common/enr, ../testlib/wakucore
suite "nim-eth ENR - builder and typed record":
test "Non-supported private key (ECDSA)":
## Given
let privateKey = generateEcdsaKey()
@ -45,21 +37,21 @@ suite "nim-eth ENR - builder and typed record":
publicKey.isSome()
@(publicKey.get()) == expectedPubKey
suite "nim-eth ENR - Ext: IP address and TCP/UDP ports":
test "EIP-778 test vector":
## Given
# Test vector from EIP-778
# See: https://eips.ethereum.org/EIPS/eip-778#test-vectors
let expectedEnr = "-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04j" &
let expectedEnr =
"-IS4QHCYrYZbAKWCBRlAy5zzaDZXJBGkcnh4MHcBFZntXNFrdvJjX04j" &
"RzjzCBOonrkTfj499SZuOh8R33Ls8RRcy5wBgmlkgnY0gmlwhH8AAAGJ" &
"c2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0x" &
"OIN1ZHCCdl8"
"c2VjcDI1NmsxoQPKY0yuDUmstAHYpMa2_oxVtw0RW_QAdpzBQA8yWM0x" & "OIN1ZHCCdl8"
let
seqNum = 1u64
privateKey = ethSecp256k1Key("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
privateKey = ethSecp256k1Key(
"b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291"
)
enrIpAddr = parseIpAddress("127.0.0.1")
enrUdpPort = Port(30303)
@ -89,10 +81,7 @@ suite "nim-eth ENR - Ext: IP address and TCP/UDP ports":
## When
var builder = EnrBuilder.init(privateKey, seqNum)
builder.withIpAddressAndPorts(
ipAddr=some(enrIpAddr),
tcpPort=some(enrTcpPort),
)
builder.withIpAddressAndPorts(ipAddr = some(enrIpAddr), tcpPort = some(enrTcpPort))
let enrRes = builder.build()
@ -119,10 +108,7 @@ suite "nim-eth ENR - Ext: IP address and TCP/UDP ports":
## When
var builder = EnrBuilder.init(privateKey, seqNum)
builder.withIpAddressAndPorts(
ipAddr=some(enrIpAddr),
udpPort=some(enrUdpPort),
)
builder.withIpAddressAndPorts(ipAddr = some(enrIpAddr), udpPort = some(enrUdpPort))
let enrRes = builder.build()

View File

@ -1,10 +1,7 @@
{.used.}
import
testutils/unittests
import
../../waku/common/envvar_serialization/utils
import testutils/unittests
import ../../waku/common/envvar_serialization/utils
suite "nim-envvar-serialization - utils":
test "construct env var key":

View File

@ -1,10 +1,7 @@
{.used.}
import
testutils/unittests,
stew/results
import
../../waku/common/utils/parse_size_units
import testutils/unittests, stew/results
import ../../waku/common/utils/parse_size_units
suite "Size serialization test":
test "parse normal sizes":

View File

@ -1,11 +1,7 @@
{.used.}
import
testutils/unittests
import
../../waku/common/protobuf
import testutils/unittests
import ../../waku/common/protobuf
## Fixtures
@ -40,11 +36,9 @@ proc decode(T: type TestRpc, buf: seq[byte]): ProtobufResult[T] =
ok(TestRpc.init(field))
## Tests
suite "Waku Common - libp2p minprotobuf wrapper":
test "serialize and deserialize - valid length field":
## Given
let field = "12345"
@ -82,7 +76,6 @@ suite "Waku Common - libp2p minprotobuf wrapper":
error.kind == ProtobufErrorKind.MissingRequiredField
error.field == "test_field"
test "serialize and deserialize - invalid length field":
## Given
let field = "123456" # field.len = MaxTestRpcFieldLen + 1

View File

@ -1,19 +1,12 @@
{.used.}
import
std/[strutils, os],
stew/results,
testutils/unittests
import
../../waku/common/databases/db_sqlite {.all.},
../waku_archive/archive_utils
template sourceDir: string = currentSourcePath.rsplit(DirSep, 1)[0]
import std/[strutils, os], stew/results, testutils/unittests
import ../../waku/common/databases/db_sqlite {.all.}, ../waku_archive/archive_utils
template sourceDir(): string =
currentSourcePath.rsplit(DirSep, 1)[0]
suite "SQLite - migrations":
test "set and get user version":
## Given
let database = newSqliteDatabase()
@ -36,7 +29,8 @@ suite "SQLite - migrations":
test "filter and order migration script file paths":
## Given
let paths = @[
let paths =
@[
sourceDir / "00001_valid.up.sql",
sourceDir / "00002_alsoValidWithUpperCaseExtension.UP.SQL",
sourceDir / "00007_unorderedValid.up.sql",
@ -53,29 +47,33 @@ suite "SQLite - migrations":
## When
var migrationSciptPaths: seq[string]
migrationSciptPaths = filterMigrationScripts(paths, lowerVersion, highVersion, direction="up")
migrationSciptPaths =
filterMigrationScripts(paths, lowerVersion, highVersion, direction = "up")
migrationSciptPaths = sortMigrationScripts(migrationSciptPaths)
## Then
check:
migrationSciptPaths == @[
migrationSciptPaths ==
@[
sourceDir / "00001_valid.up.sql",
sourceDir / "00002_alsoValidWithUpperCaseExtension.UP.SQL",
sourceDir / "00003_validRepeated.up.sql",
sourceDir / "00003_validRepeated.up.sql",
sourceDir / "00007_unorderedValid.up.sql"
sourceDir / "00007_unorderedValid.up.sql",
]
test "break migration scripts into queries":
## Given
let statement1 = """CREATE TABLE contacts1 (
let statement1 =
"""CREATE TABLE contacts1 (
contact_id INTEGER PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
phone TEXT NOT NULL UNIQUE
);"""
let statement2 = """CREATE TABLE contacts2 (
let statement2 =
"""CREATE TABLE contacts2 (
contact_id INTEGER PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
@ -93,14 +91,16 @@ suite "SQLite - migrations":
test "break statements script into queries - empty statements":
## Given
let statement1 = """CREATE TABLE contacts1 (
let statement1 =
"""CREATE TABLE contacts1 (
contact_id INTEGER PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
phone TEXT NOT NULL UNIQUE
);"""
let statement2 = """CREATE TABLE contacts2 (
let statement2 =
"""CREATE TABLE contacts2 (
contact_id INTEGER PRIMARY KEY,
first_name TEXT NOT NULL,
last_name TEXT NOT NULL,

View File

@ -1,13 +1,8 @@
{.used.}
import
testutils/unittests,
chronos
import testutils/unittests, chronos
import
../testlib/wakunode,
../../waku/factory/node_factory,
../../waku/waku_node
import ../testlib/wakunode, ../../waku/factory/node_factory, ../../waku/waku_node
suite "Node Factory":
test "Set up a node based on default configurations":
@ -55,7 +50,8 @@ test "Start a node based on default configurations":
assert not node.isNil(), "Node can't be nil"
let startRes = catch: (waitFor startNode(node, conf))
let startRes = catch:
(waitFor startNode(node, conf))
assert not startRes.isErr(), "Exception starting node"
assert startRes.get().isOk(), "Error starting node " & startRes.get().error

View File

@ -17,9 +17,7 @@ suite "PeerStorage":
suite "getAll":
test "unimplemented":
let
emptyClosure =
proc(remotePeerInfo: RemotePeerInfo) =
let emptyClosure = proc(remotePeerInfo: RemotePeerInfo) =
discard
check:
peerStorage.getAll(emptyClosure) == PeerStorageResult[void].err("Unimplemented")

View File

@ -13,8 +13,7 @@ import
../../../../waku/node/peer_manager/peer_store/waku_peer_storage
proc `==`(a, b: RemotePeerInfo): bool =
let
comparisons =
let comparisons =
@[
a.peerId == b.peerId,
a.addrs == b.addrs,
@ -28,7 +27,7 @@ proc `==`(a, b: RemotePeerInfo): bool =
a.origin == b.origin,
a.direction == b.direction,
a.lastFailedConn == b.lastFailedConn,
a.numberFailedConn == b.numberFailedConn
a.numberFailedConn == b.numberFailedConn,
]
allIt(comparisons, it == true)
@ -65,18 +64,17 @@ suite "Protobuf Serialisation":
suite "encode":
test "simple":
# Given the expected bytes representation of a valid RemotePeerInfo
let
expectedBuffer: seq[byte] =
let expectedBuffer: seq[byte] =
@[
10, 39, 0, 37, 8, 2, 18, 33, 3, 43, 246, 238, 219, 109, 147, 79, 129, 40,
145, 217, 209, 109, 105, 185, 186, 200, 180, 203, 72, 166, 220, 196, 232,
170, 74, 141, 125, 255, 112, 238, 204, 18, 8, 4, 192, 168, 0, 1, 6, 31, 144,
34, 95, 8, 3, 18, 91, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6,
8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 222, 61, 48, 15, 163, 106,
224, 232, 245, 213, 48, 137, 157, 131, 171, 171, 68, 171, 243, 22, 31, 22,
42, 75, 201, 1, 216, 230, 236, 218, 2, 14, 139, 109, 95, 141, 163, 5, 37,
231, 29, 104, 81, 81, 12, 9, 142, 92, 71, 198, 70, 165, 151, 251, 77, 206,
192, 52, 233, 247, 124, 64, 158, 98, 40, 0, 48, 0
10, 39, 0, 37, 8, 2, 18, 33, 3, 43, 246, 238, 219, 109, 147, 79, 129, 40, 145,
217, 209, 109, 105, 185, 186, 200, 180, 203, 72, 166, 220, 196, 232, 170, 74,
141, 125, 255, 112, 238, 204, 18, 8, 4, 192, 168, 0, 1, 6, 31, 144, 34, 95, 8,
3, 18, 91, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134,
72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 222, 61, 48, 15, 163, 106, 224, 232, 245,
213, 48, 137, 157, 131, 171, 171, 68, 171, 243, 22, 31, 22, 42, 75, 201, 1,
216, 230, 236, 218, 2, 14, 139, 109, 95, 141, 163, 5, 37, 231, 29, 104, 81,
81, 12, 9, 142, 92, 71, 198, 70, 165, 151, 251, 77, 206, 192, 52, 233, 247,
124, 64, 158, 98, 40, 0, 48, 0,
]
# When converting a valid RemotePeerInfo to a ProtoBuffer
@ -92,18 +90,17 @@ suite "Protobuf Serialisation":
suite "decode":
test "simple":
# Given the bytes representation of a valid RemotePeerInfo
let
buffer: seq[byte] =
let buffer: seq[byte] =
@[
10, 39, 0, 37, 8, 2, 18, 33, 3, 43, 246, 238, 219, 109, 147, 79, 129, 40,
145, 217, 209, 109, 105, 185, 186, 200, 180, 203, 72, 166, 220, 196, 232,
170, 74, 141, 125, 255, 112, 238, 204, 18, 8, 4, 192, 168, 0, 1, 6, 31, 144,
34, 95, 8, 3, 18, 91, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6,
8, 42, 134, 72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 222, 61, 48, 15, 163, 106,
224, 232, 245, 213, 48, 137, 157, 131, 171, 171, 68, 171, 243, 22, 31, 22,
42, 75, 201, 1, 216, 230, 236, 218, 2, 14, 139, 109, 95, 141, 163, 5, 37,
231, 29, 104, 81, 81, 12, 9, 142, 92, 71, 198, 70, 165, 151, 251, 77, 206,
192, 52, 233, 247, 124, 64, 158, 98, 40, 0, 48, 0
10, 39, 0, 37, 8, 2, 18, 33, 3, 43, 246, 238, 219, 109, 147, 79, 129, 40, 145,
217, 209, 109, 105, 185, 186, 200, 180, 203, 72, 166, 220, 196, 232, 170, 74,
141, 125, 255, 112, 238, 204, 18, 8, 4, 192, 168, 0, 1, 6, 31, 144, 34, 95, 8,
3, 18, 91, 48, 89, 48, 19, 6, 7, 42, 134, 72, 206, 61, 2, 1, 6, 8, 42, 134,
72, 206, 61, 3, 1, 7, 3, 66, 0, 4, 222, 61, 48, 15, 163, 106, 224, 232, 245,
213, 48, 137, 157, 131, 171, 171, 68, 171, 243, 22, 31, 22, 42, 75, 201, 1,
216, 230, 236, 218, 2, 14, 139, 109, 95, 141, 163, 5, 37, 231, 29, 104, 81,
81, 12, 9, 142, 92, 71, 198, 70, 165, 151, 251, 77, 206, 192, 52, 233, 247,
124, 64, 158, 98, 40, 0, 48, 0,
]
# When converting a valid buffer to RemotePeerInfo

View File

@ -16,7 +16,7 @@ import
node/waku_node,
waku_filter_v2,
waku_filter_v2/client,
waku_filter_v2/subscriptions
waku_filter_v2/subscriptions,
],
../testlib/[common, wakucore, wakunode, testasync, futures, testutils]
@ -34,10 +34,9 @@ suite "Waku Filter - End to End":
asyncSetup:
pushHandlerFuture = newFuture[(string, WakuMessage)]()
messagePushHandler =
proc(pubsubTopic: PubsubTopic, message: WakuMessage): Future[void] {.
async, closure, gcsafe
.} =
messagePushHandler = proc(
pubsubTopic: PubsubTopic, message: WakuMessage
): Future[void] {.async, closure, gcsafe.} =
pushHandlerFuture.complete((pubsubTopic, message))
pubsubTopic = DefaultPubsubTopic
@ -72,9 +71,7 @@ suite "Waku Filter - End to End":
asyncTest "Client Node receives Push from Server Node, via Filter":
# When a client node subscribes to a filter node
let
subscribeResponse =
await client.filterSubscribe(
let subscribeResponse = await client.filterSubscribe(
some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo
)
@ -96,9 +93,7 @@ suite "Waku Filter - End to End":
pushedMsg1 == msg1
# When unsubscribing from the subscription
let
unsubscribeResponse =
await client.filterUnsubscribe(
let unsubscribeResponse = await client.filterUnsubscribe(
some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo
)
@ -121,9 +116,7 @@ suite "Waku Filter - End to End":
await server.mountRelay()
# And valid filter subscription
let
subscribeResponse =
await client.filterSubscribe(
let subscribeResponse = await client.filterSubscribe(
some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo
)
require:
@ -149,9 +142,7 @@ suite "Waku Filter - End to End":
let serverRemotePeerInfo = server.peerInfo.toRemotePeerInfo()
# When a client node subscribes to the server node
let
subscribeResponse =
await client.filterSubscribe(
let subscribeResponse = await client.filterSubscribe(
some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo
)
@ -160,9 +151,7 @@ suite "Waku Filter - End to End":
asyncTest "Filter Client Node can receive messages after subscribing and restarting, via Filter":
# Given a valid filter subscription
let
subscribeResponse =
await client.filterSubscribe(
let subscribeResponse = await client.filterSubscribe(
some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo
)
require:
@ -188,9 +177,7 @@ suite "Waku Filter - End to End":
await server.mountRelay()
# Given a valid filter subscription
let
subscribeResponse =
await client.filterSubscribe(
let subscribeResponse = await client.filterSubscribe(
some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo
)
require:
@ -209,9 +196,7 @@ suite "Waku Filter - End to End":
check (not await pushHandlerFuture.withTimeout(FUTURE_TIMEOUT))
# Given the client refreshes the subscription
let
subscribeResponse2 =
await clientClone.filterSubscribe(
let subscribeResponse2 = await clientClone.filterSubscribe(
some(pubsubTopic), contentTopicSeq, serverRemotePeerInfo
)
check:

View File

@ -21,7 +21,7 @@ import
waku_lightpush/common,
waku_lightpush/client,
waku_lightpush/protocol_metrics,
waku_lightpush/rpc
waku_lightpush/rpc,
],
../testlib/[assertions, common, wakucore, wakunode, testasync, futures, testutils]
@ -40,8 +40,7 @@ suite "Waku Lightpush - End To End":
asyncSetup:
handlerFuture = newPushHandlerFuture()
handler =
proc(
handler = proc(
peer: PeerId, pubsubTopic: PubsubTopic, message: WakuMessage
): Future[WakuLightPushResult[void]] {.async.} =
handlerFuture.complete((pubsubTopic, message))
@ -72,17 +71,12 @@ suite "Waku Lightpush - End To End":
suite "Assessment of Message Relaying Mechanisms":
asyncTest "Via 11/WAKU2-RELAY from Relay/Full Node":
# Given a light lightpush client
let
lightpushClient =
newTestWakuNode(
generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)
)
let lightpushClient =
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
lightpushClient.mountLightpushClient()
# When the client publishes a message
let
publishResponse =
await lightpushClient.lightpushPublish(
let publishResponse = await lightpushClient.lightpushPublish(
some(pubsubTopic), message, serverRemotePeerInfo
)

View File

@ -19,7 +19,7 @@ import
waku_peer_exchange,
node/peer_manager,
waku_relay/protocol,
waku_core
waku_core,
],
../waku_peer_exchange/utils,
../testlib/[wakucore, wakunode, testasync]
@ -187,8 +187,7 @@ suite "Waku Peer Exchange with discv5":
## Given (copied from test_waku_discv5.nim)
let
# todo: px flag
flags =
CapabilitiesBitfield.init(
flags = CapabilitiesBitfield.init(
lightpush = false, filter = false, store = false, relay = true
)
bindIp = parseIpAddress("0.0.0.0")
@ -197,8 +196,7 @@ suite "Waku Peer Exchange with discv5":
nodeKey1 = generateSecp256k1Key()
nodeTcpPort1 = Port(64010)
nodeUdpPort1 = Port(9000)
node1 =
newTestWakuNode(
node1 = newTestWakuNode(
nodeKey1,
bindIp,
nodeTcpPort1,
@ -210,8 +208,7 @@ suite "Waku Peer Exchange with discv5":
nodeKey2 = generateSecp256k1Key()
nodeTcpPort2 = Port(64012)
nodeUdpPort2 = Port(9002)
node2 =
newTestWakuNode(
node2 = newTestWakuNode(
nodeKey2,
bindIp,
nodeTcpPort2,
@ -223,8 +220,7 @@ suite "Waku Peer Exchange with discv5":
nodeKey3 = generateSecp256k1Key()
nodeTcpPort3 = Port(64014)
nodeUdpPort3 = Port(9004)
node3 =
newTestWakuNode(
node3 = newTestWakuNode(
nodeKey3,
bindIp,
nodeTcpPort3,
@ -234,9 +230,7 @@ suite "Waku Peer Exchange with discv5":
)
# discv5
let
conf1 =
WakuDiscoveryV5Config(
let conf1 = WakuDiscoveryV5Config(
discv5Config: none(DiscoveryConfig),
address: bindIp,
port: nodeUdpPort1,
@ -245,13 +239,10 @@ suite "Waku Peer Exchange with discv5":
autoupdateRecord: true,
)
let
disc1 =
let disc1 =
WakuDiscoveryV5.new(node1.rng, conf1, some(node1.enr), some(node1.peerManager))
let
conf2 =
WakuDiscoveryV5Config(
let conf2 = WakuDiscoveryV5Config(
discv5Config: none(DiscoveryConfig),
address: bindIp,
port: nodeUdpPort2,
@ -260,8 +251,7 @@ suite "Waku Peer Exchange with discv5":
autoupdateRecord: true,
)
let
disc2 =
let disc2 =
WakuDiscoveryV5.new(node2.rng, conf2, some(node2.enr), some(node2.peerManager))
await allFutures(node1.start(), node2.start(), node3.start())
@ -286,8 +276,7 @@ suite "Waku Peer Exchange with discv5":
await node1.mountPeerExchange()
await node3.mountPeerExchange()
let
dialResponse =
let dialResponse =
await node3.dialForPeerExchange(node1.switch.peerInfo.toRemotePeerInfo())
check dialResponse.isOk

View File

@ -12,13 +12,8 @@ import
from std/times import epochTime
import
../../../waku/[
node/waku_node,
node/peer_manager,
waku_core,
waku_node,
waku_rln_relay,
],
../../../waku/
[node/waku_node, node/peer_manager, waku_core, waku_node, waku_rln_relay],
../waku_store/store_utils,
../waku_archive/archive_utils,
../testlib/[wakucore, wakunode, testasync, futures],
@ -30,7 +25,7 @@ proc setupRln(node: WakuNode, identifier: uint) {.async.} =
rlnRelayDynamic: false,
rlnRelayCredIndex: some(identifier),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $identifier),
rlnEpochSizeSec: 1
rlnEpochSizeSec: 1,
)
)
@ -73,11 +68,10 @@ proc sendRlnMessageWithInvalidProof(
): Future[bool] {.async.} =
let
extraBytes: seq[byte] = @[byte(1), 2, 3]
rateLimitProofRes =
client.wakuRlnRelay.groupManager.generateProof(
rateLimitProofRes = client.wakuRlnRelay.groupManager.generateProof(
concat(payload, extraBytes),
# we add extra bytes to invalidate proof verification against original payload
client.wakuRlnRelay.getCurrentEpoch()
client.wakuRlnRelay.getCurrentEpoch(),
)
rateLimitProof = rateLimitProofRes.get().encode().buffer
message =
@ -127,9 +121,7 @@ suite "Waku RlnRelay - End to End":
server.wakuRlnRelay == nil
# When RlnRelay is mounted
let
catchRes =
catch:
let catchRes = catch:
await server.setupRln(1)
# Then Relay and RLN are not mounted,and the process fails
@ -156,8 +148,7 @@ suite "Waku RlnRelay - End to End":
var completionFuture = subscribeCompletionHandler(server, pubsubTopic)
# When the client sends a valid RLN message
let
isCompleted1 =
let isCompleted1 =
await sendRlnMessage(client, pubsubTopic, contentTopic, completionFuture)
# Then the valid RLN message is relayed
@ -167,9 +158,7 @@ suite "Waku RlnRelay - End to End":
# When the client sends an invalid RLN message
completionFuture = newBoolFuture()
let
isCompleted2 =
await sendRlnMessageWithInvalidProof(
let isCompleted2 = await sendRlnMessageWithInvalidProof(
client, pubsubTopic, contentTopic, completionFuture
)
@ -191,8 +180,7 @@ suite "Waku RlnRelay - End to End":
await sleepAsync(FUTURE_TIMEOUT)
# When the client sends a valid RLN message
let
isCompleted1 =
let isCompleted1 =
await sendRlnMessage(client, pubsubTopic, contentTopic, completionFuture)
# Then the valid RLN message is relayed
@ -202,9 +190,7 @@ suite "Waku RlnRelay - End to End":
# When the client sends an invalid RLN message
completionFuture = newBoolFuture()
let
isCompleted2 =
await sendRlnMessageWithInvalidProof(
let isCompleted2 = await sendRlnMessageWithInvalidProof(
client, pubsubTopic, contentTopic, completionFuture
)
@ -250,18 +236,26 @@ suite "Waku RlnRelay - End to End":
WakuMessage(payload: @payload150kibPlus, contentTopic: contentTopic)
doAssert(
client.wakuRlnRelay.appendRLNProof(message1b, epoch + client.wakuRlnRelay.rlnEpochSizeSec * 0).isOk()
client.wakuRlnRelay
.appendRLNProof(message1b, epoch + client.wakuRlnRelay.rlnEpochSizeSec * 0)
.isOk()
)
doAssert(
client.wakuRlnRelay.appendRLNProof(message1kib, epoch + client.wakuRlnRelay.rlnEpochSizeSec * 1).isOk()
client.wakuRlnRelay
.appendRLNProof(message1kib, epoch + client.wakuRlnRelay.rlnEpochSizeSec * 1)
.isOk()
)
doAssert(
client.wakuRlnRelay.appendRLNProof(message150kib, epoch + client.wakuRlnRelay.rlnEpochSizeSec * 2).isOk()
client.wakuRlnRelay
.appendRLNProof(message150kib, epoch + client.wakuRlnRelay.rlnEpochSizeSec * 2)
.isOk()
)
doAssert(
client.wakuRlnRelay.appendRLNProof(
client.wakuRlnRelay
.appendRLNProof(
message151kibPlus, epoch + client.wakuRlnRelay.rlnEpochSizeSec * 3
).isOk()
)
.isOk()
)
# When sending the 1B message
@ -319,8 +313,7 @@ suite "Waku RlnRelay - End to End":
overhead: uint64 = 419
payload150kibPlus = getByteSequence((150 * 1024) - overhead + 1)
var
message151kibPlus =
var message151kibPlus =
WakuMessage(payload: @payload150kibPlus, contentTopic: contentTopic)
doAssert(

View File

@ -17,7 +17,7 @@ import
waku_store/client,
waku_archive,
waku_archive/driver/sqlite_driver,
common/databases/db_sqlite
common/databases/db_sqlite,
],
../waku_store/store_utils,
../waku_archive/archive_utils,
@ -55,11 +55,10 @@ suite "Waku Store - End to End - Sorted Archive":
fakeWakuMessage(@[byte 06], ts = ts(60, timeOrigin)),
fakeWakuMessage(@[byte 07], ts = ts(70, timeOrigin)),
fakeWakuMessage(@[byte 08], ts = ts(80, timeOrigin)),
fakeWakuMessage(@[byte 09], ts = ts(90, timeOrigin))
fakeWakuMessage(@[byte 09], ts = ts(90, timeOrigin)),
]
historyQuery =
HistoryQuery(
historyQuery = HistoryQuery(
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
direction: PagingDirection.Forward,
@ -98,9 +97,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse.get().messages == archiveMessages[0 ..< 5]
# Given the next query
var
otherHistoryQuery =
HistoryQuery(
var otherHistoryQuery = HistoryQuery(
cursor: queryResponse.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -109,8 +106,8 @@ suite "Waku Store - End to End - Sorted Archive":
)
# When making the next history query
let
otherQueryResponse = await client.query(otherHistoryQuery, serverRemotePeerInfo)
let otherQueryResponse =
await client.query(otherHistoryQuery, serverRemotePeerInfo)
# Then the response contains the messages
check:
@ -128,9 +125,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse.get().messages == archiveMessages[5 ..< 10]
# Given the next query
var
nextHistoryQuery =
HistoryQuery(
var nextHistoryQuery = HistoryQuery(
cursor: queryResponse.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -139,8 +134,8 @@ suite "Waku Store - End to End - Sorted Archive":
)
# When making the next history query
let
otherQueryResponse = await client.query(nextHistoryQuery, serverRemotePeerInfo)
let otherQueryResponse =
await client.query(nextHistoryQuery, serverRemotePeerInfo)
# Then the response contains the messages
check:
@ -159,9 +154,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse1.get().messages == archiveMessages[0 ..< 2]
# Given the next query (2/5)
let
historyQuery2 =
HistoryQuery(
let historyQuery2 = HistoryQuery(
cursor: queryResponse1.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -177,9 +170,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse2.get().messages == archiveMessages[2 ..< 4]
# Given the next query (3/5)
let
historyQuery3 =
HistoryQuery(
let historyQuery3 = HistoryQuery(
cursor: queryResponse2.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -195,9 +186,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse3.get().messages == archiveMessages[4 ..< 6]
# Given the next query (4/5)
let
historyQuery4 =
HistoryQuery(
let historyQuery4 = HistoryQuery(
cursor: queryResponse3.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -213,9 +202,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse4.get().messages == archiveMessages[6 ..< 8]
# Given the next query (5/5)
let
historyQuery5 =
HistoryQuery(
let historyQuery5 = HistoryQuery(
cursor: queryResponse4.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -242,9 +229,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse1.get().messages == archiveMessages[0 ..< 8]
# Given the next query (2/2)
let
historyQuery2 =
HistoryQuery(
let historyQuery2 = HistoryQuery(
cursor: queryResponse1.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -282,9 +267,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse1.get().messages == archiveMessages[0 ..< 2]
# Given the next query (2/3)
let
historyQuery2 =
HistoryQuery(
let historyQuery2 = HistoryQuery(
cursor: queryResponse1.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -300,9 +283,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse2.get().messages == archiveMessages[2 ..< 6]
# Given the next query (3/3)
let
historyQuery3 =
HistoryQuery(
let historyQuery3 = HistoryQuery(
cursor: queryResponse2.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -348,9 +329,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse1.get().messages == totalMessages[0 ..< archive.DefaultPageSize]
# Given the next query (2/2)
let
historyQuery2 =
HistoryQuery(
let historyQuery2 = HistoryQuery(
cursor: queryResponse1.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -387,8 +366,7 @@ suite "Waku Store - End to End - Sorted Archive":
let totalMessages = archiveMessages & extraMessages
# Given a query with default page size (1/2)
historyQuery =
HistoryQuery(
historyQuery = HistoryQuery(
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
direction: PagingDirection.FORWARD,
@ -402,9 +380,7 @@ suite "Waku Store - End to End - Sorted Archive":
queryResponse.get().messages == totalMessages[0 ..< archive.DefaultPageSize]
# Given the next query (2/2)
let
historyQuery2 =
HistoryQuery(
let historyQuery2 = HistoryQuery(
cursor: queryResponse.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -488,17 +464,14 @@ suite "Waku Store - End to End - Sorted Archive":
let cursor = queryResponse.get().cursor
# When making a history query to the second server node
let
otherHistoryQuery =
HistoryQuery(
let otherHistoryQuery = HistoryQuery(
cursor: cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
direction: PagingDirection.FORWARD,
pageSize: 5,
)
let
otherQueryResponse =
let otherQueryResponse =
await client.query(otherHistoryQuery, otherServerRemotePeerInfo)
# Then the response contains the remaining messages
@ -526,8 +499,7 @@ suite "Waku Store - End to End - Unsorted Archive":
contentTopic = DefaultContentTopic
contentTopicSeq = @[contentTopic]
historyQuery =
HistoryQuery(
historyQuery = HistoryQuery(
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
direction: PagingDirection.FORWARD,
@ -546,7 +518,7 @@ suite "Waku Store - End to End - Unsorted Archive":
fakeWakuMessage(@[byte 06], ts = ts(20, timeOrigin)), # 6
fakeWakuMessage(@[byte 01], ts = ts(20, timeOrigin)), # 9
fakeWakuMessage(@[byte 04], ts = ts(20, timeOrigin)), # 7
fakeWakuMessage(@[byte 05], ts = ts(20, timeOrigin)) # 8
fakeWakuMessage(@[byte 05], ts = ts(20, timeOrigin)), # 8
]
let
@ -586,13 +558,11 @@ suite "Waku Store - End to End - Unsorted Archive":
unsortedArchiveMessages[0],
unsortedArchiveMessages[1],
unsortedArchiveMessages[4],
unsortedArchiveMessages[3]
unsortedArchiveMessages[3],
]
# Given the next query
var
historyQuery2 =
HistoryQuery(
var historyQuery2 = HistoryQuery(
cursor: queryResponse.get().cursor,
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
@ -611,7 +581,7 @@ suite "Waku Store - End to End - Unsorted Archive":
unsortedArchiveMessages[6],
unsortedArchiveMessages[8],
unsortedArchiveMessages[9],
unsortedArchiveMessages[7]
unsortedArchiveMessages[7],
]
asyncTest "Backward pagination with Ascending Sorting":
@ -629,7 +599,7 @@ suite "Waku Store - End to End - Unsorted Archive":
@[
unsortedArchiveMessages[2],
unsortedArchiveMessages[0],
unsortedArchiveMessages[1]
unsortedArchiveMessages[1],
]
asyncTest "Forward Pagination with Ascending Sorting":
@ -649,7 +619,7 @@ suite "Waku Store - End to End - Unsorted Archive":
unsortedArchiveMessages[5],
unsortedArchiveMessages[6],
unsortedArchiveMessages[8],
unsortedArchiveMessages[9]
unsortedArchiveMessages[9],
]
suite "Waku Store - End to End - Archive with Multiple Topics":
@ -680,8 +650,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
contentTopicSeq =
@[contentTopic, contentTopicB, contentTopicC, contentTopicSpecials]
historyQuery =
HistoryQuery(
historyQuery = HistoryQuery(
pubsubTopic: some(pubsubTopic),
contentTopics: contentTopicSeq,
direction: PagingDirection.FORWARD,
@ -689,8 +658,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
)
let timeOrigin = now()
originTs =
proc(offset = 0): Timestamp {.gcsafe, raises: [].} =
originTs = proc(offset = 0): Timestamp {.gcsafe, raises: [].} =
ts(offset, timeOrigin)
archiveMessages =
@ -706,7 +674,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
fakeWakuMessage(@[byte 08], ts = originTs(80), contentTopic = contentTopicC),
fakeWakuMessage(
@[byte 09], ts = originTs(90), contentTopic = contentTopicSpecials
)
),
]
let
@ -716,11 +684,9 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
server = newTestWakuNode(serverKey, ValidIpAddress.init("0.0.0.0"), Port(0))
client = newTestWakuNode(clientKey, ValidIpAddress.init("0.0.0.0"), Port(0))
let
archiveDriver =
newSqliteArchiveDriver().put(pubsubTopic, archiveMessages[0..<6]).put(
pubsubTopicB, archiveMessages[6..<10]
)
let archiveDriver = newSqliteArchiveDriver()
.put(pubsubTopic, archiveMessages[0 ..< 6])
.put(pubsubTopicB, archiveMessages[6 ..< 10])
let mountSortedArchiveResult = server.mountArchive(archiveDriver)
assert mountSortedArchiveResult.isOk()
@ -761,7 +727,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
archiveMessages[0],
archiveMessages[1],
archiveMessages[3],
archiveMessages[4]
archiveMessages[4],
]
asyncTest "Empty Content Filtering":
@ -776,9 +742,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
queryResponse.get().messages == archiveMessages[0 ..< 5]
# Given the next query
let
historyQuery2 =
HistoryQuery(
let historyQuery2 = HistoryQuery(
cursor: queryResponse.get().cursor,
pubsubTopic: none(PubsubTopic),
contentTopics: contentTopicSeq,
@ -830,7 +794,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
archiveMessages[6],
archiveMessages[7],
archiveMessages[8],
archiveMessages[9]
archiveMessages[9],
]
asyncTest "PubsubTopic Left Empty":
@ -845,9 +809,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
queryResponse.get().messages == archiveMessages[0 ..< 5]
# Given the next query
let
historyQuery2 =
HistoryQuery(
let historyQuery2 = HistoryQuery(
cursor: queryResponse.get().cursor,
pubsubTopic: none(PubsubTopic),
contentTopics: contentTopicSeq,
@ -891,7 +853,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
archiveMessages[2],
archiveMessages[3],
archiveMessages[4],
archiveMessages[5]
archiveMessages[5],
]
asyncTest "Only End Time Specified":
@ -910,7 +872,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
archiveMessages[1],
archiveMessages[2],
archiveMessages[3],
archiveMessages[4]
archiveMessages[4],
]
asyncTest "Invalid Time Range":
@ -959,7 +921,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
@[
fakeWakuMessage(@[byte 00], ts = ts(00), ephemeral = true),
fakeWakuMessage(@[byte 01], ts = ts(10), ephemeral = true),
fakeWakuMessage(@[byte 02], ts = ts(20), ephemeral = true)
fakeWakuMessage(@[byte 02], ts = ts(20), ephemeral = true),
]
ephemeralArchiveDriver =
newSqliteArchiveDriver().put(pubsubTopic, ephemeralMessages)
@ -978,8 +940,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
let ephemeralServerRemotePeerInfo = ephemeralServer.peerInfo.toRemotePeerInfo()
# When making a history query to the server with only ephemeral messages
let
queryResponse = await client.query(historyQuery, ephemeralServerRemotePeerInfo)
let queryResponse =
await client.query(historyQuery, ephemeralServerRemotePeerInfo)
# Then the response contains no messages
check:
@ -995,18 +957,17 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
@[
fakeWakuMessage(@[byte 00], ts = ts(00), ephemeral = true),
fakeWakuMessage(@[byte 01], ts = ts(10), ephemeral = true),
fakeWakuMessage(@[byte 02], ts = ts(20), ephemeral = true)
fakeWakuMessage(@[byte 02], ts = ts(20), ephemeral = true),
]
nonEphemeralMessages =
@[
fakeWakuMessage(@[byte 03], ts = ts(30), ephemeral = false),
fakeWakuMessage(@[byte 04], ts = ts(40), ephemeral = false),
fakeWakuMessage(@[byte 05], ts = ts(50), ephemeral = false)
fakeWakuMessage(@[byte 05], ts = ts(50), ephemeral = false),
]
mixedArchiveDriver =
newSqliteArchiveDriver().put(pubsubTopic, ephemeralMessages).put(
pubsubTopic, nonEphemeralMessages
)
mixedArchiveDriver = newSqliteArchiveDriver()
.put(pubsubTopic, ephemeralMessages)
.put(pubsubTopic, nonEphemeralMessages)
# And a server node with the mixed archive
let
@ -1063,8 +1024,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
for i in 0 ..< 100000:
let topic = "topic" & $i
voluminousArchiveMessages.add(fakeWakuMessage(@[byte i], contentTopic = topic))
let
voluminousArchiveDriverWithMessages =
let voluminousArchiveDriverWithMessages =
newArchiveDriverWithMessages(pubsubTopic, voluminousArchiveMessages)
# And a server node with the voluminous archive
@ -1085,8 +1045,8 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
@["topic10000", "topic30000", "topic50000", "topic70000", "topic90000"]
# When making a history query to the server with a voluminous archive
let
queryResponse = await client.query(historyQuery, voluminousServerRemotePeerInfo)
let queryResponse =
await client.query(historyQuery, voluminousServerRemotePeerInfo)
# Then the response contains the messages
check:
@ -1096,7 +1056,7 @@ suite "Waku Store - End to End - Archive with Multiple Topics":
voluminousArchiveMessages[30000],
voluminousArchiveMessages[50000],
voluminousArchiveMessages[70000],
voluminousArchiveMessages[90000]
voluminousArchiveMessages[90000],
]
# Cleanup

View File

@ -1,7 +1,11 @@
proc getContentTopic*(applicationName: string, applicationVersion: int, contentTopicName: string, encoding: string): string =
proc getContentTopic*(
applicationName: string,
applicationVersion: int,
contentTopicName: string,
encoding: string,
): string =
return "/$applicationName/$applicationVersion/$contentTopicName/$enconding"
const
CURRENT* = getContentTopic("application", 1, "content-topic", "proto")
TESTNET* = getContentTopic("toychat", 2, "huilong", "proto")

View File

@ -1,13 +1,15 @@
import
std/json
import std/json
const
ALPHABETIC* = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
ALPHANUMERIC* = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
ALPHANUMERIC_SPECIAL* = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;':\\\",./<>?`~"
EMOJI* = "😀 😃 😄 😁 😆 😅 🤣 😂 🙂 🙃 😉 😊 😇 🥰 😍 🤩 😘 😗 😚 😙"
ALPHANUMERIC_SPECIAL* =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]{}|;':\\\",./<>?`~"
EMOJI* =
"😀 😃 😄 😁 😆 😅 🤣 😂 🙂 🙃 😉 😊 😇 🥰 😍 🤩 😘 😗 😚 😙"
CODE* = "def main():\n\tprint('Hello, world!')"
QUERY* = """
QUERY* =
"""
SELECT
u.id,
u.name,
@ -28,7 +30,8 @@ const
u.id = 1
"""
TEXT_SMALL* = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
TEXT_LARGE* = """
TEXT_LARGE* =
"""
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras gravida vulputate semper. Proin
eleifend varius cursus. Morbi lacinia posuere quam sit amet pretium. Sed non metus fermentum,
venenatis nisl id, vestibulum eros. Quisque non lorem sit amet lectus faucibus elementum eu
@ -40,35 +43,12 @@ const
proc getSampleJsonDictionary*(): JsonNode =
%*{
"shapes": [
{
"type": "circle",
"radius": 10
},
{
"type": "square",
"side": 10
}
],
"colours": [
"red",
"green",
"blue"
]
"shapes": [{"type": "circle", "radius": 10}, {"type": "square", "side": 10}],
"colours": ["red", "green", "blue"],
}
proc getSampleJsonList*(): JsonNode =
%*[
{
"type": "cat",
"name": "Salem"
},
{
"type": "dog",
"name": "Oberon"
},
]
%*[{"type": "cat", "name": "Salem"}, {"type": "dog", "name": "Oberon"}]
proc getByteSequence*(bytesNumber: uint64): seq[byte] =
result = newSeq[byte](bytesNumber)

View File

@ -3,7 +3,6 @@ import std/strformat
proc getPubsubTopic*(pubsubTopicName: string): string =
return fmt"/waku/2/{pubsubTopicName}"
const
CURRENT* = getPubsubTopic("test")
CURRENT_NESTED* = getPubsubTopic("test/nested")

View File

@ -1,6 +1,3 @@
{.used.}
import
./all_tests_common,
./all_tests_waku,
./all_tests_wakunode2
import ./all_tests_common, ./all_tests_waku, ./all_tests_wakunode2

View File

@ -1,6 +1,4 @@
import
chronos, bearssl/rand,
eth/[keys, p2p]
import chronos, bearssl/rand, eth/[keys, p2p]
import libp2p/crypto/crypto
@ -8,20 +6,23 @@ var nextPort = 30303
proc localAddress*(port: int): Address =
let port = Port(port)
result = Address(udpPort: port, tcpPort: port,
ip: parseIpAddress("127.0.0.1"))
result = Address(udpPort: port, tcpPort: port, ip: parseIpAddress("127.0.0.1"))
proc setupTestNode*(
rng: ref HmacDrbgContext,
capabilities: varargs[ProtocolInfo, `protocolInfo`]): EthereumNode =
rng: ref HmacDrbgContext, capabilities: varargs[ProtocolInfo, `protocolInfo`]
): EthereumNode =
let
keys1 = keys.KeyPair.random(rng[])
address = localAddress(nextPort)
result = newEthereumNode(keys1, address, NetworkId(1),
result = newEthereumNode(
keys1,
address,
NetworkId(1),
addAllCapabilities = false,
bindUdpPort = address.udpPort, # Assume same as external
bindTcpPort = address.tcpPort, # Assume same as external
rng = rng)
rng = rng,
)
nextPort.inc
for capability in capabilities:
result.addCapability capability

View File

@ -1,13 +1,7 @@
{.used.}
import
std/sets,
stew/[results, byteutils],
testutils/unittests
import
../../waku/waku_core,
../../waku/waku_api/message_cache,
./testlib/wakucore
import std/sets, stew/[results, byteutils], testutils/unittests
import ../../waku/waku_core, ../../waku/waku_api/message_cache, ./testlib/wakucore
suite "MessageCache":
setup:

View File

@ -37,20 +37,28 @@ import
procSuite "Peer Manager":
asyncTest "connectRelay() works":
# Create 2 nodes
let nodes = toSeq(0..<2).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
let nodes = toSeq(0 ..< 2).mapIt(
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
)
await allFutures(nodes.mapIt(it.start()))
let connOk = await nodes[0].peerManager.connectRelay(nodes[1].peerInfo.toRemotePeerInfo())
let connOk =
await nodes[0].peerManager.connectRelay(nodes[1].peerInfo.toRemotePeerInfo())
await sleepAsync(chronos.milliseconds(500))
check:
connOk == true
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[1].peerInfo.peerId)
nodes[0].peerManager.peerStore.connectedness(nodes[1].peerInfo.peerId) == Connectedness.Connected
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[1].peerInfo.peerId
)
nodes[0].peerManager.peerStore.connectedness(nodes[1].peerInfo.peerId) ==
Connectedness.Connected
asyncTest "dialPeer() works":
# Create 2 nodes
let nodes = toSeq(0..<2).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
let nodes = toSeq(0 ..< 2).mapIt(
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
)
await allFutures(nodes.mapIt(it.start()))
await allFutures(nodes.mapIt(it.mountRelay()))
@ -58,7 +66,9 @@ procSuite "Peer Manager":
await allFutures(nodes.mapIt(it.mountLegacyFilter()))
# Dial node2 from node1
let conn = await nodes[0].peerManager.dialPeer(nodes[1].peerInfo.toRemotePeerInfo(), WakuLegacyFilterCodec)
let conn = await nodes[0].peerManager.dialPeer(
nodes[1].peerInfo.toRemotePeerInfo(), WakuLegacyFilterCodec
)
await sleepAsync(chronos.milliseconds(500))
# Check connection
@ -69,32 +79,42 @@ procSuite "Peer Manager":
# Check that node2 is being managed in node1
check:
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[1].peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[1].peerInfo.peerId
)
# Check connectedness
check:
nodes[0].peerManager.peerStore.connectedness(nodes[1].peerInfo.peerId) == Connectedness.Connected
nodes[0].peerManager.peerStore.connectedness(nodes[1].peerInfo.peerId) ==
Connectedness.Connected
await allFutures(nodes.mapIt(it.stop()))
asyncTest "dialPeer() fails gracefully":
# Create 2 nodes and start them
let nodes = toSeq(0..<2).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
let nodes = toSeq(0 ..< 2).mapIt(
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
)
await allFutures(nodes.mapIt(it.start()))
await allFutures(nodes.mapIt(it.mountRelay()))
let nonExistentPeerRes = parsePeerInfo("/ip4/0.0.0.0/tcp/1000/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e")
let nonExistentPeerRes = parsePeerInfo(
"/ip4/0.0.0.0/tcp/1000/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e"
)
require nonExistentPeerRes.isOk()
let nonExistentPeer = nonExistentPeerRes.value
# Dial non-existent peer from node1
let conn1 = await nodes[0].peerManager.dialPeer(nonExistentPeer, WakuLegacyFilterCodec)
let conn1 =
await nodes[0].peerManager.dialPeer(nonExistentPeer, WakuLegacyFilterCodec)
check:
conn1.isNone()
# Dial peer not supporting given protocol
let conn2 = await nodes[0].peerManager.dialPeer(nodes[1].peerInfo.toRemotePeerInfo(), WakuLegacyFilterCodec)
let conn2 = await nodes[0].peerManager.dialPeer(
nodes[1].peerInfo.toRemotePeerInfo(), WakuLegacyFilterCodec
)
check:
conn2.isNone()
@ -102,7 +122,8 @@ procSuite "Peer Manager":
asyncTest "Adding, selecting and filtering peers work":
let
node = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
node =
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
# Create filter peer
filterLoc = MultiAddress.init("/ip4/127.0.0.1/tcp/0").tryGet()
@ -117,23 +138,29 @@ procSuite "Peer Manager":
node.mountStoreClient()
node.peerManager.addServicePeer(storePeer.toRemotePeerInfo(), WakuStoreCodec)
node.peerManager.addServicePeer(filterPeer.toRemotePeerInfo(), WakuLegacyFilterCodec)
node.peerManager.addServicePeer(
filterPeer.toRemotePeerInfo(), WakuLegacyFilterCodec
)
# Check peers were successfully added to peer manager
check:
node.peerManager.peerStore.peers().len == 2
node.peerManager.peerStore.peers(WakuLegacyFilterCodec).allIt(it.peerId == filterPeer.peerId and
it.addrs.contains(filterLoc) and
it.protocols.contains(WakuLegacyFilterCodec))
node.peerManager.peerStore.peers(WakuStoreCodec).allIt(it.peerId == storePeer.peerId and
it.addrs.contains(storeLoc) and
it.protocols.contains(WakuStoreCodec))
node.peerManager.peerStore.peers(WakuLegacyFilterCodec).allIt(
it.peerId == filterPeer.peerId and it.addrs.contains(filterLoc) and
it.protocols.contains(WakuLegacyFilterCodec)
)
node.peerManager.peerStore.peers(WakuStoreCodec).allIt(
it.peerId == storePeer.peerId and it.addrs.contains(storeLoc) and
it.protocols.contains(WakuStoreCodec)
)
await node.stop()
asyncTest "Peer manager keeps track of connections":
# Create 2 nodes
let nodes = toSeq(0..<2).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
let nodes = toSeq(0 ..< 2).mapIt(
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
)
await allFutures(nodes.mapIt(it.start()))
await allFutures(nodes.mapIt(it.mountRelay()))
@ -142,10 +169,13 @@ procSuite "Peer Manager":
nodes[0].peerManager.addPeer(nodes[1].peerInfo.toRemotePeerInfo())
check:
# No information about node2's connectedness
nodes[0].peerManager.peerStore.connectedness(nodes[1].peerInfo.peerId) == NotConnected
nodes[0].peerManager.peerStore.connectedness(nodes[1].peerInfo.peerId) ==
NotConnected
# Failed connection
let nonExistentPeerRes = parsePeerInfo("/ip4/0.0.0.0/tcp/1000/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e")
let nonExistentPeerRes = parsePeerInfo(
"/ip4/0.0.0.0/tcp/1000/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e"
)
require:
nonExistentPeerRes.isOk()
@ -156,11 +186,13 @@ procSuite "Peer Manager":
check:
# Cannot connect to node2
nodes[0].peerManager.peerStore.connectedness(nonExistentPeer.peerId) == CannotConnect
nodes[0].peerManager.peerStore.connectedness(nonExistentPeer.peerId) ==
CannotConnect
# Successful connection
require:
(await nodes[0].peerManager.connectRelay(nodes[1].peerInfo.toRemotePeerInfo())) == true
(await nodes[0].peerManager.connectRelay(nodes[1].peerInfo.toRemotePeerInfo())) ==
true
await sleepAsync(chronos.milliseconds(500))
check:
@ -171,18 +203,23 @@ procSuite "Peer Manager":
await nodes[0].stop()
check:
# Not currently connected to node2, but had recent, successful connection.
nodes[0].peerManager.peerStore.connectedness(nodes[1].peerInfo.peerId) == CanConnect
nodes[0].peerManager.peerStore.connectedness(nodes[1].peerInfo.peerId) ==
CanConnect
await nodes[1].stop()
asyncTest "Peer manager updates failed peers correctly":
# Create 2 nodes
let nodes = toSeq(0..<2).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
let nodes = toSeq(0 ..< 2).mapIt(
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
)
await allFutures(nodes.mapIt(it.start()))
await allFutures(nodes.mapIt(it.mountRelay()))
let nonExistentPeerRes = parsePeerInfo("/ip4/0.0.0.0/tcp/1000/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e")
let nonExistentPeerRes = parsePeerInfo(
"/ip4/0.0.0.0/tcp/1000/p2p/16Uiu2HAmL5okWopX7NqZWBUKVqW8iUxCEmd5GMHLVPwCgzYzQv3e"
)
require nonExistentPeerRes.isOk()
let nonExistentPeer = nonExistentPeerRes.value
@ -197,8 +234,10 @@ procSuite "Peer Manager":
let conn1Ok = await nodes[0].peerManager.connectRelay(nonExistentPeer)
check:
# Cannot connect to node2
nodes[0].peerManager.peerStore.connectedness(nonExistentPeer.peerId) == CannotConnect
nodes[0].peerManager.peerStore[ConnectionBook][nonExistentPeer.peerId] == CannotConnect
nodes[0].peerManager.peerStore.connectedness(nonExistentPeer.peerId) ==
CannotConnect
nodes[0].peerManager.peerStore[ConnectionBook][nonExistentPeer.peerId] ==
CannotConnect
nodes[0].peerManager.peerStore[NumberFailedConnBook][nonExistentPeer.peerId] == 1
# Connection attempt failed
@ -216,7 +255,8 @@ procSuite "Peer Manager":
# After a successful connection, the number of failed connections is reset
nodes[0].peerManager.peerStore[NumberFailedConnBook][nodes[1].peerInfo.peerId] = 4
let conn2Ok = await nodes[0].peerManager.connectRelay(nodes[1].peerInfo.toRemotePeerInfo())
let conn2Ok =
await nodes[0].peerManager.connectRelay(nodes[1].peerInfo.toRemotePeerInfo())
check:
conn2Ok == true
nodes[0].peerManager.peerStore[NumberFailedConnBook][nodes[1].peerInfo.peerId] == 0
@ -231,9 +271,11 @@ procSuite "Peer Manager":
generateSecp256k1Key(),
ValidIpAddress.init("127.0.0.1"),
Port(44048),
peerStorage = storage
peerStorage = storage,
)
node2 = newTestWakuNode(
generateSecp256k1Key(), ValidIpAddress.init("127.0.0.1"), Port(34023)
)
node2 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("127.0.0.1"), Port(34023))
node1.mountMetadata(0).expect("Mounted Waku Metadata")
node2.mountMetadata(0).expect("Mounted Waku Metadata")
@ -252,7 +294,8 @@ procSuite "Peer Manager":
assert is12Connected == true, "Node 1 and 2 not connected"
check:
node1.peerManager.peerStore[AddressBook][remotePeerInfo2.peerId] == remotePeerInfo2.addrs
node1.peerManager.peerStore[AddressBook][remotePeerInfo2.peerId] ==
remotePeerInfo2.addrs
# wait for the peer store update
await sleepAsync(chronos.milliseconds(500))
@ -268,7 +311,7 @@ procSuite "Peer Manager":
generateSecp256k1Key(),
ValidIpAddress.init("127.0.0.1"),
Port(56037),
peerStorage = storage
peerStorage = storage,
)
node3.mountMetadata(0).expect("Mounted Waku Metadata")
@ -303,9 +346,11 @@ procSuite "Peer Manager":
generateSecp256k1Key(),
ValidIpAddress.init("127.0.0.1"),
Port(44048),
peerStorage = storage
peerStorage = storage,
)
node2 = newTestWakuNode(
generateSecp256k1Key(), ValidIpAddress.init("127.0.0.1"), Port(34023)
)
node2 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("127.0.0.1"), Port(34023))
node1.mountMetadata(0).expect("Mounted Waku Metadata")
node2.mountMetadata(0).expect("Mounted Waku Metadata")
@ -324,7 +369,8 @@ procSuite "Peer Manager":
assert is12Connected == true, "Node 1 and 2 not connected"
check:
node1.peerManager.peerStore[AddressBook][remotePeerInfo2.peerId] == remotePeerInfo2.addrs
node1.peerManager.peerStore[AddressBook][remotePeerInfo2.peerId] ==
remotePeerInfo2.addrs
# wait for the peer store update
await sleepAsync(chronos.milliseconds(500))
@ -340,7 +386,7 @@ procSuite "Peer Manager":
generateSecp256k1Key(),
ValidIpAddress.init("127.0.0.1"),
Port(56037),
peerStorage = storage
peerStorage = storage,
)
node3.mountMetadata(0).expect("Mounted Waku Metadata")
@ -405,13 +451,19 @@ procSuite "Peer Manager":
await allFutures([node1.start(), node2.start(), node3.start()])
# 1->2 (fails)
let conn1 = await node1.peerManager.dialPeer(node2.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec)
let conn1 = await node1.peerManager.dialPeer(
node2.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec
)
# 1->3 (fails)
let conn2 = await node1.peerManager.dialPeer(node3.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec)
let conn2 = await node1.peerManager.dialPeer(
node3.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec
)
# 2->3 (succeeds)
let conn3 = await node2.peerManager.dialPeer(node3.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec)
let conn3 = await node2.peerManager.dialPeer(
node3.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec
)
check:
conn1.isNone
@ -423,8 +475,14 @@ procSuite "Peer Manager":
let
database = SqliteDatabase.new(":memory:")[]
storage = WakuPeerStorage.new(database)[]
node1 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0), peerStorage = storage)
node2 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
node1 = newTestWakuNode(
generateSecp256k1Key(),
ValidIpAddress.init("0.0.0.0"),
Port(0),
peerStorage = storage,
)
node2 =
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
peerInfo2 = node2.switch.peerInfo
betaCodec = "/vac/waku/relay/2.0.0-beta2"
stableCodec = "/vac/waku/relay/2.0.0"
@ -443,12 +501,18 @@ procSuite "Peer Manager":
# Currently connected to node2
node1.peerManager.peerStore.peers().len == 1
node1.peerManager.peerStore.peers().anyIt(it.peerId == peerInfo2.peerId)
node1.peerManager.peerStore.peers().anyIt(it.protocols.contains(node2.wakuRelay.codec))
node1.peerManager.peerStore.peers().anyIt(
it.protocols.contains(node2.wakuRelay.codec)
)
node1.peerManager.peerStore.connectedness(peerInfo2.peerId) == Connected
# Simulate restart by initialising a new node using the same storage
let
node3 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0), peerStorage = storage)
let node3 = newTestWakuNode(
generateSecp256k1Key(),
ValidIpAddress.init("0.0.0.0"),
Port(0),
peerStorage = storage,
)
await node3.mountRelay()
node3.wakuRelay.codec = stableCodec
@ -476,14 +540,12 @@ procSuite "Peer Manager":
asyncTest "Peer manager connects to all peers supporting a given protocol":
# Create 4 nodes
let nodes =
toSeq(0..<4)
.mapIt(
let nodes = toSeq(0 ..< 4).mapIt(
newTestWakuNode(
nodeKey = generateSecp256k1Key(),
bindIp = ValidIpAddress.init("0.0.0.0"),
bindPort = Port(0),
wakuFlags = some(CapabilitiesBitfield.init(@[Relay]))
wakuFlags = some(CapabilitiesBitfield.init(@[Relay])),
)
)
@ -512,32 +574,45 @@ procSuite "Peer Manager":
nodes[0].peerManager.peerStore.peers().len == 3
# All peer ids are correct
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[1].switch.peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[2].switch.peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[3].switch.peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[1].switch.peerInfo.peerId
)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[2].switch.peerInfo.peerId
)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[3].switch.peerInfo.peerId
)
# All peers support the relay protocol
nodes[0].peerManager.peerStore[ProtoBook][nodes[1].switch.peerInfo.peerId].contains(WakuRelayCodec)
nodes[0].peerManager.peerStore[ProtoBook][nodes[2].switch.peerInfo.peerId].contains(WakuRelayCodec)
nodes[0].peerManager.peerStore[ProtoBook][nodes[3].switch.peerInfo.peerId].contains(WakuRelayCodec)
nodes[0].peerManager.peerStore[ProtoBook][nodes[1].switch.peerInfo.peerId].contains(
WakuRelayCodec
)
nodes[0].peerManager.peerStore[ProtoBook][nodes[2].switch.peerInfo.peerId].contains(
WakuRelayCodec
)
nodes[0].peerManager.peerStore[ProtoBook][nodes[3].switch.peerInfo.peerId].contains(
WakuRelayCodec
)
# All peers are connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[1].switch.peerInfo.peerId] == Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[2].switch.peerInfo.peerId] == Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[3].switch.peerInfo.peerId] == Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[1].switch.peerInfo.peerId] ==
Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[2].switch.peerInfo.peerId] ==
Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[3].switch.peerInfo.peerId] ==
Connected
await allFutures(nodes.mapIt(it.stop()))
asyncTest "Sharded peer manager connects to all peers supporting a given protocol":
# Create 4 nodes
let nodes =
toSeq(0..<4)
.mapIt(
let nodes = toSeq(0 ..< 4).mapIt(
newTestWakuNode(
nodeKey = generateSecp256k1Key(),
bindIp = ValidIpAddress.init("0.0.0.0"),
bindPort = Port(0),
wakuFlags = some(CapabilitiesBitfield.init(@[Relay]))
wakuFlags = some(CapabilitiesBitfield.init(@[Relay])),
)
)
@ -566,25 +641,42 @@ procSuite "Peer Manager":
nodes[0].peerManager.peerStore.peers().len == 3
# All peer ids are correct
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[1].switch.peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[2].switch.peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[3].switch.peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[1].switch.peerInfo.peerId
)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[2].switch.peerInfo.peerId
)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[3].switch.peerInfo.peerId
)
# All peers support the relay protocol
nodes[0].peerManager.peerStore[ProtoBook][nodes[1].switch.peerInfo.peerId].contains(WakuRelayCodec)
nodes[0].peerManager.peerStore[ProtoBook][nodes[2].switch.peerInfo.peerId].contains(WakuRelayCodec)
nodes[0].peerManager.peerStore[ProtoBook][nodes[3].switch.peerInfo.peerId].contains(WakuRelayCodec)
nodes[0].peerManager.peerStore[ProtoBook][nodes[1].switch.peerInfo.peerId].contains(
WakuRelayCodec
)
nodes[0].peerManager.peerStore[ProtoBook][nodes[2].switch.peerInfo.peerId].contains(
WakuRelayCodec
)
nodes[0].peerManager.peerStore[ProtoBook][nodes[3].switch.peerInfo.peerId].contains(
WakuRelayCodec
)
# All peers are connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[1].switch.peerInfo.peerId] == Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[2].switch.peerInfo.peerId] == Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[3].switch.peerInfo.peerId] == Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[1].switch.peerInfo.peerId] ==
Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[2].switch.peerInfo.peerId] ==
Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[3].switch.peerInfo.peerId] ==
Connected
await allFutures(nodes.mapIt(it.stop()))
asyncTest "Peer store keeps track of incoming connections":
# Create 4 nodes
let nodes = toSeq(0..<4).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
let nodes = toSeq(0 ..< 4).mapIt(
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
)
# Start them
await allFutures(nodes.mapIt(it.start()))
@ -616,29 +708,50 @@ procSuite "Peer Manager":
nodes[3].peerManager.peerStore.getPeersByDirection(Outbound).len == 1
# All peer ids are correct
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[1].switch.peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[2].switch.peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[3].switch.peerInfo.peerId)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[1].switch.peerInfo.peerId
)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[2].switch.peerInfo.peerId
)
nodes[0].peerManager.peerStore.peers().anyIt(
it.peerId == nodes[3].switch.peerInfo.peerId
)
# All peers support the relay protocol
nodes[0].peerManager.peerStore[ProtoBook][nodes[1].switch.peerInfo.peerId].contains(WakuRelayCodec)
nodes[0].peerManager.peerStore[ProtoBook][nodes[2].switch.peerInfo.peerId].contains(WakuRelayCodec)
nodes[0].peerManager.peerStore[ProtoBook][nodes[3].switch.peerInfo.peerId].contains(WakuRelayCodec)
nodes[0].peerManager.peerStore[ProtoBook][nodes[1].switch.peerInfo.peerId].contains(
WakuRelayCodec
)
nodes[0].peerManager.peerStore[ProtoBook][nodes[2].switch.peerInfo.peerId].contains(
WakuRelayCodec
)
nodes[0].peerManager.peerStore[ProtoBook][nodes[3].switch.peerInfo.peerId].contains(
WakuRelayCodec
)
# All peers are connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[1].switch.peerInfo.peerId] == Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[2].switch.peerInfo.peerId] == Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[3].switch.peerInfo.peerId] == Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[1].switch.peerInfo.peerId] ==
Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[2].switch.peerInfo.peerId] ==
Connected
nodes[0].peerManager.peerStore[ConnectionBook][nodes[3].switch.peerInfo.peerId] ==
Connected
# All peers are Inbound in peer 0
nodes[0].peerManager.peerStore[DirectionBook][nodes[1].switch.peerInfo.peerId] == Inbound
nodes[0].peerManager.peerStore[DirectionBook][nodes[2].switch.peerInfo.peerId] == Inbound
nodes[0].peerManager.peerStore[DirectionBook][nodes[3].switch.peerInfo.peerId] == Inbound
nodes[0].peerManager.peerStore[DirectionBook][nodes[1].switch.peerInfo.peerId] ==
Inbound
nodes[0].peerManager.peerStore[DirectionBook][nodes[2].switch.peerInfo.peerId] ==
Inbound
nodes[0].peerManager.peerStore[DirectionBook][nodes[3].switch.peerInfo.peerId] ==
Inbound
# All peers have an Outbound connection with peer 0
nodes[1].peerManager.peerStore[DirectionBook][nodes[0].switch.peerInfo.peerId] == Outbound
nodes[2].peerManager.peerStore[DirectionBook][nodes[0].switch.peerInfo.peerId] == Outbound
nodes[3].peerManager.peerStore[DirectionBook][nodes[0].switch.peerInfo.peerId] == Outbound
nodes[1].peerManager.peerStore[DirectionBook][nodes[0].switch.peerInfo.peerId] ==
Outbound
nodes[2].peerManager.peerStore[DirectionBook][nodes[0].switch.peerInfo.peerId] ==
Outbound
nodes[3].peerManager.peerStore[DirectionBook][nodes[0].switch.peerInfo.peerId] ==
Outbound
await allFutures(nodes.mapIt(it.stop()))
@ -647,11 +760,10 @@ procSuite "Peer Manager":
let basePeerId = "16Uiu2HAm7QGEZKujdSbbo1aaQyfDPQ6Bw3ybQnj6fruH5Dxwd7D"
let
node = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
node =
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
peers = toSeq(1 .. 5)
.mapIt(
parsePeerInfo("/ip4/0.0.0.0/tcp/30300/p2p/" & basePeerId & $it)
)
.mapIt(parsePeerInfo("/ip4/0.0.0.0/tcp/30300/p2p/" & basePeerId & $it))
.filterIt(it.isOk())
.mapIt(it.value)
@ -689,7 +801,9 @@ procSuite "Peer Manager":
asyncTest "connectedPeers() returns expected number of connections per protocol":
# Create 4 nodes
let nodes = toSeq(0..<4).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
let nodes = toSeq(0 ..< 4).mapIt(
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
)
# Start them with relay + filter
await allFutures(nodes.mapIt(it.start()))
@ -706,12 +820,14 @@ procSuite "Peer Manager":
(await nodes[0].peerManager.connectRelay(pInfos[2])) == true
(await nodes[1].peerManager.connectRelay(pInfos[2])) == true
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() == true
(await nodes[0].peerManager.dialPeer(pInfos[2], WakuLegacyFilterCodec)).isSome() == true
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() ==
true
(await nodes[0].peerManager.dialPeer(pInfos[2], WakuLegacyFilterCodec)).isSome() ==
true
# isolated dial creates a relay conn under the hood (libp2p behaviour)
(await nodes[2].peerManager.dialPeer(pInfos[3], WakuLegacyFilterCodec)).isSome() == true
(await nodes[2].peerManager.dialPeer(pInfos[3], WakuLegacyFilterCodec)).isSome() ==
true
# assert physical connections
check:
@ -741,7 +857,9 @@ procSuite "Peer Manager":
asyncTest "getNumStreams() returns expected number of connections per protocol":
# Create 2 nodes
let nodes = toSeq(0..<2).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
let nodes = toSeq(0 ..< 2).mapIt(
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
)
# Start them with relay + filter
await allFutures(nodes.mapIt(it.start()))
@ -754,10 +872,14 @@ procSuite "Peer Manager":
require:
# multiple streams are multiplexed over a single connection.
# note that a relay connection is created under the hood when dialing a peer (libp2p behaviour)
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() == true
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() == true
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() == true
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() == true
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() ==
true
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() ==
true
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() ==
true
(await nodes[0].peerManager.dialPeer(pInfos[1], WakuLegacyFilterCodec)).isSome() ==
true
check:
nodes[0].peerManager.getNumStreams(WakuRelayCodec) == (1, 1)
@ -773,7 +895,8 @@ procSuite "Peer Manager":
# Create peer manager
let pm = PeerManager.new(
switch = SwitchBuilder.new().withRng(rng).withMplex().withNoise().build(),
storage = nil)
storage = nil,
)
# Create 3 peer infos
let peers = toSeq(1 .. 3)
@ -785,7 +908,8 @@ procSuite "Peer Manager":
# Add a peer[0] to the peerstore
pm.peerStore[AddressBook][peers[0].peerId] = peers[0].addrs
pm.peerStore[ProtoBook][peers[0].peerId] = @[WakuRelayCodec, WakuStoreCodec, WakuLegacyFilterCodec]
pm.peerStore[ProtoBook][peers[0].peerId] =
@[WakuRelayCodec, WakuStoreCodec, WakuLegacyFilterCodec]
# When no service peers, we get one from the peerstore
let selectedPeer1 = pm.selectPeer(WakuStoreCodec)
@ -826,22 +950,32 @@ procSuite "Peer Manager":
expect(Defect):
let pm = PeerManager.new(
switch = SwitchBuilder.new().withRng(rng).withMplex().withNoise()
switch = SwitchBuilder
.new()
.withRng(rng)
.withMplex()
.withNoise()
.withPeerStore(peerStoreSize)
.withMaxConnections(maxConnections)
.build(),
storage = nil)
storage = nil,
)
test "prunePeerStore() correctly removes peers to match max quota":
# Create peer manager
let pm = PeerManager.new(
switch = SwitchBuilder.new().withRng(rng).withMplex().withNoise()
switch = SwitchBuilder
.new()
.withRng(rng)
.withMplex()
.withNoise()
.withPeerStore(10)
.withMaxConnections(5)
.build(),
maxFailedAttempts = 1,
maxRelayPeers = some(5),
storage = nil)
storage = nil,
)
# Create 15 peers and add them to the peerstore
let peers = toSeq(1 .. 15)
@ -886,19 +1020,24 @@ procSuite "Peer Manager":
asyncTest "canBeConnected() returns correct value":
let pm = PeerManager.new(
switch = SwitchBuilder.new().withRng(rng).withMplex().withNoise()
switch = SwitchBuilder
.new()
.withRng(rng)
.withMplex()
.withNoise()
.withPeerStore(10)
.withMaxConnections(5)
.build(),
initialBackoffInSec = 1, # with InitialBackoffInSec = 1 backoffs are: 1, 2, 4, 8secs.
initialBackoffInSec = 1,
# with InitialBackoffInSec = 1 backoffs are: 1, 2, 4, 8secs.
backoffFactor = 2,
maxFailedAttempts = 10,
maxRelayPeers = some(5),
storage = nil)
storage = nil,
)
var p1: PeerId
require p1.init("QmeuZJbXrszW2jdT7GdduSjQskPU3S7vvGWKtKgDfkDvW" & "1")
# new peer with no errors can be connected
check:
pm.canBeConnected(p1) == true
@ -938,37 +1077,54 @@ procSuite "Peer Manager":
# Should result in overflow exception
expect(Defect):
let pm = PeerManager.new(
switch = SwitchBuilder.new().withRng(rng).withMplex().withNoise()
switch = SwitchBuilder
.new()
.withRng(rng)
.withMplex()
.withNoise()
.withPeerStore(10)
.withMaxConnections(5)
.build(),
maxRelayPeers = some(5),
maxFailedAttempts = 150,
storage = nil)
storage = nil,
)
# Should result in backoff > 1 week
expect(Defect):
let pm = PeerManager.new(
switch = SwitchBuilder.new().withRng(rng).withMplex().withNoise()
switch = SwitchBuilder
.new()
.withRng(rng)
.withMplex()
.withNoise()
.withPeerStore(10)
.withMaxConnections(5)
.build(),
maxFailedAttempts = 10,
maxRelayPeers = some(5),
storage = nil)
storage = nil,
)
let pm = PeerManager.new(
switch = SwitchBuilder.new().withRng(rng).withMplex().withNoise()
switch = SwitchBuilder
.new()
.withRng(rng)
.withMplex()
.withNoise()
.withPeerStore(10)
.withMaxConnections(5)
.build(),
maxFailedAttempts = 5,
maxRelayPeers = some(5),
storage = nil)
storage = nil,
)
asyncTest "colocationLimit is enforced by pruneConnsByIp()":
# Create 5 nodes
let nodes = toSeq(0..<5).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
let nodes = toSeq(0 ..< 5).mapIt(
newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0))
)
# Start them with relay + filter
await allFutures(nodes.mapIt(it.start()))

View File

@ -1,10 +1,6 @@
{.used.}
import
std/options,
testutils/unittests,
eth/p2p/discoveryv5/enr,
libp2p/crypto/crypto
import std/options, testutils/unittests, eth/p2p/discoveryv5/enr, libp2p/crypto/crypto
import
../../waku/common/databases/db_sqlite,
../../waku/node/peer_manager/peer_manager,
@ -12,9 +8,7 @@ import
../../waku/waku_enr,
./testlib/wakucore
suite "Peer Storage":
test "Store, replace and retrieve from persistent peer storage":
let
database = SqliteDatabase.new(":memory:").tryGet()
@ -41,9 +35,11 @@ suite "Peer Storage":
protocols: @[peerProto],
publicKey: peerKey.getPublicKey().tryGet(),
connectedness: connectedness,
disconnectTime: disconn)
disconnectTime: disconn,
)
defer: storage.close()
defer:
storage.close()
# Test insert and retrieve
@ -71,7 +67,8 @@ suite "Peer Storage":
resStoredInfo.disconnectTime == disconn
assert resStoredInfo.enr.isSome(), "The ENR info wasn't properly stored"
check: resStoredInfo.enr.get() == record
check:
resStoredInfo.enr.get() == record
# Test replace and retrieve (update an existing entry)
stored.connectedness = CannotConnect

View File

@ -14,7 +14,6 @@ import
../../waku/waku_node,
./testlib/wakucore
suite "Extended nim-libp2p Peer Store":
# Valid peerId missing the last digit. Useful for creating new peerIds
# basePeerId & "1"
@ -64,7 +63,8 @@ suite "Extended nim-libp2p Peer Store":
# Peer3: Connected
peerStore[AddressBook][p3] = @[MultiAddress.init("/ip4/127.0.0.1/tcp/3").tryGet()]
peerStore[ProtoBook][p3] = @["/vac/waku/lightpush/2.0.0", "/vac/waku/store/2.0.0-beta1"]
peerStore[ProtoBook][p3] =
@["/vac/waku/lightpush/2.0.0", "/vac/waku/store/2.0.0-beta1"]
peerStore[KeyBook][p3] = generateEcdsaKeyPair().pubkey
peerStore[AgentBook][p3] = "gowaku"
peerStore[ProtoVersionBook][p3] = "protoVersion3"
@ -180,7 +180,8 @@ suite "Extended nim-libp2p Peer Store":
# Only p3 supports that protocol
lpPeers.len == 1
lpPeers.anyIt(it.peerId == p3)
lpPeers[0].protocols == @["/vac/waku/lightpush/2.0.0", "/vac/waku/store/2.0.0-beta1"]
lpPeers[0].protocols ==
@["/vac/waku/lightpush/2.0.0", "/vac/waku/store/2.0.0-beta1"]
test "peers() returns all StoredInfo matching a given protocolMatcher":
# When
@ -197,15 +198,20 @@ suite "Extended nim-libp2p Peer Store":
pMatcherStorePeers.anyIt(it.peerId == p5)
check:
pMatcherStorePeers.filterIt(it.peerId == p1)[0].protocols == @["/vac/waku/relay/2.0.0-beta1", "/vac/waku/store/2.0.0"]
pMatcherStorePeers.filterIt(it.peerId == p2)[0].protocols == @["/vac/waku/relay/2.0.0", "/vac/waku/store/2.0.0"]
pMatcherStorePeers.filterIt(it.peerId == p3)[0].protocols == @["/vac/waku/lightpush/2.0.0", "/vac/waku/store/2.0.0-beta1"]
pMatcherStorePeers.filterIt(it.peerId == p5)[0].protocols == @["/vac/waku/swap/2.0.0", "/vac/waku/store/2.0.0-beta2"]
pMatcherStorePeers.filterIt(it.peerId == p1)[0].protocols ==
@["/vac/waku/relay/2.0.0-beta1", "/vac/waku/store/2.0.0"]
pMatcherStorePeers.filterIt(it.peerId == p2)[0].protocols ==
@["/vac/waku/relay/2.0.0", "/vac/waku/store/2.0.0"]
pMatcherStorePeers.filterIt(it.peerId == p3)[0].protocols ==
@["/vac/waku/lightpush/2.0.0", "/vac/waku/store/2.0.0-beta1"]
pMatcherStorePeers.filterIt(it.peerId == p5)[0].protocols ==
@["/vac/waku/swap/2.0.0", "/vac/waku/store/2.0.0-beta2"]
check:
pMatcherSwapPeers.len == 1
pMatcherSwapPeers.anyIt(it.peerId == p5)
pMatcherSwapPeers[0].protocols == @["/vac/waku/swap/2.0.0", "/vac/waku/store/2.0.0-beta2"]
pMatcherSwapPeers[0].protocols ==
@["/vac/waku/swap/2.0.0", "/vac/waku/store/2.0.0-beta2"]
test "toRemotePeerInfo() converts a StoredInfo to a RemotePeerInfo":
# Given

View File

@ -11,10 +11,7 @@ import
libp2p/protocols/pubsub/gossipsub
import
../../waku/waku_core,
../../waku/waku_node,
./testlib/wakucore,
./testlib/wakunode
../../waku/waku_core, ../../waku/waku_node, ./testlib/wakucore, ./testlib/wakunode
procSuite "Relay (GossipSub) Peer Exchange":
asyncTest "Mount relay without peer exchange handler":

View File

@ -1,7 +1,6 @@
{.used.}
import
testutils/unittests
import testutils/unittests
import
stew/results,
../../waku/waku_core/message,
@ -9,7 +8,6 @@ import
./testlib/common
suite "Waku Payload":
test "Encode/Decode waku message with timestamp":
## Test encoding and decoding of the timestamp field of a WakuMessage

View File

@ -42,9 +42,12 @@ suite "Waku DNS Discovery":
await allFutures([node1.start(), node2.start(), node3.start()])
# Build and sign tree
var tree = buildTree(1, # Seq no
var tree = buildTree(
1, # Seq no
@[enr1, enr2, enr3], # ENR entries
@[]).get() # No link entries
@[],
)
.get() # No link entries
let treeKeys = keys.KeyPair.random(rng[])
@ -57,7 +60,8 @@ suite "Waku DNS Discovery":
domain = "testnodes.aq"
zoneTxts = tree.buildTXT(domain).get()
username = Base32.encode(treeKeys.pubkey().toRawCompressed())
location = LinkPrefix & username & "@" & domain # See EIP-1459: https://eips.ethereum.org/EIPS/eip-1459
location = LinkPrefix & username & "@" & domain
# See EIP-1459: https://eips.ethereum.org/EIPS/eip-1459
# Create a resolver for the domain
@ -90,11 +94,20 @@ suite "Waku DNS Discovery":
check:
# We have successfully connected to all discovered nodes
node4.peerManager.peerStore.peers().anyIt(it.peerId == node1.switch.peerInfo.peerId)
node4.peerManager.peerStore.connectedness(node1.switch.peerInfo.peerId) == Connected
node4.peerManager.peerStore.peers().anyIt(it.peerId == node2.switch.peerInfo.peerId)
node4.peerManager.peerStore.connectedness(node2.switch.peerInfo.peerId) == Connected
node4.peerManager.peerStore.peers().anyIt(it.peerId == node3.switch.peerInfo.peerId)
node4.peerManager.peerStore.connectedness(node3.switch.peerInfo.peerId) == Connected
node4.peerManager.peerStore.peers().anyIt(
it.peerId == node1.switch.peerInfo.peerId
)
node4.peerManager.peerStore.connectedness(node1.switch.peerInfo.peerId) ==
Connected
node4.peerManager.peerStore.peers().anyIt(
it.peerId == node2.switch.peerInfo.peerId
)
node4.peerManager.peerStore.connectedness(node2.switch.peerInfo.peerId) ==
Connected
node4.peerManager.peerStore.peers().anyIt(
it.peerId == node3.switch.peerInfo.peerId
)
node4.peerManager.peerStore.connectedness(node3.switch.peerInfo.peerId) ==
Connected
await allFutures([node1.stop(), node2.stop(), node3.stop(), node4.stop()])

View File

@ -1,14 +1,7 @@
{.used.}
import
std/[options, sequtils],
stew/results,
testutils/unittests
import
../../waku/waku_core,
../../waku/waku_enr,
./testlib/wakucore
import std/[options, sequtils], stew/results, testutils/unittests
import ../../waku/waku_core, ../../waku/waku_enr, ./testlib/wakucore
suite "Waku ENR - Capabilities bitfield":
test "check capabilities support":
@ -25,10 +18,7 @@ suite "Waku ENR - Capabilities bitfield":
test "bitfield to capabilities list":
## Given
let bitfield = CapabilitiesBitfield.init(
relay = true,
store = false,
lightpush = true,
filter = true
relay = true, store = false, lightpush = true, filter = true
)
## When
@ -83,7 +73,8 @@ suite "Waku ENR - Capabilities bitfield":
test "check capabilities on a waku node record":
## Given
let wakuRecord = "-Hy4QC73_E3B_FkZhsOakaD4pHe-U--UoGASdG9N0F3SFFUDY_jdQbud8" &
let wakuRecord =
"-Hy4QC73_E3B_FkZhsOakaD4pHe-U--UoGASdG9N0F3SFFUDY_jdQbud8" &
"EXVyrlOZ5pZ7VYFBDPMRCENwy87Lh74dFIBgmlkgnY0iXNlY3AyNTZrMaECvNt1jIWbWGp" &
"AWWdlLGYm1E1OjlkQk3ONoxDC5sfw8oOFd2FrdTID"
@ -109,7 +100,8 @@ suite "Waku ENR - Capabilities bitfield":
test "check capabilities on a non-waku node record":
## Given
# non waku enr, i.e. Ethereum one
let nonWakuEnr = "enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2G" &
let nonWakuEnr =
"enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2G" &
"xb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNl" &
"Y3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA"
@ -131,12 +123,11 @@ suite "Waku ENR - Capabilities bitfield":
record.supportsCapability(Capabilities.Filter) == false
record.supportsCapability(Capabilities.Lightpush) == false
suite "Waku ENR - Multiaddresses":
test "decode record with multiaddrs field":
## Given
let enrUri = "enr:-QEnuEBEAyErHEfhiQxAVQoWowGTCuEF9fKZtXSd7H_PymHFhGJA3rGAYDVSH" &
let enrUri =
"enr:-QEnuEBEAyErHEfhiQxAVQoWowGTCuEF9fKZtXSd7H_PymHFhGJA3rGAYDVSH" &
"KCyJDGRLBGsloNbS8AZF33IVuefjOO6BIJpZIJ2NIJpcIQS39tkim11bHRpYWRkcn" &
"O4lgAvNihub2RlLTAxLmRvLWFtczMud2FrdXYyLnRlc3Quc3RhdHVzaW0ubmV0BgG" &
"73gMAODcxbm9kZS0wMS5hYy1jbi1ob25na29uZy1jLndha3V2Mi50ZXN0LnN0YXR1" &
@ -148,9 +139,17 @@ suite "Waku ENR - Multiaddresses":
require record.fromURI(enrUri)
let
expectedAddr1 = MultiAddress.init("/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss").get()
expectedAddr2 = MultiAddress.init("/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss").get()
expectedAddr3 = MultiAddress.init("/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss").get()
expectedAddr1 = MultiAddress
.init("/dns4/node-01.do-ams3.wakuv2.test.statusim.net/tcp/443/wss")
.get()
expectedAddr2 = MultiAddress
.init("/dns6/node-01.ac-cn-hongkong-c.wakuv2.test.statusim.net/tcp/443/wss")
.get()
expectedAddr3 = MultiAddress
.init(
"/onion3/vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd:1234/wss"
)
.get()
## When
let typedRecord = record.toTyped()
@ -225,7 +224,11 @@ suite "Waku ENR - Multiaddresses":
enrPrivKey = generatesecp256k1key()
let
addr1 = MultiAddress.init("/ip4/127.0.0.1/tcp/80/ws/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr31iDQpSN5Qa882BCjjwgrD").get()
addr1 = MultiAddress
.init(
"/ip4/127.0.0.1/tcp/80/ws/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr31iDQpSN5Qa882BCjjwgrD"
)
.get()
addr2 = MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss").get()
let expectedAddr1 = MultiAddress.init("/ip4/127.0.0.1/tcp/80/ws").get()
@ -252,9 +255,7 @@ suite "Waku ENR - Multiaddresses":
multiaddrs.contains(expectedAddr1)
multiaddrs.contains(addr2)
suite "Waku ENR - Relay static sharding":
test "new relay shards object with single invalid shard id":
## Given
let
@ -374,7 +375,8 @@ suite "Waku ENR - Relay static sharding":
enrSeqNum = 1u64
enrPrivKey = generatesecp256k1key()
let shardsTopics = RelayShards.init(33, toSeq(0u16 ..< 64u16)).expect("Valid Shards")
let shardsTopics =
RelayShards.init(33, toSeq(0u16 ..< 64u16)).expect("Valid Shards")
var builder = EnrBuilder.init(enrPrivKey, seqNum = enrSeqNum)
require builder.withWakuRelaySharding(shardsTopics).isOk()
@ -402,9 +404,12 @@ suite "Waku ENR - Relay static sharding":
enrPrivKey = generatesecp256k1key()
let
relayShardsIndicesList = RelayShards.init(22, @[1u16, 1u16, 2u16, 3u16, 5u16, 8u16]).expect("Valid Shards")
relayShardsBitVector = RelayShards.init(33, @[13u16, 24u16, 37u16, 61u16, 98u16, 159u16]).expect("Valid Shards")
relayShardsIndicesList = RelayShards
.init(22, @[1u16, 1u16, 2u16, 3u16, 5u16, 8u16])
.expect("Valid Shards")
relayShardsBitVector = RelayShards
.init(33, @[13u16, 24u16, 37u16, 61u16, 98u16, 159u16])
.expect("Valid Shards")
var builder = EnrBuilder.init(enrPrivKey, seqNum = enrSeqNum)
require builder.withWakuRelayShardingIndicesList(relayShardsIndicesList).isOk()

View File

@ -1,11 +1,7 @@
{.used.}
import
std/[options, tables],
testutils/unittests,
chronicles,
chronos,
libp2p/crypto/crypto
std/[options, tables], testutils/unittests, chronicles, chronos, libp2p/crypto/crypto
import
../../waku/node/peer_manager,
../../waku/waku_core,
@ -14,8 +10,9 @@ import
./testlib/common,
./testlib/wakucore
proc newTestWakuFilterNode(switch: Switch, timeout: Duration = 2.hours): Future[WakuFilterLegacy] {.async.} =
proc newTestWakuFilterNode(
switch: Switch, timeout: Duration = 2.hours
): Future[WakuFilterLegacy] {.async.} =
let
peerManager = PeerManager.new(switch)
proto = WakuFilterLegacy.new(peerManager, rng, timeout)
@ -35,7 +32,6 @@ proc newTestWakuFilterClient(switch: Switch): Future[WakuFilterClientLegacy] {.a
return proto
# TODO: Extend test coverage
suite "Waku Filter":
asyncTest "should forward messages to client after subscribed":
@ -54,7 +50,9 @@ suite "Waku Filter":
let serverAddr = serverSwitch.peerInfo.toRemotePeerInfo()
let pushHandlerFuture = newFuture[(string, WakuMessage)]()
proc pushHandler(pubsubTopic: PubsubTopic, message: WakuMessage) {.async, gcsafe, closure.} =
proc pushHandler(
pubsubTopic: PubsubTopic, message: WakuMessage
) {.async, gcsafe, closure.} =
pushHandlerFuture.complete((pubsubTopic, message))
let
@ -63,7 +61,9 @@ suite "Waku Filter":
msg = fakeWakuMessage(contentTopic = contentTopic)
## When
require (await client.subscribe(pubsubTopic, contentTopic, pushHandler, peer=serverAddr)).isOk()
require (
await client.subscribe(pubsubTopic, contentTopic, pushHandler, peer = serverAddr)
).isOk()
# WARN: Sleep necessary to avoid a race condition between the subscription and the handle message proc
await sleepAsync(500.milliseconds)
@ -97,7 +97,9 @@ suite "Waku Filter":
let serverAddr = serverSwitch.peerInfo.toRemotePeerInfo()
var pushHandlerFuture = newFuture[void]()
proc pushHandler(pubsubTopic: PubsubTopic, message: WakuMessage) {.async, gcsafe, closure.} =
proc pushHandler(
pubsubTopic: PubsubTopic, message: WakuMessage
) {.async, gcsafe, closure.} =
pushHandlerFuture.complete()
let
@ -106,7 +108,9 @@ suite "Waku Filter":
msg = fakeWakuMessage(contentTopic = contentTopic)
## When
require (await client.subscribe(pubsubTopic, contentTopic, pushHandler, peer=serverAddr)).isOk()
require (
await client.subscribe(pubsubTopic, contentTopic, pushHandler, peer = serverAddr)
).isOk()
# WARN: Sleep necessary to avoid a race condition between the subscription and the handle message proc
await sleepAsync(500.milliseconds)
@ -126,7 +130,8 @@ suite "Waku Filter":
await server.handleMessage(pubsubTopic, msg)
## Then
let handlerWasCalledAfterUnsubscription = await pushHandlerFuture.withTimeout(1.seconds)
let handlerWasCalledAfterUnsubscription =
await pushHandlerFuture.withTimeout(1.seconds)
check:
not handlerWasCalledAfterUnsubscription
@ -149,7 +154,9 @@ suite "Waku Filter":
let serverAddr = serverSwitch.peerInfo.toRemotePeerInfo()
var pushHandlerFuture = newFuture[void]()
proc pushHandler(pubsubTopic: PubsubTopic, message: WakuMessage) {.async, gcsafe, closure.} =
proc pushHandler(
pubsubTopic: PubsubTopic, message: WakuMessage
) {.async, gcsafe, closure.} =
pushHandlerFuture.complete()
let
@ -158,7 +165,9 @@ suite "Waku Filter":
msg = fakeWakuMessage(contentTopic = contentTopic)
## When
require (await client.subscribe(pubsubTopic, contentTopic, pushHandler, peer=serverAddr)).isOk()
require (
await client.subscribe(pubsubTopic, contentTopic, pushHandler, peer = serverAddr)
).isOk()
# WARN: Sleep necessary to avoid a race condition between the unsubscription and the handle message proc
await sleepAsync(500.milliseconds)
@ -214,7 +223,9 @@ suite "Waku Filter":
let serverAddr = serverSwitch.peerInfo.toRemotePeerInfo()
var pushHandlerFuture = newFuture[void]()
proc pushHandler(pubsubTopic: PubsubTopic, message: WakuMessage) {.async, gcsafe, closure.} =
proc pushHandler(
pubsubTopic: PubsubTopic, message: WakuMessage
) {.async, gcsafe, closure.} =
pushHandlerFuture.complete()
let
@ -223,7 +234,9 @@ suite "Waku Filter":
msg = fakeWakuMessage(contentTopic = contentTopic)
## When
require (await client.subscribe(pubsubTopic, contentTopic, pushHandler, peer=serverAddr)).isOk()
require (
await client.subscribe(pubsubTopic, contentTopic, pushHandler, peer = serverAddr)
).isOk()
# WARN: Sleep necessary to avoid a race condition between the unsubscription and the handle message proc
await sleepAsync(500.milliseconds)
@ -255,8 +268,7 @@ suite "Waku Filter":
# Start switch with same key as before
let clientSwitch2 = newTestSwitch(
some(clientSwitch.peerInfo.privateKey),
some(clientSwitch.peerInfo.addrs[0])
some(clientSwitch.peerInfo.privateKey), some(clientSwitch.peerInfo.addrs[0])
)
await clientSwitch2.start()
await client.start()

View File

@ -12,14 +12,9 @@ import
libp2p/stream/connection,
libp2p/crypto/crypto
import
../../waku/waku_core,
../../waku/waku_node,
./testlib/wakucore,
./testlib/wakunode
../../waku/waku_core, ../../waku/waku_node, ./testlib/wakucore, ./testlib/wakunode
suite "Waku Keepalive":
asyncTest "handle ping keepalives":
let
nodeKey1 = generateSecp256k1Key()

View File

@ -1,38 +1,30 @@
{.used.}
import
std/[os, json],
chronos,
testutils/unittests
import
../../waku/waku_keystore,
./testlib/common
import std/[os, json], chronos, testutils/unittests
import ../../waku/waku_keystore, ./testlib/common
from ../../waku/waku_noise/noise_utils import randomSeqByte
procSuite "Credentials test suite":
let testAppInfo = AppInfo(application: "test", appIdentifier: "1234", version: "0.1")
test "Create keystore":
let filepath = "./testAppKeystore.txt"
defer: removeFile(filepath)
defer:
removeFile(filepath)
let keystoreRes = createAppKeystore(path = filepath,
appInfo = testAppInfo)
let keystoreRes = createAppKeystore(path = filepath, appInfo = testAppInfo)
check:
keystoreRes.isOk()
test "Load keystore":
let filepath = "./testAppKeystore.txt"
defer: removeFile(filepath)
defer:
removeFile(filepath)
# If no keystore exists at filepath, a new one is created for appInfo and empty credentials
let keystoreRes = loadAppKeystore(path = filepath,
appInfo = testAppInfo)
let keystoreRes = loadAppKeystore(path = filepath, appInfo = testAppInfo)
check:
keystoreRes.isOk()
@ -48,9 +40,9 @@ procSuite "Credentials test suite":
keystore["credentials"].len() == 0
test "Add credentials to keystore":
let filepath = "./testAppKeystore.txt"
defer: removeFile(filepath)
defer:
removeFile(filepath)
# We generate a random identity credential (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
var
@ -59,28 +51,37 @@ procSuite "Credentials test suite":
idSecretHash = randomSeqByte(rng[], 32)
idCommitment = randomSeqByte(rng[], 32)
var idCredential = IdentityCredential(idTrapdoor: idTrapdoor, idNullifier: idNullifier, idSecretHash: idSecretHash, idCommitment: idCommitment)
var idCredential = IdentityCredential(
idTrapdoor: idTrapdoor,
idNullifier: idNullifier,
idSecretHash: idSecretHash,
idCommitment: idCommitment,
)
var contract = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
var contract = MembershipContract(
chainId: "5", address: "0x0123456789012345678901234567890123456789"
)
var index = MembershipIndex(1)
let membershipCredential = KeystoreMembership(membershipContract: contract,
treeIndex: index,
identityCredential: idCredential)
let membershipCredential = KeystoreMembership(
membershipContract: contract, treeIndex: index, identityCredential: idCredential
)
let password = "%m0um0ucoW%"
let keystoreRes = addMembershipCredentials(path = filepath,
let keystoreRes = addMembershipCredentials(
path = filepath,
membership = membershipCredential,
password = password,
appInfo = testAppInfo)
appInfo = testAppInfo,
)
check:
keystoreRes.isOk()
test "Add/retrieve credentials in keystore":
let filepath = "./testAppKeystore.txt"
defer: removeFile(filepath)
defer:
removeFile(filepath)
# We generate two random identity credentials (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
var
@ -88,45 +89,55 @@ procSuite "Credentials test suite":
idNullifier = randomSeqByte(rng[], 32)
idSecretHash = randomSeqByte(rng[], 32)
idCommitment = randomSeqByte(rng[], 32)
idCredential = IdentityCredential(idTrapdoor: idTrapdoor, idNullifier: idNullifier, idSecretHash: idSecretHash, idCommitment: idCommitment)
idCredential = IdentityCredential(
idTrapdoor: idTrapdoor,
idNullifier: idNullifier,
idSecretHash: idSecretHash,
idCommitment: idCommitment,
)
# We generate two distinct membership groups
var contract = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
var contract = MembershipContract(
chainId: "5", address: "0x0123456789012345678901234567890123456789"
)
var index = MembershipIndex(1)
var membershipCredential = KeystoreMembership(membershipContract: contract,
treeIndex: index,
identityCredential: idCredential)
var membershipCredential = KeystoreMembership(
membershipContract: contract, treeIndex: index, identityCredential: idCredential
)
let password = "%m0um0ucoW%"
# We add credentials to the keystore. Note that only 3 credentials should be effectively added, since rlnMembershipCredentials3 is equal to membershipCredentials2
let keystoreRes = addMembershipCredentials(path = filepath,
let keystoreRes = addMembershipCredentials(
path = filepath,
membership = membershipCredential,
password = password,
appInfo = testAppInfo)
appInfo = testAppInfo,
)
check:
keystoreRes.isOk()
# We test retrieval of credentials.
var expectedMembership = membershipCredential
let membershipQuery = KeystoreMembership(membershipContract: contract,
treeIndex: index)
let membershipQuery =
KeystoreMembership(membershipContract: contract, treeIndex: index)
var recoveredCredentialsRes = getMembershipCredentials(path = filepath,
var recoveredCredentialsRes = getMembershipCredentials(
path = filepath,
password = password,
query = membershipQuery,
appInfo = testAppInfo)
appInfo = testAppInfo,
)
check:
recoveredCredentialsRes.isOk()
recoveredCredentialsRes.get() == expectedMembership
test "if the keystore contains only one credential, fetch that irrespective of treeIndex":
let filepath = "./testAppKeystore.txt"
defer: removeFile(filepath)
defer:
removeFile(filepath)
# We generate random identity credentials (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
let
@ -134,20 +145,29 @@ procSuite "Credentials test suite":
idNullifier = randomSeqByte(rng[], 32)
idSecretHash = randomSeqByte(rng[], 32)
idCommitment = randomSeqByte(rng[], 32)
idCredential = IdentityCredential(idTrapdoor: idTrapdoor, idNullifier: idNullifier, idSecretHash: idSecretHash, idCommitment: idCommitment)
idCredential = IdentityCredential(
idTrapdoor: idTrapdoor,
idNullifier: idNullifier,
idSecretHash: idSecretHash,
idCommitment: idCommitment,
)
let contract = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
let contract = MembershipContract(
chainId: "5", address: "0x0123456789012345678901234567890123456789"
)
let index = MembershipIndex(1)
let membershipCredential = KeystoreMembership(membershipContract: contract,
treeIndex: index,
identityCredential: idCredential)
let membershipCredential = KeystoreMembership(
membershipContract: contract, treeIndex: index, identityCredential: idCredential
)
let password = "%m0um0ucoW%"
let keystoreRes = addMembershipCredentials(path = filepath,
let keystoreRes = addMembershipCredentials(
path = filepath,
membership = membershipCredential,
password = password,
appInfo = testAppInfo)
appInfo = testAppInfo,
)
assert(keystoreRes.isOk(), $keystoreRes.error)
@ -155,17 +175,21 @@ procSuite "Credentials test suite":
let expectedMembership = membershipCredential
let membershipQuery = KeystoreMembership(membershipContract: contract)
let recoveredCredentialsRes = getMembershipCredentials(path = filepath,
let recoveredCredentialsRes = getMembershipCredentials(
path = filepath,
password = password,
query = membershipQuery,
appInfo = testAppInfo)
appInfo = testAppInfo,
)
assert(recoveredCredentialsRes.isOk(), $recoveredCredentialsRes.error)
check: recoveredCredentialsRes.get() == expectedMembership
check:
recoveredCredentialsRes.get() == expectedMembership
test "if the keystore contains multiple credentials, then error out if treeIndex has not been passed in":
let filepath = "./testAppKeystore.txt"
defer: removeFile(filepath)
defer:
removeFile(filepath)
# We generate random identity credentials (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
let
@ -173,38 +197,51 @@ procSuite "Credentials test suite":
idNullifier = randomSeqByte(rng[], 32)
idSecretHash = randomSeqByte(rng[], 32)
idCommitment = randomSeqByte(rng[], 32)
idCredential = IdentityCredential(idTrapdoor: idTrapdoor, idNullifier: idNullifier, idSecretHash: idSecretHash, idCommitment: idCommitment)
idCredential = IdentityCredential(
idTrapdoor: idTrapdoor,
idNullifier: idNullifier,
idSecretHash: idSecretHash,
idCommitment: idCommitment,
)
# We generate two distinct membership groups
let contract = MembershipContract(chainId: "5", address: "0x0123456789012345678901234567890123456789")
let contract = MembershipContract(
chainId: "5", address: "0x0123456789012345678901234567890123456789"
)
let index = MembershipIndex(1)
var membershipCredential = KeystoreMembership(membershipContract: contract,
treeIndex: index,
identityCredential: idCredential)
var membershipCredential = KeystoreMembership(
membershipContract: contract, treeIndex: index, identityCredential: idCredential
)
let password = "%m0um0ucoW%"
let keystoreRes = addMembershipCredentials(path = filepath,
let keystoreRes = addMembershipCredentials(
path = filepath,
membership = membershipCredential,
password = password,
appInfo = testAppInfo)
appInfo = testAppInfo,
)
assert(keystoreRes.isOk(), $keystoreRes.error)
membershipCredential.treeIndex = MembershipIndex(2)
let keystoreRes2 = addMembershipCredentials(path = filepath,
let keystoreRes2 = addMembershipCredentials(
path = filepath,
membership = membershipCredential,
password = password,
appInfo = testAppInfo)
appInfo = testAppInfo,
)
assert(keystoreRes2.isOk(), $keystoreRes2.error)
# We test retrieval of credentials.
let membershipQuery = KeystoreMembership(membershipContract: contract)
let recoveredCredentialsRes = getMembershipCredentials(path = filepath,
let recoveredCredentialsRes = getMembershipCredentials(
path = filepath,
password = password,
query = membershipQuery,
appInfo = testAppInfo)
appInfo = testAppInfo,
)
check:
recoveredCredentialsRes.isErr()

View File

@ -1,26 +1,19 @@
{.used.}
import
std/[json, os],
stew/byteutils,
testutils/unittests, chronos,
eth/keys
import
../../waku/waku_keystore,
./testlib/common
import std/[json, os], stew/byteutils, testutils/unittests, chronos, eth/keys
import ../../waku/waku_keystore, ./testlib/common
from ../../waku/waku_noise/noise_utils import randomSeqByte
suite "KeyFile test suite":
test "Create/Save/Load single keyfile":
# The password we use to encrypt our secret
let password = "randompassword"
# The filepath were the keyfile will be stored
let filepath = "./test.keyfile"
defer: removeFile(filepath)
defer:
removeFile(filepath)
# The secret
var secret = randomSeqByte(rng[], 300)
@ -48,7 +41,6 @@ suite "KeyFile test suite":
secret == decodedSecret.get()
test "Create/Save/Load multiple keyfiles in same file":
# We set different passwords for different keyfiles that will be stored in same file
let password1 = string.fromBytes(randomSeqByte(rng[], 20))
let password2 = ""
@ -56,7 +48,8 @@ suite "KeyFile test suite":
var keyfile: KfResult[JsonNode]
let filepath = "./test.keyfile"
defer: removeFile(filepath)
defer:
removeFile(filepath)
# We generate 6 different secrets and we encrypt them using 3 different passwords, and we store the obtained keystore
@ -133,12 +126,10 @@ suite "KeyFile test suite":
secret3 == decodedSecretsPassword3[0].get()
secret4 == decodedSecretsPassword3[1].get()
# The following tests are originally from the nim-eth keyfile tests module https://github.com/status-im/nim-eth/blob/master/tests/keyfile/test_keyfile.nim
# and are slightly adapted to test backwards compatibility with nim-eth implementation of our customized version of the utils/keyfile module
# Note: the original nim-eth "Create/Save/Load test" is redefined and expanded above in "KeyFile test suite"
suite "KeyFile test suite (adapted from nim-eth keyfile tests)":
# Testvectors originally from https://github.com/status-im/nim-eth/blob/fef47331c37ee8abb8608037222658737ff498a6/tests/keyfile/test_keyfile.nim#L22-L168
let TestVectors = [
%*{
@ -146,103 +137,104 @@ suite "KeyFile test suite (adapted from nim-eth keyfile tests)":
"crypto": {
"cipher": "aes-128-ctr",
"cipherparams": {"iv": "6087dab2f9fdbbfaddc31a909735c1e6"},
"ciphertext" : "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46",
"ciphertext":
"5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46",
"kdf": "pbkdf2",
"kdfparams": {
"c": 262144,
"dklen": 32,
"prf": "hmac-sha256",
"salt" : "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd"
"salt": "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd",
},
"mac" : "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2"
"mac": "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e9b2",
},
"id": "3198bc9c-6672-5ab3-d995-4942343ae5b6",
"version" : 3
"version": 3,
},
"name": "test1",
"password": "testpassword",
"priv": "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"
"priv": "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d",
},
%*{
"keyfile": {
"version": 3,
"crypto": {
"ciphertext": "ee75456c006b1e468133c5d2a916bacd3cf515ced4d9b021b5c59978007d1e87",
"ciphertext":
"ee75456c006b1e468133c5d2a916bacd3cf515ced4d9b021b5c59978007d1e87",
"version": 1,
"kdf": "pbkdf2",
"kdfparams": {
"dklen": 32,
"c": 262144,
"prf": "hmac-sha256",
"salt": "504490577620f64f43d73f29479c2cf0"
"salt": "504490577620f64f43d73f29479c2cf0",
},
"mac": "196815708465de9af7504144a1360d08874fc3c30bb0e648ce88fbc36830d35d",
"cipherparams": {"iv": "514ccc8c4fb3e60e5538e0cf1e27c233"},
"cipher": "aes-128-ctr"
"cipher": "aes-128-ctr",
},
"id": "98d193c7-5174-4c7c-5345-c1daf95477b5"
"id": "98d193c7-5174-4c7c-5345-c1daf95477b5",
},
"name": "python_generated_test_with_odd_iv",
"password": "foo",
"priv": "0101010101010101010101010101010101010101010101010101010101010101"
"priv": "0101010101010101010101010101010101010101010101010101010101010101",
},
%*{
"keyfile": {
"version": 3,
"crypto": {
"ciphertext": "d69313b6470ac1942f75d72ebf8818a0d484ac78478a132ee081cd954d6bd7a9",
"ciphertext":
"d69313b6470ac1942f75d72ebf8818a0d484ac78478a132ee081cd954d6bd7a9",
"cipherparams": {"iv": "ffffffffffffffffffffffffffffffff"},
"kdf": "pbkdf2",
"kdfparams": {
"dklen": 32,
"c": 262144,
"prf": "hmac-sha256",
"salt": "c82ef14476014cbf438081a42709e2ed"
"salt": "c82ef14476014cbf438081a42709e2ed",
},
"mac": "cf6bfbcc77142a22c4a908784b4a16f1023a1d0e2aff404c20158fa4f1587177",
"cipher": "aes-128-ctr",
"version": 1
"version": 1,
},
"id": "abb67040-8dbe-0dad-fc39-2b082ef0ee5f"
"id": "abb67040-8dbe-0dad-fc39-2b082ef0ee5f",
},
"name": "evilnonce",
"password": "bar",
"priv": "0202020202020202020202020202020202020202020202020202020202020202"
"priv": "0202020202020202020202020202020202020202020202020202020202020202",
},
%*{
"keyfile": {
"version": 3,
"crypto": {
"cipher": "aes-128-ctr",
"cipherparams" : {
"iv" : "83dbcc02d8ccb40e466191a123791e0e"
},
"ciphertext" : "d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c",
"cipherparams": {"iv": "83dbcc02d8ccb40e466191a123791e0e"},
"ciphertext":
"d172bf743a674da9cdad04534d56926ef8358534d458fffccd4e6ad2fbde479c",
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"r": 1,
"p": 8,
"salt" : "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19"
"salt": "ab0c7876052600dd703518d6fc3fe8984592145b591fc8fb5c6d43190334ba19",
},
"mac" : "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097"
"mac": "2103ac29920d71da29f15d75b4a16dbe95cfd7ff8faea1056c33131d846e3097",
},
"id" : "3198bc9c-6672-5ab3-d995-4942343ae5b6"
"id": "3198bc9c-6672-5ab3-d995-4942343ae5b6",
},
"name": "test2",
"password": "testpassword",
"priv": "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"
"priv": "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d",
},
%*{
"keyfile": {
"version": 3,
"address": "460121576cc7df020759730751f92bd62fd78dd6",
"crypto": {
"ciphertext": "54ae683c6287fa3d58321f09d56e26d94e58a00d4f90bdd95782ae0e4aab618b",
"cipherparams": {
"iv": "681679cdb125bba9495d068b002816a4"
},
"ciphertext":
"54ae683c6287fa3d58321f09d56e26d94e58a00d4f90bdd95782ae0e4aab618b",
"cipherparams": {"iv": "681679cdb125bba9495d068b002816a4"},
"cipher": "aes-128-ctr",
"kdf": "scrypt",
"kdfparams": {
@ -250,24 +242,23 @@ suite "KeyFile test suite (adapted from nim-eth keyfile tests)":
"salt": "c3407f363fce02a66e3c4bf4a8f6b7da1c1f54266cef66381f0625c251c32785",
"n": 8192,
"r": 8,
"p": 1
"p": 1,
},
"mac": "dea6bdf22a2f522166ed82808c22a6311e84c355f4bbe100d4260483ff675a46"
"mac": "dea6bdf22a2f522166ed82808c22a6311e84c355f4bbe100d4260483ff675a46",
},
"id": "0eb785e0-340a-4290-9c42-90a11973ee47"
"id": "0eb785e0-340a-4290-9c42-90a11973ee47",
},
"name": "mycrypto",
"password": "foobartest121",
"priv": "05a4d3eb46c742cb8850440145ce70cbc80b59f891cf5f50fd3e9c280b50c4e4"
"priv": "05a4d3eb46c742cb8850440145ce70cbc80b59f891cf5f50fd3e9c280b50c4e4",
},
%*{
"keyfile": {
"crypto": {
"cipher": "aes-128-ctr",
"cipherparams": {
"iv": "7e7b02d2b4ef45d6c98cb885e75f48d5",
},
"ciphertext": "a7a5743a6c7eb3fa52396bd3fd94043b79075aac3ccbae8e62d3af94db00397c",
"cipherparams": {"iv": "7e7b02d2b4ef45d6c98cb885e75f48d5"},
"ciphertext":
"a7a5743a6c7eb3fa52396bd3fd94043b79075aac3ccbae8e62d3af94db00397c",
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
@ -280,71 +271,73 @@ suite "KeyFile test suite (adapted from nim-eth keyfile tests)":
},
"address": "0b6f2de3dee015a95d3330dcb7baf8e08aa0112d",
"id": "3c8efdd6-d538-47ec-b241-36783d3418b9",
"version": 3
"version": 3,
},
"password": "moomoocow",
"priv": "21eac69b9a52f466bfe9047f0f21c9caf3a5cdaadf84e2750a9b3265d450d481",
"name": "eth-keyfile-conftest"
}
"name": "eth-keyfile-conftest",
},
]
test "Testing nim-eth test vectors":
var secret: KfResult[seq[byte]]
var expectedSecret: seq[byte]
for i in 0 ..< TestVectors.len:
# Decryption with correct password
expectedSecret = decodeHex(TestVectors[i].getOrDefault("priv").getStr())
secret =
decodeKeyFileJson(TestVectors[i].getOrDefault("keyfile"),
TestVectors[i].getOrDefault("password").getStr())
secret = decodeKeyFileJson(
TestVectors[i].getOrDefault("keyfile"),
TestVectors[i].getOrDefault("password").getStr(),
)
check:
secret.isOk()
secret.get() == expectedSecret
# Decryption with wrong password
secret = decodeKeyFileJson(TestVectors[i].getOrDefault("keyfile"), "wrongpassword")
secret =
decodeKeyFileJson(TestVectors[i].getOrDefault("keyfile"), "wrongpassword")
check:
secret.isErr()
secret.error == KeyFileError.KeyfileIncorrectMac
test "Wrong mac in keyfile":
# This keyfile is the same as the first one in TestVectors,
# but the last byte of mac is changed to 00.
# While ciphertext is the correct encryption of priv under password,
# mac verfication should fail and nothing will be decrypted
let keyfileWrongMac = %*{
let keyfileWrongMac =
%*{
"keyfile": {
"crypto": {
"cipher": "aes-128-ctr",
"cipherparams": {"iv": "6087dab2f9fdbbfaddc31a909735c1e6"},
"ciphertext" : "5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46",
"ciphertext":
"5318b4d5bcd28de64ee5559e671353e16f075ecae9f99c7a79a38af5f869aa46",
"kdf": "pbkdf2",
"kdfparams": {
"c": 262144,
"dklen": 32,
"prf": "hmac-sha256",
"salt" : "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd"
"salt": "ae3cd4e7013836a3df6bd7241b12db061dbe2c6785853cce422d148a624ce0bd",
},
"mac" : "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e900"
"mac": "517ead924a9d0dc3124507e3393d175ce3ff7c1e96529c6c555ce9e51205e900",
},
"id": "3198bc9c-6672-5ab3-d995-4942343ae5b6",
"version" : 3
"version": 3,
},
"name": "test1",
"password": "testpassword",
"priv": "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d"
"priv": "7a28b5ba57c53603b0b07b56bba752f7784bf506fa95edc395f5cf6c7514fe9d",
}
# Decryption with correct password
let expectedSecret = decodeHex(keyfileWrongMac.getOrDefault("priv").getStr())
let secret =
decodeKeyFileJson(keyfileWrongMac.getOrDefault("keyfile"),
keyfileWrongMac.getOrDefault("password").getStr())
let secret = decodeKeyFileJson(
keyfileWrongMac.getOrDefault("keyfile"),
keyfileWrongMac.getOrDefault("password").getStr(),
)
check:
secret.isErr()
secret.error == KeyFileError.KeyFileIncorrectMac
@ -368,7 +361,6 @@ suite "KeyFile test suite (adapted from nim-eth keyfile tests)":
secret.get() == expectedSecret
test "Load non-existent keyfile test":
check:
loadKeyFiles("nonexistant.keyfile", "password").error ==
KeyFileError.KeyfileDoesNotExist

View File

@ -22,13 +22,22 @@ import
./testlib/wakucore,
./testlib/wakunode
procSuite "Waku Metadata Protocol":
asyncTest "request() returns the supported metadata of the peer":
let clusterId = 10.uint32
let
node1 = newTestWakuNode(generateSecp256k1Key(), parseIpAddress("0.0.0.0"), Port(0), clusterId = clusterId)
node2 = newTestWakuNode(generateSecp256k1Key(), parseIpAddress("0.0.0.0"), Port(0), clusterId = clusterId)
node1 = newTestWakuNode(
generateSecp256k1Key(),
parseIpAddress("0.0.0.0"),
Port(0),
clusterId = clusterId,
)
node2 = newTestWakuNode(
generateSecp256k1Key(),
parseIpAddress("0.0.0.0"),
Port(0),
clusterId = clusterId,
)
# Start nodes
await allFutures([node1.start(), node2.start()])
@ -37,7 +46,9 @@ procSuite "Waku Metadata Protocol":
node1.topicSubscriptionQueue.emit((kind: PubsubSub, topic: "/waku/2/rs/10/6"))
# Create connection
let connOpt = await node2.peerManager.dialPeer(node1.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec)
let connOpt = await node2.peerManager.dialPeer(
node1.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec
)
require:
connOpt.isSome
@ -51,4 +62,3 @@ procSuite "Waku Metadata Protocol":
check:
response1.get().clusterId.get() == clusterId
response1.get().shards == @[uint32(6), uint32(7)]

View File

@ -1,30 +1,18 @@
{.used.}
import
chronos,
confutils/toml/std/net,
libp2p/multiaddress,
testutils/unittests
import chronos, confutils/toml/std/net, libp2p/multiaddress, testutils/unittests
import
./testlib/wakunode,
../../waku/waku_enr/capabilities
import ./testlib/wakunode, ../../waku/waku_enr/capabilities
include
../../waku/node/config
include ../../waku/node/config
proc defaultTestWakuFlags(): CapabilitiesBitfield =
CapabilitiesBitfield.init(
lightpush = false,
filter = false,
store = false,
relay = true
lightpush = false, filter = false, store = false, relay = true
)
suite "Waku NetConfig":
asyncTest "Create NetConfig with default values":
let conf = defaultTestWakuNodeConf()
let wakuFlags = defaultTestWakuFlags()
@ -40,20 +28,17 @@ suite "Waku NetConfig":
wssEnabled = conf.websocketSecureSupport,
dns4DomainName = none(string),
discv5UdpPort = none(Port),
wakuFlags = some(wakuFlags)
wakuFlags = some(wakuFlags),
)
check:
netConfigRes.isOk()
asyncTest "AnnouncedAddresses contains only bind address when no external addresses are provided":
let conf = defaultTestWakuNodeConf()
let netConfigRes = NetConfig.init(
bindIp = conf.listenAddress,
bindPort = conf.tcpPort
)
let netConfigRes =
NetConfig.init(bindIp = conf.listenAddress, bindPort = conf.tcpPort)
assert netConfigRes.isOk(), $netConfigRes.error
@ -61,11 +46,10 @@ suite "Waku NetConfig":
check:
netConfig.announcedAddresses.len == 1 # Only bind address should be present
netConfig.announcedAddresses[0] == formatListenAddress(ip4TcpEndPoint(conf.listenAddress, conf.tcpPort))
netConfig.announcedAddresses[0] ==
formatListenAddress(ip4TcpEndPoint(conf.listenAddress, conf.tcpPort))
asyncTest "AnnouncedAddresses contains external address if extIp/Port are provided":
let
conf = defaultTestWakuNodeConf()
extIp = parseIpAddress("1.2.3.4")
@ -75,7 +59,7 @@ suite "Waku NetConfig":
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
extIp = some(extIp),
extPort = some(extPort)
extPort = some(extPort),
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -87,7 +71,6 @@ suite "Waku NetConfig":
netConfig.announcedAddresses[0] == ip4TcpEndPoint(extIp, extPort)
asyncTest "AnnouncedAddresses contains dns4DomainName if provided":
let
conf = defaultTestWakuNodeConf()
dns4DomainName = "example.com"
@ -97,7 +80,7 @@ suite "Waku NetConfig":
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
dns4DomainName = some(dns4DomainName),
extPort = some(extPort)
extPort = some(extPort),
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -109,7 +92,6 @@ suite "Waku NetConfig":
netConfig.announcedAddresses[0] == dns4TcpEndPoint(dns4DomainName, extPort)
asyncTest "AnnouncedAddresses includes extMultiAddrs when provided":
let
conf = defaultTestWakuNodeConf()
extIp = parseIpAddress("1.2.3.4")
@ -119,7 +101,7 @@ suite "Waku NetConfig":
let netConfigRes = NetConfig.init(
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
extMultiAddrs = extMultiAddrs
extMultiAddrs = extMultiAddrs,
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -130,9 +112,7 @@ suite "Waku NetConfig":
netConfig.announcedAddresses.len == 2 # Bind address + extAddress
netConfig.announcedAddresses[1] == extMultiAddrs[0]
asyncTest "AnnouncedAddresses uses dns4DomainName over extIp when both are provided":
let
conf = defaultTestWakuNodeConf()
dns4DomainName = "example.com"
@ -144,7 +124,7 @@ suite "Waku NetConfig":
bindPort = conf.tcpPort,
dns4DomainName = some(dns4DomainName),
extIp = some(extIp),
extPort = some(extPort)
extPort = some(extPort),
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -156,7 +136,6 @@ suite "Waku NetConfig":
netConfig.announcedAddresses[0] == dns4TcpEndPoint(dns4DomainName, extPort)
asyncTest "AnnouncedAddresses includes WebSocket addresses when enabled":
var
conf = defaultTestWakuNodeConf()
wssEnabled = false
@ -165,7 +144,7 @@ suite "Waku NetConfig":
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
wsEnabled = true,
wssEnabled = wssEnabled
wssEnabled = wssEnabled,
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -174,8 +153,8 @@ suite "Waku NetConfig":
check:
netConfig.announcedAddresses.len == 2 # Bind address + wsHostAddress
netConfig.announcedAddresses[1] == (ip4TcpEndPoint(conf.listenAddress,
conf.websocketPort) & wsFlag(wssEnabled))
netConfig.announcedAddresses[1] ==
(ip4TcpEndPoint(conf.listenAddress, conf.websocketPort) & wsFlag(wssEnabled))
## Now try the same for the case of wssEnabled = true
@ -185,7 +164,7 @@ suite "Waku NetConfig":
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
wsEnabled = true,
wssEnabled = wssEnabled
wssEnabled = wssEnabled,
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -194,11 +173,10 @@ suite "Waku NetConfig":
check:
netConfig.announcedAddresses.len == 2 # Bind address + wsHostAddress
netConfig.announcedAddresses[1] == (ip4TcpEndPoint(conf.listenAddress,
conf.websocketPort) & wsFlag(wssEnabled))
netConfig.announcedAddresses[1] ==
(ip4TcpEndPoint(conf.listenAddress, conf.websocketPort) & wsFlag(wssEnabled))
asyncTest "Announced WebSocket address contains external IP if provided":
let
conf = defaultTestWakuNodeConf()
extIp = parseIpAddress("1.2.3.4")
@ -211,7 +189,7 @@ suite "Waku NetConfig":
extIp = some(extIp),
extPort = some(extPort),
wsEnabled = true,
wssEnabled = wssEnabled
wssEnabled = wssEnabled,
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -220,11 +198,10 @@ suite "Waku NetConfig":
check:
netConfig.announcedAddresses.len == 2 # External address + wsHostAddress
netConfig.announcedAddresses[1] == (ip4TcpEndPoint(extIp,
conf.websocketPort) & wsFlag(wssEnabled))
netConfig.announcedAddresses[1] ==
(ip4TcpEndPoint(extIp, conf.websocketPort) & wsFlag(wssEnabled))
asyncTest "Announced WebSocket address contains dns4DomainName if provided":
let
conf = defaultTestWakuNodeConf()
dns4DomainName = "example.com"
@ -237,7 +214,7 @@ suite "Waku NetConfig":
dns4DomainName = some(dns4DomainName),
extPort = some(extPort),
wsEnabled = true,
wssEnabled = wssEnabled
wssEnabled = wssEnabled,
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -246,11 +223,10 @@ suite "Waku NetConfig":
check:
netConfig.announcedAddresses.len == 2 # Bind address + wsHostAddress
netConfig.announcedAddresses[1] == (dns4TcpEndPoint(dns4DomainName, conf.websocketPort) &
wsFlag(wssEnabled))
netConfig.announcedAddresses[1] ==
(dns4TcpEndPoint(dns4DomainName, conf.websocketPort) & wsFlag(wssEnabled))
asyncTest "Announced WebSocket address contains dns4DomainName if provided alongside extIp":
let
conf = defaultTestWakuNodeConf()
dns4DomainName = "example.com"
@ -265,7 +241,7 @@ suite "Waku NetConfig":
extIp = some(extIp),
extPort = some(extPort),
wsEnabled = true,
wssEnabled = wssEnabled
wssEnabled = wssEnabled,
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -275,17 +251,14 @@ suite "Waku NetConfig":
check:
netConfig.announcedAddresses.len == 2 # DNS address + wsHostAddress
netConfig.announcedAddresses[0] == dns4TcpEndPoint(dns4DomainName, extPort)
netConfig.announcedAddresses[1] == (dns4TcpEndPoint(dns4DomainName, conf.websocketPort) &
wsFlag(wssEnabled))
netConfig.announcedAddresses[1] ==
(dns4TcpEndPoint(dns4DomainName, conf.websocketPort) & wsFlag(wssEnabled))
asyncTest "ENR is set with bindIp/Port if no extIp/Port are provided":
let conf = defaultTestWakuNodeConf()
let netConfigRes = NetConfig.init(
bindIp = conf.listenAddress,
bindPort = conf.tcpPort
)
let netConfigRes =
NetConfig.init(bindIp = conf.listenAddress, bindPort = conf.tcpPort)
assert netConfigRes.isOk(), $netConfigRes.error
@ -296,7 +269,6 @@ suite "Waku NetConfig":
netConfig.enrPort.get() == conf.tcpPort
asyncTest "ENR is set with extIp/Port if provided":
let
conf = defaultTestWakuNodeConf()
extIp = parseIpAddress("1.2.3.4")
@ -306,7 +278,7 @@ suite "Waku NetConfig":
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
extIp = some(extIp),
extPort = some(extPort)
extPort = some(extPort),
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -318,7 +290,6 @@ suite "Waku NetConfig":
netConfig.enrPort.get() == extPort
asyncTest "ENR is set with dns4DomainName if provided":
let
conf = defaultTestWakuNodeConf()
dns4DomainName = "example.com"
@ -328,7 +299,7 @@ suite "Waku NetConfig":
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
dns4DomainName = some(dns4DomainName),
extPort = some(extPort)
extPort = some(extPort),
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -339,7 +310,6 @@ suite "Waku NetConfig":
netConfig.enrMultiaddrs.contains(dns4TcpEndPoint(dns4DomainName, extPort))
asyncTest "wsHostAddress is not announced if a WS/WSS address is provided in extMultiAddrs":
var
conf = defaultTestWakuNodeConf()
extAddIp = parseIpAddress("1.2.3.4")
@ -352,7 +322,7 @@ suite "Waku NetConfig":
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
extMultiAddrs = extMultiAddrs,
wsEnabled = wsEnabled
wsEnabled = wsEnabled,
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -371,7 +341,7 @@ suite "Waku NetConfig":
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
extMultiAddrs = extMultiAddrs,
wssEnabled = wssEnabled
wssEnabled = wssEnabled,
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -383,7 +353,6 @@ suite "Waku NetConfig":
netConfig.announcedAddresses[1] == extMultiAddrs[0]
asyncTest "Only extMultiAddrs are published when enabling extMultiAddrsOnly flag":
let
conf = defaultTestWakuNodeConf()
extAddIp = parseIpAddress("1.2.3.4")
@ -394,7 +363,7 @@ suite "Waku NetConfig":
bindIp = conf.listenAddress,
bindPort = conf.tcpPort,
extMultiAddrs = extMultiAddrs,
extMultiAddrsOnly = true
extMultiAddrsOnly = true,
)
assert netConfigRes.isOk(), $netConfigRes.error
@ -404,4 +373,3 @@ suite "Waku NetConfig":
check:
netConfig.announcedAddresses.len == 1 # ExtAddress
netConfig.announcedAddresses[0] == extMultiAddrs[0]

View File

@ -17,16 +17,13 @@ import
../../waku/waku_core,
./testlib/common
procSuite "Waku Noise":
common.randomize()
test "PKCS#7 Padding/Unpadding":
# We test padding for different message lengths
let maxMessageLength = 3 * NoisePaddingBlockSize
for messageLen in 0 .. maxMessageLength:
let
message = randomSeqByte(rng[], messageLen)
padded = pkcs7_pad(message, NoisePaddingBlockSize)
@ -38,7 +35,6 @@ procSuite "Waku Noise":
message == unpadded
test "ChaChaPoly Encryption/Decryption: random byte sequences":
let cipherState = randomChaChaPolyCipherState(rng[])
# We encrypt/decrypt random byte sequences
@ -51,7 +47,6 @@ procSuite "Waku Noise":
plaintext == decryptedCiphertext
test "ChaChaPoly Encryption/Decryption: random strings":
let cipherState = randomChaChaPolyCipherState(rng[])
# We encrypt/decrypt random strings
@ -67,7 +62,6 @@ procSuite "Waku Noise":
plaintext.toBytes() == decryptedCiphertext
test "Noise public keys: encrypt and decrypt a public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
let
@ -79,7 +73,6 @@ procSuite "Waku Noise":
noisePublicKey == decryptedPk
test "Noise public keys: decrypt an unencrypted public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
let
@ -90,7 +83,6 @@ procSuite "Waku Noise":
noisePublicKey == decryptedPk
test "Noise public keys: encrypt an encrypted public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
let
@ -102,7 +94,6 @@ procSuite "Waku Noise":
encryptedPk == encryptedPk2
test "Noise public keys: encrypt, decrypt and decrypt a public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
let
@ -115,32 +106,31 @@ procSuite "Waku Noise":
decryptedPk == decryptedPk2
test "Noise public keys: serialize and deserialize an unencrypted public key":
let
noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
serializedNoisePublicKey: seq[byte] = serializeNoisePublicKey(noisePublicKey)
deserializedNoisePublicKey: NoisePublicKey = intoNoisePublicKey(serializedNoisePublicKey)
deserializedNoisePublicKey: NoisePublicKey =
intoNoisePublicKey(serializedNoisePublicKey)
check:
noisePublicKey == deserializedNoisePublicKey
test "Noise public keys: encrypt, serialize, deserialize and decrypt a public key":
let noisePublicKey: NoisePublicKey = genNoisePublicKey(rng[])
let
cs: ChaChaPolyCipherState = randomChaChaPolyCipherState(rng[])
encryptedPk: NoisePublicKey = encryptNoisePublicKey(cs, noisePublicKey)
serializedNoisePublicKey: seq[byte] = serializeNoisePublicKey(encryptedPk)
deserializedNoisePublicKey: NoisePublicKey = intoNoisePublicKey(serializedNoisePublicKey)
decryptedPk: NoisePublicKey = decryptNoisePublicKey(cs, deserializedNoisePublicKey)
deserializedNoisePublicKey: NoisePublicKey =
intoNoisePublicKey(serializedNoisePublicKey)
decryptedPk: NoisePublicKey =
decryptNoisePublicKey(cs, deserializedNoisePublicKey)
check:
noisePublicKey == decryptedPk
test "PayloadV2: serialize/deserialize PayloadV2 to byte sequence":
let
payload2: PayloadV2 = randomPayloadV2(rng[])
serializedPayload = serializePayloadV2(payload2)
@ -154,9 +144,7 @@ procSuite "Waku Noise":
deserializedPayload.isOk()
payload2 == deserializedPayload.get()
test "PayloadV2: Encode/Decode a Waku Message (version 2) to a PayloadV2":
# We encode to a WakuMessage a random PayloadV2
let
payload2 = randomPayloadV2(rng[])
@ -181,7 +169,6 @@ procSuite "Waku Noise":
payload2 == decoded.get()
test "Noise State Machine: Diffie-Hellman operation":
#We generate random keypairs
let
aliceKey = genKeyPair(rng[])
@ -197,7 +184,6 @@ procSuite "Waku Noise":
dh1 == dh2
test "Noise State Machine: Cipher State primitives":
# We generate a random Cipher State, associated data ad and plaintext
var
cipherState: CipherState = randomCipherState(rng[])
@ -297,7 +283,6 @@ procSuite "Waku Noise":
getNonce(cipherState) == NonceMax + 1
test "Noise State Machine: Symmetric State primitives":
# We select one supported handshake pattern and we initialize a symmetric state
var
hsPattern = NoiseHandshakePatterns["XX"]
@ -431,12 +416,12 @@ procSuite "Waku Noise":
getKey(cs1) != getKey(cs2)
test "Noise XX Handhshake and message encryption (extended test)":
let hsPattern = NoiseHandshakePatterns["XX"]
# We initialize Alice's and Bob's Handshake State
let aliceStaticKey = genKeyPair(rng[])
var aliceHS = initialize(hsPattern = hsPattern, staticKey = aliceStaticKey, initiator = true)
var aliceHS =
initialize(hsPattern = hsPattern, staticKey = aliceStaticKey, initiator = true)
let bobStaticKey = genKeyPair(rng[])
var bobHS = initialize(hsPattern = hsPattern, staticKey = bobStaticKey)
@ -457,7 +442,8 @@ procSuite "Waku Noise":
# By being the handshake initiator, Alice writes a Waku2 payload v2 containing her handshake message
# and the (encrypted) transport message
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
aliceStep =
stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
# Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep.payload2).get()
@ -489,7 +475,8 @@ procSuite "Waku Noise":
sentTransportMessage = randomSeqByte(rng[], 32)
# Similarly as in first step, Alice writes a Waku2 payload containing the handshake message and the (encrypted) transport message
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
aliceStep =
stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
# Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep.payload2).get()
@ -504,10 +491,14 @@ procSuite "Waku Noise":
let prevAliceHS = aliceHS
let prevBobHS = bobHS
let bobStep1 = stepHandshake(rng[], bobHS, transportMessage = sentTransportMessage).get()
let aliceStep1 = stepHandshake(rng[], aliceHS, readPayloadV2 = bobStep1.payload2).get()
let aliceStep2 = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
let bobStep2 = stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep2.payload2).get()
let bobStep1 =
stepHandshake(rng[], bobHS, transportMessage = sentTransportMessage).get()
let aliceStep1 =
stepHandshake(rng[], aliceHS, readPayloadV2 = bobStep1.payload2).get()
let aliceStep2 =
stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
let bobStep2 =
stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep2.payload2).get()
check:
aliceStep1 == default(HandshakeStepResult)
@ -535,11 +526,11 @@ procSuite "Waku Noise":
defaultMessageNametagBuffer: MessageNametagBuffer
for _ in 0 .. 10:
# Alice writes to Bob
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(aliceHSResult, message, defaultMessageNametagBuffer)
readMessage = readMessage(bobHSResult, payload2, defaultMessageNametagBuffer).get()
readMessage =
readMessage(bobHSResult, payload2, defaultMessageNametagBuffer).get()
check:
message == readMessage
@ -547,13 +538,13 @@ procSuite "Waku Noise":
# Bob writes to Alice
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(bobHSResult, message, defaultMessageNametagBuffer)
readMessage = readMessage(aliceHSResult, payload2, defaultMessageNametagBuffer).get()
readMessage =
readMessage(aliceHSResult, payload2, defaultMessageNametagBuffer).get()
check:
message == readMessage
test "Noise XXpsk0 Handhshake and message encryption (short test)":
let hsPattern = NoiseHandshakePatterns["XXpsk0"]
# We generate a random psk
@ -561,7 +552,9 @@ procSuite "Waku Noise":
# We initialize Alice's and Bob's Handshake State
let aliceStaticKey = genKeyPair(rng[])
var aliceHS = initialize(hsPattern = hsPattern, staticKey = aliceStaticKey, psk = psk, initiator = true)
var aliceHS = initialize(
hsPattern = hsPattern, staticKey = aliceStaticKey, psk = psk, initiator = true
)
let bobStaticKey = genKeyPair(rng[])
var bobHS = initialize(hsPattern = hsPattern, staticKey = bobStaticKey, psk = psk)
@ -582,7 +575,8 @@ procSuite "Waku Noise":
# By being the handshake initiator, Alice writes a Waku2 payload v2 containing her handshake message
# and the (encrypted) transport message
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
aliceStep =
stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
# Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep.payload2).get()
@ -614,7 +608,8 @@ procSuite "Waku Noise":
sentTransportMessage = randomSeqByte(rng[], 32)
# Similarly as in first step, Alice writes a Waku2 payload containing the handshake message and the (encrypted) transport message
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
aliceStep =
stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
# Bob reads Alice's payloads, and returns the (decrypted) transportMessage alice sent to him
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep.payload2).get()
@ -642,11 +637,11 @@ procSuite "Waku Noise":
defaultMessageNametagBuffer: MessageNametagBuffer
for _ in 0 .. 10:
# Alice writes to Bob
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(aliceHSResult, message, defaultMessageNametagBuffer)
readMessage = readMessage(bobHSResult, payload2, defaultMessageNametagBuffer).get()
readMessage =
readMessage(bobHSResult, payload2, defaultMessageNametagBuffer).get()
check:
message == readMessage
@ -654,13 +649,13 @@ procSuite "Waku Noise":
# Bob writes to Alice
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(bobHSResult, message, defaultMessageNametagBuffer)
readMessage = readMessage(aliceHSResult, payload2, defaultMessageNametagBuffer).get()
readMessage =
readMessage(aliceHSResult, payload2, defaultMessageNametagBuffer).get()
check:
message == readMessage
test "Noise K1K1 Handhshake and message encryption (short test)":
let hsPattern = NoiseHandshakePatterns["K1K1"]
# We initialize Alice's and Bob's Handshake State
@ -672,10 +667,21 @@ procSuite "Waku Noise":
# <- s
# ...
# So we define accordingly the sequence of the pre-message public keys
let preMessagePKs: seq[NoisePublicKey] = @[toNoisePublicKey(getPublicKey(aliceStaticKey)), toNoisePublicKey(getPublicKey(bobStaticKey))]
let preMessagePKs: seq[NoisePublicKey] =
@[
toNoisePublicKey(getPublicKey(aliceStaticKey)),
toNoisePublicKey(getPublicKey(bobStaticKey)),
]
var aliceHS = initialize(hsPattern = hsPattern, staticKey = aliceStaticKey, preMessagePKs = preMessagePKs, initiator = true)
var bobHS = initialize(hsPattern = hsPattern, staticKey = bobStaticKey, preMessagePKs = preMessagePKs)
var aliceHS = initialize(
hsPattern = hsPattern,
staticKey = aliceStaticKey,
preMessagePKs = preMessagePKs,
initiator = true,
)
var bobHS = initialize(
hsPattern = hsPattern, staticKey = bobStaticKey, preMessagePKs = preMessagePKs
)
var
sentTransportMessage: seq[byte]
@ -693,7 +699,8 @@ procSuite "Waku Noise":
# By being the handshake initiator, Alice writes a Waku2 payload v2 containing her handshake message
# and the (encrypted) transport message
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
aliceStep =
stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
# Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep.payload2).get()
@ -725,7 +732,8 @@ procSuite "Waku Noise":
sentTransportMessage = randomSeqByte(rng[], 32)
# Similarly as in first step, Alice writes a Waku2 payload containing the handshake_message and the (encrypted) transportMessage
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
aliceStep =
stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
# Bob reads Alice's payloads, and returns the (decrypted) transportMessage alice sent to him
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep.payload2).get()
@ -753,11 +761,11 @@ procSuite "Waku Noise":
defaultMessageNametagBuffer: MessageNametagBuffer
for _ in 0 .. 10:
# Alice writes to Bob
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(aliceHSResult, message, defaultMessageNametagBuffer)
readMessage = readMessage(bobHSResult, payload2, defaultMessageNametagBuffer).get()
readMessage =
readMessage(bobHSResult, payload2, defaultMessageNametagBuffer).get()
check:
message == readMessage
@ -765,14 +773,13 @@ procSuite "Waku Noise":
# Bob writes to Alice
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(bobHSResult, message, defaultMessageNametagBuffer)
readMessage = readMessage(aliceHSResult, payload2, defaultMessageNametagBuffer).get()
readMessage =
readMessage(aliceHSResult, payload2, defaultMessageNametagBuffer).get()
check:
message == readMessage
test "Noise XK1 Handhshake and message encryption (short test)":
let hsPattern = NoiseHandshakePatterns["XK1"]
# We initialize Alice's and Bob's Handshake State
@ -783,10 +790,18 @@ procSuite "Waku Noise":
# <- s
# ...
# So we define accordingly the sequence of the pre-message public keys
let preMessagePKs: seq[NoisePublicKey] = @[toNoisePublicKey(getPublicKey(bobStaticKey))]
let preMessagePKs: seq[NoisePublicKey] =
@[toNoisePublicKey(getPublicKey(bobStaticKey))]
var aliceHS = initialize(hsPattern = hsPattern, staticKey = aliceStaticKey, preMessagePKs = preMessagePKs, initiator = true)
var bobHS = initialize(hsPattern = hsPattern, staticKey = bobStaticKey, preMessagePKs = preMessagePKs)
var aliceHS = initialize(
hsPattern = hsPattern,
staticKey = aliceStaticKey,
preMessagePKs = preMessagePKs,
initiator = true,
)
var bobHS = initialize(
hsPattern = hsPattern, staticKey = bobStaticKey, preMessagePKs = preMessagePKs
)
var
sentTransportMessage: seq[byte]
@ -804,7 +819,8 @@ procSuite "Waku Noise":
# By being the handshake initiator, Alice writes a Waku2 payload v2 containing her handshake message
# and the (encrypted) transport message
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
aliceStep =
stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
# Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep.payload2).get()
@ -836,7 +852,8 @@ procSuite "Waku Noise":
sentTransportMessage = randomSeqByte(rng[], 32)
# Similarly as in first step, Alice writes a Waku2 payload containing the handshake message and the (encrypted) transport message
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
aliceStep =
stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage).get()
# Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = aliceStep.payload2).get()
@ -864,11 +881,11 @@ procSuite "Waku Noise":
defaultMessageNametagBuffer: MessageNametagBuffer
for _ in 0 .. 10:
# Alice writes to Bob
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(aliceHSResult, message, defaultMessageNametagBuffer)
readMessage = readMessage(bobHSResult, payload2, defaultMessageNametagBuffer).get()
readMessage =
readMessage(bobHSResult, payload2, defaultMessageNametagBuffer).get()
check:
message == readMessage
@ -876,7 +893,8 @@ procSuite "Waku Noise":
# Bob writes to Alice
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(bobHSResult, message, defaultMessageNametagBuffer)
readMessage = readMessage(aliceHSResult, payload2, defaultMessageNametagBuffer).get()
readMessage =
readMessage(aliceHSResult, payload2, defaultMessageNametagBuffer).get()
check:
message == readMessage

View File

@ -1,9 +1,6 @@
{.used.}
import
std/tables,
stew/[results, byteutils],
testutils/unittests
import std/tables, stew/[results, byteutils], testutils/unittests
import
../../waku/common/protobuf,
../../waku/utils/noise as waku_message_utils,
@ -19,7 +16,6 @@ procSuite "Waku Noise Sessions":
# This test implements the Device pairing and Secure Transfers with Noise
# detailed in the 43/WAKU2-DEVICE-PAIRING RFC https://rfc.vac.dev/spec/43/
test "Noise Waku Pairing Handhshake and Secure transfer":
#########################
# Pairing Phase
#########################
@ -47,10 +43,19 @@ procSuite "Waku Noise Sessions":
# Out-of-band Communication
# Bob prepares the QR and sends it out-of-band to Alice
let qr = toQr(applicationName, applicationVersion, shardId, getPublicKey(bobEphemeralKey), bobCommittedStaticKey)
let qr = toQr(
applicationName,
applicationVersion,
shardId,
getPublicKey(bobEphemeralKey),
bobCommittedStaticKey,
)
# Alice deserializes the QR code
let (readApplicationName, readApplicationVersion, readShardId, readEphemeralKey, readCommittedStaticKey) = fromQr(qr)
let (
readApplicationName, readApplicationVersion, readShardId, readEphemeralKey,
readCommittedStaticKey,
) = fromQr(qr)
# We check if QR serialization/deserialization works
check:
@ -61,19 +66,35 @@ procSuite "Waku Noise Sessions":
bobCommittedStaticKey == readCommittedStaticKey
# We set the contentTopic from the content topic parameters exchanged in the QR
let contentTopic: ContentTopic = "/" & applicationName & "/" & applicationVersion & "/wakunoise/1/sessions_shard-" & shardId & "/proto"
let contentTopic: ContentTopic =
"/" & applicationName & "/" & applicationVersion & "/wakunoise/1/sessions_shard-" &
shardId & "/proto"
###############
# Pre-handshake message
#
# <- eB {H(sB||r), contentTopicParams, messageNametag}
###############
let preMessagePKs: seq[NoisePublicKey] = @[toNoisePublicKey(getPublicKey(bobEphemeralKey))]
let preMessagePKs: seq[NoisePublicKey] =
@[toNoisePublicKey(getPublicKey(bobEphemeralKey))]
# We initialize the Handshake states.
# Note that we pass the whole qr serialization as prologue information
var aliceHS = initialize(hsPattern = hsPattern, ephemeralKey = aliceEphemeralKey, staticKey = aliceStaticKey, prologue = qr.toBytes, preMessagePKs = preMessagePKs, initiator = true)
var bobHS = initialize(hsPattern = hsPattern, ephemeralKey = bobEphemeralKey, staticKey = bobStaticKey, prologue = qr.toBytes, preMessagePKs = preMessagePKs)
var aliceHS = initialize(
hsPattern = hsPattern,
ephemeralKey = aliceEphemeralKey,
staticKey = aliceStaticKey,
prologue = qr.toBytes,
preMessagePKs = preMessagePKs,
initiator = true,
)
var bobHS = initialize(
hsPattern = hsPattern,
ephemeralKey = bobEphemeralKey,
staticKey = bobStaticKey,
prologue = qr.toBytes,
preMessagePKs = preMessagePKs,
)
###############
# Pairing Handshake
@ -109,7 +130,13 @@ procSuite "Waku Noise Sessions":
# By being the handshake initiator, Alice writes a Waku2 payload v2 containing her handshake message
# and the (encrypted) transport message
# The message is sent with a messageNametag equal to the one received through the QR code
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage, messageNametag = qrMessageNametag).get()
aliceStep = stepHandshake(
rng[],
aliceHS,
transportMessage = sentTransportMessage,
messageNametag = qrMessageNametag,
)
.get()
###############################################
# We prepare a Waku message from Alice's payload2
@ -138,7 +165,10 @@ procSuite "Waku Noise Sessions":
# Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
# Note that Bob verifies if the received payloadv2 has the expected messageNametag set
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = readPayloadV2, messageNametag = qrMessageNametag).get()
bobStep = stepHandshake(
rng[], bobHS, readPayloadV2 = readPayloadV2, messageNametag = qrMessageNametag
)
.get()
check:
bobStep.transportMessage == sentTransportMessage
@ -166,7 +196,13 @@ procSuite "Waku Noise Sessions":
sentTransportMessage = r
# At this step, Bob writes and returns a payload
bobStep = stepHandshake(rng[], bobHS, transportMessage = sentTransportMessage, messageNametag = bobMessageNametag).get()
bobStep = stepHandshake(
rng[],
bobHS,
transportMessage = sentTransportMessage,
messageNametag = bobMessageNametag,
)
.get()
###############################################
# We prepare a Waku message from Bob's payload2
@ -194,13 +230,20 @@ procSuite "Waku Noise Sessions":
###############################################
# While Alice reads and returns the (decrypted) transport message
aliceStep = stepHandshake(rng[], aliceHS, readPayloadV2 = readPayloadV2, messageNametag = aliceMessageNametag).get()
aliceStep = stepHandshake(
rng[],
aliceHS,
readPayloadV2 = readPayloadV2,
messageNametag = aliceMessageNametag,
)
.get()
check:
aliceStep.transportMessage == sentTransportMessage
# Alice further checks if Bob's commitment opens to Bob's static key she just received
let expectedBobCommittedStaticKey = commitPublicKey(aliceHS.rs, aliceStep.transportMessage)
let expectedBobCommittedStaticKey =
commitPublicKey(aliceHS.rs, aliceStep.transportMessage)
check:
expectedBobCommittedStaticKey == bobCommittedStaticKey
@ -219,7 +262,13 @@ procSuite "Waku Noise Sessions":
sentTransportMessage = s
# Similarly as in first step, Alice writes a Waku2 payload containing the handshake message and the (encrypted) transport message
aliceStep = stepHandshake(rng[], aliceHS, transportMessage = sentTransportMessage, messageNametag = aliceMessageNametag).get()
aliceStep = stepHandshake(
rng[],
aliceHS,
transportMessage = sentTransportMessage,
messageNametag = aliceMessageNametag,
)
.get()
###############################################
# We prepare a Waku message from Bob's payload2
@ -247,13 +296,17 @@ procSuite "Waku Noise Sessions":
###############################################
# Bob reads Alice's payloads, and returns the (decrypted) transport message Alice sent to him
bobStep = stepHandshake(rng[], bobHS, readPayloadV2 = readPayloadV2, messageNametag = bobMessageNametag).get()
bobStep = stepHandshake(
rng[], bobHS, readPayloadV2 = readPayloadV2, messageNametag = bobMessageNametag
)
.get()
check:
bobStep.transportMessage == sentTransportMessage
# Bob further checks if Alice's commitment opens to Alice's static key he just received
let expectedAliceCommittedStaticKey = commitPublicKey(bobHS.rs, bobStep.transportMessage)
let expectedAliceCommittedStaticKey =
commitPublicKey(bobHS.rs, bobStep.transportMessage)
check:
expectedAliceCommittedStaticKey == aliceCommittedStaticKey
@ -277,19 +330,36 @@ procSuite "Waku Noise Sessions":
# We test message exchange
# Note that we exchange more than the number of messages contained in the nametag buffer to test if they are filled correctly as the communication proceeds
for i in 0 .. 10 * MessageNametagBufferSize:
# Alice writes to Bob
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(aliceHSResult, message, outboundMessageNametagBuffer = aliceHSResult.nametagsOutbound)
readMessage = readMessage(bobHSResult, payload2, inboundMessageNametagBuffer = bobHSResult.nametagsInbound).get()
payload2 = writeMessage(
aliceHSResult,
message,
outboundMessageNametagBuffer = aliceHSResult.nametagsOutbound,
)
readMessage = readMessage(
bobHSResult,
payload2,
inboundMessageNametagBuffer = bobHSResult.nametagsInbound,
)
.get()
check:
message == readMessage
# Bob writes to Alice
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(bobHSResult, message, outboundMessageNametagBuffer = bobHSResult.nametagsOutbound)
readMessage = readMessage(aliceHSResult, payload2, inboundMessageNametagBuffer = aliceHSResult.nametagsInbound).get()
payload2 = writeMessage(
bobHSResult,
message,
outboundMessageNametagBuffer = bobHSResult.nametagsOutbound,
)
readMessage = readMessage(
aliceHSResult,
payload2,
inboundMessageNametagBuffer = aliceHSResult.nametagsInbound,
)
.get()
check:
message == readMessage
@ -297,25 +367,53 @@ procSuite "Waku Noise Sessions":
# We test how nametag buffers help in detecting lost messages
# Alice writes two messages to Bob, but only the second is received
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(aliceHSResult, message, outboundMessageNametagBuffer = aliceHSResult.nametagsOutbound)
payload2 = writeMessage(
aliceHSResult,
message,
outboundMessageNametagBuffer = aliceHSResult.nametagsOutbound,
)
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(aliceHSResult, message, outboundMessageNametagBuffer = aliceHSResult.nametagsOutbound)
payload2 = writeMessage(
aliceHSResult,
message,
outboundMessageNametagBuffer = aliceHSResult.nametagsOutbound,
)
expect NoiseSomeMessagesWereLost:
readMessage = readMessage(bobHSResult, payload2, inboundMessageNametagBuffer = bobHSResult.nametagsInbound).get()
readMessage = readMessage(
bobHSResult,
payload2,
inboundMessageNametagBuffer = bobHSResult.nametagsInbound,
)
.get()
# We adjust bob nametag buffer for next test (i.e. the missed message is correctly recovered)
delete(bobHSResult.nametagsInbound, 2)
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(bobHSResult, message, outboundMessageNametagBuffer = bobHSResult.nametagsOutbound)
readMessage = readMessage(aliceHSResult, payload2, inboundMessageNametagBuffer = aliceHSResult.nametagsInbound).get()
payload2 = writeMessage(
bobHSResult, message, outboundMessageNametagBuffer = bobHSResult.nametagsOutbound
)
readMessage = readMessage(
aliceHSResult,
payload2,
inboundMessageNametagBuffer = aliceHSResult.nametagsInbound,
)
.get()
check:
message == readMessage
# We test if a missing nametag is correctly detected
message = randomSeqByte(rng[], 32)
payload2 = writeMessage(aliceHSResult, message, outboundMessageNametagBuffer = aliceHSResult.nametagsOutbound)
payload2 = writeMessage(
aliceHSResult,
message,
outboundMessageNametagBuffer = aliceHSResult.nametagsOutbound,
)
delete(bobHSResult.nametagsInbound, 1)
expect NoiseMessageNametagError:
readMessage = readMessage(bobHSResult, payload2, inboundMessageNametagBuffer = bobHSResult.nametagsInbound).get()
readMessage = readMessage(
bobHSResult,
payload2,
inboundMessageNametagBuffer = bobHSResult.nametagsInbound,
)
.get()

View File

@ -1,25 +1,17 @@
{.used.}
import
std/[options, sequtils, tables],
testutils/unittests,
chronos,
chronicles
import std/[options, sequtils, tables], testutils/unittests, chronos, chronicles
import
../../waku/waku_metadata,
../../waku/waku_metadata/rpc,
./testlib/wakucore,
./testlib/wakunode
procSuite "Waku Protobufs":
# TODO: Missing test coverage in many encode/decode protobuf functions
test "WakuMetadataResponse":
let res = WakuMetadataResponse(
clusterId: some(7),
shards: @[10, 23, 33],
)
let res = WakuMetadataResponse(clusterId: some(7), shards: @[10, 23, 33])
let buffer = res.encode()
@ -30,10 +22,7 @@ procSuite "Waku Protobufs":
decodedBuff.get().shards == res.shards
test "WakuMetadataRequest":
let req = WakuMetadataRequest(
clusterId: some(5),
shards: @[100, 2, 0],
)
let req = WakuMetadataRequest(clusterId: some(5), shards: @[100, 2, 0])
let buffer = req.encode()
@ -42,4 +31,3 @@ procSuite "Waku Protobufs":
decodedBuff.isOk()
decodedBuff.get().clusterId.get() == req.clusterId.get()
decodedBuff.get().shards == req.shards

View File

@ -1,18 +1,12 @@
{.used.}
import
chronos,
testutils/unittests,
libp2p,
libp2p/protocols/rendezvous
import chronos, testutils/unittests, libp2p, libp2p/protocols/rendezvous
import
../../waku/node/waku_switch,
./testlib/common,
./testlib/wakucore
import ../../waku/node/waku_switch, ./testlib/common, ./testlib/wakucore
proc newRendezvousClientSwitch(rdv: RendezVous): Switch =
SwitchBuilder.new()
SwitchBuilder
.new()
.withRng(rng())
.withAddresses(@[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()])
.withTcpTransport()
@ -55,5 +49,3 @@ procSuite "Waku Rendezvous":
res1[0] == sourceSwitch.peerInfo.signedPeerRecord.data
await allFutures(wakuSwitch.stop(), sourceSwitch.stop(), destSwitch.stop())

View File

@ -8,13 +8,11 @@ import
libp2p/protocols/connectivity/relay/relay,
libp2p/protocols/connectivity/relay/client,
stew/byteutils
import
../../waku/node/waku_switch,
./testlib/common,
./testlib/wakucore
import ../../waku/node/waku_switch, ./testlib/common, ./testlib/wakucore
proc newCircuitRelayClientSwitch(relayClient: RelayClient): Switch =
SwitchBuilder.new()
SwitchBuilder
.new()
.withRng(rng())
.withAddresses(@[MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()])
.withTcpTransport()
@ -24,7 +22,6 @@ proc newCircuitRelayClientSwitch(relayClient: RelayClient): Switch =
.build()
suite "Waku Switch":
asyncTest "Waku Switch works with AutoNat":
## Given
let
@ -35,7 +32,9 @@ suite "Waku Switch":
## When
await sourceSwitch.connect(wakuSwitch.peerInfo.peerId, wakuSwitch.peerInfo.addrs)
let ma = await AutonatClient.new().dialMe(sourceSwitch, wakuSwitch.peerInfo.peerId, wakuSwitch.peerInfo.addrs)
let ma = await AutonatClient.new().dialMe(
sourceSwitch, wakuSwitch.peerInfo.peerId, wakuSwitch.peerInfo.addrs
)
## Then
check:
@ -62,8 +61,12 @@ suite "Waku Switch":
## Given
let
# Create a relay address to destSwitch using wakuSwitch as the relay
addrs = MultiAddress.init($wakuSwitch.peerInfo.addrs[0] & "/p2p/" &
$wakuSwitch.peerInfo.peerId & "/p2p-circuit").get()
addrs = MultiAddress
.init(
$wakuSwitch.peerInfo.addrs[0] & "/p2p/" & $wakuSwitch.peerInfo.peerId &
"/p2p-circuit"
)
.get()
msg = "Just one relay away..."
# Create a custom protocol
@ -87,10 +90,12 @@ suite "Waku Switch":
await sourceSwitch.connect(wakuSwitch.peerInfo.peerId, wakuSwitch.peerInfo.addrs)
# destClient reserves a slot on the relay.
let rsvp = await destClient.reserve(wakuSwitch.peerInfo.peerId, wakuSwitch.peerInfo.addrs)
let rsvp =
await destClient.reserve(wakuSwitch.peerInfo.peerId, wakuSwitch.peerInfo.addrs)
# sourceSwitch dial destSwitch using the relay
let conn = await sourceSwitch.dial(destSwitch.peerInfo.peerId, @[addrs], customProtoCodec)
let conn =
await sourceSwitch.dial(destSwitch.peerInfo.peerId, @[addrs], customProtoCodec)
await conn.writeLp(msg)

View File

@ -25,9 +25,7 @@ import
./testlib/wakucore,
./testlib/wakunode
suite "WakuNode":
asyncTest "Protocol matcher works as expected":
let
nodeKey1 = generateSecp256k1Key()
@ -60,7 +58,9 @@ suite "WakuNode":
await node1.connectToNodes(@[node2.switch.peerInfo.toRemotePeerInfo()])
var completionFut = newFuture[bool]()
proc relayHandler(topic: PubsubTopic, msg: WakuMessage): Future[void] {.async, gcsafe.} =
proc relayHandler(
topic: PubsubTopic, msg: WakuMessage
): Future[void] {.async, gcsafe.} =
check:
topic == pubSubTopic
msg.contentTopic == contentTopic
@ -87,7 +87,9 @@ suite "WakuNode":
let
nodeKey1 = generateSecp256k1Key()
node1 = newTestWakuNode(nodeKey1, parseIpAddress("0.0.0.0"), Port(61020), nameResolver = resolver)
node1 = newTestWakuNode(
nodeKey1, parseIpAddress("0.0.0.0"), Port(61020), nameResolver = resolver
)
nodeKey2 = generateSecp256k1Key()
node2 = newTestWakuNode(nodeKey2, parseIpAddress("0.0.0.0"), Port(61022))
@ -112,14 +114,16 @@ suite "WakuNode":
let
maxConnections = 2
nodeKey1 = generateSecp256k1Key()
node1 = newTestWakuNode(nodeKey1, parseIpAddress("0.0.0.0"),
Port(60010), maxConnections = maxConnections)
node1 = newTestWakuNode(
nodeKey1,
parseIpAddress("0.0.0.0"),
Port(60010),
maxConnections = maxConnections,
)
nodeKey2 = generateSecp256k1Key()
node2 = newTestWakuNode(nodeKey2, parseIpAddress("0.0.0.0"),
Port(60012))
node2 = newTestWakuNode(nodeKey2, parseIpAddress("0.0.0.0"), Port(60012))
nodeKey3 = generateSecp256k1Key()
node3 = newTestWakuNode(nodeKey3, parseIpAddress("0.0.0.0"),
Port(60013))
node3 = newTestWakuNode(nodeKey3, parseIpAddress("0.0.0.0"), Port(60013))
check:
# Sanity check, to verify config was applied
@ -137,9 +141,11 @@ suite "WakuNode":
await node3.start()
await node3.mountRelay()
discard await node1.peerManager.connectRelay(node2.switch.peerInfo.toRemotePeerInfo())
discard
await node1.peerManager.connectRelay(node2.switch.peerInfo.toRemotePeerInfo())
await sleepAsync(3.seconds)
discard await node1.peerManager.connectRelay(node3.switch.peerInfo.toRemotePeerInfo())
discard
await node1.peerManager.connectRelay(node3.switch.peerInfo.toRemotePeerInfo())
check:
# Verify that only the first connection succeeded
@ -153,11 +159,14 @@ suite "WakuNode":
expect ResultDefect:
# gibberish
discard newTestWakuNode(nodeKey1, parseIpAddress("0.0.0.0"),
discard newTestWakuNode(
nodeKey1,
parseIpAddress("0.0.0.0"),
bindPort = Port(61004),
wsBindPort = Port(8000),
wssEnabled = true,
secureKey = "../../waku/node/key_dummy.txt")
secureKey = "../../waku/node/key_dummy.txt",
)
asyncTest "Peer info updates with correct announced addresses":
let
@ -166,10 +175,7 @@ suite "WakuNode":
bindPort = Port(61006)
extIp = some(parseIpAddress("127.0.0.1"))
extPort = some(Port(61008))
node = newTestWakuNode(
nodeKey,
bindIp, bindPort,
extIp, extPort)
node = newTestWakuNode(nodeKey, bindIp, bindPort, extIp, extPort)
let
bindEndpoint = MultiAddress.init(bindIp, tcpProtocol, bindPort)
@ -206,12 +212,11 @@ suite "WakuNode":
extIp = some(parseIpAddress("127.0.0.1"))
extPort = some(Port(61012))
domainName = "example.com"
expectedDns4Addr = MultiAddress.init("/dns4/" & domainName & "/tcp/" & $(extPort.get())).get()
expectedDns4Addr =
MultiAddress.init("/dns4/" & domainName & "/tcp/" & $(extPort.get())).get()
node = newTestWakuNode(
nodeKey,
bindIp, bindPort,
extIp, extPort,
dns4DomainName = some(domainName))
nodeKey, bindIp, bindPort, extIp, extPort, dns4DomainName = some(domainName)
)
check:
node.announcedAddresses.len == 1
@ -224,10 +229,8 @@ suite "WakuNode":
bindPort = Port(0)
domainName = "status.im"
node = newTestWakuNode(
nodeKey,
bindIp, bindPort,
dns4DomainName = some(domainName))
node =
newTestWakuNode(nodeKey, bindIp, bindPort, dns4DomainName = some(domainName))
var ipStr = ""
var enrIp = node.enr.tryGet("ip", array[4, byte])
@ -257,18 +260,15 @@ suite "WakuNode":
# Create node with inexistent domain
try:
let node = newTestWakuNode(
nodeKey,
bindIp, bindPort,
dns4DomainName = some(inexistentDomain))
nodeKey, bindIp, bindPort, dns4DomainName = some(inexistentDomain)
)
except Exception as e:
inexistentDomainErr = e.msg
# Create node with invalid domain
try:
let node = newTestWakuNode(
nodeKey,
bindIp, bindPort,
dns4DomainName = some(invalidDomain))
let node =
newTestWakuNode(nodeKey, bindIp, bindPort, dns4DomainName = some(invalidDomain))
except Exception as e:
invalidDomainErr = e.msg
@ -287,8 +287,12 @@ suite "WakuNode":
let
# node with custom agent string
nodeKey1 = generateSecp256k1Key()
node1 = newTestWakuNode(nodeKey1, parseIpAddress("0.0.0.0"), Port(61014),
agentString = some(expectedAgentString1))
node1 = newTestWakuNode(
nodeKey1,
parseIpAddress("0.0.0.0"),
Port(61014),
agentString = some(expectedAgentString1),
)
# node with default agent string from libp2p
nodeKey2 = generateSecp256k1Key()
@ -303,8 +307,10 @@ suite "WakuNode":
await node1.connectToNodes(@[node2.switch.peerInfo.toRemotePeerInfo()])
await node2.connectToNodes(@[node1.switch.peerInfo.toRemotePeerInfo()])
let node1Agent = node2.switch.peerStore[AgentBook][node1.switch.peerInfo.toRemotePeerInfo().peerId]
let node2Agent = node1.switch.peerStore[AgentBook][node2.switch.peerInfo.toRemotePeerInfo().peerId]
let node1Agent =
node2.switch.peerStore[AgentBook][node1.switch.peerInfo.toRemotePeerInfo().peerId]
let node2Agent =
node1.switch.peerStore[AgentBook][node2.switch.peerInfo.toRemotePeerInfo().peerId]
check:
node1Agent == expectedAgentString1
@ -322,8 +328,12 @@ suite "WakuNode":
let
# node with custom multiaddress
nodeKey1 = generateSecp256k1Key()
node1 = newTestWakuNode(nodeKey1, parseIpAddress("0.0.0.0"), Port(61018),
extMultiAddrs = @[expectedMultiaddress1])
node1 = newTestWakuNode(
nodeKey1,
parseIpAddress("0.0.0.0"),
Port(61018),
extMultiAddrs = @[expectedMultiaddress1],
)
# node with default multiaddress
nodeKey2 = generateSecp256k1Key()
@ -338,7 +348,9 @@ suite "WakuNode":
await node1.connectToNodes(@[node2.switch.peerInfo.toRemotePeerInfo()])
await node2.connectToNodes(@[node1.switch.peerInfo.toRemotePeerInfo()])
let node1MultiAddrs = node2.switch.peerStore[AddressBook][node1.switch.peerInfo.toRemotePeerInfo().peerId]
let node1MultiAddrs = node2.switch.peerStore[AddressBook][
node1.switch.peerInfo.toRemotePeerInfo().peerId
]
check:
node1MultiAddrs.contains(expectedMultiaddress1)

View File

@ -15,9 +15,7 @@ import
./testlib/wakucore,
./testlib/wakunode
suite "WakuNode - Filter":
asyncTest "subscriber should receive the message handled by the publisher":
## Setup
let
@ -41,11 +39,15 @@ suite "WakuNode - Filter":
message = fakeWakuMessage(contentTopic = contentTopic)
var filterPushHandlerFut = newFuture[(PubsubTopic, WakuMessage)]()
proc filterPushHandler(pubsubTopic: PubsubTopic, msg: WakuMessage) {.async, gcsafe, closure.} =
proc filterPushHandler(
pubsubTopic: PubsubTopic, msg: WakuMessage
) {.async, gcsafe, closure.} =
filterPushHandlerFut.complete((pubsubTopic, msg))
## When
await client.legacyFilterSubscribe(some(pubsubTopic), contentTopic, filterPushHandler, peer=serverPeerInfo)
await client.legacyFilterSubscribe(
some(pubsubTopic), contentTopic, filterPushHandler, peer = serverPeerInfo
)
# Wait for subscription to take effect
waitFor sleepAsync(100.millis)

View File

@ -1,10 +1,6 @@
{.used.}
import
std/options,
stew/shims/net as stewNet,
testutils/unittests,
chronos
import std/options, stew/shims/net as stewNet, testutils/unittests, chronos
import
../../waku/waku_core,
../../waku/waku_lightpush/common,
@ -13,7 +9,6 @@ import
./testlib/wakucore,
./testlib/wakunode
suite "WakuNode - Lightpush":
asyncTest "Lightpush message return success":
## Setup
@ -32,7 +27,9 @@ suite "WakuNode - Lightpush":
await bridgeNode.mountLightPush()
lightNode.mountLightPushClient()
discard await lightNode.peerManager.dialPeer(bridgeNode.peerInfo.toRemotePeerInfo(), WakuLightPushCodec)
discard await lightNode.peerManager.dialPeer(
bridgeNode.peerInfo.toRemotePeerInfo(), WakuLightPushCodec
)
await sleepAsync(100.milliseconds)
await destNode.connectToNodes(@[bridgeNode.peerInfo.toRemotePeerInfo()])
@ -40,11 +37,14 @@ suite "WakuNode - Lightpush":
let message = fakeWakuMessage()
var completionFutRelay = newFuture[bool]()
proc relayHandler(topic: PubsubTopic, msg: WakuMessage): Future[void] {.async, gcsafe.} =
proc relayHandler(
topic: PubsubTopic, msg: WakuMessage
): Future[void] {.async, gcsafe.} =
check:
topic == DefaultPubsubTopic
msg == message
completionFutRelay.complete(true)
destNode.subscribe((kind: PubsubSub, topic: DefaultPubsubTopic), some(relayHandler))
# Wait for subscription to take effect

View File

@ -1,8 +1,4 @@
import
std/[times, random],
bearssl/rand,
libp2p/crypto/crypto
import std/[times, random], bearssl/rand, libp2p/crypto/crypto
## Randomization
@ -12,7 +8,6 @@ proc randomize*() =
let now = getTime()
randomize(now.toUnix() * 1_000_000_000 + now.nanosecond)
## RNG
# Copied from here: https://github.com/status-im/nim-libp2p/blob/d522537b19a532bc4af94fcd146f779c1f23bad0/tests/helpers.nim#L28
@ -33,5 +28,5 @@ proc getRng(): ref HmacDrbgContext =
rngVar.rng
template rng*(): ref HmacDrbgContext = getRng()
template rng*(): ref HmacDrbgContext =
getRng()

View File

@ -1,7 +1,4 @@
import
chronicles,
chronos
import chronicles, chronos
import
../../../waku/waku_archive,
../../../waku/waku_archive/driver as driver_module,
@ -11,7 +8,6 @@ import
const storeMessageDbUrl = "postgres://postgres:test123@localhost:5432/postgres"
proc newTestPostgresDriver*(): Future[Result[ArchiveDriver, string]] {.async.} =
proc onErr(errMsg: string) {.gcsafe, closure.} =
error "error creating ArchiveDriver", error = errMsg
quit(QuitFailure)
@ -21,13 +17,9 @@ proc newTestPostgresDriver*(): Future[Result[ArchiveDriver, string]] {.async.} =
migrate = true
maxNumConn = 50
let driverRes = await ArchiveDriver.new(storeMessageDbUrl,
vacuum,
migrate,
maxNumConn,
onErr)
let driverRes =
await ArchiveDriver.new(storeMessageDbUrl, vacuum, migrate, maxNumConn, onErr)
if driverRes.isErr():
onErr("could not create archive driver: " & driverRes.error)
return ok(driverRes.get())

View File

@ -2,8 +2,7 @@
import posix
type
Instr {.union.} = object
type Instr {.union.} = object
bytes: array[8, byte]
value: uint64
@ -13,9 +12,7 @@ proc mockImpl(target, replacement: pointer) =
var page = cast[pointer](cast[ByteAddress](target) and (not 0xfff))
doAssert mprotect(page, 4096, PROT_WRITE or PROT_EXEC) == 0
let rel = cast[ByteAddress](replacement) - cast[ByteAddress](target) - 5
var
instr =
Instr(
var instr = Instr(
bytes: [
0xe9.byte,
(rel shr 0).byte,
@ -24,7 +21,7 @@ proc mockImpl(target, replacement: pointer) =
(rel shr 24).byte,
0,
0,
0
0,
]
)
cast[ptr uint64](target)[] = instr.value

View File

@ -1,26 +1,19 @@
import
std/[
tables,
sequtils,
options
]
import std/[tables, sequtils, options]
import
../../../waku/waku_core/topics,
../testlib/wakucore
import ../../../waku/waku_core/topics, ../testlib/wakucore
proc `==`*(table: Table[pubsub_topic.NsPubsubTopic, seq[NsContentTopic]], other: array[0..0, (string, seq[string])]): bool =
proc `==`*(
table: Table[pubsub_topic.NsPubsubTopic, seq[NsContentTopic]],
other: array[0 .. 0, (string, seq[string])],
): bool =
let otherTyped = other.map(
proc(item: (string, seq[string])): (NsPubsubTopic, seq[NsContentTopic]) =
let
(pubsubTopic, contentTopics) = item
nsPubsubTopic = NsPubsubTopic.parse(pubsubTopic).value()
nsContentTopics = contentTopics.map(
proc(contentTopic: string): NsContentTopic = NsContentTopic.parse(contentTopic).value()
proc(contentTopic: string): NsContentTopic =
NsContentTopic.parse(contentTopic).value()
)
return (nsPubsubTopic, nsContentTopics)
)

View File

@ -3,14 +3,18 @@
template asyncTeardown*(body: untyped): untyped =
teardown:
waitFor((
waitFor(
(
proc() {.async, gcsafe.} =
body
)())
)()
)
template asyncSetup*(body: untyped): untyped =
setup:
waitFor((
waitFor(
(
proc() {.async, gcsafe.} =
body
)())
)()
)

View File

@ -1,12 +1,16 @@
import
testutils/unittests
import testutils/unittests
template xsuite*(name: string, body: untyped) = discard
template suitex*(name: string, body: untyped) = discard
template xsuite*(name: string, body: untyped) =
discard
template xprocSuite*(name: string, body: untyped) = discard
template procSuitex*(name: string, body: untyped) = discard
template suitex*(name: string, body: untyped) =
discard
template xprocSuite*(name: string, body: untyped) =
discard
template procSuitex*(name: string, body: untyped) =
discard
template xtest*(name: string, body: untyped) =
test name:

View File

@ -7,13 +7,10 @@ import
libp2p/builders,
libp2p/crypto/crypto as libp2p_keys,
eth/keys as eth_keys
import
../../../waku/waku_core,
./common
import ../../../waku/waku_core, ./common
export switch
# Time
proc now*(): Timestamp =
@ -22,7 +19,6 @@ proc now*(): Timestamp =
proc ts*(offset = 0, origin = now()): Timestamp =
origin + getNanosecondTime(int64(offset))
# Switch
proc generateEcdsaKey*(): libp2p_keys.PrivateKey =
@ -37,26 +33,23 @@ proc generateSecp256k1Key*(): libp2p_keys.PrivateKey =
proc ethSecp256k1Key*(hex: string): eth_keys.PrivateKey =
eth_keys.PrivateKey.fromHex(hex).get()
proc newTestSwitch*(key=none(libp2p_keys.PrivateKey), address=none(MultiAddress)): Switch =
proc newTestSwitch*(
key = none(libp2p_keys.PrivateKey), address = none(MultiAddress)
): Switch =
let peerKey = key.get(generateSecp256k1Key())
let peerAddr = address.get(MultiAddress.init("/ip4/127.0.0.1/tcp/0").get())
return newStandardSwitch(some(peerKey), addrs = peerAddr)
# Waku message
export
waku_core.DefaultPubsubTopic,
waku_core.DefaultContentTopic
export waku_core.DefaultPubsubTopic, waku_core.DefaultContentTopic
proc fakeWakuMessage*(
payload: string | seq[byte] = "TEST-PAYLOAD",
contentTopic = DefaultContentTopic,
meta = newSeq[byte](),
ts = now(),
ephemeral = false
ephemeral = false,
): WakuMessage =
var payloadBytes: seq[byte]
when payload is string:
@ -70,5 +63,5 @@ proc fakeWakuMessage*(
meta: meta,
version: 2,
timestamp: ts,
ephemeral: ephemeral
ephemeral: ephemeral,
)

View File

@ -18,7 +18,6 @@ import
../../../waku/factory/builder,
./common
# Waku node
proc defaultTestWakuNodeConf*(): WakuNodeConf =
@ -36,10 +35,11 @@ proc defaultTestWakuNodeConf*(): WakuNodeConf =
clusterId: 1.uint32,
topics: @["/waku/2/rs/1/0"],
relay: true,
storeMessageDbUrl: "sqlite://store.sqlite3"
storeMessageDbUrl: "sqlite://store.sqlite3",
)
proc newTestWakuNode*(nodeKey: crypto.PrivateKey,
proc newTestWakuNode*(
nodeKey: crypto.PrivateKey,
bindIp: IpAddress,
bindPort: Port,
extIp = none(IpAddress),
@ -60,14 +60,16 @@ proc newTestWakuNode*(nodeKey: crypto.PrivateKey,
agentString = none(string),
clusterId: uint32 = 1.uint32,
topics: seq[string] = @["/waku/2/rs/1/0"],
peerStoreCapacity = none(int)): WakuNode =
peerStoreCapacity = none(int),
): WakuNode =
var resolvedExtIp = extIp
# Update extPort to default value if it's missing and there's an extIp or a DNS domain
let extPort =
if (extIp.isSome() or dns4DomainName.isSome()) and extPort.isNone(): some(Port(60000))
else: extPort
if (extIp.isSome() or dns4DomainName.isSome()) and extPort.isNone():
some(Port(60000))
else:
extPort
var conf = defaultTestWakuNodeConf()
@ -103,9 +105,7 @@ proc newTestWakuNode*(nodeKey: crypto.PrivateKey,
raise newException(Defect, "Invalid record: " & error)
enrBuilder.withIpAddressAndPorts(
ipAddr = netConf.enrIp,
tcpPort = netConf.enrPort,
udpPort = netConf.discv5UdpPort,
ipAddr = netConf.enrIp, tcpPort = netConf.enrPort, udpPort = netConf.discv5UdpPort
)
enrBuilder.withMultiaddrs(netConf.enrMultiaddrs)
@ -126,10 +126,19 @@ proc newTestWakuNode*(nodeKey: crypto.PrivateKey,
maxConnections = some(maxConnections),
nameResolver = nameResolver,
sendSignedPeerRecord = sendSignedPeerRecord,
secureKey = if secureKey != "": some(secureKey) else: none(string),
secureCert = if secureCert != "": some(secureCert) else: none(string),
secureKey =
if secureKey != "":
some(secureKey)
else:
none(string)
,
secureCert =
if secureCert != "":
some(secureCert)
else:
none(string)
,
agentString = agentString,
)
return builder.build().get()

View File

@ -9,7 +9,7 @@ import
waku_archive,
waku_archive/common,
waku_archive/driver/sqlite_driver,
common/databases/db_sqlite
common/databases/db_sqlite,
],
../testlib/[wakucore]

View File

@ -1,9 +1,6 @@
{.used.}
import
std/[sequtils,options],
testutils/unittests,
chronos
import std/[sequtils, options], testutils/unittests, chronos
import
../../../waku/waku_archive,
../../../waku/waku_archive/driver/postgres_driver,
@ -13,9 +10,7 @@ import
../testlib/testasync,
../testlib/postgres
proc computeTestCursor(pubsubTopic: PubsubTopic,
message: WakuMessage):
ArchiveCursor =
proc computeTestCursor(pubsubTopic: PubsubTopic, message: WakuMessage): ArchiveCursor =
ArchiveCursor(
pubsubTopic: pubsubTopic,
senderTime: message.timestamp,
@ -65,7 +60,9 @@ suite "Postgres driver":
let computedDigest = computeDigest(msg)
let computedHash = computeMessageHash(DefaultPubsubTopic, msg)
let putRes = await driver.put(DefaultPubsubTopic, msg, computedDigest, computedHash, msg.timestamp)
let putRes = await driver.put(
DefaultPubsubTopic, msg, computedDigest, computedHash, msg.timestamp
)
assert putRes.isOk(), putRes.error
let storedMsg = (await driver.getAllMessages()).tryGet()
@ -87,12 +84,24 @@ suite "Postgres driver":
let msg1 = fakeWakuMessage(contentTopic = contentTopic1)
var putRes = await driver.put(pubsubTopic1, msg1, computeDigest(msg1), computeMessageHash(pubsubTopic1, msg1), msg1.timestamp)
var putRes = await driver.put(
pubsubTopic1,
msg1,
computeDigest(msg1),
computeMessageHash(pubsubTopic1, msg1),
msg1.timestamp,
)
assert putRes.isOk(), putRes.error
let msg2 = fakeWakuMessage(contentTopic = contentTopic2)
putRes = await driver.put(pubsubTopic2, msg2, computeDigest(msg2), computeMessageHash(pubsubTopic2, msg2), msg2.timestamp)
putRes = await driver.put(
pubsubTopic2,
msg2,
computeDigest(msg2),
computeMessageHash(pubsubTopic2, msg2),
msg2.timestamp,
)
assert putRes.isOk(), putRes.error
let countMessagesRes = await driver.getMessagesCount()
@ -106,17 +115,17 @@ suite "Postgres driver":
assert messagesRes.get().len == 1
# Get both content topics, check ordering
messagesRes = await driver.getMessages(contentTopic = @[contentTopic1,
contentTopic2])
messagesRes =
await driver.getMessages(contentTopic = @[contentTopic1, contentTopic2])
assert messagesRes.isOk(), messagesRes.error
assert messagesRes.get().len == 2
assert messagesRes.get()[0][1].contentTopic == contentTopic1
# Descending order
messagesRes = await driver.getMessages(contentTopic = @[contentTopic1,
contentTopic2],
ascendingOrder = false)
messagesRes = await driver.getMessages(
contentTopic = @[contentTopic1, contentTopic2], ascendingOrder = false
)
assert messagesRes.isOk(), messagesRes.error
assert messagesRes.get().len == 2
@ -124,28 +133,26 @@ suite "Postgres driver":
# cursor
# Get both content topics
messagesRes =
await driver.getMessages(contentTopic = @[contentTopic1,
contentTopic2],
cursor = some(
computeTestCursor(pubsubTopic1,
messagesRes.get()[1][1])))
messagesRes = await driver.getMessages(
contentTopic = @[contentTopic1, contentTopic2],
cursor = some(computeTestCursor(pubsubTopic1, messagesRes.get()[1][1])),
)
assert messagesRes.isOk()
assert messagesRes.get().len == 1
# Get both content topics but one pubsub topic
messagesRes = await driver.getMessages(contentTopic = @[contentTopic1,
contentTopic2],
pubsubTopic = some(pubsubTopic1))
messagesRes = await driver.getMessages(
contentTopic = @[contentTopic1, contentTopic2], pubsubTopic = some(pubsubTopic1)
)
assert messagesRes.isOk(), messagesRes.error
assert messagesRes.get().len == 1
assert messagesRes.get()[0][1].contentTopic == contentTopic1
# Limit
messagesRes = await driver.getMessages(contentTopic = @[contentTopic1,
contentTopic2],
maxPageSize = 1)
messagesRes = await driver.getMessages(
contentTopic = @[contentTopic1, contentTopic2], maxPageSize = 1
)
assert messagesRes.isOk(), messagesRes.error
assert messagesRes.get().len == 1
@ -157,11 +164,20 @@ suite "Postgres driver":
let msg1 = fakeWakuMessage(ts = now)
let msg2 = fakeWakuMessage(ts = now)
var putRes = await driver.put(DefaultPubsubTopic,
msg1, computeDigest(msg1), computeMessageHash(DefaultPubsubTopic, msg1), msg1.timestamp)
var putRes = await driver.put(
DefaultPubsubTopic,
msg1,
computeDigest(msg1),
computeMessageHash(DefaultPubsubTopic, msg1),
msg1.timestamp,
)
assert putRes.isOk(), putRes.error
putRes = await driver.put(DefaultPubsubTopic,
msg2, computeDigest(msg2), computeMessageHash(DefaultPubsubTopic, msg2), msg2.timestamp)
putRes = await driver.put(
DefaultPubsubTopic,
msg2,
computeDigest(msg2),
computeMessageHash(DefaultPubsubTopic, msg2),
msg2.timestamp,
)
assert not putRes.isOk()

File diff suppressed because it is too large Load Diff

View File

@ -1,22 +1,19 @@
{.used.}
import
std/options,
stew/results,
testutils/unittests
import std/options, stew/results, testutils/unittests
import
../../../waku/waku_archive,
../../../waku/waku_archive/driver/queue_driver/queue_driver {.all.},
../../../waku/waku_archive/driver/queue_driver/index,
../../../waku/waku_core
# Helper functions
proc genIndexedWakuMessage(i: int8): (Index, WakuMessage) =
## Use i to generate an Index WakuMessage
var data {.noinit.}: array[32, byte]
for x in data.mitems: x = i.byte
for x in data.mitems:
x = i.byte
let
message = WakuMessage(payload: @[byte i], timestamp: Timestamp(i))
@ -24,7 +21,7 @@ proc genIndexedWakuMessage(i: int8): (Index, WakuMessage) =
receiverTime: Timestamp(i),
senderTime: Timestamp(i),
digest: MessageDigest(data: data),
pubsubTopic: "test-pubsub-topic"
pubsubTopic: "test-pubsub-topic",
)
(cursor, message)
@ -38,9 +35,7 @@ proc getPrepopulatedTestQueue(unsortedSet: auto, capacity: int): QueueDriver =
driver
procSuite "Sorted driver queue":
test "queue capacity - add a message over the limit":
## Given
let capacity = 5

View File

@ -1,14 +1,7 @@
{.used.}
import
std/times,
stew/byteutils,
testutils/unittests,
nimcrypto
import
../../../waku/waku_core,
../../../waku/waku_archive/driver/queue_driver/index
import std/times, stew/byteutils, testutils/unittests, nimcrypto
import ../../../waku/waku_core, ../../../waku/waku_archive/driver/queue_driver/index
## Helpers
@ -26,52 +19,75 @@ proc hashFromStr(input: string): MDigest[256] =
return hashed
suite "Queue Driver - index":
## Test vars
let
smallIndex1 = Index(digest: hashFromStr("1234"),
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(1000))
smallIndex2 = Index(digest: hashFromStr("1234567"), # digest is less significant than senderTime
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(1000))
largeIndex1 = Index(digest: hashFromStr("1234"),
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(9000)) # only senderTime differ from smallIndex1
largeIndex2 = Index(digest: hashFromStr("12345"), # only digest differs from smallIndex1
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(1000))
eqIndex1 = Index(digest: hashFromStr("0003"),
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(54321))
eqIndex2 = Index(digest: hashFromStr("0003"),
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(54321))
eqIndex3 = Index(digest: hashFromStr("0003"),
receiverTime: getNanosecondTime(9999), # receiverTime difference should have no effect on comparisons
senderTime: getNanosecondTime(54321))
diffPsTopic = Index(digest: hashFromStr("1234"),
smallIndex1 = Index(
digest: hashFromStr("1234"),
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(1000),
pubsubTopic: "zzzz")
noSenderTime1 = Index(digest: hashFromStr("1234"),
)
smallIndex2 = Index(
digest: hashFromStr("1234567"), # digest is less significant than senderTime
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(1000),
)
largeIndex1 = Index(
digest: hashFromStr("1234"),
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(9000),
) # only senderTime differ from smallIndex1
largeIndex2 = Index(
digest: hashFromStr("12345"), # only digest differs from smallIndex1
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(1000),
)
eqIndex1 = Index(
digest: hashFromStr("0003"),
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(54321),
)
eqIndex2 = Index(
digest: hashFromStr("0003"),
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(54321),
)
eqIndex3 = Index(
digest: hashFromStr("0003"),
receiverTime: getNanosecondTime(9999),
# receiverTime difference should have no effect on comparisons
senderTime: getNanosecondTime(54321),
)
diffPsTopic = Index(
digest: hashFromStr("1234"),
receiverTime: getNanosecondTime(0),
senderTime: getNanosecondTime(1000),
pubsubTopic: "zzzz",
)
noSenderTime1 = Index(
digest: hashFromStr("1234"),
receiverTime: getNanosecondTime(1100),
senderTime: getNanosecondTime(0),
pubsubTopic: "zzzz")
noSenderTime2 = Index(digest: hashFromStr("1234"),
pubsubTopic: "zzzz",
)
noSenderTime2 = Index(
digest: hashFromStr("1234"),
receiverTime: getNanosecondTime(10000),
senderTime: getNanosecondTime(0),
pubsubTopic: "zzzz")
noSenderTime3 = Index(digest: hashFromStr("1234"),
pubsubTopic: "zzzz",
)
noSenderTime3 = Index(
digest: hashFromStr("1234"),
receiverTime: getNanosecondTime(1200),
senderTime: getNanosecondTime(0),
pubsubTopic: "aaaa")
noSenderTime4 = Index(digest: hashFromStr("0"),
pubsubTopic: "aaaa",
)
noSenderTime4 = Index(
digest: hashFromStr("0"),
receiverTime: getNanosecondTime(1200),
senderTime: getNanosecondTime(0),
pubsubTopic: "zzzz")
pubsubTopic: "zzzz",
)
test "Index comparison":
# Index comparison with senderTime diff

View File

@ -1,9 +1,7 @@
{.used.}
import
std/[options, sequtils, algorithm],
testutils/unittests,
libp2p/protobuf/minprotobuf
std/[options, sequtils, algorithm], testutils/unittests, libp2p/protobuf/minprotobuf
import
../../../waku/waku_archive,
../../../waku/waku_archive/driver/queue_driver/queue_driver {.all.},
@ -12,28 +10,26 @@ import
../testlib/common,
../testlib/wakucore
proc getTestQueueDriver(numMessages: int): QueueDriver =
let testQueueDriver = QueueDriver.new(numMessages)
var data {.noinit.}: array[32, byte]
for x in data.mitems: x = 1
for x in data.mitems:
x = 1
for i in 0 ..< numMessages:
let msg = WakuMessage(payload: @[byte i], timestamp: Timestamp(i))
let index = Index(
receiverTime: Timestamp(i),
senderTime: Timestamp(i),
digest: MessageDigest(data: data)
digest: MessageDigest(data: data),
)
discard testQueueDriver.add(index, msg)
return testQueueDriver
procSuite "Queue driver - pagination":
let driver = getTestQueueDriver(10)
let
@ -157,7 +153,7 @@ procSuite "Queue driver - pagination":
pubsubTopic: DefaultPubsubTopic,
senderTime: msg.timestamp,
storeTime: msg.timestamp,
digest: computeDigest(msg)
digest: computeDigest(msg),
).toIndex()
let
@ -212,17 +208,19 @@ procSuite "Queue driver - pagination":
cursor: Option[Index] = none(Index)
forward = true
proc onlyEvenTimes(index: Index, msg: WakuMessage): bool = msg.timestamp.int64 mod 2 == 0
proc onlyEvenTimes(index: Index, msg: WakuMessage): bool =
msg.timestamp.int64 mod 2 == 0
## When
let page = driver.getPage(pageSize=pageSize, forward=forward, cursor=cursor, predicate=onlyEvenTimes)
let page = driver.getPage(
pageSize = pageSize, forward = forward, cursor = cursor, predicate = onlyEvenTimes
)
## Then
let data = page.tryGet().mapIt(it[1])
check:
data.mapIt(it.timestamp.int) == @[0, 2, 4]
test "Backward pagination - normal pagination":
## Given
let
@ -338,7 +336,7 @@ procSuite "Queue driver - pagination":
pubsubTopic: DefaultPubsubTopic,
senderTime: msg.timestamp,
storeTime: msg.timestamp,
digest: computeDigest(msg)
digest: computeDigest(msg),
).toIndex()
let
@ -393,10 +391,13 @@ procSuite "Queue driver - pagination":
cursor: Option[Index] = none(Index)
forward = false
proc onlyOddTimes(index: Index, msg: WakuMessage): bool = msg.timestamp.int64 mod 2 != 0
proc onlyOddTimes(index: Index, msg: WakuMessage): bool =
msg.timestamp.int64 mod 2 != 0
## When
let page = driver.getPage(pageSize=pageSize, forward=forward, cursor=cursor, predicate=onlyOddTimes)
let page = driver.getPage(
pageSize = pageSize, forward = forward, cursor = cursor, predicate = onlyOddTimes
)
## Then
let data = page.tryGet().mapIt(it[1])

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,6 @@
{.used.}
import
std/sequtils,
testutils/unittests,
chronos
import std/sequtils, testutils/unittests, chronos
import
../../../waku/common/databases/db_sqlite,
../../../waku/waku_archive,
@ -13,9 +10,7 @@ import
../testlib/common,
../testlib/wakucore
suite "SQLite driver":
test "init driver and database":
## Given
let database = newSqliteDatabase()
@ -44,7 +39,9 @@ suite "SQLite driver":
let msgHash = computeMessageHash(DefaultPubsubTopic, msg)
## When
let putRes = waitFor driver.put(DefaultPubsubTopic, msg, computeDigest(msg), msgHash, msg.timestamp)
let putRes = waitFor driver.put(
DefaultPubsubTopic, msg, computeDigest(msg), msgHash, msg.timestamp
)
## Then
check:
@ -55,8 +52,7 @@ suite "SQLite driver":
storedMsg.len == 1
storedMsg.all do(item: auto) -> bool:
let (pubsubTopic, msg, _, _, hash) = item
msg.contentTopic == contentTopic and
pubsubTopic == DefaultPubsubTopic and
msg.contentTopic == contentTopic and pubsubTopic == DefaultPubsubTopic and
hash == msgHash
## Cleanup

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,6 @@
{.used.}
import
std/[sequtils,times],
stew/results,
testutils/unittests,
chronos
import std/[sequtils, times], stew/results, testutils/unittests, chronos
import
../../../waku/common/databases/db_sqlite,
../../../waku/waku_core,
@ -18,9 +14,7 @@ import
../testlib/common,
../testlib/wakucore
suite "Waku Archive - Retention policy":
test "capacity retention policy - windowed message deletion":
## Given
let
@ -29,13 +23,24 @@ suite "Waku Archive - Retention policy":
let driver = newSqliteArchiveDriver()
let retentionPolicy: RetentionPolicy = CapacityRetentionPolicy.new(capacity=capacity)
let retentionPolicy: RetentionPolicy =
CapacityRetentionPolicy.new(capacity = capacity)
var putFutures = newSeq[Future[ArchiveDriverResult[void]]]()
## When
for i in 1 .. capacity + excess:
let msg = fakeWakuMessage(payload= @[byte i], contentTopic=DefaultContentTopic, ts=Timestamp(i))
putFutures.add(driver.put(DefaultPubsubTopic, msg, computeDigest(msg), computeMessageHash(DefaultPubsubTopic, msg), msg.timestamp))
let msg = fakeWakuMessage(
payload = @[byte i], contentTopic = DefaultContentTopic, ts = Timestamp(i)
)
putFutures.add(
driver.put(
DefaultPubsubTopic,
msg,
computeDigest(msg),
computeMessageHash(DefaultPubsubTopic, msg),
msg.timestamp,
)
)
discard waitFor allFinished(putFutures)
@ -77,8 +82,18 @@ suite "Waku Archive - Retention policy":
# create a number of messages so that the size of the DB overshoots
for i in 1 .. excess:
let msg = fakeWakuMessage(payload= @[byte i], contentTopic=DefaultContentTopic, ts=Timestamp(i))
putFutures.add(driver.put(DefaultPubsubTopic, msg, computeDigest(msg), computeMessageHash(DefaultPubsubTopic, msg), msg.timestamp))
let msg = fakeWakuMessage(
payload = @[byte i], contentTopic = DefaultContentTopic, ts = Timestamp(i)
)
putFutures.add(
driver.put(
DefaultPubsubTopic,
msg,
computeDigest(msg),
computeMessageHash(DefaultPubsubTopic, msg),
msg.timestamp,
)
)
# waitFor is used to synchronously wait for the futures to complete.
discard waitFor allFinished(putFutures)
@ -115,22 +130,31 @@ suite "Waku Archive - Retention policy":
let
driver = newSqliteArchiveDriver()
retentionPolicy: RetentionPolicy = CapacityRetentionPolicy.new(capacity=capacity)
retentionPolicy: RetentionPolicy =
CapacityRetentionPolicy.new(capacity = capacity)
let messages = @[
let messages =
@[
fakeWakuMessage(contentTopic = DefaultContentTopic, ts = ts(0)),
fakeWakuMessage(contentTopic = DefaultContentTopic, ts = ts(1)),
fakeWakuMessage(contentTopic = contentTopic, ts = ts(2)),
fakeWakuMessage(contentTopic = contentTopic, ts = ts(3)),
fakeWakuMessage(contentTopic = contentTopic, ts = ts(4)),
fakeWakuMessage(contentTopic = contentTopic, ts = ts(5)),
fakeWakuMessage(contentTopic=contentTopic, ts=ts(6))
fakeWakuMessage(contentTopic = contentTopic, ts = ts(6)),
]
## When
for msg in messages:
require (waitFor driver.put(DefaultPubsubTopic, msg, computeDigest(msg), computeMessageHash(DefaultPubsubTopic, msg), msg.timestamp)).isOk()
require (
waitFor driver.put(
DefaultPubsubTopic,
msg,
computeDigest(msg),
computeMessageHash(DefaultPubsubTopic, msg),
msg.timestamp,
)
).isOk()
require (waitFor retentionPolicy.execute(driver)).isOk()
## Then
@ -139,9 +163,7 @@ suite "Waku Archive - Retention policy":
storedMsg.len == capacity
storedMsg.all do(item: auto) -> bool:
let (pubsubTopic, msg, _, _, _) = item
msg.contentTopic == contentTopic and
pubsubTopic == DefaultPubsubTopic
msg.contentTopic == contentTopic and pubsubTopic == DefaultPubsubTopic
## Cleanup
(waitFor driver.close()).expect("driver to close")

View File

@ -18,9 +18,7 @@ import
../testlib/common,
../testlib/wakucore
suite "Waku Archive - message handling":
test "it should archive a valid and non-ephemeral message":
## Setup
let driver = newSqliteArchiveDriver()
@ -43,7 +41,8 @@ suite "Waku Archive - message handling":
let archive = newWakuArchive(driver)
## Given
let msgList = @[
let msgList =
@[
fakeWakuMessage(ephemeral = false, payload = "1"),
fakeWakuMessage(ephemeral = true, payload = "2"),
fakeWakuMessage(ephemeral = true, payload = "3"),
@ -83,7 +82,8 @@ suite "Waku Archive - message handling":
## Given
let
now = now()
invalidSenderTime = now + MaxMessageTimestampVariance + 1_000_000_000 # 1 second over the max variance
invalidSenderTime = now + MaxMessageTimestampVariance + 1_000_000_000
# 1 second over the max variance
let message = fakeWakuMessage(ts = invalidSenderTime)
@ -113,21 +113,41 @@ suite "Waku Archive - message handling":
check:
(waitFor driver.getMessagesCount()).tryGet() == 0
procSuite "Waku Archive - find messages":
## Fixtures
let timeOrigin = now()
let msgListA = @[
fakeWakuMessage(@[byte 00], contentTopic=ContentTopic("2"), ts=ts(00, timeOrigin)),
fakeWakuMessage(@[byte 01], contentTopic=ContentTopic("1"), ts=ts(10, timeOrigin)),
fakeWakuMessage(@[byte 02], contentTopic=ContentTopic("2"), ts=ts(20, timeOrigin)),
fakeWakuMessage(@[byte 03], contentTopic=ContentTopic("1"), ts=ts(30, timeOrigin)),
fakeWakuMessage(@[byte 04], contentTopic=ContentTopic("2"), ts=ts(40, timeOrigin)),
fakeWakuMessage(@[byte 05], contentTopic=ContentTopic("1"), ts=ts(50, timeOrigin)),
fakeWakuMessage(@[byte 06], contentTopic=ContentTopic("2"), ts=ts(60, timeOrigin)),
fakeWakuMessage(@[byte 07], contentTopic=ContentTopic("1"), ts=ts(70, timeOrigin)),
fakeWakuMessage(@[byte 08], contentTopic=ContentTopic("2"), ts=ts(80, timeOrigin)),
fakeWakuMessage(@[byte 09], contentTopic=ContentTopic("1"), ts=ts(90, timeOrigin))
let msgListA =
@[
fakeWakuMessage(
@[byte 00], contentTopic = ContentTopic("2"), ts = ts(00, timeOrigin)
),
fakeWakuMessage(
@[byte 01], contentTopic = ContentTopic("1"), ts = ts(10, timeOrigin)
),
fakeWakuMessage(
@[byte 02], contentTopic = ContentTopic("2"), ts = ts(20, timeOrigin)
),
fakeWakuMessage(
@[byte 03], contentTopic = ContentTopic("1"), ts = ts(30, timeOrigin)
),
fakeWakuMessage(
@[byte 04], contentTopic = ContentTopic("2"), ts = ts(40, timeOrigin)
),
fakeWakuMessage(
@[byte 05], contentTopic = ContentTopic("1"), ts = ts(50, timeOrigin)
),
fakeWakuMessage(
@[byte 06], contentTopic = ContentTopic("2"), ts = ts(60, timeOrigin)
),
fakeWakuMessage(
@[byte 07], contentTopic = ContentTopic("1"), ts = ts(70, timeOrigin)
),
fakeWakuMessage(
@[byte 08], contentTopic = ContentTopic("2"), ts = ts(80, timeOrigin)
),
fakeWakuMessage(
@[byte 09], contentTopic = ContentTopic("1"), ts = ts(90, timeOrigin)
),
]
let archiveA = block:
@ -136,7 +156,15 @@ procSuite "Waku Archive - find messages":
archive = newWakuArchive(driver)
for msg in msgListA:
require (waitFor driver.put(DefaultPubsubTopic, msg, computeDigest(msg), computeMessageHash(DefaultPubsubTopic, msg), msg.timestamp)).isOk()
require (
waitFor driver.put(
DefaultPubsubTopic,
msg,
computeDigest(msg),
computeMessageHash(DefaultPubsubTopic, msg),
msg.timestamp,
)
).isOk()
archive
@ -255,8 +283,7 @@ procSuite "Waku Archive - find messages":
## Given
# This query targets: pubsubtopic1 AND (contentTopic1 OR contentTopic3)
let req = ArchiveQuery(
pubsubTopic: some(pubsubTopic1),
contentTopics: @[contentTopic1, contentTopic3]
pubsubTopic: some(pubsubTopic1), contentTopics: @[contentTopic1, contentTopic3]
)
## When
@ -340,10 +367,7 @@ procSuite "Waku Archive - find messages":
test "handle query with forward pagination":
## Given
let req = ArchiveQuery(
pageSize: 4,
direction: PagingDirection.FORWARD
)
let req = ArchiveQuery(pageSize: 4, direction: PagingDirection.FORWARD)
## When
var nextReq = req # copy
@ -376,10 +400,7 @@ procSuite "Waku Archive - find messages":
test "handle query with backward pagination":
## Given
let req = ArchiveQuery(
pageSize: 4,
direction: PagingDirection.BACKWARD
)
let req = ArchiveQuery(pageSize: 4, direction: PagingDirection.BACKWARD)
## When
var nextReq = req # copy
@ -416,7 +437,8 @@ procSuite "Waku Archive - find messages":
driver = newSqliteArchiveDriver()
archive = newWakuArchive(driver)
let msgList = @[
let msgList =
@[
fakeWakuMessage(@[byte 0], contentTopic = ContentTopic("2")),
fakeWakuMessage(@[byte 1], contentTopic = DefaultContentTopic),
fakeWakuMessage(@[byte 2], contentTopic = DefaultContentTopic),
@ -426,11 +448,19 @@ procSuite "Waku Archive - find messages":
fakeWakuMessage(@[byte 6], contentTopic = DefaultContentTopic),
fakeWakuMessage(@[byte 7], contentTopic = DefaultContentTopic),
fakeWakuMessage(@[byte 8], contentTopic = DefaultContentTopic),
fakeWakuMessage(@[byte 9], contentTopic=ContentTopic("2"))
fakeWakuMessage(@[byte 9], contentTopic = ContentTopic("2")),
]
for msg in msgList:
require (waitFor driver.put(DefaultPubsubTopic, msg, computeDigest(msg), computeMessageHash(DefaultPubsubTopic, msg), msg.timestamp)).isOk()
require (
waitFor driver.put(
DefaultPubsubTopic,
msg,
computeDigest(msg),
computeMessageHash(DefaultPubsubTopic, msg),
msg.timestamp,
)
).isOk()
## Given
let req = ArchiveQuery(contentTopics: @[DefaultContentTopic])
@ -455,7 +485,7 @@ procSuite "Waku Archive - find messages":
contentTopics: @[ContentTopic("1")],
startTime: some(ts(15, timeOrigin)),
endTime: some(ts(55, timeOrigin)),
direction: PagingDirection.FORWARD
direction: PagingDirection.FORWARD,
)
## When
@ -475,7 +505,7 @@ procSuite "Waku Archive - find messages":
let req = ArchiveQuery(
contentTopics: @[ContentTopic("1")],
startTime: some(Timestamp(2)),
endTime: some(Timestamp(2))
endTime: some(Timestamp(2)),
)
## When
@ -494,7 +524,7 @@ procSuite "Waku Archive - find messages":
let req = ArchiveQuery(
contentTopics: @[ContentTopic("1")],
startTime: some(Timestamp(5)),
endTime: some(Timestamp(2))
endTime: some(Timestamp(2)),
)
## When

Some files were not shown because too many files have changed in this diff Show More