mirror of
https://github.com/logos-messaging/logos-messaging-nim.git
synced 2026-01-02 14:03:06 +00:00
chore: allow multiple rln eth clients (#3402)
* use of multiple Eth clients instead of just one * config_chat2 enhance param comment * group_manager: raise exception if could not connect to any of the eth clients
This commit is contained in:
parent
d86babac3a
commit
42ab866f2c
@ -560,8 +560,7 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
|
||||
dynamic: conf.rlnRelayDynamic,
|
||||
credIndex: conf.rlnRelayCredIndex,
|
||||
chainId: conf.rlnRelayChainId,
|
||||
ethContractAddress: conf.rlnRelayEthContractAddress,
|
||||
ethClientAddress: string(conf.rlnRelayethClientAddress),
|
||||
ethClientUrls: conf.ethClientUrls.mapIt(string(it)),
|
||||
creds: some(
|
||||
RlnRelayCreds(
|
||||
path: conf.rlnRelayCredPath, password: conf.rlnRelayCredPassword
|
||||
|
||||
@ -18,7 +18,8 @@ type
|
||||
prod
|
||||
test
|
||||
|
||||
EthRpcUrl = distinct string
|
||||
EthRpcUrl* = distinct string
|
||||
|
||||
Chat2Conf* = object ## General node config
|
||||
logLevel* {.
|
||||
desc: "Sets the log level.", defaultValue: LogLevel.INFO, name: "log-level"
|
||||
@ -248,11 +249,12 @@ type
|
||||
name: "rln-relay-id-commitment-key"
|
||||
.}: string
|
||||
|
||||
rlnRelayEthClientAddress* {.
|
||||
desc: "HTTP address of an Ethereum testnet client e.g., http://localhost:8540/",
|
||||
defaultValue: "http://localhost:8540/",
|
||||
ethClientUrls* {.
|
||||
desc:
|
||||
"HTTP address of an Ethereum testnet client e.g., http://localhost:8540/. Argument may be repeated.",
|
||||
defaultValue: newSeq[EthRpcUrl](0),
|
||||
name: "rln-relay-eth-client-address"
|
||||
.}: EthRpcUrl
|
||||
.}: seq[EthRpcUrl]
|
||||
|
||||
rlnRelayEthContractAddress* {.
|
||||
desc: "Address of membership contract on an Ethereum testnet",
|
||||
|
||||
@ -638,7 +638,7 @@ when isMainModule:
|
||||
dynamic: conf.rlnRelayDynamic,
|
||||
credIndex: some(uint(0)),
|
||||
ethContractAddress: conf.rlnRelayEthContractAddress,
|
||||
ethClientAddress: string(conf.rlnRelayethClientAddress),
|
||||
ethClientUrls: conf.ethClientUrls.mapIt(string(it)),
|
||||
treePath: conf.rlnRelayTreePath,
|
||||
epochSizeSec: conf.rlnEpochSizeSec,
|
||||
creds: none(RlnRelayCreds),
|
||||
|
||||
@ -8,7 +8,7 @@ import
|
||||
stew/shims/net,
|
||||
regex
|
||||
|
||||
type EthRpcUrl = distinct string
|
||||
type EthRpcUrl* = distinct string
|
||||
|
||||
type NetworkMonitorConf* = object
|
||||
logLevel* {.
|
||||
@ -82,11 +82,12 @@ type NetworkMonitorConf* = object
|
||||
name: "rln-relay-tree-path"
|
||||
.}: string
|
||||
|
||||
rlnRelayEthClientAddress* {.
|
||||
desc: "HTTP address of an Ethereum testnet client e.g., http://localhost:8540/",
|
||||
defaultValue: "http://localhost:8540/",
|
||||
ethClientUrls* {.
|
||||
desc:
|
||||
"HTTP address of an Ethereum testnet client e.g., http://localhost:8540/. Argument may be repeated.",
|
||||
defaultValue: newSeq[EthRpcUrl](0),
|
||||
name: "rln-relay-eth-client-address"
|
||||
.}: EthRpcUrl
|
||||
.}: seq[EthRpcUrl]
|
||||
|
||||
rlnRelayEthContractAddress* {.
|
||||
desc: "Address of membership contract on an Ethereum testnet",
|
||||
|
||||
@ -26,7 +26,7 @@ suite "Waku config - apply preset":
|
||||
cmd: noCommand,
|
||||
preset: "twn",
|
||||
relay: true,
|
||||
rlnRelayEthClientAddress: "http://someaddress".EthRpcUrl,
|
||||
ethClientUrls: @["http://someaddress".EthRpcUrl],
|
||||
rlnRelayTreePath: "/tmp/sometreepath",
|
||||
)
|
||||
|
||||
@ -109,7 +109,7 @@ suite "Waku config - apply preset":
|
||||
cmd: noCommand,
|
||||
clusterId: 1.uint16,
|
||||
relay: true,
|
||||
rlnRelayEthClientAddress: "http://someaddress".EthRpcUrl,
|
||||
ethClientUrls: @["http://someaddress".EthRpcUrl],
|
||||
rlnRelayTreePath: "/tmp/sometreepath",
|
||||
)
|
||||
|
||||
|
||||
@ -77,10 +77,10 @@ suite "Onchain group manager":
|
||||
assert metadata.contractAddress == manager.ethContractAddress,
|
||||
"contractAddress is not equal to " & manager.ethContractAddress
|
||||
|
||||
let differentContractAddress = await uploadRLNContract(manager.ethClientUrl)
|
||||
let differentContractAddress = await uploadRLNContract(manager.ethClientUrls[0])
|
||||
# simulating a change in the contractAddress
|
||||
let manager2 = OnchainGroupManager(
|
||||
ethClientUrl: EthClient,
|
||||
ethClientUrls: @[EthClient],
|
||||
ethContractAddress: $differentContractAddress,
|
||||
rlnInstance: manager.rlnInstance,
|
||||
onFatalErrorAction: proc(errStr: string) =
|
||||
|
||||
@ -250,7 +250,7 @@ proc stopAnvil*(runAnvil: Process) {.used.} =
|
||||
error "Anvil daemon termination failed: ", err = getCurrentExceptionMsg()
|
||||
|
||||
proc setupOnchainGroupManager*(
|
||||
ethClientAddress: string = EthClient, amountEth: UInt256 = 10.u256
|
||||
ethClientUrl: string = EthClient, amountEth: UInt256 = 10.u256
|
||||
): Future[OnchainGroupManager] {.async.} =
|
||||
let rlnInstanceRes =
|
||||
createRlnInstance(tree_path = genTempPath("rln_tree", "group_manager_onchain"))
|
||||
@ -259,9 +259,9 @@ proc setupOnchainGroupManager*(
|
||||
|
||||
let rlnInstance = rlnInstanceRes.get()
|
||||
|
||||
let contractAddress = await uploadRLNContract(ethClientAddress)
|
||||
let contractAddress = await uploadRLNContract(ethClientUrl)
|
||||
# connect to the eth client
|
||||
let web3 = await newWeb3(ethClientAddress)
|
||||
let web3 = await newWeb3(ethClientUrl)
|
||||
|
||||
let accounts = await web3.provider.eth_accounts()
|
||||
web3.defaultAccount = accounts[0]
|
||||
@ -275,7 +275,7 @@ proc setupOnchainGroupManager*(
|
||||
)
|
||||
|
||||
let manager = OnchainGroupManager(
|
||||
ethClientUrl: ethClientAddress,
|
||||
ethClientUrls: @[ethClientUrl],
|
||||
ethContractAddress: $contractAddress,
|
||||
chainId: CHAIN_ID,
|
||||
ethPrivateKey: some($privateKey),
|
||||
|
||||
@ -3,7 +3,7 @@ when (NimMajor, NimMinor) < (1, 4):
|
||||
else:
|
||||
{.push raises: [].}
|
||||
|
||||
import chronicles, results, std/tempfiles
|
||||
import chronicles, results, std/[tempfiles, sequtils]
|
||||
|
||||
import
|
||||
waku/[
|
||||
@ -19,7 +19,7 @@ logScope:
|
||||
type RlnKeystoreGeneratorConf* = object
|
||||
execute*: bool
|
||||
ethContractAddress*: string
|
||||
ethClientAddress*: string
|
||||
ethClientUrls*: seq[string]
|
||||
chainId*: uint
|
||||
credPath*: string
|
||||
credPassword*: string
|
||||
@ -65,7 +65,7 @@ proc doRlnKeystoreGenerator*(conf: RlnKeystoreGeneratorConf) =
|
||||
|
||||
# 4. initialize OnchainGroupManager
|
||||
let groupManager = OnchainGroupManager(
|
||||
ethClientUrl: string(conf.ethClientAddress),
|
||||
ethClientUrls: conf.ethClientUrls,
|
||||
chainId: conf.chainId,
|
||||
ethContractAddress: conf.ethContractAddress,
|
||||
rlnInstance: rlnInstance,
|
||||
|
||||
@ -9,9 +9,8 @@ logScope:
|
||||
##############################
|
||||
type RlnRelayConfBuilder* = object
|
||||
enabled*: Option[bool]
|
||||
|
||||
chainId*: Option[uint]
|
||||
ethClientAddress*: Option[string]
|
||||
ethClientUrls*: Option[seq[string]]
|
||||
ethContractAddress*: Option[string]
|
||||
credIndex*: Option[uint]
|
||||
credPassword*: Option[string]
|
||||
@ -42,8 +41,8 @@ proc withCredPath*(b: var RlnRelayConfBuilder, credPath: string) =
|
||||
proc withDynamic*(b: var RlnRelayConfBuilder, dynamic: bool) =
|
||||
b.dynamic = some(dynamic)
|
||||
|
||||
proc withEthClientAddress*(b: var RlnRelayConfBuilder, ethClientAddress: string) =
|
||||
b.ethClientAddress = some(ethClientAddress)
|
||||
proc withEthClientUrls*(b: var RlnRelayConfBuilder, ethClientUrls: seq[string]) =
|
||||
b.ethClientUrls = some(ethClientUrls)
|
||||
|
||||
proc withEthContractAddress*(b: var RlnRelayConfBuilder, ethContractAddress: string) =
|
||||
b.ethContractAddress = some(ethContractAddress)
|
||||
@ -76,8 +75,8 @@ proc build*(b: RlnRelayConfBuilder): Result[Option[RlnRelayConf], string] =
|
||||
|
||||
if b.dynamic.isNone():
|
||||
return err("rlnRelay.dynamic is not specified")
|
||||
if b.ethClientAddress.get("") == "":
|
||||
return err("rlnRelay.ethClientAddress is not specified")
|
||||
if b.ethClientUrls.get(newSeq[string](0)).len == 0:
|
||||
return err("rlnRelay.ethClientUrls is not specified")
|
||||
if b.ethContractAddress.get("") == "":
|
||||
return err("rlnRelay.ethContractAddress is not specified")
|
||||
if b.epochSizeSec.isNone():
|
||||
@ -94,7 +93,7 @@ proc build*(b: RlnRelayConfBuilder): Result[Option[RlnRelayConf], string] =
|
||||
credIndex: b.credIndex,
|
||||
creds: creds,
|
||||
dynamic: b.dynamic.get(),
|
||||
ethClientAddress: b.ethClientAddress.get(),
|
||||
ethClientUrls: b.ethClientUrls.get(),
|
||||
ethContractAddress: b.ethContractAddress.get(),
|
||||
epochSizeSec: b.epochSizeSec.get(),
|
||||
userMessageLimit: b.userMessageLimit.get(),
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import
|
||||
std/[strutils, strformat],
|
||||
std/[strutils, strformat, sequtils],
|
||||
results,
|
||||
chronicles,
|
||||
chronos,
|
||||
@ -75,11 +75,12 @@ type WakuNodeConf* = object
|
||||
name: "rln-relay-cred-path"
|
||||
.}: string
|
||||
|
||||
rlnRelayEthClientAddress* {.
|
||||
desc: "HTTP address of an Ethereum testnet client e.g., http://localhost:8540/",
|
||||
defaultValue: "http://localhost:8540/",
|
||||
ethClientUrls* {.
|
||||
desc:
|
||||
"HTTP address of an Ethereum testnet client e.g., http://localhost:8540/. Argument may be repeated.",
|
||||
defaultValue: @[EthRpcUrl("http://localhost:8540/")],
|
||||
name: "rln-relay-eth-client-address"
|
||||
.}: EthRpcUrl
|
||||
.}: seq[EthRpcUrl]
|
||||
|
||||
rlnRelayEthContractAddress* {.
|
||||
desc: "Address of membership contract on an Ethereum testnet.",
|
||||
@ -867,7 +868,7 @@ proc toKeystoreGeneratorConf*(n: WakuNodeConf): RlnKeystoreGeneratorConf =
|
||||
RlnKeystoreGeneratorConf(
|
||||
execute: n.execute,
|
||||
chainId: n.rlnRelayChainId,
|
||||
ethClientAddress: n.rlnRelayEthClientAddress.string,
|
||||
ethClientUrls: n.ethClientUrls.mapIt(string(it)),
|
||||
ethContractAddress: n.rlnRelayEthContractAddress,
|
||||
userMessageLimit: n.rlnRelayUserMessageLimit,
|
||||
ethPrivateKey: n.rlnRelayEthPrivateKey,
|
||||
@ -907,8 +908,8 @@ proc toWakuConf*(n: WakuNodeConf): ConfResult[WakuConf] =
|
||||
b.rlnRelayConf.withCredPath(n.rlnRelayCredPath)
|
||||
if n.rlnRelayCredPassword != "":
|
||||
b.rlnRelayConf.withCredPassword(n.rlnRelayCredPassword)
|
||||
if n.rlnRelayEthClientAddress.string != "":
|
||||
b.rlnRelayConf.withEthClientAddress(n.rlnRelayEthClientAddress.string)
|
||||
if n.ethClientUrls.len > 0:
|
||||
b.rlnRelayConf.withEthClientUrls(n.ethClientUrls.mapIt(string(it)))
|
||||
if n.rlnRelayEthContractAddress != "":
|
||||
b.rlnRelayConf.withEthContractAddress(n.rlnRelayEthContractAddress)
|
||||
|
||||
|
||||
@ -354,7 +354,7 @@ proc setupProtocols(
|
||||
credIndex: rlnRelayConf.credIndex,
|
||||
ethContractAddress: rlnRelayConf.ethContractAddress,
|
||||
chainId: rlnRelayConf.chainId,
|
||||
ethClientAddress: rlnRelayConf.ethClientAddress,
|
||||
ethClientUrls: rlnRelayConf.ethClientUrls,
|
||||
creds: rlnRelayConf.creds,
|
||||
treePath: rlnRelayConf.treePath,
|
||||
userMessageLimit: rlnRelayConf.userMessageLimit,
|
||||
|
||||
@ -160,7 +160,7 @@ proc logConf*(conf: WakuConf) =
|
||||
maxMessageSize = conf.maxMessageSizeBytes,
|
||||
rlnEpochSizeSec = rlnRelayConf.epochSizeSec,
|
||||
rlnRelayUserMessageLimit = rlnRelayConf.userMessageLimit,
|
||||
rlnRelayEthClientAddress = string(rlnRelayConf.ethClientAddress)
|
||||
ethClientUrls = rlnRelayConf.ethClientUrls
|
||||
|
||||
proc validateNodeKey(wakuConf: WakuConf): Result[void, string] =
|
||||
wakuConf.nodeKey.getPublicKey().isOkOr:
|
||||
@ -224,8 +224,8 @@ proc validateNoEmptyStrings(wakuConf: WakuConf): Result[void, string] =
|
||||
|
||||
if isEmptyOrWhiteSpace(rlnRelayConf.treePath):
|
||||
return err("rlnRelayConf.treepath is an empty string")
|
||||
if isEmptyOrWhiteSpace(rlnRelayConf.ethClientAddress):
|
||||
return err("rlnRelayConf.ethClientAddress is an empty string")
|
||||
if rlnRelayConf.ethClientUrls.len == 0:
|
||||
return err("rlnRelayConf.ethClientUrls is empty")
|
||||
if isEmptyOrWhiteSpace(rlnRelayConf.ethContractAddress):
|
||||
return err("rlnRelayConf.ethContractAddress is an empty string")
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ contract(WakuRlnContract):
|
||||
type
|
||||
WakuRlnContractWithSender = Sender[WakuRlnContract]
|
||||
OnchainGroupManager* = ref object of GroupManager
|
||||
ethClientUrl*: string
|
||||
ethClientUrls*: seq[string]
|
||||
ethPrivateKey*: Option[string]
|
||||
ethContractAddress*: string
|
||||
ethRpc*: Option[Web3]
|
||||
@ -458,11 +458,35 @@ method onRegister*(g: OnchainGroupManager, cb: OnRegisterCallback) {.gcsafe.} =
|
||||
method onWithdraw*(g: OnchainGroupManager, cb: OnWithdrawCallback) {.gcsafe.} =
|
||||
g.withdrawCb = some(cb)
|
||||
|
||||
proc establishConnection(
|
||||
g: OnchainGroupManager
|
||||
): Future[GroupManagerResult[Web3]] {.async.} =
|
||||
var ethRpc: Web3
|
||||
|
||||
g.retryWrapper(ethRpc, "Failed to connect to the Ethereum client"):
|
||||
var innerEthRpc: Web3
|
||||
var connected = false
|
||||
for clientUrl in g.ethClientUrls:
|
||||
## We give a chance to the user to provide multiple clients
|
||||
## and we try to connect to each of them
|
||||
try:
|
||||
innerEthRpc = await newWeb3(clientUrl)
|
||||
connected = true
|
||||
break
|
||||
except CatchableError:
|
||||
error "failed connect Eth client", error = getCurrentExceptionMsg()
|
||||
|
||||
if not connected:
|
||||
raise newException(CatchableError, "all failed")
|
||||
|
||||
innerEthRpc
|
||||
|
||||
return ok(ethRpc)
|
||||
|
||||
method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} =
|
||||
# check if the Ethereum client is reachable
|
||||
var ethRpc: Web3
|
||||
g.retryWrapper(ethRpc, "Failed to connect to the Ethereum client"):
|
||||
await newWeb3(g.ethClientUrl)
|
||||
let ethRpc: Web3 = (await establishConnection(g)).valueOr:
|
||||
return err("failed to connect to Ethereum clients: " & $error)
|
||||
|
||||
var fetchedChainId: uint
|
||||
g.retryWrapper(fetchedChainId, "Failed to get the chain id"):
|
||||
@ -544,9 +568,11 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.}
|
||||
|
||||
proc onDisconnect() {.async.} =
|
||||
error "Ethereum client disconnected"
|
||||
var newEthRpc: Web3
|
||||
g.retryWrapper(newEthRpc, "Failed to reconnect with the Ethereum client"):
|
||||
await newWeb3(g.ethClientUrl)
|
||||
|
||||
var newEthRpc: Web3 = (await g.establishConnection()).valueOr:
|
||||
g.onFatalErrorAction("failed to connect to Ethereum clients onDisconnect")
|
||||
return
|
||||
|
||||
newEthRpc.ondisconnect = ethRpc.ondisconnect
|
||||
g.ethRpc = some(newEthRpc)
|
||||
|
||||
|
||||
@ -43,7 +43,7 @@ type RlnRelayConf* = object of RootObj
|
||||
dynamic*: bool
|
||||
credIndex*: Option[uint]
|
||||
ethContractAddress*: string
|
||||
ethClientAddress*: string
|
||||
ethClientUrls*: seq[string]
|
||||
chainId*: uint
|
||||
creds*: Option[RlnRelayCreds]
|
||||
treePath*: string
|
||||
@ -455,7 +455,7 @@ proc mount(
|
||||
(none(string), none(string))
|
||||
|
||||
groupManager = OnchainGroupManager(
|
||||
ethClientUrl: string(conf.ethClientAddress),
|
||||
ethClientUrls: conf.ethClientUrls,
|
||||
ethContractAddress: $conf.ethContractAddress,
|
||||
chainId: conf.chainId,
|
||||
rlnInstance: rlnInstance,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user