Skip to content

Commit

Permalink
feat!: introduce preset option instead of deducing from cluster-id
Browse files Browse the repository at this point in the history
  • Loading branch information
fryorcraken committed Jul 2, 2024
1 parent c5e23a0 commit 5489bd3
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 69 deletions.
3 changes: 2 additions & 1 deletion tests/all_tests_waku.nim
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import
const os* {.strdefine.} = ""
when os == "Linux" and
# GitHub only supports container actions on Linux
# and we need to start a postgress database in a docker container
# and we need to start a postgres database in a docker container
defined(postgres):
import
./waku_archive/test_driver_postgres_query,
Expand Down Expand Up @@ -93,3 +93,4 @@ import
import ./waku_rln_relay/test_all

# Node Factory
import ./factory/test_config
82 changes: 82 additions & 0 deletions tests/factory/test_config.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{.used.}

import std/options, testutils/unittests, chronos
import
../../waku/factory/external_config,
../../waku/factory/internal_config,
../../waku/factory/networks_config

suite "Waku config":
test "Default preset is TWN":
## Setup
let twnConf = ClusterConf.TheWakuNetworkConf()

## Given
let preConfig = WakuNodeConf(cmd: noCommand, preset: "default")

## When
let res = applyPresetConfiguration(preConfig)
assert res.isOk(), $res.error

## Then
let conf = res.get()
assert conf.maxMessageSize == twnConf.maxMessageSize
assert conf.clusterId == twnConf.clusterId
assert conf.rlnRelay == twnConf.rlnRelay
assert conf.rlnRelayEthContractAddress == twnConf.rlnRelayEthContractAddress
assert conf.rlnRelayDynamic == twnConf.rlnRelayDynamic
assert conf.rlnRelayBandwidthThreshold == twnConf.rlnRelayBandwidthThreshold
assert conf.rlnEpochSizeSec == twnConf.rlnEpochSizeSec
assert conf.rlnRelayUserMessageLimit == twnConf.rlnRelayUserMessageLimit
assert conf.pubsubTopics == twnConf.pubsubTopics
assert conf.discv5Discovery == twnConf.discv5Discovery
assert conf.discv5BootstrapNodes == twnConf.discv5BootstrapNodes

test "Subscribes to all valid shards in default network":
## Setup
let twnConf = ClusterConf.TheWakuNetworkConf()

## Given
let shards: seq[uint16] = @[0, 1, 2, 3, 4, 5, 6, 7]
let preConfig = WakuNodeConf(cmd: noCommand, preset: "default", shards: shards)

## When
let res = applyPresetConfiguration(preConfig)
assert res.isOk(), $res.error

## Then
let conf = res.get()
assert conf.pubsubTopics == twnConf.pubsubTopics

test "Subscribes to some valid shards in default network":
## Setup
let twnConf = ClusterConf.TheWakuNetworkConf()

## Given
let shards: seq[uint16] = @[0, 4, 7]
let preConfig = WakuNodeConf(cmd: noCommand, preset: "default", shards: shards)

## When
let res = applyPresetConfiguration(preConfig)
assert res.isOk(), $res.error

## Then
let conf = res.get()
assert conf.pubsubTopics.len() == shards.len()
assert twnConf.pubsubTopics[0] in conf.pubsubTopics
assert twnConf.pubsubTopics[4] in conf.pubsubTopics
assert twnConf.pubsubTopics[7] in conf.pubsubTopics

test "Subscribes to invalid shards in default network":
## Setup
let twnConf = ClusterConf.TheWakuNetworkConf()

## Given
let shards: seq[uint16] = @[0, 4, 7, 10]
let preConfig = WakuNodeConf(cmd: noCommand, preset: "default", shards: shards)

## When
let res = applyPresetConfiguration(preConfig)

## Then
assert res.isErr(), "Invalid shard was accepted"
32 changes: 21 additions & 11 deletions waku/factory/external_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ type WakuNodeConf* = object
.}: EthRpcUrl

