From 6d74aa08a9bd961734a14ad094c479f1fd7bfdf9 Mon Sep 17 00:00:00 2001 From: Aaryamann Challani <43716372+rymnc@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:20:30 +0530 Subject: [PATCH] chore(rln-relay-v2): wakunode testing + improvements (#2501) * chore(rln-relay-v2): additional testing * fix: bump librln to v0.4.2 for v2 * fix: catch possible error from the copyFrom * ci: rename step title for rln-version --- .github/workflows/ci.yml | 10 +- .github/workflows/container-image.yml | 7 +- Makefile | 2 +- tests/all_tests_waku.nim | 7 +- .../rln/waku_rln_relay_utils.nim | 26 +- .../rln_v2/test_rln_relay_v2_serde.nim | 2 +- tests/waku_rln_relay/test_all.nim | 3 + .../waku_rln_relay/test_rln_nonce_manager.nim | 31 +-- tests/waku_rln_relay/test_waku_rln_relay.nim | 130 +++++---- .../test_wakunode_rln_relay.nim | 252 ++++++++++++------ tests/wakunode_rest/test_rest_relay.nim | 60 ++++- waku/waku_api/rest/relay/handlers.nim | 4 +- waku/waku_rln_relay/conversion_utils.nim | 2 +- waku/waku_rln_relay/nonce_manager.nim | 6 +- waku/waku_rln_relay/rln/wrappers.nim | 48 ++-- waku/waku_rln_relay/rln_relay.nim | 2 +- 16 files changed, 379 insertions(+), 213 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce99e29a3..92ba10568 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,11 +55,12 @@ jobs: if: ${{ needs.changes.outputs.v2 == 'true' || needs.changes.outputs.common == 'true' }} strategy: matrix: + rln_version : [1, 2] os: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.os }} timeout-minutes: 60 - name: build-${{ matrix.os }} + name: build-${{ matrix.os }}-rln-v${{ matrix.rln_version }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -78,18 +79,19 @@ jobs: key: ${{ runner.os }}-vendor-modules-${{ steps.submodules.outputs.hash }} - name: Build binaries - run: make V=1 QUICK_AND_DIRTY_COMPILER=1 all tools + run: make RLN_V${{matrix.rln_version}}=true V=1 QUICK_AND_DIRTY_COMPILER=1 all tools test: needs: changes if: ${{ needs.changes.outputs.v2 == 'true' || needs.changes.outputs.common == 'true' }} strategy: matrix: + rln_version : [1, 2] os: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.os }} timeout-minutes: 60 - name: test-${{ matrix.os }} + name: test-${{ matrix.os }}-rln-v${{ matrix.rln_version }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -118,7 +120,7 @@ jobs: sudo docker run --rm -d -e POSTGRES_PASSWORD=test123 -p 5432:5432 postgres:15.4-alpine3.18 fi - make V=1 LOG_LEVEL=DEBUG QUICK_AND_DIRTY_COMPILER=1 POSTGRES=1 test testwakunode2 + make RLN_V${{matrix.rln_version}}=true V=1 LOG_LEVEL=DEBUG QUICK_AND_DIRTY_COMPILER=1 POSTGRES=1 test testwakunode2 build-docker-image: needs: changes diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml index b5953f263..16f7e3d62 100644 --- a/.github/workflows/container-image.yml +++ b/.github/workflows/container-image.yml @@ -20,11 +20,12 @@ jobs: build-docker-image: strategy: matrix: + rln_v2: [true, false] os: [ubuntu-latest] runs-on: ${{ matrix.os }} timeout-minutes: 60 - name: docker-build-${{ matrix.os }} + name: docker-build-${{ matrix.os }}-rln-v2-${{ matrix.rln_v2 }} outputs: image: ${{ steps.build.outputs.image }} steps: @@ -48,12 +49,12 @@ jobs: id: build run: | - make -j${NPROC} V=1 QUICK_AND_DIRTY_COMPILER=1 NIMFLAGS="-d:disableMarchNative -d:postgres" wakunode2 + make RLN_V2=${{matrix.rln_v2}} -j${NPROC} V=1 QUICK_AND_DIRTY_COMPILER=1 NIMFLAGS="-d:disableMarchNative -d:postgres" wakunode2 SHORT_REF=$(git rev-parse --short HEAD) TAG=$([ "${PR_NUMBER}" == "" ] && echo "${SHORT_REF}" || echo "${PR_NUMBER}") - IMAGE=quay.io/wakuorg/nwaku-pr:${TAG} + IMAGE=quay.io/wakuorg/nwaku-pr:${TAG}-rln-v2-${{matrix.rln_v2}} echo "image=${IMAGE}" >> $GITHUB_OUTPUT echo "commit_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT diff --git a/Makefile b/Makefile index b02c2296a..c4e140a62 100644 --- a/Makefile +++ b/Makefile @@ -135,7 +135,7 @@ clean: | clean-libbacktrace LIBRLN_BUILDDIR := $(CURDIR)/vendor/zerokit ifeq ($(RLN_V2),true) -LIBRLN_VERSION := v0.4.1 +LIBRLN_VERSION := v0.4.2 else LIBRLN_VERSION := v0.3.6 endif diff --git a/tests/all_tests_waku.nim b/tests/all_tests_waku.nim index 74f006a75..b6b7e4b73 100644 --- a/tests/all_tests_waku.nim +++ b/tests/all_tests_waku.nim @@ -80,9 +80,4 @@ import ./wakunode_rest/test_rest_admin, ./wakunode_rest/test_rest_cors -import - ./waku_rln_relay/test_waku_rln_relay, - ./waku_rln_relay/test_wakunode_rln_relay, - ./waku_rln_relay/test_rln_group_manager_onchain, - ./waku_rln_relay/test_rln_group_manager_static, - ./wakunode_rest/test_rest_health +import ./waku_rln_relay/test_all diff --git a/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim b/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim index eeefe6236..458a61ec3 100644 --- a/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim +++ b/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim @@ -1,6 +1,30 @@ import std/tempfiles -import ../../../waku/waku_rln_relay/[rln, protocol_types] +import + ../../../waku/waku_rln_relay, + ../../../waku/waku_rln_relay/[rln, protocol_types] proc createRLNInstanceWrapper*(): RLNResult = return createRlnInstance(tree_path = genTempPath("rln_tree", "waku_rln_relay")) + + +proc unsafeAppendRLNProof*(rlnPeer: WakuRLNRelay, + msg: var WakuMessage, + senderEpochTime: float64): RlnRelayResult[void] = + ## this proc derived from appendRLNProof, does not perform nonce check to + ## facilitate bad message id generation for testing + + let input = msg.toRLNSignal() + let epoch = rlnPeer.calcEpoch(senderEpochTime) + + when defined(rln_v2): + # we do not fetch a nonce from the nonce manager, + # instead we use 0 as the nonce + let proof = rlnPeer.groupManager.generateProof(input, epoch, 0).valueOr: + return err("could not generate rln-v2 proof: " & $error) + else: + let proof = rlnPeer.groupManager.generateProof(input, epoch).valueOr: + return err("could not generate rln proof: " & $error) + + msg.proof = proof.encode().buffer + return ok() \ No newline at end of file diff --git a/tests/waku_rln_relay/rln_v2/test_rln_relay_v2_serde.nim b/tests/waku_rln_relay/rln_v2/test_rln_relay_v2_serde.nim index 06bdcb840..5b5bf2b66 100644 --- a/tests/waku_rln_relay/rln_v2/test_rln_relay_v2_serde.nim +++ b/tests/waku_rln_relay/rln_v2/test_rln_relay_v2_serde.nim @@ -73,7 +73,7 @@ suite "RLN Relay v2: serde": userMessageLimit = rateCommitment.userMessageLimit, messageId = 0, index = 0, - epoch = rln.calcEpoch(epochTime())) + epoch = uint64(epochTime()/1.float64).toEpoch()) assert proofRes.isOk, $proofRes.error diff --git a/tests/waku_rln_relay/test_all.nim b/tests/waku_rln_relay/test_all.nim index ed5b690d8..7aa3f395e 100644 --- a/tests/waku_rln_relay/test_all.nim +++ b/tests/waku_rln_relay/test_all.nim @@ -6,3 +6,6 @@ import ./test_waku_rln_relay, ./test_wakunode_rln_relay, ./test_rln_nonce_manager + +when defined(rln_v2): + import ./rln_v2/test_rln_relay_v2_serde diff --git a/tests/waku_rln_relay/test_rln_nonce_manager.nim b/tests/waku_rln_relay/test_rln_nonce_manager.nim index 8e5df8a18..250d244ae 100644 --- a/tests/waku_rln_relay/test_rln_nonce_manager.nim +++ b/tests/waku_rln_relay/test_rln_nonce_manager.nim @@ -18,34 +18,31 @@ suite "Nonce manager": test "should generate a new nonce": let nm = NonceManager.init(nonceLimit = 100.uint) - let nonceRes = nm.get() - - assert nonceRes.isOk(), $nonceRes.error + let nonce = nm.getNonce().valueOr: + raiseAssert $error check: - nonceRes.get() == 0.uint + nonce == 0.uint nm.nextNonce == 1.uint test "should fail to generate a new nonce if limit is reached": let nm = NonceManager.init(nonceLimit = 1.uint) - let nonceRes = nm.get() - let nonceRes2 = nm.get() - - assert nonceRes.isOk(), $nonceRes.error - assert nonceRes2.isErr(), "Expected error, got: " & $nonceRes2.value + let nonce = nm.getNonce().valueOr: + raiseAssert $error + let failedNonceRes = nm.getNonce() check: - nonceRes2.error.kind == NonceManagerErrorKind.NonceLimitReached + failedNonceRes.isErr() + failedNonceRes.error.kind == NonceManagerErrorKind.NonceLimitReached test "should generate a new nonce if epoch is crossed": let nm = NonceManager.init(nonceLimit = 1.uint, epoch = float(0.000001)) - let nonceRes = nm.get() + let nonce = nm.getNonce().valueOr: + raiseAssert $error sleep(1) - let nonceRes2 = nm.get() - - assert nonceRes.isOk(), $nonceRes.error - assert nonceRes2.isOk(), $nonceRes2.error + let nonce2 = nm.getNonce().valueOr: + raiseAssert $error check: - nonceRes.value == 0.uint - nonceRes2.value == 0.uint \ No newline at end of file + nonce == 0.uint + nonce2 == 0.uint \ No newline at end of file diff --git a/tests/waku_rln_relay/test_waku_rln_relay.nim b/tests/waku_rln_relay/test_waku_rln_relay.nim index e0a831d65..20ce66b75 100644 --- a/tests/waku_rln_relay/test_waku_rln_relay.nim +++ b/tests/waku_rln_relay/test_waku_rln_relay.nim @@ -518,18 +518,23 @@ suite "Waku rln relay": let rln = rlnInstance.get() # create a Merkle tree - let membersAdded = rln.insertMembers(0, groupIDCommitments) - require: - membersAdded - let rootRes = rln.getMerkleRoot() + when defined(rln_v2): + let rateCommitments = groupIDCommitments.mapIt(RateCommitment(idCommitment: it, + userMessageLimit: 20)) + let leaves = rateCommitments.toLeaves().valueOr: + raiseAssert $error + let membersAdded = rln.insertMembers(0, leaves) + else: + let membersAdded = rln.insertMembers(0, groupIDCommitments) + + assert membersAdded, "members should be added" + let rawRoot = rln.getMerkleRoot().valueOr: + raiseAssert $error - require: - rootRes.isOk() - - let root = rootRes.get().inHex() + let root = rawRoot.inHex() debug "groupIdCredentials", groupIdCredentials - debug "groupIDCommitments", groupIDCommitments + debug "groupIDCommitments", groupIDCommitments = groupIDCommitments.mapIt(it.inHex()) debug "root", root check: @@ -597,8 +602,8 @@ suite "Waku rln relay": test "updateLog and hasDuplicate tests": let - wakurlnrelay = WakuRLNRelay() - epoch = wakurlnrelay.getCurrentEpoch() + wakuRlnRelay = WakuRLNRelay() + epoch = wakuRlnRelay.getCurrentEpoch() # create some dummy nullifiers and secret shares var nullifier1: Nullifier @@ -640,37 +645,44 @@ suite "Waku rln relay": # check whether hasDuplicate correctly finds records with the same nullifiers but different secret shares # no duplicate for proof1 should be found, since the log is empty - let result1 = wakurlnrelay.hasDuplicate(epoch, proof1.extractMetadata().tryGet()) - assert result1.isOk(), $result1.error - assert result1.value == false, "no duplicate should be found" + let proofMetadata1 = proof1.extractMetadata().tryGet() + let isDuplicate1 = wakuRlnRelay.hasDuplicate(epoch, proofMetadata1).valueOr: + raiseAssert $error + assert isDuplicate1 == false, "no duplicate should be found" # add it to the log - discard wakurlnrelay.updateLog(epoch, proof1.extractMetadata().tryGet()) + discard wakuRlnRelay.updateLog(epoch, proofMetadata1) # no duplicate for proof2 should be found, its nullifier differs from proof1 - let result2 = wakurlnrelay.hasDuplicate(epoch, proof2.extractMetadata().tryGet()) - assert result2.isOk(), $result2.error + let proofMetadata2 = proof2.extractMetadata().tryGet() + let isDuplicate2 = wakuRlnRelay.hasDuplicate(epoch, proofMetadata2).valueOr: + raiseAssert $error # no duplicate is found - assert result2.value == false, "no duplicate should be found" + assert isDuplicate2 == false, "no duplicate should be found" # add it to the log - discard wakurlnrelay.updateLog(epoch, proof2.extractMetadata().tryGet()) + discard wakuRlnRelay.updateLog(epoch, proofMetadata2) # proof3 has the same nullifier as proof1 but different secret shares, it should be detected as duplicate - let result3 = wakurlnrelay.hasDuplicate(epoch, proof3.extractMetadata().tryGet()) - assert result3.isOk(), $result3.error + let isDuplicate3 = wakuRlnRelay.hasDuplicate(epoch, proof3.extractMetadata().tryGet()).valueOr: + raiseAssert $error # it is a duplicate - assert result3.value, "duplicate should be found" + assert isDuplicate3, "duplicate should be found" asyncTest "validateMessageAndUpdateLog test": let index = MembershipIndex(5) - let rlnConf = WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(index), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_2")) - let wakuRlnRelayRes = await WakuRlnRelay.new(rlnConf) - require: - wakuRlnRelayRes.isOk() - let wakuRlnRelay = wakuRlnRelayRes.get() + when defined(rln_v2): + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(index), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_2")) + else: + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(index), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_2")) + let wakuRlnRelay = (await WakuRlnRelay.new(wakuRlnConfig)).valueOr: + raiseAssert $error # get the current epoch time let time = epochTime() @@ -684,16 +696,12 @@ suite "Waku rln relay": wm3 = WakuMessage(payload: "Valid message".toBytes()) wm4 = WakuMessage(payload: "Invalid message".toBytes()) - let - proofAdded1 = wakuRlnRelay.appendRLNProof(wm1, time) - proofAdded2 = wakuRlnRelay.appendRLNProof(wm2, time) - proofAdded3 = wakuRlnRelay.appendRLNProof(wm3, time+float64(wakuRlnRelay.rlnEpochSizeSec)) - - # ensure proofs are added - require: - proofAdded1.isOk() - proofAdded2.isOk() - proofAdded3.isOk() + wakuRlnRelay.unsafeAppendRLNProof(wm1, time).isOkOr: + raiseAssert $error + wakuRlnRelay.unsafeAppendRLNProof(wm2, time).isOkOr: + raiseAssert $error + wakuRlnRelay.unsafeAppendRLNProof(wm3, time+float64(wakuRlnRelay.rlnEpochSizeSec)).isOkOr: + raiseAssert $error # validate messages # validateMessage proc checks the validity of the message fields and adds it to the log (if valid) @@ -717,17 +725,32 @@ suite "Waku rln relay": let index1 = MembershipIndex(5) let index2 = MembershipIndex(6) - let rlnConf1 = WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(index1), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_3")) + when defined(rln_v2): + let rlnConf1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(index1), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_3")) + else: + let rlnConf1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(index1), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_3")) + let wakuRlnRelay1 = (await WakuRlnRelay.new(rlnConf1)).valueOr: raiseAssert "failed to create waku rln relay: " & $error - let rlnConf2 = WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(index2), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_4")) + when defined(rln_v2): + let rlnConf2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(index2), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_4")) + else: + let rlnConf2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(index2), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_4")) let wakuRlnRelay2 = (await WakuRlnRelay.new(rlnConf2)).valueOr: raiseAssert "failed to create waku rln relay: " & $error # get the current epoch time @@ -740,13 +763,10 @@ suite "Waku rln relay": wm2 = WakuMessage(payload: "Valid message from sender 2".toBytes()) - let - proofAdded1 = wakuRlnRelay1.appendRLNProof(wm1, time) - proofAdded2 = wakuRlnRelay2.appendRLNProof(wm2, time) - - # ensure proofs are added - assert proofAdded1.isOk(), "failed to append rln proof: " & $proofAdded1.error - assert proofAdded2.isOk(), "failed to append rln proof: " & $proofAdded2.error + wakuRlnRelay1.appendRLNProof(wm1, time).isOkOr: + raiseAssert $error + wakuRlnRelay2.appendRLNProof(wm2, time).isOkOr: + raiseAssert $error # validate messages # validateMessage proc checks the validity of the message fields and adds it to the log (if valid) diff --git a/tests/waku_rln_relay/test_wakunode_rln_relay.nim b/tests/waku_rln_relay/test_wakunode_rln_relay.nim index d0e4d2d98..f3399909c 100644 --- a/tests/waku_rln_relay/test_wakunode_rln_relay.nim +++ b/tests/waku_rln_relay/test_wakunode_rln_relay.nim @@ -14,11 +14,13 @@ import ../../../waku/waku_node, ../../../waku/waku_rln_relay, ../testlib/wakucore, - ../testlib/wakunode + ../testlib/wakunode, + ./rln/waku_rln_relay_utils from std/times import epochTime procSuite "WakuNode - RLN relay": + # NOTE: we set the rlnRelayUserMessageLimit to 1 to make the tests easier to reason about asyncTest "testing rln-relay with valid proof": let @@ -39,33 +41,54 @@ procSuite "WakuNode - RLN relay": await node1.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - await node1.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(1.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode"), - )) + when defined(rln_v2): + let wakuRlnConfig1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode")) + else: + let wakuRlnConfig1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode")) + await node1.mountRlnRelay(wakuRlnConfig1) await node1.start() # node 2 await node2.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - await node2.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(2.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_2"), - )) + when defined(rln_v2): + let wakuRlnConfig2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_2")) + else: + let wakuRlnConfig2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_2")) + await node2.mountRlnRelay(wakuRlnConfig2) await node2.start() # node 3 await node3.mountRelay(@[DefaultPubsubTopic]) - await node3.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(3.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_3"), - )) + when defined(rln_v2): + let wakuRlnConfig3 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(3.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_3")) + else: + let wakuRlnConfig3 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(3.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_3")) + await node3.mountRlnRelay(wakuRlnConfig3) await node3.start() @@ -88,7 +111,7 @@ procSuite "WakuNode - RLN relay": # prepare the epoch var message = WakuMessage(payload: @payload, contentTopic: contentTopic) - doAssert(node1.wakuRlnRelay.appendRLNProof(message, epochTime()).isOk()) + doAssert(node1.wakuRlnRelay.unsafeAppendRLNProof(message, epochTime()).isOk()) ## node1 publishes a message with a rate limit proof, the message is then relayed to node2 which in turn @@ -123,10 +146,18 @@ procSuite "WakuNode - RLN relay": # mount rlnrelay in off-chain mode for index, node in nodes: - await node.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(index.uint + 1), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $(index+1)))) + when defined(rln_v2): + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(index.uint + 1), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $(index+1))) + else: + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(index.uint + 1), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $(index+1))) + await node.mountRlnRelay(wakuRlnConfig) # start them await allFutures(nodes.mapIt(it.start())) @@ -159,12 +190,14 @@ procSuite "WakuNode - RLN relay": for i in 0..<3: var message = WakuMessage(payload: ("Payload_" & $i).toBytes(), contentTopic: contentTopics[0]) - doAssert(nodes[0].wakuRlnRelay.appendRLNProof(message, epochTime).isOk()) + nodes[0].wakuRlnRelay.unsafeAppendRLNProof(message, epochTime).isOkOr: + raiseAssert $error messages1.add(message) for i in 0..<3: var message = WakuMessage(payload: ("Payload_" & $i).toBytes(), contentTopic: contentTopics[1]) - doAssert(nodes[1].wakuRlnRelay.appendRLNProof(message, epochTime).isOk()) + nodes[1].wakuRlnRelay.unsafeAppendRLNProof(message, epochTime).isOkOr: + raiseAssert $error messages2.add(message) # publish 3 messages from node[0] (last 2 are spam, window is 10 secs) @@ -202,34 +235,54 @@ procSuite "WakuNode - RLN relay": await node1.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - await node1.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(1.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_4"), - )) + when defined(rln_v2): + let wakuRlnConfig1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_4")) + else: + let wakuRlnConfig1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_4")) + await node1.mountRlnRelay(wakuRlnConfig1) await node1.start() # node 2 await node2.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - await node2.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(2.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_5"), - )) + when defined(rln_v2): + let wakuRlnConfig2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_5")) + else: + let wakuRlnConfig2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_5")) + await node2.mountRlnRelay(wakuRlnConfig2) await node2.start() # node 3 await node3.mountRelay(@[DefaultPubsubTopic]) - await node3.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(3.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_6"), - )) - + when defined(rln_v2): + let wakuRlnConfig3 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(3.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_6")) + else: + let wakuRlnConfig3 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(3.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_6")) + await node3.mountRlnRelay(wakuRlnConfig3) await node3.start() # connect them together @@ -261,14 +314,13 @@ procSuite "WakuNode - RLN relay": when defined(rln_v2): let nonceManager = node1.wakuRlnRelay.nonceManager - let rateLimitProofRes = node1.wakuRlnRelay.groupManager.generateProof(input, + let rateLimitProofRes = node1.wakuRlnRelay.groupManager.generateProof(concat(input, extraBytes), epoch, MessageId(0)) else: let rateLimitProofRes = node1.wakuRlnRelay.groupManager.generateProof(concat(input, extraBytes), # we add extra bytes to invalidate proof verification against original payload epoch) - require: - rateLimitProofRes.isOk() + assert rateLimitProofRes.isOk(), $rateLimitProofRes.error # check the proof is generated correctly outside when block to avoid duplication let rateLimitProof = rateLimitProofRes.get().encode().buffer let message = WakuMessage(payload: @payload, @@ -311,11 +363,18 @@ procSuite "WakuNode - RLN relay": await node1.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - await node1.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(1.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_7"), - )) + when defined(rln_v2): + let wakuRlnConfig1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_7")) + else: + let wakuRlnConfig1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_7")) + await node1.mountRlnRelay(wakuRlnConfig1) await node1.start() @@ -323,23 +382,36 @@ procSuite "WakuNode - RLN relay": await node2.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - await node2.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(2.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_8"), - )) - + when defined(rln_v2): + let wakuRlnConfig2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_8")) + else: + let wakuRlnConfig2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_8")) + await node2.mountRlnRelay(wakuRlnConfig2) await node2.start() # node 3 await node3.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - await node3.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(3.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_9"), - )) + when defined(rln_v2): + let wakuRlnConfig3 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(3.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_9")) + else: + let wakuRlnConfig3 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(3.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_9")) + await node3.mountRlnRelay(wakuRlnConfig3) await node3.start() @@ -352,20 +424,18 @@ procSuite "WakuNode - RLN relay": # create some messages with rate limit proofs var wm1 = WakuMessage(payload: "message 1".toBytes(), contentTopic: contentTopic) - proofAdded1 = node3.wakuRlnRelay.appendRLNProof(wm1, time) # another message in the same epoch as wm1, it will break the messaging rate limit wm2 = WakuMessage(payload: "message 2".toBytes(), contentTopic: contentTopic) - proofAdded2 = node3.wakuRlnRelay.appendRLNProof(wm2, time) # wm3 points to the next epoch wm3 = WakuMessage(payload: "message 3".toBytes(), contentTopic: contentTopic) - proofAdded3 = node3.wakuRlnRelay.appendRLNProof(wm3, time+float64(node3.wakuRlnRelay.rlnEpochSizeSec)) wm4 = WakuMessage(payload: "message 4".toBytes(), contentTopic: contentTopic) - - # check proofs are added correctly - check: - proofAdded1.isOk() - proofAdded2.isOk() - proofAdded3.isOk() + + node3.wakuRlnRelay.unsafeAppendRLNProof(wm1, time).isOkOr: + raiseAssert $error + node3.wakuRlnRelay.unsafeAppendRLNProof(wm2, time).isOkOr: + raiseAssert $error + node3.wakuRlnRelay.unsafeAppendRLNProof(wm3, time+float64(node3.wakuRlnRelay.rlnEpochSizeSec)).isOkOr: + raiseAssert $error # relay handler for node3 var completionFut1 = newFuture[bool]() @@ -434,11 +504,18 @@ procSuite "WakuNode - RLN relay": await node1.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - await node1.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(1.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_10"), - )) + when defined(rln_v2): + let wakuRlnConfig1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_10")) + else: + let wakuRlnConfig1 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_10")) + await node1.mountRlnRelay(wakuRlnConfig1) await node1.start() @@ -446,11 +523,18 @@ procSuite "WakuNode - RLN relay": await node2.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - await node2.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, - rlnRelayCredIndex: some(2.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_11"), - )) + when defined(rln_v2): + let wakuRlnConfig2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_11")) + else: + let wakuRlnConfig2 = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_11")) + await node2.mountRlnRelay(wakuRlnConfig2) await node2.start() @@ -461,19 +545,17 @@ procSuite "WakuNode - RLN relay": # create some messages with rate limit proofs var wm1 = WakuMessage(payload: "message 1".toBytes(), contentTopic: contentTopic) - proofAdded1 = node1.wakuRlnRelay.appendRLNProof(wm1, time) # another message in the same epoch as wm1, it will break the messaging rate limit wm2 = WakuMessage(payload: "message 2".toBytes(), contentTopic: contentTopic) - proofAdded2 = node1.wakuRlnRelay.appendRLNProof(wm2, time) # wm3 points to the next epoch wm3 = WakuMessage(payload: "message 3".toBytes(), contentTopic: contentTopic) - proofAdded3 = node1.wakuRlnRelay.appendRLNProof(wm3, time + float64(node1.wakuRlnRelay.rlnEpochSizeSec * 2)) - # check proofs are added correctly - check: - proofAdded1.isOk() - proofAdded2.isOk() - proofAdded3.isOk() + node1.wakuRlnRelay.unsafeAppendRLNProof(wm1, time).isOkOr: + raiseAssert $error + node1.wakuRlnRelay.unsafeAppendRLNProof(wm2, time).isOkOr: + raiseAssert $error + node1.wakuRlnRelay.unsafeAppendRLNProof(wm3, time + float64(node1.wakuRlnRelay.rlnEpochSizeSec * 2)).isOkOr: + raiseAssert $error # relay handler for node2 var completionFut1 = newFuture[bool]() diff --git a/tests/wakunode_rest/test_rest_relay.nim b/tests/wakunode_rest/test_rest_relay.nim index 9ec2485af..a287c0329 100644 --- a/tests/wakunode_rest/test_rest_relay.nim +++ b/tests/wakunode_rest/test_rest_relay.nim @@ -208,10 +208,18 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - await node.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, + when defined(rln_v2): + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + else: + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint), rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"))) + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup var restPort = Port(0) @@ -411,10 +419,18 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - await node.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, + when defined(rln_v2): + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + else: + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint), rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"))) + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup var restPort = Port(0) @@ -456,10 +472,18 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - await node.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, + when defined(rln_v2): + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + else: + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint), rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"))) + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup var restPort = Port(0) @@ -496,10 +520,18 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - await node.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, + when defined(rln_v2): + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + else: + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint), rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"))) + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup var restPort = Port(0) @@ -541,10 +573,18 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - await node.mountRlnRelay(WakuRlnConfig(rlnRelayDynamic: false, + when defined(rln_v2): + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + else: + let wakuRlnConfig = WakuRlnConfig(rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint), rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"))) + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1")) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup var restPort = Port(0) diff --git a/waku/waku_api/rest/relay/handlers.nim b/waku/waku_api/rest/relay/handlers.nim index d3efa0278..00e94caa7 100644 --- a/waku/waku_api/rest/relay/handlers.nim +++ b/waku/waku_api/rest/relay/handlers.nim @@ -132,7 +132,7 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes # append the proof to the message node.wakuRlnRelay.appendRLNProof(message, float64(getTime().toUnix())).isOkOr: - return RestApiResponse.internalServerError("Failed to publish: error appending RLN proof to message") + return RestApiResponse.internalServerError("Failed to publish: error appending RLN proof to message: " & $error) (await node.wakuRelay.validateMessage(pubsubTopic, message)).isOkOr: return RestApiResponse.badRequest("Failed to publish: " & error) @@ -220,7 +220,7 @@ proc installRelayApiHandlers*(router: var RestRouter, node: WakuNode, cache: Mes if not node.wakuRlnRelay.isNil(): node.wakuRlnRelay.appendRLNProof(message, float64(getTime().toUnix())).isOkOr: return RestApiResponse.internalServerError( - "Failed to publish: error appending RLN proof to message") + "Failed to publish: error appending RLN proof to message: " & $error) (await node.wakuRelay.validateMessage(pubsubTopic, message)).isOkOr: return RestApiResponse.badRequest("Failed to publish: " & error) diff --git a/waku/waku_rln_relay/conversion_utils.nim b/waku/waku_rln_relay/conversion_utils.nim index 814eb98af..f1bd7b6cd 100644 --- a/waku/waku_rln_relay/conversion_utils.nim +++ b/waku/waku_rln_relay/conversion_utils.nim @@ -149,7 +149,7 @@ proc serialize*(memIndices: seq[MembershipIndex]): seq[byte] = proc toEpoch*(t: uint64): Epoch = ## converts `t` to `Epoch` in little-endian order let bytes = toBytes(t, Endianness.littleEndian) - debug "bytes", bytes = bytes + trace "epoch bytes", bytes = bytes var epoch: Epoch discard epoch.copyFrom(bytes) return epoch diff --git a/waku/waku_rln_relay/nonce_manager.nim b/waku/waku_rln_relay/nonce_manager.nim index e41e7ce4a..13f8ae546 100644 --- a/waku/waku_rln_relay/nonce_manager.nim +++ b/waku/waku_rln_relay/nonce_manager.nim @@ -43,9 +43,9 @@ proc `$`*(ne: NonceManagerError): string = of NonceLimitReached: return "NonceLimitReached: " & ne.error -proc init*(T: type NonceManager, nonceLimit: Nonce): T = +proc init*(T: type NonceManager, nonceLimit: Nonce, epoch = 1.float64): T = return NonceManager( - epoch: 0, + epoch: epoch, nextNonce: 0, lastNonceTime: 0, nonceLimit: nonceLimit @@ -62,6 +62,6 @@ proc getNonce*(n: NonceManager): NonceManagerResult[Nonce] = if retNonce >= n.nonceLimit: return err(NonceManagerError(kind: NonceLimitReached, - error: "Nonce limit reached. Please wait for the next epoch")) + error: "Nonce limit reached. Please wait for the next epoch. requested nonce: " & $retNonce & " & nonceLimit: " & $n.nonceLimit)) return ok(retNonce) diff --git a/waku/waku_rln_relay/rln/wrappers.nim b/waku/waku_rln_relay/rln/wrappers.nim index 675918fcf..ae83db052 100644 --- a/waku/waku_rln_relay/rln/wrappers.nim +++ b/waku/waku_rln_relay/rln/wrappers.nim @@ -163,7 +163,11 @@ proc poseidon*(data: seq[seq[byte]]): RlnRelayResult[array[32, byte]] = when defined(rln_v2): proc toLeaf*(rateCommitment: RateCommitment): RlnRelayResult[seq[byte]] = let idCommitment = rateCommitment.idCommitment - let userMessageLimit = cast[array[32, byte]](rateCommitment.userMessageLimit) + var userMessageLimit: array[32, byte] + try: + discard userMessageLimit.copyFrom(toBytes(rateCommitment.userMessageLimit, Endianness.littleEndian)) + except CatchableError: + return err("could not convert the user message limit to bytes: " & getCurrentExceptionMsg()) let leaf = poseidon(@[@idCommitment, @userMessageLimit]).valueOr: return err("could not convert the rate commitment to a leaf") var retLeaf = newSeq[byte](leaf.len) @@ -179,27 +183,16 @@ when defined(rln_v2): leaves.add(leaf) return ok(leaves) - # TODO: collocate this proc with the definition of the RateLimitProof - # and the ProofMetadata types - proc extractMetadata*(proof: RateLimitProof): RlnRelayResult[ProofMetadata] = - return ok(ProofMetadata( - nullifier: proof.nullifier, - shareX: proof.shareX, - shareY: proof.shareY, - externalNullifier: proof.externalNullifier - )) -else: - proc extractMetadata*(proof: RateLimitProof): RlnRelayResult[ProofMetadata] = - let externalNullifierRes = poseidon(@[@(proof.epoch), - @(proof.rlnIdentifier)]) - if externalNullifierRes.isErr(): - return err("could not construct the external nullifier") - return ok(ProofMetadata( - nullifier: proof.nullifier, - shareX: proof.shareX, - shareY: proof.shareY, - externalNullifier: externalNullifierRes.get() - )) +proc extractMetadata*(proof: RateLimitProof): RlnRelayResult[ProofMetadata] = + let externalNullifier = poseidon(@[@(proof.epoch), + @(proof.rlnIdentifier)]).valueOr: + return err("could not construct the external nullifier") + return ok(ProofMetadata( + nullifier: proof.nullifier, + shareX: proof.shareX, + shareY: proof.shareY, + externalNullifier: externalNullifier + )) when defined(rln_v2): proc proofGen*(rlnInstance: ptr RLN, @@ -266,6 +259,8 @@ when defined(rln_v2): let output = RateLimitProof(proof: zkproof, merkleRoot: proofRoot, externalNullifier: externalNullifier, + epoch: epoch, + rlnIdentifier: rlnIdentifier, shareX: shareX, shareY: shareY, nullifier: nullifier) @@ -339,8 +334,15 @@ proc proofVerify*(rlnInstance: ptr RLN, validRoots: seq[MerkleNode] = @[]): RlnRelayResult[bool] = ## verifies the proof, returns an error if the proof verification fails ## returns true if the proof is valid + var normalizedProof = proof + when defined(rln_v2): + # when we do this, we ensure that we compute the proof for the derived value + # of the externalNullifier. The proof verification will fail if a malicious peer + # attaches invalid epoch+rlnidentifier pair + normalizedProof.externalNullifier = poseidon(@[@(proof.epoch), @(proof.rlnIdentifier)]).valueOr: + return err("could not construct the external nullifier") var - proofBytes = serialize(proof, data) + proofBytes = serialize(normalizedProof, data) proofBuffer = proofBytes.toBuffer() validProof: bool rootsBytes = serialize(validRoots) diff --git a/waku/waku_rln_relay/rln_relay.nim b/waku/waku_rln_relay/rln_relay.nim index d0a4583da..5e690f47d 100644 --- a/waku/waku_rln_relay/rln_relay.nim +++ b/waku/waku_rln_relay/rln_relay.nim @@ -408,7 +408,7 @@ proc mount(conf: WakuRlnConfig, when defined(rln_v2): return WakuRLNRelay(groupManager: groupManager, - nonceManager: NonceManager.init(conf.rlnRelayUserMessageLimit), + nonceManager: NonceManager.init(conf.rlnRelayUserMessageLimit, conf.rlnEpochSizeSec.float), rlnEpochSizeSec: conf.rlnEpochSizeSec, rlnMaxEpochGap: uint64(MaxClockGapSeconds/float64(conf.rlnEpochSizeSec)), onFatalErrorAction: conf.onFatalErrorAction)