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
|
msgValidate2 == MessageValidationResult.Spam
|
||||||
msgValidate3 == MessageValidationResult.Valid
|
msgValidate3 == MessageValidationResult.Valid
|
||||||
msgValidate4 == MessageValidationResult.Invalid
|
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
|
||||||
|
|
|
@ -128,6 +128,80 @@ procSuite "Waku-rln-relay":
|
||||||
# wait for the event to be received
|
# wait for the event to be received
|
||||||
await fut
|
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 -----------------------
|
# release resources -----------------------
|
||||||
await web3.close()
|
await web3.close()
|
||||||
|
|
||||||
|
@ -215,7 +289,7 @@ procSuite "Waku-rln-relay":
|
||||||
web3 = await newWeb3(ETH_CLIENT)
|
web3 = await newWeb3(ETH_CLIENT)
|
||||||
accounts = await web3.provider.eth_accounts()
|
accounts = await web3.provider.eth_accounts()
|
||||||
# choose one of the existing account for the rln-relay peer
|
# choose one of the existing account for the rln-relay peer
|
||||||
ethAccountAddress = accounts[9]
|
ethAccountAddress = accounts[0]
|
||||||
await web3.close()
|
await web3.close()
|
||||||
|
|
||||||
# create current peer's pk
|
# create current peer's pk
|
||||||
|
@ -268,4 +342,3 @@ procSuite "Waku-rln-relay":
|
||||||
expectedRoot == calculatedRoot
|
expectedRoot == calculatedRoot
|
||||||
|
|
||||||
await node.stop()
|
await node.stop()
|
||||||
|
|
||||||
|
|
|
@ -636,9 +636,9 @@ when defined(rln):
|
||||||
|
|
||||||
if onchainMode:
|
if onchainMode:
|
||||||
# register the rln-relay peer to the membership contract
|
# 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
|
# check whether registration is done
|
||||||
doAssert(is_successful)
|
doAssert(isSuccessful)
|
||||||
debug "peer is successfully registered into the membership contract"
|
debug "peer is successfully registered into the membership contract"
|
||||||
|
|
||||||
# adds a topic validator for the supplied pubsub topic at the relay protocol
|
# adds a topic validator for the supplied pubsub topic at the relay protocol
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
import
|
import
|
||||||
std/sequtils, tables, times,
|
std/sequtils, tables, times,
|
||||||
chronicles, options, chronos, stint,
|
chronicles, options, chronos, stint,
|
||||||
web3,
|
web3, json,
|
||||||
stew/results,
|
stew/results,
|
||||||
stew/[byteutils, arrayops, endians2],
|
stew/[byteutils, arrayops, endians2],
|
||||||
rln,
|
rln,
|
||||||
|
@ -21,8 +21,12 @@ type SpamHandler* = proc(wakuMessage: WakuMessage): void {.gcsafe, closure,
|
||||||
|
|
||||||
# membership contract interface
|
# membership contract interface
|
||||||
contract(MembershipContract):
|
contract(MembershipContract):
|
||||||
# TODO define a return type of bool for register method to signify a successful registration
|
|
||||||
proc register(pubkey: Uint256) # external payable
|
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
|
proc createRLNInstance*(d: int = MERKLE_TREE_DEPTH): RLNResult
|
||||||
{.raises: [Defect, IOError].} =
|
{.raises: [Defect, IOError].} =
|
||||||
|
@ -98,6 +102,10 @@ proc toUInt256*(idCommitment: IDCommitment): UInt256 =
|
||||||
let pk = cast[UInt256](idCommitment)
|
let pk = cast[UInt256](idCommitment)
|
||||||
return pk
|
return pk
|
||||||
|
|
||||||
|
proc toIDCommitment*(idCommitment: UInt256): IDCommitment =
|
||||||
|
let pk = cast[IDCommitment](idCommitment)
|
||||||
|
return pk
|
||||||
|
|
||||||
proc register*(rlnPeer: WakuRLNRelay): Future[bool] {.async.} =
|
proc register*(rlnPeer: WakuRLNRelay): Future[bool] {.async.} =
|
||||||
## registers the public key of the rlnPeer which is rlnPeer.membershipKeyPair.publicKey
|
## registers the public key of the rlnPeer which is rlnPeer.membershipKeyPair.publicKey
|
||||||
## into the membership contract whose address is in rlnPeer.membershipContractAddress
|
## 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
|
web3.privateKey = rlnPeer.ethAccountPrivateKey
|
||||||
var sender = web3.contractSender(MembershipContract,
|
var sender = web3.contractSender(MembershipContract,
|
||||||
rlnPeer.membershipContractAddress) # creates a Sender object with a web3 field and contract address of type Address
|
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)
|
discard await sender.register(pk).send(MEMBERSHIP_FEE)
|
||||||
debug "pk", pk = pk
|
debug "pk", pk = pk
|
||||||
# TODO check the receipt and then return true/false
|
# 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:
|
if not member_is_added:
|
||||||
return false
|
return false
|
||||||
return true
|
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