deploy: 47a9fcfd77a7c452dfb1d19a708aee5ca64c596f

This commit is contained in:
staheri14 2022-05-10 21:36:32 +00:00
parent 27fa2aebbb
commit 804a182ce7
146 changed files with 963 additions and 570 deletions

View File

@ -27,6 +27,8 @@ import
when defined(rln):
import ./v2/test_waku_rln_relay
when defined(onchain_rln):
import ./v2/test_waku_rln_relay_onchain
# TODO Only enable this once swap module is integrated more nicely as a dependency, i.e. as submodule with CI etc

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,8 @@ import
testutils/unittests, chronos, chronicles, stint, web3,
stew/byteutils, stew/shims/net as stewNet,
libp2p/crypto/crypto,
../../waku/v2/protocol/waku_rln_relay/[rln, waku_rln_relay_utils, waku_rln_relay_types],
../../waku/v2/protocol/waku_rln_relay/[rln, waku_rln_relay_utils,
waku_rln_relay_types],
../../waku/v2/node/wakunode2,
../test_helpers,
./test_utils
@ -14,258 +15,7 @@ import
const RLNRELAY_PUBSUB_TOPIC = "waku/2/rlnrelay/proto"
const RLNRELAY_CONTENT_TOPIC = "waku/2/rlnrelay/proto"
# POSEIDON_HASHER_CODE holds the bytecode of Poseidon hasher solidity smart contract:
# https://github.com/kilic/rlnapp/blob/master/packages/contracts/contracts/crypto/PoseidonHasher.sol
# the solidity contract is compiled separately and the resultant bytecode is copied here
const POSEIDON_HASHER_CODE = readFile("tests/v2/poseidonHasher.txt")
# MEMBERSHIP_CONTRACT_CODE contains the bytecode of the membership solidity smart contract:
# https://github.com/kilic/rlnapp/blob/master/packages/contracts/contracts/RLN.sol
# the solidity contract is compiled separately and the resultant bytecode is copied here
const MEMBERSHIP_CONTRACT_CODE = readFile("tests/v2/membershipContract.txt")
# the membership contract code in solidity
# uint256 public immutable MEMBERSHIP_DEPOSIT;
# uint256 public immutable DEPTH;
# uint256 public immutable SET_SIZE;
# uint256 public pubkeyIndex = 0;
# mapping(uint256 => uint256) public members;
# IPoseidonHasher public poseidonHasher;
# event MemberRegistered(uint256 indexed pubkey, uint256 indexed index);
# event MemberWithdrawn(uint256 indexed pubkey, uint256 indexed index);
# constructor(
# uint256 membershipDeposit,
# uint256 depth,
# address _poseidonHasher
# ) public {
# MEMBERSHIP_DEPOSIT = membershipDeposit;
# DEPTH = depth;
# SET_SIZE = 1 << depth;
# poseidonHasher = IPoseidonHasher(_poseidonHasher);
# }
# function register(uint256 pubkey) external payable {
# require(pubkeyIndex < SET_SIZE, "RLN, register: set is full");
# require(msg.value == MEMBERSHIP_DEPOSIT, "RLN, register: membership deposit is not satisfied");
# _register(pubkey);
# }
# function registerBatch(uint256[] calldata pubkeys) external payable {
# require(pubkeyIndex + pubkeys.length <= SET_SIZE, "RLN, registerBatch: set is full");
# require(msg.value == MEMBERSHIP_DEPOSIT * pubkeys.length, "RLN, registerBatch: membership deposit is not satisfied");
# for (uint256 i = 0; i < pubkeys.length; i++) {
# _register(pubkeys[i]);
# }
# }
# function withdrawBatch(
# uint256[] calldata secrets,
# uint256[] calldata pubkeyIndexes,
# address payable[] calldata receivers
# ) external {
# uint256 batchSize = secrets.length;
# require(batchSize != 0, "RLN, withdrawBatch: batch size zero");
# require(batchSize == pubkeyIndexes.length, "RLN, withdrawBatch: batch size mismatch pubkey indexes");
# require(batchSize == receivers.length, "RLN, withdrawBatch: batch size mismatch receivers");
# for (uint256 i = 0; i < batchSize; i++) {
# _withdraw(secrets[i], pubkeyIndexes[i], receivers[i]);
# }
# }
# function withdraw(
# uint256 secret,
# uint256 _pubkeyIndex,
# address payable receiver
# ) external {
# _withdraw(secret, _pubkeyIndex, receiver);
# }
contract(MembershipContract):
proc register(pubkey: Uint256) # external payable
# proc registerBatch(pubkeys: seq[Uint256]) # external payable
# TODO will add withdraw function after integrating the keyGeneration function (required to compute public keys from secret keys)
# proc withdraw(secret: Uint256, pubkeyIndex: Uint256, receiver: Address)
# proc withdrawBatch( secrets: seq[Uint256], pubkeyIndex: seq[Uint256], receiver: seq[Address])
proc uploadContract(ethClientAddress: string): Future[Address] {.async.} =
let web3 = await newWeb3(ethClientAddress)
debug "web3 connected to", ethClientAddress
# fetch the list of registered accounts
let accounts = await web3.provider.eth_accounts()
web3.defaultAccount = accounts[1]
let add =web3.defaultAccount
debug "contract deployer account address ", add
var balance = await web3.provider.eth_getBalance(web3.defaultAccount , "latest")
debug "Initial account balance: ", balance
# deploy the poseidon hash first
let
hasherReceipt = await web3.deployContract(POSEIDON_HASHER_CODE)
hasherAddress = hasherReceipt.contractAddress.get
debug "hasher address: ", hasherAddress
# encode membership contract inputs to 32 bytes zero-padded
let
membershipFeeEncoded = encode(MembershipFee).data
depthEncoded = encode(MERKLE_TREE_DEPTH.u256).data
hasherAddressEncoded = encode(hasherAddress).data
# this is the contract constructor input
contractInput = membershipFeeEncoded & depthEncoded & hasherAddressEncoded
debug "encoded membership fee: ", membershipFeeEncoded
debug "encoded depth: ", depthEncoded
debug "encoded hasher address: ", hasherAddressEncoded
debug "encoded contract input:" , contractInput
# deploy membership contract with its constructor inputs
let receipt = await web3.deployContract(MEMBERSHIP_CONTRACT_CODE, contractInput = contractInput)
var contractAddress = receipt.contractAddress.get
debug "Address of the deployed membership contract: ", contractAddress
# balance = await web3.provider.eth_getBalance(web3.defaultAccount , "latest")
# debug "Account balance after the contract deployment: ", balance
await web3.close()
debug "disconnected from ", ethClientAddress
return contractAddress
procSuite "Waku rln relay":
when defined(onchain_rln):
asyncTest "contract membership":
debug "ethereum client address", ETH_CLIENT
let contractAddress = await uploadContract(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]
let add = web3.defaultAccount
debug "contract deployer account address ", add
# prepare a contract sender to interact with it
var sender = web3.contractSender(MembershipContract, contractAddress) # creates a Sender object with a web3 field and contract address of type Address
# send takes three parameters, c: ContractCallBase, value = 0.u256, gas = 3000000'u64 gasPrice = 0
# should use send proc for the contract functions that update the state of the contract
let tx = await sender.register(20.u256).send(value = MembershipFee)
debug "The hash of registration tx: ", tx # value is the membership fee
# var members: array[2, uint256] = [20.u256, 21.u256]
# debug "This is the batch registration result ", await sender.registerBatch(members).send(value = (members.len * membershipFee)) # value is the membership fee
# balance = await web3.provider.eth_getBalance(web3.defaultAccount , "latest")
# debug "Balance after registration: ", balance
await web3.close()
debug "disconnected from", ETH_CLIENT
asyncTest "registration procedure":
# deploy the contract
let contractAddress = await uploadContract(ETH_CLIENT)
# prepare rln-relay peer inputs
let
web3 = await newWeb3(ETH_CLIENT)
accounts = await web3.provider.eth_accounts()
# choose one of the existing accounts for the rln-relay peer
ethAccountAddress = accounts[9]
await web3.close()
# create an RLN instance
var rlnInstance = createRLNInstance()
check: rlnInstance.isOk == true
# generate the membership keys
let membershipKeyPair = membershipKeyGen(rlnInstance.value)
check: membershipKeyPair.isSome
# initialize the WakuRLNRelay
var rlnPeer = WakuRLNRelay(membershipKeyPair: membershipKeyPair.get(),
membershipIndex: MembershipIndex(0),
ethClientAddress: ETH_CLIENT,
ethAccountAddress: ethAccountAddress,
membershipContractAddress: contractAddress)
# register the rln-relay peer to the membership contract
let is_successful = await rlnPeer.register()
check:
is_successful
asyncTest "mounting waku rln-relay":
let
nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[]
node = WakuNode.new(nodeKey, ValidIpAddress.init("0.0.0.0"),
Port(60000))
await node.start()
# deploy the contract
let membershipContractAddress = await uploadContract(ETH_CLIENT)
# prepare rln-relay inputs
let
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]
await web3.close()
# create current peer's pk
var rlnInstance = createRLNInstance()
check rlnInstance.isOk == true
var rln = rlnInstance.value
# generate a key pair
var keypair = rln.membershipKeyGen()
doAssert(keypair.isSome())
# current peer index in the Merkle tree
let index = uint(5)
# Create a group of 10 members
var group = newSeq[IDCommitment]()
for i in 0..10:
var member_is_added: bool = false
if (uint(i) == index):
# insert the current peer's pk
group.add(keypair.get().idCommitment)
member_is_added = rln.insertMember(keypair.get().idCommitment)
doAssert(member_is_added)
debug "member key", key=keypair.get().idCommitment.toHex
else:
var memberKeypair = rln.membershipKeyGen()
doAssert(memberKeypair.isSome())
group.add(memberKeypair.get().idCommitment)
member_is_added = rln.insertMember(memberKeypair.get().idCommitment)
doAssert(member_is_added)
debug "member key", key=memberKeypair.get().idCommitment.toHex
let expectedRoot = rln.getMerkleRoot().value().toHex
debug "expected root ", expectedRoot
# start rln-relay
node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
await node.mountRlnRelay(ethClientAddrOpt = some(EthClient),
ethAccAddrOpt = some(ethAccountAddress),
memContractAddOpt = some(membershipContractAddress),
groupOpt = some(group),
memKeyPairOpt = some(keypair.get()),
memIndexOpt = some(index),
pubsubTopic = RLNRELAY_PUBSUB_TOPIC,
contentTopic = RLNRELAY_CONTENT_TOPIC)
let calculatedRoot = node.wakuRlnRelay.rlnInstance.getMerkleRoot().value().toHex
debug "calculated root ", calculatedRoot
check expectedRoot == calculatedRoot
await node.stop()
asyncTest "mount waku-rln-relay in the off-chain mode":
let
nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[]
@ -278,7 +28,8 @@ procSuite "Waku rln relay":
# create a group of 100 membership keys
let
(groupKeys, root) = createMembershipList(100)
check groupKeys.len == 100
check:
groupKeys.len == 100
let
# convert the keys to MembershipKeyPair structs
groupKeyPairs = groupKeys.toMembershipKeyPairs()
@ -308,7 +59,8 @@ procSuite "Waku rln relay":
# this part checks whether the Merkle tree is constructed correctly inside the mountRlnRelay proc
# this check is done by comparing the tree root resulted from mountRlnRelay i.e., calculatedRoot
# against the root which is the expected root
check calculatedRoot == root
check:
calculatedRoot == root
await node.stop()
@ -323,7 +75,7 @@ suite "Waku rln relay":
# the file is generated separately and copied here
parameters = readFile("waku/v2/protocol/waku_rln_relay/parameters.key")
pbytes = parameters.toBytes()
len : csize_t = uint(pbytes.len)
len: csize_t = uint(pbytes.len)
parametersBuffer = Buffer(`ptr`: addr(pbytes[0]), len: len)
check:
# check the parameters.key is not empty
@ -331,14 +83,15 @@ suite "Waku rln relay":
var
rlnInstance: RLN[Bn256]
let res = new_circuit_from_params(merkleDepth, addr parametersBuffer, addr rlnInstance)
let res = new_circuit_from_params(merkleDepth, addr parametersBuffer,
addr rlnInstance)
check:
# check whether the circuit parameters are generated successfully
res == true
# keysBufferPtr will hold the generated key pairs i.e., secret and public keys
var
keysBuffer : Buffer
keysBuffer: Buffer
keysBufferPtr = addr(keysBuffer)
done = key_gen(rlnInstance, keysBufferPtr)
check:
@ -359,7 +112,7 @@ suite "Waku rln relay":
rlnInstance.isOk == true
var key = membershipKeyGen(rlnInstance.value)
var empty : array[32,byte]
var empty: array[32, byte]
check:
key.isSome
key.get().idKey.len == 32
@ -377,7 +130,7 @@ suite "Waku rln relay":
# read the Merkle Tree root
var
root1 {.noinit.} : Buffer = Buffer()
root1 {.noinit.}: Buffer = Buffer()
rootPtr1 = addr(root1)
get_root_successful1 = get_root(rlnInstance.value, rootPtr1)
check:
@ -386,21 +139,22 @@ suite "Waku rln relay":
# read the Merkle Tree root
var
root2 {.noinit.} : Buffer = Buffer()
root2 {.noinit.}: Buffer = Buffer()
rootPtr2 = addr(root2)
get_root_successful2 = get_root(rlnInstance.value, rootPtr2)
check:
get_root_successful2
root2.len == 32
var rootValue1 = cast[ptr array[32,byte]] (root1.`ptr`)
var rootValue1 = cast[ptr array[32, byte]] (root1.`ptr`)
let rootHex1 = rootValue1[].toHex
var rootValue2 = cast[ptr array[32,byte]] (root2.`ptr`)
var rootValue2 = cast[ptr array[32, byte]] (root2.`ptr`)
let rootHex2 = rootValue2[].toHex
# the two roots must be identical
check rootHex1 == rootHex2
check:
rootHex1 == rootHex2
test "getMerkleRoot utils":
# create an RLN instance which also includes an empty Merkle tree
var rlnInstance = createRLNInstance()
@ -409,16 +163,19 @@ suite "Waku rln relay":
# read the Merkle Tree root
var root1 = getMerkleRoot(rlnInstance.value())
check root1.isOk
check:
root1.isOk
let rootHex1 = root1.value().toHex
# read the Merkle Tree root
var root2 = getMerkleRoot(rlnInstance.value())
check root2.isOk
check:
root2.isOk
let rootHex2 = root2.value().toHex
# the two roots must be identical
check rootHex1 == rootHex2
check:
rootHex1 == rootHex2
test "update_next_member Nim Wrapper":
# create an RLN instance which also includes an empty Merkle tree
@ -428,7 +185,8 @@ suite "Waku rln relay":
# generate a key pair
var keypair = membershipKeyGen(rlnInstance.value)
check keypair.isSome()
check:
keypair.isSome()
var pkBuffer = toBuffer(keypair.get().idCommitment)
let pkBufferPtr = addr pkBuffer
@ -446,7 +204,8 @@ suite "Waku rln relay":
# delete the first member
var deleted_member_index = MembershipIndex(0)
let deletion_success = delete_member(rlnInstance.value, deleted_member_index)
check deletion_success
check:
deletion_success
test "insertMember rln utils":
# create an RLN instance which also includes an empty Merkle tree
@ -456,7 +215,8 @@ suite "Waku rln relay":
var rln = rlnInstance.value
# generate a key pair
var keypair = rln.membershipKeyGen()
check keypair.isSome()
check:
keypair.isSome()
check:
rln.insertMember(keypair.get().idCommitment)
@ -477,7 +237,7 @@ suite "Waku rln relay":
# read the Merkle Tree root
var
root1 {.noinit.} : Buffer = Buffer()
root1 {.noinit.}: Buffer = Buffer()
rootPtr1 = addr(root1)
get_root_successful1 = get_root(rlnInstance.value, rootPtr1)
check:
@ -492,11 +252,12 @@ suite "Waku rln relay":
# add the member to the tree
var member_is_added = update_next_member(rlnInstance.value, pkBufferPtr)
check member_is_added
check:
member_is_added
# read the Merkle Tree root after insertion
var
root2 {.noinit.} : Buffer = Buffer()
root2 {.noinit.}: Buffer = Buffer()
rootPtr2 = addr(root2)
get_root_successful2 = get_root(rlnInstance.value, rootPtr2)
check:
@ -506,26 +267,27 @@ suite "Waku rln relay":
# delete the first member
var deleted_member_index = MembershipIndex(0)
let deletion_success = delete_member(rlnInstance.value, deleted_member_index)
check deletion_success
check:
deletion_success
# read the Merkle Tree root after the deletion
var
root3 {.noinit.} : Buffer = Buffer()
root3 {.noinit.}: Buffer = Buffer()
rootPtr3 = addr(root3)
get_root_successful3 = get_root(rlnInstance.value, rootPtr3)
check:
get_root_successful3
root3.len == 32
var rootValue1 = cast[ptr array[32,byte]] (root1.`ptr`)
var rootValue1 = cast[ptr array[32, byte]] (root1.`ptr`)
let rootHex1 = rootValue1[].toHex
debug "The initial root", rootHex1
var rootValue2 = cast[ptr array[32,byte]] (root2.`ptr`)
var rootValue2 = cast[ptr array[32, byte]] (root2.`ptr`)
let rootHex2 = rootValue2[].toHex
debug "The root after insertion", rootHex2
var rootValue3 = cast[ptr array[32,byte]] (root3.`ptr`)
var rootValue3 = cast[ptr array[32, byte]] (root3.`ptr`)
let rootHex3 = rootValue3[].toHex
debug "The root after deletion", rootHex3
@ -534,7 +296,8 @@ suite "Waku rln relay":
## The initial root of the tree (empty tree) must be identical to
## the root of the tree after one insertion followed by a deletion
check rootHex1 == rootHex3
check:
rootHex1 == rootHex3
test "Merkle tree consistency check between deletion and insertion using rln utils":
# create an RLN instance
var rlnInstance = createRLNInstance()
@ -544,29 +307,35 @@ suite "Waku rln relay":
# read the Merkle Tree root
var root1 = rln.getMerkleRoot()
check root1.isOk
check:
root1.isOk
let rootHex1 = root1.value().toHex()
# generate a key pair
var keypair = rln.membershipKeyGen()
check keypair.isSome()
check:
keypair.isSome()
let member_inserted = rln.insertMember(keypair.get().idCommitment)
check member_inserted
check:
member_inserted
# read the Merkle Tree root after insertion
var root2 = rln.getMerkleRoot()
check root2.isOk
check:
root2.isOk
let rootHex2 = root2.value().toHex()
# delete the first member
var deleted_member_index = MembershipIndex(0)
let deletion_success = rln.removeMember(deleted_member_index)
check deletion_success
check:
deletion_success
# read the Merkle Tree root after the deletion
var root3 = rln.getMerkleRoot()
check root3.isOk
check:
root3.isOk
let rootHex3 = root3.value().toHex()
@ -575,11 +344,13 @@ suite "Waku rln relay":
debug "The root after deletion", rootHex3
# the root must change after the insertion
check not(rootHex1 == rootHex2)
check:
not(rootHex1 == rootHex2)
## The initial root of the tree (empty tree) must be identical to
## the root of the tree after one insertion followed by a deletion
check rootHex1 == rootHex3
check:
rootHex1 == rootHex3
test "hash Nim Wrappers":
# create an RLN instance
@ -596,14 +367,17 @@ suite "Waku rln relay":
# prepare other inputs to the hash function
var outputBuffer: Buffer
let hashSuccess = hash(rlnInstance.value, addr hashInputBuffer, addr outputBuffer)
check hashSuccess
let outputArr = cast[ptr array[32,byte]](outputBuffer.`ptr`)[]
let hashSuccess = hash(rlnInstance.value, addr hashInputBuffer,
addr outputBuffer)
check:
"efb8ac39dc22eaf377fe85b405b99ba78dbc2f3f32494add4501741df946bd1d" == outputArr.toHex()
hashSuccess
let outputArr = cast[ptr array[32, byte]](outputBuffer.`ptr`)[]
check:
"efb8ac39dc22eaf377fe85b405b99ba78dbc2f3f32494add4501741df946bd1d" ==
outputArr.toHex()
var
hashOutput = cast[ptr array[32,byte]] (outputBuffer.`ptr`)[]
hashOutput = cast[ptr array[32, byte]] (outputBuffer.`ptr`)[]
hashOutputHex = hashOutput.toHex()
debug "hash output", hashOutputHex
@ -620,7 +394,8 @@ suite "Waku rln relay":
let hash = rln.hash(msg)
check:
"efb8ac39dc22eaf377fe85b405b99ba78dbc2f3f32494add4501741df946bd1d" == hash.toHex()
"efb8ac39dc22eaf377fe85b405b99ba78dbc2f3f32494add4501741df946bd1d" ==
hash.toHex()
test "create a list of membership keys and construct a Merkle tree based on the list":
let
@ -663,12 +438,12 @@ suite "Waku rln relay":
shareY: MerkleNode
nullifier: Nullifier
# populate fields with dummy values
for x in proof.mitems : x = 1
for x in merkleRoot.mitems : x = 2
for x in epoch.mitems : x = 3
for x in shareX.mitems : x = 4
for x in shareY.mitems : x = 5
for x in nullifier.mitems : x = 6
for x in proof.mitems: x = 1
for x in merkleRoot.mitems: x = 2
for x in epoch.mitems: x = 3
for x in shareX.mitems: x = 4
for x in shareY.mitems: x = 5
for x in nullifier.mitems: x = 6
let
rateLimitProof = RateLimitProof(proof: proof,
@ -686,7 +461,8 @@ suite "Waku rln relay":
test "test proofVerify and proofGen for a valid proof":
var rlnInstance = createRLNInstance()
check rlnInstance.isOk
check:
rlnInstance.isOk
var rln = rlnInstance.value
let
@ -706,27 +482,30 @@ suite "Waku rln relay":
let memberKeys = rln.membershipKeyGen()
member_is_added = rln.insertMember(memberKeys.get().idCommitment)
# check the member is added
check member_is_added
check:
member_is_added
# prepare the message
let messageBytes = "Hello".toBytes()
# prepare the epoch
var epoch : Epoch
debug "epoch", epochHex=epoch.toHex()
var epoch: Epoch
debug "epoch", epochHex = epoch.toHex()
# generate proof
let proofRes = rln.proofGen(data = messageBytes,
memKeys = memKeys,
memIndex = MembershipIndex(index),
epoch = epoch)
check proofRes.isOk()
check:
proofRes.isOk()
let proof = proofRes.value
# verify the proof
let verified = rln.proofVerify(data = messageBytes,
proof = proof)
check verified == true
check:
verified == true
test "test proofVerify and proofGen for an invalid proof":
var rlnInstance = createRLNInstance()
@ -751,14 +530,15 @@ suite "Waku rln relay":
let memberKeys = rln.membershipKeyGen()
member_is_added = rln.insertMember(memberKeys.get().idCommitment)
# check the member is added
check member_is_added
check:
member_is_added
# prepare the message
let messageBytes = "Hello".toBytes()
# prepare the epoch
var epoch : Epoch
debug "epoch in bytes", epochHex=epoch.toHex()
var epoch: Epoch
debug "epoch in bytes", epochHex = epoch.toHex()
let badIndex = 4
@ -767,21 +547,25 @@ suite "Waku rln relay":
memKeys = memKeys,
memIndex = MembershipIndex(badIndex),
epoch = epoch)
check proofRes.isOk()
check:
proofRes.isOk()
let proof = proofRes.value
# verify the proof (should not be verified)
let verified = rln.proofVerify(data = messageBytes,
proof = proof)
check verified == false
check:
verified == false
test "toEpoch and fromEpoch consistency check":
# check edge cases
let
time = uint64.high
epoch = time.toEpoch()
decodedTime = epoch.fromEpoch()
check time == decodedTime
debug "encoded and decode time", time=time, epoch=epoch, decodedTime=decodedTime
epoch = uint64.high # rln epoch
epochBytes = epoch.toEpoch()
decodedEpoch = epochBytes.fromEpoch()
check:
epoch == decodedEpoch
debug "encoded and decode time", epoch = epoch, epochBytes = epochBytes,
decodedEpoch = decodedEpoch
test "Epoch comparison":
# check edge cases
@ -790,8 +574,9 @@ suite "Waku rln relay":
time2 = uint64.high - 1
epoch1 = time1.toEpoch()
epoch2 = time2.toEpoch()
check compare(epoch1, epoch2) == int64(1)
check compare(epoch2, epoch1) == int64(-1)
check:
diff(epoch1, epoch2) == int64(1)
diff(epoch2, epoch1) == int64(-1)
test "updateLog and hasDuplicate tests":
let
@ -817,9 +602,12 @@ suite "Waku rln relay":
let shareY3 = shareX3
let
wm1 = WakuMessage(proof: RateLimitProof(epoch: epoch, nullifier: nullifier1, shareX: shareX1, shareY: shareY1))
wm2 = WakuMessage(proof: RateLimitProof(epoch: epoch, nullifier: nullifier2, shareX: shareX2, shareY: shareY2))
wm3 = WakuMessage(proof: RateLimitProof(epoch: epoch, nullifier: nullifier3, shareX: shareX3, shareY: shareY3))
wm1 = WakuMessage(proof: RateLimitProof(epoch: epoch,
nullifier: nullifier1, shareX: shareX1, shareY: shareY1))
wm2 = WakuMessage(proof: RateLimitProof(epoch: epoch,
nullifier: nullifier2, shareX: shareX2, shareY: shareY2))
wm3 = WakuMessage(proof: RateLimitProof(epoch: epoch,
nullifier: nullifier3, shareX: shareX3, shareY: shareY3))
# check whether hasDuplicate correctly finds records with the same nullifiers but different secret shares
# no duplicate for wm1 should be found, since the log is empty
@ -874,7 +662,8 @@ suite "Waku rln relay":
discard rln.addAll(groupIDCommitments)
let
wakuRlnRelay = WakuRLNRelay(membershipIndex: index, membershipKeyPair: groupKeyPairs[index], rlnInstance: rln)
wakuRlnRelay = WakuRLNRelay(membershipIndex: index,
membershipKeyPair: groupKeyPairs[index], rlnInstance: rln)
# get the current epoch time
let time = epochTime()

