diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index b6e94c747..d98c59550 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -63,9 +63,11 @@ when isMainModule: let restServer = rest_server_builder.startRestServerEsentials( nodeHealthMonitor, confCopy ).valueOr: - error "Starting esential REST server failed.", error = $error + error "Starting essential REST server failed.", error = $error quit(QuitFailure) + # applyPresetConfiguration(wakuNodeConf, confBuilder) + var waku = Waku.new(confCopy).valueOr: error "Waku initialization failed", error = error quit(QuitFailure) diff --git a/tests/factory/test_waku_conf.nim b/tests/factory/test_waku_conf.nim index a6315120a..dee8417e3 100644 --- a/tests/factory/test_waku_conf.nim +++ b/tests/factory/test_waku_conf.nim @@ -2,12 +2,14 @@ import libp2p/crypto/[crypto, secp], + libp2p/multiaddress, nimcrypto/utils, std/[options, sequtils], results, testutils/unittests import waku/factory/waku_conf, + waku/factory/waku_conf_builder, waku/factory/networks_config, waku/common/utils/parse_size_units @@ -16,12 +18,13 @@ suite "Waku Conf - build with cluster conf": ## Setup let clusterConf = ClusterConf.TheWakuNetworkConf() var builder = WakuConfBuilder.init() - builder.withTcpPort(3000) + builder.withTcpPort(60000) + builder.discv5Conf.withUdpPort(9000) # Mount all shards in network let expectedShards = toSeq[0.uint16 .. 7.uint16] ## Given - builder.withRlnRelayEthClientAddress("https://my_eth_rpc_url/") + builder.rlnRelayConf.withEthClientAddress("https://my_eth_rpc_url/") builder.withClusterConf(clusterConf) builder.withRelay(true) @@ -31,13 +34,14 @@ suite "Waku Conf - build with cluster conf": ## Then let conf = res.get() + assert conf.validate().isOk() assert conf.clusterId == clusterConf.clusterId assert conf.numShardsInNetwork == clusterConf.numShardsInNetwork assert conf.shards == expectedShards assert conf.maxMessageSizeBytes == int(parseCorrectMsgSize(clusterConf.maxMessageSize)) - assert conf.discv5BootstrapNodes.map( + assert conf.discv5Conf.get().bootstrapNodes.map( proc(e: TextEnr): string = e.string ) == clusterConf.discv5BootstrapNodes @@ -46,26 +50,25 @@ suite "Waku Conf - build with cluster conf": assert conf.rlnRelayConf.isSome let rlnRelayConf = conf.rlnRelayConf.get() - assert rlnRelayConf.rlnRelayEthContractAddress.string == + assert rlnRelayConf.ethContractAddress.string == clusterConf.rlnRelayEthContractAddress - assert rlnRelayConf.rlnRelayDynamic == clusterConf.rlnRelayDynamic - assert rlnRelayConf.rlnRelayChainId == clusterConf.rlnRelayChainId - assert rlnRelayConf.rlnRelayBandwidthThreshold == - clusterConf.rlnRelayBandwidthThreshold - assert rlnRelayConf.rlnEpochSizeSec == clusterConf.rlnEpochSizeSec - assert rlnRelayConf.rlnRelayUserMessageLimit == - clusterConf.rlnRelayUserMessageLimit + assert rlnRelayConf.dynamic == clusterConf.rlnRelayDynamic + assert rlnRelayConf.chainId == clusterConf.rlnRelayChainId + assert rlnRelayConf.bandwidthThreshold == clusterConf.rlnRelayBandwidthThreshold + assert rlnRelayConf.epochSizeSec == clusterConf.rlnEpochSizeSec + assert rlnRelayConf.userMessageLimit == clusterConf.rlnRelayUserMessageLimit test "Cluster Conf is passed, but relay is disabled": ## Setup let clusterConf = ClusterConf.TheWakuNetworkConf() var builder = WakuConfBuilder.init() - builder.withTcpPort(3000) + builder.withTcpPort(60000) + builder.discv5Conf.withUdpPort(9000) # Mount all shards in network let expectedShards = toSeq[0.uint16 .. 7.uint16] ## Given - builder.withRlnRelayEthClientAddress("https://my_eth_rpc_url/") + builder.rlnRelayConf.withEthClientAddress("https://my_eth_rpc_url/") builder.withClusterConf(clusterConf) builder.withRelay(false) @@ -75,12 +78,13 @@ suite "Waku Conf - build with cluster conf": ## Then let conf = res.get() + assert conf.validate().isOk() assert conf.clusterId == clusterConf.clusterId assert conf.numShardsInNetwork == clusterConf.numShardsInNetwork assert conf.shards == expectedShards assert conf.maxMessageSizeBytes == int(parseCorrectMsgSize(clusterConf.maxMessageSize)) - assert conf.discv5BootstrapNodes.map( + assert conf.discv5Conf.get().bootstrapNodes.map( proc(e: TextEnr): string = e.string ) == clusterConf.discv5BootstrapNodes @@ -91,15 +95,16 @@ suite "Waku Conf - build with cluster conf": ## Setup let clusterConf = ClusterConf.TheWakuNetworkConf() var builder = WakuConfBuilder.init() - builder.withTcpPort(3000) + builder.withTcpPort(60000) + builder.discv5Conf.withUdpPort(9000) let # Mount all shards in network expectedShards = toSeq[0.uint16 .. 7.uint16] ## Given - builder.withRlnRelayEthClientAddress("https://my_eth_rpc_url/") + builder.rlnRelayConf.withEthClientAddress("https://my_eth_rpc_url/") builder.withClusterConf(clusterConf) - builder.withRlnRelay(false) + builder.rlnRelayConf.withRlnRelay(false) ## When let res = builder.build() @@ -107,12 +112,13 @@ suite "Waku Conf - build with cluster conf": ## Then let conf = res.get() + assert conf.validate().isOk() assert conf.clusterId == clusterConf.clusterId assert conf.numShardsInNetwork == clusterConf.numShardsInNetwork assert conf.shards == expectedShards assert conf.maxMessageSizeBytes == int(parseCorrectMsgSize(clusterConf.maxMessageSize)) - assert conf.discv5BootstrapNodes.map( + assert conf.discv5Conf.get().bootstrapNodes.map( proc(e: TextEnr): string = e.string ) == clusterConf.discv5BootstrapNodes @@ -123,11 +129,12 @@ suite "Waku Conf - build with cluster conf": ## Setup let clusterConf = ClusterConf.TheWakuNetworkConf() var builder = WakuConfBuilder.init() - builder.withTcpPort(3000) + builder.withTcpPort(60000) + builder.discv5Conf.withUdpPort(9000) let shards = @[2.uint16, 3.uint16] ## Given - builder.withRlnRelayEthClientAddress("https://my_eth_rpc_url/") + builder.rlnRelayConf.withEthClientAddress("https://my_eth_rpc_url/") builder.withClusterConf(clusterConf) builder.withShards(shards) @@ -137,12 +144,13 @@ suite "Waku Conf - build with cluster conf": ## Then let conf = res.get() + assert conf.validate().isOk() assert conf.clusterId == clusterConf.clusterId assert conf.numShardsInNetwork == clusterConf.numShardsInNetwork assert conf.shards == shards assert conf.maxMessageSizeBytes == int(parseCorrectMsgSize(clusterConf.maxMessageSize)) - assert conf.discv5BootstrapNodes.map( + assert conf.discv5Conf.get().bootstrapNodes.map( proc(e: TextEnr): string = e.string ) == clusterConf.discv5BootstrapNodes @@ -151,33 +159,37 @@ suite "Waku Conf - build with cluster conf": ## Setup let clusterConf = ClusterConf.TheWakuNetworkConf() var builder = WakuConfBuilder.init() - builder.withTcpPort(3000) + builder.withTcpPort(60000) + builder.discv5Conf.withUdpPort(9000) let shards = @[2.uint16, 10.uint16] ## Given - builder.withRlnRelayEthClientAddress("https://my_eth_rpc_url/") + builder.rlnRelayConf.withEthClientAddress("https://my_eth_rpc_url/") builder.withClusterConf(clusterConf) builder.withShards(shards) ## When let res = builder.build() + assert res.isOk(), $res.error ## Then - assert res.isErr(), "Invalid shard was accepted" + let conf = res.get() + assert conf.validate().isErr(), "Invalid shard was accepted" test "Cluster Conf is passed and RLN contract is overridden": ## Setup let clusterConf = ClusterConf.TheWakuNetworkConf() var builder = WakuConfBuilder.init() - builder.withTcpPort(3000) - builder.withRlnRelayEthClientAddress("https://my_eth_rpc_url/") + builder.withTcpPort(60000) + builder.discv5Conf.withUdpPort(9000) + builder.rlnRelayConf.withEthClientAddress("https://my_eth_rpc_url/") # Mount all shards in network let expectedShards = toSeq[0.uint16 .. 7.uint16] let contractAddress = "0x0123456789ABCDEF" ## Given - builder.withRlnRelayEthContractAddress(contractAddress) + builder.rlnRelayConf.withEthContractAddress(contractAddress) builder.withClusterConf(clusterConf) builder.withRelay(true) @@ -187,13 +199,14 @@ suite "Waku Conf - build with cluster conf": ## Then let conf = res.get() + assert conf.validate().isOk() assert conf.clusterId == clusterConf.clusterId assert conf.numShardsInNetwork == clusterConf.numShardsInNetwork assert conf.shards == expectedShards assert conf.maxMessageSizeBytes == int(parseCorrectMsgSize(clusterConf.maxMessageSize)) - assert conf.discv5BootstrapNodes.map( + assert conf.discv5Conf.get().bootstrapNodes.map( proc(e: TextEnr): string = e.string ) == clusterConf.discv5BootstrapNodes @@ -202,14 +215,12 @@ suite "Waku Conf - build with cluster conf": assert conf.rlnRelayConf.isSome let rlnRelayConf = conf.rlnRelayConf.get() - assert rlnRelayConf.rlnRelayEthContractAddress.string == contractAddress - assert rlnRelayConf.rlnRelayDynamic == clusterConf.rlnRelayDynamic - assert rlnRelayConf.rlnRelayChainId == clusterConf.rlnRelayChainId - assert rlnRelayConf.rlnRelayBandwidthThreshold == - clusterConf.rlnRelayBandwidthThreshold - assert rlnRelayConf.rlnEpochSizeSec == clusterConf.rlnEpochSizeSec - assert rlnRelayConf.rlnRelayUserMessageLimit == - clusterConf.rlnRelayUserMessageLimit + assert rlnRelayConf.ethContractAddress.string == contractAddress + assert rlnRelayConf.dynamic == clusterConf.rlnRelayDynamic + assert rlnRelayConf.chainId == clusterConf.rlnRelayChainId + assert rlnRelayConf.bandwidthThreshold == clusterConf.rlnRelayBandwidthThreshold + assert rlnRelayConf.epochSizeSec == clusterConf.rlnEpochSizeSec + assert rlnRelayConf.userMessageLimit == clusterConf.rlnRelayUserMessageLimit suite "Waku Conf - node key": test "Node key is generated": @@ -217,7 +228,8 @@ suite "Waku Conf - node key": var builder = WakuConfBuilder.init() builder.withClusterId(1) builder.withMaxMessageSizeBytes(1) - builder.withTcpPort(3000) + builder.withTcpPort(60000) + builder.discv5Conf.withUdpPort(9000) ## Given @@ -227,6 +239,7 @@ suite "Waku Conf - node key": let conf = res.get() ## Then + assert conf.validate().isOk() let pubkey = getPublicKey(conf.nodeKey) assert pubkey.isOk() @@ -240,7 +253,8 @@ suite "Waku Conf - node key": var builder = WakuConfBuilder.init() builder.withClusterId(1) builder.withMaxMessageSizeBytes(1) - builder.withTcpPort(3000) + builder.withTcpPort(60000) + builder.discv5Conf.withUdpPort(9000) ## Given builder.withNodeKey(nodeKey) @@ -251,6 +265,37 @@ suite "Waku Conf - node key": let conf = res.get() ## Then + assert conf.validate().isOk() assert utils.toHex(conf.nodeKey.getRawBytes().get()) == utils.toHex(nodeKey.getRawBytes().get()), "Passed node key isn't in config:" & $nodeKey & $conf.nodeKey + +suite "Waku Conf - extMultiaddrs": + test "Valid multiaddresses are passed and accepted": + ## Setup + var builder = WakuConfBuilder.init() + builder.withClusterId(1) + builder.withMaxMessageSizeBytes(1) + builder.withTcpPort(60000) + builder.discv5Conf.withUdpPort(9000) + + ## Given + let multiaddrs = + @["/ip4/127.0.0.1/udp/9090/quic", "/ip6/::1/tcp/3217", "/dns4/foo.com/tcp/80"] + for m in multiaddrs: + builder.withExtMultiAddr(m) + + ## When + let res = builder.build() + assert res.isOk(), $res.error + let conf = res.get() + + ## Then + assert conf.validate().isOk() + assert multiaddrs.len == conf.extMultiaddrs.len + let resMultiaddrs = conf.extMultiaddrs.map( + proc(m: MultiAddress): string = + $m + ) + for m in multiaddrs: + assert m in resMultiaddrs diff --git a/waku/factory/internal_config.nim b/waku/factory/internal_config.nim index 9f0b1c54d..1ccdd7bcc 100644 --- a/waku/factory/internal_config.nim +++ b/waku/factory/internal_config.nim @@ -45,13 +45,6 @@ proc enrConfiguration*( return ok(record) -proc validateExtMultiAddrs*(vals: seq[string]): Result[seq[MultiAddress], string] = - var multiaddrs: seq[MultiAddress] - for val in vals: - let multiaddr = ?MultiAddress.init(val) - multiaddrs.add(multiaddr) - return ok(multiaddrs) - proc dnsResolve*( domain: string, conf: WakuNodeConf ): Future[Result[string, string]] {.async.} = @@ -85,15 +78,9 @@ proc networkConfiguration*(conf: WakuConf, clientId: string): NetConfigResult = var (extIp, extTcpPort, _) = natRes.get() let - dns4DomainName = - if conf.dns4DomainName != "": - some(conf.dns4DomainName) - else: - none(string) - discv5UdpPort = - if conf.discv5Discovery: - some(Port(uint16(conf.discv5UdpPort) + conf.portsShift)) + if conf.discv5Conf.isSome: + some(Port(uint16(conf.discv5Conf.get().udpPort) + conf.portsShift)) else: none(Port) @@ -102,22 +89,11 @@ proc networkConfiguration*(conf: WakuConf, clientId: string): NetConfigResult = ## extPort as well. The following heuristic assumes that, in absence of ## manual config, the external port is the same as the bind port. extPort = - if (extIp.isSome() or dns4DomainName.isSome()) and extTcpPort.isNone(): + if (extIp.isSome() or conf.dns4DomainName.isSome()) and extTcpPort.isNone(): some(Port(uint16(conf.tcpPort) + conf.portsShift)) else: extTcpPort - extMultiAddrs = - if (conf.extMultiAddrs.len > 0): - let extMultiAddrsValidationRes = validateExtMultiAddrs(conf.extMultiAddrs) - if extMultiAddrsValidationRes.isErr(): - return - err("invalid external multiaddress: " & $extMultiAddrsValidationRes.error) - else: - extMultiAddrsValidationRes.get() - else: - @[] - wakuFlags = CapabilitiesBitfield.init( lightpush = conf.lightpush, filter = conf.filter, @@ -127,7 +103,7 @@ proc networkConfiguration*(conf: WakuConf, clientId: string): NetConfigResult = ) # Resolve and use DNS domain IP - if dns4DomainName.isSome() and extIp.isNone(): + if conf.dns4DomainName.isSome() and extIp.isNone(): try: let dnsRes = waitFor dnsResolve(conf.dns4DomainName, conf) @@ -148,12 +124,12 @@ proc networkConfiguration*(conf: WakuConf, clientId: string): NetConfigResult = bindPort = Port(uint16(conf.tcpPort) + conf.portsShift), extIp = extIp, extPort = extPort, - extMultiAddrs = extMultiAddrs, + extMultiAddrs = conf.extMultiAddrs, extMultiAddrsOnly = conf.extMultiAddrsOnly, wsBindPort = Port(uint16(conf.websocketPort) + conf.portsShift), wsEnabled = conf.websocketSupport, wssEnabled = conf.websocketSecureSupport, - dns4DomainName = dns4DomainName, + dns4DomainName = conf.dns4DomainName, discv5UdpPort = discv5UdpPort, wakuFlags = some(wakuFlags), ) diff --git a/waku/factory/waku.nim b/waku/factory/waku.nim index e34140e70..8c4dcae9f 100644 --- a/waku/factory/waku.nim +++ b/waku/factory/waku.nim @@ -144,18 +144,14 @@ proc setupAppCallbacks( return ok() -# TODO: This should probably accept a `WakuConf` instead, and have the caller use `WakuConfBuilder` -# Or whatever they prefer to build a valid conf proc new*( - T: type Waku, wakuNodeConf: WakuNodeConf, appCallbacks: AppCallbacks = nil + T: type Waku, wakuConf: WakuConf, appCallbacks: AppCallbacks = nil ): Result[Waku, string] = let rng = crypto.newRng() - logging.setupLog(wakuNodeConf.logLevel, wakuNodeConf.logFormat) + logging.setupLog(wakuConf.logLevel, wakuConf.logFormat) - var confBuilder = WakuConfBuilder.init() - - applyPresetConfiguration(wakuNodeConf, confBuilder) + ?wakuConf.validate() info "Running nwaku node", version = git_version diff --git a/waku/factory/waku_conf.nim b/waku/factory/waku_conf.nim index 3874f8686..d528bf4f2 100644 --- a/waku/factory/waku_conf.nim +++ b/waku/factory/waku_conf.nim @@ -1,27 +1,36 @@ -import std/[options, sequtils, net], chronicles, libp2p/crypto/crypto, results +import + std/[net, options, strutils], + chronicles, + libp2p/crypto/crypto, + libp2p/multiaddress, + results -import ../common/logging, ../common/utils/parse_size_units - -import waku/factory/networks_config +import ../common/logging logScope: - topics = "wakunode conf" + topics = "waku conf" type TextEnr* = distinct string ContractAddress* = distinct string EthRpcUrl* = distinct string NatStrategy* = distinct string + DomainName* = distinct string + +# TODO: this should come from discv5 discovery module +type Discv5Conf* = ref object + bootstrapNodes*: seq[TextEnr] + udpPort*: Port # TODO: this should come from RLN relay module type RlnRelayConf* = ref object - rlnRelayEthContractAddress*: ContractAddress - rlnRelayChainId*: uint - rlnRelayDynamic*: bool - rlnRelayBandwidthThreshold*: int - rlnEpochSizeSec*: uint64 - rlnRelayUserMessageLimit*: uint64 - rlnRelayEthClientAddress*: EthRpcUrl + ethContractAddress*: ContractAddress + chainId*: uint + dynamic*: bool + bandwidthThreshold*: int + epochSizeSec*: uint64 + userMessageLimit*: uint64 + ethClientAddress*: EthRpcUrl type WakuConf* = ref object nodeKey*: PrivateKey @@ -36,7 +45,7 @@ type WakuConf* = ref object lightPush*: bool peerExchange*: bool - discv5BootstrapNodes*: seq[TextEnr] + discv5Conf*: Option[Discv5Conf] rlnRelayConf*: Option[RlnRelayConf] @@ -49,6 +58,8 @@ type WakuConf* = ref object tcpPort*: Port portsShift*: uint16 + dns4DomainName*: Option[DomainName] + extMultiAddrs*: seq[MultiAddress] proc log*(conf: WakuConf) = info "Configuration: Enabled protocols", @@ -64,176 +75,22 @@ proc log*(conf: WakuConf) = for shard in conf.shards: info "Configuration. Shards", shard = shard - for i in conf.discv5BootstrapNodes: - info "Configuration. Bootstrap nodes", node = i.string + if conf.discv5Conf.isSome(): + for i in conf.discv5Conf.get().bootstrapNodes: + info "Configuration. Bootstrap nodes", node = i.string if conf.rlnRelayConf.isSome: var rlnRelayConf = conf.rlnRelayConf.geT() - if rlnRelayConf.rlnRelayDynamic: + if rlnRelayConf.dynamic: info "Configuration. Validation", mechanism = "onchain rln", - contract = rlnRelayConf.rlnRelayEthContractAddress.string, + contract = rlnRelayConf.ethContractAddress.string, maxMessageSize = conf.maxMessageSizeBytes, - rlnEpochSizeSec = rlnRelayConf.rlnEpochSizeSec, - rlnRelayUserMessageLimit = rlnRelayConf.rlnRelayUserMessageLimit, - rlnRelayEthClientAddress = string(rlnRelayConf.rlnRelayEthClientAddress) + rlnEpochSizeSec = rlnRelayConf.epochSizeSec, + rlnRelayUserMessageLimit = rlnRelayConf.userMessageLimit, + rlnRelayEthClientAddress = string(rlnRelayConf.ethClientAddress) -type RlnRelayConfBuilder = ref object - rlnRelay: Option[bool] - rlnRelayEthContractAddress: Option[ContractAddress] - rlnRelayChainId: Option[uint] - rlnRelayDynamic: Option[bool] - rlnRelayBandwidthThreshold: Option[int] - rlnEpochSizeSec: Option[uint64] - rlnRelayUserMessageLimit: Option[uint64] - rlnRelayEthClientAddress: Option[EthRpcUrl] - -proc init(T: type RlnRelayConfBuilder): RlnRelayConfBuilder = - RlnRelayConfBuilder() - -proc withRlnRelay(builder: var RlnRelayConfBuilder, rlnRelay: bool) = - builder.rlnRelay = some(rlnRelay) - -proc withRlnRelayEthClientAddress( - builder: var RlnRelayConfBuilder, rlnRelayEthClientAddress: EthRpcUrl -) = - builder.rlnRelayEthClientAddress = some(rlnRelayEthClientAddress) - -proc withRlnRelayEthContractAddress( - builder: var RlnRelayConfBuilder, withRlnRelayEthContractAddress: ContractAddress -) = - builder.rlnRelayEthContractAddress = some(withRlnRelayEthContractAddress) - -proc build(builder: RlnRelayConfBuilder): Result[Option[RlnRelayConf], string] = - if builder.rlnRelay.isNone or not builder.rlnRelay.get(): - info "RLN Relay is disabled" - return ok(none(RlnRelayConf)) - - let rlnRelayEthContractAddress = - if builder.rlnRelayEthContractAddress.isSome: - builder.rlnRelayEthContractAddress.get() - else: - return err("RLN Eth Contract Address was not specified") - - let rlnRelayChainId = - if builder.rlnRelayChainId.isSome: - builder.rlnRelayChainId.get() - else: - return err("RLN Relay Chain Id was not specified") - - let rlnRelayDynamic = - if builder.rlnRelayDynamic.isSome: - builder.rlnRelayDynamic.get() - else: - return err("RLN Relay Dynamic was not specified") - - let rlnRelayBandwidthThreshold = - if builder.rlnRelayBandwidthThreshold.isSome: - builder.rlnRelayBandwidthThreshold.get() - else: - return err("RLN Relay Bandwidth Threshold was not specified") - - let rlnEpochSizeSec = - if builder.rlnEpochSizeSec.isSome: - builder.rlnEpochSizeSec.get() - else: - return err("RLN Epoch Size was not specified") - - let rlnRelayUserMessageLimit = - if builder.rlnRelayUserMessageLimit.isSome: - builder.rlnRelayUserMessageLimit.get() - else: - return err("RLN Relay User Message Limit was not specified") - - let rlnRelayEthClientAddress = - if builder.rlnRelayEthClientAddress.isSome: - builder.rlnRelayEthClientAddress.get() - else: - return err("RLN Relay Eth Client Address was not specified") - - return ok( - some( - RlnRelayConf( - rlnRelayChainId: rlnRelayChainId, - rlnRelayDynamic: rlnRelayDynamic, - rlnRelayEthContractAddress: rlnRelayEthContractAddress, - rlnEpochSizeSec: rlnEpochSizeSec, - rlnRelayUserMessageLimit: rlnRelayUserMessageLimit, - rlnRelayEthClientAddress: rlnRelayEthClientAddress, - ) - ) - ) - -type WakuConfBuilder* = ref object - nodeKey*: Option[PrivateKey] - - clusterId: Option[uint16] - numShardsInNetwork: Option[uint32] - shards: Option[seq[uint16]] - - relay: Option[bool] - store: Option[bool] - filter: Option[bool] - lightPush: Option[bool] - peerExchange: Option[bool] - - clusterConf: Option[ClusterConf] - - rlnRelayConf: RlnRelayConfBuilder - - maxMessageSizeBytes: Option[int] - - discv5Discovery: Option[bool] - discv5BootstrapNodes: Option[seq[TextEnr]] - - logLevel: Option[logging.LogLevel] - logFormat: Option[logging.LogFormat] - - natStrategy: Option[NatStrategy] - - tcpPort: Option[Port] - portsShift: Option[uint16] - -proc init*(T: type WakuConfBuilder): WakuConfBuilder = - WakuConfBuilder(rlnRelayConf: RlnRelayConfBuilder.init()) - -proc withClusterConf*(builder: var WakuConfBuilder, clusterConf: ClusterConf) = - builder.clusterConf = some(clusterConf) - -proc withNodeKey*(builder: var WakuConfBuilder, nodeKey: PrivateKey) = - builder.nodeKey = some(nodeKey) - -proc withClusterId*(builder: var WakuConfBuilder, clusterId: uint16) = - builder.clusterid = some(clusterId) - -proc withShards*(builder: var WakuConfBuilder, shards: seq[uint16]) = - builder.shards = some(shards) - -proc withRelay*(builder: var WakuConfBuilder, relay: bool) = - builder.relay = some(relay) - -proc withRlnRelay*(builder: var WakuConfBuilder, rlnRelay: bool) = - builder.rlnRelayConf.withRlnRelay(rlnRelay) - -proc withRlnRelayEthClientAddress*( - builder: var WakuConfBuilder, rlnRelayEthClientAddress: string -) = - builder.rlnRelayConf.withRlnRelayEthClientAddress(rlnRelayEthClientAddress.EthRpcUrl) - -proc withRlnRelayEthContractAddress*( - builder: var WakuConfBuilder, rlnRelayEthContractAddress: string -) = - builder.rlnRelayConf.withRlnRelayEthContractAddress( - rlnRelayEthContractAddress.ContractAddress - ) - -proc withMaxMessageSizeBytes*(builder: WakuConfBuilder, maxMessageSizeBytes: int) = - builder.maxMessageSizeBytes = some(maxMessageSizeBytes) - -proc withTcpPort*(builder: WakuConfBuilder, tcpPort: uint16) = - builder.tcpPort = some(tcpPort.Port) - -proc validateShards*(wakuConf: WakuConf): Result[void, string] = +proc validateShards(wakuConf: WakuConf): Result[void, string] = let numShardsInNetwork = wakuConf.numShardsInNetwork for shard in wakuConf.shards: @@ -246,246 +103,15 @@ proc validateShards*(wakuConf: WakuConf): Result[void, string] = return ok() -proc validate(wakuConf: WakuConf): Result[void, string] = - ?validateShards(wakuConf) +proc validateNoEmptyStrings(wakuConf: WakuConf): Result[void, string] = + if wakuConf.dns4DomainName.isSome(): + if isEmptyOrWhiteSpace(wakuConf.dns4DomainName.get().string): + return err("dns4DomainName is an empty string, set it to none(string) instead") return ok() -proc nodeKey( - builder: WakuConfBuilder, rng: ref HmacDrbgContext -): Result[PrivateKey, string] = - if builder.nodeKey.isSome(): - return ok(builder.nodeKey.get()) - else: - warn "missing node key, generating new set" - let nodeKey = crypto.PrivateKey.random(Secp256k1, rng[]).valueOr: - error "Failed to generate key", error = error - return err("Failed to generate key: " & $error) - return ok(nodeKey) +proc validate*(wakuConf: WakuConf): Result[void, string] = + ?wakuConf.validateShards() + ?wakuConf.validateNoEmptyStrings() -proc build*( - builder: var WakuConfBuilder, rng: ref HmacDrbgContext = crypto.newRng() -): Result[WakuConf, string] = - ## Return a WakuConf that contains all mandatory parameters - ## Applies some sane defaults that are applicable across any usage - ## of libwaku. It aims to be agnostic so it does not apply a - ## default when it is opinionated. - - let relay = - if builder.relay.isSome: - builder.relay.get() - else: - warn "whether to mount relay is not specified, defaulting to not mounting" - false - - let store = - if builder.store.isSome: - builder.store.get() - else: - warn "whether to mount store is not specified, defaulting to not mounting" - false - - let filter = - if builder.filter.isSome: - builder.filter.get() - else: - warn "whether to mount filter is not specified, defaulting to not mounting" - false - - let lightPush = - if builder.lightPush.isSome: - builder.lightPush.get() - else: - warn "whether to mount lightPush is not specified, defaulting to not mounting" - false - - let peerExchange = - if builder.peerExchange.isSome: - builder.peerExchange.get() - else: - warn "whether to mount peerExchange is not specified, defaulting to not mounting" - false - - # Apply cluster conf - values passed manually override cluster conf - # Should be applied **first**, before individual values are pulled - if builder.clusterConf.isSome: - var clusterConf = builder.clusterConf.get() - - if builder.clusterId.isNone: - builder.clusterId = some(clusterConf.clusterId) - else: - warn "Cluster id was manually provided alongside a cluster conf", - used = builder.clusterId, discarded = clusterConf.clusterId - - if relay and clusterConf.rlnRelay: - var rlnRelayConf = builder.rlnRelayConf - - if rlnRelayConf.rlnRelay.isNone: - rlnRelayConf.rlnRelay = some(true) - else: - warn "RLN Relay was manually provided alongside a cluster conf", - used = rlnRelayConf.rlnRelay, discarded = clusterConf.rlnRelay - - if rlnRelayConf.rlnRelayEthContractAddress.isNone: - rlnRelayConf.rlnRelayEthContractAddress = - some(clusterConf.rlnRelayEthContractAddress.ContractAddress) - else: - warn "RLN Relay ETH Contract Address was manually provided alongside a cluster conf", - used = rlnRelayConf.rlnRelayEthContractAddress.get().string, - discarded = clusterConf.rlnRelayEthContractAddress.string - - if rlnRelayConf.rlnRelayChainId.isNone: - rlnRelayConf.rlnRelayChainId = some(clusterConf.rlnRelayChainId) - else: - warn "RLN Relay Chain Id was manually provided alongside a cluster conf", - used = rlnRelayConf.rlnRelayChainId, discarded = clusterConf.rlnRelayChainId - - if rlnRelayConf.rlnRelayDynamic.isNone: - rlnRelayConf.rlnRelayDynamic = some(clusterConf.rlnRelayDynamic) - else: - warn "RLN Relay Dynamic was manually provided alongside a cluster conf", - used = rlnRelayConf.rlnRelayDynamic, discarded = clusterConf.rlnRelayDynamic - - if rlnRelayConf.rlnRelayBandwidthThreshold.isNone: - rlnRelayConf.rlnRelayBandwidthThreshold = - some(clusterConf.rlnRelayBandwidthThreshold) - else: - warn "RLN Relay Bandwidth Threshold was manually provided alongside a cluster conf", - used = rlnRelayConf.rlnRelayBandwidthThreshold, - discarded = clusterConf.rlnRelayBandwidthThreshold - - if rlnRelayConf.rlnEpochSizeSec.isNone: - rlnRelayConf.rlnEpochSizeSec = some(clusterConf.rlnEpochSizeSec) - else: - warn "RLN Epoch Size in Seconds was manually provided alongside a cluster conf", - used = rlnRelayConf.rlnEpochSizeSec, discarded = clusterConf.rlnEpochSizeSec - - if rlnRelayConf.rlnRelayUserMessageLimit.isNone: - rlnRelayConf.rlnRelayUserMessageLimit = - some(clusterConf.rlnRelayUserMessageLimit) - else: - warn "RLN Relay Dynamic was manually provided alongside a cluster conf", - used = rlnRelayConf.rlnRelayUserMessageLimit, - discarded = clusterConf.rlnRelayUserMessageLimit - - if builder.maxMessageSizeBytes.isNone: - builder.maxMessageSizeBytes = - some(int(parseCorrectMsgSize(clusterConf.maxMessageSize))) - else: - warn "Max Message Size was manually provided alongside a cluster conf", - used = builder.maxMessageSizeBytes, discarded = clusterConf.maxMessageSize - - if builder.numShardsInNetwork.isNone: - builder.numShardsInNetwork = some(clusterConf.numShardsInNetwork) - else: - warn "Num Shards In Network was manually provided alongside a cluster conf", - used = builder.numShardsInNetwork, discarded = clusterConf.numShardsInNetwork - - if builder.discv5Discovery.isNone: - builder.discv5Discovery = some(clusterConf.discv5Discovery) - - if builder.discv5BootstrapNodes.isNone: - builder.discv5BootstrapNodes = some( - clusterConf.discv5BootstrapNodes.map( - proc(e: string): TextEnr = - e.TextEnr - ) - ) - # Apply preset - end - - let nodeKey = ?nodeKey(builder, rng) - - let clusterId = - if builder.clusterId.isSome: - builder.clusterId.get() - else: - return err("Cluster Id is missing") - - let numShardsInNetwork = - if builder.numShardsInNetwork.isSome: - builder.numShardsInNetwork.get() - else: - warn "Number of shards in network not specified, defaulting to one shard" - 1 - - let shards = - if builder.shards.isSome: - builder.shards.get() - else: - warn "shards not specified, defaulting to all shards in network" - # TODO: conversion should not be needed - let upperShard: uint16 = uint16(numShardsInNetwork - 1) - toSeq(0.uint16 .. upperShard) - - let discv5BootstrapNodes = - if builder.discv5BootstrapNodes.isSome: - builder.discv5BootstrapNodes.get() - else: - @[] - - let rlnRelayConf = builder.rlnRelayConf.build().valueOr: - return err("RLN Relay Conf building failed: " & $error) - - let maxMessageSizeBytes = - if builder.maxMessageSizeBytes.isSome: - builder.maxMessageSizeBytes.get() - else: - return err("Max Message Size is missing") - - let logLevel = - if builder.logLevel.isSome: - builder.logLevel.get() - else: - warn "Log Level not specified, defaulting to INFO" - logging.LogLevel.INFO - - let logFormat = - if builder.logFormat.isSome: - builder.logFormat.get() - else: - warn "Log Format not specified, defaulting to TEXT" - logging.LogFormat.TEXT - - let natStrategy = - if builder.natStrategy.isSome: - builder.natStrategy.get() - else: - warn "Nat Strategy is not specified, defaulting to none" - "none".NatStrategy - - let tcpPort = - if builder.tcpPort.isSome: - builder.tcpPort.get() - else: - return err("TCP Port is missing") - - let portsShift = - if builder.portsShift.isSome: - builder.portsShift.get() - else: - warn "Ports Shift is not specified, defaulting to 0" - 0.uint16 - - let wakuConf = WakuConf( - nodeKey: nodeKey, - clusterId: clusterId, - numShardsInNetwork: numShardsInNetwork, - shards: shards, - relay: relay, - store: store, - filter: filter, - lightPush: lightPush, - peerExchange: peerExchange, - discv5BootstrapNodes: discv5BootstrapNodes, - rlnRelayConf: rlnRelayConf, - maxMessageSizeBytes: maxMessageSizeBytes, - logLevel: logLevel, - logFormat: logFormat, - natStrategy: natStrategy, - tcpPort: tcpPort, - portsShift: portsShift, - ) - - ?validate(wakuConf) - - return ok(wakuConf) + return ok() diff --git a/waku/factory/waku_conf_builder.nim b/waku/factory/waku_conf_builder.nim new file mode 100644 index 000000000..72f44290d --- /dev/null +++ b/waku/factory/waku_conf_builder.nim @@ -0,0 +1,476 @@ +import + libp2p/crypto/crypto, + libp2p/multiaddress, + std/[net, options, sequtils], + chronicles, + results + +import + ./waku_conf, ./networks_config, ../common/logging, ../common/utils/parse_size_units + +logScope: + topics = "waku conf builder" + +############################## +## RLN Relay Config Builder ## +############################## +type RlnRelayConfBuilder = ref object + rlnRelay: Option[bool] + ethContractAddress: Option[ContractAddress] + chainId: Option[uint] + dynamic: Option[bool] + bandwidthThreshold: Option[int] + epochSizeSec: Option[uint64] + userMessageLimit: Option[uint64] + ethClientAddress: Option[EthRpcUrl] + +proc init*(T: type RlnRelayConfBuilder): RlnRelayConfBuilder = + RlnRelayConfBuilder() + +proc withRlnRelay*(builder: var RlnRelayConfBuilder, rlnRelay: bool) = + builder.rlnRelay = some(rlnRelay) + +proc withEthContractAddress*( + builder: var RlnRelayConfBuilder, ethContractAddress: string +) = + builder.ethContractAddress = some(ethContractAddress.ContractAddress) + +proc withChainId*(builder: var RlnRelayConfBuilder, chainId: uint) = + builder.chainId = some(chainId) + +proc withDynamic*(builder: var RlnRelayConfBuilder, dynamic: bool) = + builder.dynamic = some(dynamic) + +proc withBandwidthThreshold*( + builder: var RlnRelayConfBuilder, bandwidthThreshold: int +) = + builder.bandwidthThreshold = some(bandwidthThreshold) + +proc withEpochSizeSec*(builder: var RlnRelayConfBuilder, epochSizeSec: uint64) = + builder.epochSizeSec = some(epochSizeSec) + +proc withUserMessageLimit*(builder: var RlnRelayConfBuilder, userMessageLimit: uint64) = + builder.userMessageLimit = some(userMessageLimit) + +proc withEthClientAddress*(builder: var RlnRelayConfBuilder, ethClientAddress: string) = + builder.ethClientAddress = some(ethClientAddress.EthRpcUrl) + +proc build*(builder: RlnRelayConfBuilder): Result[Option[RlnRelayConf], string] = + if builder.rlnRelay.isNone or not builder.rlnRelay.get(): + info "RLN Relay is disabled" + return ok(none(RlnRelayConf)) + + let ethContractAddress = + if builder.ethContractAddress.isSome: + builder.ethContractAddress.get() + else: + return err("RLN Eth Contract Address was not specified") + + let chainId = + if builder.chainId.isSome: + builder.chainId.get() + else: + return err("RLN Relay Chain Id was not specified") + + let dynamic = + if builder.dynamic.isSome: + builder.dynamic.get() + else: + return err("RLN Relay Dynamic was not specified") + + let bandwidthThreshold = + if builder.bandwidthThreshold.isSome: + builder.bandwidthThreshold.get() + else: + return err("RLN Relay Bandwidth Threshold was not specified") + + let epochSizeSec = + if builder.epochSizeSec.isSome: + builder.epochSizeSec.get() + else: + return err("RLN Epoch Size was not specified") + + let userMessageLimit = + if builder.userMessageLimit.isSome: + builder.userMessageLimit.get() + else: + return err("RLN Relay User Message Limit was not specified") + + let ethClientAddress = + if builder.ethClientAddress.isSome: + builder.ethClientAddress.get() + else: + return err("RLN Relay Eth Client Address was not specified") + + return ok( + some( + RlnRelayConf( + chainId: chainId, + dynamic: dynamic, + ethContractAddress: ethContractAddress, + epochSizeSec: epochSizeSec, + userMessageLimit: userMessageLimit, + ethClientAddress: ethClientAddress, + ) + ) + ) + +########################### +## Discv5 Config Builder ## +########################### +type Discv5ConfBuilder = ref object + discv5*: Option[bool] + bootstrapNodes*: Option[seq[TextEnr]] + udpPort*: Option[Port] + +proc init(T: type Discv5ConfBuilder): Discv5ConfBuilder = + Discv5ConfBuilder() + +proc withDiscv5(builder: var Discv5ConfBuilder, discv5: bool) = + builder.discv5 = some(discv5) + +proc withBootstrapNodes(builder: var Discv5ConfBuilder, bootstrapNodes: seq[string]) = + # TODO: validate ENRs? + builder.bootstrapNodes = some( + bootstrapNodes.map( + proc(e: string): TextEnr = + e.TextEnr + ) + ) + +proc withUdpPort*(builder: var Discv5ConfBuilder, udpPort: uint16) = + builder.udpPort = some (udpPort.Port) + +proc build(builder: Discv5ConfBuilder): Result[Option[Discv5Conf], string] = + if builder.discv5.isNone or not builder.discv5.get(): + return ok(none(Discv5Conf)) + + # TODO: Do we need to ensure there are bootstrap nodes? + # Not sure discv5 is of any use without bootstrap nodes + # Confirmed: discv5 is useless without bootstrap node - config valid function? + let bootstrapNodes = builder.bootstrapNodes.get(@[]) + + let udpPort = + if builder.udpPort.isSome: + builder.udpPort.get() + else: + return err("Discv5 UDP Port was not specified") + + return ok(some(Discv5Conf(bootstrapNodes: bootstrapNodes, udpPort: udpPort))) + +######################### +## Waku Config Builder ## +######################### +type WakuConfBuilder* = ref object + nodeKey*: Option[PrivateKey] + + clusterId: Option[uint16] + numShardsInNetwork: Option[uint32] + shards: Option[seq[uint16]] + + relay: Option[bool] + store: Option[bool] + filter: Option[bool] + lightPush: Option[bool] + peerExchange: Option[bool] + + clusterConf: Option[ClusterConf] + + rlnRelayConf*: RlnRelayConfBuilder + + maxMessageSizeBytes: Option[int] + + discv5Conf*: Discv5ConfBuilder + + logLevel: Option[logging.LogLevel] + logFormat: Option[logging.LogFormat] + + natStrategy: Option[NatStrategy] + + tcpPort: Option[Port] + portsShift: Option[uint16] + dns4DomainName: Option[DomainName] + extMultiAddrs: seq[string] + +proc init*(T: type WakuConfBuilder): WakuConfBuilder = + WakuConfBuilder( + rlnRelayConf: RlnRelayConfBuilder.init(), discv5Conf: Discv5ConfBuilder.init() + ) + +proc withClusterConf*(builder: var WakuConfBuilder, clusterConf: ClusterConf) = + builder.clusterConf = some(clusterConf) + +proc withNodeKey*(builder: var WakuConfBuilder, nodeKey: PrivateKey) = + builder.nodeKey = some(nodeKey) + +proc withClusterId*(builder: var WakuConfBuilder, clusterId: uint16) = + builder.clusterid = some(clusterId) + +proc withShards*(builder: var WakuConfBuilder, shards: seq[uint16]) = + builder.shards = some(shards) + +proc withRelay*(builder: var WakuConfBuilder, relay: bool) = + builder.relay = some(relay) + +proc withMaxMessageSizeBytes*(builder: var WakuConfBuilder, maxMessageSizeBytes: int) = + builder.maxMessageSizeBytes = some(maxMessageSizeBytes) + +proc withDiscv5*(builder: var WakuConfBuilder, discv5: bool) = + builder.discv5Conf.withDiscv5(discv5) + +proc withTcpPort*(builder: var WakuConfBuilder, tcpPort: uint16) = + builder.tcpPort = some(tcpPort.Port) + +proc withDns4DomainName*(builder: var WakuConfBuilder, dns4DomainName: string) = + builder.dns4DomainName = some(dns4DomainName.DomainName) + +proc withExtMultiAddr*(builder: var WakuConfBuilder, extMultiAddr: string) = + builder.extMultiAddrs.add(extMultiAddr) + +proc nodeKey( + builder: WakuConfBuilder, rng: ref HmacDrbgContext +): Result[PrivateKey, string] = + if builder.nodeKey.isSome(): + return ok(builder.nodeKey.get()) + else: + warn "missing node key, generating new set" + let nodeKey = crypto.PrivateKey.random(Secp256k1, rng[]).valueOr: + error "Failed to generate key", error = error + return err("Failed to generate key: " & $error) + return ok(nodeKey) + +proc build*( + builder: var WakuConfBuilder, rng: ref HmacDrbgContext = crypto.newRng() +): Result[WakuConf, string] = + ## Return a WakuConf that contains all mandatory parameters + ## Applies some sane defaults that are applicable across any usage + ## of libwaku. It aims to be agnostic so it does not apply a + ## default when it is opinionated. + + let relay = + if builder.relay.isSome: + builder.relay.get() + else: + warn "whether to mount relay is not specified, defaulting to not mounting" + false + + let store = + if builder.store.isSome: + builder.store.get() + else: + warn "whether to mount store is not specified, defaulting to not mounting" + false + + let filter = + if builder.filter.isSome: + builder.filter.get() + else: + warn "whether to mount filter is not specified, defaulting to not mounting" + false + + let lightPush = + if builder.lightPush.isSome: + builder.lightPush.get() + else: + warn "whether to mount lightPush is not specified, defaulting to not mounting" + false + + let peerExchange = + if builder.peerExchange.isSome: + builder.peerExchange.get() + else: + warn "whether to mount peerExchange is not specified, defaulting to not mounting" + false + + # Apply cluster conf - values passed manually override cluster conf + # Should be applied **first**, before individual values are pulled + if builder.clusterConf.isSome: + var clusterConf = builder.clusterConf.get() + + if builder.clusterId.isNone: + builder.clusterId = some(clusterConf.clusterId) + else: + warn "Cluster id was manually provided alongside a cluster conf", + used = builder.clusterId, discarded = clusterConf.clusterId + + if relay and clusterConf.rlnRelay: + var rlnRelayConf = builder.rlnRelayConf + + if rlnRelayConf.rlnRelay.isNone: + rlnRelayConf.withRlnRelay(true) + else: + warn "RLN Relay was manually provided alongside a cluster conf", + used = rlnRelayConf.rlnRelay, discarded = clusterConf.rlnRelay + + if rlnRelayConf.ethContractAddress.isNone: + rlnRelayConf.withEthContractAddress(clusterConf.rlnRelayEthContractAddress) + else: + warn "RLN Relay ETH Contract Address was manually provided alongside a cluster conf", + used = rlnRelayConf.ethContractAddress.get().string, + discarded = clusterConf.rlnRelayEthContractAddress.string + + if rlnRelayConf.chainId.isNone: + rlnRelayConf.withChainId(clusterConf.rlnRelayChainId) + else: + warn "RLN Relay Chain Id was manually provided alongside a cluster conf", + used = rlnRelayConf.chainId, discarded = clusterConf.rlnRelayChainId + + if rlnRelayConf.dynamic.isNone: + rlnRelayConf.withDynamic(clusterConf.rlnRelayDynamic) + else: + warn "RLN Relay Dynamic was manually provided alongside a cluster conf", + used = rlnRelayConf.dynamic, discarded = clusterConf.rlnRelayDynamic + + if rlnRelayConf.bandwidthThreshold.isNone: + rlnRelayConf.withBandwidthThreshold(clusterConf.rlnRelayBandwidthThreshold) + else: + warn "RLN Relay Bandwidth Threshold was manually provided alongside a cluster conf", + used = rlnRelayConf.bandwidthThreshold, + discarded = clusterConf.rlnRelayBandwidthThreshold + + if rlnRelayConf.epochSizeSec.isNone: + rlnRelayConf.withEpochSizeSec(clusterConf.rlnEpochSizeSec) + else: + warn "RLN Epoch Size in Seconds was manually provided alongside a cluster conf", + used = rlnRelayConf.epochSizeSec, discarded = clusterConf.rlnEpochSizeSec + + if rlnRelayConf.userMessageLimit.isNone: + rlnRelayConf.withUserMessageLimit(clusterConf.rlnRelayUserMessageLimit) + else: + warn "RLN Relay Dynamic was manually provided alongside a cluster conf", + used = rlnRelayConf.userMessageLimit, + discarded = clusterConf.rlnRelayUserMessageLimit + + if builder.maxMessageSizeBytes.isNone: + builder.maxMessageSizeBytes = + some(int(parseCorrectMsgSize(clusterConf.maxMessageSize))) + else: + warn "Max Message Size was manually provided alongside a cluster conf", + used = builder.maxMessageSizeBytes, discarded = clusterConf.maxMessageSize + + if builder.numShardsInNetwork.isNone: + builder.numShardsInNetwork = some(clusterConf.numShardsInNetwork) + else: + warn "Num Shards In Network was manually provided alongside a cluster conf", + used = builder.numShardsInNetwork, discarded = clusterConf.numShardsInNetwork + + if clusterConf.discv5Discovery: + var discv5ConfBuilder = builder.discv5Conf + + if discv5ConfBuilder.discv5.isNone: + discv5ConfBuilder.withDiscv5(clusterConf.discv5Discovery) + + if discv5ConfBuilder.bootstrapNodes.isNone and + clusterConf.discv5BootstrapNodes.len > 0: + discv5ConfBuilder.withBootstrapNodes(clusterConf.discv5BootstrapNodes) + # Apply preset - end + + let nodeKey = ?nodeKey(builder, rng) + + let clusterId = + if builder.clusterId.isSome: + builder.clusterId.get() + else: + return err("Cluster Id is missing") + + let numShardsInNetwork = + if builder.numShardsInNetwork.isSome: + builder.numShardsInNetwork.get() + else: + warn "Number of shards in network not specified, defaulting to one shard" + 1 + + let shards = + if builder.shards.isSome: + builder.shards.get() + else: + warn "shards not specified, defaulting to all shards in network" + # TODO: conversion should not be needed + let upperShard: uint16 = uint16(numShardsInNetwork - 1) + toSeq(0.uint16 .. upperShard) + + let discv5Conf = builder.discv5Conf.build().valueOr: + return err("Discv5 Conf building failed: " & $error) + + let rlnRelayConf = builder.rlnRelayConf.build().valueOr: + return err("RLN Relay Conf building failed: " & $error) + + let maxMessageSizeBytes = + if builder.maxMessageSizeBytes.isSome: + builder.maxMessageSizeBytes.get() + else: + return err("Max Message Size is missing") + + let logLevel = + if builder.logLevel.isSome: + builder.logLevel.get() + else: + warn "Log Level not specified, defaulting to INFO" + logging.LogLevel.INFO + + let logFormat = + if builder.logFormat.isSome: + builder.logFormat.get() + else: + warn "Log Format not specified, defaulting to TEXT" + logging.LogFormat.TEXT + + let natStrategy = + if builder.natStrategy.isSome: + builder.natStrategy.get() + else: + warn "Nat Strategy is not specified, defaulting to none" + "none".NatStrategy + + let tcpPort = + if builder.tcpPort.isSome: + builder.tcpPort.get() + else: + return err("TCP Port is missing") + + let portsShift = + if builder.portsShift.isSome: + builder.portsShift.get() + else: + warn "Ports Shift is not specified, defaulting to 0" + 0.uint16 + + let dns4DomainName = + if builder.dns4DomainName.isSome: + let d = builder.dns4DomainName.get() + if d.string != "": + some(d) + else: + none(DomainName) + else: + none(DomainName) + + var extMultiAddrs: seq[MultiAddress] = @[] + for s in builder.extMultiAddrs: + let m = MultiAddress.init(s).valueOr: + return err("Invalid multiaddress provided: " & s) + extMultiAddrs.add(m) + + return ok( + WakuConf( + nodeKey: nodeKey, + clusterId: clusterId, + numShardsInNetwork: numShardsInNetwork, + shards: shards, + relay: relay, + store: store, + filter: filter, + lightPush: lightPush, + peerExchange: peerExchange, + discv5Conf: discv5Conf, + rlnRelayConf: rlnRelayConf, + maxMessageSizeBytes: maxMessageSizeBytes, + logLevel: logLevel, + logFormat: logFormat, + natStrategy: natStrategy, + tcpPort: tcpPort, + portsShift: portsShift, + dns4DomainName: dns4DomainName, + extMultiAddrs: extMultiAddrs, + ) + )