rlnRelayEthContractAddress* {.
desc: "Address of membership contract on an Ethereum testnet",
desc: "Address of membership contract on an Ethereum testnet. Part of presets.",
defaultValue: "",
name: "rln-relay-eth-contract-address"
.}: string
Expand All @@ -91,14 +91,14 @@ type WakuNodeConf* = object

rlnRelayUserMessageLimit* {.
desc:
"Set a user message limit for the rln membership registration. Must be a positive integer. Default is 1.",
"Set a user message limit for the rln membership registration. Must be a positive integer. Default is 1. Part of presets.",
defaultValue: 1,
name: "rln-relay-user-message-limit"
.}: uint64

rlnEpochSizeSec* {.
desc:
"Epoch size in seconds used to rate limit RLN memberships. Default is 1 second.",
"Epoch size in seconds used to rate limit RLN memberships. Default is 1 second. Part of presets.",
defaultValue: 1,
name: "rln-relay-epoch-sec"
.}: uint64
Expand Down Expand Up @@ -127,9 +127,15 @@ type WakuNodeConf* = object
.}: seq[ProtectedTopic]

## General node config
preset* {.
desc: "Network preset to use." & "Must be one of 'default', ''",
defaultValue: "default",
name: "preset"
.}: string

clusterId* {.
desc:
"Cluster id that the node is running in. Node in a different cluster id is disconnected.",
"Cluster id that the node is running in. Node in a different cluster id is disconnected. Part of presets.",
defaultValue: 0,
name: "cluster-id"
.}: uint16
Expand All @@ -139,7 +145,7 @@ type WakuNodeConf* = object

maxMessageSize* {.
desc:
"Maximum message size. Accepted units: KiB, KB, and B. e.g. 1024KiB; 1500 B; etc.",
"Maximum message size. Accepted units: KiB, KB, and B. e.g. 1024KiB; 1500 B; etc. Part of presets.",
defaultValue: DefaultMaxWakuMessageSizeStr,
name: "max-msg-size"
.}: string
Expand Down Expand Up @@ -247,7 +253,9 @@ type WakuNodeConf* = object
.}: seq[string]

shards* {.
desc: "Shards index to subscribe to [0.." & $MaxShardIndex & "]. Argument may be repeated.",
desc:
"Shards index to subscribe to [0.." & $MaxShardIndex &
"]. Argument may be repeated.",
defaultValue: @[],
name: "shard"
.}: seq[uint16]
Expand All @@ -259,7 +267,7 @@ type WakuNodeConf* = object

## RLN Relay config
rlnRelay* {.
desc: "Enable spam protection through rln-relay: true|false",
desc: "Enable spam protection through rln-relay: true|false. Part of presets.",
defaultValue: false,
name: "rln-relay"
.}: bool
Expand All @@ -270,7 +278,8 @@ type WakuNodeConf* = object
.}: Option[uint]

rlnRelayDynamic* {.
desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false",
desc:
"Enable waku-rln-relay with on-chain dynamic group management: true|false. Part of presets.",
defaultValue: false,
name: "rln-relay-dynamic"
.}: bool
Expand All @@ -294,7 +303,8 @@ type WakuNodeConf* = object
.}: string

rlnRelayBandwidthThreshold* {.
desc: "Message rate in bytes/sec after which verification of proofs should happen",
desc:
"Message rate in bytes/sec after which verification of proofs should happen. Part of presets.",
defaultValue: 0, # to maintain backwards compatibility
name: "rln-relay-bandwidth-threshold"
.}: int
Expand Down Expand Up @@ -476,7 +486,7 @@ type WakuNodeConf* = object

## Discovery v5 config
discv5Discovery* {.
desc: "Enable discovering nodes via Node Discovery v5",
desc: "Enable discovering nodes via Node Discovery v5. Part of presets.",
defaultValue: false,
name: "discv5-discovery"
.}: bool
Expand All @@ -489,7 +499,7 @@ type WakuNodeConf* = object