View File

@ -0,0 +1,271 @@
# contains rln-relay tests that require interaction with Ganache i.e., onchain tests
{.used.}
import
std/options, sequtils, times,
testutils/unittests, chronos, chronicles, stint, web3, json,
stew/byteutils, stew/shims/net as stewNet,
libp2p/crypto/crypto,
../../waku/v2/protocol/waku_rln_relay/[rln, waku_rln_relay_utils,
waku_rln_relay_types, rln_relay_contract],
../../waku/v2/node/wakunode2,
../test_helpers,
./test_utils
const RLNRELAY_PUBSUB_TOPIC = "waku/2/rlnrelay/proto"
const RLNRELAY_CONTENT_TOPIC = "waku/2/rlnrelay/proto"
# contract ABI
contract(MembershipContract):
proc register(pubkey: Uint256) # external payable
proc MemberRegistered(pubkey: Uint256, index: Uint256) {.event.}
# 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])
# a util function used for testing purposes
# it deploys membership contract on Ganache (or any Eth client available on ETH_CLIENT address)
# must be edited if used for a different contract than membership contract
proc uploadRLNContract*(ethClientAddress: string): Future[Address] {.async.} =
let web3 = await newWeb3(ethClientAddress)
debug "web3 connected to", ethClientAddress
# fetch the list of registered accounts
let accounts = await web3.provider.eth_accounts()
web3.defaultAccount = accounts[1]
let add = web3.defaultAccount
debug "contract deployer account address ", add
var balance = await web3.provider.eth_getBalance(web3.defaultAccount, "latest")
debug "Initial account balance: ", balance
# deploy the poseidon hash contract and gets its address
let
hasherReceipt = await web3.deployContract(POSEIDON_HASHER_CODE)
hasherAddress = hasherReceipt.contractAddress.get
debug "hasher address: ", hasherAddress
# encode membership contract inputs to 32 bytes zero-padded
let
membershipFeeEncoded = encode(MEMBERSHIP_FEE).data
depthEncoded = encode(MERKLE_TREE_DEPTH.u256).data
hasherAddressEncoded = encode(hasherAddress).data
# this is the contract constructor input
contractInput = membershipFeeEncoded & depthEncoded & hasherAddressEncoded
debug "encoded membership fee: ", membershipFeeEncoded
debug "encoded depth: ", depthEncoded
debug "encoded hasher address: ", hasherAddressEncoded
debug "encoded contract input:", contractInput
# deploy membership contract with its constructor inputs
let receipt = await web3.deployContract(MEMBERSHIP_CONTRACT_CODE,
contractInput = contractInput)
var contractAddress = receipt.contractAddress.get
debug "Address of the deployed membership contract: ", contractAddress
balance = await web3.provider.eth_getBalance(web3.defaultAccount, "latest")
debug "Account balance after the contract deployment: ", balance
await web3.close()
debug "disconnected from ", ethClientAddress
return contractAddress
procSuite "Waku-rln-relay":
asyncTest "event subscription":
# 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
# create an RLN instance
var rlnInstance = createRLNInstance()
check:
rlnInstance.isOk == true
# generate the membership keys
let membershipKeyPair = membershipKeyGen(rlnInstance.value)
check:
membershipKeyPair.isSome
let pk = membershipKeyPair.get().idCommitment.toUInt256()
debug "membership commitment key", pk = pk
# test ------------------------------
var fut = newFuture[void]()
let s = await contractObj.subscribe(MemberRegistered, %*{"fromBlock": "0x0",
"address": contractAddress}) do(
pubkey: Uint256, index: Uint256){.raises: [Defect], gcsafe.}:
try:
debug "onRegister", pubkey = pubkey, index = index
check:
pubkey == pk
fut.complete()
except Exception as err:
# chronos still raises exceptions which inherit directly from Exception
doAssert false, err.msg
do (err: CatchableError):
echo "Error from subscription: ", err.msg
# register a member
let tx = await contractObj.register(pk).send(value = MEMBERSHIP_FEE)
debug "a member is registered", tx = tx
# wait for the event to be received
await fut
# release resources -----------------------
await web3.close()
asyncTest "insert a key to the membership contract":
# 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]
let add = web3.defaultAccount
debug "contract deployer account address ", add
# prepare a contract sender to interact with it
var sender = web3.contractSender(MembershipContract,
contractAddress) # creates a Sender object with a web3 field and contract address of type Address
# send takes the following parameters, c: ContractCallBase, value = 0.u256, gas = 3000000'u64 gasPrice = 0
# should use send proc for the contract functions that update the state of the contract
let tx = await sender.register(20.u256).send(value = MEMBERSHIP_FEE) # value is the membership fee
debug "The hash of registration tx: ", tx
# var members: array[2, uint256] = [20.u256, 21.u256]
# debug "This is the batch registration result ", await sender.registerBatch(members).send(value = (members.len * MEMBERSHIP_FEE)) # value is the membership fee
let balance = await web3.provider.eth_getBalance(web3.defaultAccount, "latest")
debug "Balance after registration: ", balance
await web3.close()
debug "disconnected from", ETH_CLIENT
asyncTest "registration procedure":
# preparation ------------------------------
# deploy the contract
let contractAddress = await uploadRLNContract(ETH_CLIENT)
# prepare rln-relay peer inputs
let
web3 = await newWeb3(ETH_CLIENT)
accounts = await web3.provider.eth_accounts()
# choose one of the existing accounts for the rln-relay peer
ethAccountAddress = accounts[0]
await web3.close()
# create an RLN instance
var rlnInstance = createRLNInstance()
check:
rlnInstance.isOk == true
# generate the membership keys
let membershipKeyPair = membershipKeyGen(rlnInstance.value)
check:
membershipKeyPair.isSome
# test ------------------------------
# initialize the WakuRLNRelay
var rlnPeer = WakuRLNRelay(membershipKeyPair: membershipKeyPair.get(),
membershipIndex: MembershipIndex(0),
ethClientAddress: ETH_CLIENT,
ethAccountAddress: ethAccountAddress,
membershipContractAddress: contractAddress)
# register the rln-relay peer to the membership contract
let is_successful = await rlnPeer.register()
check:
is_successful
asyncTest "mounting waku rln-relay":
# preparation ------------------------------
let
nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[]
node = WakuNode.new(nodeKey, ValidIpAddress.init("0.0.0.0"),
Port(60000))
await node.start()
# deploy the contract
let membershipContractAddress = await uploadRLNContract(ETH_CLIENT)
# prepare rln-relay inputs
let
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]
await web3.close()
# create current peer's pk
var rlnInstance = createRLNInstance()
check:
rlnInstance.isOk == true
var rln = rlnInstance.value
# generate a key pair
var keypair = rln.membershipKeyGen()
doAssert(keypair.isSome())
# current peer index in the Merkle tree
let index = uint(5)
# Create a group of 10 members
var group = newSeq[IDCommitment]()
for i in 0..10:
var member_is_added: bool = false
if (uint(i) == index):
# insert the current peer's pk
group.add(keypair.get().idCommitment)
member_is_added = rln.insertMember(keypair.get().idCommitment)
doAssert(member_is_added)
debug "member key", key = keypair.get().idCommitment.toHex
else:
var memberKeypair = rln.membershipKeyGen()
doAssert(memberKeypair.isSome())
group.add(memberKeypair.get().idCommitment)
member_is_added = rln.insertMember(memberKeypair.get().idCommitment)
doAssert(member_is_added)
debug "member key", key = memberKeypair.get().idCommitment.toHex
let expectedRoot = rln.getMerkleRoot().value().toHex
debug "expected root ", expectedRoot
# test ------------------------------
# start rln-relay
node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
await node.mountRlnRelay(ethClientAddrOpt = some(EthClient),
ethAccAddrOpt = some(ethAccountAddress),
memContractAddOpt = some(membershipContractAddress),
groupOpt = some(group),
memKeyPairOpt = some(keypair.get()),
memIndexOpt = some(index),
pubsubTopic = RLNRELAY_PUBSUB_TOPIC,
contentTopic = RLNRELAY_CONTENT_TOPIC)
let calculatedRoot = node.wakuRlnRelay.rlnInstance.getMerkleRoot().value().toHex
debug "calculated root ", calculatedRoot
check:
expectedRoot == calculatedRoot
await node.stop()

View File

@ -2,7 +2,7 @@
# libtool - Provide generalized library-building support services.
# Generated automatically by config.status (libbacktrace) version-unused
# Libtool was configured on host fv-az275-407:
# Libtool was configured on host fv-az193-59:
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
#
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,

Some files were not shown because too many files have changed in this diff Show More