diff --git a/apps/chat2/chat2.nim b/apps/chat2/chat2.nim index 4b0d8ff1a..fc4e27ca1 100644 --- a/apps/chat2/chat2.nim +++ b/apps/chat2/chat2.nim @@ -541,8 +541,8 @@ proc processInput(rfd: AsyncFD) {.async.} = echo "You are registered to the rln membership contract, find details of your registration transaction in https://goerli.etherscan.io/tx/0x", txHash echo "rln-relay preparation is in progress..." - let res = node.mountRlnRelay(conf = conf, spamHandler = some(spamHandler), registrationHandler = some(registrationHandler)) - if res.isErr: + let res = await node.mountRlnRelay(conf = conf, spamHandler = some(spamHandler), registrationHandler = some(registrationHandler)) + if res.isErr(): echo "failed to mount rln-relay: " & res.error() else: echo "your membership index is: ", node.wakuRlnRelay.membershipIndex diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index 239e7ff04..225cc9b50 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -363,7 +363,7 @@ proc setupProtocols(node: WakuNode, conf: WakuNodeConf, when defined(rln) or defined(rlnzerokit): if conf.rlnRelay: try: - let res = node.mountRlnRelay(conf) + let res = await node.mountRlnRelay(conf) if res.isErr(): return err("failed to mount waku RLN relay protocol: " & res.error) except: diff --git a/tests/v2/test_waku_rln_relay.nim b/tests/v2/test_waku_rln_relay.nim index 054026b6a..5edb536da 100644 --- a/tests/v2/test_waku_rln_relay.nim +++ b/tests/v2/test_waku_rln_relay.nim @@ -30,13 +30,21 @@ procSuite "Waku rln relay": # preparing inputs to mount rln-relay # create a group of 100 membership keys - let - (groupKeys, root) = createMembershipList(100) + let memListRes = createMembershipList(100) + require: + memListRes.isOk() + + let (groupKeys, root) = memListRes.get() check: - groupKeys.len == 100 + groupKeys.len == 100 let # convert the keys to MembershipKeyPair structs - groupKeyPairs = groupKeys.toMembershipKeyPairs() + groupKeyPairsRes = groupKeys.toMembershipKeyPairs() + require: + groupKeyPairsRes.isOk() + + let + groupKeyPairs = groupKeyPairsRes.get() # extract the id commitments groupIDCommitments = groupKeyPairs.mapIt(it.idCommitment) debug "groupKeyPairs", groupKeyPairs @@ -49,11 +57,13 @@ procSuite "Waku rln relay": # -------- mount rln-relay in the off-chain mode await node.mountRelay(@[RlnRelayPubsubTopic]) - node.mountRlnRelayStatic(group = groupIDCommitments, + let mountRes = node.mountRlnRelayStatic(group = groupIDCommitments, memKeyPair = groupKeyPairs[index], memIndex = index, pubsubTopic = RlnRelayPubsubTopic, contentTopic = RlnRelayContentTopic) + require: + mountRes.isOk() # get the root of Merkle tree which is constructed inside the mountRlnRelay proc let calculatedRoot = node.wakuRlnRelay.rlnInstance.getMerkleRoot().value().inHex @@ -115,15 +125,15 @@ suite "Waku rln relay": var merkleDepth: csize_t = 20 - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() # keysBufferPtr will hold the generated key pairs i.e., secret and public keys var keysBuffer: Buffer keysBufferPtr = addr(keysBuffer) - done = key_gen(rlnInstance.value(), keysBufferPtr) + done = key_gen(rlnInstance.get(), keysBufferPtr) check: # check whether the keys are generated successfully done == true @@ -135,45 +145,48 @@ suite "Waku rln relay": generatedKeys.len == 64 debug "generated keys: ", generatedKeys - test "membership Key Gen": + test "membership Key Generation": # create an RLN instance - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() - var key = membershipKeyGen(rlnInstance.value) + let keyPairRes = membershipKeyGen(rlnInstance.get()) + require: + keyPairRes.isOk() + + let keyPair = keyPairRes.get() var empty: array[32, byte] check: - key.isSome - key.get().idKey.len == 32 - key.get().idCommitment.len == 32 - key.get().idKey != empty - key.get().idCommitment != empty + keyPair.idKey.len == 32 + keyPair.idCommitment.len == 32 + keyPair.idKey != empty + keyPair.idCommitment != empty - debug "the generated membership key pair: ", key + debug "the generated membership key pair: ", keyPair - test "get_root Nim binding": + test "getRoot Nim binding": # create an RLN instance which also includes an empty Merkle tree - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() # read the Merkle Tree root var root1 {.noinit.}: Buffer = Buffer() rootPtr1 = addr(root1) - get_root_successful1 = get_root(rlnInstance.value, rootPtr1) + getRootSuccessful1 = getRoot(rlnInstance.get(), rootPtr1) check: - get_root_successful1 + getRootSuccessful1 root1.len == 32 # read the Merkle Tree root var root2 {.noinit.}: Buffer = Buffer() rootPtr2 = addr(root2) - get_root_successful2 = get_root(rlnInstance.value, rootPtr2) + getRootSuccessful2 = getRoot(rlnInstance.get(), rootPtr2) check: - get_root_successful2 + getRootSuccessful2 root2.len == 32 var rootValue1 = cast[ptr array[32, byte]] (root1.`ptr`) @@ -187,20 +200,21 @@ suite "Waku rln relay": rootHex1 == rootHex2 test "getMerkleRoot utils": # create an RLN instance which also includes an empty Merkle tree - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() # read the Merkle Tree root - var root1 = getMerkleRoot(rlnInstance.value()) - check: - root1.isOk + var root1 = getMerkleRoot(rln) + require: + root1.isOk() let rootHex1 = root1.value().inHex # read the Merkle Tree root - var root2 = getMerkleRoot(rlnInstance.value()) - check: - root2.isOk + var root2 = getMerkleRoot(rln) + require: + root2.isOk() let rootHex2 = root2.value().inHex # the two roots must be identical @@ -209,163 +223,173 @@ suite "Waku rln relay": test "update_next_member Nim Wrapper": # create an RLN instance which also includes an empty Merkle tree - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true - + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() # generate a key pair - var keypair = membershipKeyGen(rlnInstance.value) - check: - keypair.isSome() - var pkBuffer = toBuffer(keypair.get().idCommitment) + let keyPairRes = membershipKeyGen(rln) + require: + keypairRes.isOk() + + let keyPair = keyPairRes.get() + var pkBuffer = toBuffer(keyPair.idCommitment) let pkBufferPtr = addr pkBuffer # add the member to the tree - var member_is_added = update_next_member(rlnInstance.value, pkBufferPtr) + let memberAdded = updateNextMember(rln, pkBufferPtr) check: - member_is_added == true + memberAdded test "delete_member Nim wrapper": # create an RLN instance which also includes an empty Merkle tree - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() # delete the first member - var deleted_member_index = MembershipIndex(0) - let deletion_success = delete_member(rlnInstance.value, deleted_member_index) + let deletedMemberIndex = MembershipIndex(0) + let deletionSuccess = deleteMember(rlnInstance.get(), deletedMemberIndex) check: - deletion_success + deletionSuccess test "insertMember rln utils": # create an RLN instance which also includes an empty Merkle tree - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() # generate a key pair - var keypair = rln.membershipKeyGen() + let keyPairRes = rln.membershipKeyGen() + require: + keypairRes.isOk() check: - keypair.isSome() - check: - rln.insertMember(keypair.get().idCommitment) + rln.insertMember(keyPairRes.get().idCommitment) test "removeMember rln utils": # create an RLN instance which also includes an empty Merkle tree - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() check: rln.removeMember(MembershipIndex(0)) test "Merkle tree consistency check between deletion and insertion": # create an RLN instance - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + + let rln = rlnInstance.get() # read the Merkle Tree root var root1 {.noinit.}: Buffer = Buffer() rootPtr1 = addr(root1) - get_root_successful1 = get_root(rlnInstance.value, rootPtr1) - check: - get_root_successful1 + getRootSuccessful1 = getRoot(rln, rootPtr1) + require: + getRootSuccessful1 root1.len == 32 # generate a key pair - var keypair = membershipKeyGen(rlnInstance.value) - check: keypair.isSome() - var pkBuffer = toBuffer(keypair.get().idCommitment) + let keyPairRes = membershipKeyGen(rln) + require: + keypairRes.isOk() + + let keyPair = keyPairRes.get() + var pkBuffer = toBuffer(keyPair.idCommitment) let pkBufferPtr = addr pkBuffer # add the member to the tree - var member_is_added = update_next_member(rlnInstance.value, pkBufferPtr) - check: - member_is_added + let memberAdded = updateNextMember(rln, pkBufferPtr) + require: + memberAdded # read the Merkle Tree root after insertion var root2 {.noinit.}: Buffer = Buffer() rootPtr2 = addr(root2) - get_root_successful2 = get_root(rlnInstance.value, rootPtr2) - check: - get_root_successful2 + getRootSuccessful = getRoot(rln, rootPtr2) + require: + getRootSuccessful root2.len == 32 # delete the first member - var deleted_member_index = MembershipIndex(0) - let deletion_success = delete_member(rlnInstance.value, deleted_member_index) - check: - deletion_success + let deletedMemberIndex = MembershipIndex(0) + let deletionSuccess = deleteMember(rln, deletedMemberIndex) + require: + deletionSuccess # read the Merkle Tree root after the deletion var root3 {.noinit.}: Buffer = Buffer() rootPtr3 = addr(root3) - get_root_successful3 = get_root(rlnInstance.value, rootPtr3) - check: - get_root_successful3 + getRootSuccessful3 = getRoot(rln, rootPtr3) + require: + getRootSuccessful3 root3.len == 32 - var rootValue1 = cast[ptr array[32, byte]] (root1.`ptr`) + let rootValue1 = cast[ptr array[32, byte]] (root1.`ptr`) let rootHex1 = rootValue1[].inHex debug "The initial root", rootHex1 - var rootValue2 = cast[ptr array[32, byte]] (root2.`ptr`) + let rootValue2 = cast[ptr array[32, byte]] (root2.`ptr`) let rootHex2 = rootValue2[].inHex debug "The root after insertion", rootHex2 - var rootValue3 = cast[ptr array[32, byte]] (root3.`ptr`) + let rootValue3 = cast[ptr array[32, byte]] (root3.`ptr`) let rootHex3 = rootValue3[].inHex 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 + test "Merkle tree consistency check between deletion and insertion using rln utils": # create an RLN instance - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true - var rln = rlnInstance.value() + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + + let rln = rlnInstance.get() # read the Merkle Tree root - var root1 = rln.getMerkleRoot() - check: - root1.isOk + let root1 = rln.getMerkleRoot() + require: + root1.isOk() let rootHex1 = root1.value().inHex() # generate a key pair - var keypair = rln.membershipKeyGen() - check: - keypair.isSome() - let member_inserted = rln.insertMember(keypair.get().idCommitment) - check: - member_inserted + let keyPairRes = rln.membershipKeyGen() + require: + keyPairRes.isOk() + let memberInserted = rln.insertMember(keypairRes.get().idCommitment) + require: + memberInserted # read the Merkle Tree root after insertion - var root2 = rln.getMerkleRoot() - check: - root2.isOk + let root2 = rln.getMerkleRoot() + require: + root2.isOk() let rootHex2 = root2.value().inHex() # delete the first member - var deleted_member_index = MembershipIndex(0) - let deletion_success = rln.removeMember(deleted_member_index) - check: - deletion_success + let deletedMemberIndex = MembershipIndex(0) + let deletionSuccess = rln.removeMember(deletedMemberIndex) + require: + deletionSuccess # read the Merkle Tree root after the deletion - var root3 = rln.getMerkleRoot() - check: - root3.isOk + let root3 = rln.getMerkleRoot() + require: + root3.isOk() let rootHex3 = root3.value().inHex() @@ -384,9 +408,9 @@ suite "Waku rln relay": test "hash Nim Wrappers": # create an RLN instance - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() # prepare the input var @@ -397,7 +421,7 @@ suite "Waku rln relay": # prepare other inputs to the hash function var outputBuffer: Buffer - let hashSuccess = hash(rlnInstance.value, addr hashInputBuffer, + let hashSuccess = hash(rlnInstance.get(), addr hashInputBuffer, addr outputBuffer) check: hashSuccess @@ -420,10 +444,10 @@ suite "Waku rln relay": test "hash utils": # create an RLN instance - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true - let rln = rlnInstance.value + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() # prepare the input let msg = "Hello".toBytes() @@ -442,7 +466,12 @@ suite "Waku rln relay": test "create a list of membership keys and construct a Merkle tree based on the list": let groupSize = 100 - (list, root) = createMembershipList(groupSize) + memListRes = createMembershipList(groupSize) + + require: + memListRes.isOk() + + let (list, root) = memListRes.get() debug "created membership key list", list debug "the Merkle tree root", root @@ -455,11 +484,20 @@ suite "Waku rln relay": let groupKeys = StaticGroupKeys # create a set of MembershipKeyPair objects from groupKeys - let groupKeyPairs = groupKeys.toMembershipKeyPairs() + let groupKeyPairsRes = groupKeys.toMembershipKeyPairs() + require: + groupKeyPairsRes.isOk() + + let groupKeyPairs = groupKeyPairsRes.get() # extract the id commitments let groupIDCommitments = groupKeyPairs.mapIt(it.idCommitment) # calculate the Merkle tree root out of the extracted id commitments - let root = calcMerkleRoot(groupIDCommitments) + let rootRes = calcMerkleRoot(groupIDCommitments) + + require: + rootRes.isOk() + + let root = rootRes.get() debug "groupKeyPairs", groupKeyPairs debug "groupIDCommitments", groupIDCommitments @@ -538,30 +576,37 @@ suite "Waku rln relay": decodednsp.value == rateLimitProof test "test proofVerify and proofGen for a valid proof": - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() let - # create a membership key pair - memKeys = membershipKeyGen(rln).get() # peer's index in the Merkle Tree index = 5 + # create a membership key pair + memKeysRes = membershipKeyGen(rln) + + require: + memKeysRes.isOk() + + let memKeys = memKeysRes.get() # Create a Merkle tree with random members for i in 0..10: - var member_is_added: bool = false + var memberAdded: bool = false if (i == index): # insert the current peer's pk - member_is_added = rln.insertMember(memKeys.idCommitment) + memberAdded = rln.insertMember(memKeys.idCommitment) else: # create a new key pair - let memberKeys = rln.membershipKeyGen() - member_is_added = rln.insertMember(memberKeys.get().idCommitment) + let memberKeysRes = rln.membershipKeyGen() + require: + memberKeysRes.isOk() + memberAdded = rln.insertMember(memberKeysRes.get().idCommitment) # check the member is added - check: - member_is_added + require: + memberAdded # prepare the message let messageBytes = "Hello".toBytes() @@ -590,30 +635,37 @@ suite "Waku rln relay": verified.value() == true test "test proofVerify and proofGen for an invalid proof": - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() let - # create a membership key pair - memKeys = membershipKeyGen(rln).get() # peer's index in the Merkle Tree index = 5 + # create a membership key pair + memKeysRes = membershipKeyGen(rln) + + require: + memKeysRes.isOk() + + let memKeys = memKeysRes.get() # Create a Merkle tree with random members for i in 0..10: - var member_is_added: bool = false + var memberAdded: bool = false if (i == index): # insert the current peer's pk - member_is_added = rln.insertMember(memKeys.idCommitment) + memberAdded = rln.insertMember(memKeys.idCommitment) else: # create a new key pair - let memberKeys = rln.membershipKeyGen() - member_is_added = rln.insertMember(memberKeys.get().idCommitment) + let memberKeysRes = rln.membershipKeyGen() + require: + memberKeysRes.isOk() + memberAdded = rln.insertMember(memberKeysRes.get().idCommitment) # check the member is added - check: - member_is_added + require: + memberAdded # prepare the message let messageBytes = "Hello".toBytes() @@ -648,18 +700,23 @@ suite "Waku rln relay": # This step consists of creating the rln instance and waku-rln-relay, # Inserting members, and creating a valid proof with the merkle root # create an RLN instance - var rlnInstance = createRLNInstance() + let rlnInstance = createRLNInstance() require: rlnInstance.isOk() - var rln = rlnInstance.value + let rln = rlnInstance.get() let rlnRelay = WakuRLNRelay(rlnInstance:rln) let - # create a membership key pair - memKeys = membershipKeyGen(rlnRelay.rlnInstance).get() # peer's index in the Merkle Tree. index = 5 + # create a membership key pair + memKeysRes = membershipKeyGen(rlnRelay.rlnInstance) + + require: + memKeysRes.isOk() + + let memKeys = memKeysRes.get() let membershipCount = AcceptableRootWindowSize + 5 @@ -671,8 +728,10 @@ suite "Waku rln relay": memberIsAdded = rlnRelay.insertMember(memKeys.idCommitment) else: # create a new key pair - let memberKeys = rlnRelay.rlnInstance.membershipKeyGen() - memberIsAdded = rlnRelay.insertMember(memberKeys.get().idCommitment) + let memberKeysRes = rlnRelay.rlnInstance.membershipKeyGen() + require: + memberKeysRes.isOk() + memberIsAdded = rlnRelay.insertMember(memberKeysRes.get().idCommitment) # require that the member is added require: memberIsAdded.isOk() @@ -733,18 +792,23 @@ suite "Waku rln relay": AcceptableRootWindowSize < 10 # create an RLN instance - var rlnInstance = createRLNInstance() + let rlnInstance = createRLNInstance() require: rlnInstance.isOk() - var rln = rlnInstance.value + let rln = rlnInstance.get() let rlnRelay = WakuRLNRelay(rlnInstance:rln) let - # create a membership key pair - memKeys = membershipKeyGen(rlnRelay.rlnInstance).get() # peer's index in the Merkle Tree. index = 6 + # create a membership key pair + memKeysRes = membershipKeyGen(rlnRelay.rlnInstance) + + require: + memKeysRes.isOk() + + let memKeys = memKeysRes.get() let membershipCount = AcceptableRootWindowSize + 5 @@ -756,8 +820,10 @@ suite "Waku rln relay": memberIsAdded = rlnRelay.insertMember(memKeys.idCommitment) else: # create a new key pair - let memberKeys = rlnRelay.rlnInstance.membershipKeyGen() - memberIsAdded = rlnRelay.insertMember(memberKeys.get().idCommitment) + let memberKeysRes = rlnRelay.rlnInstance.membershipKeyGen() + require: + memberKeysRes.isOk() + memberIsAdded = rlnRelay.insertMember(memberKeysRes.get().idCommitment) # require that the member is added require: memberIsAdded.isOk() @@ -865,8 +931,8 @@ suite "Waku rln relay": # 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 let result1 = wakurlnrelay.hasDuplicate(wm1) - check: - result1.isOk + require: + result1.isOk() # no duplicate is found result1.value == false # add it to the log @@ -874,8 +940,8 @@ suite "Waku rln relay": # # no duplicate for wm2 should be found, its nullifier differs from wm1 let result2 = wakurlnrelay.hasDuplicate(wm2) - check: - result2.isOk + require: + result2.isOk() # no duplicate is found result2.value == false # add it to the log @@ -884,7 +950,7 @@ suite "Waku rln relay": # wm3 has the same nullifier as wm1 but different secret shares, it should be detected as duplicate let result3 = wakurlnrelay.hasDuplicate(wm3) check: - result3.isOk + result3.isOk() # it is a duplicate result3.value == true @@ -892,12 +958,21 @@ suite "Waku rln relay": # setup a wakurlnrelay peer with a static group---------- # create a group of 100 membership keys - let - (groupKeys, root) = createMembershipList(100) + let memListRes = createMembershipList(100) + + require: + memListRes.isOk() + let + (groupKeys, _) = memListRes.get() # convert the keys to MembershipKeyPair structs - groupKeyPairs = groupKeys.toMembershipKeyPairs() - # extract the id commitments - groupIDCommitments = groupKeyPairs.mapIt(it.idCommitment) + groupKeyPairsRes = groupKeys.toMembershipKeyPairs() + + require: + groupKeyPairsRes.isOk() + + let groupKeyPairs = groupKeyPairsRes.get() + # extract the id commitments + let groupIDCommitments = groupKeyPairs.mapIt(it.idCommitment) debug "groupKeyPairs", groupKeyPairs debug "groupIDCommitments", groupIDCommitments @@ -907,9 +982,10 @@ suite "Waku rln relay": let index = MembershipIndex(5) # create an RLN instance - var rlnInstance = createRLNInstance() - doAssert(rlnInstance.isOk) - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() let wakuRlnRelay = WakuRLNRelay(membershipIndex: index, @@ -961,46 +1037,52 @@ suite "Waku rln relay": test "toIDCommitment and toUInt256": # create an instance of rln - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + + let rln = rlnInstance.get() # create a key pair - var keypair = rlnInstance.value.membershipKeyGen() - check: - keypair.isSome() + let keyPairRes = rln.membershipKeyGen() + require: + keyPairRes.isOk() + + let keyPair = keyPairRes.get() # convert the idCommitment to UInt256 - let idCUInt = keypair.get().idCommitment.toUInt256() + let idCUInt = keypair.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 + keypair.idCommitment == idCommitment test "Read/Write RLN credentials": # create an RLN instance - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() - var key = membershipKeyGen(rlnInstance.value) + let keyPairRes = membershipKeyGen(rlnInstance.get()) + require: + keyPairRes.isOk() + + let keyPair = keyPairRes.get() var empty: array[32, byte] check: - key.isSome - key.get().idKey.len == 32 - key.get().idCommitment.len == 32 - key.get().idKey != empty - key.get().idCommitment != empty + keyPair.idKey.len == 32 + keyPair.idCommitment.len == 32 + keyPair.idKey != empty + keyPair.idCommitment != empty - debug "the generated membership key pair: ", key + debug "the generated membership key pair: ", keyPair - let - k = key.get() - index = MembershipIndex(1) + let index = MembershipIndex(1) - var rlnMembershipCredentials = RlnMembershipCredentials(membershipKeyPair: k, rlnIndex: index) + let rlnMembershipCredentials = RlnMembershipCredentials(membershipKeyPair: keyPair, + rlnIndex: index) let password = "%m0um0ucoW%" @@ -1008,7 +1090,7 @@ suite "Waku rln relay": defer: removeFile(filepath) # Write RLN credentials - check: + require: writeRlnCredentials(filepath, rlnMembershipCredentials, password).isOk() let readCredentialsResult = readRlnCredentials(filepath, password) @@ -1019,7 +1101,7 @@ suite "Waku rln relay": check: credentials.isSome() - credentials.get().membershipKeyPair == k + credentials.get().membershipKeyPair == keyPair credentials.get().rlnIndex == index test "histogram static bucket generation": diff --git a/tests/v2/test_waku_rln_relay_onchain.nim b/tests/v2/test_waku_rln_relay_onchain.nim index 022cac09a..8f4cc3334 100644 --- a/tests/v2/test_waku_rln_relay_onchain.nim +++ b/tests/v2/test_waku_rln_relay_onchain.nim @@ -119,18 +119,19 @@ procSuite "Waku-rln-relay": defaultAccount = web3.defaultAccount # prepare a contract sender to interact with it - var contractObj = web3.contractSender(MembershipContract, + let 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 + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() # generate the membership keys - let membershipKeyPair = membershipKeyGen(rlnInstance.value) - check: - membershipKeyPair.isSome - let pk = membershipKeyPair.get().idCommitment.toUInt256() + let membershipKeyPairRes = membershipKeyGen(rlnInstance.get()) + require: + membershipKeyPairRes.isOk() + let membershipKeyPair = membershipKeyPairRes.get() + let pk = membershipKeyPair.idCommitment.toUInt256() debug "membership commitment key", pk = pk # test ------------------------------ @@ -173,24 +174,25 @@ procSuite "Waku-rln-relay": defaultAccount = web3.defaultAccount # prepare a contract sender to interact with it - var contractObj = web3.contractSender(MembershipContract, + let 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 + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() - let keyPair = rln.membershipKeyGen() - check: - keyPair.isSome - let pk = keyPair.get().idCommitment.toUInt256() + let keyPairRes = rln.membershipKeyGen() + require: + keyPairRes.isOk() + let keypair = keyPairRes.get() + let pk = keyPair.idCommitment.toUInt256() debug "membership commitment key", pk = pk # initialize the WakuRLNRelay - var rlnPeer = WakuRLNRelay(membershipKeyPair: keyPair.get(), + let rlnPeer = WakuRLNRelay(membershipKeyPair: keyPair, membershipIndex: MembershipIndex(0), ethClientAddress: EthClient, ethAccountAddress: some(accounts[0]), @@ -198,10 +200,11 @@ procSuite "Waku-rln-relay": rlnInstance: rln) # generate another membership key pair - let keyPair2 = rln.membershipKeyGen() - check: - keyPair2.isSome - let pk2 = keyPair2.get().idCommitment.toUInt256() + let keyPair2Res = rln.membershipKeyGen() + require: + keyPair2Res.isOk() + let keyPair2 = keyPair2Res.get() + let pk2 = keyPair2.idCommitment.toUInt256() debug "membership commitment key", pk2 = pk2 var events = [newFuture[void](), newFuture[void]()] @@ -252,7 +255,7 @@ procSuite "Waku-rln-relay": debug "contract deployer account address ", add # prepare a contract sender to interact with it - var sender = web3.contractSender(MembershipContract, + let 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 @@ -277,27 +280,25 @@ procSuite "Waku-rln-relay": # prepare rln-relay peer inputs let web3 = await newWeb3(EthClient) - 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 + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() # generate the membership keys - let membershipKeyPair = membershipKeyGen(rlnInstance.value) - check: - membershipKeyPair.isSome + let membershipKeyPairRes = membershipKeyGen(rlnInstance.get()) + require: + membershipKeyPairRes.isOk() + let membershipKeyPair = membershipKeyPairRes.get() # create an Ethereum private key and the corresponding account let (ethPrivKey, ethacc) = await createEthAccount() # test ------------------------------ # initialize the WakuRLNRelay - var rlnPeer = WakuRLNRelay(membershipKeyPair: membershipKeyPair.get(), + let rlnPeer = WakuRLNRelay(membershipKeyPair: membershipKeyPair, membershipIndex: MembershipIndex(0), ethClientAddress: EthClient, ethAccountPrivateKey: some(ethPrivKey), @@ -305,9 +306,9 @@ procSuite "Waku-rln-relay": membershipContractAddress: contractAddress) # register the rln-relay peer to the membership contract - let is_successful = await rlnPeer.register() + let isSuccessful = await rlnPeer.register() check: - is_successful.isOk + isSuccessful.isOk() asyncTest "mounting waku rln-relay: check correct Merkle tree construction in the static/off-chain group management": @@ -318,34 +319,39 @@ procSuite "Waku-rln-relay": await node.start() # create current peer's pk - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() # generate a key pair - var keypair = rln.membershipKeyGen() - doAssert(keypair.isSome()) + let keyPairRes = rln.membershipKeyGen() + require: + keyPairRes.isOk() + let keyPair = keyPairRes.get() # 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 + var memberAdded: 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.inHex + group.add(keyPair.idCommitment) + memberAdded = rln.insertMember(keyPair.idCommitment) + doAssert(memberAdded) + debug "member key", key = keyPair.idCommitment.inHex 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.inHex + let memberKeyPairRes = rln.membershipKeyGen() + require: + memberKeyPairRes.isOk() + let memberKeyPair = memberKeyPairRes.get() + group.add(memberKeyPair.idCommitment) + let memberAdded = rln.insertMember(memberKeyPair.idCommitment) + require: + memberAdded + debug "member key", key = memberKeyPair.idCommitment.inHex let expectedRoot = rln.getMerkleRoot().value().inHex debug "expected root ", expectedRoot @@ -353,11 +359,15 @@ procSuite "Waku-rln-relay": # test ------------------------------ # start rln-relay await node.mountRelay(@[RlnRelayPubsubTopic]) - node.mountRlnRelayStatic(group = group, - memKeyPair = keypair.get(), + let mountRes = node.mountRlnRelayStatic(group = group, + memKeyPair = keyPair, memIndex = index, pubsubTopic = RlnRelayPubsubTopic, contentTopic = RlnRelayContentTopic) + + require: + mountRes.isOk() + let calculatedRoot = node.wakuRlnRelay.rlnInstance.getMerkleRoot().value().inHex debug "calculated root ", calculatedRoot @@ -387,36 +397,41 @@ procSuite "Waku-rln-relay": # create an rln instance - var rlnInstance = createRLNInstance() - check: - rlnInstance.isOk == true - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + require: + rlnInstance.isOk() + let rln = rlnInstance.get() # create two rln key pairs let - keyPair1 = rln.membershipKeyGen() - keyPair2 = rln.membershipKeyGen() - check: - keyPair1.isSome - keyPair2.isSome - let - pk1 = keyPair1.get().idCommitment.toUInt256() - pk2 = keyPair2.get().idCommitment.toUInt256() - debug "member key1", key = keyPair1.get().idCommitment.inHex - debug "member key2", key = keyPair2.get().idCommitment.inHex + keyPair1Res = rln.membershipKeyGen() + keyPair2Res = rln.membershipKeyGen() + require: + keyPair1Res.isOk() + keyPair2Res.isOk() + + let + keyPair1 = keyPair1Res.get() + keyPair2 = keyPair2Res.get() + pk1 = keyPair1.idCommitment.toUInt256() + pk2 = keyPair2.idCommitment.toUInt256() + debug "member key1", key = keyPair1.idCommitment.inHex + debug "member key2", key = keyPair2.idCommitment.inHex # add the rln keys to the Merkle tree let - member_is_added1 = rln.insertMember(keyPair1.get().idCommitment) - member_is_added2 = rln.insertMember(keyPair2.get().idCommitment) - doAssert(member_is_added1) - doAssert(member_is_added2) + memberIsAdded1 = rln.insertMember(keyPair1.idCommitment) + memberIsAdded2 = rln.insertMember(keyPair2.idCommitment) + + require: + memberIsAdded1 + memberIsAdded2 # get the Merkle root let expectedRoot = rln.getMerkleRoot().value().inHex # prepare a contract sender to interact with it - var contractObj = web3.contractSender(MembershipContract, + let contractObj = web3.contractSender(MembershipContract, contractAddress) # creates a Sender object with a web3 field and contract address of type Address # register the members to the contract @@ -438,7 +453,7 @@ procSuite "Waku-rln-relay": ethAccountAddress = some(ethacc), ethAccountPrivKeyOpt = some(ethPrivKey), memContractAddr = contractAddress, - memKeyPair = keyPair1, + memKeyPair = some(keyPair1), memIndex = some(MembershipIndex(0)), pubsubTopic = RlnRelayPubsubTopic, contentTopic = RlnRelayContentTopic) diff --git a/tests/v2/test_wakunode_rln_relay.nim b/tests/v2/test_wakunode_rln_relay.nim index 627b9a6a7..a9ecd54f5 100644 --- a/tests/v2/test_wakunode_rln_relay.nim +++ b/tests/v2/test_wakunode_rln_relay.nim @@ -50,35 +50,55 @@ procSuite "WakuNode - RLN relay": # set up three nodes # node1 await node1.mountRelay(@[rlnRelayPubSubTopic]) - let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = rlnRelayStaticSetUp(1) # set up rln relay inputs + let staticSetupRes1 = rlnRelayStaticSetUp(1) # set up rln relay inputs + require: + staticSetupRes1.isOk() + + let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = staticSetupRes1.get() # mount rlnrelay in off-chain mode - node1.mountRlnRelayStatic(group = groupOpt1.get(), + let mountRes1 = node1.mountRlnRelayStatic(group = groupOpt1.get(), memKeyPair = memKeyPairOpt1.get(), memIndex = memIndexOpt1.get(), pubsubTopic = rlnRelayPubSubTopic, contentTopic = contentTopic) + require: + mountRes1.isOk() + await node1.start() # node 2 await node2.mountRelay(@[rlnRelayPubSubTopic]) - let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = rlnRelayStaticSetUp(2) # set up rln relay inputs + let staticSetupRes2 = rlnRelayStaticSetUp(2) # set up rln relay inputs + require: + staticSetupRes2.isOk() + let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = staticSetupRes2.get() # mount rlnrelay in off-chain mode - node2.mountRlnRelayStatic(group = groupOpt2.get(), + let mountRes2 = node2.mountRlnRelayStatic(group = groupOpt2.get(), memKeyPair = memKeyPairOpt2.get(), memIndex = memIndexOpt2.get(), pubsubTopic = rlnRelayPubSubTopic, contentTopic = contentTopic) + require: + mountRes2.isOk() + await node2.start() # node 3 await node3.mountRelay(@[rlnRelayPubSubTopic]) - let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = rlnRelayStaticSetUp(3) # set up rln relay inputs + let staticSetupRes3 = rlnRelayStaticSetUp(3) # set up rln relay inputs + require: + staticSetupRes3.isOk() + + let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = staticSetupRes3.get() # mount rlnrelay in off-chain mode - node3.mountRlnRelayStatic(group = groupOpt3.get(), + let mountRes3 = node3.mountRlnRelayStatic(group = groupOpt3.get(), memKeyPair = memKeyPairOpt3.get(), memIndex = memIndexOpt3.get(), pubsubTopic = rlnRelayPubSubTopic, contentTopic = contentTopic) + require: + mountRes3.isOk() + await node3.start() # connect them together @@ -136,35 +156,53 @@ procSuite "WakuNode - RLN relay": # set up three nodes # node1 await node1.mountRelay(@[rlnRelayPubSubTopic]) - let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = rlnRelayStaticSetUp(1) # set up rln relay inputs + let staticSetupRes1 = rlnRelayStaticSetUp(1) # set up rln relay inputs + require: + staticSetupRes1.isOk() + + let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = staticSetupRes1.get() # mount rlnrelay in off-chain mode - node1.mountRlnRelayStatic(group = groupOpt1.get(), + let mountRes1 = node1.mountRlnRelayStatic(group = groupOpt1.get(), memKeyPair = memKeyPairOpt1.get(), memIndex = memIndexOpt1.get(), pubsubTopic = rlnRelayPubSubTopic, contentTopic = contentTopic) + require: + mountRes1.isOk() await node1.start() # node 2 await node2.mountRelay(@[rlnRelayPubSubTopic]) - let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = rlnRelayStaticSetUp(2) # set up rln relay inputs + let staticSetupRes2 = rlnRelayStaticSetUp(2) # set up rln relay inputs + require: + staticSetupRes2.isOk() + + let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = staticSetupRes2.get() # mount rlnrelay in off-chain mode - node2.mountRlnRelayStatic(group = groupOpt2.get(), + let mountRes2 = node2.mountRlnRelayStatic(group = groupOpt2.get(), memKeyPair = memKeyPairOpt2.get(), memIndex = memIndexOpt2.get(), pubsubTopic = rlnRelayPubSubTopic, contentTopic = contentTopic) + require: + mountRes2.isOk() await node2.start() # node 3 await node3.mountRelay(@[rlnRelayPubSubTopic]) - let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = rlnRelayStaticSetUp(3) # set up rln relay inputs + let staticSetupRes3 = rlnRelayStaticSetUp(3) # set up rln relay inputs + require: + staticSetupRes3.isOk() + + let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = staticSetupRes3.get() # mount rlnrelay in off-chain mode - node3.mountRlnRelayStatic(group = groupOpt3.get(), + let mountRes3 = node3.mountRlnRelayStatic(group = groupOpt3.get(), memKeyPair = memKeyPairOpt3.get(), memIndex= memIndexOpt3.get(), pubsubTopic = rlnRelayPubSubTopic, contentTopic = contentTopic) + require: + mountRes3.isOk() await node3.start() # connect them together @@ -241,35 +279,56 @@ procSuite "WakuNode - RLN relay": # set up three nodes # node1 await node1.mountRelay(@[rlnRelayPubSubTopic]) - let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = rlnRelayStaticSetUp(1) # set up rln relay inputs + let staticSetupRes1 = rlnRelayStaticSetUp(1) # set up rln relay inputs + require: + staticSetupRes1.isOk() + + let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = staticSetupRes1.get() # mount rlnrelay in off-chain mode - node1.mountRlnRelayStatic(group = groupOpt1.get(), + let mountRes1 = node1.mountRlnRelayStatic(group = groupOpt1.get(), memKeyPair = memKeyPairOpt1.get(), memIndex = memIndexOpt1.get(), pubsubTopic = rlnRelayPubSubTopic, contentTopic = contentTopic) + require: + mountRes1.isOk() + await node1.start() # node 2 await node2.mountRelay(@[rlnRelayPubSubTopic]) - let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = rlnRelayStaticSetUp(2) # set up rln relay inputs + let staticSetupRes2 = rlnRelayStaticSetUp(2) # set up rln relay inputs + require: + staticSetupRes2.isOk() + + let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = staticSetupRes2.get() # mount rlnrelay in off-chain mode - node2.mountRlnRelayStatic(group = groupOpt2.get(), + let mountRes2 = node2.mountRlnRelayStatic(group = groupOpt2.get(), memKeyPair = memKeyPairOpt2.get(), memIndex = memIndexOpt2.get(), pubsubTopic = rlnRelayPubSubTopic, contentTopic = contentTopic) + require: + mountRes2.isOk() + await node2.start() # node 3 await node3.mountRelay(@[rlnRelayPubSubTopic]) - let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = rlnRelayStaticSetUp(3) # set up rln relay inputs + let staticSetupRes3 = rlnRelayStaticSetUp(3) # set up rln relay inputs + require: + staticSetupRes3.isOk() + + let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = staticSetupRes3.get() # mount rlnrelay in off-chain mode - node3.mountRlnRelayStatic(group = groupOpt3.get(), + let mountRes3 = node3.mountRlnRelayStatic(group = groupOpt3.get(), memKeyPair = memKeyPairOpt3.get(), memIndex = memIndexOpt3.get(), pubsubTopic = rlnRelayPubSubTopic, contentTopic = contentTopic) + require: + mountRes3.isOk() + await node3.start() # connect the nodes together node1 <-> node2 <-> node3 diff --git a/waku/v2/protocol/waku_rln_relay/waku_rln_relay_types.nim b/waku/v2/protocol/waku_rln_relay/waku_rln_relay_types.nim index 4713d439a..1dc3f3da4 100644 --- a/waku/v2/protocol/waku_rln_relay/waku_rln_relay_types.nim +++ b/waku/v2/protocol/waku_rln_relay/waku_rln_relay_types.nim @@ -10,19 +10,19 @@ import waku_rln_relay_constants, ../../utils/protobuf +type RlnRelayResult*[T] = Result[T, string] + when defined(rln) or (not defined(rln) and not defined(rlnzerokit)): ## Bn256 and RLN are Nim wrappers for the data types used in ## the rln library https://github.com/kilic/rln/blob/3bbec368a4adc68cd5f9bfae80b17e1bbb4ef373/src/ffi.rs type Bn256* = pointer type RLN*[E] = pointer - type RLNResult* = Result[RLN[Bn256], string] + type RLNResult* = RlnRelayResult[RLN[Bn256]] when defined(rlnzerokit): ## RLN is a Nim wrapper for the data types used in zerokit RLN type RLN* {.incompleteStruct.} = object - type RLNResult* = Result[ptr RLN, string] - -type RlnRelayResult*[T] = Result[T, string] + type RLNResult* = RlnRelayResult[ptr RLN] type # identity key as defined in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership diff --git a/waku/v2/protocol/waku_rln_relay/waku_rln_relay_utils.nim b/waku/v2/protocol/waku_rln_relay/waku_rln_relay_utils.nim index b29bedcda..46d2fe854 100644 --- a/waku/v2/protocol/waku_rln_relay/waku_rln_relay_utils.nim +++ b/waku/v2/protocol/waku_rln_relay/waku_rln_relay_utils.nim @@ -49,12 +49,11 @@ proc toBuffer*(x: openArray[byte]): Buffer = when defined(rln) or (not defined(rln) and not defined(rlnzerokit)): - proc createRLNInstanceLocal(d: int = MerkleTreeDepth): RLNResult - {.raises: [Defect, IOError].} = - + proc createRLNInstanceLocal(d: int = MerkleTreeDepth): RLNResult = ## generates an instance of RLN ## An RLN instance supports both zkSNARKs logics and Merkle tree data structure and operations ## d indicates the depth of Merkle tree + ## Returns an error if the instance creation fails var rlnInstance: RLN[Bn256] merkleDepth: csize_t = uint(d) @@ -67,7 +66,12 @@ when defined(rln) or (not defined(rln) and not defined(rlnzerokit)): ## to generate parameters for a different tree depth, change the tree size in the following line of rln library ## https://github.com/kilic/rln/blob/3bbec368a4adc68cd5f9bfae80b17e1bbb4ef373/examples/export_test_keys/main.rs#L4 ## and then proceed as explained above + parameters: string + try: parameters = readFile("waku/v2/protocol/waku_rln_relay/parameters.key") + except Exception as err: + return err("failed to read the parameters file: " & err.msg) + var pbytes = parameters.toBytes() len: csize_t = uint(pbytes.len) parametersBuffer = Buffer(`ptr`: addr(pbytes[0]), len: len) @@ -87,8 +91,9 @@ when defined(rln) or (not defined(rln) and not defined(rlnzerokit)): return ok(rlnInstance) - proc membershipKeyGen*(ctxPtr: RLN[Bn256]): Option[MembershipKeyPair] = + proc membershipKeyGen*(ctxPtr: RLN[Bn256]): RlnRelayResult[MembershipKeyPair] = ## generates a MembershipKeyPair that can be used for the registration into the rln membership contract + ## Returns an error if the key generation fails # keysBufferPtr will hold the generated key pairs i.e., secret and public keys var @@ -98,14 +103,12 @@ when defined(rln) or (not defined(rln) and not defined(rlnzerokit)): # check whether the keys are generated successfully if(done == false): - debug "error in key generation" - return none(MembershipKeyPair) + return err("error in key generation") var generatedKeys = cast[ptr array[64, byte]](keysBufferPtr.`ptr`)[] # the public and secret keys together are 64 bytes if (generatedKeys.len != 64): - debug "the generated keys are invalid" - return none(MembershipKeyPair) + return err("generated keys are of invalid length") # TODO define a separate proc to decode the generated keys to the secret and public components var @@ -118,15 +121,14 @@ when defined(rln) or (not defined(rln) and not defined(rlnzerokit)): keypair = MembershipKeyPair(idKey: secret, idCommitment: public) - return some(keypair) + return ok(keypair) when defined(rlnzerokit): - proc createRLNInstanceLocal(d: int = MerkleTreeDepth): RLNResult - {.raises: [Defect, IOError].} = - + proc createRLNInstanceLocal(d: int = MerkleTreeDepth): RLNResult = ## generates an instance of RLN ## An RLN instance supports both zkSNARKs logics and Merkle tree data structure and operations ## d indicates the depth of Merkle tree + ## Returns an error if the instance creation fails var rlnInstance: ptr RLN merkleDepth: csize_t = uint(d) @@ -141,8 +143,9 @@ when defined(rlnzerokit): return ok(rlnInstance) - proc membershipKeyGen*(ctxPtr: ptr RLN): Option[MembershipKeyPair] = + proc membershipKeyGen*(ctxPtr: ptr RLN): RlnRelayResult[MembershipKeyPair] = ## generates a MembershipKeyPair that can be used for the registration into the rln membership contract + ## Returns an error if the key generation fails # keysBufferPtr will hold the generated key pairs i.e., secret and public keys var @@ -152,14 +155,12 @@ when defined(rlnzerokit): # check whether the keys are generated successfully if(done == false): - debug "error in key generation" - return none(MembershipKeyPair) + return err("error in key generation") var generatedKeys = cast[ptr array[64, byte]](keysBufferPtr.`ptr`)[] # the public and secret keys together are 64 bytes if (generatedKeys.len != 64): - debug "the generated keys are invalid" - return none(MembershipKeyPair) + return err("generated keys are of invalid length") # TODO define a separate proc to decode the generated keys to the secret and public components var @@ -171,12 +172,14 @@ when defined(rlnzerokit): var keypair = MembershipKeyPair(idKey: secret, idCommitment: public) - return some(keypair) + return ok(keypair) -proc createRLNInstance*(d: int = MerkleTreeDepth): RLNResult {.raises: [Defect, IOError].} = +proc createRLNInstance*(d: int = MerkleTreeDepth): RLNResult = ## Wraps the rln instance creation for metrics + ## Returns an error if the instance creation fails + var res: RLNResult waku_rln_instance_creation_duration_seconds.nanosecondTime: - let res = createRLNInstanceLocal(d) + res = createRLNInstanceLocal(d) return res proc toUInt256*(idCommitment: IDCommitment): UInt256 = @@ -412,6 +415,8 @@ when defined(rln) or (not defined(rln) and not defined(rlnzerokit)): return ok(rootValue) proc proofVerify*(rlnInstance: RLN[Bn256], data: openArray[byte], proof: RateLimitProof, validRoots: seq[MerkleNode] = @[]): RlnRelayResult[bool] = + ## verifies the proof, returns an error if the proof verification fails + ## returns true if the proof is valid var proofBytes = serialize(proof, data) proofBuffer = proofBytes.toBuffer() @@ -528,7 +533,12 @@ when defined(rlnzerokit): # validRoots should contain a sequence of roots in the acceptable windows. # As default, it is set to an empty sequence of roots. This implies that the validity check for the proof's root is skipped - proc proofVerify*(rlnInstance: ptr RLN, data: openArray[byte], proof: RateLimitProof, validRoots: seq[MerkleNode] = @[]): RlnRelayResult[bool] = + proc proofVerify*(rlnInstance: ptr RLN, + data: openArray[byte], + proof: RateLimitProof, + validRoots: seq[MerkleNode] = @[]): RlnRelayResult[bool] = + ## verifies the proof, returns an error if the proof verification fails + ## returns true if the proof is valid var proofBytes = serialize(proof, data) proofBuffer = proofBytes.toBuffer() @@ -589,6 +599,7 @@ proc updateValidRootQueue*(wakuRlnRelay: WakuRLNRelay, root: MerkleNode): void = proc insertMember*(wakuRlnRelay: WakuRLNRelay, idComm: IDCommitment): RlnRelayResult[void] = ## inserts a new id commitment into the local merkle tree, and adds the changed root to the ## queue of valid roots + ## Returns an error if the insertion fails waku_rln_membership_insertion_duration_seconds.nanosecondTime: let actionSucceeded = wakuRlnRelay.rlnInstance.insertMember(idComm) if not actionSucceeded: @@ -602,6 +613,8 @@ proc insertMember*(wakuRlnRelay: WakuRLNRelay, idComm: IDCommitment): RlnRelayRe proc removeMember*(wakuRlnRelay: WakuRLNRelay, index: MembershipIndex): RlnRelayResult[void] = ## removes a commitment from the local merkle tree at `index`, and adds the changed root to the ## queue of valid roots + ## Returns an error if the removal fails + let actionSucceeded = wakuRlnRelay.rlnInstance.removeMember(index) if not actionSucceeded: return err("could not remove id commitment from the merkle tree") @@ -614,28 +627,35 @@ proc validateRoot*(wakuRlnRelay: WakuRLNRelay, root: MerkleNode): bool = ## Validate against the window of roots stored in wakuRlnRelay.validMerkleRoots return root in wakuRlnRelay.validMerkleRoots -proc toMembershipKeyPairs*(groupKeys: seq[(string, string)]): seq[ - MembershipKeyPair] {.raises: [Defect, ValueError].} = +proc toMembershipKeyPairs*(groupKeys: seq[(string, string)]): RlnRelayResult[seq[ + MembershipKeyPair]] = ## groupKeys is sequence of membership key tuples in the form of (identity key, identity commitment) all in the hexadecimal format ## the toMembershipKeyPairs proc populates a sequence of MembershipKeyPairs using the supplied groupKeys + ## Returns an error if the conversion fails var groupKeyPairs = newSeq[MembershipKeyPair]() for i in 0..groupKeys.len-1: - let - idKey = hexToUint[IDKey.len*8](groupKeys[i][0]).toBytesLE() - idCommitment = hexToUint[IDCommitment.len*8](groupKeys[i][1]).toBytesLE() - groupKeyPairs.add(MembershipKeyPair(idKey: idKey, - idCommitment: idCommitment)) - return groupKeyPairs + try: + let + idKey = hexToUint[IDKey.len*8](groupKeys[i][0]).toBytesLE() + idCommitment = hexToUint[IDCommitment.len*8](groupKeys[i][1]).toBytesLE() + groupKeyPairs.add(MembershipKeyPair(idKey: idKey, + idCommitment: idCommitment)) + except ValueError as err: + warn "could not convert the group key to bytes", err = err.msg + return err("could not convert the group key to bytes: " & err.msg) + return ok(groupKeyPairs) -proc calcMerkleRoot*(list: seq[IDCommitment]): string {.raises: [Defect, IOError].} = +proc calcMerkleRoot*(list: seq[IDCommitment]): RlnRelayResult[string] = ## returns the root of the Merkle tree that is computed from the supplied list ## the root is in hexadecimal format + ## Returns an error if the computation fails - var rlnInstance = createRLNInstance() - doAssert(rlnInstance.isOk) - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + if rlnInstance.isErr(): + return err("could not create rln instance: " & rlnInstance.error()) + let rln = rlnInstance.get() # create a Merkle tree for i in 0..list.len-1: @@ -644,42 +664,49 @@ proc calcMerkleRoot*(list: seq[IDCommitment]): string {.raises: [Defect, IOError doAssert(member_is_added) let root = rln.getMerkleRoot().value().inHex - return root + return ok(root) -proc createMembershipList*(n: int): (seq[(string, string)], string) {.raises: [ - Defect, IOError].} = +proc createMembershipList*(n: int): RlnRelayResult[( + seq[(string, string)], string + )] = ## createMembershipList produces a sequence of membership key pairs in the form of (identity key, id commitment keys) in the hexadecimal format ## this proc also returns the root of a Merkle tree constructed out of the identity commitment keys of the generated list ## the output of this proc is used to initialize a static group keys (to test waku-rln-relay in the off-chain mode) + ## Returns an error if it cannot create the membership list # initialize a Merkle tree - var rlnInstance = createRLNInstance() - if not rlnInstance.isOk: - return (@[], "") - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + if rlnInstance.isErr(): + return err("could not create rln instance: " & rlnInstance.error()) + let rln = rlnInstance.get() var output = newSeq[(string, string)]() for i in 0..n-1: # generate a key pair - let keypair = rln.membershipKeyGen() - doAssert(keypair.isSome()) - - let keyTuple = (keypair.get().idKey.inHex, keypair.get().idCommitment.inHex) + let keypairRes = rln.membershipKeyGen() + if keypairRes.isErr(): + return err("could not generate a key pair: " & keypairRes.error()) + let keypair = keypairRes.get() + let keyTuple = (keypair.idKey.inHex, keypair.idCommitment.inHex) output.add(keyTuple) # insert the key to the Merkle tree - let inserted = rln.insertMember(keypair.get().idCommitment) + let inserted = rln.insertMember(keypair.idCommitment) if not inserted: - return (@[], "") + return err("could not insert the key into the Merkle tree") let root = rln.getMerkleRoot().value().inHex - return (output, root) + return ok((output, root)) -proc rlnRelayStaticSetUp*(rlnRelayMembershipIndex: MembershipIndex): (Option[seq[ +proc rlnRelayStaticSetUp*(rlnRelayMembershipIndex: MembershipIndex): RlnRelayResult[(Option[seq[ IDCommitment]], Option[MembershipKeyPair], Option[ - MembershipIndex]) {.raises: [Defect, ValueError].} = + MembershipIndex])] = + ## rlnRelayStaticSetUp is a proc that is used to initialize the static group keys and the static membership index + ## this proc is used to test waku-rln-relay in the off-chain mode + ## it returns the static group keys, the static membership key pair, and the static membership index + ## Returns an error if it cannot initialize the static group keys and the static membership index let # static group groupKeys = StaticGroupKeys @@ -691,12 +718,19 @@ proc rlnRelayStaticSetUp*(rlnRelayMembershipIndex: MembershipIndex): (Option[seq if rlnRelayMembershipIndex < MembershipIndex(0) or rlnRelayMembershipIndex >= MembershipIndex(groupSize): error "wrong membership index" - return(none(seq[IDCommitment]), none(MembershipKeyPair), none(MembershipIndex)) + return ok((none(seq[IDCommitment]), none(MembershipKeyPair), none(MembershipIndex))) # prepare the outputs from the static group keys let # create a sequence of MembershipKeyPairs from the group keys (group keys are in string format) - groupKeyPairs = groupKeys.toMembershipKeyPairs() + groupKeyPairsRes = groupKeys.toMembershipKeyPairs() + + if groupKeyPairsRes.isErr(): + return err("could not convert the group keys to MembershipKeyPairs: " & + groupKeyPairsRes.error()) + + let + groupKeyPairs = groupKeyPairsRes.get() # extract id commitment keys groupIDCommitments = groupKeyPairs.mapIt(it.idCommitment) groupOpt = some(groupIDCommitments) @@ -704,13 +738,13 @@ proc rlnRelayStaticSetUp*(rlnRelayMembershipIndex: MembershipIndex): (Option[seq memKeyPairOpt = some(groupKeyPairs[rlnRelayMembershipIndex]) memIndexOpt = some(rlnRelayMembershipIndex) - return (groupOpt, memKeyPairOpt, memIndexOpt) + return ok((groupOpt, memKeyPairOpt, memIndexOpt)) proc hasDuplicate*(rlnPeer: WakuRLNRelay, msg: WakuMessage): RlnRelayResult[bool] = ## returns true if there is another message in the `nullifierLog` of the `rlnPeer` with the same ## epoch and nullifier as `msg`'s epoch and nullifier but different Shamir secret shares ## otherwise, returns false - ## emits an error string if `KeyError` occurs (never happens, it is just to avoid raising unnecessary `KeyError` exception ) + ## Returns an error if it cannot check for duplicates # extract the proof metadata of the supplied `msg` let proofMD = ProofMetadata(nullifier: msg.proof.nullifier, @@ -742,6 +776,7 @@ proc hasDuplicate*(rlnPeer: WakuRLNRelay, msg: WakuMessage): RlnRelayResult[bool proc updateLog*(rlnPeer: WakuRLNRelay, msg: WakuMessage): RlnRelayResult[bool] = ## extracts the `ProofMetadata` of the supplied messages `msg` and ## saves it in the `nullifierLog` of the `rlnPeer` + ## Returns an error if it cannot update the log let proofMD = ProofMetadata(nullifier: msg.proof.nullifier, shareX: msg.proof.shareX, shareY: msg.proof.shareY) @@ -913,6 +948,7 @@ proc appendRLNProof*(rlnPeer: WakuRLNRelay, msg: var WakuMessage, proc addAll*(wakuRlnRelay: WakuRLNRelay, list: seq[IDCommitment]): RlnRelayResult[void] = # add members to the Merkle tree of the `rlnInstance` + ## Returns an error if it cannot add any member to the Merkle tree for i in 0..list.len-1: let member = list[i] let memberAdded = wakuRlnRelay.insertMember(member) @@ -920,14 +956,14 @@ proc addAll*(wakuRlnRelay: WakuRLNRelay, list: seq[IDCommitment]): RlnRelayResul return err(memberAdded.error()) return ok() -type GroupUpdateHandler* = proc(pubkey: Uint256, index: Uint256): RlnRelayResult[void] {.gcsafe, raises: [Defect].} +type GroupUpdateHandler* = proc(pubkey: Uint256, index: Uint256): RlnRelayResult[void] {.gcsafe.} proc generateGroupUpdateHandler(rlnPeer: WakuRLNRelay): GroupUpdateHandler = ## assuming all the members arrive in order ## TODO: check the index and the pubkey depending on ## the group update operation var handler: GroupUpdateHandler - handler = proc(pubkey: Uint256, index: Uint256): RlnRelayResult[void] {.raises: [Defect].} = + handler = proc(pubkey: Uint256, index: Uint256): RlnRelayResult[void] = var pk: IDCommitment try: pk = pubkey.toIDCommitment() @@ -959,7 +995,11 @@ proc subscribeToMemberRegistrations(web3: Web3, let onMemberRegistered = proc (pubkey: Uint256, index: Uint256) {.gcsafe.} = debug "onRegister", pubkey = pubkey, index = index - let groupUpdateRes = handler(pubkey, index) + var groupUpdateRes: RlnRelayResult[void] + try: + groupUpdateRes = handler(pubkey, index) + except Exception as err: + error "failed to handle group update", err = err.msg if groupUpdateRes.isErr(): error "Error handling new member registration", err=groupUpdateRes.error() @@ -1065,32 +1105,32 @@ proc mountRlnRelayStatic*(node: WakuNode, memIndex: MembershipIndex, pubsubTopic: string, contentTopic: ContentTopic, - spamHandler: Option[SpamHandler] = none(SpamHandler)) {.raises: [Defect, IOError].}= - # TODO return a bool value to indicate the success of the call + spamHandler: Option[SpamHandler] = none(SpamHandler)): RlnRelayResult[void] = + # Returns RlnRelayResult[void] to indicate the success of the call debug "mounting rln-relay in off-chain/static mode" # check whether inputs are provided # relay protocol is the prerequisite of rln-relay - if node.wakuRelay.isNil: - error "WakuRelay protocol is not mounted." - return + if node.wakuRelay.isNil(): + return err("WakuRelay protocol is not mounted") # check whether the pubsub topic is supported at the relay level if pubsubTopic notin node.wakuRelay.defaultTopics: - error "The relay protocol does not support the configured pubsub topic.", pubsubTopic=pubsubTopic - return + return err("The relay protocol does not support the configured pubsub topic") debug "rln-relay input validation passed" # check the peer's index and the inclusion of user's identity commitment in the group - doAssert((memKeyPair.idCommitment) == group[int(memIndex)]) + if not memKeyPair.idCommitment == group[int(memIndex)]: + return err("The peer's index is not consistent with the group") # create an RLN instance - var rlnInstance = createRLNInstance() - doAssert(rlnInstance.isOk) - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + if rlnInstance.isErr(): + return err("RLN instance creation failed") + let rln = rlnInstance.get() # create the WakuRLNRelay - var rlnPeer = WakuRLNRelay(membershipKeyPair: memKeyPair, + let rlnPeer = WakuRLNRelay(membershipKeyPair: memKeyPair, membershipIndex: memIndex, rlnInstance: rln, pubsubTopic: pubsubTopic, @@ -1100,7 +1140,8 @@ proc mountRlnRelayStatic*(node: WakuNode, for index in 0..group.len-1: let member = group[index] let memberAdded = rlnPeer.insertMember(member) - doAssert(memberAdded.isOk()) + if memberAdded.isErr(): + return err("member addition to the Merkle tree failed: " & memberAdded.error()) # adds a topic validator for the supplied pubsub topic at the relay protocol # messages published on this pubsub topic will be relayed upon a successful validation, otherwise they will be dropped @@ -1108,7 +1149,8 @@ proc mountRlnRelayStatic*(node: WakuNode, node.addRLNRelayValidator(pubsubTopic, contentTopic, spamHandler) debug "rln relay topic validator is mounted successfully", pubsubTopic=pubsubTopic, contentTopic=contentTopic - node.wakuRlnRelay = rlnPeer + node.wakuRlnRelay = rlnPeer + return ok() proc mountRlnRelayDynamic*(node: WakuNode, ethClientAddr: string = "", @@ -1120,23 +1162,23 @@ proc mountRlnRelayDynamic*(node: WakuNode, pubsubTopic: string, contentTopic: ContentTopic, spamHandler: Option[SpamHandler] = none(SpamHandler), - registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler)) : Future[RlnRelayResult[bool]] {.async.} = + registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler)) : Future[RlnRelayResult[void]] {.async.} = debug "mounting rln-relay in on-chain/dynamic mode" # TODO return a bool value to indicate the success of the call # relay protocol is the prerequisite of rln-relay if node.wakuRelay.isNil: - error "WakuRelay protocol is not mounted." return err("WakuRelay protocol is not mounted.") # check whether the pubsub topic is supported at the relay level if pubsubTopic notin node.wakuRelay.defaultTopics: - error "Wakurelay protocol does not support the configured pubsub topic.", pubsubTopic=pubsubTopic return err("WakuRelay protocol does not support the configured pubsub topic.") debug "rln-relay input validation passed" # create an RLN instance - var rlnInstance = createRLNInstance() - doAssert(rlnInstance.isOk) - var rln = rlnInstance.value + let rlnInstance = createRLNInstance() + + if rlnInstance.isErr(): + return err("RLN instance creation failed.") + let rln = rlnInstance.get() # prepare rln membership key pair var @@ -1145,12 +1187,19 @@ proc mountRlnRelayDynamic*(node: WakuNode, if memKeyPair.isNone: # no rln credentials provided if ethAccountPrivKeyOpt.isSome: # if an ethereum private key is supplied, then create rln credentials and register to the membership contract trace "no rln-relay key is provided, generating one" - let keyPairOpt = rln.membershipKeyGen() - doAssert(keyPairOpt.isSome) - keyPair = keyPairOpt.get() + let keyPairRes = rln.membershipKeyGen() + if keyPairRes.isErr(): + error "failed to generate rln-relay key pair" + return err("failed to generate rln-relay key pair: " & keyPairRes.error()) + keyPair = keyPairRes.value() # register the rln-relay peer to the membership contract waku_rln_registration_duration_seconds.nanosecondTime: - let regIndexRes = await register(idComm = keyPair.idCommitment, ethAccountAddress = ethAccountAddress, ethAccountPrivKey = ethAccountPrivKeyOpt.get(), ethClientAddress = ethClientAddr, membershipContractAddress = memContractAddr, registrationHandler = registrationHandler) + let regIndexRes = await register(idComm = keyPair.idCommitment, + ethAccountAddress = ethAccountAddress, + ethAccountPrivKey = ethAccountPrivKeyOpt.get(), + ethClientAddress = ethClientAddr, + membershipContractAddress = memContractAddr, + registrationHandler = registrationHandler) # check whether registration is done if regIndexRes.isErr(): debug "membership registration failed", err=regIndexRes.error() @@ -1184,9 +1233,12 @@ proc mountRlnRelayDynamic*(node: WakuNode, debug "rln relay topic validator is mounted successfully", pubsubTopic=pubsubTopic, contentTopic=contentTopic node.wakuRlnRelay = rlnPeer - return ok(true) + return ok() -proc writeRlnCredentials*(path: string, credentials: RlnMembershipCredentials, password: string): RlnRelayResult[void] = +proc writeRlnCredentials*(path: string, + credentials: RlnMembershipCredentials, + password: string): RlnRelayResult[void] = + # Returns RlnRelayResult[void], which indicates the success of the call info "Storing RLN credentials" var jsonString: string jsonString.toUgly(%credentials) @@ -1199,7 +1251,10 @@ proc writeRlnCredentials*(path: string, credentials: RlnMembershipCredentials, p # Attempts decryptions of all keyfiles with the provided password. # If one or more credentials are successfully decrypted, the max(min(index,number_decrypted),0)-th is returned. -proc readRlnCredentials*(path: string, password: string, index: int = 0): RlnRelayResult[Option[RlnMembershipCredentials]] = +proc readRlnCredentials*(path: string, + password: string, + index: int = 0): RlnRelayResult[Option[RlnMembershipCredentials]] = + # Returns RlnRelayResult[Option[RlnMembershipCredentials]], which indicates the success of the call info "Reading RLN credentials" # With regards to printing the keys, it is purely for debugging purposes so that the user becomes explicitly aware of the current keys in use when nwaku is started. # Note that this is only until the RLN contract being used is the one deployed on Goerli testnet. @@ -1230,16 +1285,29 @@ proc mount(node: WakuNode, conf: WakuNodeConf|Chat2Conf, spamHandler: Option[SpamHandler] = none(SpamHandler), registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler) - ): RlnRelayResult[bool] {.raises: [Defect, ValueError, IOError, CatchableError, Exception].} = + ): Future[RlnRelayResult[void]] {.async.} = + # Returns RlnRelayResult[void], which indicates the success of the call if not conf.rlnRelayDynamic: info " setting up waku-rln-relay in off-chain mode... " # set up rln relay inputs - let (groupOpt, memKeyPairOpt, memIndexOpt) = rlnRelayStaticSetUp(MembershipIndex(conf.rlnRelayMembershipIndex)) + let staticSetupRes = rlnRelayStaticSetUp(MembershipIndex(conf.rlnRelayMembershipIndex)) + if staticSetupRes.isErr(): + return err("rln relay static setup failed: " & staticSetupRes.error()) + let (groupOpt, memKeyPairOpt, memIndexOpt) = staticSetupRes.get() if memIndexOpt.isNone: error "failed to mount WakuRLNRelay" + return err("failed to mount WakuRLNRelay") else: # mount rlnrelay in off-chain mode with a static group of users - node.mountRlnRelayStatic(group = groupOpt.get(), memKeyPair = memKeyPairOpt.get(), memIndex= memIndexOpt.get(), pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic, spamHandler = spamHandler) + let mountRes = node.mountRlnRelayStatic(group = groupOpt.get(), + memKeyPair = memKeyPairOpt.get(), + memIndex= memIndexOpt.get(), + pubsubTopic = conf.rlnRelayPubsubTopic, + contentTopic = conf.rlnRelayContentTopic, + spamHandler = spamHandler) + + if mountRes.isErr(): + return err("Failed to mount WakuRLNRelay: " & mountRes.error()) info "membership id key", idkey=memKeyPairOpt.get().idKey.inHex info "membership id commitment key", idCommitmentkey=memKeyPairOpt.get().idCommitment.inHex @@ -1260,7 +1328,7 @@ proc mount(node: WakuNode, error "root mismatch: something went wrong not in Merkle tree construction" debug "the calculated root", root info "WakuRLNRelay is mounted successfully", pubsubtopic=conf.rlnRelayPubsubTopic, contentTopic=conf.rlnRelayContentTopic - return ok(true) + return ok() else: # mount the rln relay protocol in the on-chain/dynamic mode debug "setting up waku-rln-relay in on-chain mode... " @@ -1268,17 +1336,27 @@ proc mount(node: WakuNode, # read related inputs to run rln-relay in on-chain mode and do type conversion when needed let ethClientAddr = conf.rlnRelayEthClientAddress + + var ethMemContractAddress: web3.Address + try: ethMemContractAddress = web3.fromHex(web3.Address, conf.rlnRelayEthContractAddress) + except ValueError as err: + return err("invalid eth contract address: " & err.msg) var ethAccountPrivKeyOpt = none(keys.PrivateKey) var ethAccountAddressOpt = none(Address) var credentials = none(RlnMembershipCredentials) - var res: RlnRelayResult[bool] + var res: RlnRelayResult[void] if conf.rlnRelayEthAccountPrivateKey != "": ethAccountPrivKeyOpt = some(keys.PrivateKey(SkSecretKey.fromHex(conf.rlnRelayEthAccountPrivateKey).value)) if conf.rlnRelayEthAccountAddress != "": - ethAccountAddressOpt = some(web3.fromHex(web3.Address, conf.rlnRelayEthAccountAddress)) + var ethAccountAddress: web3.Address + try: + ethAccountAddress = web3.fromHex(web3.Address, conf.rlnRelayEthAccountAddress) + except ValueError as err: + return err("invalid eth account address: " & err.msg) + ethAccountAddressOpt = some(ethAccountAddress) # if the rlnRelayCredPath config option is non-empty, then rln-relay credentials should be persisted # if the path does not contain any credential file, then a new set is generated and pesisted in the same path @@ -1308,7 +1386,7 @@ proc mount(node: WakuNode, if credentials.isSome(): # mount rln-relay in on-chain mode, with credentials that were read or generated - res = waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, + res = await node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, ethAccountAddress = ethAccountAddressOpt, ethAccountPrivKeyOpt = ethAccountPrivKeyOpt, @@ -1320,7 +1398,7 @@ proc mount(node: WakuNode, memIndex = some(credentials.get().rlnIndex)) else: # mount rln-relay in on-chain mode, with the provided private key - res = waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, + res = await node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, ethAccountAddress = ethAccountAddressOpt, ethAccountPrivKeyOpt = ethAccountPrivKeyOpt, @@ -1340,26 +1418,28 @@ proc mount(node: WakuNode, # do not persist or use a persisted rln-relay credential # a new credential will be generated during the mount process but will not be persisted info "no need to persist or use a persisted rln-relay credential" - res = waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, + res = await node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, ethAccountAddress = ethAccountAddressOpt, ethAccountPrivKeyOpt = ethAccountPrivKeyOpt, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic, spamHandler = spamHandler, registrationHandler = registrationHandler) if res.isErr(): - return err("dynamic rln-relay could not be mounted: " & res.error()) - return ok(res.value()) + return err("dynamic rln-relay could not be mounted: " & res.error()) + return ok() proc mountRlnRelay*(node: WakuNode, conf: WakuNodeConf|Chat2Conf, spamHandler: Option[SpamHandler] = none(SpamHandler), registrationHandler: Option[RegistrationHandler] = none(RegistrationHandler) - ): RlnRelayResult[bool] {.raises: [Defect, ValueError, IOError, CatchableError, Exception].} = - waku_rln_relay_mounting_duration_seconds.nanosecondTime: - let res = mount( + ): Future[RlnRelayResult[void]] {.async.} = + ## Mounts the rln-relay protocol on the node. + ## The rln-relay protocol can be mounted in two modes: on-chain and off-chain. + ## Returns an error if the rln-relay protocol could not be mounted. + waku_rln_relay_mounting_duration_seconds.nanosecondTime: + let res = await mount( node, conf, spamHandler, registrationHandler ) - return res