mirror of
https://github.com/logos-messaging/logos-messaging-nim.git
synced 2026-01-02 05:53:11 +00:00
feat: Waku API create node (#3580)
* introduce createNode # Conflicts: # apps/wakunode2/cli_args.nim * remove confutils dependency on the library * test: remove websocket in default test config * update to latest specs * test: cli_args * align to spec changes (sovereign, message conf, entrypoints * accept enr, entree and multiaddr as entry points * post rebase * format * change from "sovereign" to "core" * add example * get example to continue running * nitpicks * idiomatic constructors * fix enum naming * replace procs with consts * remove messageConfirmation * use pure enum * rename example file
This commit is contained in:
parent
08d14fb082
commit
bc8acf7611
@ -14,8 +14,8 @@ import
|
||||
libp2p/wire
|
||||
|
||||
import
|
||||
../../tools/confutils/cli_args,
|
||||
waku/[
|
||||
factory/external_config,
|
||||
node/peer_manager,
|
||||
waku_lightpush/common,
|
||||
waku_relay,
|
||||
|
||||
@ -11,11 +11,11 @@ import
|
||||
confutils
|
||||
|
||||
import
|
||||
../../tools/confutils/cli_args,
|
||||
waku/[
|
||||
common/enr,
|
||||
common/logging,
|
||||
factory/waku as waku_factory,
|
||||
factory/external_config,
|
||||
waku_node,
|
||||
node/waku_metrics,
|
||||
node/peer_manager,
|
||||
|
||||
@ -11,8 +11,8 @@ import
|
||||
libp2p/wire
|
||||
|
||||
import
|
||||
../wakunode2/cli_args,
|
||||
waku/[
|
||||
factory/external_config,
|
||||
common/enr,
|
||||
waku_node,
|
||||
node/peer_manager,
|
||||
|
||||
@ -12,14 +12,9 @@ import
|
||||
secp256k1
|
||||
|
||||
import
|
||||
waku/[
|
||||
common/confutils/envvar/defs as confEnvvarDefs,
|
||||
common/confutils/envvar/std/net as confEnvvarNet,
|
||||
common/logging,
|
||||
factory/external_config,
|
||||
waku_core,
|
||||
waku_core/topics/pubsub_topic,
|
||||
]
|
||||
../../tools/confutils/
|
||||
[cli_args, envvar as confEnvvarDefs, envvar_net as confEnvvarNet],
|
||||
waku/[common/logging, waku_core, waku_core/topics/pubsub_topic]
|
||||
|
||||
export confTomlDefs, confTomlNet, confEnvvarDefs, confEnvvarNet
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import results, options, chronos
|
||||
import waku/[waku_node, waku_core, waku_lightpush]
|
||||
import waku/[waku_node, waku_core, waku_lightpush, waku_lightpush/common]
|
||||
import publisher_base
|
||||
|
||||
type V3Publisher* = ref object of PublisherBase
|
||||
|
||||
@ -9,13 +9,13 @@ import
|
||||
system/ansi_c,
|
||||
libp2p/crypto/crypto
|
||||
import
|
||||
../../tools/rln_keystore_generator/rln_keystore_generator,
|
||||
../../tools/[rln_keystore_generator/rln_keystore_generator, confutils/cli_args],
|
||||
waku/[
|
||||
common/logging,
|
||||
factory/external_config,
|
||||
factory/waku,
|
||||
node/health_monitor,
|
||||
waku_api/rest/builder as rest_server_builder,
|
||||
waku_core/message/default_values,
|
||||
]
|
||||
|
||||
logScope:
|
||||
|
||||
@ -7,9 +7,21 @@ Make all examples.
|
||||
make example2
|
||||
```
|
||||
|
||||
## basic2
|
||||
## Waku API
|
||||
|
||||
TODO
|
||||
Uses the simplified Waku API to create and start a node,
|
||||
you need an RPC endpoint for Linea Sepolia for RLN:
|
||||
|
||||
```console
|
||||
./build/waku_api --ethRpcEndpoint=https://linea-sepolia.infura.io/v3/<your key>
|
||||
```
|
||||
|
||||
If you can't be bothered but still want to see some action,
|
||||
just run the binary and it will use a non-RLN network:
|
||||
|
||||
```console
|
||||
./build/waku_api
|
||||
```
|
||||
|
||||
## publisher/subscriber
|
||||
|
||||
|
||||
38
examples/waku_example.nim
Normal file
38
examples/waku_example.nim
Normal file
@ -0,0 +1,38 @@
|
||||
import std/options
|
||||
import chronos, results, confutils, confutils/defs
|
||||
import waku
|
||||
|
||||
type CliArgs = object
|
||||
ethRpcEndpoint* {.
|
||||
defaultValue: "", desc: "ETH RPC Endpoint, if passed, RLN is enabled"
|
||||
.}: string
|
||||
|
||||
when isMainModule:
|
||||
let args = CliArgs.load()
|
||||
|
||||
echo "Starting Waku node..."
|
||||
|
||||
let config =
|
||||
if (args.ethRpcEndpoint == ""):
|
||||
# Create a basic configuration for the Waku node
|
||||
# No RLN as we don't have an ETH RPC Endpoint
|
||||
NodeConfig.init(wakuConfig = WakuConfig.init(entryNodes = @[], clusterId = 42))
|
||||
else:
|
||||
# Connect to TWN, use ETH RPC Endpoint for RLN
|
||||
NodeConfig.init(ethRpcEndpoints = @[args.ethRpcEndpoint])
|
||||
|
||||
# Create the node using the library API's createNode function
|
||||
let node = (waitFor createNode(config)).valueOr:
|
||||
echo "Failed to create node: ", error
|
||||
quit(QuitFailure)
|
||||
|
||||
echo("Waku node created successfully!")
|
||||
|
||||
# Start the node
|
||||
(waitFor startWaku(addr node)).isOkOr:
|
||||
echo "Failed to start node: ", error
|
||||
quit(QuitFailure)
|
||||
|
||||
echo "Node started successfully!"
|
||||
|
||||
runForever()
|
||||
@ -1,6 +1,7 @@
|
||||
{.push raises: [].}
|
||||
|
||||
import waku/[common/logging, factory/[waku, networks_config, external_config]]
|
||||
import ../../apps/wakunode2/cli_args
|
||||
import waku/[common/logging, factory/[waku, networks_config]]
|
||||
import
|
||||
std/[options, strutils, os, sequtils],
|
||||
chronicles,
|
||||
|
||||
@ -3,7 +3,7 @@ import chronos, chronicles, results, confutils, confutils/std/net
|
||||
|
||||
import
|
||||
../../../waku/node/peer_manager/peer_manager,
|
||||
../../../waku/factory/external_config,
|
||||
../../../tools/confutils/cli_args,
|
||||
../../../waku/factory/waku,
|
||||
../../../waku/factory/node_factory,
|
||||
../../../waku/factory/networks_config,
|
||||
|
||||
@ -2,7 +2,8 @@ import std/[net, sequtils, strutils]
|
||||
import chronicles, chronos, stew/byteutils, results
|
||||
import
|
||||
../../../../waku/waku_core/message/message,
|
||||
../../../../waku/factory/[external_config, validator_signed, waku],
|
||||
../../../../waku/factory/[validator_signed, waku],
|
||||
../../../../tools/confutils/cli_args,
|
||||
../../../../waku/waku_node,
|
||||
../../../../waku/waku_core/message,
|
||||
../../../../waku/waku_core/time, # Timestamp
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
## Waku v2
|
||||
|
||||
import ./test_waku
|
||||
|
||||
# Waku core test suite
|
||||
import
|
||||
./waku_core/test_namespaced_topics,
|
||||
@ -96,3 +98,9 @@ import ./waku_rln_relay/test_all
|
||||
|
||||
# Node Factory
|
||||
import ./factory/test_all
|
||||
|
||||
# Waku API tests
|
||||
import ./api/test_all
|
||||
|
||||
# Waku tools tests
|
||||
import ./tools/test_all
|
||||
|
||||
3
tests/api/test_all.nim
Normal file
3
tests/api/test_all.nim
Normal file
@ -0,0 +1,3 @@
|
||||
{.used.}
|
||||
|
||||
import ./test_entry_nodes, ./test_node_conf
|
||||
264
tests/api/test_entry_nodes.nim
Normal file
264
tests/api/test_entry_nodes.nim
Normal file
@ -0,0 +1,264 @@
|
||||
{.used.}
|
||||
|
||||
import std/options, results, testutils/unittests
|
||||
|
||||
import waku/api/entry_nodes
|
||||
|
||||
# Since classifyEntryNode is internal, we test it indirectly through processEntryNodes behavior
|
||||
# The enum is exported so we can test against it
|
||||
|
||||
suite "Entry Nodes Classification":
|
||||
test "Process ENRTree - standard format":
|
||||
let result = processEntryNodes(
|
||||
@[
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im"
|
||||
]
|
||||
)
|
||||
check:
|
||||
result.isOk()
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 1
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 0
|
||||
|
||||
test "Process ENRTree - case insensitive":
|
||||
let result = processEntryNodes(
|
||||
@[
|
||||
"ENRTREE://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im"
|
||||
]
|
||||
)
|
||||
check:
|
||||
result.isOk()
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 1
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 0
|
||||
|
||||
test "Process ENR - standard format":
|
||||
let result = processEntryNodes(
|
||||
@[
|
||||
"enr:-QESuEC1p_s3xJzAC_XlOuuNrhVUETmfhbm1wxRGis0f7DlqGSw2FM-p2Vn7gmfkTTnAe8Ys2cgGBN8ufJnvzKQFZqFMBgmlkgnY0iXNlY3AyNTZrMaEDS8-D878DrdbNwcuY-3p1qdDp5MOoCurhdsNPJTXZ3c5g3RjcIJ2X4N1ZHCCd2g"
|
||||
]
|
||||
)
|
||||
check:
|
||||
result.isOk()
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 0
|
||||
bootstrapEnrs.len == 1
|
||||
staticNodes.len == 0
|
||||
|
||||
test "Process ENR - case insensitive":
|
||||
let result = processEntryNodes(
|
||||
@[
|
||||
"ENR:-QESuEC1p_s3xJzAC_XlOuuNrhVUETmfhbm1wxRGis0f7DlqGSw2FM-p2Vn7gmfkTTnAe8Ys2cgGBN8ufJnvzKQFZqFMBgmlkgnY0iXNlY3AyNTZrMaEDS8-D878DrdbNwcuY-3p1qdDp5MOoCurhdsNPJTXZ3c5g3RjcIJ2X4N1ZHCCd2g"
|
||||
]
|
||||
)
|
||||
check:
|
||||
result.isOk()
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 0
|
||||
bootstrapEnrs.len == 1
|
||||
staticNodes.len == 0
|
||||
|
||||
test "Process Multiaddress - IPv4":
|
||||
let result = processEntryNodes(
|
||||
@[
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc"
|
||||
]
|
||||
)
|
||||
check:
|
||||
result.isOk()
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 0
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 1
|
||||
|
||||
test "Process Multiaddress - IPv6":
|
||||
let result = processEntryNodes(
|
||||
@["/ip6/::1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc"]
|
||||
)
|
||||
check:
|
||||
result.isOk()
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 0
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 1
|
||||
|
||||
test "Process Multiaddress - DNS":
|
||||
let result = processEntryNodes(
|
||||
@[
|
||||
"/dns4/example.com/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc"
|
||||
]
|
||||
)
|
||||
check:
|
||||
result.isOk()
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 0
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 1
|
||||
|
||||
test "Process empty string":
|
||||
let result = processEntryNodes(@[""])
|
||||
check:
|
||||
result.isErr()
|
||||
result.error == "Entry node error: Empty entry node address"
|
||||
|
||||
test "Process invalid format - HTTP URL":
|
||||
let result = processEntryNodes(@["http://example.com"])
|
||||
check:
|
||||
result.isErr()
|
||||
result.error ==
|
||||
"Entry node error: Unrecognized entry node format. Must start with 'enrtree:', 'enr:', or '/'"
|
||||
|
||||
test "Process invalid format - some string":
|
||||
let result = processEntryNodes(@["some-string-here"])
|
||||
check:
|
||||
result.isErr()
|
||||
result.error ==
|
||||
"Entry node error: Unrecognized entry node format. Must start with 'enrtree:', 'enr:', or '/'"
|
||||
|
||||
suite "Entry Nodes Processing":
|
||||
test "Process mixed entry nodes":
|
||||
let entryNodes =
|
||||
@[
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im",
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc",
|
||||
"enr:-QESuEC1p_s3xJzAC_XlOuuNrhVUETmfhbm1wxRGis0f7DlqGSw2FM-p2Vn7gmfkTTnAe8Ys2cgGBN8ufJnvzKQFZqFMBgmlkgnY0iXNlY3AyNTZrMaEDS8-D878DrdbNwcuY-3p1qdDp5MOoCurhdsNPJTXZ3c5g3RjcIJ2X4N1ZHCCd2g",
|
||||
]
|
||||
|
||||
let result = processEntryNodes(entryNodes)
|
||||
check:
|
||||
result.isOk()
|
||||
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 1 # enrtree
|
||||
bootstrapEnrs.len == 1 # enr
|
||||
staticNodes.len >= 1 # at least the multiaddr
|
||||
enrTreeUrls[0] == entryNodes[0] # enrtree unchanged
|
||||
bootstrapEnrs[0] == entryNodes[2] # enr unchanged
|
||||
staticNodes[0] == entryNodes[1] # multiaddr added to static
|
||||
|
||||
test "Process only ENRTree nodes":
|
||||
let entryNodes =
|
||||
@[
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im",
|
||||
"enrtree://ANOTHER_TREE@example.com",
|
||||
]
|
||||
|
||||
let result = processEntryNodes(entryNodes)
|
||||
check:
|
||||
result.isOk()
|
||||
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 2
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 0
|
||||
enrTreeUrls == entryNodes
|
||||
|
||||
test "Process only multiaddresses":
|
||||
let entryNodes =
|
||||
@[
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc",
|
||||
"/ip4/192.168.1.1/tcp/60001/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYd",
|
||||
]
|
||||
|
||||
let result = processEntryNodes(entryNodes)
|
||||
check:
|
||||
result.isOk()
|
||||
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 0
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 2
|
||||
staticNodes == entryNodes
|
||||
|
||||
test "Process only ENR nodes":
|
||||
let entryNodes =
|
||||
@[
|
||||
"enr:-QESuEC1p_s3xJzAC_XlOuuNrhVUETmfhbm1wxRGis0f7DlqGSw2FM-p2Vn7gmfkTTnAe8Ys2cgGBN8ufJnvzKQFZqFMBgmlkgnY0iXNlY3AyNTZrMaEDS8-D878DrdbNwcuY-3p1qdDp5MOoCurhdsNPJTXZ3c5g3RjcIJ2X4N1ZHCCd2g",
|
||||
"enr:-QEkuECnZ3IbVAgkOzv-QLnKC4dRKAPRY80m1-R7G8jZ7yfT3ipEfBrhKN7ARcQgQ-vg-h40AQzyvAkPYlHPaFKk6u9MBgmlkgnY0iXNlY3AyNTZrMaEDk49D8JjMSns4p1XVNBvJquOUzT4PENSJknkROspfAFGg3RjcIJ2X4N1ZHCCd2g",
|
||||
]
|
||||
|
||||
let result = processEntryNodes(entryNodes)
|
||||
check:
|
||||
result.isOk()
|
||||
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 0
|
||||
bootstrapEnrs.len == 2
|
||||
staticNodes.len == 0
|
||||
bootstrapEnrs == entryNodes
|
||||
# Note: staticNodes may or may not be populated depending on ENR parsing
|
||||
|
||||
test "Process empty list":
|
||||
let entryNodes: seq[string] = @[]
|
||||
|
||||
let result = processEntryNodes(entryNodes)
|
||||
check:
|
||||
result.isOk()
|
||||
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 0
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 0
|
||||
|
||||
test "Process with invalid entry":
|
||||
let entryNodes = @["enrtree://VALID@example.com", "invalid://notvalid"]
|
||||
|
||||
let result = processEntryNodes(entryNodes)
|
||||
check:
|
||||
result.isErr()
|
||||
result.error ==
|
||||
"Entry node error: Unrecognized entry node format. Must start with 'enrtree:', 'enr:', or '/'"
|
||||
|
||||
test "Process different multiaddr formats":
|
||||
let entryNodes =
|
||||
@[
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc",
|
||||
"/ip6/::1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYd",
|
||||
"/dns4/example.com/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYe",
|
||||
"/dns/node.example.org/tcp/443/wss/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYf",
|
||||
]
|
||||
|
||||
let result = processEntryNodes(entryNodes)
|
||||
check:
|
||||
result.isOk()
|
||||
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
enrTreeUrls.len == 0
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 4
|
||||
staticNodes == entryNodes
|
||||
|
||||
test "Process with duplicate entries":
|
||||
let entryNodes =
|
||||
@[
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc",
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc",
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im",
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im",
|
||||
]
|
||||
|
||||
let result = processEntryNodes(entryNodes)
|
||||
check:
|
||||
result.isOk()
|
||||
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodes) = result.get()
|
||||
check:
|
||||
# Duplicates are not filtered out (by design - let downstream handle it)
|
||||
enrTreeUrls.len == 2
|
||||
bootstrapEnrs.len == 0
|
||||
staticNodes.len == 2
|
||||
277
tests/api/test_node_conf.nim
Normal file
277
tests/api/test_node_conf.nim
Normal file
@ -0,0 +1,277 @@
|
||||
{.used.}
|
||||
|
||||
import std/options, results, stint, testutils/unittests
|
||||
import waku/api/api_conf, waku/factory/waku_conf, waku/factory/networks_config
|
||||
|
||||
suite "LibWaku Conf - toWakuConf":
|
||||
test "Minimal configuration":
|
||||
## Given
|
||||
let nodeConfig = NodeConfig.init(ethRpcEndpoints = @["http://someaddress"])
|
||||
|
||||
## When
|
||||
let wakuConfRes = toWakuConf(nodeConfig)
|
||||
|
||||
## Then
|
||||
let wakuConf = wakuConfRes.valueOr:
|
||||
raiseAssert error
|
||||
wakuConf.validate().isOkOr:
|
||||
raiseAssert error
|
||||
check:
|
||||
wakuConf.clusterId == 1
|
||||
wakuConf.shardingConf.numShardsInCluster == 8
|
||||
wakuConf.staticNodes.len == 0
|
||||
|
||||
test "Core mode configuration":
|
||||
## Given
|
||||
let wakuConfig = WakuConfig.init(entryNodes = @[], clusterId = 1)
|
||||
|
||||
let nodeConfig = NodeConfig.init(mode = Core, wakuConfig = wakuConfig)
|
||||
|
||||
## When
|
||||
let wakuConfRes = toWakuConf(nodeConfig)
|
||||
|
||||
## Then
|
||||
require wakuConfRes.isOk()
|
||||
let wakuConf = wakuConfRes.get()
|
||||
require wakuConf.validate().isOk()
|
||||
check:
|
||||
wakuConf.relay == true
|
||||
wakuConf.lightPush == true
|
||||
wakuConf.peerExchangeService == true
|
||||
wakuConf.clusterId == 1
|
||||
|
||||
test "Auto-sharding configuration":
|
||||
## Given
|
||||
let nodeConfig = NodeConfig.init(
|
||||
mode = Core,
|
||||
wakuConfig = WakuConfig.init(
|
||||
entryNodes = @[],
|
||||
staticStoreNodes = @[],
|
||||
clusterId = 42,
|
||||
autoShardingConfig = AutoShardingConfig(numShardsInCluster: 16),
|
||||
),
|
||||
)
|
||||
|
||||
## When
|
||||
let wakuConfRes = toWakuConf(nodeConfig)
|
||||
|
||||
## Then
|
||||
require wakuConfRes.isOk()
|
||||
let wakuConf = wakuConfRes.get()
|
||||
require wakuConf.validate().isOk()
|
||||
check:
|
||||
wakuConf.clusterId == 42
|
||||
wakuConf.shardingConf.numShardsInCluster == 16
|
||||
|
||||
test "Bootstrap nodes configuration":
|
||||
## Given
|
||||
let entryNodes =
|
||||
@[
|
||||
"enr:-QESuEC1p_s3xJzAC_XlOuuNrhVUETmfhbm1wxRGis0f7DlqGSw2FM-p2Vn7gmfkTTnAe8Ys2cgGBN8ufJnvzKQFZqFMBgmlkgnY0iXNlY3AyNTZrMaEDS8-D878DrdbNwcuY-3p1qdDp5MOoCurhdsNPJTXZ3c5g3RjcIJ2X4N1ZHCCd2g",
|
||||
"enr:-QEkuECnZ3IbVAgkOzv-QLnKC4dRKAPRY80m1-R7G8jZ7yfT3ipEfBrhKN7ARcQgQ-vg-h40AQzyvAkPYlHPaFKk6u9MBgmlkgnY0iXNlY3AyNTZrMaEDk49D8JjMSns4p1XVNBvJquOUzT4PENSJknkROspfAFGg3RjcIJ2X4N1ZHCCd2g",
|
||||
]
|
||||
let libConf = NodeConfig.init(
|
||||
mode = Core,
|
||||
wakuConfig =
|
||||
WakuConfig.init(entryNodes = entryNodes, staticStoreNodes = @[], clusterId = 1),
|
||||
)
|
||||
|
||||
## When
|
||||
let wakuConfRes = toWakuConf(libConf)
|
||||
|
||||
## Then
|
||||
require wakuConfRes.isOk()
|
||||
let wakuConf = wakuConfRes.get()
|
||||
require wakuConf.validate().isOk()
|
||||
require wakuConf.discv5Conf.isSome()
|
||||
check:
|
||||
wakuConf.discv5Conf.get().bootstrapNodes == entryNodes
|
||||
|
||||
test "Static store nodes configuration":
|
||||
## Given
|
||||
let staticStoreNodes =
|
||||
@[
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc",
|
||||
"/ip4/192.168.1.1/tcp/60001/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYd",
|
||||
]
|
||||
let nodeConf = NodeConfig.init(
|
||||
wakuConfig = WakuConfig.init(
|
||||
entryNodes = @[], staticStoreNodes = staticStoreNodes, clusterId = 1
|
||||
)
|
||||
)
|
||||
|
||||
## When
|
||||
let wakuConfRes = toWakuConf(nodeConf)
|
||||
|
||||
## Then
|
||||
require wakuConfRes.isOk()
|
||||
let wakuConf = wakuConfRes.get()
|
||||
require wakuConf.validate().isOk()
|
||||
check:
|
||||
wakuConf.staticNodes == staticStoreNodes
|
||||
|
||||
test "Message validation with max message size":
|
||||
## Given
|
||||
let nodeConfig = NodeConfig.init(
|
||||
wakuConfig = WakuConfig.init(
|
||||
entryNodes = @[],
|
||||
staticStoreNodes = @[],
|
||||
clusterId = 1,
|
||||
messageValidation =
|
||||
MessageValidation(maxMessageSize: "100KiB", rlnConfig: none(RlnConfig)),
|
||||
)
|
||||
)
|
||||
|
||||
## When
|
||||
let wakuConfRes = toWakuConf(nodeConfig)
|
||||
|
||||
## Then
|
||||
require wakuConfRes.isOk()
|
||||
let wakuConf = wakuConfRes.get()
|
||||
require wakuConf.validate().isOk()
|
||||
check:
|
||||
wakuConf.maxMessageSizeBytes == 100'u64 * 1024'u64
|
||||
|
||||
test "Message validation with RLN config":
|
||||
## Given
|
||||
let nodeConfig = NodeConfig.init(
|
||||
wakuConfig = WakuConfig.init(
|
||||
entryNodes = @[],
|
||||
clusterId = 1,
|
||||
messageValidation = MessageValidation(
|
||||
maxMessageSize: "150 KiB",
|
||||
rlnConfig: some(
|
||||
RlnConfig(
|
||||
contractAddress: "0x1234567890123456789012345678901234567890",
|
||||
chainId: 1'u,
|
||||
epochSizeSec: 600'u64,
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
ethRpcEndpoints = @["http://127.0.0.1:1111"],
|
||||
)
|
||||
|
||||
## When
|
||||
let wakuConf = toWakuConf(nodeConfig).valueOr:
|
||||
raiseAssert error
|
||||
|
||||
wakuConf.validate().isOkOr:
|
||||
raiseAssert error
|
||||
|
||||
check:
|
||||
wakuConf.maxMessageSizeBytes == 150'u64 * 1024'u64
|
||||
|
||||
require wakuConf.rlnRelayConf.isSome()
|
||||
let rlnConf = wakuConf.rlnRelayConf.get()
|
||||
check:
|
||||
rlnConf.dynamic == true
|
||||
rlnConf.ethContractAddress == "0x1234567890123456789012345678901234567890"
|
||||
rlnConf.chainId == 1'u256
|
||||
rlnConf.epochSizeSec == 600'u64
|
||||
|
||||
test "Full Core mode configuration with all fields":
|
||||
## Given
|
||||
let nodeConfig = NodeConfig.init(
|
||||
mode = Core,
|
||||
wakuConfig = WakuConfig.init(
|
||||
entryNodes =
|
||||
@[
|
||||
"enr:-QESuEC1p_s3xJzAC_XlOuuNrhVUETmfhbm1wxRGis0f7DlqGSw2FM-p2Vn7gmfkTTnAe8Ys2cgGBN8ufJnvzKQFZqFMBgmlkgnY0iXNlY3AyNTZrMaEDS8-D878DrdbNwcuY-3p1qdDp5MOoCurhdsNPJTXZ3c5g3RjcIJ2X4N1ZHCCd2g"
|
||||
],
|
||||
staticStoreNodes =
|
||||
@[
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc"
|
||||
],
|
||||
clusterId = 99,
|
||||
autoShardingConfig = AutoShardingConfig(numShardsInCluster: 12),
|
||||
messageValidation = MessageValidation(
|
||||
maxMessageSize: "512KiB",
|
||||
rlnConfig: some(
|
||||
RlnConfig(
|
||||
contractAddress: "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
||||
chainId: 5'u, # Goerli
|
||||
epochSizeSec: 300'u64,
|
||||
)
|
||||
),
|
||||
),
|
||||
),
|
||||
ethRpcEndpoints = @["https://127.0.0.1:8333"],
|
||||
)
|
||||
|
||||
## When
|
||||
let wakuConfRes = toWakuConf(nodeConfig)
|
||||
|
||||
## Then
|
||||
let wakuConf = wakuConfRes.valueOr:
|
||||
raiseAssert error
|
||||
wakuConf.validate().isOkOr:
|
||||
raiseAssert error
|
||||
|
||||
# Check basic settings
|
||||
check:
|
||||
wakuConf.relay == true
|
||||
wakuConf.lightPush == true
|
||||
wakuConf.peerExchangeService == true
|
||||
wakuConf.rendezvous == true
|
||||
wakuConf.clusterId == 99
|
||||
|
||||
# Check sharding
|
||||
check:
|
||||
wakuConf.shardingConf.numShardsInCluster == 12
|
||||
|
||||
# Check bootstrap nodes
|
||||
require wakuConf.discv5Conf.isSome()
|
||||
check:
|
||||
wakuConf.discv5Conf.get().bootstrapNodes.len == 1
|
||||
|
||||
# Check static nodes
|
||||
check:
|
||||
wakuConf.staticNodes.len == 1
|
||||
wakuConf.staticNodes[0] ==
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc"
|
||||
|
||||
# Check message validation
|
||||
check:
|
||||
wakuConf.maxMessageSizeBytes == 512'u64 * 1024'u64
|
||||
|
||||
# Check RLN config
|
||||
require wakuConf.rlnRelayConf.isSome()
|
||||
let rlnConf = wakuConf.rlnRelayConf.get()
|
||||
check:
|
||||
rlnConf.dynamic == true
|
||||
rlnConf.ethContractAddress == "0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
||||
rlnConf.chainId == 5'u256
|
||||
rlnConf.epochSizeSec == 300'u64
|
||||
|
||||
test "NodeConfig with mixed entry nodes (integration test)":
|
||||
## Given
|
||||
let entryNodes =
|
||||
@[
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im",
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc",
|
||||
]
|
||||
|
||||
let nodeConfig = NodeConfig.init(
|
||||
mode = Core,
|
||||
wakuConfig =
|
||||
WakuConfig.init(entryNodes = entryNodes, staticStoreNodes = @[], clusterId = 1),
|
||||
)
|
||||
|
||||
## When
|
||||
let wakuConfRes = toWakuConf(nodeConfig)
|
||||
|
||||
## Then
|
||||
require wakuConfRes.isOk()
|
||||
let wakuConf = wakuConfRes.get()
|
||||
require wakuConf.validate().isOk()
|
||||
|
||||
# Check that ENRTree went to DNS discovery
|
||||
require wakuConf.dnsDiscoveryConf.isSome()
|
||||
check:
|
||||
wakuConf.dnsDiscoveryConf.get().enrTreeUrl == entryNodes[0]
|
||||
|
||||
# Check that multiaddr went to static nodes
|
||||
check:
|
||||
wakuConf.staticNodes.len == 1
|
||||
wakuConf.staticNodes[0] == entryNodes[1]
|
||||
@ -2,9 +2,7 @@
|
||||
|
||||
import
|
||||
./test_base64_codec,
|
||||
./test_confutils_envvar,
|
||||
./test_enr_builder,
|
||||
./test_envvar_serialization,
|
||||
./test_protobuf_validation,
|
||||
./test_sqlite_migrations,
|
||||
./test_parse_size,
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
{.used.}
|
||||
|
||||
import ./test_external_config, ./test_node_factory, ./test_waku_conf
|
||||
import ./test_waku_conf, ./test_node_factory
|
||||
|
||||
@ -4,9 +4,10 @@ import testutils/unittests, chronos, libp2p/protocols/connectivity/relay/relay
|
||||
|
||||
import
|
||||
../testlib/wakunode,
|
||||
waku/factory/node_factory,
|
||||
waku/waku_node,
|
||||
waku/factory/conf_builder/conf_builder
|
||||
waku/factory/node_factory,
|
||||
waku/factory/conf_builder/conf_builder,
|
||||
waku/factory/conf_builder/web_socket_conf_builder
|
||||
|
||||
suite "Node Factory":
|
||||
asynctest "Set up a node based on default configurations":
|
||||
@ -48,8 +49,9 @@ asynctest "Set up a node with Filter enabled":
|
||||
check:
|
||||
not node.isNil()
|
||||
not node.wakuFilter.isNil()
|
||||
echo "TEST END"
|
||||
|
||||
asynctest "Start a node based on default configurations":
|
||||
asynctest "Start a node based on default test configuration":
|
||||
let conf = defaultTestWakuConf()
|
||||
|
||||
let node = (await setupNode(conf, relay = Relay.new())).valueOr:
|
||||
|
||||
91
tests/test_waku.nim
Normal file
91
tests/test_waku.nim
Normal file
@ -0,0 +1,91 @@
|
||||
{.used.}
|
||||
|
||||
import chronos, testutils/unittests, std/options
|
||||
|
||||
import waku
|
||||
|
||||
suite "Waku API - Create node":
|
||||
asyncTest "Create node with minimal configuration":
|
||||
## Given
|
||||
let nodeConfig =
|
||||
NodeConfig.init(wakuConfig = WakuConfig.init(entryNodes = @[], clusterId = 1))
|
||||
|
||||
# This is the actual minimal config but as the node auto-start, it is not suitable for tests
|
||||
# NodeConfig.init(ethRpcEndpoints = @["http://someaddress"])
|
||||
|
||||
## When
|
||||
let node = (await createNode(nodeConfig)).valueOr:
|
||||
raiseAssert error
|
||||
|
||||
## Then
|
||||
check:
|
||||
not node.isNil()
|
||||
node.conf.clusterId == 1
|
||||
node.conf.relay == true
|
||||
|
||||
asyncTest "Create node with full configuration":
|
||||
## Given
|
||||
let nodeConfig = NodeConfig.init(
|
||||
mode = Core,
|
||||
wakuConfig = WakuConfig.init(
|
||||
entryNodes =
|
||||
@[
|
||||
"enr:-QESuEC1p_s3xJzAC_XlOuuNrhVUETmfhbm1wxRGis0f7DlqGSw2FM-p2Vn7gmfkTTnAe8Ys2cgGBN8ufJnvzKQFZqFMBgmlkgnY0iXNlY3AyNTZrMaEDS8-D878DrdbNwcuY-3p1qdDp5MOoCurhdsNPJTXZ3c5g3RjcIJ2X4N1ZHCCd2g"
|
||||
],
|
||||
staticStoreNodes =
|
||||
@[
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc"
|
||||
],
|
||||
clusterId = 99,
|
||||
autoShardingConfig = AutoShardingConfig(numShardsInCluster: 16),
|
||||
messageValidation =
|
||||
MessageValidation(maxMessageSize: "1024 KiB", rlnConfig: none(RlnConfig)),
|
||||
),
|
||||
)
|
||||
|
||||
## When
|
||||
let node = (await createNode(nodeConfig)).valueOr:
|
||||
raiseAssert error
|
||||
|
||||
## Then
|
||||
check:
|
||||
not node.isNil()
|
||||
node.conf.clusterId == 99
|
||||
node.conf.shardingConf.numShardsInCluster == 16
|
||||
node.conf.maxMessageSizeBytes == 1024'u64 * 1024'u64
|
||||
node.conf.staticNodes.len == 1
|
||||
node.conf.relay == true
|
||||
node.conf.lightPush == true
|
||||
node.conf.peerExchangeService == true
|
||||
node.conf.rendezvous == true
|
||||
|
||||
asyncTest "Create node with mixed entry nodes (enrtree, multiaddr)":
|
||||
## Given
|
||||
let nodeConfig = NodeConfig.init(
|
||||
mode = Core,
|
||||
wakuConfig = WakuConfig.init(
|
||||
entryNodes =
|
||||
@[
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im",
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc",
|
||||
],
|
||||
clusterId = 42,
|
||||
),
|
||||
)
|
||||
|
||||
## When
|
||||
let node = (await createNode(nodeConfig)).valueOr:
|
||||
raiseAssert error
|
||||
|
||||
## Then
|
||||
check:
|
||||
not node.isNil()
|
||||
node.conf.clusterId == 42
|
||||
# ENRTree should go to DNS discovery
|
||||
node.conf.dnsDiscoveryConf.isSome()
|
||||
node.conf.dnsDiscoveryConf.get().enrTreeUrl ==
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im"
|
||||
# Multiaddr should go to static nodes
|
||||
node.conf.staticNodes.len == 1
|
||||
node.conf.staticNodes[0] ==
|
||||
"/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc"
|
||||
@ -4,7 +4,10 @@ import chronos, confutils/toml/std/net, libp2p/multiaddress, testutils/unittests
|
||||
|
||||
import ./testlib/wakunode, waku/waku_enr/capabilities
|
||||
|
||||
include waku/node/net_config
|
||||
include
|
||||
waku/node/net_config,
|
||||
waku/factory/conf_builder/web_socket_conf_builder,
|
||||
waku/factory/conf_builder/conf_builder
|
||||
|
||||
proc defaultTestWakuFlags(): CapabilitiesBitfield =
|
||||
CapabilitiesBitfield.init(
|
||||
@ -150,9 +153,15 @@ suite "Waku NetConfig":
|
||||
netConfig.announcedAddresses[0] == dns4TcpEndPoint(dns4DomainName, extPort)
|
||||
|
||||
asyncTest "AnnouncedAddresses includes WebSocket addresses when enabled":
|
||||
var
|
||||
conf = defaultTestWakuConf()
|
||||
wssEnabled = false
|
||||
var confBuilder = defaultTestWakuConfBuilder()
|
||||
|
||||
confBuilder.webSocketConf.withEnabled(true)
|
||||
confBuilder.webSocketConf.withWebSocketPort(Port(8000))
|
||||
|
||||
let conf = confBuilder.build().valueOr:
|
||||
raiseAssert error
|
||||
|
||||
var wssEnabled = false
|
||||
|
||||
var netConfigRes = NetConfig.init(
|
||||
bindIp = conf.endpointConf.p2pListenAddress,
|
||||
@ -197,8 +206,14 @@ suite "Waku NetConfig":
|
||||
)
|
||||
|
||||
asyncTest "Announced WebSocket address contains external IP if provided":
|
||||
var confBuilder = defaultTestWakuConfBuilder()
|
||||
confBuilder.webSocketConf.withEnabled(true)
|
||||
confBuilder.webSocketConf.withWebSocketPort(Port(8000))
|
||||
|
||||
let conf = confBuilder.build().valueOr:
|
||||
raiseAssert error
|
||||
|
||||
let
|
||||
conf = defaultTestWakuConf()
|
||||
extIp = parseIpAddress("1.2.3.4")
|
||||
extPort = Port(1234)
|
||||
wssEnabled = false
|
||||
@ -222,8 +237,14 @@ suite "Waku NetConfig":
|
||||
(ip4TcpEndPoint(extIp, conf.websocketConf.get().port) & wsFlag(wssEnabled))
|
||||
|
||||
asyncTest "Announced WebSocket address contains dns4DomainName if provided":
|
||||
var confBuilder = defaultTestWakuConfBuilder()
|
||||
confBuilder.webSocketConf.withEnabled(true)
|
||||
confBuilder.webSocketConf.withWebSocketPort(Port(8000))
|
||||
|
||||
let conf = confBuilder.build().valueOr:
|
||||
raiseAssert error
|
||||
|
||||
let
|
||||
conf = defaultTestWakuConf()
|
||||
dns4DomainName = "example.com"
|
||||
extPort = Port(1234)
|
||||
wssEnabled = false
|
||||
@ -249,8 +270,14 @@ suite "Waku NetConfig":
|
||||
)
|
||||
|
||||
asyncTest "Announced WebSocket address contains dns4DomainName if provided alongside extIp":
|
||||
var confBuilder = defaultTestWakuConfBuilder()
|
||||
confBuilder.webSocketConf.withEnabled(true)
|
||||
confBuilder.webSocketConf.withWebSocketPort(Port(8000))
|
||||
|
||||
let conf = confBuilder.build().valueOr:
|
||||
raiseAssert error
|
||||
|
||||
let
|
||||
conf = defaultTestWakuConf()
|
||||
dns4DomainName = "example.com"
|
||||
extIp = parseIpAddress("1.2.3.4")
|
||||
extPort = Port(1234)
|
||||
|
||||
@ -42,8 +42,6 @@ proc defaultTestWakuConfBuilder*(): WakuConfBuilder =
|
||||
builder.withRendezvous(true)
|
||||
builder.storeServiceConf.withDbMigration(false)
|
||||
builder.storeServiceConf.withSupportV2(false)
|
||||
builder.webSocketConf.withWebSocketPort(Port(8000))
|
||||
builder.webSocketConf.withEnabled(true)
|
||||
return builder
|
||||
|
||||
proc defaultTestWakuConf*(): WakuConf =
|
||||
|
||||
3
tests/tools/test_all.nim
Normal file
3
tests/tools/test_all.nim
Normal file
@ -0,0 +1,3 @@
|
||||
{.used.}
|
||||
|
||||
import ./test_confutils_envvar, ./test_confutils_envvar_serialization.nim
|
||||
@ -7,9 +7,7 @@ import
|
||||
confutils,
|
||||
confutils/defs,
|
||||
confutils/std/net
|
||||
import
|
||||
waku/common/confutils/envvar/defs as confEnvvarDefs,
|
||||
waku/common/confutils/envvar/std/net as confEnvvarNet
|
||||
import ../../tools/confutils/[envvar as confEnvvarDefs, envvar_net as confEnvvarNet]
|
||||
|
||||
type ConfResult[T] = Result[T, string]
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{.used.}
|
||||
|
||||
import testutils/unittests
|
||||
import waku/common/envvar_serialization/utils
|
||||
import ../../tools/confutils/envvar_serialization/utils
|
||||
|
||||
suite "nim-envvar-serialization - utils":
|
||||
test "construct env var key":
|
||||
@ -439,7 +439,6 @@ suite "Waku Discovery v5":
|
||||
confBuilder.discv5Conf.withEnabled(true)
|
||||
confBuilder.discv5Conf.withUdpPort(9001.Port)
|
||||
confBuilder.withP2pTcpPort(60001.Port)
|
||||
confBuilder.websocketConf.withEnabled(false)
|
||||
|
||||
let conf1 = confBuilder.build().valueOr:
|
||||
raiseAssert error
|
||||
@ -456,7 +455,6 @@ suite "Waku Discovery v5":
|
||||
confBuilder.withP2pTcpPort(60003.Port)
|
||||
confBuilder.discv5Conf.withUdpPort(9003.Port)
|
||||
confBuilder.withNodeKey(crypto.PrivateKey.random(Secp256k1, myRng[])[])
|
||||
confBuilder.websocketConf.withEnabled(false)
|
||||
|
||||
let conf2 = confBuilder.build().valueOr:
|
||||
raiseAssert error
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
{.used.}
|
||||
|
||||
import ./test_app, ./test_validators
|
||||
import ./test_app, ./test_validators, ./test_cli_args
|
||||
|
||||
@ -10,12 +10,15 @@ import
|
||||
secp256k1,
|
||||
confutils,
|
||||
stint
|
||||
|
||||
import tools/confutils/cli_args
|
||||
|
||||
import
|
||||
../../waku/factory/external_config,
|
||||
../../waku/factory/networks_config,
|
||||
../../waku/factory/waku_conf,
|
||||
../../waku/common/logging,
|
||||
../../waku/common/utils/parse_size_units
|
||||
../../waku/common/utils/parse_size_units,
|
||||
../../waku/waku_core/message/default_values
|
||||
|
||||
suite "Waku external config - default values":
|
||||
test "Default sharding value":
|
||||
@ -12,14 +12,8 @@ import
|
||||
libp2p/multihash,
|
||||
secp256k1
|
||||
import
|
||||
waku/[
|
||||
waku_core,
|
||||
node/peer_manager,
|
||||
waku_node,
|
||||
waku_relay,
|
||||
factory/external_config,
|
||||
factory/validator_signed,
|
||||
],
|
||||
waku/[waku_core, node/peer_manager, waku_node, factory/validator_signed],
|
||||
tools/confutils/cli_args,
|
||||
../testlib/wakucore,
|
||||
../testlib/wakunode
|
||||
|
||||
|
||||
@ -19,23 +19,22 @@ import
|
||||
json
|
||||
|
||||
import
|
||||
./waku_conf,
|
||||
./conf_builder/conf_builder,
|
||||
./networks_config,
|
||||
../common/confutils/envvar/defs as confEnvvarDefs,
|
||||
../common/confutils/envvar/std/net as confEnvvarNet,
|
||||
../common/logging,
|
||||
../waku_enr,
|
||||
../node/peer_manager,
|
||||
../waku_core/topics/pubsub_topic,
|
||||
waku/factory/[waku_conf, conf_builder/conf_builder, networks_config],
|
||||
waku/common/[logging],
|
||||
waku/[
|
||||
waku_enr,
|
||||
node/peer_manager,
|
||||
waku_core/topics/pubsub_topic,
|
||||
waku_core/message/default_values,
|
||||
],
|
||||
../../tools/rln_keystore_generator/rln_keystore_generator
|
||||
|
||||
include ../waku_core/message/default_values
|
||||
import ./envvar as confEnvvarDefs, ./envvar_net as confEnvvarNet
|
||||
|
||||
export confTomlDefs, confTomlNet, confEnvvarDefs, confEnvvarNet, ProtectedShard
|
||||
|
||||
logScope:
|
||||
topics = "waku external config"
|
||||
topics = "waku cli args"
|
||||
|
||||
# Git version in git describe format (defined at compile time)
|
||||
const git_version* {.strdefine.} = "n/a"
|
||||
@ -161,7 +160,7 @@ type WakuNodeConf* = object
|
||||
.}: uint16
|
||||
|
||||
agentString* {.
|
||||
defaultValue: "nwaku-" & external_config.git_version,
|
||||
defaultValue: "nwaku-" & cli_args.git_version,
|
||||
desc: "Node agent string which is used as identifier in network",
|
||||
name: "agent-string"
|
||||
.}: string
|
||||
@ -1,7 +1,7 @@
|
||||
{.push raises: [].}
|
||||
|
||||
import confutils/defs as confutilsDefs
|
||||
import ../../envvar_serialization
|
||||
import ./envvar_serialization
|
||||
|
||||
export envvar_serialization, confutilsDefs
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{.push raises: [].}
|
||||
|
||||
import std/[strutils, net]
|
||||
import ../../../envvar_serialization
|
||||
import ./envvar_serialization
|
||||
|
||||
export net, envvar_serialization
|
||||
|
||||
10
waku.nim
Normal file
10
waku.nim
Normal file
@ -0,0 +1,10 @@
|
||||
## Main module for using nwaku as a Nimble library
|
||||
##
|
||||
## This module re-exports the public API for creating and managing Waku nodes
|
||||
## when using nwaku as a library dependency.
|
||||
|
||||
import waku/api/[api, api_conf]
|
||||
export api, api_conf
|
||||
|
||||
import waku/factory/waku
|
||||
export waku
|
||||
@ -140,6 +140,7 @@ task testwakunode2, "Build & run wakunode2 app tests":
|
||||
test "all_tests_wakunode2"
|
||||
|
||||
task example2, "Build Waku examples":
|
||||
buildBinary "waku_example", "examples/"
|
||||
buildBinary "publisher", "examples/"
|
||||
buildBinary "subscriber", "examples/"
|
||||
buildBinary "filter_subscriber", "examples/"
|
||||
|
||||
17
waku/api/api.nim
Normal file
17
waku/api/api.nim
Normal file
@ -0,0 +1,17 @@
|
||||
import chronicles, chronos, results
|
||||
|
||||
import waku/factory/waku
|
||||
|
||||
import ./api_conf
|
||||
|
||||
# TODO: Specs says it should return a `WakuNode`. As `send` and other APIs are defined, we can align.
|
||||
proc createNode*(config: NodeConfig): Future[Result[Waku, string]] {.async.} =
|
||||
let wakuConf = toWakuConf(config).valueOr:
|
||||
return err("Failed to handle the configuration: " & error)
|
||||
|
||||
## We are not defining app callbacks at node creation
|
||||
let wakuRes = (await Waku.new(wakuConf)).valueOr:
|
||||
error "waku initialization failed", error = error
|
||||
return err("Failed setting up Waku: " & $error)
|
||||
|
||||
return ok(wakuRes)
|
||||
203
waku/api/api_conf.nim
Normal file
203
waku/api/api_conf.nim
Normal file
@ -0,0 +1,203 @@
|
||||
import std/[net, options]
|
||||
|
||||
import results
|
||||
|
||||
import
|
||||
waku/common/utils/parse_size_units,
|
||||
waku/factory/waku_conf,
|
||||
waku/factory/conf_builder/conf_builder,
|
||||
waku/factory/networks_config,
|
||||
./entry_nodes
|
||||
|
||||
type AutoShardingConfig* {.requiresInit.} = object
|
||||
numShardsInCluster*: uint16
|
||||
|
||||
type RlnConfig* {.requiresInit.} = object
|
||||
contractAddress*: string
|
||||
chainId*: uint
|
||||
epochSizeSec*: uint64
|
||||
|
||||
type NetworkingConfig* {.requiresInit.} = object
|
||||
listenIpv4*: string
|
||||
p2pTcpPort*: uint16
|
||||
discv5UdpPort*: uint16
|
||||
|
||||
type MessageValidation* {.requiresInit.} = object
|
||||
maxMessageSize*: string # Accepts formats like "150 KiB", "1500 B"
|
||||
rlnConfig*: Option[RlnConfig]
|
||||
|
||||
type WakuConfig* {.requiresInit.} = object
|
||||
entryNodes: seq[string]
|
||||
staticStoreNodes: seq[string]
|
||||
clusterId: uint16
|
||||
autoShardingConfig: AutoShardingConfig
|
||||
messageValidation: MessageValidation
|
||||
|
||||
const DefaultNetworkingConfig* =
|
||||
NetworkingConfig(listenIpv4: "0.0.0.0", p2pTcpPort: 60000, discv5UdpPort: 9000)
|
||||
|
||||
const DefaultAutoShardingConfig* = AutoShardingConfig(numShardsInCluster: 1)
|
||||
|
||||
const DefaultMessageValidation* =
|
||||
MessageValidation(maxMessageSize: "150 KiB", rlnConfig: none(RlnConfig))
|
||||
|
||||
proc init*(
|
||||
T: typedesc[WakuConfig],
|
||||
entryNodes: seq[string],
|
||||
staticStoreNodes: seq[string] = @[],
|
||||
clusterId: uint16,
|
||||
autoShardingConfig: AutoShardingConfig = DefaultAutoShardingConfig,
|
||||
messageValidation: MessageValidation = DefaultMessageValidation,
|
||||
): T =
|
||||
return T(
|
||||
entryNodes: entryNodes,
|
||||
staticStoreNodes: staticStoreNodes,
|
||||
clusterId: clusterId,
|
||||
autoShardingConfig: autoShardingConfig,
|
||||
messageValidation: messageValidation,
|
||||
)
|
||||
|
||||
const TheWakuNetworkPreset* = WakuConfig(
|
||||
entryNodes:
|
||||
@[
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im"
|
||||
],
|
||||
staticStoreNodes: @[],
|
||||
clusterId: 1,
|
||||
autoShardingConfig: AutoShardingConfig(numShardsInCluster: 8),
|
||||
messageValidation: MessageValidation(
|
||||
maxMessageSize: "150 KiB",
|
||||
rlnConfig: some(
|
||||
RlnConfig(
|
||||
contractAddress: "0xB9cd878C90E49F797B4431fBF4fb333108CB90e6",
|
||||
chainId: 59141,
|
||||
epochSizeSec: 600, # 10 minutes
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
type WakuMode* {.pure.} = enum
|
||||
Edge
|
||||
Core
|
||||
|
||||
type NodeConfig* {.requiresInit.} = object
|
||||
mode: WakuMode
|
||||
wakuConfig: WakuConfig
|
||||
networkingConfig: NetworkingConfig
|
||||
ethRpcEndpoints: seq[string]
|
||||
|
||||
proc init*(
|
||||
T: typedesc[NodeConfig],
|
||||
mode: WakuMode = WakuMode.Core,
|
||||
wakuConfig: WakuConfig = TheWakuNetworkPreset,
|
||||
networkingConfig: NetworkingConfig = DefaultNetworkingConfig,
|
||||
ethRpcEndpoints: seq[string] = @[],
|
||||
): T =
|
||||
return T(
|
||||
mode: mode,
|
||||
wakuConfig: wakuConfig,
|
||||
networkingConfig: networkingConfig,
|
||||
ethRpcEndpoints: ethRpcEndpoints,
|
||||
)
|
||||
|
||||
proc toWakuConf*(nodeConfig: NodeConfig): Result[WakuConf, string] =
|
||||
var b = WakuConfBuilder.init()
|
||||
|
||||
# Apply networking configuration
|
||||
let networkingConfig = nodeConfig.networkingConfig
|
||||
let ip = parseIpAddress(networkingConfig.listenIpv4)
|
||||
|
||||
b.withP2pListenAddress(ip)
|
||||
b.withP2pTcpPort(networkingConfig.p2pTcpPort)
|
||||
b.discv5Conf.withUdpPort(networkingConfig.discv5UdpPort)
|
||||
|
||||
case nodeConfig.mode
|
||||
of Core:
|
||||
b.withRelay(true)
|
||||
|
||||
# Metadata is always mounted
|
||||
|
||||
b.filterServiceConf.withEnabled(true)
|
||||
b.filterServiceConf.withMaxPeersToServe(20)
|
||||
|
||||
b.withLightPush(true)
|
||||
|
||||
b.discv5Conf.withEnabled(true)
|
||||
b.withPeerExchange(true)
|
||||
b.withRendezvous(true)
|
||||
|
||||
# TODO: fix store as client usage
|
||||
|
||||
b.rateLimitConf.withRateLimits(@["filter:100/1s", "lightpush:5/1s", "px:5/1s"])
|
||||
of Edge:
|
||||
return err("Edge mode is not implemented")
|
||||
|
||||
## Network Conf
|
||||
let wakuConfig = nodeConfig.wakuConfig
|
||||
|
||||
# Set cluster ID
|
||||
b.withClusterId(wakuConfig.clusterId)
|
||||
|
||||
# Set sharding configuration
|
||||
b.withShardingConf(ShardingConfKind.AutoSharding)
|
||||
let autoShardingConfig = wakuConfig.autoShardingConfig
|
||||
b.withNumShardsInCluster(autoShardingConfig.numShardsInCluster)
|
||||
|
||||
# Process entry nodes - supports enrtree:, enr:, and multiaddress formats
|
||||
if wakuConfig.entryNodes.len > 0:
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodesFromEntry) = processEntryNodes(
|
||||
wakuConfig.entryNodes
|
||||
).valueOr:
|
||||
return err("Failed to process entry nodes: " & error)
|
||||
|
||||
# Set ENRTree URLs for DNS discovery
|
||||
if enrTreeUrls.len > 0:
|
||||
for url in enrTreeUrls:
|
||||
b.dnsDiscoveryConf.withEnrTreeUrl(url)
|
||||
b.dnsDiscoveryconf.withNameServers(
|
||||
@[parseIpAddress("1.1.1.1"), parseIpAddress("1.0.0.1")]
|
||||
)
|
||||
|
||||
# Set ENR records as bootstrap nodes for discv5
|
||||
if bootstrapEnrs.len > 0:
|
||||
b.discv5Conf.withBootstrapNodes(bootstrapEnrs)
|
||||
|
||||
# Add static nodes (multiaddrs and those extracted from ENR entries)
|
||||
if staticNodesFromEntry.len > 0:
|
||||
b.withStaticNodes(staticNodesFromEntry)
|
||||
|
||||
# TODO: verify behaviour
|
||||
# Set static store nodes
|
||||
if wakuConfig.staticStoreNodes.len > 0:
|
||||
b.withStaticNodes(wakuConfig.staticStoreNodes)
|
||||
|
||||
# Set message validation
|
||||
let msgValidation = wakuConfig.messageValidation
|
||||
let maxSizeBytes = parseMsgSize(msgValidation.maxMessageSize).valueOr:
|
||||
return err("Failed to parse max message size: " & error)
|
||||
b.withMaxMessageSize(maxSizeBytes)
|
||||
|
||||
# Set RLN config if provided
|
||||
if msgValidation.rlnConfig.isSome():
|
||||
let rlnConfig = msgValidation.rlnConfig.get()
|
||||
b.rlnRelayConf.withEnabled(true)
|
||||
b.rlnRelayConf.withEthContractAddress(rlnConfig.contractAddress)
|
||||
b.rlnRelayConf.withChainId(rlnConfig.chainId)
|
||||
b.rlnRelayConf.withEpochSizeSec(rlnConfig.epochSizeSec)
|
||||
b.rlnRelayConf.withDynamic(true)
|
||||
b.rlnRelayConf.withEthClientUrls(nodeConfig.ethRpcEndpoints)
|
||||
|
||||
# TODO: we should get rid of those two
|
||||
b.rlnRelayconf.withUserMessageLimit(100)
|
||||
|
||||
## Various configurations
|
||||
b.withNatStrategy("any")
|
||||
|
||||
let wakuConf = b.build().valueOr:
|
||||
return err("Failed to build configuration: " & error)
|
||||
|
||||
wakuConf.validate().isOkOr:
|
||||
return err("Failed to validate configuration: " & error)
|
||||
|
||||
return ok(wakuConf)
|
||||
77
waku/api/entry_nodes.nim
Normal file
77
waku/api/entry_nodes.nim
Normal file
@ -0,0 +1,77 @@
|
||||
import std/strutils
|
||||
|
||||
import results, eth/p2p/discoveryv5/enr
|
||||
|
||||
import waku/waku_core/peers
|
||||
|
||||
type EntryNodeType {.pure.} = enum
|
||||
EnrTree
|
||||
Enr
|
||||
Multiaddr
|
||||
|
||||
proc classifyEntryNode(address: string): Result[EntryNodeType, string] =
|
||||
## Classifies an entry node address by its type
|
||||
## Returns the type as EntryNodeType enum
|
||||
if address.len == 0:
|
||||
return err("Empty entry node address")
|
||||
|
||||
let lowerAddress = address.toLowerAscii()
|
||||
if lowerAddress.startsWith("enrtree:"):
|
||||
return ok(EnrTree)
|
||||
elif lowerAddress.startsWith("enr:"):
|
||||
return ok(Enr)
|
||||
elif address[0] == '/':
|
||||
return ok(Multiaddr)
|
||||
else:
|
||||
return
|
||||
err("Unrecognized entry node format. Must start with 'enrtree:', 'enr:', or '/'")
|
||||
|
||||
proc parseEnrToMultiaddrs(enrStr: string): Result[seq[string], string] =
|
||||
## Parses an ENR string and extracts multiaddresses from it
|
||||
let enrRec = enr.Record.fromURI(enrStr).valueOr:
|
||||
return err("Invalid ENR record")
|
||||
|
||||
let remotePeerInfo = toRemotePeerInfo(enrRec).valueOr:
|
||||
return err("Failed to convert ENR to peer info: " & $error)
|
||||
|
||||
# Convert RemotePeerInfo addresses to multiaddr strings
|
||||
var multiaddrs: seq[string]
|
||||
for addr in remotePeerInfo.addrs:
|
||||
multiaddrs.add($addr & "/p2p/" & $remotePeerInfo.peerId)
|
||||
|
||||
if multiaddrs.len == 0:
|
||||
return err("No valid addresses found in ENR")
|
||||
|
||||
return ok(multiaddrs)
|
||||
|
||||
proc processEntryNodes*(
|
||||
entryNodes: seq[string]
|
||||
): Result[(seq[string], seq[string], seq[string]), string] =
|
||||
## Processes entry nodes and returns (enrTreeUrls, bootstrapEnrs, staticNodes)
|
||||
## ENRTree URLs for DNS discovery, ENR records for bootstrap, multiaddrs for static nodes
|
||||
var enrTreeUrls: seq[string]
|
||||
var bootstrapEnrs: seq[string]
|
||||
var staticNodes: seq[string]
|
||||
|
||||
for node in entryNodes:
|
||||
let nodeType = classifyEntryNode(node).valueOr:
|
||||
return err("Entry node error: " & error)
|
||||
|
||||
case nodeType
|
||||
of EnrTree:
|
||||
# ENRTree URLs go to DNS discovery configuration
|
||||
enrTreeUrls.add(node)
|
||||
of Enr:
|
||||
# ENR records go to bootstrap nodes for discv5
|
||||
bootstrapEnrs.add(node)
|
||||
# Additionally, extract multiaddrs for static connections
|
||||
let multiaddrsRes = parseEnrToMultiaddrs(node)
|
||||
if multiaddrsRes.isOk():
|
||||
for maddr in multiaddrsRes.get():
|
||||
staticNodes.add(maddr)
|
||||
# If we can't extract multiaddrs, just use it as bootstrap (already added above)
|
||||
of Multiaddr:
|
||||
# Multiaddresses go to static nodes
|
||||
staticNodes.add(node)
|
||||
|
||||
return ok((enrTreeUrls, bootstrapEnrs, staticNodes))
|
||||
@ -1,7 +1,7 @@
|
||||
import
|
||||
libp2p/crypto/crypto,
|
||||
libp2p/multiaddress,
|
||||
std/[net, options, sequtils, strutils],
|
||||
std/[net, options, sequtils],
|
||||
stint,
|
||||
chronicles,
|
||||
chronos,
|
||||
|
||||
@ -5,7 +5,7 @@ import
|
||||
libp2p/crypto/curve25519,
|
||||
libp2p/multiaddress,
|
||||
libp2p/nameresolving/dnsresolver,
|
||||
std/[options, sequtils, net, strutils],
|
||||
std/[options, sequtils, net],
|
||||
results
|
||||
|
||||
import ../common/utils/nat, ../node/net_config, ../waku_enr, ../waku_core, ./waku_conf
|
||||
|
||||
@ -42,7 +42,6 @@ import
|
||||
../waku_filter_v2,
|
||||
../factory/node_factory,
|
||||
../factory/internal_config,
|
||||
../factory/external_config,
|
||||
../factory/app_callbacks,
|
||||
../waku_enr/multiaddr,
|
||||
./waku_conf
|
||||
|
||||
@ -57,7 +57,6 @@ import
|
||||
../common/rate_limit/setting,
|
||||
../common/callbacks,
|
||||
../common/nimchronos,
|
||||
../waku_enr/mix,
|
||||
../waku_mix
|
||||
|
||||
declarePublicCounter waku_node_messages, "number of messages received", ["type"]
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
{.push raises: [].}
|
||||
|
||||
import
|
||||
std/[options, sequtils, sets, strutils, tables],
|
||||
std/[options, sequtils, sets, tables],
|
||||
stew/byteutils,
|
||||
chronicles,
|
||||
chronos,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user