discv5BootstrapNodes* {.
desc:
"Text-encoded ENR for bootstrap node. Used when connecting to the network. Argument may be repeated.",
"Text-encoded ENR for bootstrap node. Used when connecting to the network. Argument may be repeated. Part of presets.",
name: "discv5-bootstrap-node"
.}: seq[string]

Expand Down
57 changes: 56 additions & 1 deletion waku/factory/internal_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import
../node/config,
../waku_enr/capabilities,
../waku_enr,
../waku_core
../waku_core,
./networks_config

proc enrConfiguration*(
conf: WakuNodeConf, netConfig: NetConfig, key: crypto.PrivateKey
Expand Down Expand Up @@ -172,3 +173,57 @@ proc networkConfiguration*(conf: WakuNodeConf, clientId: string): NetConfigResul
)

return netConfigRes

proc applyPresetConfiguration*(srcConf: WakuNodeConf): Result[WakuNodeConf, string] =
var resConf = srcConf

case resConf.preset
of "default":
let twnClusterConf = ClusterConf.TheWakuNetworkConf()
if len(resConf.shards) != 0:
for shard in resConf.shards:
if not (shard.int < twnClusterConf.pubsubTopics.len):
return err(
"Invalid shard received: " & $shard &
" is not part of the available shards: " &
$toSeq(0 .. twnClusterConf.pubsubTopics.len - 1)
)
else:
resConf.pubsubTopics.add(twnClusterConf.pubsubTopics[shard.uint16])
else:
resConf.pubsubTopics = twnClusterConf.pubsubTopics

# Override configuration
resConf.maxMessageSize = twnClusterConf.maxMessageSize
resConf.clusterId = twnClusterConf.clusterId
resConf.rlnRelay = twnClusterConf.rlnRelay
resConf.rlnRelayEthContractAddress = twnClusterConf.rlnRelayEthContractAddress
resConf.rlnRelayDynamic = twnClusterConf.rlnRelayDynamic
resConf.rlnRelayBandwidthThreshold = twnClusterConf.rlnRelayBandwidthThreshold
resConf.rlnEpochSizeSec = twnClusterConf.rlnEpochSizeSec
resConf.rlnRelayUserMessageLimit = twnClusterConf.rlnRelayUserMessageLimit
resConf.discv5Discovery = twnClusterConf.discv5Discovery
resConf.discv5BootstrapNodes =
resConf.discv5BootstrapNodes & twnClusterConf.discv5BootstrapNodes
else:
discard

return ok(resConf)

proc nodeKeyConfiguration*(
conf: WakuNodeConf, rng: Option[ref HmacDrbgContext] = none(ref HmacDrbgContext)
): Result[PrivateKey, string] =
if conf.nodeKey.isSome:
return ok(conf.nodeKey.get())

var nodeRng =
if rng.isSome():
rng.get()
else:
crypto.newRng()

let key = crypto.PrivateKey.random(Secp256k1, nodeRng[]).valueOr:
error "Failed to generate key", error = $error
return err("Failed to generate key: " & $error)

