Prem Chaitanya Prathi b0cd75f4cb
feat: update rendezvous to broadcast and discover WakuPeerRecords (#3617)
* update rendezvous to work with WakuPeeRecord and use libp2p updated version

* split rendezvous client and service implementation

* mount rendezvous client by default
2025-11-21 23:15:12 +05:30

239 lines
7.3 KiB
Nim

import
std/[net, options, strutils],
chronicles,
libp2p/crypto/crypto,
libp2p/multiaddress,
libp2p/crypto/curve25519,
secp256k1,
results
import
../waku_rln_relay/rln_relay,
../rest_api/endpoint/builder,
../discovery/waku_discv5,
../node/waku_metrics,
../common/logging,
../common/rate_limit/setting,
../waku_enr/capabilities,
./networks_config,
../waku_mix
export RlnRelayConf, RlnRelayCreds, RestServerConf, Discv5Conf, MetricsServerConf
logScope:
topics = "waku conf"
type WebSocketSecureConf* {.requiresInit.} = object
keyPath*: string
certPath*: string
type WebSocketConf* = object
port*: Port
secureConf*: Option[WebSocketSecureConf]
# TODO: should be defined in validator_signed.nim and imported here
type ProtectedShard* {.requiresInit.} = object
shard*: uint16
key*: secp256k1.SkPublicKey
type DnsDiscoveryConf* {.requiresInit.} = object
enrTreeUrl*: string
# TODO: should probably only have one set of name servers (see dnsaddrs)
nameServers*: seq[IpAddress]
type StoreSyncConf* {.requiresInit.} = object
rangeSec*: uint32
intervalSec*: uint32
relayJitterSec*: uint32
type MixConf* = ref object
mixKey*: Curve25519Key
mixPubKey*: Curve25519Key
mixnodes*: seq[MixNodePubInfo]
type StoreServiceConf* {.requiresInit.} = object
dbMigration*: bool
dbURl*: string
dbVacuum*: bool
supportV2*: bool
maxNumDbConnections*: int
retentionPolicy*: string
resume*: bool
storeSyncConf*: Option[StoreSyncConf]
type FilterServiceConf* {.requiresInit.} = object
maxPeersToServe*: uint32
subscriptionTimeout*: uint16
maxCriteria*: uint32
type EndpointConf* = object # TODO: make enum
natStrategy*: string
p2pTcpPort*: Port
dns4DomainName*: Option[string]
p2pListenAddress*: IpAddress
extMultiAddrs*: seq[MultiAddress]
extMultiAddrsOnly*: bool
## `WakuConf` is a valid configuration for a Waku node
## All information needed by a waku node should be contained
## In this object. A convenient `validate` method enables doing
## sanity checks beyond type enforcement.
## If `Option` is `some` it means the related protocol is enabled.
type WakuConf* {.requiresInit.} = ref object
# ref because `getRunningNetConfig` modifies it
nodeKey*: crypto.PrivateKey
clusterId*: uint16
subscribeShards*: seq[uint16]
protectedShards*: seq[ProtectedShard]
shardingConf*: ShardingConf
contentTopics*: seq[string]
relay*: bool
lightPush*: bool
peerExchangeService*: bool
peerExchangeDiscovery*: bool
# TODO: remove relay peer exchange
relayPeerExchange*: bool
rendezvous*: bool
circuitRelayClient*: bool
discv5Conf*: Option[Discv5Conf]
dnsDiscoveryConf*: Option[DnsDiscoveryConf]
filterServiceConf*: Option[FilterServiceConf]
storeServiceConf*: Option[StoreServiceConf]
rlnRelayConf*: Option[RlnRelayConf]
restServerConf*: Option[RestServerConf]
metricsServerConf*: Option[MetricsServerConf]
webSocketConf*: Option[WebSocketConf]
mixConf*: Option[MixConf]
portsShift*: uint16
dnsAddrsNameServers*: seq[IpAddress]
endpointConf*: EndpointConf
wakuFlags*: CapabilitiesBitfield
# TODO: could probably make it a `PeerRemoteInfo`
staticNodes*: seq[string]
remoteStoreNode*: Option[string]
remoteLightPushNode*: Option[string]
remoteFilterNode*: Option[string]
remotePeerExchangeNode*: Option[string]
maxMessageSizeBytes*: uint64
logLevel*: logging.LogLevel
logFormat*: logging.LogFormat
peerPersistence*: bool
# TODO: should clearly be a uint
peerStoreCapacity*: Option[int]
# TODO: should clearly be a uint
maxConnections*: int
agentString*: string
colocationLimit*: int
rateLimit*: ProtocolRateLimitSettings
# TODO: those could be in a relay conf object
maxRelayPeers*: Option[int]
relayShardedPeerManagement*: bool
# TODO: use proper type
relayServiceRatio*: string
p2pReliability*: bool
proc logConf*(conf: WakuConf) =
info "Configuration: Enabled protocols",
relay = conf.relay,
rlnRelay = conf.rlnRelayConf.isSome(),
store = conf.storeServiceConf.isSome(),
filter = conf.filterServiceConf.isSome(),
lightPush = conf.lightPush,
peerExchange = conf.peerExchangeService,
rendezvous = conf.rendezvous
info "Configuration. Network", cluster = conf.clusterId
for shard in conf.subscribeShards:
info "Configuration. Active Relay Shards", shard = shard
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.dynamic:
info "Configuration. Validation",
mechanism = "onchain rln",
contract = rlnRelayConf.ethContractAddress.string,
maxMessageSize = conf.maxMessageSizeBytes,
rlnEpochSizeSec = rlnRelayConf.epochSizeSec,
rlnRelayUserMessageLimit = rlnRelayConf.userMessageLimit
proc validateNodeKey(wakuConf: WakuConf): Result[void, string] =
wakuConf.nodeKey.getPublicKey().isOkOr:
return err("nodekey param is invalid")
return ok()
proc validateNoEmptyStrings(wakuConf: WakuConf): Result[void, string] =
if wakuConf.endpointConf.dns4DomainName.isSome() and
isEmptyOrWhiteSpace(wakuConf.endpointConf.dns4DomainName.get().string):
return err("dns4-domain-name is an empty string, set it to none(string) instead")
if isEmptyOrWhiteSpace(wakuConf.relayServiceRatio):
return err("relay-service-ratio is an empty string")
for sn in wakuConf.staticNodes:
if isEmptyOrWhiteSpace(sn):
return err("staticnode contain an empty string")
if wakuConf.remoteStoreNode.isSome() and
isEmptyOrWhiteSpace(wakuConf.remoteStoreNode.get()):
return err("storenode is an empty string, set it to none(string) instead")
if wakuConf.remoteLightPushNode.isSome() and
isEmptyOrWhiteSpace(wakuConf.remoteLightPushNode.get()):
return err("lightpushnode is an empty string, set it to none(string) instead")
if wakuConf.remotePeerExchangeNode.isSome() and
isEmptyOrWhiteSpace(wakuConf.remotePeerExchangeNode.get()):
return err("peer-exchange-node is an empty string, set it to none(string) instead")
if wakuConf.remoteFilterNode.isSome() and
isEmptyOrWhiteSpace(wakuConf.remoteFilterNode.get()):
return err("filternode is an empty string, set it to none(string) instead")
if wakuConf.dnsDiscoveryConf.isSome() and
isEmptyOrWhiteSpace(wakuConf.dnsDiscoveryConf.get().enrTreeUrl):
return err("dns-discovery-url is an empty string")
# TODO: rln relay config should validate itself
if wakuConf.rlnRelayConf.isSome():
let rlnRelayConf = wakuConf.rlnRelayConf.get()
if rlnRelayConf.ethClientUrls.len == 0:
return err("rln-relay-eth-client-address is empty")
if isEmptyOrWhiteSpace(rlnRelayConf.ethContractAddress):
return err("rln-relay-eth-contract-address is an empty string")
if rlnRelayConf.creds.isSome():
let creds = rlnRelayConf.creds.get()
if isEmptyOrWhiteSpace(creds.path):
return err ("rln-relay-cred-path is an empty string")
if isEmptyOrWhiteSpace(creds.password):
return err ("rln-relay-cred-password is an empty string")
return ok()
proc validate*(wakuConf: WakuConf): Result[void, string] =
?wakuConf.validateNodeKey()
?wakuConf.shardingConf.validateShards(wakuConf.subscribeShards)
?wakuConf.validateNoEmptyStrings()
return ok()