Feat (Rln relay): enabling signed tx (#1023)

This commit is contained in:
Sanaz Taheri Boshrooyeh 2022-06-30 18:05:38 -07:00 committed by GitHub
parent 993781a137
commit a40686e26e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 16 deletions

View File

@ -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
@ -347,6 +377,8 @@ procSuite "Waku-rln-relay":
# choose one of the existing accounts for the rln-relay peer
ethAccountAddress = accounts[0]
web3.defaultAccount = accounts[0]
# create an rln instance
var rlnInstance = createRLNInstance()
@ -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),

View File

@ -145,9 +145,14 @@ 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/",

View File

@ -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

View File

@ -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)