return ok(key)
12 changes: 3 additions & 9 deletions waku/factory/node_factory.nim
Original file line number Diff line number Diff line change
Expand Up @@ -353,15 +353,9 @@ proc setupNode*(
else:
crypto.newRng()

# Use provided key only if corresponding rng is also provided
let key =
if conf.nodeKey.isSome() and rng.isSome():
conf.nodeKey.get()
else:
warn "missing key or rng, generating new set"
crypto.PrivateKey.random(Secp256k1, nodeRng[]).valueOr:
error "Failed to generate key", error = error
return err("Failed to generate key: " & $error)
let key = nodeKeyConfiguration(conf).valueOr:
error "Failed to generate key", error = error
return err("Failed to generate key: " & error)

let netConfig = networkConfiguration(conf, clientId).valueOr:
error "failed to create internal config", error = error
Expand Down
62 changes: 15 additions & 47 deletions waku/factory/waku.nim
Original file line number Diff line number Diff line change
Expand Up @@ -85,57 +85,25 @@ func version*(waku: Waku): string =

## Initialisation

proc init*(T: type Waku, conf: WakuNodeConf): Result[Waku, string] =
var confCopy = conf
proc init*(T: type Waku, srcConf: WakuNodeConf): Result[Waku, string] =
let rng = crypto.newRng()

logging.setupLog(conf.logLevel, conf.logFormat)

case confCopy.clusterId

# cluster-id=0
of 0:
let clusterZeroConf = ClusterConf.ClusterZeroConf()
confCopy.pubsubTopics = clusterZeroConf.pubsubTopics
# TODO: Write some template to "merge" the configs

# cluster-id=1 (aka The Waku Network)
of 1:
let twnClusterConf = ClusterConf.TheWakuNetworkConf()
if len(confCopy.shards) != 0:
confCopy.pubsubTopics =
confCopy.shards.mapIt(twnClusterConf.pubsubTopics[it.uint16])
else:
confCopy.pubsubTopics = twnClusterConf.pubsubTopics

# Override configuration
confCopy.maxMessageSize = twnClusterConf.maxMessageSize
confCopy.clusterId = twnClusterConf.clusterId
confCopy.rlnRelay = twnClusterConf.rlnRelay
confCopy.rlnRelayEthContractAddress = twnClusterConf.rlnRelayEthContractAddress
confCopy.rlnRelayDynamic = twnClusterConf.rlnRelayDynamic
confCopy.rlnRelayBandwidthThreshold = twnClusterConf.rlnRelayBandwidthThreshold
confCopy.discv5Discovery = twnClusterConf.discv5Discovery
confCopy.discv5BootstrapNodes =
confCopy.discv5BootstrapNodes & twnClusterConf.discv5BootstrapNodes
confCopy.rlnEpochSizeSec = twnClusterConf.rlnEpochSizeSec
confCopy.rlnRelayUserMessageLimit = twnClusterConf.rlnRelayUserMessageLimit
else:
discard
logConfig(srcConf)
logging.setupLog(srcConf.logLevel, srcConf.logFormat)

info "Running nwaku node", version = git_version
logConfig(confCopy)
# Why can't I replace this block with a concise `.valueOr`?
let finalConf = block:
let res = applyPresetConfiguration(srcConf)
if res.isErr():
error "Failed to complete the config", error = res.error
return err("Failed to complete the config:" & $res.error)
res.get()

if not confCopy.nodekey.isSome():
let keyRes = crypto.PrivateKey.random(Secp256k1, rng[])
if keyRes.isErr():
error "Failed to generate key", error = $keyRes.error
return err("Failed to generate key: " & $keyRes.error)
confCopy.nodekey = some(keyRes.get())
info "Running nwaku node", version = git_version

debug "Retrieve dynamic bootstrap nodes"
let dynamicBootstrapNodesRes = waku_dnsdisc.retrieveDynamicBootstrapNodes(
confCopy.dnsDiscovery, confCopy.dnsDiscoveryUrl, confCopy.dnsDiscoveryNameServers
finalConf.dnsDiscovery, finalConf.dnsDiscoveryUrl, finalConf.dnsDiscoveryNameServers
)
if dynamicBootstrapNodesRes.isErr():
error "Retrieving dynamic bootstrap nodes failed",
Expand All @@ -144,16 +112,16 @@ proc init*(T: type Waku, conf: WakuNodeConf): Result[Waku, string] =
"Retrieving dynamic bootstrap nodes failed: " & dynamicBootstrapNodesRes.error
)

let nodeRes = setupNode(confCopy, some(rng))
let nodeRes = setupNode(finalConf, some(rng))
if nodeRes.isErr():
error "Failed setting up node", error = nodeRes.error
return err("Failed setting up node: " & nodeRes.error)

var waku = Waku(
version: git_version,
conf: confCopy,
conf: finalConf,
rng: rng,
key: confCopy.nodekey.get(),
key: finalConf.nodekey.get(),
node: nodeRes.get(),
dynamicBootstrapNodes: dynamicBootstrapNodesRes.get(),
)
Expand Down

0 comments on commit 5489bd3

Please sign in to comment.