mirror of
https://github.com/logos-messaging/logos-messaging-nim.git
synced 2026-06-13 13:09:26 +00:00
feat: Improve config (v2) (#3925)
* rename NetworkConf -> NetworkPresetConf and related procs/vars * Rewrite applyNetworkPresetConf to apply user-set fields over preset fields * New dedicated parser for configJson * Fix tests to use actual extract JSON nodeconf parser * Change all confbuilder defaults from literal values to DefaultXXX consts * Change int/bool WakuNodeConf fields to Option to get user intent w/o sentinels * Make Option CLI default-value help mention defaults now owned by confbuilder * Document CLI defaults that differ from confbuilder defaults * Fix agent-string builder default deviating from CLI default * Add WakuConfBuilder.enforceSecurityConstraints() * Fail on RLN user preset overrides instead of drop-and-continue * Add regression tests for initial set of conf constraints * fix kademliaDiscoveryConfBuilder.build() enable/disable kad logic * Misc refactors, fixes * Add tests Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
This commit is contained in:
parent
362c35f2fb
commit
41b5c4906f
@ -95,7 +95,7 @@ when isMainModule:
|
||||
|
||||
wakuNodeConf.shards = @[conf.shard]
|
||||
wakuNodeConf.contentTopics = conf.contentTopics
|
||||
wakuNodeConf.clusterId = conf.clusterId
|
||||
wakuNodeConf.clusterId = some(conf.clusterId)
|
||||
## TODO: Depending on the tester needs we might extend here with shards, clusterId, etc...
|
||||
|
||||
wakuNodeConf.metricsServer = true
|
||||
|
||||
@ -550,7 +550,7 @@ when isMainModule:
|
||||
info "cli flags", conf = conf
|
||||
|
||||
if conf.clusterId == 1:
|
||||
let twnNetworkConf = NetworkConf.TheWakuNetworkConf()
|
||||
let twnNetworkConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
|
||||
conf.bootstrapNodes = twnNetworkConf.discv5BootstrapNodes
|
||||
conf.rlnRelayDynamic = twnNetworkConf.rlnRelayDynamic
|
||||
|
||||
@ -21,7 +21,7 @@ proc setup*(): Waku =
|
||||
error "failure while loading the configuration", error = $error
|
||||
quit(QuitFailure)
|
||||
|
||||
let twnNetworkConf = NetworkConf.TheWakuNetworkConf()
|
||||
let twnNetworkConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
if len(conf.shards) != 0:
|
||||
conf.pubsubTopics = conf.shards.mapIt(twnNetworkConf.pubsubTopics[it.uint16])
|
||||
else:
|
||||
@ -29,18 +29,18 @@ proc setup*(): Waku =
|
||||
|
||||
# Override configuration
|
||||
conf.maxMessageSize = twnNetworkConf.maxMessageSize
|
||||
conf.clusterId = twnNetworkConf.clusterId
|
||||
conf.clusterId = some(twnNetworkConf.clusterId)
|
||||
conf.rlnRelayEthContractAddress = twnNetworkConf.rlnRelayEthContractAddress
|
||||
conf.rlnRelayDynamic = twnNetworkConf.rlnRelayDynamic
|
||||
conf.discv5Discovery = twnNetworkConf.discv5Discovery
|
||||
conf.rlnRelayDynamic = some(twnNetworkConf.rlnRelayDynamic)
|
||||
conf.discv5Discovery = some(twnNetworkConf.discv5Discovery)
|
||||
conf.discv5BootstrapNodes =
|
||||
conf.discv5BootstrapNodes & twnNetworkConf.discv5BootstrapNodes
|
||||
conf.rlnEpochSizeSec = twnNetworkConf.rlnEpochSizeSec
|
||||
conf.rlnRelayUserMessageLimit = twnNetworkConf.rlnRelayUserMessageLimit
|
||||
conf.rlnEpochSizeSec = some(twnNetworkConf.rlnEpochSizeSec)
|
||||
conf.rlnRelayUserMessageLimit = some(twnNetworkConf.rlnRelayUserMessageLimit)
|
||||
|
||||
# Only set rlnRelay to true if relay is configured
|
||||
if conf.relay:
|
||||
conf.rlnRelay = twnNetworkConf.rlnRelay
|
||||
conf.rlnRelay = some(twnNetworkConf.rlnRelay)
|
||||
|
||||
info "Starting node"
|
||||
var waku = (waitFor Waku.new(conf)).valueOr:
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import std/[json, strutils, tables]
|
||||
import chronos, chronicles, results, confutils, confutils/std/net, ffi
|
||||
import std/json
|
||||
import chronos, chronicles, results, ffi
|
||||
import
|
||||
logos_delivery/waku/factory/waku,
|
||||
logos_delivery/waku/node/waku_node,
|
||||
logos_delivery/waku/api/[api, types],
|
||||
logos_delivery/waku/events/[message_events, health_events],
|
||||
tools/confutils/cli_args,
|
||||
tools/confutils/conf_from_json,
|
||||
../declare_lib,
|
||||
../json_event
|
||||
|
||||
@ -15,59 +15,11 @@ proc `%`*(id: RequestId): JsonNode =
|
||||
|
||||
registerReqFFI(CreateNodeRequest, ctx: ptr FFIContext[Waku]):
|
||||
proc(configJson: cstring): Future[Result[string, string]] {.async.} =
|
||||
## Parse the JSON configuration using fieldPairs approach (WakuNodeConf)
|
||||
var conf = defaultWakuNodeConf().valueOr:
|
||||
return err("Failed creating default conf: " & error)
|
||||
let conf = parseNodeConfFromJson($configJson).valueOr:
|
||||
error "Failed to assemble WakuNodeConf from JSON",
|
||||
error = error, configJson = $configJson
|
||||
return err("failed parseNodeConfFromJson " & error)
|
||||
|
||||
var jsonNode: JsonNode
|
||||
try:
|
||||
jsonNode = parseJson($configJson)
|
||||
except Exception:
|
||||
let exceptionMsg = getCurrentExceptionMsg()
|
||||
error "Failed to parse config JSON",
|
||||
error = exceptionMsg, configJson = $configJson
|
||||
return err(
|
||||
"Failed to parse config JSON: " & exceptionMsg & " configJson string: " &
|
||||
$configJson
|
||||
)
|
||||
|
||||
var jsonFields: Table[string, (string, JsonNode)]
|
||||
for key, value in jsonNode:
|
||||
let lowerKey = key.toLowerAscii()
|
||||
|
||||
if jsonFields.hasKey(lowerKey):
|
||||
error "Duplicate configuration option found when normalized to lowercase",
|
||||
key = key
|
||||
return err(
|
||||
"Duplicate configuration option found when normalized to lowercase: '" & key &
|
||||
"'"
|
||||
)
|
||||
|
||||
jsonFields[lowerKey] = (key, value)
|
||||
|
||||
for confField, confValue in fieldPairs(conf):
|
||||
let lowerField = confField.toLowerAscii()
|
||||
if jsonFields.hasKey(lowerField):
|
||||
let (jsonKey, jsonValue) = jsonFields[lowerField]
|
||||
let formattedString = ($jsonValue).strip(chars = {'\"'})
|
||||
try:
|
||||
confValue = parseCmdArg(typeof(confValue), formattedString)
|
||||
except Exception:
|
||||
return err(
|
||||
"Failed to parse field '" & confField & "' from JSON key '" & jsonKey & "': " &
|
||||
getCurrentExceptionMsg() & ". Value: " & formattedString
|
||||
)
|
||||
|
||||
jsonFields.del(lowerField)
|
||||
|
||||
if jsonFields.len > 0:
|
||||
var unknownKeys = newSeq[string]()
|
||||
for _, (jsonKey, _) in pairs(jsonFields):
|
||||
unknownKeys.add(jsonKey)
|
||||
error "Unrecognized configuration option(s) found", option = unknownKeys
|
||||
return err("Unrecognized configuration option(s) found: " & $unknownKeys)
|
||||
|
||||
# Create the node
|
||||
ctx.myLib[] = (await api.createNode(conf)).valueOr:
|
||||
let errMsg = $error
|
||||
chronicles.error "CreateNodeRequest failed", err = errMsg
|
||||
@ -96,7 +48,7 @@ proc logosdelivery_create_node(
|
||||
): pointer {.dynlib, exportc, cdecl.} =
|
||||
initializeLibrary()
|
||||
|
||||
if isNil(callback):
|
||||
if callback.isNil():
|
||||
echo "error: missing callback in logosdelivery_create_node"
|
||||
return nil
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import chronicles, chronos, results
|
||||
import std/[net, options]
|
||||
|
||||
import chronicles, chronos, libp2p/peerid, results
|
||||
|
||||
import logos_delivery/waku/factory/waku
|
||||
import logos_delivery/messaging/messaging_client
|
||||
|
||||
@ -4,7 +4,13 @@ import ../waku_conf
|
||||
logScope:
|
||||
topics = "waku conf builder discv5"
|
||||
|
||||
const DefaultDiscv5UdpPort*: Port = Port(9000)
|
||||
const
|
||||
DefaultDiscv5Enabled*: bool = false
|
||||
DefaultDiscv5BitsPerHop: int = 1
|
||||
DefaultDiscv5BucketIpLimit: uint = 2
|
||||
DefaultDiscv5EnrAutoUpdate: bool = true
|
||||
DefaultDiscv5TableIpLimit: uint = 10
|
||||
DefaultDiscv5UdpPort: Port = Port(9000)
|
||||
|
||||
###########################
|
||||
## Discv5 Config Builder ##
|
||||
@ -48,17 +54,17 @@ proc withBootstrapNodes*(b: var Discv5ConfBuilder, bootstrapNodes: seq[string])
|
||||
b.bootstrapNodes = concat(b.bootstrapNodes, bootstrapNodes)
|
||||
|
||||
proc build*(b: Discv5ConfBuilder): Result[Option[Discv5Conf], string] =
|
||||
if not b.enabled.get(false):
|
||||
if not b.enabled.get(DefaultDiscv5Enabled):
|
||||
return ok(none(Discv5Conf))
|
||||
|
||||
return ok(
|
||||
some(
|
||||
Discv5Conf(
|
||||
bootstrapNodes: b.bootstrapNodes,
|
||||
bitsPerHop: b.bitsPerHop.get(1),
|
||||
bucketIpLimit: b.bucketIpLimit.get(2),
|
||||
enrAutoUpdate: b.enrAutoUpdate.get(true),
|
||||
tableIpLimit: b.tableIpLimit.get(10),
|
||||
bitsPerHop: b.bitsPerHop.get(DefaultDiscv5BitsPerHop),
|
||||
bucketIpLimit: b.bucketIpLimit.get(DefaultDiscv5BucketIpLimit),
|
||||
enrAutoUpdate: b.enrAutoUpdate.get(DefaultDiscv5EnrAutoUpdate),
|
||||
tableIpLimit: b.tableIpLimit.get(DefaultDiscv5TableIpLimit),
|
||||
udpPort: b.udpPort.get(DefaultDiscv5UdpPort),
|
||||
)
|
||||
)
|
||||
|
||||
@ -4,6 +4,12 @@ import ../waku_conf
|
||||
logScope:
|
||||
topics = "waku conf builder filter service"
|
||||
|
||||
const
|
||||
DefaultFilterEnabled: bool = false
|
||||
DefaultFilterMaxPeersToServe: uint32 = 500
|
||||
DefaultFilterSubscriptionTimeout: uint16 = 300
|
||||
DefaultFilterMaxCriteria: uint32 = 1000
|
||||
|
||||
###################################
|
||||
## Filter Service Config Builder ##
|
||||
###################################
|
||||
@ -37,15 +43,15 @@ proc withMaxCriteria*(b: var FilterServiceConfBuilder, maxCriteria: uint32) =
|
||||
b.maxCriteria = some(maxCriteria)
|
||||
|
||||
proc build*(b: FilterServiceConfBuilder): Result[Option[FilterServiceConf], string] =
|
||||
if not b.enabled.get(false):
|
||||
if not b.enabled.get(DefaultFilterEnabled):
|
||||
return ok(none(FilterServiceConf))
|
||||
|
||||
return ok(
|
||||
some(
|
||||
FilterServiceConf(
|
||||
maxPeersToServe: b.maxPeersToServe.get(500),
|
||||
subscriptionTimeout: b.subscriptionTimeout.get(300),
|
||||
maxCriteria: b.maxCriteria.get(1000),
|
||||
maxPeersToServe: b.maxPeersToServe.get(DefaultFilterMaxPeersToServe),
|
||||
subscriptionTimeout: b.subscriptionTimeout.get(DefaultFilterSubscriptionTimeout),
|
||||
maxCriteria: b.maxCriteria.get(DefaultFilterMaxCriteria),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@ -5,18 +5,20 @@ import logos_delivery/waku/factory/waku_conf
|
||||
logScope:
|
||||
topics = "waku conf builder kademlia discovery"
|
||||
|
||||
const DefaultKadEnabled*: bool = false
|
||||
|
||||
#######################################
|
||||
## Kademlia Discovery Config Builder ##
|
||||
#######################################
|
||||
type KademliaDiscoveryConfBuilder* = object
|
||||
enabled*: bool
|
||||
enabled*: Option[bool]
|
||||
bootstrapNodes*: seq[string]
|
||||
|
||||
proc init*(T: type KademliaDiscoveryConfBuilder): KademliaDiscoveryConfBuilder =
|
||||
KademliaDiscoveryConfBuilder()
|
||||
|
||||
proc withEnabled*(b: var KademliaDiscoveryConfBuilder, enabled: bool) =
|
||||
b.enabled = enabled
|
||||
b.enabled = some(enabled)
|
||||
|
||||
proc withBootstrapNodes*(
|
||||
b: var KademliaDiscoveryConfBuilder, bootstrapNodes: seq[string]
|
||||
@ -26,11 +28,12 @@ proc withBootstrapNodes*(
|
||||
proc build*(
|
||||
b: KademliaDiscoveryConfBuilder
|
||||
): Result[Option[KademliaDiscoveryConf], string] =
|
||||
# Kademlia is enabled if explicitly enabled OR if bootstrap nodes are provided
|
||||
let enabled = b.enabled or b.bootstrapNodes.len > 0
|
||||
if not enabled:
|
||||
# Explicit disable wins: enabled=false disables regardless of bootstrap nodes.
|
||||
if b.enabled == some(false):
|
||||
return ok(none(KademliaDiscoveryConf))
|
||||
# Otherwise enabled if config-enabled or any bootstrap nodes are provided.
|
||||
if not b.enabled.get(DefaultKadEnabled) and b.bootstrapNodes.len == 0:
|
||||
return ok(none(KademliaDiscoveryConf))
|
||||
|
||||
var parsedNodes: seq[(PeerId, seq[MultiAddress])]
|
||||
for nodeStr in b.bootstrapNodes:
|
||||
let (peerId, ma) = parseFullAddress(nodeStr).valueOr:
|
||||
|
||||
@ -4,7 +4,11 @@ import ../waku_conf
|
||||
logScope:
|
||||
topics = "waku conf builder metrics server"
|
||||
|
||||
const DefaultMetricsHttpPort*: Port = Port(8008)
|
||||
const
|
||||
DefaultMetricsEnabled: bool = false
|
||||
DefaultMetricsHttpAddress: IpAddress = static parseIpAddress("127.0.0.1")
|
||||
DefaultMetricsHttpPort: Port = Port(8008)
|
||||
DefaultMetricsLogging: bool = false
|
||||
|
||||
###################################
|
||||
## Metrics Server Config Builder ##
|
||||
@ -35,15 +39,15 @@ proc withLogging*(b: var MetricsServerConfBuilder, logging: bool) =
|
||||
b.logging = some(logging)
|
||||
|
||||
proc build*(b: MetricsServerConfBuilder): Result[Option[MetricsServerConf], string] =
|
||||
if not b.enabled.get(false):
|
||||
if not b.enabled.get(DefaultMetricsEnabled):
|
||||
return ok(none(MetricsServerConf))
|
||||
|
||||
return ok(
|
||||
some(
|
||||
MetricsServerConf(
|
||||
httpAddress: b.httpAddress.get(static parseIpAddress("127.0.0.1")),
|
||||
httpAddress: b.httpAddress.get(DefaultMetricsHttpAddress),
|
||||
httpPort: b.httpPort.get(DefaultMetricsHttpPort),
|
||||
logging: b.logging.get(false),
|
||||
logging: b.logging.get(DefaultMetricsLogging),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@ -5,6 +5,8 @@ import ../waku_conf, logos_delivery/waku/waku_mix
|
||||
logScope:
|
||||
topics = "waku conf builder mix"
|
||||
|
||||
const DefaultMixEnabled: bool = false
|
||||
|
||||
##################################
|
||||
## Mix Config Builder ##
|
||||
##################################
|
||||
@ -26,7 +28,7 @@ proc withMixNodes*(b: var MixConfBuilder, mixNodes: seq[MixNodePubInfo]) =
|
||||
b.mixNodes = mixNodes
|
||||
|
||||
proc build*(b: MixConfBuilder): Result[Option[MixConf], string] =
|
||||
if not b.enabled.get(false):
|
||||
if not b.enabled.get(DefaultMixEnabled):
|
||||
return ok(none[MixConf]())
|
||||
else:
|
||||
if b.mixKey.isSome():
|
||||
|
||||
@ -4,7 +4,10 @@ import ../waku_conf
|
||||
logScope:
|
||||
topics = "waku conf builder rest server"
|
||||
|
||||
const DefaultRestPort*: Port = Port(8645)
|
||||
const
|
||||
DefaultRestEnabled: bool = false
|
||||
DefaultRestPort: Port = Port(8645)
|
||||
DefaultRestAdmin: bool = false
|
||||
|
||||
################################
|
||||
## REST Server Config Builder ##
|
||||
@ -43,7 +46,7 @@ proc withRelayCacheCapacity*(b: var RestServerConfBuilder, relayCacheCapacity: u
|
||||
b.relayCacheCapacity = some(relayCacheCapacity)
|
||||
|
||||
proc build*(b: RestServerConfBuilder): Result[Option[RestServerConf], string] =
|
||||
if not b.enabled.get(false):
|
||||
if not b.enabled.get(DefaultRestEnabled):
|
||||
return ok(none(RestServerConf))
|
||||
|
||||
if b.listenAddress.isNone():
|
||||
@ -57,7 +60,7 @@ proc build*(b: RestServerConfBuilder): Result[Option[RestServerConf], string] =
|
||||
allowOrigin: b.allowOrigin,
|
||||
listenAddress: b.listenAddress.get(),
|
||||
port: b.port.get(DefaultRestPort),
|
||||
admin: b.admin.get(false),
|
||||
admin: b.admin.get(DefaultRestAdmin),
|
||||
relayCacheCapacity: b.relayCacheCapacity.get(),
|
||||
)
|
||||
)
|
||||
|
||||
@ -4,6 +4,11 @@ import ../waku_conf
|
||||
logScope:
|
||||
topics = "waku conf builder rln relay"
|
||||
|
||||
const
|
||||
DefaultRlnRelayEnabled*: bool = false
|
||||
DefaultRlnRelayEpochSizeSec*: uint64 = 1
|
||||
DefaultRlnRelayUserMessageLimit*: uint64 = 1
|
||||
|
||||
##############################
|
||||
## RLN Relay Config Builder ##
|
||||
##############################
|
||||
@ -56,7 +61,7 @@ proc withUserMessageLimit*(b: var RlnRelayConfBuilder, userMessageLimit: uint64)
|
||||
b.userMessageLimit = some(userMessageLimit)
|
||||
|
||||
proc build*(b: RlnRelayConfBuilder): Result[Option[RlnRelayConf], string] =
|
||||
if not b.enabled.get(false):
|
||||
if not b.enabled.get(DefaultRlnRelayEnabled):
|
||||
return ok(none(RlnRelayConf))
|
||||
|
||||
if b.chainId.isNone():
|
||||
@ -78,11 +83,6 @@ proc build*(b: RlnRelayConfBuilder): Result[Option[RlnRelayConf], string] =
|
||||
return err("rlnRelay.ethClientUrls is not specified")
|
||||
if b.ethContractAddress.get("") == "":
|
||||
return err("rlnRelay.ethContractAddress is not specified")
|
||||
if b.epochSizeSec.isNone():
|
||||
return err("rlnRelay.epochSizeSec is not specified")
|
||||
if b.userMessageLimit.isNone():
|
||||
return err("rlnRelay.userMessageLimit is not specified")
|
||||
|
||||
return ok(
|
||||
some(
|
||||
RlnRelayConf(
|
||||
@ -92,8 +92,8 @@ proc build*(b: RlnRelayConfBuilder): Result[Option[RlnRelayConf], string] =
|
||||
dynamic: b.dynamic.get(),
|
||||
ethClientUrls: b.ethClientUrls.get(),
|
||||
ethContractAddress: b.ethContractAddress.get(),
|
||||
epochSizeSec: b.epochSizeSec.get(),
|
||||
userMessageLimit: b.userMessageLimit.get(),
|
||||
epochSizeSec: b.epochSizeSec.get(DefaultRlnRelayEpochSizeSec),
|
||||
userMessageLimit: b.userMessageLimit.get(DefaultRlnRelayUserMessageLimit),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@ -5,6 +5,14 @@ import ../waku_conf, ./store_sync_conf_builder
|
||||
logScope:
|
||||
topics = "waku conf builder store service"
|
||||
|
||||
const
|
||||
DefaultStoreEnabled: bool = false
|
||||
DefaultStoreDbMigration: bool = true
|
||||
DefaultStoreDbVacuum: bool = false
|
||||
DefaultStoreMaxNumDbConnections: int = 50
|
||||
DefaultStoreResume: bool = false
|
||||
DefaultStoreRetentionPolicy: string = "time:" & $2.days.seconds
|
||||
|
||||
##################################
|
||||
## Store Service Config Builder ##
|
||||
##################################
|
||||
@ -77,7 +85,7 @@ proc validateRetentionPolicies(policies: seq[string]): Result[void, string] =
|
||||
return ok()
|
||||
|
||||
proc build*(b: StoreServiceConfBuilder): Result[Option[StoreServiceConf], string] =
|
||||
if not b.enabled.get(false):
|
||||
if not b.enabled.get(DefaultStoreEnabled):
|
||||
return ok(none(StoreServiceConf))
|
||||
|
||||
if b.dbUrl.get("") == "":
|
||||
@ -88,7 +96,7 @@ proc build*(b: StoreServiceConfBuilder): Result[Option[StoreServiceConf], string
|
||||
|
||||
let retentionPolicies =
|
||||
if b.retentionPolicies.len == 0:
|
||||
@["time:" & $2.days.seconds]
|
||||
@[DefaultStoreRetentionPolicy]
|
||||
else:
|
||||
validateRetentionPolicies(b.retentionPolicies).isOkOr:
|
||||
return err("invalid retention policies: " & error)
|
||||
@ -97,12 +105,12 @@ proc build*(b: StoreServiceConfBuilder): Result[Option[StoreServiceConf], string
|
||||
return ok(
|
||||
some(
|
||||
StoreServiceConf(
|
||||
dbMigration: b.dbMigration.get(true),
|
||||
dbMigration: b.dbMigration.get(DefaultStoreDbMigration),
|
||||
dbURl: b.dbUrl.get(),
|
||||
dbVacuum: b.dbVacuum.get(false),
|
||||
maxNumDbConnections: b.maxNumDbConnections.get(50),
|
||||
dbVacuum: b.dbVacuum.get(DefaultStoreDbVacuum),
|
||||
maxNumDbConnections: b.maxNumDbConnections.get(DefaultStoreMaxNumDbConnections),
|
||||
retentionPolicies: retentionPolicies,
|
||||
resume: b.resume.get(false),
|
||||
resume: b.resume.get(DefaultStoreResume),
|
||||
storeSyncConf: storeSyncConf,
|
||||
)
|
||||
)
|
||||
|
||||
@ -4,6 +4,8 @@ import ../waku_conf
|
||||
logScope:
|
||||
topics = "waku conf builder store sync"
|
||||
|
||||
const DefaultStoreSyncEnabled: bool = false
|
||||
|
||||
##################################
|
||||
## Store Sync Config Builder ##
|
||||
##################################
|
||||
@ -30,7 +32,7 @@ proc withRelayJitterSec*(b: var StoreSyncConfBuilder, relayJitterSec: uint32) =
|
||||
b.relayJitterSec = some(relayJitterSec)
|
||||
|
||||
proc build*(b: StoreSyncConfBuilder): Result[Option[StoreSyncConf], string] =
|
||||
if not b.enabled.get(false):
|
||||
if not b.enabled.get(DefaultStoreSyncEnabled):
|
||||
return ok(none(StoreSyncConf))
|
||||
|
||||
if b.rangeSec.isNone():
|
||||
|
||||
@ -13,6 +13,9 @@ import
|
||||
factory/networks_config,
|
||||
common/logging,
|
||||
common/utils/parse_size_units,
|
||||
node/peer_manager,
|
||||
waku_core/message/default_values,
|
||||
waku_core/topics/pubsub_topic,
|
||||
waku_enr/capabilities,
|
||||
persistency/persistency,
|
||||
],
|
||||
@ -35,9 +38,38 @@ import
|
||||
logScope:
|
||||
topics = "waku conf builder"
|
||||
|
||||
# Picks up the same -d:git_version=... build flag that cli_args.nim defines.
|
||||
const git_version {.strdefine.} = "(unknown)"
|
||||
|
||||
const
|
||||
DefaultMaxConnections* = 150
|
||||
DefaultP2pTcpPort*: Port = Port(60000)
|
||||
DefaultMaxConnections = 150
|
||||
DefaultRelay: bool = false
|
||||
# historical confbuilder default; wakunode2 CLI deviates (true)
|
||||
DefaultLightPush: bool = false
|
||||
DefaultPeerExchange: bool = false
|
||||
# historical confbuilder default; wakunode2 CLI deviates (true)
|
||||
DefaultStoreSyncMount: bool = false
|
||||
DefaultRendezvous: bool = false
|
||||
# historical confbuilder default; wakunode2 CLI deviates (true)
|
||||
DefaultMix*: bool = false
|
||||
DefaultRelayPeerExchange: bool = false
|
||||
DefaultLogLevel: logging.LogLevel = logging.LogLevel.INFO
|
||||
DefaultLogFormat: logging.LogFormat = logging.LogFormat.TEXT
|
||||
DefaultNatStrategy: string = "none"
|
||||
DefaultP2pTcpPort: Port = Port(60000)
|
||||
DefaultP2pListenAddress: IpAddress = static parseIpAddress("0.0.0.0")
|
||||
DefaultPortsShift: uint16 = 0
|
||||
DefaultExtMultiAddrsOnly: bool = false
|
||||
DefaultDnsAddrsNameServers: seq[IpAddress] =
|
||||
@[static parseIpAddress("1.1.1.1"), static parseIpAddress("1.0.0.1")]
|
||||
DefaultPeerPersistence: bool = false
|
||||
DefaultAgentString*: string = "logos-delivery-" & git_version
|
||||
DefaultRelayShardedPeerManagement: bool = false
|
||||
DefaultRelayServiceRatio: string = "50:50"
|
||||
DefaultCircuitRelayClient: bool = false
|
||||
DefaultP2pReliability*: bool = true
|
||||
DefaultNumShardsInCluster: uint16 = 1
|
||||
DefaultShardingConfKind: ShardingConfKind = AutoSharding
|
||||
|
||||
type MaxMessageSizeKind* = enum
|
||||
mmskNone
|
||||
@ -99,7 +131,7 @@ type WakuConfBuilder* = object
|
||||
# TODO: move within a relayConf
|
||||
rendezvous: Option[bool]
|
||||
|
||||
networkConf: Option[NetworkConf]
|
||||
networkPresetConf: Option[NetworkPresetConf]
|
||||
|
||||
staticNodes: seq[string]
|
||||
|
||||
@ -153,8 +185,10 @@ proc init*(T: type WakuConfBuilder): WakuConfBuilder =
|
||||
kademliaDiscoveryConf: KademliaDiscoveryConfBuilder.init(),
|
||||
)
|
||||
|
||||
proc withNetworkConf*(b: var WakuConfBuilder, networkConf: NetworkConf) =
|
||||
b.networkConf = some(networkConf)
|
||||
proc withNetworkPresetConf*(
|
||||
b: var WakuConfBuilder, networkPresetConf: NetworkPresetConf
|
||||
) =
|
||||
b.networkPresetConf = some(networkPresetConf)
|
||||
|
||||
proc withNodeKey*(b: var WakuConfBuilder, nodeKey: crypto.PrivateKey) =
|
||||
b.nodeKey = some(nodeKey)
|
||||
@ -309,121 +343,129 @@ proc buildShardingConf(
|
||||
bNumShardsInCluster: Option[uint16],
|
||||
bSubscribeShards: Option[seq[uint16]],
|
||||
): (ShardingConf, seq[uint16]) =
|
||||
case bShardingConfKind.get(AutoSharding)
|
||||
case bShardingConfKind.get(DefaultShardingConfKind)
|
||||
of StaticSharding:
|
||||
(ShardingConf(kind: StaticSharding), bSubscribeShards.get(@[]))
|
||||
of AutoSharding:
|
||||
let numShardsInCluster = bNumShardsInCluster.get(1)
|
||||
let numShardsInCluster = bNumShardsInCluster.get(DefaultNumShardsInCluster)
|
||||
let shardingConf =
|
||||
ShardingConf(kind: AutoSharding, numShardsInCluster: numShardsInCluster)
|
||||
let upperShard = uint16(numShardsInCluster - 1)
|
||||
(shardingConf, bSubscribeShards.get(toSeq(0.uint16 .. upperShard)))
|
||||
|
||||
proc applyNetworkConf(builder: var WakuConfBuilder) =
|
||||
# Apply network conf, overrides most values passed individually
|
||||
# If you want to tweak values, don't use networkConf
|
||||
# TODO: networkconf should be one field of the conf builder so that this function becomes unnecessary
|
||||
if builder.networkConf.isNone():
|
||||
return
|
||||
let networkConf = builder.networkConf.get()
|
||||
template checkSetPresetValueToField[T](
|
||||
field: var Option[T], presetVal: T, msg: static string
|
||||
) =
|
||||
## Set the field to the preset's value, unless the field is already set
|
||||
## (explicit wins). Warn iff the field's existing value differs from the
|
||||
## preset's. No-op if they agree.
|
||||
|
||||
if builder.clusterId.isSome():
|
||||
warn "Cluster id was provided alongside a network conf",
|
||||
used = networkConf.clusterId, discarded = builder.clusterId.get()
|
||||
builder.clusterId = some(networkConf.clusterId)
|
||||
if field.isSome():
|
||||
if field.get() != presetVal:
|
||||
warn msg, used = field.get(), discarded = presetVal
|
||||
else:
|
||||
field = some(presetVal)
|
||||
|
||||
proc checkAddPresetValueToField[T](field: var seq[T], presetVals: seq[T]) =
|
||||
## Append the preset's list values to the field's existing list. Lists
|
||||
## concat rather than override; both the user's and the preset's entries
|
||||
## end up in the final list.
|
||||
|
||||
field = field & presetVals
|
||||
|
||||
proc applyNetworkPresetConf(builder: var WakuConfBuilder) =
|
||||
## NetworkPresetConf = network presets.
|
||||
## Cascade the chosen preset's values onto builder fields the user hasn't set.
|
||||
## User-set fields stay; preset fills the gaps and warns on conflict (explicit wins).
|
||||
## List fields concat (preset's nodes appended to user's).
|
||||
|
||||
if builder.networkPresetConf.isNone():
|
||||
return # If there is no preset given, then nothing to do.
|
||||
|
||||
let networkPresetConf = builder.networkPresetConf.get()
|
||||
|
||||
checkSetPresetValueToField(
|
||||
builder.clusterId, networkPresetConf.clusterId,
|
||||
"Cluster id was provided alongside a network conf",
|
||||
)
|
||||
|
||||
# Apply relay parameters
|
||||
if builder.relay.get(false) and networkConf.rlnRelay:
|
||||
if builder.rlnRelayConf.enabled.isSome():
|
||||
warn "RLN Relay was provided alongside a network conf",
|
||||
used = networkConf.rlnRelay, discarded = builder.rlnRelayConf.enabled
|
||||
builder.rlnRelayConf.withEnabled(true)
|
||||
|
||||
if builder.rlnRelayConf.ethContractAddress.get("") != "":
|
||||
warn "RLN Relay ETH Contract Address was provided alongside a network conf",
|
||||
used = networkConf.rlnRelayEthContractAddress.string,
|
||||
discarded = builder.rlnRelayConf.ethContractAddress.get().string
|
||||
builder.rlnRelayConf.withEthContractAddress(networkConf.rlnRelayEthContractAddress)
|
||||
|
||||
if builder.rlnRelayConf.chainId.isSome():
|
||||
warn "RLN Relay Chain Id was provided alongside a network conf",
|
||||
used = networkConf.rlnRelayChainId, discarded = builder.rlnRelayConf.chainId
|
||||
builder.rlnRelayConf.withChainId(networkConf.rlnRelayChainId)
|
||||
|
||||
if builder.rlnRelayConf.dynamic.isSome():
|
||||
warn "RLN Relay Dynamic was provided alongside a network conf",
|
||||
used = networkConf.rlnRelayDynamic, discarded = builder.rlnRelayConf.dynamic
|
||||
builder.rlnRelayConf.withDynamic(networkConf.rlnRelayDynamic)
|
||||
|
||||
if builder.rlnRelayConf.epochSizeSec.isSome():
|
||||
warn "RLN Epoch Size in Seconds was provided alongside a network conf",
|
||||
used = networkConf.rlnEpochSizeSec,
|
||||
discarded = builder.rlnRelayConf.epochSizeSec
|
||||
builder.rlnRelayConf.withEpochSizeSec(networkConf.rlnEpochSizeSec)
|
||||
|
||||
if builder.rlnRelayConf.userMessageLimit.isSome():
|
||||
warn "RLN Relay User Message Limit was provided alongside a network conf",
|
||||
used = networkConf.rlnRelayUserMessageLimit,
|
||||
discarded = builder.rlnRelayConf.userMessageLimit
|
||||
if builder.rlnRelayConf.userMessageLimit.get(0) == 0:
|
||||
## only override with the "preset" value if there was not explicit set value
|
||||
builder.rlnRelayConf.withUserMessageLimit(networkConf.rlnRelayUserMessageLimit)
|
||||
|
||||
if builder.relay.get(DefaultRelay) and networkPresetConf.rlnRelay:
|
||||
checkSetPresetValueToField(
|
||||
builder.rlnRelayConf.enabled,
|
||||
networkPresetConf.rlnRelay, # true
|
||||
"RLN Relay was provided alongside a network conf",
|
||||
)
|
||||
checkSetPresetValueToField(
|
||||
builder.rlnRelayConf.ethContractAddress,
|
||||
networkPresetConf.rlnRelayEthContractAddress,
|
||||
"RLN Relay ETH Contract Address was provided alongside a network conf",
|
||||
)
|
||||
checkSetPresetValueToField(
|
||||
builder.rlnRelayConf.chainId, networkPresetConf.rlnRelayChainId,
|
||||
"RLN Relay Chain Id was provided alongside a network conf",
|
||||
)
|
||||
checkSetPresetValueToField(
|
||||
builder.rlnRelayConf.dynamic, networkPresetConf.rlnRelayDynamic,
|
||||
"RLN Relay Dynamic was provided alongside a network conf",
|
||||
)
|
||||
checkSetPresetValueToField(
|
||||
builder.rlnRelayConf.epochSizeSec, networkPresetConf.rlnEpochSizeSec,
|
||||
"RLN Epoch Size in Seconds was provided alongside a network conf",
|
||||
)
|
||||
checkSetPresetValueToField(
|
||||
builder.rlnRelayConf.userMessageLimit, networkPresetConf.rlnRelayUserMessageLimit,
|
||||
"RLN Relay User Message Limit was provided alongside a network conf",
|
||||
)
|
||||
# End Apply relay parameters
|
||||
|
||||
case builder.maxMessageSize.kind
|
||||
of mmskNone:
|
||||
discard
|
||||
builder.withMaxMessageSize(parseCorrectMsgSize(networkPresetConf.maxMessageSize))
|
||||
of mmskStr, mmskInt:
|
||||
warn "Max Message Size was provided alongside a network conf",
|
||||
used = networkConf.maxMessageSize, discarded = $builder.maxMessageSize
|
||||
builder.withMaxMessageSize(parseCorrectMsgSize(networkConf.maxMessageSize))
|
||||
used = $builder.maxMessageSize, discarded = networkPresetConf.maxMessageSize
|
||||
|
||||
if builder.shardingConf.isSome():
|
||||
warn "Sharding Conf was provided alongside a network conf",
|
||||
used = networkConf.shardingConf.kind, discarded = builder.shardingConf
|
||||
|
||||
case networkConf.shardingConf.kind
|
||||
of StaticSharding:
|
||||
builder.shardingConf = some(StaticSharding)
|
||||
checkSetPresetValueToField(
|
||||
builder.shardingConf, networkPresetConf.shardingConf.kind,
|
||||
"Sharding Conf was provided alongside a network conf",
|
||||
)
|
||||
case networkPresetConf.shardingConf.kind
|
||||
of AutoSharding:
|
||||
builder.shardingConf = some(AutoSharding)
|
||||
if builder.numShardsInCluster.isSome():
|
||||
warn "Num Shards In Cluster overrides network conf preset",
|
||||
used = builder.numShardsInCluster.get(),
|
||||
ignored = networkConf.shardingConf.numShardsInCluster
|
||||
else:
|
||||
builder.numShardsInCluster = some(networkConf.shardingConf.numShardsInCluster)
|
||||
checkSetPresetValueToField(
|
||||
builder.numShardsInCluster, networkPresetConf.shardingConf.numShardsInCluster,
|
||||
"Num Shards In Cluster overrides network conf preset",
|
||||
)
|
||||
of StaticSharding:
|
||||
discard
|
||||
|
||||
if networkConf.discv5Discovery:
|
||||
if builder.discv5Conf.enabled.isNone:
|
||||
builder.discv5Conf.withEnabled(networkConf.discv5Discovery)
|
||||
checkSetPresetValueToField(
|
||||
builder.discv5Conf.enabled, networkPresetConf.discv5Discovery,
|
||||
"Discv5 Discovery was provided alongside a network conf",
|
||||
)
|
||||
checkAddPresetValueToField(
|
||||
builder.discv5Conf.bootstrapNodes, networkPresetConf.discv5BootstrapNodes
|
||||
)
|
||||
|
||||
if builder.discv5Conf.bootstrapNodes.len == 0 and
|
||||
networkConf.discv5BootstrapNodes.len > 0:
|
||||
warn "Discv5 Bootstrap nodes were provided alongside a network conf",
|
||||
used = networkConf.discv5BootstrapNodes,
|
||||
discarded = builder.discv5Conf.bootstrapNodes
|
||||
builder.discv5Conf.withBootstrapNodes(networkConf.discv5BootstrapNodes)
|
||||
checkSetPresetValueToField(
|
||||
builder.kademliaDiscoveryConf.enabled, networkPresetConf.enableKadDiscovery,
|
||||
"Kademlia Discovery was provided alongside a network conf",
|
||||
)
|
||||
checkAddPresetValueToField(
|
||||
builder.kademliaDiscoveryConf.bootstrapNodes, networkPresetConf.kadBootstrapNodes
|
||||
)
|
||||
|
||||
if networkConf.enableKadDiscovery:
|
||||
if not builder.kademliaDiscoveryConf.enabled:
|
||||
builder.kademliaDiscoveryConf.withEnabled(networkConf.enableKadDiscovery)
|
||||
|
||||
if builder.kademliaDiscoveryConf.bootstrapNodes.len == 0 and
|
||||
networkConf.kadBootstrapNodes.len > 0:
|
||||
builder.kademliaDiscoveryConf.withBootstrapNodes(networkConf.kadBootstrapNodes)
|
||||
|
||||
if networkConf.mix:
|
||||
if builder.mix.isNone:
|
||||
builder.mix = some(networkConf.mix)
|
||||
|
||||
if builder.p2pReliability.isNone:
|
||||
builder.withP2pReliability(networkConf.p2pReliability)
|
||||
checkSetPresetValueToField(
|
||||
builder.mix, networkPresetConf.mix, "Mix was provided alongside a network conf"
|
||||
)
|
||||
checkSetPresetValueToField(
|
||||
builder.p2pReliability, networkPresetConf.p2pReliability,
|
||||
"P2P Reliability was provided alongside a network conf",
|
||||
)
|
||||
|
||||
# Process entry nodes from network config - classify and distribute
|
||||
if networkConf.entryNodes.len > 0:
|
||||
let processed = processEntryNodes(networkConf.entryNodes)
|
||||
if networkPresetConf.entryNodes.len > 0:
|
||||
let processed = processEntryNodes(networkPresetConf.entryNodes)
|
||||
if processed.isOk():
|
||||
let (enrTreeUrls, bootstrapEnrs, staticNodesFromEntry) = processed.get()
|
||||
|
||||
@ -442,6 +484,47 @@ proc applyNetworkConf(builder: var WakuConfBuilder) =
|
||||
else:
|
||||
warn "Failed to process entry nodes from network conf", error = processed.error()
|
||||
|
||||
proc rejectOverride[T](
|
||||
field: Option[T], presetValue: T, msg: string
|
||||
): Result[void, string] =
|
||||
## Errors with `msg` if `field` is set to anything other than the preset's value.
|
||||
if field.isSome() and field.get() != presetValue:
|
||||
return err(msg)
|
||||
ok()
|
||||
|
||||
proc enforceSecurityConstraints(builder: WakuConfBuilder): Result[void, string] =
|
||||
## Errors if the resolved config violates a security constraint.
|
||||
|
||||
if builder.networkPresetConf.isSome():
|
||||
let preset = builder.networkPresetConf.get()
|
||||
let relayEnabled = builder.relay.get(DefaultRelay)
|
||||
let rlnRelayConf = builder.rlnRelayConf
|
||||
let rlnRelayEnabled = rlnRelayConf.enabled.get(DefaultRlnRelayEnabled)
|
||||
|
||||
if relayEnabled and preset.rlnRelay:
|
||||
if not rlnRelayEnabled:
|
||||
return
|
||||
err("network preset mandates RLN relay: cannot relay with rln-relay disabled")
|
||||
|
||||
?rejectOverride(
|
||||
rlnRelayConf.ethContractAddress, preset.rlnRelayEthContractAddress,
|
||||
"network preset mandates its RLN contract: cannot relay with a different rln-relay-eth-contract-address",
|
||||
)
|
||||
?rejectOverride(
|
||||
rlnRelayConf.chainId, preset.rlnRelayChainId,
|
||||
"network preset mandates its RLN chain id: cannot relay with a different rln-relay-chain-id",
|
||||
)
|
||||
?rejectOverride(
|
||||
rlnRelayConf.dynamic, preset.rlnRelayDynamic,
|
||||
"network preset mandates its RLN membership mode: cannot relay with a different rln-relay-dynamic",
|
||||
)
|
||||
?rejectOverride(
|
||||
rlnRelayConf.epochSizeSec, preset.rlnEpochSizeSec,
|
||||
"network preset mandates its RLN epoch size: cannot relay with a different rln-relay-epoch-sec",
|
||||
)
|
||||
|
||||
ok()
|
||||
|
||||
proc build*(
|
||||
builder: var WakuConfBuilder, rng: ref HmacDrbgContext = crypto.newRng()
|
||||
): Result[WakuConf, string] =
|
||||
@ -450,51 +533,59 @@ proc build*(
|
||||
## of libwaku. It aims to be agnostic so it does not apply a
|
||||
## default when it is opinionated.
|
||||
|
||||
applyNetworkConf(builder)
|
||||
applyNetworkPresetConf(builder)
|
||||
|
||||
# We should not ignore any user-supplied config parameter: the user is
|
||||
# allowed to override any preset parameter with any explicit config
|
||||
# parameter. However, we do gate config building with an error if any
|
||||
# one of these preset overrides is considered a security concern.
|
||||
# This eliminates ambiguous behavior such as warning of an override and
|
||||
# then ignoring it: either fail-fast or accept the override.
|
||||
?enforceSecurityConstraints(builder)
|
||||
|
||||
let relay =
|
||||
if builder.relay.isSome():
|
||||
builder.relay.get()
|
||||
else:
|
||||
warn "whether to mount relay is not specified, defaulting to not mounting"
|
||||
false
|
||||
DefaultRelay
|
||||
|
||||
let lightPush =
|
||||
if builder.lightPush.isSome():
|
||||
builder.lightPush.get()
|
||||
else:
|
||||
warn "whether to mount lightPush is not specified, defaulting to not mounting"
|
||||
false
|
||||
DefaultLightPush
|
||||
|
||||
let peerExchange =
|
||||
if builder.peerExchange.isSome():
|
||||
builder.peerExchange.get()
|
||||
else:
|
||||
warn "whether to mount peerExchange is not specified, defaulting to not mounting"
|
||||
false
|
||||
DefaultPeerExchange
|
||||
|
||||
let storeSync =
|
||||
if builder.storeSync.isSome():
|
||||
builder.storeSync.get()
|
||||
else:
|
||||
warn "whether to mount storeSync is not specified, defaulting to not mounting"
|
||||
false
|
||||
DefaultStoreSyncMount
|
||||
|
||||
let rendezvous =
|
||||
if builder.rendezvous.isSome():
|
||||
builder.rendezvous.get()
|
||||
else:
|
||||
warn "whether to mount rendezvous is not specified, defaulting to not mounting"
|
||||
false
|
||||
DefaultRendezvous
|
||||
|
||||
let mix =
|
||||
if builder.mix.isSome():
|
||||
builder.mix.get()
|
||||
else:
|
||||
warn "whether to mount mix is not specified, defaulting to not mounting"
|
||||
false
|
||||
DefaultMix
|
||||
|
||||
let relayPeerExchange = builder.relayPeerExchange.get(false)
|
||||
let relayPeerExchange = builder.relayPeerExchange.get(DefaultRelayPeerExchange)
|
||||
|
||||
let nodeKey = ?nodeKey(builder, rng)
|
||||
|
||||
@ -503,7 +594,7 @@ proc build*(
|
||||
# TODO: ClusterId should never be defaulted, instead, presets
|
||||
# should be defined and used
|
||||
warn("Cluster Id was not specified, defaulting to 0")
|
||||
0.uint16
|
||||
DefaultClusterId
|
||||
else:
|
||||
builder.clusterId.get().uint16
|
||||
|
||||
@ -522,8 +613,9 @@ proc build*(
|
||||
of mmskStr:
|
||||
?parseMsgSize(builder.maxMessageSize.str)
|
||||
else:
|
||||
warn "Max Message Size not specified, defaulting to 150KiB"
|
||||
parseCorrectMsgSize("150KiB")
|
||||
warn "Max Message Size not specified, defaulting to DefaultMaxWakuMessageSize",
|
||||
default = DefaultMaxWakuMessageSizeStr
|
||||
DefaultMaxWakuMessageSize
|
||||
|
||||
let contentTopics = builder.contentTopics.get(@[])
|
||||
|
||||
@ -568,21 +660,21 @@ proc build*(
|
||||
builder.logLevel.get()
|
||||
else:
|
||||
warn "Log Level not specified, defaulting to INFO"
|
||||
logging.LogLevel.INFO
|
||||
DefaultLogLevel
|
||||
|
||||
let logFormat =
|
||||
if builder.logFormat.isSome():
|
||||
builder.logFormat.get()
|
||||
else:
|
||||
warn "Log Format not specified, defaulting to TEXT"
|
||||
logging.LogFormat.TEXT
|
||||
DefaultLogFormat
|
||||
|
||||
let natStrategy =
|
||||
if builder.natStrategy.isSome():
|
||||
builder.natStrategy.get()
|
||||
else:
|
||||
warn "Nat Strategy is not specified, defaulting to none"
|
||||
"none"
|
||||
DefaultNatStrategy
|
||||
|
||||
let p2pTcpPort = builder.p2pTcpPort.get(DefaultP2pTcpPort)
|
||||
|
||||
@ -591,14 +683,14 @@ proc build*(
|
||||
builder.p2pListenAddress.get()
|
||||
else:
|
||||
warn "P2P listening address not specified, listening on 0.0.0.0"
|
||||
(static parseIpAddress("0.0.0.0"))
|
||||
DefaultP2pListenAddress
|
||||
|
||||
let portsShift =
|
||||
if builder.portsShift.isSome():
|
||||
builder.portsShift.get()
|
||||
else:
|
||||
warn "Ports Shift is not specified, defaulting to 0"
|
||||
0.uint16
|
||||
DefaultPortsShift
|
||||
|
||||
let dns4DomainName =
|
||||
if builder.dns4DomainName.isSome():
|
||||
@ -621,21 +713,21 @@ proc build*(
|
||||
builder.extMultiAddrsOnly.get()
|
||||
else:
|
||||
warn "Whether to only announce external multiaddresses is not specified, defaulting to false"
|
||||
false
|
||||
DefaultExtMultiAddrsOnly
|
||||
|
||||
let dnsAddrsNameServers =
|
||||
if builder.dnsAddrsNameServers.len != 0:
|
||||
builder.dnsAddrsNameServers
|
||||
else:
|
||||
warn "DNS name servers IPs not provided, defaulting to Cloudflare's."
|
||||
@[static parseIpAddress("1.1.1.1"), static parseIpAddress("1.0.0.1")]
|
||||
DefaultDnsAddrsNameServers
|
||||
|
||||
let peerPersistence =
|
||||
if builder.peerPersistence.isSome():
|
||||
builder.peerPersistence.get()
|
||||
else:
|
||||
warn "Peer persistence not specified, defaulting to false"
|
||||
false
|
||||
DefaultPeerPersistence
|
||||
|
||||
let maxConnections =
|
||||
if builder.maxConnections.isSome():
|
||||
@ -649,15 +741,13 @@ proc build*(
|
||||
warn "max-connections less than DefaultMaxConnections; we suggest using DefaultMaxConnections or more for better connectivity",
|
||||
provided = maxConnections, recommended = DefaultMaxConnections
|
||||
|
||||
# TODO: Do the git version thing here
|
||||
let agentString = builder.agentString.get("logos-delivery")
|
||||
let agentString = builder.agentString.get(DefaultAgentString)
|
||||
|
||||
# TODO: use `DefaultColocationLimit`. the user of this value should
|
||||
# probably be defining a config object
|
||||
let colocationLimit = builder.colocationLimit.get(5)
|
||||
let colocationLimit = builder.colocationLimit.get(DefaultColocationLimit)
|
||||
|
||||
# TODO: is there a strategy for experimental features? delete vs promote
|
||||
let relayShardedPeerManagement = builder.relayShardedPeerManagement.get(false)
|
||||
let relayShardedPeerManagement =
|
||||
builder.relayShardedPeerManagement.get(DefaultRelayShardedPeerManagement)
|
||||
|
||||
let wakuFlags = CapabilitiesBitfield.init(
|
||||
lightpush = lightPush and relay,
|
||||
@ -718,12 +808,12 @@ proc build*(
|
||||
agentString: agentString,
|
||||
colocationLimit: colocationLimit,
|
||||
maxRelayPeers: builder.maxRelayPeers,
|
||||
relayServiceRatio: builder.relayServiceRatio.get("50:50"),
|
||||
relayServiceRatio: builder.relayServiceRatio.get(DefaultRelayServiceRatio),
|
||||
rateLimit: rateLimit,
|
||||
circuitRelayClient: builder.circuitRelayClient.get(false),
|
||||
circuitRelayClient: builder.circuitRelayClient.get(DefaultCircuitRelayClient),
|
||||
staticNodes: builder.staticNodes,
|
||||
relayShardedPeerManagement: relayShardedPeerManagement,
|
||||
p2pReliability: builder.p2pReliability.get(false),
|
||||
p2pReliability: builder.p2pReliability.get(DefaultP2pReliability),
|
||||
wakuFlags: wakuFlags,
|
||||
localStoragePath: builder.localStoragePath.get(DefaultStoragePath),
|
||||
)
|
||||
|
||||
@ -4,7 +4,10 @@ import logos_delivery/waku/factory/waku_conf
|
||||
logScope:
|
||||
topics = "waku conf builder websocket"
|
||||
|
||||
const DefaultWebSocketPort*: Port = Port(8000)
|
||||
const
|
||||
DefaultWebSocketEnabled: bool = false
|
||||
DefaultWebSocketSecureEnabled: bool = false
|
||||
DefaultWebSocketPort: Port = Port(8000)
|
||||
|
||||
##############################
|
||||
## WebSocket Config Builder ##
|
||||
@ -40,10 +43,10 @@ proc withCertPath*(b: var WebSocketConfBuilder, certPath: string) =
|
||||
b.certPath = some(certPath)
|
||||
|
||||
proc build*(b: WebSocketConfBuilder): Result[Option[WebSocketConf], string] =
|
||||
if not b.enabled.get(false):
|
||||
if not b.enabled.get(DefaultWebSocketEnabled):
|
||||
return ok(none(WebSocketConf))
|
||||
|
||||
if not b.secureEnabled.get(false):
|
||||
if not b.secureEnabled.get(DefaultWebSocketSecureEnabled):
|
||||
return ok(
|
||||
some(
|
||||
WebSocketConf(
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{.push raises: [].}
|
||||
|
||||
import chronicles, results, stint
|
||||
import logos_delivery/waku/waku_core/message/default_values
|
||||
|
||||
logScope:
|
||||
topics = "waku networks conf"
|
||||
@ -17,7 +18,8 @@ type
|
||||
of StaticSharding:
|
||||
discard
|
||||
|
||||
type NetworkConf* = object
|
||||
type NetworkPresetConf* = object
|
||||
## A network "preset" (--preset=twn, --preset=logos.dev).
|
||||
maxMessageSize*: string # TODO: static convert to a uint64
|
||||
clusterId*: uint16
|
||||
rlnRelay*: bool
|
||||
@ -38,10 +40,10 @@ type NetworkConf* = object
|
||||
# cluster-id=1 (aka The Waku Network)
|
||||
# Cluster configuration corresponding to The Waku Network. Note that it
|
||||
# overrides existing cli configuration
|
||||
proc TheWakuNetworkConf*(T: type NetworkConf): NetworkConf =
|
||||
proc TheWakuNetworkConf*(T: type NetworkPresetConf): NetworkPresetConf =
|
||||
const RelayChainId = 59141'u256
|
||||
return NetworkConf(
|
||||
maxMessageSize: "150KiB",
|
||||
return NetworkPresetConf(
|
||||
maxMessageSize: DefaultMaxWakuMessageSizeStr,
|
||||
clusterId: 1,
|
||||
rlnRelay: true,
|
||||
rlnRelayEthContractAddress: "0xB9cd878C90E49F797B4431fBF4fb333108CB90e6",
|
||||
@ -65,10 +67,10 @@ proc TheWakuNetworkConf*(T: type NetworkConf): NetworkConf =
|
||||
|
||||
# cluster-id=2 (Logos Dev Network)
|
||||
# Cluster configuration for the Logos Dev Network.
|
||||
proc LogosDevConf*(T: type NetworkConf): NetworkConf =
|
||||
proc LogosDevConf*(T: type NetworkPresetConf): NetworkPresetConf =
|
||||
const ZeroChainId = 0'u256
|
||||
return NetworkConf(
|
||||
maxMessageSize: "150KiB",
|
||||
return NetworkPresetConf(
|
||||
maxMessageSize: DefaultMaxWakuMessageSizeStr,
|
||||
clusterId: 2,
|
||||
rlnRelay: false,
|
||||
rlnRelayEthContractAddress: "",
|
||||
@ -94,9 +96,9 @@ proc LogosDevConf*(T: type NetworkConf): NetworkConf =
|
||||
|
||||
# cluster-id=2 (Logos Test Network)
|
||||
# Cluster configuration for the Logos Test Network.
|
||||
proc LogosTestConf*(T: type NetworkConf): NetworkConf =
|
||||
proc LogosTestConf*(T: type NetworkPresetConf): NetworkPresetConf =
|
||||
const ZeroChainId = 0'u256
|
||||
return NetworkConf(
|
||||
return NetworkPresetConf(
|
||||
maxMessageSize: "150KiB",
|
||||
clusterId: 2,
|
||||
rlnRelay: false,
|
||||
|
||||
@ -98,7 +98,7 @@ suite "LM API health checking":
|
||||
conf.listenAddress = parseIpAddress("0.0.0.0")
|
||||
conf.tcpPort = Port(0)
|
||||
conf.discv5UdpPort = Port(0)
|
||||
conf.clusterId = 3'u16
|
||||
conf.clusterId = some(3'u16)
|
||||
conf.numShardsInNetwork = 1
|
||||
conf.rest = false
|
||||
|
||||
@ -277,7 +277,7 @@ suite "LM API health checking":
|
||||
edgeConf.listenAddress = parseIpAddress("0.0.0.0")
|
||||
edgeConf.tcpPort = Port(0)
|
||||
edgeConf.discv5UdpPort = Port(0)
|
||||
edgeConf.clusterId = 3'u16
|
||||
edgeConf.clusterId = some(3'u16)
|
||||
edgeConf.maxMessageSize = "150 KiB"
|
||||
edgeConf.rest = false
|
||||
|
||||
|
||||
@ -67,9 +67,9 @@ proc createApiNodeConf(numShards: uint16 = 1): WakuNodeConf =
|
||||
conf.listenAddress = parseIpAddress("0.0.0.0")
|
||||
conf.tcpPort = Port(0)
|
||||
conf.discv5UdpPort = Port(0)
|
||||
conf.clusterId = 3'u16
|
||||
conf.clusterId = some(3'u16)
|
||||
conf.numShardsInNetwork = numShards
|
||||
conf.reliabilityEnabled = true
|
||||
conf.reliabilityEnabled = some(true)
|
||||
conf.rest = false
|
||||
result = conf
|
||||
|
||||
|
||||
@ -126,9 +126,9 @@ proc createApiNodeConf(mode: cli_args.WakuMode = cli_args.WakuMode.Core): WakuNo
|
||||
conf.listenAddress = parseIpAddress("0.0.0.0")
|
||||
conf.tcpPort = Port(0)
|
||||
conf.discv5UdpPort = Port(0)
|
||||
conf.clusterId = 3'u16
|
||||
conf.clusterId = some(3'u16)
|
||||
conf.numShardsInNetwork = 1
|
||||
conf.reliabilityEnabled = true
|
||||
conf.reliabilityEnabled = some(true)
|
||||
conf.rest = false
|
||||
result = conf
|
||||
|
||||
|
||||
@ -77,9 +77,9 @@ proc createApiNodeConf(
|
||||
conf.listenAddress = parseIpAddress("0.0.0.0")
|
||||
conf.tcpPort = Port(0)
|
||||
conf.discv5UdpPort = Port(0)
|
||||
conf.clusterId = 3'u16
|
||||
conf.clusterId = some(3'u16)
|
||||
conf.numShardsInNetwork = numShards
|
||||
conf.reliabilityEnabled = true
|
||||
conf.reliabilityEnabled = some(true)
|
||||
conf.rest = false
|
||||
result = conf
|
||||
|
||||
|
||||
@ -1,43 +1,23 @@
|
||||
{.used.}
|
||||
|
||||
import std/[options, json, strutils], results, stint, testutils/unittests
|
||||
import std/[options, strutils], results, stint, testutils/unittests
|
||||
import json_serialization, confutils, confutils/std/net
|
||||
import
|
||||
tools/confutils/cli_args,
|
||||
tools/confutils/conf_from_json,
|
||||
logos_delivery/waku/api/api_conf,
|
||||
logos_delivery/waku/factory/waku_conf,
|
||||
logos_delivery/waku/factory/networks_config,
|
||||
logos_delivery/waku/factory/conf_builder/conf_builder,
|
||||
logos_delivery/waku/common/logging
|
||||
|
||||
# Helper: parse JSON into WakuNodeConf using fieldPairs (same as liblogosdelivery)
|
||||
proc parseWakuNodeConfFromJson(jsonStr: string): Result[WakuNodeConf, string] =
|
||||
var conf = defaultWakuNodeConf().valueOr:
|
||||
return err(error)
|
||||
var jsonNode: JsonNode
|
||||
try:
|
||||
jsonNode = parseJson(jsonStr)
|
||||
except Exception:
|
||||
return err("JSON parse error: " & getCurrentExceptionMsg())
|
||||
for confField, confValue in fieldPairs(conf):
|
||||
if jsonNode.contains(confField):
|
||||
let formattedString = ($jsonNode[confField]).strip(chars = {'\"'})
|
||||
try:
|
||||
confValue = parseCmdArg(typeof(confValue), formattedString)
|
||||
except Exception:
|
||||
return err(
|
||||
"Field '" & confField & "' parse error: " & getCurrentExceptionMsg() &
|
||||
". Value: " & formattedString
|
||||
)
|
||||
return ok(conf)
|
||||
|
||||
suite "WakuNodeConf - mode-driven toWakuConf":
|
||||
test "Core mode enables service protocols":
|
||||
## Given
|
||||
var conf = defaultWakuNodeConf().valueOr:
|
||||
raiseAssert error
|
||||
conf.mode = Core
|
||||
conf.clusterId = 1
|
||||
conf.clusterId = some(1'u16)
|
||||
|
||||
## When
|
||||
let wakuConfRes = conf.toWakuConf()
|
||||
@ -58,7 +38,7 @@ suite "WakuNodeConf - mode-driven toWakuConf":
|
||||
var conf = defaultWakuNodeConf().valueOr:
|
||||
raiseAssert error
|
||||
conf.mode = Edge
|
||||
conf.clusterId = 1
|
||||
conf.clusterId = some(1'u16)
|
||||
|
||||
## When
|
||||
let wakuConfRes = conf.toWakuConf()
|
||||
@ -81,7 +61,7 @@ suite "WakuNodeConf - mode-driven toWakuConf":
|
||||
conf.mode = cli_args.WakuMode.noMode
|
||||
conf.relay = true
|
||||
conf.lightpush = false
|
||||
conf.clusterId = 5
|
||||
conf.clusterId = some(5'u16)
|
||||
|
||||
## When
|
||||
let wakuConfRes = conf.toWakuConf()
|
||||
@ -115,30 +95,30 @@ suite "WakuNodeConf - mode-driven toWakuConf":
|
||||
suite "WakuNodeConf - JSON parsing with fieldPairs":
|
||||
test "Empty JSON produces valid default conf":
|
||||
## Given / When
|
||||
let confRes = parseWakuNodeConfFromJson("{}")
|
||||
let confRes = parseNodeConfFromJson("{}")
|
||||
|
||||
## Then
|
||||
require confRes.isOk()
|
||||
let conf = confRes.get()
|
||||
check:
|
||||
conf.mode == cli_args.WakuMode.noMode
|
||||
conf.clusterId == 0
|
||||
conf.clusterId.isNone()
|
||||
conf.logLevel == logging.LogLevel.INFO
|
||||
|
||||
test "JSON with mode and clusterId":
|
||||
## Given / When
|
||||
let confRes = parseWakuNodeConfFromJson("""{"mode": "Core", "clusterId": 42}""")
|
||||
let confRes = parseNodeConfFromJson("""{"mode": "Core", "clusterId": 42}""")
|
||||
|
||||
## Then
|
||||
require confRes.isOk()
|
||||
let conf = confRes.get()
|
||||
check:
|
||||
conf.mode == Core
|
||||
conf.clusterId == 42
|
||||
conf.clusterId == some(42'u16)
|
||||
|
||||
test "JSON with Edge mode":
|
||||
## Given / When
|
||||
let confRes = parseWakuNodeConfFromJson("""{"mode": "Edge"}""")
|
||||
let confRes = parseNodeConfFromJson("""{"mode": "Edge"}""")
|
||||
|
||||
## Then
|
||||
require confRes.isOk()
|
||||
@ -148,7 +128,7 @@ suite "WakuNodeConf - JSON parsing with fieldPairs":
|
||||
|
||||
test "JSON with logLevel":
|
||||
## Given / When
|
||||
let confRes = parseWakuNodeConfFromJson("""{"logLevel": "DEBUG"}""")
|
||||
let confRes = parseNodeConfFromJson("""{"logLevel": "DEBUG"}""")
|
||||
|
||||
## Then
|
||||
require confRes.isOk()
|
||||
@ -159,29 +139,25 @@ suite "WakuNodeConf - JSON parsing with fieldPairs":
|
||||
test "JSON with sharding config":
|
||||
## Given / When
|
||||
let confRes =
|
||||
parseWakuNodeConfFromJson("""{"clusterId": 99, "numShardsInNetwork": 16}""")
|
||||
parseNodeConfFromJson("""{"clusterId": 99, "numShardsInNetwork": 16}""")
|
||||
|
||||
## Then
|
||||
require confRes.isOk()
|
||||
let conf = confRes.get()
|
||||
check:
|
||||
conf.clusterId == 99
|
||||
conf.clusterId == some(99'u16)
|
||||
conf.numShardsInNetwork == 16
|
||||
|
||||
test "JSON with unknown fields is silently ignored":
|
||||
test "JSON with unknown fields is rejected":
|
||||
## Given / When
|
||||
let confRes =
|
||||
parseWakuNodeConfFromJson("""{"unknownField": true, "clusterId": 5}""")
|
||||
let confRes = parseNodeConfFromJson("""{"unknownField": true, "clusterId": 5}""")
|
||||
|
||||
## Then - unknown fields are just ignored (not in fieldPairs)
|
||||
require confRes.isOk()
|
||||
let conf = confRes.get()
|
||||
check:
|
||||
conf.clusterId == 5
|
||||
## Then - the parser rejects unrecognized config keys
|
||||
check confRes.isErr()
|
||||
|
||||
test "Invalid JSON syntax returns error":
|
||||
## Given / When
|
||||
let confRes = parseWakuNodeConfFromJson("{ not valid json }")
|
||||
let confRes = parseNodeConfFromJson("{ not valid json }")
|
||||
|
||||
## Then
|
||||
check confRes.isErr()
|
||||
@ -250,7 +226,7 @@ suite "WakuNodeConf - preset integration":
|
||||
suite "WakuNodeConf JSON -> WakuConf integration":
|
||||
test "Core mode JSON config produces valid WakuConf":
|
||||
## Given
|
||||
let confRes = parseWakuNodeConfFromJson(
|
||||
let confRes = parseNodeConfFromJson(
|
||||
"""{"mode": "Core", "clusterId": 55, "numShardsInNetwork": 6}"""
|
||||
)
|
||||
require confRes.isOk()
|
||||
@ -272,7 +248,7 @@ suite "WakuNodeConf JSON -> WakuConf integration":
|
||||
|
||||
test "Edge mode JSON config produces valid WakuConf":
|
||||
## Given
|
||||
let confRes = parseWakuNodeConfFromJson("""{"mode": "Edge", "clusterId": 1}""")
|
||||
let confRes = parseNodeConfFromJson("""{"mode": "Edge", "clusterId": 1}""")
|
||||
require confRes.isOk()
|
||||
let conf = confRes.get()
|
||||
|
||||
@ -290,8 +266,7 @@ suite "WakuNodeConf JSON -> WakuConf integration":
|
||||
|
||||
test "JSON with preset produces valid WakuConf":
|
||||
## Given
|
||||
let confRes =
|
||||
parseWakuNodeConfFromJson("""{"mode": "Core", "preset": "logosdev"}""")
|
||||
let confRes = parseNodeConfFromJson("""{"mode": "Core", "preset": "logosdev"}""")
|
||||
require confRes.isOk()
|
||||
let conf = confRes.get()
|
||||
|
||||
@ -308,7 +283,7 @@ suite "WakuNodeConf JSON -> WakuConf integration":
|
||||
|
||||
test "JSON with static nodes":
|
||||
## Given
|
||||
let confRes = parseWakuNodeConfFromJson(
|
||||
let confRes = parseNodeConfFromJson(
|
||||
"""{"mode": "Core", "clusterId": 42, "staticnodes": ["/ip4/127.0.0.1/tcp/60000/p2p/16Uuu2HBmAcHvhLqQKwSSbX6BG5JLWUDRcaLVrehUVqpw7fz1hbYc"]}"""
|
||||
)
|
||||
require confRes.isOk()
|
||||
@ -327,7 +302,7 @@ suite "WakuNodeConf JSON -> WakuConf integration":
|
||||
test "JSON with max message size":
|
||||
## Given
|
||||
let confRes =
|
||||
parseWakuNodeConfFromJson("""{"clusterId": 42, "maxMessageSize": "100KiB"}""")
|
||||
parseNodeConfFromJson("""{"clusterId": 42, "maxMessageSize": "100KiB"}""")
|
||||
require confRes.isOk()
|
||||
let conf = confRes.get()
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{.used.}
|
||||
|
||||
import std/[net]
|
||||
import std/[net, options]
|
||||
import chronos, testutils/unittests, stew/byteutils
|
||||
import brokers/broker_context
|
||||
|
||||
@ -24,9 +24,9 @@ proc createApiNodeConf(): WakuNodeConf =
|
||||
conf.listenAddress = parseIpAddress("0.0.0.0")
|
||||
conf.tcpPort = Port(0)
|
||||
conf.discv5UdpPort = Port(0)
|
||||
conf.clusterId = 3'u16
|
||||
conf.clusterId = some(3'u16)
|
||||
conf.numShardsInNetwork = 1
|
||||
conf.reliabilityEnabled = true
|
||||
conf.reliabilityEnabled = some(true)
|
||||
conf.rest = false
|
||||
return conf
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ import
|
||||
suite "Waku Conf - build with cluster conf":
|
||||
test "Cluster Conf is passed and relay is enabled":
|
||||
## Setup
|
||||
let networkConf = NetworkConf.TheWakuNetworkConf()
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
builder.discv5Conf.withUdpPort(9000)
|
||||
builder.withRelayServiceRatio("50:50")
|
||||
@ -26,7 +26,7 @@ suite "Waku Conf - build with cluster conf":
|
||||
|
||||
## Given
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
builder.withNetworkConf(networkConf)
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withRelay(true)
|
||||
builder.rlnRelayConf.withUserMessageLimit(userMessageLimit)
|
||||
|
||||
@ -38,29 +38,29 @@ suite "Waku Conf - build with cluster conf":
|
||||
## Then
|
||||
let resValidate = conf.validate()
|
||||
assert resValidate.isOk(), $resValidate.error
|
||||
check conf.clusterId == networkConf.clusterId
|
||||
check conf.shardingConf.kind == networkConf.shardingConf.kind
|
||||
check conf.clusterId == networkPresetConf.clusterId
|
||||
check conf.shardingConf.kind == networkPresetConf.shardingConf.kind
|
||||
check conf.shardingConf.numShardsInCluster ==
|
||||
networkConf.shardingConf.numShardsInCluster
|
||||
networkPresetConf.shardingConf.numShardsInCluster
|
||||
check conf.subscribeShards == expectedShards
|
||||
check conf.maxMessageSizeBytes ==
|
||||
uint64(parseCorrectMsgSize(networkConf.maxMessageSize))
|
||||
check conf.discv5Conf.get().bootstrapNodes == networkConf.discv5BootstrapNodes
|
||||
uint64(parseCorrectMsgSize(networkPresetConf.maxMessageSize))
|
||||
check conf.discv5Conf.get().bootstrapNodes == networkPresetConf.discv5BootstrapNodes
|
||||
|
||||
if networkConf.rlnRelay:
|
||||
if networkPresetConf.rlnRelay:
|
||||
assert conf.rlnRelayConf.isSome(), "RLN Relay conf is disabled"
|
||||
|
||||
let rlnRelayConf = conf.rlnRelayConf.get()
|
||||
check rlnRelayConf.ethContractAddress.string ==
|
||||
networkConf.rlnRelayEthContractAddress
|
||||
check rlnRelayConf.dynamic == networkConf.rlnRelayDynamic
|
||||
check rlnRelayConf.chainId == networkConf.rlnRelayChainId
|
||||
check rlnRelayConf.epochSizeSec == networkConf.rlnEpochSizeSec
|
||||
networkPresetConf.rlnRelayEthContractAddress
|
||||
check rlnRelayConf.dynamic == networkPresetConf.rlnRelayDynamic
|
||||
check rlnRelayConf.chainId == networkPresetConf.rlnRelayChainId
|
||||
check rlnRelayConf.epochSizeSec == networkPresetConf.rlnEpochSizeSec
|
||||
check rlnRelayConf.userMessageLimit == userMessageLimit.uint
|
||||
|
||||
test "Cluster Conf is passed, but relay is disabled":
|
||||
## Setup
|
||||
let networkConf = NetworkConf.TheWakuNetworkConf()
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
builder.withRelayServiceRatio("50:50")
|
||||
builder.discv5Conf.withUdpPort(9000)
|
||||
@ -69,7 +69,7 @@ suite "Waku Conf - build with cluster conf":
|
||||
|
||||
## Given
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
builder.withNetworkConf(networkConf)
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withRelay(false)
|
||||
|
||||
## When
|
||||
@ -80,20 +80,20 @@ suite "Waku Conf - build with cluster conf":
|
||||
## Then
|
||||
let resValidate = conf.validate()
|
||||
assert resValidate.isOk(), $resValidate.error
|
||||
check conf.clusterId == networkConf.clusterId
|
||||
check conf.shardingConf.kind == networkConf.shardingConf.kind
|
||||
check conf.clusterId == networkPresetConf.clusterId
|
||||
check conf.shardingConf.kind == networkPresetConf.shardingConf.kind
|
||||
check conf.shardingConf.numShardsInCluster ==
|
||||
networkConf.shardingConf.numShardsInCluster
|
||||
networkPresetConf.shardingConf.numShardsInCluster
|
||||
check conf.subscribeShards == expectedShards
|
||||
check conf.maxMessageSizeBytes ==
|
||||
uint64(parseCorrectMsgSize(networkConf.maxMessageSize))
|
||||
check conf.discv5Conf.get().bootstrapNodes == networkConf.discv5BootstrapNodes
|
||||
uint64(parseCorrectMsgSize(networkPresetConf.maxMessageSize))
|
||||
check conf.discv5Conf.get().bootstrapNodes == networkPresetConf.discv5BootstrapNodes
|
||||
|
||||
assert conf.rlnRelayConf.isNone
|
||||
|
||||
test "Cluster Conf is passed, but rln relay is disabled":
|
||||
## Setup
|
||||
let networkConf = NetworkConf.TheWakuNetworkConf()
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
|
||||
let # Mount all shards in network
|
||||
@ -101,7 +101,7 @@ suite "Waku Conf - build with cluster conf":
|
||||
|
||||
## Given
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
builder.withNetworkConf(networkConf)
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.rlnRelayConf.withEnabled(false)
|
||||
|
||||
## When
|
||||
@ -112,25 +112,25 @@ suite "Waku Conf - build with cluster conf":
|
||||
## Then
|
||||
let resValidate = conf.validate()
|
||||
assert resValidate.isOk(), $resValidate.error
|
||||
check conf.clusterId == networkConf.clusterId
|
||||
check conf.shardingConf.kind == networkConf.shardingConf.kind
|
||||
check conf.clusterId == networkPresetConf.clusterId
|
||||
check conf.shardingConf.kind == networkPresetConf.shardingConf.kind
|
||||
check conf.shardingConf.numShardsInCluster ==
|
||||
networkConf.shardingConf.numShardsInCluster
|
||||
networkPresetConf.shardingConf.numShardsInCluster
|
||||
check conf.subscribeShards == expectedShards
|
||||
check conf.maxMessageSizeBytes ==
|
||||
uint64(parseCorrectMsgSize(networkConf.maxMessageSize))
|
||||
check conf.discv5Conf.get().bootstrapNodes == networkConf.discv5BootstrapNodes
|
||||
uint64(parseCorrectMsgSize(networkPresetConf.maxMessageSize))
|
||||
check conf.discv5Conf.get().bootstrapNodes == networkPresetConf.discv5BootstrapNodes
|
||||
assert conf.rlnRelayConf.isNone
|
||||
|
||||
test "Cluster Conf is passed and valid shards are specified":
|
||||
## Setup
|
||||
let networkConf = NetworkConf.TheWakuNetworkConf()
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
let shards = @[2.uint16, 3.uint16]
|
||||
|
||||
## Given
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
builder.withNetworkConf(networkConf)
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withSubscribeShards(shards)
|
||||
|
||||
## When
|
||||
@ -141,24 +141,24 @@ suite "Waku Conf - build with cluster conf":
|
||||
## Then
|
||||
let resValidate = conf.validate()
|
||||
assert resValidate.isOk(), $resValidate.error
|
||||
check conf.clusterId == networkConf.clusterId
|
||||
check conf.shardingConf.kind == networkConf.shardingConf.kind
|
||||
check conf.clusterId == networkPresetConf.clusterId
|
||||
check conf.shardingConf.kind == networkPresetConf.shardingConf.kind
|
||||
check conf.shardingConf.numShardsInCluster ==
|
||||
networkConf.shardingConf.numShardsInCluster
|
||||
networkPresetConf.shardingConf.numShardsInCluster
|
||||
check conf.subscribeShards == shards
|
||||
check conf.maxMessageSizeBytes ==
|
||||
uint64(parseCorrectMsgSize(networkConf.maxMessageSize))
|
||||
check conf.discv5Conf.get().bootstrapNodes == networkConf.discv5BootstrapNodes
|
||||
uint64(parseCorrectMsgSize(networkPresetConf.maxMessageSize))
|
||||
check conf.discv5Conf.get().bootstrapNodes == networkPresetConf.discv5BootstrapNodes
|
||||
|
||||
test "Cluster Conf is passed and invalid shards are specified":
|
||||
## Setup
|
||||
let networkConf = NetworkConf.TheWakuNetworkConf()
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
let shards = @[2.uint16, 10.uint16]
|
||||
|
||||
## Given
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
builder.withNetworkConf(networkConf)
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withSubscribeShards(shards)
|
||||
|
||||
## When
|
||||
@ -167,63 +167,112 @@ suite "Waku Conf - build with cluster conf":
|
||||
## Then
|
||||
assert resConf.isErr(), "Invalid shard was accepted"
|
||||
|
||||
test "Cluster Conf is passed and RLN contract is **not** overridden":
|
||||
test "Cluster Conf mandating RLN fails conf build if user disables rln relay":
|
||||
## Setup
|
||||
let networkConf = NetworkConf.TheWakuNetworkConf()
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
|
||||
# Mount all shards in network
|
||||
let expectedShards = toSeq[0.uint16 .. 7.uint16]
|
||||
let contractAddress = "0x0123456789ABCDEF"
|
||||
let userMessageLimit = rand(1 .. 1000).uint64
|
||||
|
||||
## Given
|
||||
builder.rlnRelayConf.withEthContractAddress(contractAddress)
|
||||
builder.withNetworkConf(networkConf)
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withRelay(true)
|
||||
builder.rlnRelayConf.withUserMessageLimit(userMessageLimit)
|
||||
builder.rlnRelayConf.withEnabled(false)
|
||||
|
||||
## When
|
||||
let resConf = builder.build()
|
||||
assert resConf.isOk(), $resConf.error
|
||||
let conf = resConf.get()
|
||||
|
||||
## Then
|
||||
let resValidate = conf.validate()
|
||||
assert resValidate.isOk(), $resValidate.error
|
||||
check conf.clusterId == networkConf.clusterId
|
||||
check conf.shardingConf.kind == networkConf.shardingConf.kind
|
||||
check conf.shardingConf.numShardsInCluster ==
|
||||
networkConf.shardingConf.numShardsInCluster
|
||||
check conf.subscribeShards == expectedShards
|
||||
check conf.maxMessageSizeBytes ==
|
||||
uint64(parseCorrectMsgSize(networkConf.maxMessageSize))
|
||||
check conf.discv5Conf.isSome == networkConf.discv5Discovery
|
||||
check conf.discv5Conf.get().bootstrapNodes == networkConf.discv5BootstrapNodes
|
||||
assert networkPresetConf.rlnRelay, "precondition: preset must mandate RLN"
|
||||
assert resConf.isErr(), "relay with rln relay disabled was accepted"
|
||||
|
||||
if networkConf.rlnRelay:
|
||||
assert conf.rlnRelayConf.isSome
|
||||
test "Cluster Conf mandating RLN fails conf build if user overrides the rln contract":
|
||||
## Setup
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
# otherwise-valid RLN, so only the security gate can fail the build
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
|
||||
let rlnRelayConf = conf.rlnRelayConf.get()
|
||||
check rlnRelayConf.ethContractAddress.string ==
|
||||
networkConf.rlnRelayEthContractAddress
|
||||
check rlnRelayConf.dynamic == networkConf.rlnRelayDynamic
|
||||
check rlnRelayConf.chainId == networkConf.rlnRelayChainId
|
||||
check rlnRelayConf.epochSizeSec == networkConf.rlnEpochSizeSec
|
||||
check rlnRelayConf.userMessageLimit == userMessageLimit.uint
|
||||
## Given
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withRelay(true)
|
||||
builder.rlnRelayConf.withEthContractAddress(
|
||||
networkPresetConf.rlnRelayEthContractAddress & "0"
|
||||
)
|
||||
|
||||
## When
|
||||
let resConf = builder.build()
|
||||
|
||||
## Then
|
||||
assert networkPresetConf.rlnRelay, "precondition: preset must mandate RLN"
|
||||
assert resConf.isErr(), "relay with an overridden rln contract was accepted"
|
||||
|
||||
test "Cluster Conf mandating RLN fails conf build if user overrides the rln chain id":
|
||||
## Setup
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
# otherwise-valid RLN, so only the security gate can fail the build
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
|
||||
## Given
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withRelay(true)
|
||||
builder.rlnRelayConf.withChainId(1'u) # chain id 1 differs from the preset's
|
||||
|
||||
## When
|
||||
let resConf = builder.build()
|
||||
|
||||
## Then
|
||||
assert networkPresetConf.rlnRelay, "precondition: preset must mandate RLN"
|
||||
assert resConf.isErr(), "relay with an overridden rln chain id was accepted"
|
||||
|
||||
test "Cluster Conf mandating RLN fails conf build if user overrides rln dynamic mode":
|
||||
## Setup
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
# otherwise-valid RLN, so only the security gate can fail the build
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
|
||||
## Given
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withRelay(true)
|
||||
builder.rlnRelayConf.withDynamic(not networkPresetConf.rlnRelayDynamic)
|
||||
|
||||
## When
|
||||
let resConf = builder.build()
|
||||
|
||||
## Then
|
||||
assert networkPresetConf.rlnRelay, "precondition: preset must mandate RLN"
|
||||
assert resConf.isErr(), "relay with an overridden rln dynamic mode was accepted"
|
||||
|
||||
test "Cluster Conf mandating RLN fails conf build if user overrides the rln epoch size":
|
||||
## Setup
|
||||
let networkPresetConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
# otherwise-valid RLN, so only the security gate can fail the build
|
||||
builder.rlnRelayConf.withEthClientUrls(@["https://my_eth_rpc_url/"])
|
||||
|
||||
## Given
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withRelay(true)
|
||||
builder.rlnRelayConf.withEpochSizeSec(networkPresetConf.rlnEpochSizeSec + 1'u64)
|
||||
|
||||
## When
|
||||
let resConf = builder.build()
|
||||
|
||||
## Then
|
||||
assert networkPresetConf.rlnRelay, "precondition: preset must mandate RLN"
|
||||
assert resConf.isErr(), "relay with an overridden rln epoch size was accepted"
|
||||
|
||||
test "num-shards-in-network > 0 overrides preset":
|
||||
## Setup
|
||||
let networkConf = NetworkConf.LogosDevConf()
|
||||
let networkPresetConf = NetworkPresetConf.LogosDevConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
|
||||
# Sanity check
|
||||
check networkConf.shardingConf.kind == AutoSharding
|
||||
check networkConf.shardingConf.numShardsInCluster > 1
|
||||
check networkPresetConf.shardingConf.kind == AutoSharding
|
||||
check networkPresetConf.shardingConf.numShardsInCluster > 1
|
||||
|
||||
## Given: preset says >1 shards but user explicitly sets 1
|
||||
builder.withNetworkConf(networkConf)
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
builder.withNumShardsInCluster(1)
|
||||
builder.withShardingConf(AutoSharding)
|
||||
|
||||
@ -244,22 +293,18 @@ suite "Waku Conf - build with cluster conf":
|
||||
## StaticSharding shouldn't make any sense (that is, no use case).
|
||||
|
||||
## Given: emulate --preset=logos.dev --num-shards-in-network=0
|
||||
let networkConf = NetworkConf.LogosDevConf()
|
||||
let networkPresetConf = NetworkPresetConf.LogosDevConf()
|
||||
var builder = WakuConfBuilder.init()
|
||||
builder.withNetworkConf(networkConf)
|
||||
# Note: builder.withNumShardsInCluster() is not called when the
|
||||
# value that comes from the CLI path is 0 (which means it was
|
||||
# either set to 0 or was left unset).
|
||||
builder.withShardingConf(StaticSharding)
|
||||
builder.withNetworkPresetConf(networkPresetConf)
|
||||
|
||||
## When
|
||||
let conf = builder.build().expect("build should succeed")
|
||||
|
||||
## Then: preset wins and StaticSharding user intent is lost
|
||||
conf.validate().expect("conf should validate")
|
||||
check conf.shardingConf.kind == networkConf.shardingConf.kind
|
||||
check conf.shardingConf.kind == networkPresetConf.shardingConf.kind
|
||||
check conf.shardingConf.numShardsInCluster ==
|
||||
networkConf.shardingConf.numShardsInCluster
|
||||
networkPresetConf.shardingConf.numShardsInCluster
|
||||
|
||||
suite "Waku Conf - node key":
|
||||
test "Node key is generated":
|
||||
|
||||
@ -1,24 +1,28 @@
|
||||
{.used.}
|
||||
|
||||
import chronos, testutils/unittests, std/options
|
||||
import std/[net, options]
|
||||
|
||||
import chronos, testutils/unittests
|
||||
|
||||
import logos_delivery
|
||||
import tools/confutils/cli_args
|
||||
import logos_delivery/waku/factory/networks_config
|
||||
import logos_delivery/waku/factory/conf_builder/conf_builder
|
||||
|
||||
suite "Waku API - Create node":
|
||||
asyncTest "Create node with minimal configuration":
|
||||
## Given
|
||||
var nodeConf = defaultWakuNodeConf().valueOr:
|
||||
raiseAssert error
|
||||
raiseAssert "defaultWakuNodeConf failed: " & error
|
||||
nodeConf.mode = Core
|
||||
nodeConf.clusterId = 3'u16
|
||||
nodeConf.clusterId = some(3'u16)
|
||||
nodeConf.rest = false
|
||||
|
||||
# This is the actual minimal config but as the node auto-start, it is not suitable for tests
|
||||
|
||||
## When
|
||||
let node = (await createNode(nodeConf)).valueOr:
|
||||
raiseAssert error
|
||||
raiseAssert "createNode (minimal config) failed: " & error
|
||||
|
||||
## Then
|
||||
check:
|
||||
@ -29,9 +33,9 @@ suite "Waku API - Create node":
|
||||
asyncTest "Create node with full configuration":
|
||||
## Given
|
||||
var nodeConf = defaultWakuNodeConf().valueOr:
|
||||
raiseAssert error
|
||||
raiseAssert "defaultWakuNodeConf failed: " & error
|
||||
nodeConf.mode = Core
|
||||
nodeConf.clusterId = 99'u16
|
||||
nodeConf.clusterId = some(99'u16)
|
||||
nodeConf.rest = false
|
||||
nodeConf.numShardsInNetwork = 16
|
||||
nodeConf.maxMessageSize = "1024 KiB"
|
||||
@ -44,7 +48,7 @@ suite "Waku API - Create node":
|
||||
|
||||
## When
|
||||
let node = (await createNode(nodeConf)).valueOr:
|
||||
raiseAssert error
|
||||
raiseAssert "createNode (full config) failed: " & error
|
||||
|
||||
## Then
|
||||
check:
|
||||
@ -61,9 +65,9 @@ suite "Waku API - Create node":
|
||||
asyncTest "Create node with mixed entry nodes (enrtree, multiaddr)":
|
||||
## Given
|
||||
var nodeConf = defaultWakuNodeConf().valueOr:
|
||||
raiseAssert error
|
||||
raiseAssert "defaultWakuNodeConf failed: " & error
|
||||
nodeConf.mode = Core
|
||||
nodeConf.clusterId = 42'u16
|
||||
nodeConf.clusterId = some(42'u16)
|
||||
nodeConf.rest = false
|
||||
nodeConf.entryNodes = @[
|
||||
"enrtree://AIRVQ5DDA4FFWLRBCHJWUWOO6X6S4ZTZ5B667LQ6AJU6PEYDLRD5O@sandbox.waku.nodes.status.im",
|
||||
@ -72,7 +76,7 @@ suite "Waku API - Create node":
|
||||
|
||||
## When
|
||||
let node = (await createNode(nodeConf)).valueOr:
|
||||
raiseAssert error
|
||||
raiseAssert "createNode (mixed entry nodes) failed: " & error
|
||||
|
||||
## Then
|
||||
check:
|
||||
|
||||
@ -57,7 +57,7 @@ suite "Waku external config - default values":
|
||||
suite "Waku external config - apply preset":
|
||||
test "Preset is TWN":
|
||||
## Setup
|
||||
let expectedConf = NetworkConf.TheWakuNetworkConf()
|
||||
let expectedConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
|
||||
## Given
|
||||
let preConfig = WakuNodeConf(
|
||||
@ -94,7 +94,7 @@ suite "Waku external config - apply preset":
|
||||
|
||||
test "Subscribes to all valid shards in twn":
|
||||
## Setup
|
||||
let expectedConf = NetworkConf.TheWakuNetworkConf()
|
||||
let expectedConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
|
||||
## Given
|
||||
let shards: seq[uint16] = @[0, 1, 2, 3, 4, 5, 6, 7]
|
||||
@ -110,7 +110,7 @@ suite "Waku external config - apply preset":
|
||||
|
||||
test "Subscribes to some valid shards in twn":
|
||||
## Setup
|
||||
let expectedConf = NetworkConf.TheWakuNetworkConf()
|
||||
let expectedConf = NetworkPresetConf.TheWakuNetworkConf()
|
||||
|
||||
## Given
|
||||
let shards: seq[uint16] = @[0, 4, 7]
|
||||
|
||||
@ -37,7 +37,7 @@ import ./envvar as confEnvvarDefs, ./envvar_net as confEnvvarNet
|
||||
|
||||
export
|
||||
confTomlDefs, confTomlNet, confEnvvarDefs, confEnvvarNet, ProtectedShard,
|
||||
DefaultMaxWakuMessageSizeStr
|
||||
DefaultMaxWakuMessageSizeStr, DefaultAgentString
|
||||
|
||||
logScope:
|
||||
topics = "waku cli args"
|
||||
@ -45,6 +45,13 @@ logScope:
|
||||
# Git version in git describe format (defined at compile time)
|
||||
const git_version* {.strdefine.} = "n/a"
|
||||
|
||||
# CLI defaults that differ from confbuilder defaults
|
||||
const
|
||||
DefaultCLIRelay* = true
|
||||
DefaultCLIPeerExchange* = true
|
||||
DefaultCLIRendezvous* = true
|
||||
DefaultCLINat* = "any"
|
||||
|
||||
type ConfResult*[T] = Result[T, string]
|
||||
|
||||
type EthRpcUrl* = distinct string
|
||||
@ -117,20 +124,23 @@ type WakuNodeConf* = object
|
||||
name: "rln-relay-eth-private-key"
|
||||
.}: string
|
||||
|
||||
# TODO: Remove "Default is" when it's already visible on the CLI
|
||||
# Option-typed; desc states the default since the CLI can't auto-show it for none().
|
||||
rlnRelayUserMessageLimit* {.
|
||||
desc:
|
||||
"Set a user message limit for the rln membership registration. Must be a positive integer. Default is 1.",
|
||||
defaultValue: 1,
|
||||
"Set a user message limit for the rln membership registration. Must be a positive integer. Default is " &
|
||||
$DefaultRlnRelayUserMessageLimit & ".",
|
||||
defaultValue: none(uint64),
|
||||
name: "rln-relay-user-message-limit"
|
||||
.}: uint64
|
||||
.}: Option[uint64]
|
||||
|
||||
# Option-typed; desc states the default since the CLI can't auto-show it for none().
|
||||
rlnEpochSizeSec* {.
|
||||
desc:
|
||||
"Epoch size in seconds used to rate limit RLN memberships. Default is 1 second.",
|
||||
defaultValue: 1,
|
||||
"Epoch size in seconds used to rate limit RLN memberships. Default is " &
|
||||
$DefaultRlnRelayEpochSizeSec & " second.",
|
||||
defaultValue: none(uint64),
|
||||
name: "rln-relay-epoch-sec"
|
||||
.}: uint64
|
||||
.}: Option[uint64]
|
||||
|
||||
maxMessageSize* {.
|
||||
desc:
|
||||
@ -170,15 +180,18 @@ type WakuNodeConf* = object
|
||||
name: "preset"
|
||||
.}: string
|
||||
|
||||
# Option-typed; desc states the default since the CLI can't auto-show it for none().
|
||||
clusterId* {.
|
||||
desc:
|
||||
"Cluster id that the node is running in. Node in a different cluster id is disconnected.",
|
||||
defaultValue: 0,
|
||||
desc: static(
|
||||
"Cluster id that the node is running in. Node in a different cluster id is disconnected. Default is " &
|
||||
$DefaultClusterId & "."
|
||||
),
|
||||
defaultValue: none(uint16),
|
||||
name: "cluster-id"
|
||||
.}: uint16
|
||||
.}: Option[uint16]
|
||||
|
||||
agentString* {.
|
||||
defaultValue: "logos-delivery-" & cli_args.git_version,
|
||||
defaultValue: DefaultAgentString,
|
||||
desc: "Node agent string which is used as identifier in network",
|
||||
name: "agent-string"
|
||||
.}: string
|
||||
@ -203,7 +216,7 @@ type WakuNodeConf* = object
|
||||
desc:
|
||||
"Specify method to use for determining public address. " &
|
||||
"Must be one of: any, none, upnp, pmp, extip:<IP>.",
|
||||
defaultValue: "any"
|
||||
defaultValue: DefaultCLINat
|
||||
.}: string
|
||||
|
||||
extMultiAddrs* {.
|
||||
@ -275,7 +288,9 @@ hence would have reachability issues.""",
|
||||
|
||||
## Relay config
|
||||
relay* {.
|
||||
desc: "Enable relay protocol: true|false", defaultValue: true, name: "relay"
|
||||
desc: "Enable relay protocol: true|false",
|
||||
defaultValue: DefaultCLIRelay,
|
||||
name: "relay"
|
||||
.}: bool
|
||||
|
||||
relayPeerExchange* {.
|
||||
@ -291,11 +306,14 @@ hence would have reachability issues.""",
|
||||
name: "relay-shard-manager"
|
||||
.}: bool
|
||||
|
||||
# Option-typed; desc states the default since the CLI can't auto-show it for none().
|
||||
rlnRelay* {.
|
||||
desc: "Enable spam protection through rln-relay: true|false.",
|
||||
defaultValue: false,
|
||||
desc:
|
||||
"Enable spam protection through rln-relay: true|false. Default is " &
|
||||
$DefaultRlnRelayEnabled & ".",
|
||||
defaultValue: none(bool),
|
||||
name: "rln-relay"
|
||||
.}: bool
|
||||
.}: Option[bool]
|
||||
|
||||
rlnRelayCredIndex* {.
|
||||
desc: "the index of the onchain commitment to use",
|
||||
@ -304,9 +322,9 @@ hence would have reachability issues.""",
|
||||
|
||||
rlnRelayDynamic* {.
|
||||
desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false.",
|
||||
defaultValue: false,
|
||||
defaultValue: none(bool),
|
||||
name: "rln-relay-dynamic"
|
||||
.}: bool
|
||||
.}: Option[bool]
|
||||
|
||||
entryNodes* {.
|
||||
desc:
|
||||
@ -466,13 +484,14 @@ hence would have reachability issues.""",
|
||||
.}: string
|
||||
|
||||
## Reliability config
|
||||
# Option-typed; desc states the default since the CLI can't auto-show it for none().
|
||||
reliabilityEnabled* {.
|
||||
desc:
|
||||
"""Adds an extra effort in the delivery/reception of messages by leveraging store-v3 requests.
|
||||
with the drawback of consuming some more bandwidth.""",
|
||||
defaultValue: true,
|
||||
"""Adds an extra effort in the delivery/reception of messages by leveraging store-v3 requests, with the drawback of consuming some more bandwidth. Default is """ &
|
||||
$DefaultP2pReliability & ".",
|
||||
defaultValue: none(bool),
|
||||
name: "reliability"
|
||||
.}: bool
|
||||
.}: Option[bool]
|
||||
|
||||
## REST HTTP config
|
||||
rest* {.
|
||||
@ -557,8 +576,11 @@ with the drawback of consuming some more bandwidth.""",
|
||||
.}: string
|
||||
|
||||
## Discovery v5 config
|
||||
# Option-typed; desc states the default since the CLI can't auto-show it for none().
|
||||
discv5Discovery* {.
|
||||
desc: "Enable discovering nodes via Node Discovery v5.",
|
||||
desc:
|
||||
"Enable discovering nodes via Node Discovery v5. Default is " &
|
||||
$DefaultDiscv5Enabled & ".",
|
||||
defaultValue: none(bool),
|
||||
name: "discv5-discovery"
|
||||
.}: Option[bool]
|
||||
@ -608,7 +630,7 @@ with the drawback of consuming some more bandwidth.""",
|
||||
## waku peer exchange config
|
||||
peerExchange* {.
|
||||
desc: "Enable waku peer exchange protocol (responder side): true|false",
|
||||
defaultValue: true,
|
||||
defaultValue: DefaultCLIPeerExchange,
|
||||
name: "peer-exchange"
|
||||
.}: bool
|
||||
|
||||
@ -622,13 +644,17 @@ with the drawback of consuming some more bandwidth.""",
|
||||
## Rendez vous
|
||||
rendezvous* {.
|
||||
desc: "Enable waku rendezvous discovery server",
|
||||
defaultValue: true,
|
||||
defaultValue: DefaultCLIRendezvous,
|
||||
name: "rendezvous"
|
||||
.}: bool
|
||||
|
||||
#Mix config
|
||||
mix* {.desc: "Enable mix protocol: true|false", defaultValue: false, name: "mix".}:
|
||||
bool
|
||||
# Option-typed; desc states the default since the CLI can't auto-show it for none().
|
||||
mix* {.
|
||||
desc: "Enable mix protocol: true|false. Default is " & $DefaultMix & ".",
|
||||
defaultValue: none(bool),
|
||||
name: "mix"
|
||||
.}: Option[bool]
|
||||
|
||||
mixkey* {.
|
||||
desc:
|
||||
@ -643,12 +669,14 @@ with the drawback of consuming some more bandwidth.""",
|
||||
.}: seq[MixNodePubInfo]
|
||||
|
||||
# Kademlia Discovery config
|
||||
# Option-typed; desc states the default since the CLI can't auto-show it for none().
|
||||
enableKadDiscovery* {.
|
||||
desc:
|
||||
"Enable extended kademlia discovery. Can be enabled without bootstrap nodes for the first node in the network.",
|
||||
defaultValue: false,
|
||||
"Enable extended kademlia discovery. Can be enabled without bootstrap nodes for the first node in the network. Default is " &
|
||||
$DefaultKadEnabled & ".",
|
||||
defaultValue: none(bool),
|
||||
name: "enable-kad-discovery"
|
||||
.}: bool
|
||||
.}: Option[bool]
|
||||
|
||||
kadBootstrapNodes* {.
|
||||
desc:
|
||||
@ -919,15 +947,15 @@ proc toKeystoreGeneratorConf*(n: WakuNodeConf): RlnKeystoreGeneratorConf =
|
||||
chainId: UInt256.fromBytesBE(n.rlnRelayChainId.toBytesBE()),
|
||||
ethClientUrls: n.ethClientUrls.mapIt(string(it)),
|
||||
ethContractAddress: n.rlnRelayEthContractAddress,
|
||||
userMessageLimit: n.rlnRelayUserMessageLimit,
|
||||
userMessageLimit: n.rlnRelayUserMessageLimit.get(DefaultRlnRelayUserMessageLimit),
|
||||
ethPrivateKey: n.rlnRelayEthPrivateKey,
|
||||
credPath: n.rlnRelayCredPath,
|
||||
credPassword: n.rlnRelayCredPassword,
|
||||
)
|
||||
|
||||
proc toNetworkConf(
|
||||
proc toNetworkPresetConf(
|
||||
preset: string, clusterId: Option[uint16]
|
||||
): ConfResult[Option[NetworkConf]] =
|
||||
): ConfResult[Option[NetworkPresetConf]] =
|
||||
var lcPreset = toLowerAscii(preset)
|
||||
if clusterId.isSome() and clusterId.get() == 1:
|
||||
warn(
|
||||
@ -942,29 +970,30 @@ proc toNetworkConf(
|
||||
|
||||
case lcPreset
|
||||
of "":
|
||||
ok(none(NetworkConf))
|
||||
ok(none(NetworkPresetConf))
|
||||
of "twn":
|
||||
ok(some(NetworkConf.TheWakuNetworkConf()))
|
||||
ok(some(NetworkPresetConf.TheWakuNetworkConf()))
|
||||
of "logos.dev", "logosdev":
|
||||
ok(some(NetworkConf.LogosDevConf()))
|
||||
ok(some(NetworkPresetConf.LogosDevConf()))
|
||||
of "logos.test", "logostest":
|
||||
ok(some(NetworkConf.LogosTestConf()))
|
||||
ok(some(NetworkPresetConf.LogosTestConf()))
|
||||
else:
|
||||
err("Invalid --preset value passed: " & lcPreset)
|
||||
|
||||
proc toWakuConf*(n: WakuNodeConf): ConfResult[WakuConf] =
|
||||
var b = WakuConfBuilder.init()
|
||||
|
||||
let networkConf = toNetworkConf(n.preset, some(n.clusterId)).valueOr:
|
||||
let networkPresetConf = toNetworkPresetConf(n.preset, n.clusterId).valueOr:
|
||||
return err("Error determining cluster from preset: " & $error)
|
||||
|
||||
if networkConf.isSome():
|
||||
b.withNetworkConf(networkConf.get())
|
||||
if networkPresetConf.isSome():
|
||||
b.withNetworkPresetConf(networkPresetConf.get())
|
||||
|
||||
b.withLogLevel(n.logLevel)
|
||||
b.withLogFormat(n.logFormat)
|
||||
|
||||
b.rlnRelayConf.withEnabled(n.rlnRelay)
|
||||
if n.rlnRelay.isSome():
|
||||
b.rlnRelayConf.withEnabled(n.rlnRelay.get())
|
||||
if n.rlnRelayCredPath != "":
|
||||
b.rlnRelayConf.withCredPath(n.rlnRelayCredPath)
|
||||
if n.rlnRelayCredPassword != "":
|
||||
@ -976,18 +1005,22 @@ proc toWakuConf*(n: WakuNodeConf): ConfResult[WakuConf] =
|
||||
|
||||
if n.rlnRelayChainId != 0:
|
||||
b.rlnRelayConf.withChainId(n.rlnRelayChainId)
|
||||
b.rlnRelayConf.withUserMessageLimit(n.rlnRelayUserMessageLimit)
|
||||
b.rlnRelayConf.withEpochSizeSec(n.rlnEpochSizeSec)
|
||||
if n.rlnRelayUserMessageLimit.isSome():
|
||||
b.rlnRelayConf.withUserMessageLimit(n.rlnRelayUserMessageLimit.get())
|
||||
if n.rlnEpochSizeSec.isSome():
|
||||
b.rlnRelayConf.withEpochSizeSec(n.rlnEpochSizeSec.get())
|
||||
|
||||
if n.rlnRelayCredIndex.isSome():
|
||||
b.rlnRelayConf.withCredIndex(n.rlnRelayCredIndex.get())
|
||||
b.rlnRelayConf.withDynamic(n.rlnRelayDynamic)
|
||||
if n.rlnRelayDynamic.isSome():
|
||||
b.rlnRelayConf.withDynamic(n.rlnRelayDynamic.get())
|
||||
|
||||
if n.maxMessageSize != "":
|
||||
b.withMaxMessageSize(n.maxMessageSize)
|
||||
|
||||
b.withProtectedShards(n.protectedShards)
|
||||
b.withClusterId(n.clusterId)
|
||||
if n.clusterId.isSome():
|
||||
b.withClusterId(n.clusterId.get())
|
||||
|
||||
b.withAgentString(n.agentString)
|
||||
|
||||
@ -1041,7 +1074,7 @@ proc toWakuConf*(n: WakuNodeConf): ConfResult[WakuConf] =
|
||||
if n.numShardsInNetwork != 0:
|
||||
b.withNumShardsInCluster(n.numShardsInNetwork)
|
||||
b.withShardingConf(AutoSharding)
|
||||
else:
|
||||
elif networkPresetConf.isNone():
|
||||
b.withShardingConf(StaticSharding)
|
||||
|
||||
# It is not possible to pass an empty sequence on the CLI
|
||||
@ -1074,9 +1107,10 @@ proc toWakuConf*(n: WakuNodeConf): ConfResult[WakuConf] =
|
||||
b.storeServiceConf.storeSyncConf.withRangeSec(n.storeSyncRange)
|
||||
b.storeServiceConf.storeSyncConf.withRelayJitterSec(n.storeSyncRelayJitter)
|
||||
|
||||
b.mixConf.withEnabled(n.mix)
|
||||
if n.mix.isSome():
|
||||
b.mixConf.withEnabled(n.mix.get())
|
||||
b.withMix(n.mix.get())
|
||||
b.mixConf.withMixNodes(n.mixnodes)
|
||||
b.withMix(n.mix)
|
||||
if n.mixkey.isSome():
|
||||
b.mixConf.withMixKey(n.mixkey.get())
|
||||
|
||||
@ -1086,7 +1120,8 @@ proc toWakuConf*(n: WakuNodeConf): ConfResult[WakuConf] =
|
||||
b.filterServiceConf.withMaxCriteria(n.filterMaxCriteria)
|
||||
|
||||
b.withLightPush(n.lightpush)
|
||||
b.withP2pReliability(n.reliabilityEnabled)
|
||||
if n.reliabilityEnabled.isSome():
|
||||
b.withP2pReliability(n.reliabilityEnabled.get())
|
||||
|
||||
b.restServerConf.withEnabled(n.rest)
|
||||
b.restServerConf.withListenAddress(n.restAddress)
|
||||
@ -1129,7 +1164,8 @@ proc toWakuConf*(n: WakuNodeConf): ConfResult[WakuConf] =
|
||||
|
||||
b.withLocalStoragePath(n.localStoragePath)
|
||||
|
||||
b.kademliaDiscoveryConf.withEnabled(n.enableKadDiscovery)
|
||||
if n.enableKadDiscovery.isSome():
|
||||
b.kademliaDiscoveryConf.withEnabled(n.enableKadDiscovery.get())
|
||||
b.kademliaDiscoveryConf.withBootstrapNodes(n.kadBootstrapNodes)
|
||||
|
||||
# Mode-driven configuration overrides
|
||||
|
||||
121
tools/confutils/conf_from_json.nim
Normal file
121
tools/confutils/conf_from_json.nim
Normal file
@ -0,0 +1,121 @@
|
||||
import std/[json, strutils, tables]
|
||||
import confutils, confutils/std/net, results
|
||||
import ./cli_args
|
||||
|
||||
proc collectJsonFields*(
|
||||
jsonNode: JsonNode
|
||||
): Result[Table[string, (string, JsonNode)], string] =
|
||||
## Walk the top-level JSON object and key it by lowercased names.
|
||||
if jsonNode.kind != JObject:
|
||||
return err("config JSON must be a JSON object, got " & $jsonNode.kind)
|
||||
var jsonFields: Table[string, (string, JsonNode)]
|
||||
for key, value in jsonNode:
|
||||
let lowerKey = key.toLowerAscii()
|
||||
if jsonFields.hasKey(lowerKey):
|
||||
let firstKey = jsonFields[lowerKey][0]
|
||||
return err(
|
||||
"Duplicate configuration option (case-insensitive): '" & firstKey & "' and '" &
|
||||
key & "'"
|
||||
)
|
||||
jsonFields[lowerKey] = (key, value)
|
||||
return ok(jsonFields)
|
||||
|
||||
proc unknownKeysError(
|
||||
jsonFields: Table[string, (string, JsonNode)], prefix: string
|
||||
): string =
|
||||
## Format leftover JSON keys as an error message.
|
||||
var keys = newSeq[string]()
|
||||
for _, (jsonKey, _) in pairs(jsonFields):
|
||||
keys.add(jsonKey)
|
||||
return prefix & ": " & $keys
|
||||
|
||||
proc jsonScalarToString(node: JsonNode): Result[string, string] =
|
||||
## Convert a scalar JSON value to its string form.
|
||||
case node.kind
|
||||
of JString:
|
||||
return ok(node.getStr())
|
||||
of JInt:
|
||||
return ok($node.getInt())
|
||||
of JFloat:
|
||||
return ok($node.getFloat())
|
||||
of JBool:
|
||||
return ok($node.getBool())
|
||||
of JNull:
|
||||
return ok("")
|
||||
else:
|
||||
return err("expected scalar JSON value, got " & $node.kind)
|
||||
|
||||
proc applyJsonFieldsToConf(
|
||||
conf: var WakuNodeConf,
|
||||
jsonFields: var Table[string, (string, JsonNode)],
|
||||
parseErrPrefix: string,
|
||||
unknownErrPrefix: string,
|
||||
): Result[void, string] =
|
||||
## Walk `conf`'s fields and write each one matched (case-insensitive) by
|
||||
## `jsonFields`. seq fields take a JArray (full replace); scalar fields
|
||||
## take any scalar JSON kind. Errors on leftover unknown keys.
|
||||
for confField, confValue in fieldPairs(conf):
|
||||
let lowerField = confField.toLowerAscii()
|
||||
if jsonFields.hasKey(lowerField):
|
||||
let (jsonKey, jsonValue) = jsonFields[lowerField]
|
||||
when confValue is seq:
|
||||
if jsonValue.kind != JArray:
|
||||
return err(
|
||||
parseErrPrefix & " '" & confField & "' from JSON key '" & jsonKey &
|
||||
"' must be a JSON array"
|
||||
)
|
||||
var newSeq: typeof(confValue) = @[]
|
||||
for item in jsonValue:
|
||||
let formattedItem = jsonScalarToString(item).valueOr:
|
||||
return err(
|
||||
parseErrPrefix & " '" & confField & "' from JSON key '" & jsonKey & "': " &
|
||||
error
|
||||
)
|
||||
try:
|
||||
type ElemType = typeof(confValue[0])
|
||||
newSeq.add(parseCmdArg(ElemType, formattedItem))
|
||||
except CatchableError as e:
|
||||
return err(
|
||||
parseErrPrefix & " '" & confField & "' from JSON key '" & jsonKey & "': " &
|
||||
e.msg & ". Value: " & formattedItem
|
||||
)
|
||||
confValue = newSeq
|
||||
else:
|
||||
let formattedString = jsonScalarToString(jsonValue).valueOr:
|
||||
return err(
|
||||
parseErrPrefix & " '" & confField & "' from JSON key '" & jsonKey & "': " &
|
||||
error
|
||||
)
|
||||
try:
|
||||
confValue = parseCmdArg(typeof(confValue), formattedString)
|
||||
except CatchableError as e:
|
||||
return err(
|
||||
parseErrPrefix & " '" & confField & "' from JSON key '" & jsonKey & "': " &
|
||||
e.msg & ". Value: " & formattedString
|
||||
)
|
||||
jsonFields.del(lowerField)
|
||||
if jsonFields.len > 0:
|
||||
return err(unknownKeysError(jsonFields, unknownErrPrefix))
|
||||
return ok()
|
||||
|
||||
proc assembleFullConf*(
|
||||
jsonFields: Table[string, (string, JsonNode)]
|
||||
): Result[WakuNodeConf, string] =
|
||||
## Build a WakuNodeConf from a flat JSON object whose keys are WakuNodeConf field names.
|
||||
var conf = ?defaultWakuNodeConf()
|
||||
var fields = jsonFields
|
||||
?applyJsonFieldsToConf(
|
||||
conf, fields, "Failed to parse field", "Unrecognized configuration option(s) found"
|
||||
)
|
||||
return ok(conf)
|
||||
|
||||
proc parseNodeConfFromJson*(jsonStr: string): Result[WakuNodeConf, string] =
|
||||
## Parse a flat JSON config whose keys are WakuNodeConf field names.
|
||||
var jsonNode: JsonNode
|
||||
try:
|
||||
jsonNode = parseJson(jsonStr)
|
||||
except CatchableError as e:
|
||||
return err("Failed to parse config JSON: " & e.msg)
|
||||
|
||||
let jsonFields = ?collectJsonFields(jsonNode)
|
||||
return assembleFullConf(jsonFields)
|
||||
Loading…
x
Reference in New Issue
Block a user