mirror of https://github.com/waku-org/nwaku.git
Feat (Rln relay): enabling signed tx (#1023)
This commit is contained in:
parent
993781a137
commit
a40686e26e
|
@ -7,6 +7,7 @@ import
|
|||
testutils/unittests, chronos, chronicles, stint, web3, json,
|
||||
stew/byteutils, stew/shims/net as stewNet,
|
||||
libp2p/crypto/crypto,
|
||||
eth/keys,
|
||||
../../waku/v2/protocol/waku_rln_relay/[waku_rln_relay_utils,
|
||||
waku_rln_relay_types, rln_relay_contract],
|
||||
../../waku/v2/node/wakunode2,
|
||||
|
@ -75,6 +76,31 @@ proc uploadRLNContract*(ethClientAddress: string): Future[Address] {.async.} =
|
|||
|
||||
return contractAddress
|
||||
|
||||
|
||||
proc createEthAccount(): Future[(keys.PrivateKey, Address)] {.async.} =
|
||||
let theRNG = keys.newRng()
|
||||
|
||||
let web3 = await newWeb3(ETH_CLIENT)
|
||||
let accounts = await web3.provider.eth_accounts()
|
||||
let gasPrice = int(await web3.provider.eth_gasPrice())
|
||||
web3.defaultAccount = accounts[0]
|
||||
|
||||
let pk = keys.PrivateKey.random(theRNG[])
|
||||
let acc = Address(toCanonicalAddress(pk.toPublicKey()))
|
||||
|
||||
var tx: EthSend
|
||||
tx.source = accounts[0]
|
||||
tx.value = some(ethToWei(10.u256))
|
||||
tx.to = some(acc)
|
||||
tx.gasPrice = some(gasPrice)
|
||||
|
||||
# Send 10 eth to acc
|
||||
discard await web3.send(tx)
|
||||
var balance = await web3.provider.eth_getBalance(acc, "latest")
|
||||
assert(balance == ethToWei(10.u256))
|
||||
|
||||
return (pk, acc)
|
||||
|
||||
procSuite "Waku-rln-relay":
|
||||
asyncTest "event subscription":
|
||||
# preparation ------------------------------
|
||||
|
@ -259,12 +285,16 @@ procSuite "Waku-rln-relay":
|
|||
check:
|
||||
membershipKeyPair.isSome
|
||||
|
||||
# create an Ethereum private key and the corresponding account
|
||||
let (ethPrivKey, ethacc) = await createEthAccount()
|
||||
|
||||
# test ------------------------------
|
||||
# initialize the WakuRLNRelay
|
||||
var rlnPeer = WakuRLNRelay(membershipKeyPair: membershipKeyPair.get(),
|
||||
membershipIndex: MembershipIndex(0),
|
||||
ethClientAddress: ETH_CLIENT,
|
||||
ethAccountAddress: ethAccountAddress,
|
||||
ethAccountPrivateKey: ethPrivKey,
|
||||
ethAccountAddress: ethacc,
|
||||
membershipContractAddress: contractAddress)
|
||||
|
||||
# register the rln-relay peer to the membership contract
|
||||
|
@ -348,6 +378,8 @@ procSuite "Waku-rln-relay":
|
|||
ethAccountAddress = accounts[0]
|
||||
web3.defaultAccount = accounts[0]
|
||||
|
||||
|
||||
|
||||
# create an rln instance
|
||||
var rlnInstance = createRLNInstance()
|
||||
check:
|
||||
|
@ -389,11 +421,16 @@ procSuite "Waku-rln-relay":
|
|||
let tx2Hash = await contractObj.register(pk2).send(value = MEMBERSHIP_FEE)
|
||||
debug "a member is registered", tx2 = tx2Hash
|
||||
|
||||
# create an Ethereum private key and the corresponding account
|
||||
let (ethPrivKey, ethacc) = await createEthAccount()
|
||||
|
||||
|
||||
# test ------------------------------
|
||||
# start rln-relay
|
||||
node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
|
||||
await node.mountRlnRelayDynamic(ethClientAddr = EthClient,
|
||||
ethAccAddr = ethAccountAddress,
|
||||
ethAccAddr = ethacc,
|
||||
ethAccountPrivKey = ethPrivKey,
|
||||
memContractAddr = contractAddress,
|
||||
memKeyPair = keyPair1,
|
||||
memIndex = some(MembershipIndex(0)),
|
||||
|
@ -439,10 +476,14 @@ procSuite "Waku-rln-relay":
|
|||
node2 = WakuNode.new(nodeKey2, ValidIpAddress.init("0.0.0.0"), Port(60001))
|
||||
await node2.start()
|
||||
|
||||
# create an Ethereum private key and the corresponding account
|
||||
let (ethPrivKey, ethacc) = await createEthAccount()
|
||||
|
||||
# start rln-relay on the first node, leave rln-relay credentials empty
|
||||
node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
|
||||
await node.mountRlnRelayDynamic(ethClientAddr = EthClient,
|
||||
ethAccAddr = ethAccountAddress1,
|
||||
ethAccAddr = ethacc,
|
||||
ethAccountPrivKey = ethPrivKey,
|
||||
memContractAddr = contractAddress,
|
||||
memKeyPair = none(MembershipKeyPair),
|
||||
memIndex = none(MembershipIndex),
|
||||
|
@ -454,7 +495,8 @@ procSuite "Waku-rln-relay":
|
|||
# start rln-relay on the second node, leave rln-relay credentials empty
|
||||
node2.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
|
||||
await node2.mountRlnRelayDynamic(ethClientAddr = EthClient,
|
||||
ethAccAddr = ethAccountAddress2,
|
||||
ethAccAddr = ethacc,
|
||||
ethAccountPrivKey = ethPrivKey,
|
||||
memContractAddr = contractAddress,
|
||||
memKeyPair = none(MembershipKeyPair),
|
||||
memIndex = none(MembershipIndex),
|
||||
|
|
|
@ -145,10 +145,15 @@ type
|
|||
name: "rln-relay-id-commitment" }: string
|
||||
|
||||
rlnRelayEthAccount* {.
|
||||
desc: "Ethereum testnet account address",
|
||||
desc: "Account address for the Ethereum testnet Goerli",
|
||||
defaultValue: ""
|
||||
name: "eth-account-address" }: string
|
||||
|
||||
rlnRelayEthAccountPrivKey* {.
|
||||
desc: "Account private key for the Ethereum testnet Goerli",
|
||||
defaultValue: ""
|
||||
name: "eth-account-privatekey" }: string
|
||||
|
||||
rlnRelayEthClientAddress* {.
|
||||
desc: "Ethereum testnet client address e.g., ws://localhost:8540/",
|
||||
defaultValue: "ws://localhost:8540/"
|
||||
|
|
|
@ -90,8 +90,8 @@ type MessageValidationResult* {.pure.} = enum
|
|||
# inputs of the membership contract constructor
|
||||
# TODO may be able to make these constants private and put them inside the waku_rln_relay_utils
|
||||
const
|
||||
MEMBERSHIP_FEE* = 5.u256
|
||||
# the current implementation of the rln lib only supports a circuit for Merkle tree with depth 32
|
||||
MEMBERSHIP_FEE* = 1000000000000000.u256
|
||||
# the current implementation of the rln lib supports a circuit for Merkle tree with depth 20
|
||||
MERKLE_TREE_DEPTH* = 20
|
||||
# TODO the ETH_CLIENT should be an input to the rln-relay, though hardcoded for now
|
||||
# the current address is the address of ganache-cli when run locally
|
||||
|
|
|
@ -119,11 +119,15 @@ proc toMembershipIndex(v: UInt256): MembershipIndex =
|
|||
let result: MembershipIndex = cast[MembershipIndex](v)
|
||||
return result
|
||||
|
||||
proc register*(idComm: IDCommitment, ethAccountAddress: Address, ethClientAddress: string, membershipContractAddress: Address): Future[Result[MembershipIndex, string]] {.async.} =
|
||||
proc register*(idComm: IDCommitment, ethAccountAddress: Address, ethAccountPrivKey: keys.PrivateKey, ethClientAddress: string, membershipContractAddress: Address): Future[Result[MembershipIndex, string]] {.async.} =
|
||||
# TODO may need to also get eth Account Private Key as PrivateKey
|
||||
## registers the idComm into the membership contract whose address is in rlnPeer.membershipContractAddress
|
||||
let web3 = await newWeb3(ethClientAddress)
|
||||
web3.defaultAccount = ethAccountAddress
|
||||
# set the account private key
|
||||
web3.privateKey = some(ethAccountPrivKey)
|
||||
# set the gas price twice the suggested price in order for the fast mining
|
||||
let gasPrice = int(await web3.provider.eth_gasPrice()) * 2
|
||||
|
||||
# when the private key is set in a web3 instance, the send proc (sender.register(pk).send(MEMBERSHIP_FEE))
|
||||
# does the signing using the provided key
|
||||
|
@ -133,7 +137,7 @@ proc register*(idComm: IDCommitment, ethAccountAddress: Address, ethClientAddres
|
|||
debug "registering an id commitment", idComm=idComm
|
||||
let
|
||||
pk = idComm.toUInt256()
|
||||
txHash = await sender.register(pk).send(MEMBERSHIP_FEE)
|
||||
txHash = await sender.register(pk).send(value = MEMBERSHIP_FEE, gasPrice = gasPrice)
|
||||
tsReceipt = await web3.getMinedTransactionReceipt(txHash)
|
||||
|
||||
# the receipt topic holds the hash of signature of the raised events
|
||||
|
@ -165,7 +169,7 @@ proc register*(rlnPeer: WakuRLNRelay): Future[bool] {.async.} =
|
|||
## registers the public key of the rlnPeer which is rlnPeer.membershipKeyPair.publicKey
|
||||
## into the membership contract whose address is in rlnPeer.membershipContractAddress
|
||||
let pk = rlnPeer.membershipKeyPair.idCommitment
|
||||
discard await register(idComm = pk, ethAccountAddress = rlnPeer.ethAccountAddress, ethClientAddress = rlnPeer.ethClientAddress, membershipContractAddress = rlnPeer.membershipContractAddress )
|
||||
discard await register(idComm = pk, ethAccountAddress = rlnPeer.ethAccountAddress, ethAccountPrivKey = rlnPeer.ethAccountPrivateKey, ethClientAddress = rlnPeer.ethClientAddress, membershipContractAddress = rlnPeer.membershipContractAddress )
|
||||
|
||||
return true
|
||||
|
||||
|
@ -607,16 +611,19 @@ proc addAll*(rlnInstance: RLN[Bn256], list: seq[IDCommitment]): bool =
|
|||
type RegistrationEventHandler = proc(pubkey: Uint256, index: Uint256): void {.gcsafe, closure, raises: [Defect].}
|
||||
|
||||
|
||||
proc subscribeToGroupEvents(ethClientUri: string, contractAddress: Address, blockNumber: string = "0x0", handler: RegistrationEventHandler) {.async, gcsafe.} =
|
||||
proc subscribeToGroupEvents(ethClientUri: string, ethAccountAddress: Address, contractAddress: Address, blockNumber: string = "0x0", handler: RegistrationEventHandler) {.async, gcsafe.} =
|
||||
## connects to the eth client whose URI is supplied as `ethClientUri`
|
||||
## subscribes to the `MemberRegistered` event emitted from the `MembershipContract` which is available on the supplied `contractAddress`
|
||||
## it collects all the events starting from the given `blockNumber`
|
||||
## for every received event, it calls the `handler`
|
||||
|
||||
# connect to the eth client
|
||||
let web3 = await newWeb3(ETH_CLIENT)
|
||||
let web3 = await newWeb3(ethClientUri)
|
||||
# prepare a contract sender to interact with it
|
||||
var contractObj = web3.contractSender(MembershipContract, contractAddress)
|
||||
web3.defaultAccount = ethAccountAddress
|
||||
# set the gas price twice the suggested price in order for the fast mining
|
||||
# let gasPrice = int(await web3.provider.eth_gasPrice()) * 2
|
||||
|
||||
# subscribe to the MemberRegistered events
|
||||
# TODO can do similarly for deletion events, though it is not yet supported
|
||||
|
@ -632,7 +639,7 @@ proc subscribeToGroupEvents(ethClientUri: string, contractAddress: Address, bloc
|
|||
|
||||
proc handleGroupUpdates*(rlnPeer: WakuRLNRelay, handler: RegistrationEventHandler) {.async, gcsafe.} =
|
||||
# mounts the supplied handler for the registration events emitting from the membership contract
|
||||
await subscribeToGroupEvents(ethClientUri = rlnPeer.ethClientAddress, contractAddress = rlnPeer.membershipContractAddress, handler = handler)
|
||||
await subscribeToGroupEvents(ethClientUri = rlnPeer.ethClientAddress, ethAccountAddress = rlnPeer.ethAccountAddress, contractAddress = rlnPeer.membershipContractAddress, handler = handler)
|
||||
|
||||
proc addRLNRelayValidator*(node: WakuNode, pubsubTopic: string, contentTopic: ContentTopic, spamHandler: Option[SpamHandler] = none(SpamHandler)) =
|
||||
## this procedure is a thin wrapper for the pubsub addValidator method
|
||||
|
@ -737,6 +744,7 @@ proc mountRlnRelayStatic*(node: WakuNode,
|
|||
proc mountRlnRelayDynamic*(node: WakuNode,
|
||||
ethClientAddr: string = "",
|
||||
ethAccAddr: web3.Address,
|
||||
ethAccountPrivKey: keys.PrivateKey,
|
||||
memContractAddr: web3.Address,
|
||||
memKeyPair: Option[MembershipKeyPair] = none(MembershipKeyPair),
|
||||
memIndex: Option[MembershipIndex] = none(MembershipIndex),
|
||||
|
@ -770,7 +778,7 @@ proc mountRlnRelayDynamic*(node: WakuNode,
|
|||
doAssert(keyPairOpt.isSome)
|
||||
keyPair = keyPairOpt.get()
|
||||
# register the rln-relay peer to the membership contract
|
||||
let regIndexRes = await register(idComm = keyPair.idCommitment, ethAccountAddress = ethAccAddr, ethClientAddress = ethClientAddr, membershipContractAddress = memContractAddr)
|
||||
let regIndexRes = await register(idComm = keyPair.idCommitment, ethAccountAddress = ethAccAddr, ethAccountPrivKey = ethAccountPrivKey, ethClientAddress = ethClientAddr, membershipContractAddress = memContractAddr)
|
||||
# check whether registration is done
|
||||
doAssert(regIndexRes.isOk())
|
||||
rlnIndex = regIndexRes.value
|
||||
|
@ -785,6 +793,7 @@ proc mountRlnRelayDynamic*(node: WakuNode,
|
|||
membershipContractAddress: memContractAddr,
|
||||
ethClientAddress: ethClientAddr,
|
||||
ethAccountAddress: ethAccAddr,
|
||||
ethAccountPrivateKey: ethAccountPrivKey,
|
||||
rlnInstance: rln,
|
||||
pubsubTopic: pubsubTopic,
|
||||
contentTopic: contentTopic)
|
||||
|
@ -839,6 +848,7 @@ proc mountRlnRelay*(node: WakuNode, conf: WakuNodeConf) {.raises: [Defect, Value
|
|||
# read related inputs to run rln-relay in on-chain mode and do type conversion when needed
|
||||
let
|
||||
ethAccountAddr = web3.fromHex(web3.Address, conf.rlnRelayEthAccount)
|
||||
ethAccountPrivKey = keys.PrivateKey(SkSecretKey.fromHex(conf.rlnRelayEthAccountPrivKey).value)
|
||||
ethClientAddr = conf.rlnRelayEthClientAddress
|
||||
ethMemContractAddress = web3.fromHex(web3.Address, conf.rlnRelayEthMemContractAddress)
|
||||
rlnRelayId = conf.rlnRelayIdKey
|
||||
|
@ -850,9 +860,9 @@ proc mountRlnRelay*(node: WakuNode, conf: WakuNodeConf) {.raises: [Defect, Value
|
|||
let keyPair = @[(rlnRelayId, rlnRelayIdCommitmentKey)]
|
||||
let memKeyPair = keyPair.toMembershipKeyPairs()[0]
|
||||
# mount the rln relay protocol in the on-chain/dynamic mode
|
||||
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, memKeyPair = some(memKeyPair), memIndex = some(rlnRelayIndex), ethAccAddr = ethAccountAddr, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic)
|
||||
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, memKeyPair = some(memKeyPair), memIndex = some(rlnRelayIndex), ethAccAddr = ethAccountAddr, ethAccountPrivKey = ethAccountPrivKey, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic)
|
||||
else:
|
||||
# no rln credential is provided
|
||||
# mount the rln relay protocol in the on-chain/dynamic mode
|
||||
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, ethAccAddr = ethAccountAddr, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic)
|
||||
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, ethAccAddr = ethAccountAddr, ethAccountPrivKey = ethAccountPrivKey, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic)
|
||||
|
||||
|
|
Loading…
Reference in New Issue