mirror of https://github.com/waku-org/nwaku.git
Feat (Rln relay): adds utility procs to listen to the registration events emitted by the rln membership contract (#976)
* adds the contract handler file * adds integration test for the group listening * adds groupManagement proc * deletes rln relay contract handler file * brings back all the tests * replaces toUINT256 with getIdCommitment proc * replaces individual futures with an array of futures * adds code documentation * asyncSpawn instead of await * adds untitest for toIDCommitment and toUInt256 * reorganizes the test and add rlnInstance * mounts handleGroupUpdates on the rln peer * asyncSpawn to await * implements toIDCommitment * updates the unittest * improves the code documentation * removes unused tests * removes registration of the dynamic group management handler * adds a comment * adds a comment * adds a TODO * removes getIdCommitment
This commit is contained in:
parent
32d230b474
commit
1ac029025a
|
@ -703,4 +703,22 @@ suite "Waku rln relay":
|
|||
msgValidate2 == MessageValidationResult.Spam
|
||||
msgValidate3 == MessageValidationResult.Valid
|
||||
msgValidate4 == MessageValidationResult.Invalid
|
||||
test "toIDCommitment and toUInt256":
|
||||
# create an instance of rln
|
||||
var rlnInstance = createRLNInstance()
|
||||
check:
|
||||
rlnInstance.isOk == true
|
||||
|
||||
# create a key pair
|
||||
var keypair = rlnInstance.value.membershipKeyGen()
|
||||
check:
|
||||
keypair.isSome()
|
||||
|
||||
# convert the idCommitment to UInt256
|
||||
let idCUInt = keypair.get().idCommitment.toUInt256()
|
||||
# convert the UInt256 back to ICommitment
|
||||
let idCommitment = toIDCommitment(idCUInt)
|
||||
|
||||
# check that the conversion has not distorted the original value
|
||||
check:
|
||||
keypair.get().idCommitment == idCommitment
|
||||
|
|
|
@ -102,7 +102,7 @@ procSuite "Waku-rln-relay":
|
|||
let membershipKeyPair = membershipKeyGen(rlnInstance.value)
|
||||
check:
|
||||
membershipKeyPair.isSome
|
||||
let pk = membershipKeyPair.get().idCommitment.toUInt256()
|
||||
let pk = membershipKeyPair.get().idCommitment.toUInt256()
|
||||
debug "membership commitment key", pk = pk
|
||||
|
||||
# test ------------------------------
|
||||
|
@ -128,6 +128,80 @@ procSuite "Waku-rln-relay":
|
|||
# wait for the event to be received
|
||||
await fut
|
||||
|
||||
# release resources -----------------------
|
||||
await web3.close()
|
||||
asyncTest "dynamic group management":
|
||||
# preparation ------------------------------
|
||||
debug "ethereum client address", ETH_CLIENT
|
||||
let contractAddress = await uploadRLNContract(ETH_CLIENT)
|
||||
# connect to the eth client
|
||||
let web3 = await newWeb3(ETH_CLIENT)
|
||||
debug "web3 connected to", ETH_CLIENT
|
||||
|
||||
# fetch the list of registered accounts
|
||||
let accounts = await web3.provider.eth_accounts()
|
||||
web3.defaultAccount = accounts[1]
|
||||
debug "contract deployer account address ",
|
||||
defaultAccount = web3.defaultAccount
|
||||
|
||||
# prepare a contract sender to interact with it
|
||||
var contractObj = web3.contractSender(MembershipContract,
|
||||
contractAddress) # creates a Sender object with a web3 field and contract address of type Address
|
||||
|
||||
# test ------------------------------
|
||||
# create an RLN instance
|
||||
var rlnInstance = createRLNInstance()
|
||||
check:
|
||||
rlnInstance.isOk == true
|
||||
var rln = rlnInstance.value
|
||||
|
||||
# create rln membership key pair
|
||||
let keyPair = rln.membershipKeyGen()
|
||||
check:
|
||||
keyPair.isSome
|
||||
let pk = keyPair.get().idCommitment.toUInt256()
|
||||
debug "membership commitment key", pk = pk
|
||||
|
||||
# initialize the WakuRLNRelay
|
||||
var rlnPeer = WakuRLNRelay(membershipKeyPair: keyPair.get(),
|
||||
membershipIndex: MembershipIndex(0),
|
||||
ethClientAddress: ETH_CLIENT,
|
||||
ethAccountAddress: accounts[0],
|
||||
membershipContractAddress: contractAddress,
|
||||
rlnInstance: rln)
|
||||
|
||||
# generate another membership key pair
|
||||
let keyPair2 = rln.membershipKeyGen()
|
||||
check:
|
||||
keyPair2.isSome
|
||||
let pk2 = keyPair2.get().idCommitment.toUInt256()
|
||||
debug "membership commitment key", pk2 = pk2
|
||||
|
||||
var events = [newFuture[void](), newFuture[void]()]
|
||||
proc handler(pubkey: Uint256, index: Uint256) =
|
||||
debug "handler is called", pubkey = pubkey, index = index
|
||||
if pubkey == pk:
|
||||
events[0].complete()
|
||||
if pubkey == pk2:
|
||||
events[1].complete()
|
||||
let isSuccessful = rlnPeer.rlnInstance.insertMember(pubkey.toIDCommitment())
|
||||
check:
|
||||
isSuccessful
|
||||
|
||||
# mount the handler for listening to the contract events
|
||||
await rlnPeer.handleGroupUpdates(handler)
|
||||
|
||||
# register a member to the contract
|
||||
let tx = await contractObj.register(pk).send(value = MEMBERSHIP_FEE)
|
||||
debug "a member is registered", tx = tx
|
||||
|
||||
# register another member to the contract
|
||||
let tx2 = await contractObj.register(pk2).send(value = MEMBERSHIP_FEE)
|
||||
debug "a member is registered", tx2 = tx2
|
||||
|
||||
# wait for all the events to be received by the rlnPeer
|
||||
await all(events)
|
||||
|
||||
# release resources -----------------------
|
||||
await web3.close()
|
||||
|
||||
|
@ -215,7 +289,7 @@ procSuite "Waku-rln-relay":
|
|||
web3 = await newWeb3(ETH_CLIENT)
|
||||
accounts = await web3.provider.eth_accounts()
|
||||
# choose one of the existing account for the rln-relay peer
|
||||
ethAccountAddress = accounts[9]
|
||||
ethAccountAddress = accounts[0]
|
||||
await web3.close()
|
||||
|
||||
# create current peer's pk
|
||||
|
@ -267,5 +341,4 @@ procSuite "Waku-rln-relay":
|
|||
check:
|
||||
expectedRoot == calculatedRoot
|
||||
|
||||
await node.stop()
|
||||
|
||||
await node.stop()
|
|
@ -636,9 +636,9 @@ when defined(rln):
|
|||
|
||||
if onchainMode:
|
||||
# register the rln-relay peer to the membership contract
|
||||
let is_successful = await rlnPeer.register()
|
||||
let isSuccessful = await rlnPeer.register()
|
||||
# check whether registration is done
|
||||
doAssert(is_successful)
|
||||
doAssert(isSuccessful)
|
||||
debug "peer is successfully registered into the membership contract"
|
||||
|
||||
# adds a topic validator for the supplied pubsub topic at the relay protocol
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
import
|
||||
std/sequtils, tables, times,
|
||||
chronicles, options, chronos, stint,
|
||||
web3,
|
||||
web3, json,
|
||||
stew/results,
|
||||
stew/[byteutils, arrayops, endians2],
|
||||
rln,
|
||||
|
@ -21,8 +21,12 @@ type SpamHandler* = proc(wakuMessage: WakuMessage): void {.gcsafe, closure,
|
|||
|
||||
# membership contract interface
|
||||
contract(MembershipContract):
|
||||
# TODO define a return type of bool for register method to signify a successful registration
|
||||
proc register(pubkey: Uint256) # external payable
|
||||
proc MemberRegistered(pubkey: Uint256, index: Uint256) {.event.}
|
||||
# TODO the followings are to be supported
|
||||
# proc registerBatch(pubkeys: seq[Uint256]) # external payable
|
||||
# proc withdraw(secret: Uint256, pubkeyIndex: Uint256, receiver: Address)
|
||||
# proc withdrawBatch( secrets: seq[Uint256], pubkeyIndex: seq[Uint256], receiver: seq[Address])
|
||||
|
||||
proc createRLNInstance*(d: int = MERKLE_TREE_DEPTH): RLNResult
|
||||
{.raises: [Defect, IOError].} =
|
||||
|
@ -98,6 +102,10 @@ proc toUInt256*(idCommitment: IDCommitment): UInt256 =
|
|||
let pk = cast[UInt256](idCommitment)
|
||||
return pk
|
||||
|
||||
proc toIDCommitment*(idCommitment: UInt256): IDCommitment =
|
||||
let pk = cast[IDCommitment](idCommitment)
|
||||
return pk
|
||||
|
||||
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
|
||||
|
@ -108,7 +116,7 @@ proc register*(rlnPeer: WakuRLNRelay): Future[bool] {.async.} =
|
|||
web3.privateKey = rlnPeer.ethAccountPrivateKey
|
||||
var sender = web3.contractSender(MembershipContract,
|
||||
rlnPeer.membershipContractAddress) # creates a Sender object with a web3 field and contract address of type Address
|
||||
let pk = toUInt256(rlnPeer.membershipKeyPair.idCommitment)
|
||||
let pk = rlnPeer.membershipKeyPair.idCommitment.toUInt256()
|
||||
discard await sender.register(pk).send(MEMBERSHIP_FEE)
|
||||
debug "pk", pk = pk
|
||||
# TODO check the receipt and then return true/false
|
||||
|
@ -548,3 +556,33 @@ proc addAll*(rlnInstance: RLN[Bn256], list: seq[IDCommitment]): bool =
|
|||
if not member_is_added:
|
||||
return false
|
||||
return true
|
||||
|
||||
# the types of inputs to this handler matches the MemberRegistered event/proc defined in the MembershipContract interface
|
||||
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.} =
|
||||
## 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)
|
||||
# prepare a contract sender to interact with it
|
||||
var contractObj = web3.contractSender(MembershipContract, contractAddress)
|
||||
|
||||
# subscribe to the MemberRegistered events
|
||||
# TODO can do similarly for deletion events, though it is not yet supported
|
||||
discard await contractObj.subscribe(MemberRegistered, %*{"fromBlock": blockNumber, "address": contractAddress}) do(pubkey: Uint256, index: Uint256){.raises: [Defect], gcsafe.}:
|
||||
try:
|
||||
debug "onRegister", pubkey = pubkey, index = index
|
||||
handler(pubkey, index)
|
||||
except Exception as err:
|
||||
doAssert false, err.msg
|
||||
do (err: CatchableError):
|
||||
echo "Error from subscription: ", err.msg
|
||||
|
||||
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)
|
Loading…
Reference in New Issue