From a02832fe1296d2deb8d8c874fb13287cbc3ec143 Mon Sep 17 00:00:00 2001 From: Aaryamann Challani <43716372+rymnc@users.noreply.github.com> Date: Thu, 20 Jun 2024 15:05:21 +0530 Subject: [PATCH 01/11] feat(rlnv2): clean fork of rlnv2 (#2828) * chore(rlnv2): contract interface changes (#2770) * fix: tests * fix: remove stuint[32] * chore(submodule): update zerokit submodule to v0.5.1 (#2782) * fix: remove cond comp for lightpush test * fix: ci and nonceManager --- .github/workflows/ci.yml | 10 +- .github/workflows/container-image.yml | 7 +- .gitmodules | 2 +- Makefile | 17 +- apps/chat2/chat2.nim | 31 +- scripts/build_rln.sh | 6 +- tests/node/test_wakunode_lightpush.nim | 23 +- tests/waku_relay/utils.nim | 70 +-- .../rln/waku_rln_relay_utils.nim | 13 +- tests/waku_rln_relay/test_all.nim | 6 +- .../test_rln_group_manager_onchain.nim | 309 ++++-------- .../test_rln_group_manager_static.nim | 60 +-- ..._relay_v2_serde.nim => test_rln_serde.nim} | 8 +- tests/waku_rln_relay/test_waku_rln_relay.nim | 81 ++- .../test_wakunode_rln_relay.nim | 292 ++++------- tests/wakunode_rest/test_rest_relay.nim | 115 ++--- .../rln_keystore_generator.nim | 34 +- vendor/zerokit | 2 +- waku/factory/node_factory.nim | 37 +- waku/waku_keystore/protocol_types.nim | 57 +-- waku/waku_rln_relay/constants.nim | 25 +- waku/waku_rln_relay/contract.nim | 29 +- waku/waku_rln_relay/conversion_utils.nim | 101 ++-- .../group_manager/group_manager_base.nim | 175 +++---- .../group_manager/on_chain/group_manager.nim | 465 ++++++------------ .../group_manager/static/group_manager.nim | 183 +++---- waku/waku_rln_relay/nonce_manager.nim | 5 +- waku/waku_rln_relay/protocol_types.nim | 23 +- waku/waku_rln_relay/rln/wrappers.nim | 284 ++++------- waku/waku_rln_relay/rln_relay.nim | 57 +-- 30 files changed, 856 insertions(+), 1671 deletions(-) rename tests/waku_rln_relay/{rln_v2/test_rln_relay_v2_serde.nim => test_rln_serde.nim} (94%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 025ef880d7..1745146a09 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,12 +54,11 @@ jobs: strategy: fail-fast: false matrix: - rln_version: [1, 2] os: [ubuntu-latest, macos-13] runs-on: ${{ matrix.os }} timeout-minutes: 60 - name: build-${{ matrix.os }}-rln-v${{ matrix.rln_version }} + name: build-${{ matrix.os }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -78,7 +77,7 @@ jobs: key: ${{ runner.os }}-vendor-modules-${{ steps.submodules.outputs.hash }} - name: Build binaries - run: make RLN_V${{matrix.rln_version}}=true V=1 QUICK_AND_DIRTY_COMPILER=1 all tools + run: make V=1 QUICK_AND_DIRTY_COMPILER=1 all tools test: needs: changes @@ -86,12 +85,11 @@ jobs: strategy: fail-fast: false matrix: - rln_version: [1, 2] os: [ubuntu-latest, macos-13] runs-on: ${{ matrix.os }} timeout-minutes: 60 - name: test-${{ matrix.os }}-rln-v${{ matrix.rln_version }} + name: test-${{ matrix.os }} steps: - name: Checkout code uses: actions/checkout@v3 @@ -120,7 +118,7 @@ jobs: export MAKEFLAGS="-j1" export NIMFLAGS="--colors:off -d:chronicles_colors:none" - make RLN_V${{matrix.rln_version}}=true V=1 LOG_LEVEL=DEBUG QUICK_AND_DIRTY_COMPILER=1 POSTGRES=$postgres_enabled test testwakunode2 + make V=1 LOG_LEVEL=DEBUG QUICK_AND_DIRTY_COMPILER=1 POSTGRES=$postgres_enabled test testwakunode2 build-docker-image: needs: changes diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml index acfd078194..99cee03028 100644 --- a/.github/workflows/container-image.yml +++ b/.github/workflows/container-image.yml @@ -22,12 +22,11 @@ jobs: build-docker-image: strategy: matrix: - rln_version : [1, 2] os: [ubuntu-latest] runs-on: ${{ matrix.os }} timeout-minutes: 60 - name: docker-build-${{ matrix.os }}-rln-v${{ matrix.rln_version }} + name: docker-build-${{ matrix.os }} outputs: image: ${{ steps.build.outputs.image }} steps: @@ -67,12 +66,12 @@ jobs: if: ${{ steps.secrets.outcome == 'success' }} run: | - make RLN_V${{matrix.rln_version}}=true -j${NPROC} V=1 QUICK_AND_DIRTY_COMPILER=1 NIMFLAGS="-d:disableMarchNative -d:postgres" wakunode2 + make -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}-rln-v${{matrix.rln_version}} + IMAGE=quay.io/wakuorg/nwaku-pr:${TAG} echo "image=${IMAGE}" >> $GITHUB_OUTPUT echo "commit_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT diff --git a/.gitmodules b/.gitmodules index b829df2947..0a1488063c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -143,7 +143,7 @@ path = vendor/zerokit url = https://github.com/vacp2p/zerokit.git ignore = dirty - branch = v0.3.4 + branch = v0.5.1 [submodule "vendor/nim-regex"] path = vendor/nim-regex url = https://github.com/nitely/nim-regex.git diff --git a/Makefile b/Makefile index edcdf7a9b8..98517e3aa3 100644 --- a/Makefile +++ b/Makefile @@ -136,14 +136,10 @@ clean: | clean-libbacktrace ################## ## RLN ## ################## -.PHONY: librln shouldUseRLNV2 +.PHONY: librln LIBRLN_BUILDDIR := $(CURDIR)/vendor/zerokit -ifeq ($(RLN_V2),true) -LIBRLN_VERSION := v0.4.4 -else -LIBRLN_VERSION := v0.3.7 -endif +LIBRLN_VERSION := v0.5.1 ifeq ($(OS),Windows_NT) LIBRLN_FILE := rln.lib @@ -155,12 +151,7 @@ $(LIBRLN_FILE): echo -e $(BUILD_MSG) "$@" && \ ./scripts/build_rln.sh $(LIBRLN_BUILDDIR) $(LIBRLN_VERSION) $(LIBRLN_FILE) -shouldUseRLNV2: -ifeq ($(RLN_V2),true) - $(eval NIM_PARAMS += -d:rln_v2) -endif - -librln: | $(LIBRLN_FILE) shouldUseRLNV2 +librln: | $(LIBRLN_FILE) $(eval NIM_PARAMS += --passL:$(LIBRLN_FILE) --passL:-lm) clean-librln: @@ -320,7 +311,7 @@ endif rebuild-nat-libs: | clean-cross nat-libs -libwaku-android-precheck: shouldUseRLNV2 +libwaku-android-precheck: ifndef ANDROID_NDK_HOME $(error ANDROID_NDK_HOME is not set) endif diff --git a/apps/chat2/chat2.nim b/apps/chat2/chat2.nim index 64ab61c392..42e2461b1a 100644 --- a/apps/chat2/chat2.nim +++ b/apps/chat2/chat2.nim @@ -542,27 +542,16 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} = echo "rln-relay preparation is in progress..." - when defined(rln_v2): - let rlnConf = WakuRlnConfig( - rlnRelayDynamic: conf.rlnRelayDynamic, - rlnRelayCredIndex: conf.rlnRelayCredIndex, - rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress, - rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress), - rlnRelayCredPath: conf.rlnRelayCredPath, - rlnRelayCredPassword: conf.rlnRelayCredPassword, - rlnRelayUserMessageLimit: conf.rlnRelayUserMessageLimit, - rlnEpochSizeSec: conf.rlnEpochSizeSec, - ) - else: - let rlnConf = WakuRlnConfig( - rlnRelayDynamic: conf.rlnRelayDynamic, - rlnRelayCredIndex: conf.rlnRelayCredIndex, - rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress, - rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress), - rlnRelayCredPath: conf.rlnRelayCredPath, - rlnRelayCredPassword: conf.rlnRelayCredPassword, - rlnEpochSizeSec: conf.rlnEpochSizeSec, - ) + let rlnConf = WakuRlnConfig( + rlnRelayDynamic: conf.rlnRelayDynamic, + rlnRelayCredIndex: conf.rlnRelayCredIndex, + rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress, + rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress), + rlnRelayCredPath: conf.rlnRelayCredPath, + rlnRelayCredPassword: conf.rlnRelayCredPassword, + rlnRelayUserMessageLimit: conf.rlnRelayUserMessageLimit, + rlnEpochSizeSec: conf.rlnEpochSizeSec, + ) waitFor node.mountRlnRelay(rlnConf, spamHandler = some(spamHandler)) diff --git a/scripts/build_rln.sh b/scripts/build_rln.sh index 2a7d9ed381..d4843ca5ed 100755 --- a/scripts/build_rln.sh +++ b/scripts/build_rln.sh @@ -19,9 +19,9 @@ host_triplet=$(rustc --version --verbose | awk '/host:/{print $2}') tarball="${host_triplet}" -# use arkzkey feature for v0.4.4 +# use arkzkey feature for v0.5.1 # TODO: update this script in the future when arkzkey is default -if [[ "${rln_version}" == "v0.4.4" ]]; then +if [[ "${rln_version}" == "v0.5.1" ]]; then tarball+="-arkzkey-rln.tar.gz" else tarball+="-rln.tar.gz" @@ -52,6 +52,6 @@ else exit 1 fi # if submodule version = version in Makefile, build rln - cargo build --release -p rln --manifest-path "${build_dir}/rln/Cargo.toml" + cargo build --release -p rln --manifest-path "${build_dir}/rln/Cargo.toml" --features arkzkey cp "${build_dir}/target/release/librln.a" "${output_filename}" fi diff --git a/tests/node/test_wakunode_lightpush.nim b/tests/node/test_wakunode_lightpush.nim index b5d7a2ea90..0bbfaa88a8 100644 --- a/tests/node/test_wakunode_lightpush.nim +++ b/tests/node/test_wakunode_lightpush.nim @@ -135,21 +135,14 @@ suite "RLN Proofs as a Lightpush Service": client = newTestWakuNode(clientKey, ValidIpAddress.init("0.0.0.0"), Port(0)) # mount rln-relay - when defined(rln_v2): - let wakuRlnConfig = WakuRlnConfig( - rlnRelayDynamic: false, - rlnRelayCredIndex: some(1.uint), - rlnRelayUserMessageLimit: 1, - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode"), - ) - else: - let wakuRlnConfig = WakuRlnConfig( - rlnRelayDynamic: false, - rlnRelayCredIndex: some(1.uint), - rlnEpochSizeSec: 1, - rlnRelayTreePath: genTempPath("rln_tree", "wakunode"), - ) + let wakuRlnConfig = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode"), + ) + await allFutures(server.start(), client.start()) await server.start() diff --git a/tests/waku_relay/utils.nim b/tests/waku_relay/utils.nim index 0826cd2f4b..2e44189d12 100644 --- a/tests/waku_relay/utils.nim +++ b/tests/waku_relay/utils.nim @@ -95,51 +95,25 @@ proc sendRlnMessage*( let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) return isCompleted -when defined(rln_v2): - proc sendRlnMessageWithInvalidProof*( - client: WakuNode, - pubsubTopic: string, - contentTopic: string, - completionFuture: Future[bool], - payload: seq[byte] = "Hello".toBytes(), - ): Future[bool] {.async.} = - let - extraBytes: seq[byte] = @[byte(1), 2, 3] - rateLimitProofRes = client.wakuRlnRelay.groupManager.generateProof( - concat(payload, extraBytes), - # we add extra bytes to invalidate proof verification against original payload - client.wakuRlnRelay.getCurrentEpoch(), - messageId = MessageId(0), - ) - rateLimitProof = rateLimitProofRes.get().encode().buffer - message = WakuMessage( - payload: @payload, contentTopic: contentTopic, proof: rateLimitProof - ) - - discard await client.publish(some(pubsubTopic), message) - let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) - return isCompleted - -else: - proc sendRlnMessageWithInvalidProof*( - client: WakuNode, - pubsubTopic: string, - contentTopic: string, - completionFuture: Future[bool], - payload: seq[byte] = "Hello".toBytes(), - ): Future[bool] {.async.} = - let - extraBytes: seq[byte] = @[byte(1), 2, 3] - rateLimitProofRes = client.wakuRlnRelay.groupManager.generateProof( - concat(payload, extraBytes), - # we add extra bytes to invalidate proof verification against original payload - client.wakuRlnRelay.getCurrentEpoch(), - ) - rateLimitProof = rateLimitProofRes.get().encode().buffer - message = WakuMessage( - payload: @payload, contentTopic: contentTopic, proof: rateLimitProof - ) - - discard await client.publish(some(pubsubTopic), message) - let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) - return isCompleted +proc sendRlnMessageWithInvalidProof*( + client: WakuNode, + pubsubTopic: string, + contentTopic: string, + completionFuture: Future[bool], + payload: seq[byte] = "Hello".toBytes(), +): Future[bool] {.async.} = + let + extraBytes: seq[byte] = @[byte(1), 2, 3] + rateLimitProofRes = client.wakuRlnRelay.groupManager.generateProof( + concat(payload, extraBytes), + # we add extra bytes to invalidate proof verification against original payload + client.wakuRlnRelay.getCurrentEpoch(), + messageId = MessageId(0), + ) + rateLimitProof = rateLimitProofRes.get().encode().buffer + message = + WakuMessage(payload: @payload, contentTopic: contentTopic, proof: rateLimitProof) + + discard await client.publish(some(pubsubTopic), message) + let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) + return isCompleted 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 e25f98212f..ab3807983f 100644 --- a/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim +++ b/tests/waku_rln_relay/rln/waku_rln_relay_utils.nim @@ -14,14 +14,11 @@ proc unsafeAppendRLNProof*( 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) + # 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) + msg.proof = proof.encode().buffer return ok() diff --git a/tests/waku_rln_relay/test_all.nim b/tests/waku_rln_relay/test_all.nim index 7aa3f395ec..fe23eb9fe9 100644 --- a/tests/waku_rln_relay/test_all.nim +++ b/tests/waku_rln_relay/test_all.nim @@ -5,7 +5,5 @@ import ./test_rln_group_manager_static, ./test_waku_rln_relay, ./test_wakunode_rln_relay, - ./test_rln_nonce_manager - -when defined(rln_v2): - import ./rln_v2/test_rln_relay_v2_serde + ./test_rln_nonce_manager, + ./test_rln_serde diff --git a/tests/waku_rln_relay/test_rln_group_manager_onchain.nim b/tests/waku_rln_relay/test_rln_group_manager_onchain.nim index 571a30ed01..94b1ed213e 100644 --- a/tests/waku_rln_relay/test_rln_group_manager_onchain.nim +++ b/tests/waku_rln_relay/test_rln_group_manager_onchain.nim @@ -30,13 +30,12 @@ proc generateCredentials(rlnInstance: ptr RLN): IdentityCredential = let credRes = membershipKeyGen(rlnInstance) return credRes.get() -when defined(rln_v2): - proc getRateCommitment( - idCredential: IdentityCredential, userMessageLimit: UserMessageLimit - ): RateCommitment = - return RateCommitment( - idCommitment: idCredential.idCommitment, userMessageLimit: userMessageLimit - ) +proc getRateCommitment( + idCredential: IdentityCredential, userMessageLimit: UserMessageLimit +): RlnRelayResult[RawRateCommitment] = + return RateCommitment( + idCommitment: idCredential.idCommitment, userMessageLimit: userMessageLimit + ).toLeaf() proc generateCredentials(rlnInstance: ptr RLN, n: int): seq[IdentityCredential] = var credentials: seq[IdentityCredential] @@ -61,48 +60,38 @@ proc uploadRLNContract*(ethClientAddress: string): Future[Address] {.async.} = let balance = await web3.provider.eth_getBalance(web3.defaultAccount, "latest") debug "Initial account balance: ", balance - when defined(rln_v2): - # deploy registry contract with its constructor inputs - let receipt = await web3.deployContract(RegistryContractCode) - else: - # deploy the poseidon hash contract and gets its address - let - hasherReceipt = await web3.deployContract(PoseidonHasherCode) - hasherAddress = hasherReceipt.contractAddress.get - debug "hasher address: ", hasherAddress - - # encode registry contract inputs to 32 bytes zero-padded - let - hasherAddressEncoded = encode(hasherAddress).data - # this is the contract constructor input - contractInput = hasherAddressEncoded + # deploy poseidon hasher bytecode + let poseidonT3Receipt = await web3.deployContract(PoseidonT3) + let poseidonT3Address = poseidonT3Receipt.contractAddress.get() + let poseidonAddressStripped = strip0xPrefix($poseidonT3Address) - debug "encoded hasher address: ", hasherAddressEncoded - debug "encoded contract input:", contractInput + # deploy lazy imt bytecode + let lazyImtReceipt = await web3.deployContract(LazyIMT.replace("__$PoseidonT3$__", poseidonAddressStripped)) + let lazyImtAddress = lazyImtReceipt.contractAddress.get() + let lazyImtAddressStripped = strip0xPrefix($lazyImtAddress) - # deploy registry contract with its constructor inputs - let receipt = - await web3.deployContract(RegistryContractCode, contractInput = contractInput) + # deploy waku rlnv2 contract + let wakuRlnContractReceipt = await web3.deployContract(WakuRlnV2Contract.replace("__$PoseidonT3$__", poseidonAddressStripped).replace("__$LazyIMT$__", lazyImtAddressStripped)) + let wakuRlnContractAddress = wakuRlnContractReceipt.contractAddress.get() + let wakuRlnAddressStripped = strip0xPrefix($wakuRlnContractAddress) - let contractAddress = receipt.contractAddress.get() + debug "Address of the deployed rlnv2 contract: ", wakuRlnContractAddress - debug "Address of the deployed registry contract: ", contractAddress + # need to send concat: impl & init_bytes + let contractInput = encode(wakuRlnContractAddress).data & Erc1967ProxyContractInput + debug "contractInput", contractInput + let proxyReceipt = await web3.deployContract(Erc1967Proxy, contractInput = contractInput) + + debug "proxy receipt", proxyReceipt + let proxyAddress = proxyReceipt.contractAddress.get() - let registryContract = web3.contractSender(WakuRlnRegistry, contractAddress) - when defined(rln_v2): - let initReceipt = await registryContract.initialize().send() - let newStorageReceipt = await registryContract.newStorage(20.u256).send() - else: - let newStorageReceipt = await registryContract.newStorage().send() - - debug "Receipt of the newStorage transaction: ", newStorageReceipt let newBalance = await web3.provider.eth_getBalance(web3.defaultAccount, "latest") debug "Account balance after the contract deployment: ", newBalance await web3.close() debug "disconnected from ", ethClientAddress - return contractAddress + return proxyAddress proc createEthAccount(): Future[(keys.PrivateKey, Address)] {.async.} = let web3 = await newWeb3(EthClient) @@ -187,7 +176,7 @@ proc stopAnvil(runAnvil: Process) {.used.} = proc setup(): Future[OnchainGroupManager] {.async.} = let rlnInstanceRes = createRlnInstance(tree_path = genTempPath("rln_tree", "group_manager_onchain")) - require: + check: rlnInstanceRes.isOk() let rlnInstance = rlnInstanceRes.get() @@ -223,8 +212,7 @@ suite "Onchain group manager": check: manager.ethRpc.isSome() - manager.rlnContract.isSome() - manager.membershipFee.isSome() + manager.wakuRlnContract.isSome() manager.initialized manager.rlnContractDeployedBlockNumber > 0 @@ -287,6 +275,8 @@ suite "Onchain group manager": asyncTest "startGroupSync: should sync to the state of the group": let manager = await setup() let credentials = generateCredentials(manager.rlnInstance) + let rateCommitment = getRateCommitment(credentials, UserMessageLimit(1)).valueOr: + raiseAssert $error (await manager.init()).isOkOr: raiseAssert $error @@ -297,28 +287,17 @@ suite "Onchain group manager": proc generateCallback(fut: Future[void]): OnRegisterCallback = proc callback(registrations: seq[Membership]): Future[void] {.async.} = - require: + check: registrations.len == 1 registrations[0].index == 0 - when defined(rln_v2): - require: - registrations[0].rateCommitment == - getRateCommitment(credentials, UserMessageLimit(1)) - else: - require: - registrations[0].idCommitment == credentials.idCommitment - require: - registrations[0].index == 0 + registrations[0].rateCommitment == rateCommitment fut.complete() return callback try: manager.onRegister(generateCallback(fut)) - when defined(rln_v2): - await manager.register(credentials, UserMessageLimit(1)) - else: - await manager.register(credentials) + await manager.register(credentials, UserMessageLimit(1)) (await manager.startGroupSync()).isOkOr: raiseAssert $error except Exception, CatchableError: @@ -355,19 +334,12 @@ suite "Onchain group manager": ): OnRegisterCallback = var futureIndex = 0 proc callback(registrations: seq[Membership]): Future[void] {.async.} = - when defined(rln_v2): - if registrations.len == 1 and - registrations[0].rateCommitment == - getRateCommitment(credentials[futureIndex], UserMessageLimit(1)) and - registrations[0].index == MembershipIndex(futureIndex): - futs[futureIndex].complete() - futureIndex += 1 - else: - if registrations.len == 1 and - registrations[0].idCommitment == credentials[futureIndex].idCommitment and - registrations[0].index == MembershipIndex(futureIndex): - futs[futureIndex].complete() - futureIndex += 1 + let rateCommitment = getRateCommitment(credentials[futureIndex], UserMessageLimit(1)) + if registrations.len == 1 and + registrations[0].rateCommitment == rateCommitment.get() and + registrations[0].index == MembershipIndex(futureIndex): + futs[futureIndex].complete() + futureIndex += 1 return callback @@ -377,10 +349,7 @@ suite "Onchain group manager": raiseAssert $error for i in 0 ..< credentials.len(): - when defined(rln_v2): - await manager.register(credentials[i], UserMessageLimit(1)) - else: - await manager.register(credentials[i]) + await manager.register(credentials[i], UserMessageLimit(1)) except Exception, CatchableError: assert false, "exception raised: " & getCurrentExceptionMsg() @@ -399,14 +368,11 @@ suite "Onchain group manager": let dummyCommitment = default(IDCommitment) try: - when defined(rln_v2): - await manager.register( - RateCommitment( - idCommitment: dummyCommitment, userMessageLimit: UserMessageLimit(1) - ) + await manager.register( + RateCommitment( + idCommitment: dummyCommitment, userMessageLimit: UserMessageLimit(1) ) - else: - await manager.register(dummyCommitment) + ) except CatchableError: assert true except Exception: @@ -426,14 +392,11 @@ suite "Onchain group manager": raiseAssert $error try: - when defined(rln_v2): - await manager.register( - RateCommitment( - idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1) - ) + await manager.register( + RateCommitment( + idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1) ) - else: - await manager.register(idCommitment) + ) except Exception, CatchableError: assert false, "exception raised when calling register: " & getCurrentExceptionMsg() @@ -448,23 +411,16 @@ suite "Onchain group manager": asyncTest "register: callback is called": let manager = await setup() - let idCommitment = generateCredentials(manager.rlnInstance).idCommitment + let idCredentials = generateCredentials(manager.rlnInstance) + let idCommitment = idCredentials.idCommitment let fut = newFuture[void]() proc callback(registrations: seq[Membership]): Future[void] {.async.} = - require: + let rateCommitment = getRateCommitment(idCredentials, UserMessageLimit(1)) + check: registrations.len == 1 - when defined(rln_v2): - require: - registrations[0].rateCommitment == - RateCommitment( - idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1) - ) - else: - require: - registrations[0].idCommitment == idCommitment - require: + registrations[0].rateCommitment == rateCommitment.get() registrations[0].index == 0 fut.complete() @@ -474,18 +430,15 @@ suite "Onchain group manager": try: (await manager.startGroupSync()).isOkOr: raiseAssert $error - when defined(rln_v2): - await manager.register( - RateCommitment( - idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1) - ) + await manager.register( + RateCommitment( + idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1) ) - else: - await manager.register(idCommitment) + ) except Exception, CatchableError: assert false, "exception raised: " & getCurrentExceptionMsg() - check await fut.withTimeout(5.seconds) + await fut await manager.stop() @@ -511,29 +464,20 @@ suite "Onchain group manager": let fut = newFuture[void]() proc callback(registrations: seq[Membership]): Future[void] {.async.} = - when defined(rln_v2): - if registrations.len == 1 and - registrations[0].rateCommitment == - getRateCommitment(credentials, UserMessageLimit(1)) and - registrations[0].index == 0: - manager.idCredentials = some(credentials) - fut.complete() - else: - if registrations.len == 1 and - registrations[0].idCommitment == credentials.idCommitment and - registrations[0].index == 0: - manager.idCredentials = some(credentials) - fut.complete() + if registrations.len == 1 and + registrations[0].rateCommitment == + getRateCommitment(credentials, UserMessageLimit(1)).get() and + registrations[0].index == 0: + manager.idCredentials = some(credentials) + fut.complete() + manager.onRegister(callback) try: (await manager.startGroupSync()).isOkOr: raiseAssert $error - when defined(rln_v2): - await manager.register(credentials, UserMessageLimit(1)) - else: - await manager.register(credentials) + await manager.register(credentials, UserMessageLimit(1)) except Exception, CatchableError: assert false, "exception raised: " & getCurrentExceptionMsg() @@ -546,14 +490,11 @@ suite "Onchain group manager": debug "epoch in bytes", epochHex = epoch.inHex() # generate proof - when defined(rln_v2): - let validProofRes = manager.generateProof( - data = messageBytes, epoch = epoch, messageId = MessageId(1) - ) - else: - let validProofRes = manager.generateProof(data = messageBytes, epoch = epoch) + let validProofRes = manager.generateProof( + data = messageBytes, epoch = epoch, messageId = MessageId(1) + ) - require: + check: validProofRes.isOk() let validProof = validProofRes.get() @@ -576,8 +517,7 @@ suite "Onchain group manager": ## Assume the registration occured out of band manager.idCredentials = some(credentials) manager.membershipIndex = some(MembershipIndex(0)) - when defined(rln_v2): - manager.userMessageLimit = some(UserMessageLimit(1)) + manager.userMessageLimit = some(UserMessageLimit(1)) let messageBytes = "Hello".toBytes() @@ -586,15 +526,10 @@ suite "Onchain group manager": debug "epoch in bytes", epochHex = epoch.inHex() # generate proof - when defined(rln_v2): - let validProofRes = manager.generateProof( - data = messageBytes, epoch = epoch, messageId = MessageId(0) - ) - else: - let validProofRes = manager.generateProof(data = messageBytes, epoch = epoch) - require: - validProofRes.isOk() - let validProof = validProofRes.get() + let validProof = manager.generateProof( + data = messageBytes, epoch = epoch, messageId = MessageId(0) + ).valueOr: + raiseAssert $error # validate the root (should be false) let validated = manager.validateRoot(validProof.merkleRoot) @@ -612,29 +547,20 @@ suite "Onchain group manager": let fut = newFuture[void]() proc callback(registrations: seq[Membership]): Future[void] {.async.} = - when defined(rln_v2): - if registrations.len == 1 and - registrations[0].rateCommitment == - getRateCommitment(credentials, UserMessageLimit(1)) and - registrations[0].index == 0: - manager.idCredentials = some(credentials) - fut.complete() - else: - if registrations.len == 1 and - registrations[0].idCommitment == credentials.idCommitment and - registrations[0].index == 0: - manager.idCredentials = some(credentials) - fut.complete() + if registrations.len == 1 and + registrations[0].rateCommitment == + getRateCommitment(credentials, UserMessageLimit(1)).get() and + registrations[0].index == 0: + manager.idCredentials = some(credentials) + fut.complete() + manager.onRegister(callback) try: (await manager.startGroupSync()).isOkOr: raiseAssert $error - when defined(rln_v2): - await manager.register(credentials, UserMessageLimit(1)) - else: - await manager.register(credentials) + await manager.register(credentials, UserMessageLimit(1)) except Exception, CatchableError: assert false, "exception raised: " & getCurrentExceptionMsg() await fut @@ -646,23 +572,16 @@ suite "Onchain group manager": debug "epoch in bytes", epochHex = epoch.inHex() # generate proof - when defined(rln_v2): - let validProofRes = manager.generateProof( - data = messageBytes, epoch = epoch, messageId = MessageId(0) - ) - else: - let validProofRes = manager.generateProof(data = messageBytes, epoch = epoch) - require: - validProofRes.isOk() - let validProof = validProofRes.get() + let validProof = manager.generateProof( + data = messageBytes, epoch = epoch, messageId = MessageId(0) + ).valueOr: + raiseAssert $error # verify the proof (should be true) - let verifiedRes = manager.verifyProof(messageBytes, validProof) - require: - verifiedRes.isOk() + let verified = manager.verifyProof(messageBytes, validProof).valueOr: + raiseAssert $error - check: - verifiedRes.get() + check: verified await manager.stop() asyncTest "verifyProof: should reject invalid proof": @@ -675,10 +594,8 @@ suite "Onchain group manager": let idCredential = generateCredentials(manager.rlnInstance) try: - when defined(rln_v2): - await manager.register(getRateCommitment(idCredential, UserMessageLimit(1))) - else: - await manager.register(idCredential.idCommitment) + await manager.register(RateCommitment(idCommitment: idCredential.idCommitment, + userMessageLimit: UserMessageLimit(1))) except Exception, CatchableError: assert false, "exception raised when calling startGroupSync: " & getCurrentExceptionMsg() @@ -688,8 +605,7 @@ suite "Onchain group manager": ## Assume the registration occured out of band manager.idCredentials = some(idCredential2) manager.membershipIndex = some(MembershipIndex(0)) - when defined(rln_v2): - manager.userMessageLimit = some(UserMessageLimit(1)) + manager.userMessageLimit = some(UserMessageLimit(1)) let messageBytes = "Hello".toBytes() @@ -698,14 +614,11 @@ suite "Onchain group manager": debug "epoch in bytes", epochHex = epoch.inHex() # generate proof - when defined(rln_v2): - let invalidProofRes = manager.generateProof( - data = messageBytes, epoch = epoch, messageId = MessageId(0) - ) - else: - let invalidProofRes = manager.generateProof(data = messageBytes, epoch = epoch) + let invalidProofRes = manager.generateProof( + data = messageBytes, epoch = epoch, messageId = MessageId(0) + ) - require: + check: invalidProofRes.isOk() let invalidProof = invalidProofRes.get() @@ -734,19 +647,12 @@ suite "Onchain group manager": ): OnRegisterCallback = var futureIndex = 0 proc callback(registrations: seq[Membership]): Future[void] {.async.} = - when defined(rln_v2): - if registrations.len == 1 and - registrations[0].rateCommitment == - getRateCommitment(credentials[futureIndex], UserMessageLimit(1)) and - registrations[0].index == MembershipIndex(futureIndex): - futs[futureIndex].complete() - futureIndex += 1 - else: - if registrations.len == 1 and - registrations[0].idCommitment == credentials[futureIndex].idCommitment and - registrations[0].index == MembershipIndex(futureIndex): - futs[futureIndex].complete() - futureIndex += 1 + if registrations.len == 1 and + registrations[0].rateCommitment == + getRateCommitment(credentials[futureIndex], UserMessageLimit(1)).get() and + registrations[0].index == MembershipIndex(futureIndex): + futs[futureIndex].complete() + futureIndex += 1 return callback @@ -756,17 +662,14 @@ suite "Onchain group manager": raiseAssert $error for i in 0 ..< credentials.len(): - when defined(rln_v2): - await manager.register(credentials[i], UserMessageLimit(1)) - else: - await manager.register(credentials[i]) + await manager.register(credentials[i], UserMessageLimit(1)) except Exception, CatchableError: assert false, "exception raised: " & getCurrentExceptionMsg() await allFutures(futures) # At this point, we should have a full root queue, 5 roots, and partial buffer of 1 root - require: + check: manager.validRoots.len() == credentialCount - 1 manager.validRootBuffer.len() == 1 diff --git a/tests/waku_rln_relay/test_rln_group_manager_static.nim b/tests/waku_rln_relay/test_rln_group_manager_static.nim index b6ff5a511a..a9f2a71e4c 100644 --- a/tests/waku_rln_relay/test_rln_group_manager_static.nim +++ b/tests/waku_rln_relay/test_rln_group_manager_static.nim @@ -94,14 +94,11 @@ suite "Static group manager": let dummyCommitment = default(IDCommitment) try: - when defined(rln_v2): - await manager.register( - RateCommitment( - idCommitment: dummyCommitment, userMessageLimit: DefaultUserMessageLimit - ) + await manager.register( + RateCommitment( + idCommitment: dummyCommitment, userMessageLimit: DefaultUserMessageLimit ) - else: - await manager.register(dummyCommitment) + ) except ValueError: assert true except Exception, CatchableError: @@ -117,14 +114,11 @@ suite "Static group manager": let merkleRootBefore = manager.rlnInstance.getMerkleRoot().valueOr: raiseAssert $error try: - when defined(rln_v2): - await manager.register( - RateCommitment( - idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit - ) + await manager.register( + RateCommitment( + idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit ) - else: - await manager.register(idCommitment) + ) except Exception, CatchableError: assert false, "exception raised: " & getCurrentExceptionMsg() let merkleRootAfter = manager.rlnInstance.getMerkleRoot().valueOr: @@ -143,15 +137,10 @@ suite "Static group manager": require: registrations.len == 1 registrations[0].index == 10 - when defined(rln_v2): - require: - registrations[0].rateCommitment == - RateCommitment( - idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit - ) - else: - require: - registrations[0].idCommitment == idCommitment + registrations[0].rateCommitment == + RateCommitment( + idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit + ).toLeaf().get() callbackCalled = true fut.complete() @@ -161,14 +150,11 @@ suite "Static group manager": raiseAssert $error (await manager.startGroupSync()).isOkOr: raiseAssert $error - when defined(rln_v2): - await manager.register( - RateCommitment( - idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit - ) + await manager.register( + RateCommitment( + idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit ) - else: - await manager.register(idCommitment) + ) except Exception, CatchableError: assert false, "exception raised: " & getCurrentExceptionMsg() @@ -215,15 +201,11 @@ suite "Static group manager": require: withdrawals.len == 1 withdrawals[0].index == 0 - when defined(rln_v2): - require: - withdrawals[0].rateCommitment == - RateCommitment( - idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit - ) - else: - require: - withdrawals[0].idCommitment == idCommitment + withdrawals[0].rateCommitment == + RateCommitment( + idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit + ).toLeaf().get() + callbackCalled = true fut.complete() diff --git a/tests/waku_rln_relay/rln_v2/test_rln_relay_v2_serde.nim b/tests/waku_rln_relay/test_rln_serde.nim similarity index 94% rename from tests/waku_rln_relay/rln_v2/test_rln_relay_v2_serde.nim rename to tests/waku_rln_relay/test_rln_serde.nim index fb0d5de65e..b1b57f53c0 100644 --- a/tests/waku_rln_relay/rln_v2/test_rln_relay_v2_serde.nim +++ b/tests/waku_rln_relay/test_rln_serde.nim @@ -6,10 +6,10 @@ else: {.push raises: [].} import - ../rln/waku_rln_relay_utils, - ../../../waku/waku_keystore/protocol_types, - ../../../waku/waku_rln_relay, - ../../../waku/waku_rln_relay/rln + ./rln/waku_rln_relay_utils, + ../../waku/waku_keystore/protocol_types, + ../../waku/waku_rln_relay, + ../../waku/waku_rln_relay/rln import testutils/unittests import stew/results, stint diff --git a/tests/waku_rln_relay/test_waku_rln_relay.nim b/tests/waku_rln_relay/test_waku_rln_relay.nim index ea0e371037..c8f655ad7d 100644 --- a/tests/waku_rln_relay/test_waku_rln_relay.nim +++ b/tests/waku_rln_relay/test_waku_rln_relay.nim @@ -525,14 +525,11 @@ suite "Waku rln relay": let rln = rlnInstance.get() # create a Merkle tree - 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) + let rateCommitments = + groupIDCommitments.mapIt(RateCommitment(idCommitment: it, userMessageLimit: 20)) + let leaves = rateCommitments.toLeaves().valueOr: + raiseAssert $error + let membersAdded = rln.insertMembers(0, leaves) assert membersAdded, "members should be added" let rawRoot = rln.getMerkleRoot().valueOr: @@ -691,21 +688,14 @@ suite "Waku rln relay": asyncTest "validateMessageAndUpdateLog test": let index = MembershipIndex(5) - 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 wakuRlnConfig = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(index), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_2"), + ) + let wakuRlnRelay = (await WakuRlnRelay.new(wakuRlnConfig)).valueOr: raiseAssert $error @@ -749,40 +739,25 @@ suite "Waku rln relay": let index1 = MembershipIndex(5) let index2 = MembershipIndex(6) - 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 rlnConf1 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(index1), + rlnRelayUserMessageLimit: 1, + 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 - 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 rlnConf2 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(index2), + rlnRelayUserMessageLimit: 1, + 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 diff --git a/tests/waku_rln_relay/test_wakunode_rln_relay.nim b/tests/waku_rln_relay/test_wakunode_rln_relay.nim index d9f705945a..9a25f21ad8 100644 --- a/tests/waku_rln_relay/test_wakunode_rln_relay.nim +++ b/tests/waku_rln_relay/test_wakunode_rln_relay.nim @@ -40,21 +40,14 @@ procSuite "WakuNode - RLN relay": await node1.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - 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"), - ) + let wakuRlnConfig1 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode"), + ) + await node1.mountRlnRelay(wakuRlnConfig1) await node1.start() @@ -62,21 +55,14 @@ procSuite "WakuNode - RLN relay": # node 2 await node2.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - 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"), - ) + let wakuRlnConfig2 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_2"), + ) + await node2.mountRlnRelay(wakuRlnConfig2) await node2.start() @@ -84,21 +70,14 @@ procSuite "WakuNode - RLN relay": # node 3 await node3.mountRelay(@[DefaultPubsubTopic]) - 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"), - ) + let wakuRlnConfig3 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(3.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_3"), + ) + await node3.mountRlnRelay(wakuRlnConfig3) await node3.start() @@ -162,21 +141,14 @@ procSuite "WakuNode - RLN relay": # mount rlnrelay in off-chain mode for index, node in nodes: - 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)), - ) + let wakuRlnConfig = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(index.uint + 1), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $(index + 1)), + ) + await node.mountRlnRelay(wakuRlnConfig) # start them @@ -263,21 +235,14 @@ procSuite "WakuNode - RLN relay": await node1.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - 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"), - ) + let wakuRlnConfig1 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_4"), + ) + await node1.mountRlnRelay(wakuRlnConfig1) await node1.start() @@ -285,21 +250,14 @@ procSuite "WakuNode - RLN relay": # node 2 await node2.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - 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"), - ) + let wakuRlnConfig2 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_5"), + ) + await node2.mountRlnRelay(wakuRlnConfig2) await node2.start() @@ -307,21 +265,14 @@ procSuite "WakuNode - RLN relay": # node 3 await node3.mountRelay(@[DefaultPubsubTopic]) - 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"), - ) + let wakuRlnConfig3 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(3.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_6"), + ) + await node3.mountRlnRelay(wakuRlnConfig3) await node3.start() @@ -354,17 +305,11 @@ procSuite "WakuNode - RLN relay": input = concat(payload, contentTopicBytes) extraBytes: seq[byte] = @[byte(1), 2, 3] - when defined(rln_v2): - let nonceManager = node1.wakuRlnRelay.nonceManager - 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, - ) + let nonceManager = node1.wakuRlnRelay.nonceManager + let rateLimitProofRes = node1.wakuRlnRelay.groupManager.generateProof( + concat(input, extraBytes), epoch, MessageId(0) + ) + assert rateLimitProofRes.isOk(), $rateLimitProofRes.error # check the proof is generated correctly outside when block to avoid duplication let rateLimitProof = rateLimitProofRes.get().encode().buffer @@ -406,21 +351,14 @@ procSuite "WakuNode - RLN relay": await node1.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - 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"), - ) + let wakuRlnConfig1 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_7"), + ) + await node1.mountRlnRelay(wakuRlnConfig1) await node1.start() @@ -429,21 +367,14 @@ procSuite "WakuNode - RLN relay": await node2.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - 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"), - ) + let wakuRlnConfig2 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_8"), + ) + await node2.mountRlnRelay(wakuRlnConfig2) await node2.start() @@ -451,21 +382,14 @@ procSuite "WakuNode - RLN relay": await node3.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - 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"), - ) + let wakuRlnConfig3 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(3.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_9"), + ) + await node3.mountRlnRelay(wakuRlnConfig3) await node3.start() @@ -562,21 +486,14 @@ procSuite "WakuNode - RLN relay": await node1.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - 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"), - ) + let wakuRlnConfig1 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_10"), + ) + await node1.mountRlnRelay(wakuRlnConfig1) await node1.start() @@ -585,21 +502,14 @@ procSuite "WakuNode - RLN relay": await node2.mountRelay(@[DefaultPubsubTopic]) # mount rlnrelay in off-chain mode - 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"), - ) + let wakuRlnConfig2 = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(2.uint), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_11"), + ) + await node2.mountRlnRelay(wakuRlnConfig2) await node2.start() diff --git a/tests/wakunode_rest/test_rest_relay.nim b/tests/wakunode_rest/test_rest_relay.nim index 36bea003da..c672ee6e4f 100644 --- a/tests/wakunode_rest/test_rest_relay.nim +++ b/tests/wakunode_rest/test_rest_relay.nim @@ -219,21 +219,14 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - 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"), - ) + let wakuRlnConfig = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"), + ) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup @@ -443,21 +436,14 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - 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"), - ) + let wakuRlnConfig = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"), + ) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup @@ -502,21 +488,14 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - 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"), - ) + let wakuRlnConfig = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"), + ) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup @@ -557,21 +536,14 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - 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"), - ) + let wakuRlnConfig = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"), + ) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup @@ -619,21 +591,14 @@ suite "Waku v2 Rest API - Relay": let node = testWakuNode() await node.start() await node.mountRelay() - 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"), - ) + let wakuRlnConfig = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(1.uint), + rlnRelayUserMessageLimit: 20, + rlnEpochSizeSec: 1, + rlnRelayTreePath: genTempPath("rln_tree", "wakunode_1"), + ) + await node.mountRlnRelay(wakuRlnConfig) # RPC server setup diff --git a/tools/rln_keystore_generator/rln_keystore_generator.nim b/tools/rln_keystore_generator/rln_keystore_generator.nim index c904519c0d..6c64ed6d2d 100644 --- a/tools/rln_keystore_generator/rln_keystore_generator.nim +++ b/tools/rln_keystore_generator/rln_keystore_generator.nim @@ -67,10 +67,7 @@ proc doRlnKeystoreGenerator*(conf: WakuNodeConf) = # 5. register on-chain try: - when defined(rln_v2): - waitFor groupManager.register(credential, conf.rlnRelayUserMessageLimit) - else: - waitFor groupManager.register(credential) + waitFor groupManager.register(credential, conf.rlnRelayUserMessageLimit) except Exception, CatchableError: error "failure while registering credentials on-chain", error = getCurrentExceptionMsg() @@ -82,27 +79,18 @@ proc doRlnKeystoreGenerator*(conf: WakuNodeConf) = chainId = $groupManager.chainId.get(), contractAddress = conf.rlnRelayEthContractAddress, membershipIndex = groupManager.membershipIndex.get() - when defined(rln_v2): - info "Your user message limit is", userMessageLimit = conf.rlnRelayUserMessageLimit + info "Your user message limit is", userMessageLimit = conf.rlnRelayUserMessageLimit # 6. write to keystore - when defined(rln_v2): - let keystoreCred = KeystoreMembership( - membershipContract: MembershipContract( - chainId: $groupManager.chainId.get(), address: conf.rlnRelayEthContractAddress - ), - treeIndex: groupManager.membershipIndex.get(), - identityCredential: credential, - userMessageLimit: conf.rlnRelayUserMessageLimit, - ) - else: - let keystoreCred = KeystoreMembership( - membershipContract: MembershipContract( - chainId: $groupManager.chainId.get(), address: conf.rlnRelayEthContractAddress - ), - treeIndex: groupManager.membershipIndex.get(), - identityCredential: credential, - ) + let keystoreCred = KeystoreMembership( + membershipContract: MembershipContract( + chainId: $groupManager.chainId.get(), address: conf.rlnRelayEthContractAddress + ), + treeIndex: groupManager.membershipIndex.get(), + identityCredential: credential, + userMessageLimit: conf.rlnRelayUserMessageLimit, + ) + let persistRes = addMembershipCredentials( conf.rlnRelayCredPath, keystoreCred, conf.rlnRelayCredPassword, RLNAppInfo diff --git a/vendor/zerokit b/vendor/zerokit index 0ad1ed296d..85d71a5427 160000 --- a/vendor/zerokit +++ b/vendor/zerokit @@ -1 +1 @@ -Subproject commit 0ad1ed296d49e85598e0ec0bae7c220885e47912 +Subproject commit 85d71a5427ee78528d6420c04b67c7825e3c6e91 diff --git a/waku/factory/node_factory.nim b/waku/factory/node_factory.nim index f3cbb7fe74..2bc468fb82 100644 --- a/waku/factory/node_factory.nim +++ b/waku/factory/node_factory.nim @@ -195,31 +195,18 @@ proc setupProtocols( quit(QuitFailure) if conf.rlnRelay: - when defined(rln_v2): - let rlnConf = WakuRlnConfig( - rlnRelayDynamic: conf.rlnRelayDynamic, - rlnRelayCredIndex: conf.rlnRelayCredIndex, - rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress, - rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress), - rlnRelayCredPath: conf.rlnRelayCredPath, - rlnRelayCredPassword: conf.rlnRelayCredPassword, - rlnRelayTreePath: conf.rlnRelayTreePath, - rlnRelayUserMessageLimit: conf.rlnRelayUserMessageLimit, - rlnEpochSizeSec: conf.rlnEpochSizeSec, - onFatalErrorAction: onFatalErrorAction, - ) - else: - let rlnConf = WakuRlnConfig( - rlnRelayDynamic: conf.rlnRelayDynamic, - rlnRelayCredIndex: conf.rlnRelayCredIndex, - rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress, - rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress), - rlnRelayCredPath: conf.rlnRelayCredPath, - rlnRelayCredPassword: conf.rlnRelayCredPassword, - rlnRelayTreePath: conf.rlnRelayTreePath, - rlnEpochSizeSec: conf.rlnEpochSizeSec, - onFatalErrorAction: onFatalErrorAction, - ) + let rlnConf = WakuRlnConfig( + rlnRelayDynamic: conf.rlnRelayDynamic, + rlnRelayCredIndex: conf.rlnRelayCredIndex, + rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress, + rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress), + rlnRelayCredPath: conf.rlnRelayCredPath, + rlnRelayCredPassword: conf.rlnRelayCredPassword, + rlnRelayTreePath: conf.rlnRelayTreePath, + rlnRelayUserMessageLimit: conf.rlnRelayUserMessageLimit, + rlnEpochSizeSec: conf.rlnEpochSizeSec, + onFatalErrorAction: onFatalErrorAction, + ) try: waitFor node.mountRlnRelay(rlnConf) diff --git a/waku/waku_keystore/protocol_types.nim b/waku/waku_keystore/protocol_types.nim index a3d9fb366c..2fab64e6f4 100644 --- a/waku/waku_keystore/protocol_types.nim +++ b/waku/waku_keystore/protocol_types.nim @@ -15,9 +15,7 @@ type IdentitySecretHash* = seq[byte] #array[32, byte] # hash of identity key as defined ed in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership IDCommitment* = seq[byte] #array[32, byte] - -when defined(rln_v2): - type UserMessageLimit* = uint64 + UserMessageLimit* = uint64 type IdentityCredential* = object idTrapdoor*: IdentityTrapdoor @@ -103,45 +101,24 @@ type KeystoreMembership* = ref object of RootObj membershipContract*: MembershipContract treeIndex*: MembershipIndex identityCredential*: IdentityCredential - when defined(rln_v2): - userMessageLimit*: UserMessageLimit - -when defined(rln_v2): - proc `$`*(m: KeystoreMembership): string = - return - "KeystoreMembership(chainId: " & m.membershipContract.chainId & - ", contractAddress: " & m.membershipContract.address & ", treeIndex: " & - $m.treeIndex & ", userMessageLimit: " & $m.userMessageLimit & - ", identityCredential: " & $m.identityCredential & ")" + userMessageLimit*: UserMessageLimit -else: - proc `$`*(m: KeystoreMembership): string = - return - "KeystoreMembership(chainId: " & m.membershipContract.chainId & - ", contractAddress: " & m.membershipContract.address & ", treeIndex: " & - $m.treeIndex & ", identityCredential: " & $m.identityCredential & ")" - -when defined(rln_v2): - proc `==`*(x, y: KeystoreMembership): bool = - return - x.membershipContract.chainId == y.membershipContract.chainId and - x.membershipContract.address == y.membershipContract.address and - x.treeIndex == y.treeIndex and x.userMessageLimit == y.userMessageLimit and - x.identityCredential.idTrapdoor == y.identityCredential.idTrapdoor and - x.identityCredential.idNullifier == y.identityCredential.idNullifier and - x.identityCredential.idSecretHash == y.identityCredential.idSecretHash and - x.identityCredential.idCommitment == y.identityCredential.idCommitment +proc `$`*(m: KeystoreMembership): string = + return + "KeystoreMembership(chainId: " & m.membershipContract.chainId & + ", contractAddress: " & m.membershipContract.address & ", treeIndex: " & + $m.treeIndex & ", userMessageLimit: " & $m.userMessageLimit & + ", identityCredential: " & $m.identityCredential & ")" -else: - proc `==`*(x, y: KeystoreMembership): bool = - return - x.membershipContract.chainId == y.membershipContract.chainId and - x.membershipContract.address == y.membershipContract.address and - x.treeIndex == y.treeIndex and - x.identityCredential.idTrapdoor == y.identityCredential.idTrapdoor and - x.identityCredential.idNullifier == y.identityCredential.idNullifier and - x.identityCredential.idSecretHash == y.identityCredential.idSecretHash and - x.identityCredential.idCommitment == y.identityCredential.idCommitment +proc `==`*(x, y: KeystoreMembership): bool = + return + x.membershipContract.chainId == y.membershipContract.chainId and + x.membershipContract.address == y.membershipContract.address and + x.treeIndex == y.treeIndex and x.userMessageLimit == y.userMessageLimit and + x.identityCredential.idTrapdoor == y.identityCredential.idTrapdoor and + x.identityCredential.idNullifier == y.identityCredential.idNullifier and + x.identityCredential.idSecretHash == y.identityCredential.idSecretHash and + x.identityCredential.idCommitment == y.identityCredential.idCommitment proc hash*(m: KeystoreMembership): string = # hash together the chainId, address and treeIndex diff --git a/waku/waku_rln_relay/constants.nim b/waku/waku_rln_relay/constants.nim index 9d69fdfd18..16678ad5c7 100644 --- a/waku/waku_rln_relay/constants.nim +++ b/waku/waku_rln_relay/constants.nim @@ -27,14 +27,13 @@ const const DefaultRlnTreePath* = "rln_tree.db" -when defined(rln_v2): - const - # pre-processed "rln/waku-rln-relay/v2.0.0" to array[32, byte] - DefaultRlnIdentifier*: RlnIdentifier = [ - 114, 108, 110, 47, 119, 97, 107, 117, 45, 114, 108, 110, 45, 114, 101, 108, 97, - 121, 47, 118, 50, 46, 48, 46, 48, 0, 0, 0, 0, 0, 0, 0, - ] - DefaultUserMessageLimit* = UserMessageLimit(20) +const + # pre-processed "rln/waku-rln-relay/v2.0.0" to array[32, byte] + DefaultRlnIdentifier*: RlnIdentifier = [ + 114, 108, 110, 47, 119, 97, 107, 117, 45, 114, 108, 110, 45, 114, 101, 108, 97, + 121, 47, 118, 50, 46, 48, 46, 48, 0, 0, 0, 0, 0, 0, 0, + ] + DefaultUserMessageLimit* = UserMessageLimit(20) # temporary variables to test waku-rln-relay performance in the static group mode const @@ -60048,15 +60047,11 @@ const StaticGroupKeys* = ] # StaticGroupMerkleRoot is the root of the Merkle tree constructed from the StaticGroupKeys above -# only identity commitments are used for the Merkle tree construction # rln-v2: rate commitments are used for the Merkle tree construction, defaulting the UserMessageLimit to 20 # the root is created locally, using createMembershipList proc from waku_rln_relay_utils module, and the result is hardcoded in here -when defined(rln_v2): - const StaticGroupMerkleRoot* = - "2c149e48886b5ba3da2edf8db8d7a364ae7a25618489c04cf0c0380f7cdd4d6f" -else: - const StaticGroupMerkleRoot* = - "1e534adab58f7d300aaeecae57a25e0a0b18c368a09f720280da92b288950901" +const StaticGroupMerkleRoot* = + "2c149e48886b5ba3da2edf8db8d7a364ae7a25618489c04cf0c0380f7cdd4d6f" + const MaxClockGapSeconds* = 20.0 # the maximum clock difference between peers in seconds diff --git a/waku/waku_rln_relay/contract.nim b/waku/waku_rln_relay/contract.nim index 2ff1d92b90..23bb9ff937 100644 --- a/waku/waku_rln_relay/contract.nim +++ b/waku/waku_rln_relay/contract.nim @@ -1,17 +1,14 @@ -when not defined(rln_v2): - # PoseidonHasherCode holds the bytecode of Poseidon hasher solidity smart contract: - # https://github.com/kilic/rlnapp/blob/master/packages/contracts/contracts/crypto/PoseidonHasher.sol - # the solidity contract is compiled separately and the resultant bytecode is copied here - const PoseidonHasherCode* = - "0x608060405234801561001057600080fd5b50613e58806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063b189fd4c1461003b578063e493ef8c1461006b575b600080fd5b61005560048036038101906100509190613dcb565b610089565b6040516100629190613e07565b60405180910390f35b61007361009b565b6040516100809190613e07565b60405180910390f35b6000610094826100bf565b9050919050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181565b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f09c46e9ec68e9bd4fe1faaba294cba38a71aa177534cdd1b6c7dc0dbd0abd7a77f0c0356530896eec42a97ed937f3135cfc5142b3ae405b8343c1d83ffa604cb81840182828309838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1e28a1d935698ad1142e51182bb54cf4a00ea5aabd6268bd317ea977cc154a30830192507f27af2d831a9d2748080965db30e298e40e5757c3e008db964cf9e2b12b91251f82019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1e6f11ce60fc8f513a6a3cfe16ae175a41291462f214cd0879aaf43545b74e03830192507f2a67384d3bbd5e438541819cb681f0be04462ed14c3613d8f719206268d142d382019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0b66fdf356093a611609f8e12fbfecf0b985e381f025188936408f5d5c9f45d0830192507f012ee3ec1e78d470830c61093c2ade370b26c83cc5cebeeddaa6852dbdb09e2182019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0252ba5f6760bfbdfd88f67f8175e3fd6cd1c431b099b6bb2d108e7b445bb1b9830192507f179474cceca5ff676c6bec3cef54296354391a8935ff71d6ef5aeaad7ca932f182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2c24261379a51bfa9228ff4a503fd4ed9c1f974a264969b37e1a2589bbed2b91830192507f1cc1d7b62692e63eac2f288bd0695b43c2f63f5001fc0fc553e66c0551801b0582019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f255059301aada98bb2ed55f852979e9600784dbf17fbacd05d9eff5fd9c91b56830192507f28437be3ac1cb2e479e1f5c0eccd32b3aea24234970a8193b11c29ce7e59efd982019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f28216a442f2e1f711ca4fa6b53766eb118548da8fb4f78d4338762c37f5f2043830192507f2c1f47cd17fa5adf1f39f4e7056dd03feee1efce03094581131f2377323482c982019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f07abad02b7a5ebc48632bcc9356ceb7dd9dafca276638a63646b8566a621afc9830192507f0230264601ffdf29275b33ffaab51dfe9429f90880a69cd137da0c4d15f96c3c82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1bc973054e51d905a0f168656497ca40a864414557ee289e717e5d66899aa0a9830192507f2e1c22f964435008206c3157e86341edd249aff5c2d8421f2a6b22288f0a67fc82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1224f38df67c5378121c1d5f461bbc509e8ea1598e46c9f7a70452bc2bba86b8830192507f02e4e69d8ba59e519280b4bd9ed0068fd7bfe8cd9dfeda1969d2989186cde20e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1f1eccc34aaba0137f5df81fc04ff3ee4f19ee364e653f076d47e9735d98018e830192507f1672ad3d709a353974266c3039a9a7311424448032cd1819eacb8a4d4284f58282019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f283e3fdc2c6e420c56f44af5192b4ae9cda6961f284d24991d2ed602df8c8fc7830192507f1c2a3d120c550ecfd0db0957170fa013683751f8fdff59d6614fbd69ff394bcc82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f216f84877aac6172f7897a7323456efe143a9a43773ea6f296cb6b8177653fbd830192507f2c0d272becf2a75764ba7e8e3e28d12bceaa47ea61ca59a411a1f51552f9478882019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f16e34299865c0e28484ee7a74c454e9f170a5480abe0508fcb4a6c3d89546f43830192507f175ceba599e96f5b375a232a6fb9cc71772047765802290f48cd939755488fc582019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0c7594440dc48c16fead9e1758b028066aa410bfbc354f54d8c5ffbb44a1ee32830192507f1a3c29bc39f21bb5c466db7d7eb6fd8f760e20013ccf912c92479882d919fd8d82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0ccfdd906f3426e5c0986ea049b253400855d349074f5a6695c8eeabcd22e68f830192507f14f6bc81d9f186f62bdb475ce6c9411866a7a8a3fd065b3ce0e699b67dd9e79682019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0962b82789fb3d129702ca70b2f6c5aacc099810c9c495c888edeb7386b97052830192507f1a880af7074d18b3bf20c79de25127bc13284ab01ef02575afef0c8f6a31a86d82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f10cba18419a6a332cd5e77f0211c154b20af2924fc20ff3f4c3012bb7ae9311b830192507f057e62a9a8f89b3ebdc76ba63a9eaca8fa27b7319cae3406756a2849f302f10d82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f287c971de91dc0abd44adf5384b4988cb961303bbf65cff5afa0413b44280cee830192507f21df3388af1687bbb3bca9da0cca908f1e562bc46d4aba4e6f7f7960e306891d82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1be5c887d25bce703e25cc974d0934cd789df8f70b498fd83eff8b560e1682b3830192507f268da36f76e568fb68117175cea2cd0dd2cb5d42fda5acea48d59c2706a0d5c182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0e17ab091f6eae50c609beaf5510ececc5d8bb74135ebd05bd06460cc26a5ed6830192507f04d727e728ffa0a67aee535ab074a43091ef62d8cf83d270040f5caa1f62af4082019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0ddbd7bf9c29341581b549762bc022ed33702ac10f1bfd862b15417d7e39ca6e830192507f2790eb3351621752768162e82989c6c234f5b0d1d3af9b588a29c49c8789654b82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1e457c601a63b73e4471950193d8a570395f3d9ab8b2fd0984b764206142f9e9830192507f21ae64301dca9625638d6ab2bbe7135ffa90ecd0c43ff91fc4c686fc46e091b082019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0379f63c8ce3468d4da293166f494928854be9e3432e09555858534eed8d350b830192507e2d56420359d0266a744a080809e054ca0e4921a46686ac8c9f58a324c3504982019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f123158e5965b5d9b1d68b3cd32e10bbeda8d62459e21f4090fc2c5af963515a6830192507f0be29fc40847a941661d14bbf6cbe0420fbb2b6f52836d4e60c80eb49cad9ec182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1ac96991dec2bb0557716142015a453c36db9d859cad5f9a233802f24fdf4c1a830192507f1596443f763dbcc25f4964fc61d23b3e5e12c9fa97f18a9251ca3355bcb0627e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f12e0bcd3654bdfa76b2861d4ec3aeae0f1857d9f17e715aed6d049eae3ba3212830192507f0fc92b4f1bbea82b9ea73d4af9af2a50ceabac7f37154b1904e6c76c7cf964ba82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1f9c0b1610446442d6f2e592a8013f40b14f7c7722236f4f9c7e965233872762830192507f0ebd74244ae72675f8cde06157a782f4050d914da38b4c058d159f643dbbf4d382019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2cb7f0ed39e16e9f69a9fafd4ab951c03b0671e97346ee397a839839dccfc6d1830192507f1a9d6e2ecff022cc5605443ee41bab20ce761d0514ce526690c72bca7352d9bf82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2a115439607f335a5ea83c3bc44a9331d0c13326a9a7ba3087da182d648ec72f830192507f23f9b6529b5d040d15b8fa7aee3e3410e738b56305cd44f29535c115c5a4c06082019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f05872c16db0f72a2249ac6ba484bb9c3a3ce97c16d58b68b260eb939f0e6e8a7830192507f1300bdee08bb7824ca20fb80118075f40219b6151d55b5c52b624a7cdeddf6a782019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f19b9b63d2f108e17e63817863a8f6c288d7ad29916d98cb1072e4e7b7d52b376830192507f015bee1357e3c015b5bda237668522f613d1c88726b5ec4224a20128481b4f7f82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2953736e94bb6b9f1b9707a4f1615e4efe1e1ce4bab218cbea92c785b128ffd1830192507f0b069353ba091618862f806180c0385f851b98d372b45f544ce7266ed6608dfc82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f304f74d461ccc13115e4e0bcfb93817e55aeb7eb9306b64e4f588ac97d81f429830192507f15bbf146ce9bca09e8a33f5e77dfe4f5aad2a164a4617a4cb8ee5415cde913fc82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0ab4dfe0c2742cde44901031487964ed9b8f4b850405c10ca9ff23859572c8c6830192507f0e32db320a044e3197f45f7649a19675ef5eedfea546dea9251de39f9639779a82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0a1756aa1f378ca4b27635a78b6888e66797733a82774896a3078efa516da016830192507f044c4a33b10f693447fd17177f952ef895e61d328f85efa94254d6a2a25d93ef82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2ed3611b725b8a70be655b537f66f700fe0879d79a496891d37b07b5466c4b8b830192507f1f9ba4e8bab7ce42c8ecc3d722aa2e0eadfdeb9cfdd347b5d8339ea7120858aa82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1b233043052e8c288f7ee907a84e518aa38e82ac4502066db74056f865c5d3da830192507f2431e1cc164bb8d074031ab72bd55b4c902053bfc0f14db0ca2f97b02087595482019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f082f934c91f5aac330cd6953a0a7db45a13e322097583319a791f273965801fd830192507f2b9a0a223e7538b0a34be074315542a3c77245e2ae7cbe999ad6bb930c48997c82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0e1cd91edd2cfa2cceb85483b887a9be8164163e75a8a00eb0b589cc70214e7d830192507f2e1eac0f2bfdfd63c951f61477e3698999774f19854d00f588d324601cebe2f982019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0cbfa95f37fb74060c76158e769d6d157345784d8efdb33c23d748115b500b83830192507f08f05b3be923ed44d65ad49d8a61e9a676d991e3a77513d9980c232dfa4a4f8482019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f22719e2a070bcd0852bf8e21984d0443e7284925dc0758a325a2dd510c047ef6830192507f041f596a9ee1cb2bc060f7fcc3a1ab4c7bdbf036119982c0f41f62b2f26830c082019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f233fd35de1be520a87628eb06f6b1d4c021be1c2d0dc464a19fcdd0986b10f89830192507f0524b46d1aa87a5e4325e0a423ebc810d31e078aa1b4707eefcb453c61c9c26782019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2c34f424c81e5716ce47fcac894b85824227bb954b0f3199cc4486237c515211830192507f0b5f2a4b63387819207effc2b5541fb72dd2025b5457cc97f33010327de4915e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f22207856082ccc54c5b72fe439d2cfd6c17435d2f57af6ceaefac41fe05c659f830192507f24d57a8bf5da63fe4e24159b7f8950b5cdfb210194caf79f27854048ce2c817182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0afab181fdd5e0583b371d75bd693f98374ad7097bb01a8573919bb23b79396e830192507f2dba9b108f208772998a52efac7cbd5676c0057194c16c0bf16290d62b1128ee82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f26349b66edb8b16f56f881c788f53f83cbb83de0bd592b255aff13e6bce420b3830192507f25af7ce0e5e10357685e95f92339753ad81a56d28ecc193b235288a3e6f137db82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f25b4ce7bd2294390c094d6a55edd68b970eed7aae88b2bff1f7c0187fe35011f830192507f22c543f10f6c89ec387e53f1908a88e5de9cef28ebdf30b18cb9d54c1e02b63182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0236f93e7789c4724fc7908a9f191e1e425e906a919d7a34df668e74882f87a9830192507f29350b401166ca010e7d27e37d05da99652bdae114eb01659cb497af980c4b5282019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0eed787d65820d3f6bd31bbab547f75a65edb75d844ebb89ee1260916652363f830192507f07cc1170f13b46f2036a753f520b3291fdcd0e99bd94297d1906f656f4de6fad82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f22b939233b1d7205f49bcf613a3d30b1908786d7f9f5d10c2059435689e8acea830192507f01451762a0aab81c8aad1dc8bc33e870740f083a5aa85438add650ace60ae5a682019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f23506bb5d8727d4461fabf1025d46d1fe32eaa61dec7da57e704fec0892fce89830192507f2e484c44e838aea0bac06ae3f71bdd092a3709531e1efea97f8bd6890735552282019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0f4bc7d07ebafd64379e78c50bd2e42baf4a594545cedc2545418da26835b54c830192507f1f4d3c8f6583e9e5fa76637862faaee851582388725df460e620996d50d8e74e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f093514e0c70711f82660d07be0e4a988fae02abc7b681d9153eb9bcb48fe7389830192507f1adab0c8e2b3bad346699a2b5f3bc03643ee83ece47228f24a58e0a347e153d882019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1672b1726057d99dd14709ebb474641a378c1b94b8072bac1a22dbef9e80dad2830192507f1dfd53d4576af2e38f44f53fdcab468cc5d8e2fae0acc4ee30d47b239b479c1482019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f0c6888a10b75b0f3a70a36263a37e17fe6d77d640f6fc3debc7f207753205c60830192507f1addb933a65be77092b34a7e77d12fe8611a61e00ee6848b85091ecca9d1e50882019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507ed7540dcd268a845c10ae18d1de933cf638ff5425f0afff7935628e299d1791830192507f140c0e42687e9ead01b2827a5664ca9c26fedde4acd99db1d316939d20b82c0e82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f2f0c3a115d4317d191ba89b8d13d1806c20a0f9b24f8c5edc091e2ae56565984830192507f0c4ee778ff7c14553006ed220cf9c81008a0cff670b22b82d8c538a1dc958c6182019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1704f2766d46f82c3693f00440ccc3609424ed26c0acc66227c3d7485de74c69830192507f2f2d19cc3ea5d78ea7a02c1b51d244abf0769c9f8544e40239b66fe9009c3cfa82019150838384099050838385838409099250837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1ae03853b75fcaba5053f112e2a8e8dcdd7ee6cb9cfed9c7d6c766a806fc6629830192507f0971aabf795241df51d131d0fa61aa5f3556921b2d6f014e4e41a86ddaf056d582019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1408c316e6014e1a91d4cf6b6e0de73eda624f8380df1c875f5c29f7bfe2f646830192507f1667f3fe2edbe850248abe42b543093b6c89f1f773ef285341691f39822ef5bd82019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f13bf7c5d0d2c4376a48b0a03557cdf915b81718409e5c133424c69576500fe37830192507f07620a6dfb0b6cec3016adf3d3533c24024b95347856b79719bc0ba743a62c2c82019150838384099050838385838409099250838283099050838285838409099150837f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88309847f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad58509019050837f1274e649a32ed355a31a6ed69724e1adade857e86eb5c3a121bcd147943203c88309847f0cc57cdbb08507d62bf67a4493cc262fb6c09d557013fff1f573f431221f8ff985090191508092507f1574c7ef0c43545f36a8ca08bdbdd8b075d2959e2f322b731675de3e1982b4d0830192507f269e4b5b7a2eb21afd567970a717ceec5bd4184571c254fdc06e03a7ff8378f08201915083838409905083838583840909925083828309905083828583840909915083847f2b9d4b4110c9ae997782e1509b1d0fdb20a7c02bbd8bea7305462b9f8125b1e88409857f066f6f85d6f68a85ec10345351a23a3aaf07f38af8c952a7bceca70bd2af7ad586090106925082945050505050919050565b600080fd5b6000819050919050565b613da881613d95565b8114613db357600080fd5b50565b600081359050613dc581613d9f565b92915050565b600060208284031215613de157613de0613d90565b5b6000613def84828501613db6565b91505092915050565b613e0181613d95565b82525050565b6000602082019050613e1c6000830184613df8565b9291505056fea2646970667358221220f20e2267360e9aeb09de75ad232eed0f5dc05f7547d686c790b156f441d402b164736f6c634300080f0033" - # RegistryContractCode contains the bytecode of the membership solidity smart contract: - # https://github.com/waku-org/rln-contract/blob/fbafa7b0bb47c5233f50ba82992c572795e7e9a6/deployments/sepolia/WakuRlnRegistry.json - # the solidity contract is compiled separately and the resultant bytecode is copied here - const RegistryContractCode* = - "0x60a06040526000600260006101000a81548161ffff021916908361ffff1602179055503480156200002f57600080fd5b5060405162002f2a38038062002f2a8339818101604052810190620000559190620001e6565b6200007562000069620000b060201b60201c565b620000b860201b60201c565b8073ffffffffffffffffffffffffffffffffffffffff1660808173ffffffffffffffffffffffffffffffffffffffff16815250505062000218565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620001ae8262000181565b9050919050565b620001c081620001a1565b8114620001cc57600080fd5b50565b600081519050620001e081620001b5565b92915050565b600060208284031215620001ff57620001fe6200017c565b5b60006200020f84828501620001cf565b91505092915050565b608051612ce862000242600039600081816103e2015281816104120152610ad80152612ce86000f3fe60806040523480156200001157600080fd5b5060043610620000e25760003560e01c8063ab02492a1162000099578063ef653d5e116200006f578063ef653d5e14620001d1578063f184ef4c14620001f1578063f2fde38b1462000213578063f5542147146200023357620000e2565b8063ab02492a1462000183578063cf61637414620001a3578063d44fda1f14620001c557620000e2565b806326e0fc1f14620000e7578063331b6ab3146200010757806342f542e21462000129578063715018a614620001355780637a34289d14620001415780638da5cb5b1462000161575b600080fd5b620001056004803603810190620000ff919062001045565b62000269565b005b62000111620003e0565b60405162000120919062001117565b60405180910390f35b6200013362000404565b005b6200013f6200048b565b005b6200015f6004803603810190620001599190620011a2565b620004a3565b005b6200016b6200075f565b6040516200017a91906200121c565b60405180910390f35b620001a160048036038101906200019b919062001239565b62000788565b005b620001ad6200088b565b604051620001bc9190620012b4565b60405180910390f35b620001cf6200089f565b005b620001ef6004803603810190620001e9919062001302565b62000a09565b005b620001fb62000c9e565b6040516200020a9190620012b4565b60405180910390f35b6200023160048036038101906200022b919062001302565b62000cb2565b005b6200025160048036038101906200024b919062001334565b62000d3c565b6040516200026091906200121c565b60405180910390f35b600060149054906101000a900461ffff1661ffff168261ffff1610620002bb576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600167ffffffffffffffff811115620002db57620002da62001366565b5b6040519080825280602002602001820160405280156200030a5781602001602082028036833780820191505090505b509050818160008151811062000325576200032462001395565b5b602002602001018181525050600160008461ffff1661ffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637a34289d826040518263ffffffff1660e01b8152600401620003a7919062001492565b600060405180830381600087803b158015620003c257600080fd5b505af1158015620003d7573d6000803e3d6000fd5b50505050505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b6200040e62000d6f565b60007f0000000000000000000000000000000000000000000000000000000000000000600060149054906101000a900461ffff16604051620004509062000fb3565b6200045d929190620014b6565b604051809103906000f0801580156200047a573d6000803e3d6000fd5b509050620004888162000df4565b50565b6200049562000d6f565b620004a1600062000ee7565b565b600060149054906101000a900461ffff1661ffff16600260009054906101000a900461ffff1661ffff161062000505576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b6001156200075b5760016000600260009054906101000a900461ffff1661ffff1661ffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637a34289d83836040518363ffffffff1660e01b8152600401620005969291906200155a565b600060405180830381600087803b158015620005b157600080fd5b505af1925050508015620005c3575060015b6200074f573d8060008114620005f6576040519150601f19603f3d011682016040523d82523d6000602084013e620005fb565b606091505b506040516024016040516020818303038152906040527f57f69531000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff8381831617835250505050805190602001208180519060200120146200069c57805181602001fd5b600060149054906101000a900461ffff1661ffff166001600260009054906101000a900461ffff16620006d09190620015af565b61ffff16106200070c576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600260008282829054906101000a900461ffff166200072e9190620015af565b92506101000a81548161ffff021916908361ffff1602179055505062000755565b6200075b565b62000506565b5050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b600060149054906101000a900461ffff1661ffff168361ffff1610620007da576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600160008461ffff1661ffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16637a34289d83836040518363ffffffff1660e01b8152600401620008529291906200155a565b600060405180830381600087803b1580156200086d57600080fd5b505af115801562000882573d6000803e3d6000fd5b50505050505050565b600260009054906101000a900461ffff1681565b620008a962000d6f565b600060149054906101000a900461ffff1661ffff16600260009054906101000a900461ffff1661ffff16106200090b576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff16600160006001600260009054906101000a900461ffff16620009469190620015af565b61ffff1661ffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1603620009cb576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001600260008282829054906101000a900461ffff16620009ed9190620015af565b92506101000a81548161ffff021916908361ffff160217905550565b62000a1362000d6f565b600073ffffffffffffffffffffffffffffffffffffffff16600160008060149054906101000a900461ffff1661ffff1661ffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff161462000ad157806040517f9cfabd1600000000000000000000000000000000000000000000000000000000815260040162000ac891906200121c565b60405180910390fd5b60008190507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1663331b6ab36040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000b59573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000b7f919062001633565b73ffffffffffffffffffffffffffffffffffffffff161462000bcc576040517eaec95400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060149054906101000a900461ffff1661ffff168173ffffffffffffffffffffffffffffffffffffffff166328b070e06040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000c2d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000c5391906200167c565b61ffff161462000c8f576040517fb893b72300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62000c9a8262000df4565b5050565b600060149054906101000a900461ffff1681565b62000cbc62000d6f565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160362000d2e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000d259062001735565b60405180910390fd5b62000d398162000ee7565b50565b60016020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b62000d7962000fab565b73ffffffffffffffffffffffffffffffffffffffff1662000d996200075f565b73ffffffffffffffffffffffffffffffffffffffff161462000df2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000de990620017a7565b60405180910390fd5b565b80600160008060149054906101000a900461ffff1661ffff1661ffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fcf6a3b406170499209d0fcf152a1605c7c5a5c99c855e2bb803433fc960718eb600060149054906101000a900461ffff168260405162000ea0929190620017c9565b60405180910390a16001600060148282829054906101000a900461ffff1662000eca9190620015af565b92506101000a81548161ffff021916908361ffff16021790555050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600033905090565b6114bc80620017f783390190565b600080fd5b600080fd5b600061ffff82169050919050565b62000fe48162000fcb565b811462000ff057600080fd5b50565b600081359050620010048162000fd9565b92915050565b6000819050919050565b6200101f816200100a565b81146200102b57600080fd5b50565b6000813590506200103f8162001014565b92915050565b600080604083850312156200105f576200105e62000fc1565b5b60006200106f8582860162000ff3565b925050602062001082858286016200102e565b9150509250929050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000620010d7620010d1620010cb846200108c565b620010ac565b6200108c565b9050919050565b6000620010eb82620010b6565b9050919050565b6000620010ff82620010de565b9050919050565b6200111181620010f2565b82525050565b60006020820190506200112e600083018462001106565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f8401126200115c576200115b62001134565b5b8235905067ffffffffffffffff8111156200117c576200117b62001139565b5b6020830191508360208202830111156200119b576200119a6200113e565b5b9250929050565b60008060208385031215620011bc57620011bb62000fc1565b5b600083013567ffffffffffffffff811115620011dd57620011dc62000fc6565b5b620011eb8582860162001143565b92509250509250929050565b600062001204826200108c565b9050919050565b6200121681620011f7565b82525050565b60006020820190506200123360008301846200120b565b92915050565b60008060006040848603121562001255576200125462000fc1565b5b6000620012658682870162000ff3565b935050602084013567ffffffffffffffff81111562001289576200128862000fc6565b5b620012978682870162001143565b92509250509250925092565b620012ae8162000fcb565b82525050565b6000602082019050620012cb6000830184620012a3565b92915050565b620012dc81620011f7565b8114620012e857600080fd5b50565b600081359050620012fc81620012d1565b92915050565b6000602082840312156200131b576200131a62000fc1565b5b60006200132b84828501620012eb565b91505092915050565b6000602082840312156200134d576200134c62000fc1565b5b60006200135d8482850162000ff3565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b620013fb816200100a565b82525050565b60006200140f8383620013f0565b60208301905092915050565b6000602082019050919050565b60006200143582620013c4565b620014418185620013cf565b93506200144e83620013e0565b8060005b838110156200148557815162001469888262001401565b975062001476836200141b565b92505060018101905062001452565b5085935050505092915050565b60006020820190508181036000830152620014ae818462001428565b905092915050565b6000604082019050620014cd60008301856200120b565b620014dc6020830184620012a3565b9392505050565b600080fd5b82818337600083830152505050565b6000620015058385620013cf565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8311156200153b576200153a620014e3565b5b6020830292506200154e838584620014e8565b82840190509392505050565b6000602082019050818103600083015262001577818486620014f7565b90509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000620015bc8262000fcb565b9150620015c98362000fcb565b92508261ffff03821115620015e357620015e262001580565b5b828201905092915050565b6000620015fb82620011f7565b9050919050565b6200160d81620015ee565b81146200161957600080fd5b50565b6000815190506200162d8162001602565b92915050565b6000602082840312156200164c576200164b62000fc1565b5b60006200165c848285016200161c565b91505092915050565b600081519050620016768162000fd9565b92915050565b60006020828403121562001695576200169462000fc1565b5b6000620016a58482850162001665565b91505092915050565b600082825260208201905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b60006200171d602683620016ae565b91506200172a82620016bf565b604082019050919050565b6000602082019050818103600083015262001750816200170e565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006200178f602083620016ae565b91506200179c8262001757565b602082019050919050565b60006020820190508181036000830152620017c28162001780565b9050919050565b6000604082019050620017e06000830185620012a3565b620017ef60208301846200120b565b939250505056fe61016060405260006001553480156200001757600080fd5b50604051620014bc380380620014bc83398181016040528101906200003d919062000290565b6000601483600062000064620000586200011b60201b60201c565b6200012360201b60201c565b83608081815250508260a08181525050826001901b60c081815250508173ffffffffffffffffffffffffffffffffffffffff1660e08173ffffffffffffffffffffffffffffffffffffffff16815250508073ffffffffffffffffffffffffffffffffffffffff166101008173ffffffffffffffffffffffffffffffffffffffff16815250504363ffffffff166101208163ffffffff1681525050505050508061ffff166101408161ffff16815250505050620002d7565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006200021982620001ec565b9050919050565b6200022b816200020c565b81146200023757600080fd5b50565b6000815190506200024b8162000220565b92915050565b600061ffff82169050919050565b6200026a8162000251565b81146200027657600080fd5b50565b6000815190506200028a816200025f565b92915050565b60008060408385031215620002aa57620002a9620001e7565b5b6000620002ba858286016200023a565b9250506020620002cd8582860162000279565b9150509250929050565b60805160a05160c05160e05161010051610120516101405161117c620003406000396000610545015260006105e3015260006105690152600081816104ac015261058d0152600081816107560152610aac015260006106fc015260006107ac015261117c6000f3fe60806040526004361061011f5760003560e01c80638be9b119116100a0578063c5b208ff11610064578063c5b208ff146103c5578063d0383d6814610402578063f207564e1461042d578063f220b9ec14610449578063f2fde38b146104745761011f565b80638be9b119146102de5780638da5cb5b1461030757806398366e3514610332578063ae74552a1461035d578063bc499128146103885761011f565b80634add651e116100e75780634add651e146101f95780635daf08ca146102245780636bdcc8ab14610261578063715018a61461029e5780637a34289d146102b55761011f565b806322d9730c1461012457806328b070e0146101615780632b7ac3f31461018c578063331b6ab3146101b75780633ccfd60b146101e2575b600080fd5b34801561013057600080fd5b5061014b60048036038101906101469190610b48565b61049d565b6040516101589190610b90565b60405180910390f35b34801561016d57600080fd5b50610176610543565b6040516101839190610bc8565b60405180910390f35b34801561019857600080fd5b506101a1610567565b6040516101ae9190610c62565b60405180910390f35b3480156101c357600080fd5b506101cc61058b565b6040516101d99190610c9e565b60405180910390f35b3480156101ee57600080fd5b506101f76105af565b005b34801561020557600080fd5b5061020e6105e1565b60405161021b9190610cd8565b60405180910390f35b34801561023057600080fd5b5061024b60048036038101906102469190610b48565b610605565b6040516102589190610d02565b60405180910390f35b34801561026d57600080fd5b5061028860048036038101906102839190610b48565b61061d565b6040516102959190610b90565b60405180910390f35b3480156102aa57600080fd5b506102b361063d565b005b3480156102c157600080fd5b506102dc60048036038101906102d79190610d82565b610651565b005b3480156102ea57600080fd5b5061030560048036038101906103009190610e2f565b61069f565b005b34801561031357600080fd5b5061031c6106d1565b6040516103299190610ea4565b60405180910390f35b34801561033e57600080fd5b506103476106fa565b6040516103549190610d02565b60405180910390f35b34801561036957600080fd5b5061037261071e565b60405161037f9190610d02565b60405180910390f35b34801561039457600080fd5b506103af60048036038101906103aa9190610b48565b610724565b6040516103bc9190610d02565b60405180910390f35b3480156103d157600080fd5b506103ec60048036038101906103e79190610eeb565b61073c565b6040516103f99190610d02565b60405180910390f35b34801561040e57600080fd5b50610417610754565b6040516104249190610d02565b60405180910390f35b61044760048036038101906104429190610b48565b610778565b005b34801561045557600080fd5b5061045e6107aa565b60405161046b9190610d02565b60405180910390f35b34801561048057600080fd5b5061049b60048036038101906104969190610eeb565b6107ce565b005b600080821415801561053c57507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663e493ef8c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610515573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105399190610f2d565b82105b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b60036020528060005260406000206000915090505481565b60046020528060005260406000206000915054906101000a900460ff1681565b610645610851565b61064f60006108cf565b565b610659610851565b600082829050905060005b818110156106995761068e84848381811061068257610681610f5a565b5b90506020020135610993565b806001019050610664565b50505050565b6040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b7f000000000000000000000000000000000000000000000000000000000000000081565b60015481565b60026020528060005260406000206000915090505481565b60056020528060005260406000206000915090505481565b7f000000000000000000000000000000000000000000000000000000000000000081565b6040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b6107d6610851565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610845576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161083c9061100c565b60405180910390fd5b61084e816108cf565b50565b610859610a0c565b73ffffffffffffffffffffffffffffffffffffffff166108776106d1565b73ffffffffffffffffffffffffffffffffffffffff16146108cd576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016108c490611078565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b61099c81610a14565b600160036000838152602001908152602001600020819055507f5a92c2530f207992057b9c3e544108ffce3beda4a63719f316967c49bf6159d2816001546040516109e8929190611098565b60405180910390a16001806000828254610a0291906110f0565b9250508190555050565b600033905090565b610a1d8161049d565b610a5e57806040517f7f3e75af000000000000000000000000000000000000000000000000000000008152600401610a559190610d02565b60405180910390fd5b6000600360008381526020019081526020016000205414610aaa576040517e0a60f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000060015410610b05576040517f57f6953100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50565b600080fd5b600080fd5b6000819050919050565b610b2581610b12565b8114610b3057600080fd5b50565b600081359050610b4281610b1c565b92915050565b600060208284031215610b5e57610b5d610b08565b5b6000610b6c84828501610b33565b91505092915050565b60008115159050919050565b610b8a81610b75565b82525050565b6000602082019050610ba56000830184610b81565b92915050565b600061ffff82169050919050565b610bc281610bab565b82525050565b6000602082019050610bdd6000830184610bb9565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b6000610c28610c23610c1e84610be3565b610c03565b610be3565b9050919050565b6000610c3a82610c0d565b9050919050565b6000610c4c82610c2f565b9050919050565b610c5c81610c41565b82525050565b6000602082019050610c776000830184610c53565b92915050565b6000610c8882610c2f565b9050919050565b610c9881610c7d565b82525050565b6000602082019050610cb36000830184610c8f565b92915050565b600063ffffffff82169050919050565b610cd281610cb9565b82525050565b6000602082019050610ced6000830184610cc9565b92915050565b610cfc81610b12565b82525050565b6000602082019050610d176000830184610cf3565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f840112610d4257610d41610d1d565b5b8235905067ffffffffffffffff811115610d5f57610d5e610d22565b5b602083019150836020820283011115610d7b57610d7a610d27565b5b9250929050565b60008060208385031215610d9957610d98610b08565b5b600083013567ffffffffffffffff811115610db757610db6610b0d565b5b610dc385828601610d2c565b92509250509250929050565b6000610dda82610be3565b9050919050565b610dea81610dcf565b8114610df557600080fd5b50565b600081359050610e0781610de1565b92915050565b600081905082602060080282011115610e2957610e28610d27565b5b92915050565b60008060006101408486031215610e4957610e48610b08565b5b6000610e5786828701610b33565b9350506020610e6886828701610df8565b9250506040610e7986828701610e0d565b9150509250925092565b6000610e8e82610be3565b9050919050565b610e9e81610e83565b82525050565b6000602082019050610eb96000830184610e95565b92915050565b610ec881610e83565b8114610ed357600080fd5b50565b600081359050610ee581610ebf565b92915050565b600060208284031215610f0157610f00610b08565b5b6000610f0f84828501610ed6565b91505092915050565b600081519050610f2781610b1c565b92915050565b600060208284031215610f4357610f42610b08565b5b6000610f5184828501610f18565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082825260208201905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000610ff6602683610f89565b915061100182610f9a565b604082019050919050565b6000602082019050818103600083015261102581610fe9565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000611062602083610f89565b915061106d8261102c565b602082019050919050565b6000602082019050818103600083015261109181611055565b9050919050565b60006040820190506110ad6000830185610cf3565b6110ba6020830184610cf3565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006110fb82610b12565b915061110683610b12565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0382111561113b5761113a6110c1565b5b82820190509291505056fea2646970667358221220507a65829a9a551e42c8757b2613a358880e56baec43e730dff9d9aa252c9a3564736f6c634300080f0033a26469706673582212208cc71be49f97f4fad7da0c74d0576129e139d0ef30e3ac4be6a3214675ab1d5264736f6c634300080f0033" -else: - # This contract code is used in deployment, note: this is not the deployedBytecode, it includes constructor args. - # Ref: https://github.com/waku-org/waku-rln-contract/blob/886891b57ae54e439563023dd50161fec5ee29f1/deployments/sepolia/WakuRlnRegistry_Implementation.json - const RegistryContractCode* = - "0x60a06040523073ffffffffffffffffffffffffffffffffffffffff1660809073ffffffffffffffffffffffffffffffffffffffff168152506000606760006101000a81548161ffff021916908361ffff16021790555034801561006157600080fd5b50608051614429610099600039600081816106870152818161071801528181610922015281816109b30152610a6c01526144296000f3fe6080604052600436106200010a5760003560e01c80638da5cb5b1162000097578063f184ef4c1162000061578063f184ef4c14620002f3578063f2fde38b1462000323578063f55421471462000351578063fc6ed4641462000395576200010a565b80638da5cb5b146200024b578063cf616374146200027b578063d44fda1f14620002ab578063ef653d5e14620002c5576200010a565b806352d1902d11620000d957806352d1902d14620001b95780635a244efd14620001e9578063715018a614620002175780638129fc1c1462000231576200010a565b80632de999bf146200010f5780633659cfe6146200013d57806339c0364b146200016b5780634f1ef2861462000199575b600080fd5b3480156200011c57600080fd5b506200013b60048036038101906200013591906200197b565b620003c3565b005b3480156200014a57600080fd5b5062000169600480360381019062000163919062001a6e565b62000685565b005b3480156200017857600080fd5b5062000197600480360381019062000191919062001b1a565b6200081d565b005b620001b76004803603810190620001b1919062001cd3565b62000920565b005b348015620001c657600080fd5b50620001d162000a68565b604051620001e0919062001d54565b60405180910390f35b348015620001f657600080fd5b506200021560048036038101906200020f919062001d71565b62000b24565b005b3480156200022457600080fd5b506200022f62000bc7565b005b3480156200023e57600080fd5b506200024962000bdf565b005b3480156200025857600080fd5b506200026362000d2b565b60405162000272919062001db4565b60405180910390f35b3480156200028857600080fd5b506200029362000d55565b604051620002a2919062001de2565b60405180910390f35b348015620002b857600080fd5b50620002c362000d69565b005b348015620002d257600080fd5b50620002f16004803603810190620002eb919062001a6e565b62000e13565b005b3480156200030057600080fd5b506200030b62000ef4565b6040516200031a919062001de2565b60405180910390f35b3480156200033057600080fd5b506200034f600480360381019062000349919062001a6e565b62000f08565b005b3480156200035e57600080fd5b506200037d600480360381019062000377919062001dff565b62000f92565b6040516200038c919062001db4565b60405180910390f35b348015620003a257600080fd5b50620003c16004803603810190620003bb919062001e31565b62000fc5565b005b606560009054906101000a900461ffff1661ffff16606760009054906101000a900461ffff1661ffff161062000425576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5b6001156200067f5760666000606760009054906101000a900461ffff1661ffff1661ffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632de999bf858585856040518563ffffffff1660e01b8152600401620004ba949392919062001f57565b600060405180830381600087803b158015620004d557600080fd5b505af1925050508015620004e7575060015b62000673573d80600081146200051a576040519150601f19603f3d011682016040523d82523d6000602084013e6200051f565b606091505b506040516024016040516020818303038152906040527f57f69531000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505080519060200120818051906020012014620005c057805181602001fd5b606560009054906101000a900461ffff1661ffff166001606760009054906101000a900461ffff16620005f4919062001fc5565b61ffff161062000630576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001606760008282829054906101000a900461ffff1662000652919062001fc5565b92506101000a81548161ffff021916908361ffff1602179055505062000679565b6200067f565b62000426565b50505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff160362000716576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200070d9062002089565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1662000757620010ce565b73ffffffffffffffffffffffffffffffffffffffff1614620007b0576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620007a79062002121565b60405180910390fd5b620007bb8162001127565b6200081a81600067ffffffffffffffff811115620007de57620007dd62001b8c565b5b6040519080825280601f01601f191660200182016040528015620008115781602001600182028036833780820191505090505b50600062001134565b50565b606560009054906101000a900461ffff1661ffff168361ffff16106200086f576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606660008461ffff1661ffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663d66d6c1083836040518363ffffffff1660e01b8152600401620008e792919062002154565b600060405180830381600087803b1580156200090257600080fd5b505af115801562000917573d6000803e3d6000fd5b50505050505050565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff1603620009b1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620009a89062002089565b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16620009f2620010ce565b73ffffffffffffffffffffffffffffffffffffffff161462000a4b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000a429062002121565b60405180910390fd5b62000a568262001127565b62000a648282600162001134565b5050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff161462000afb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000af290620021f7565b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b905090565b62000b2e620012b3565b6000810362000b69576040517fe671aff300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081606560009054906101000a900461ffff1660405162000b8b90620018eb565b62000b9892919062002219565b604051809103906000f08015801562000bb5573d6000803e3d6000fd5b50905062000bc38162001338565b5050565b62000bd1620012b3565b62000bdd60006200142c565b565b60008060019054906101000a900460ff1615905080801562000c115750600160008054906101000a900460ff1660ff16105b8062000c42575062000c2330620014f2565b15801562000c415750600160008054906101000a900460ff1660ff16145b5b62000c84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000c7b90620022bc565b60405180910390fd5b60016000806101000a81548160ff021916908360ff160217905550801562000cc2576001600060016101000a81548160ff0219169083151502179055505b62000ccc62001515565b801562000d285760008060016101000a81548160ff0219169083151502179055507f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb3847402498600160405162000d1f919062002338565b60405180910390a15b50565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b606760009054906101000a900461ffff1681565b62000d73620012b3565b606560009054906101000a900461ffff1661ffff16606760009054906101000a900461ffff1661ffff161062000dd5576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001606760008282829054906101000a900461ffff1662000df7919062001fc5565b92506101000a81548161ffff021916908361ffff160217905550565b62000e1d620012b3565b6000819050606560009054906101000a900461ffff1661ffff168173ffffffffffffffffffffffffffffffffffffffff166328b070e06040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000e83573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000ea991906200236c565b61ffff161462000ee5576040517fb893b72300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b62000ef08262001338565b5050565b606560009054906101000a900461ffff1681565b62000f12620012b3565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff160362000f84576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162000f7b9062002414565b60405180910390fd5b62000f8f816200142c565b50565b60666020528060005260406000206000915054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b606560009054906101000a900461ffff1661ffff168561ffff161062001017576040517fd23276a200000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606660008661ffff1661ffff16815260200190815260200160002060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16632de999bf858585856040518563ffffffff1660e01b815260040162001093949392919062001f57565b600060405180830381600087803b158015620010ae57600080fd5b505af1158015620010c3573d6000803e3d6000fd5b505050505050505050565b6000620010fe7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b62001573565b60000160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b62001131620012b3565b50565b620011627f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914360001b6200157d565b60000160009054906101000a900460ff16156200118a57620011848362001587565b620012ae565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015620011f557506040513d601f19601f82011682018060405250810190620011f2919062002467565b60015b62001237576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200122e906200250f565b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b81146200129f576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200129690620025a7565b60405180910390fd5b50620012ad83838362001647565b5b505050565b620012bd62001679565b73ffffffffffffffffffffffffffffffffffffffff16620012dd62000d2b565b73ffffffffffffffffffffffffffffffffffffffff161462001336576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200132d9062002619565b60405180910390fd5b565b8060666000606560009054906101000a900461ffff1661ffff1661ffff16815260200190815260200160002060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fcf6a3b406170499209d0fcf152a1605c7c5a5c99c855e2bb803433fc960718eb606560009054906101000a900461ffff1682604051620013e59291906200263b565b60405180910390a16001606560008282829054906101000a900461ffff166200140f919062001fc5565b92506101000a81548161ffff021916908361ffff16021790555050565b6000603360009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905081603360006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b600060019054906101000a900460ff1662001567576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016200155e90620026de565b60405180910390fd5b6200157162001681565b565b6000819050919050565b6000819050919050565b6200159281620016e9565b620015d4576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620015cb9062002776565b60405180910390fd5b80620016037f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc60001b62001573565b60000160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555050565b62001652836200170c565b600082511180620016605750805b1562001674576200167283836200175d565b505b505050565b600033905090565b600060019054906101000a900460ff16620016d3576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620016ca90620026de565b60405180910390fd5b620016e7620016e162001679565b6200142c565b565b6000808273ffffffffffffffffffffffffffffffffffffffff163b119050919050565b620017178162001587565b8073ffffffffffffffffffffffffffffffffffffffff167fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b60405160405180910390a250565b6060620017858383604051806060016040528060278152602001620043cd602791396200178d565b905092915050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051620017b9919062002811565b600060405180830381855af49150503d8060008114620017f6576040519150601f19603f3d011682016040523d82523d6000602084013e620017fb565b606091505b50915091506200180e8683838762001819565b925050509392505050565b60608315620018835760008351036200187a576200183785620016e9565b62001879576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040162001870906200287a565b60405180910390fd5b5b82905062001890565b6200188f838362001898565b5b949350505050565b600082511115620018ac5781518083602001fd5b806040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401620018e29190620028e8565b60405180910390fd5b611ac0806200290d83390190565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b600080fd5b60008083601f8401126200193557620019346200190d565b5b8235905067ffffffffffffffff81111562001955576200195462001912565b5b60208301915083602082028301111562001974576200197362001917565b5b9250929050565b6000806000806040858703121562001998576200199762001903565b5b600085013567ffffffffffffffff811115620019b957620019b862001908565b5b620019c7878288016200191c565b9450945050602085013567ffffffffffffffff811115620019ed57620019ec62001908565b5b620019fb878288016200191c565b925092505092959194509250565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600062001a368262001a09565b9050919050565b62001a488162001a29565b811462001a5457600080fd5b50565b60008135905062001a688162001a3d565b92915050565b60006020828403121562001a875762001a8662001903565b5b600062001a978482850162001a57565b91505092915050565b600061ffff82169050919050565b62001ab98162001aa0565b811462001ac557600080fd5b50565b60008135905062001ad98162001aae565b92915050565b6000819050919050565b62001af48162001adf565b811462001b0057600080fd5b50565b60008135905062001b148162001ae9565b92915050565b60008060006060848603121562001b365762001b3562001903565b5b600062001b468682870162001ac8565b935050602062001b598682870162001b03565b925050604062001b6c8682870162001b03565b9150509250925092565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b62001bc68262001b7b565b810181811067ffffffffffffffff8211171562001be85762001be762001b8c565b5b80604052505050565b600062001bfd620018f9565b905062001c0b828262001bbb565b919050565b600067ffffffffffffffff82111562001c2e5762001c2d62001b8c565b5b62001c398262001b7b565b9050602081019050919050565b82818337600083830152505050565b600062001c6c62001c668462001c10565b62001bf1565b90508281526020810184848401111562001c8b5762001c8a62001b76565b5b62001c9884828562001c46565b509392505050565b600082601f83011262001cb85762001cb76200190d565b5b813562001cca84826020860162001c55565b91505092915050565b6000806040838503121562001ced5762001cec62001903565b5b600062001cfd8582860162001a57565b925050602083013567ffffffffffffffff81111562001d215762001d2062001908565b5b62001d2f8582860162001ca0565b9150509250929050565b6000819050919050565b62001d4e8162001d39565b82525050565b600060208201905062001d6b600083018462001d43565b92915050565b60006020828403121562001d8a5762001d8962001903565b5b600062001d9a8482850162001b03565b91505092915050565b62001dae8162001a29565b82525050565b600060208201905062001dcb600083018462001da3565b92915050565b62001ddc8162001aa0565b82525050565b600060208201905062001df9600083018462001dd1565b92915050565b60006020828403121562001e185762001e1762001903565b5b600062001e288482850162001ac8565b91505092915050565b60008060008060006060868803121562001e505762001e4f62001903565b5b600062001e608882890162001ac8565b955050602086013567ffffffffffffffff81111562001e845762001e8362001908565b5b62001e92888289016200191c565b9450945050604086013567ffffffffffffffff81111562001eb85762001eb762001908565b5b62001ec6888289016200191c565b92509250509295509295909350565b600082825260208201905092915050565b600080fd5b82818337505050565b600062001f02838562001ed5565b93507f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff83111562001f385762001f3762001ee6565b5b60208302925062001f4b83858462001eeb565b82840190509392505050565b6000604082019050818103600083015262001f7481868862001ef4565b9050818103602083015262001f8b81848662001ef4565b905095945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600062001fd28262001aa0565b915062001fdf8362001aa0565b9250828201905061ffff81111562001ffc5762001ffb62001f96565b5b92915050565b600082825260208201905092915050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f64656c656761746563616c6c0000000000000000000000000000000000000000602082015250565b600062002071602c8362002002565b91506200207e8262002013565b604082019050919050565b60006020820190508181036000830152620020a48162002062565b9050919050565b7f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060008201527f6163746976652070726f78790000000000000000000000000000000000000000602082015250565b600062002109602c8362002002565b91506200211682620020ab565b604082019050919050565b600060208201905081810360008301526200213c81620020fa565b9050919050565b6200214e8162001adf565b82525050565b60006040820190506200216b600083018562002143565b6200217a602083018462002143565b9392505050565b7f555550535570677261646561626c653a206d757374206e6f742062652063616c60008201527f6c6564207468726f7567682064656c656761746563616c6c0000000000000000602082015250565b6000620021df60388362002002565b9150620021ec8262002181565b604082019050919050565b600060208201905081810360008301526200221281620021d0565b9050919050565b600060408201905062002230600083018562002143565b6200223f602083018462001dd1565b9392505050565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160008201527f647920696e697469616c697a6564000000000000000000000000000000000000602082015250565b6000620022a4602e8362002002565b9150620022b18262002246565b604082019050919050565b60006020820190508181036000830152620022d78162002295565b9050919050565b6000819050919050565b600060ff82169050919050565b6000819050919050565b6000620023206200231a6200231484620022de565b620022f5565b620022e8565b9050919050565b6200233281620022ff565b82525050565b60006020820190506200234f600083018462002327565b92915050565b600081519050620023668162001aae565b92915050565b60006020828403121562002385576200238462001903565b5b6000620023958482850162002355565b91505092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000620023fc60268362002002565b915062002409826200239e565b604082019050919050565b600060208201905081810360008301526200242f81620023ed565b9050919050565b620024418162001d39565b81146200244d57600080fd5b50565b600081519050620024618162002436565b92915050565b60006020828403121562002480576200247f62001903565b5b6000620024908482850162002450565b91505092915050565b7f45524331393637557067726164653a206e657720696d706c656d656e7461746960008201527f6f6e206973206e6f742055555053000000000000000000000000000000000000602082015250565b6000620024f7602e8362002002565b9150620025048262002499565b604082019050919050565b600060208201905081810360008301526200252a81620024e8565b9050919050565b7f45524331393637557067726164653a20756e737570706f727465642070726f7860008201527f6961626c65555549440000000000000000000000000000000000000000000000602082015250565b60006200258f60298362002002565b91506200259c8262002531565b604082019050919050565b60006020820190508181036000830152620025c28162002580565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006200260160208362002002565b91506200260e82620025c9565b602082019050919050565b600060208201905081810360008301526200263481620025f2565b9050919050565b600060408201905062002652600083018562001dd1565b62002661602083018462001da3565b9392505050565b7f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960008201527f6e697469616c697a696e67000000000000000000000000000000000000000000602082015250565b6000620026c6602b8362002002565b9150620026d38262002668565b604082019050919050565b60006020820190508181036000830152620026f981620026b7565b9050919050565b7f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60008201527f6f74206120636f6e747261637400000000000000000000000000000000000000602082015250565b60006200275e602d8362002002565b91506200276b8262002700565b604082019050919050565b6000602082019050818103600083015262002791816200274f565b9050919050565b600081519050919050565b600081905092915050565b60005b83811015620027ce578082015181840152602081019050620027b1565b60008484015250505050565b6000620027e78262002798565b620027f38185620027a3565b935062002805818560208601620027ae565b80840191505092915050565b60006200281f8284620027da565b915081905092915050565b7f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000600082015250565b600062002862601d8362002002565b91506200286f826200282a565b602082019050919050565b60006020820190508181036000830152620028958162002853565b9050919050565b600081519050919050565b6000620028b4826200289c565b620028c0818562002002565b9350620028d2818560208601620027ae565b620028dd8162001b7b565b840191505092915050565b60006020820190508181036000830152620029048184620028a7565b90509291505056fe61016060405260006001553480156200001757600080fd5b5060405162001ac038038062001ac083398181016040528101906200003d91906200023a565b600060148360006200006462000058620000ef60201b60201c565b620000f760201b60201c565b8360a0818152505081608081815250508260c08181525050826001901b60e081815250508073ffffffffffffffffffffffffffffffffffffffff166101008173ffffffffffffffffffffffffffffffffffffffff16815250504363ffffffff166101208163ffffffff1681525050505050508061ffff166101408161ffff1681525050505062000281565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b600080fd5b6000819050919050565b620001d581620001c0565b8114620001e157600080fd5b50565b600081519050620001f581620001ca565b92915050565b600061ffff82169050919050565b6200021481620001fb565b81146200022057600080fd5b50565b600081519050620002348162000209565b92915050565b60008060408385031215620002545762000253620001bb565b5b60006200026485828601620001e4565b9250506020620002778582860162000223565b9150509250929050565b60805160a05160c05160e0516101005161012051610140516117cf620002f16000396000610661015260006107c401526000610685015260008181610a4a0152610f24015260006109f001526000818161075f0152610aa00152600081816106050152610dd201526117cf6000f3fe6080604052600436106101665760003560e01c80638be9b119116100d1578063bc4991281161008a578063d66d6c1011610064578063d66d6c1014610568578063e493ef8c14610584578063f220b9ec146105af578063f2fde38b146105da57610166565b8063bc499128146104c3578063c5b208ff14610500578063d0383d681461053d57610166565b80638be9b1191461039f5780638da5cb5b146103c85780639056a9bf146103f3578063933ebfdd1461043057806398366e351461046d578063ae74552a1461049857610166565b80633ccfd60b116101235780633ccfd60b1461028f5780634add651e146102a65780635daf08ca146102d15780636bdcc8ab1461030e578063715018a61461034b5780637671ac051461036257610166565b806309aeb04c1461016b57806322d9730c1461019657806328b070e0146101d35780632b7ac3f3146101fe5780632de999bf14610229578063378de45b14610252575b600080fd5b34801561017757600080fd5b50610180610603565b60405161018d9190610f9c565b60405180910390f35b3480156101a257600080fd5b506101bd60048036038101906101b89190610fed565b610627565b6040516101ca9190611035565b60405180910390f35b3480156101df57600080fd5b506101e861065f565b6040516101f5919061106d565b60405180910390f35b34801561020a57600080fd5b50610213610683565b6040516102209190611107565b60405180910390f35b34801561023557600080fd5b50610250600480360381019061024b9190611187565b6106a7565b005b34801561025e57600080fd5b5061027960048036038101906102749190610fed565b61075b565b6040516102869190610f9c565b60405180910390f35b34801561029b57600080fd5b506102a4610790565b005b3480156102b257600080fd5b506102bb6107c2565b6040516102c89190611227565b60405180910390f35b3480156102dd57600080fd5b506102f860048036038101906102f39190610fed565b6107e6565b6040516103059190610f9c565b60405180910390f35b34801561031a57600080fd5b5061033560048036038101906103309190610fed565b6107fe565b6040516103429190611035565b60405180910390f35b34801561035757600080fd5b5061036061081e565b005b34801561036e57600080fd5b5061038960048036038101906103849190610fed565b610832565b6040516103969190610f9c565b60405180910390f35b3480156103ab57600080fd5b506103c660048036038101906103c191906112a2565b61084a565b005b3480156103d457600080fd5b506103dd61085a565b6040516103ea9190611317565b60405180910390f35b3480156103ff57600080fd5b5061041a60048036038101906104159190610fed565b610883565b6040516104279190610f9c565b60405180910390f35b34801561043c57600080fd5b5061045760048036038101906104529190611332565b61089b565b6040516104649190611430565b60405180910390f35b34801561047957600080fd5b506104826109ee565b60405161048f9190610f9c565b60405180910390f35b3480156104a457600080fd5b506104ad610a12565b6040516104ba9190610f9c565b60405180910390f35b3480156104cf57600080fd5b506104ea60048036038101906104e59190610fed565b610a18565b6040516104f79190610f9c565b60405180910390f35b34801561050c57600080fd5b506105276004803603810190610522919061147e565b610a30565b6040516105349190610f9c565b60405180910390f35b34801561054957600080fd5b50610552610a48565b60405161055f9190610f9c565b60405180910390f35b610582600480360381019061057d9190611332565b610a6c565b005b34801561059057600080fd5b50610599610a7a565b6040516105a69190610f9c565b60405180910390f35b3480156105bb57600080fd5b506105c4610a9e565b6040516105d19190610f9c565b60405180910390f35b3480156105e657600080fd5b5061060160048036038101906105fc919061147e565b610ac2565b005b7f000000000000000000000000000000000000000000000000000000000000000081565b600080821415801561065857507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182105b9050919050565b7f000000000000000000000000000000000000000000000000000000000000000081565b7f000000000000000000000000000000000000000000000000000000000000000081565b6106af610b45565b838383836106bf84848484610bc3565b6106f5576040517fb750624800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600088889050905060005b8181101561074f576107448a8a8381811061071e5761071d6114ab565b5b90506020020135898984818110610738576107376114ab565b5b90506020020135610bf5565b806001019050610700565b50505050505050505050565b60007f0000000000000000000000000000000000000000000000000000000000000000826107899190611509565b9050919050565b6040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000081565b60036020528060005260406000206000915090505481565b60066020528060005260406000206000915054906101000a900460ff1681565b610826610b45565b6108306000610cd1565b565b60056020528060005260406000206000915090505481565b610855838383610d95565b505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b60046020528060005260406000206000915090505481565b60608183106108e35782826040517f9ffcd53d0000000000000000000000000000000000000000000000000000000081526004016108da92919061154b565b60405180910390fd5b60015482111561092c5782826040517f9ffcd53d00000000000000000000000000000000000000000000000000000000815260040161092392919061154b565b60405180910390fd5b6000838361093a9190611574565b67ffffffffffffffff811115610953576109526115a8565b5b6040519080825280602002602001820160405280156109815781602001602082028036833780820191505090505b50905060008490505b838110156109e35760056000828152602001908152602001600020548286836109b39190611574565b815181106109c4576109c36114ab565b5b60200260200101818152505080806109db906115d7565b91505061098a565b508091505092915050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60015481565b60026020528060005260406000206000915090505481565b60076020528060005260406000206000915090505481565b7f000000000000000000000000000000000000000000000000000000000000000081565b610a768282610bf5565b5050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181565b7f000000000000000000000000000000000000000000000000000000000000000081565b610aca610b45565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1603610b39576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610b30906116a2565b60405180910390fd5b610b4281610cd1565b50565b610b4d610dc7565b73ffffffffffffffffffffffffffffffffffffffff16610b6b61085a565b73ffffffffffffffffffffffffffffffffffffffff1614610bc1576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610bb89061170e565b60405180910390fd5b565b6000808585905090506000848490509050808214610be657600092505050610bed565b6001925050505b949350505050565b610bff8282610dcf565b6001546003600084815260200190815260200160002081905550816005600060015481526020019081526020016000208190555060016006600084815260200190815260200160002060006101000a81548160ff0219169083151502179055508060046000848152602001908152602001600020819055507fff42916a89d1f5125f7f47168ee59c2b3fc9246ad1b229082ee85b69d001b5d78282600154604051610cac9392919061172e565b60405180910390a16001806000828254610cc69190611765565b925050819055505050565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6040517fd623472500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600033905090565b807f0000000000000000000000000000000000000000000000000000000000000000811115610e3557806040517f13a5e2ee000000000000000000000000000000000000000000000000000000008152600401610e2c9190610f9c565b60405180910390fd5b60008103610e7a57806040517f13a5e2ee000000000000000000000000000000000000000000000000000000008152600401610e719190610f9c565b60405180910390fd5b82610e8481610627565b610ec557806040517f7f3e75af000000000000000000000000000000000000000000000000000000008152600401610ebc9190610f9c565b60405180910390fd5b600115156006600086815260200190815260200160002060009054906101000a900460ff16151503610f22576040517e0a60f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000060015410610f7d576040517f57f6953100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b6000819050919050565b610f9681610f83565b82525050565b6000602082019050610fb16000830184610f8d565b92915050565b600080fd5b600080fd5b610fca81610f83565b8114610fd557600080fd5b50565b600081359050610fe781610fc1565b92915050565b60006020828403121561100357611002610fb7565b5b600061101184828501610fd8565b91505092915050565b60008115159050919050565b61102f8161101a565b82525050565b600060208201905061104a6000830184611026565b92915050565b600061ffff82169050919050565b61106781611050565b82525050565b6000602082019050611082600083018461105e565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000819050919050565b60006110cd6110c86110c384611088565b6110a8565b611088565b9050919050565b60006110df826110b2565b9050919050565b60006110f1826110d4565b9050919050565b611101816110e6565b82525050565b600060208201905061111c60008301846110f8565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261114757611146611122565b5b8235905067ffffffffffffffff81111561116457611163611127565b5b6020830191508360208202830111156111805761117f61112c565b5b9250929050565b600080600080604085870312156111a1576111a0610fb7565b5b600085013567ffffffffffffffff8111156111bf576111be610fbc565b5b6111cb87828801611131565b9450945050602085013567ffffffffffffffff8111156111ee576111ed610fbc565b5b6111fa87828801611131565b925092505092959194509250565b600063ffffffff82169050919050565b61122181611208565b82525050565b600060208201905061123c6000830184611218565b92915050565b600061124d82611088565b9050919050565b61125d81611242565b811461126857600080fd5b50565b60008135905061127a81611254565b92915050565b60008190508260206008028201111561129c5761129b61112c565b5b92915050565b600080600061014084860312156112bc576112bb610fb7565b5b60006112ca86828701610fd8565b93505060206112db8682870161126b565b92505060406112ec86828701611280565b9150509250925092565b600061130182611088565b9050919050565b611311816112f6565b82525050565b600060208201905061132c6000830184611308565b92915050565b6000806040838503121561134957611348610fb7565b5b600061135785828601610fd8565b925050602061136885828601610fd8565b9150509250929050565b600081519050919050565b600082825260208201905092915050565b6000819050602082019050919050565b6113a781610f83565b82525050565b60006113b9838361139e565b60208301905092915050565b6000602082019050919050565b60006113dd82611372565b6113e7818561137d565b93506113f28361138e565b8060005b8381101561142357815161140a88826113ad565b9750611415836113c5565b9250506001810190506113f6565b5085935050505092915050565b6000602082019050818103600083015261144a81846113d2565b905092915050565b61145b816112f6565b811461146657600080fd5b50565b60008135905061147881611452565b92915050565b60006020828403121561149457611493610fb7565b5b60006114a284828501611469565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061151482610f83565b915061151f83610f83565b925082820261152d81610f83565b91508282048414831517611544576115436114da565b5b5092915050565b60006040820190506115606000830185610f8d565b61156d6020830184610f8d565b9392505050565b600061157f82610f83565b915061158a83610f83565b92508282039050818111156115a2576115a16114da565b5b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006115e282610f83565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611614576116136114da565b5b600182019050919050565b600082825260208201905092915050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b600061168c60268361161f565b915061169782611630565b604082019050919050565b600060208201905081810360008301526116bb8161167f565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b60006116f860208361161f565b9150611703826116c2565b602082019050919050565b60006020820190508181036000830152611727816116eb565b9050919050565b60006060820190506117436000830186610f8d565b6117506020830185610f8d565b61175d6040830184610f8d565b949350505050565b600061177082610f83565b915061177b83610f83565b9250828201905080821115611793576117926114da565b5b9291505056fea2646970667358221220f3d63817472861b92ed47c1c0a059033d26762a83df789a2f02dba13d9cc3df464736f6c63430008130033416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564a26469706673582212206950adc7c418dd947ac3e184fb9f4d3a3206a03ca637b1c5a6fa23e8ae800c7464736f6c63430008130033" +# This contract code is used in deployment, note: this is not the deployedBytecode, it includes constructor args. +# Ref: https://github.com/waku-org/waku-rlnv2-contract +const PoseidonT3* = + "0x615be56200003b600b82828239805160001a60731461002e57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100355760003560e01c8063561558fe1461003a575b600080fd5b61004d610048366004615b3e565b61005f565b60405190815260200160405180910390f35b60007f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000017f2b90bba00fca0589f617e7dcbfe82e0df706ab640ceb247b791a93b74e36736d7f101071f0032379b697315876690f053d148d4e109f5fb065c8aacc55a0f89bfa7f19a3fc0a56702bf417ba7fee3802593fa644470307043f7773279cd71d25d5e07ef1445235f2148c5986587169fc1bcd887b08d4d00868df5696fff40956e8648460805106017f08dff3487e8ac99e1f29a058d0fa80b930c728730b7ab36ce879f3890ecf73f58560a05106018582830986838883840909925086828309905086828883840909915086868309877f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e08509017f5151bcc773d05d360fc9c923795441a9618605f30e31f2b8f087d1575b9c613b01905086858309877f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe238509017f547424ff6c2e186923faa2cf5794c8cd2b5d3e8f151620ffda4a15b70cc05b3f0187858409887f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee29118609017f23dc61092dc247151d38da17703c1ccb157f035575fe333d62fda4d2a5ae1bf5018883800989848b83840909935089838409905089838b83840909925089828309905089828b838409099150898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f28813dcaebaeaa828a376df87af4a63bc8b7bf27ad49c6298ef7b387bf28526d019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f2727673b2ccbc903f181bf38e1c1d40d2033865200c352bc150928adddf9cb78019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f234ec45ca27727c2e74abd2b2a1494cd6efbd43e340587d6b8fb9e31e65cc63201945089818209935089818b86870909905089868709935089868b86870909955089858609935089858b868709099450898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f15b52534031ae18f7f862cb2cf7cf760ab10a8150a337b1ccd99ff6e8797d428019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f0dc8fad6d9e4b35f5ed9a3d186b79ce38e0e8a8d1b58b132d701d4eecf68d1f6019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f1bcd95ffc211fbca600f705fad3fb567ea4eb378f62e1fec97805518a47e4d9c01915089848509905089848b83840909935089838409905089838b83840909925089828309905089828b838409099150898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f10520b0ab721cadfe9eff81b016fc34dc76da36c2578937817cb978d069de559019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f1f6d48149b8e7f7d9b257d8ed5fbbaf42932498075fed0ace88a9eb81f5627f6019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f1d9655f652309014d29e00ef35a2089bfff8dc1c816f0dc9ca34bdb5460c870501945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f04df5a56ff95bcafb051f7b1cd43a99ba731ff67e47032058fe3d4185697cc7d019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f0672d995f8fff640151b3d290cedaf148690a10a8c8424a7f6ec282b6e4be828019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f099952b414884454b21200d7ffafdd5f0c9a9dcc06f2708e9fc1d8209b5c75b901915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f052cba2255dfd00c7c483143ba8d469448e43586a9b4cd9183fd0e843a6b9fa6019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f0b8badee690adb8eb0bd74712b7999af82de55707251ad7716077cb93c464ddc019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f119b1590f13307af5a1ee651020c07c749c15d60683a8050b963d0a8e4b2bdd101945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f03150b7cd6d5d17b2529d36be0f67b832c4acfc884ef4ee5ce15be0bfb4a8d09019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f2cc6182c5e14546e3cf1951f173912355374efb83d80898abe69cb317c9ea565019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017e5032551e6378c450cfe129a404b3764218cadedac14e2b92d2cd73111bf0f901915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f233237e3289baa34bb147e972ebcb9516469c399fcc069fb88f9da2cc28276b5019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f05c8f4f4ebd4a6e3c980d31674bfbe6323037f21b34ae5a4e80c2d4c24d60280019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f0a7b1db13042d396ba05d818a319f25252bcf35ef3aeed91ee1f09b2590fc65b01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f2a73b71f9b210cf5b14296572c9d32dbf156e2b086ff47dc5df542365a404ec0019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f1ac9b0417abcc9a1935107e9ffc91dc3ec18f2c4dbe7f22976a760bb5c50c460019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f12c0339ae08374823fabb076707ef479269f3e4d6cb104349015ee046dc93fc001915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f0b7475b102a165ad7f5b18db4e1e704f52900aa3253baac68246682e56e9a28e019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f037c2849e191ca3edb1c5e49f6e8b8917c843e379366f2ea32ab3aa88d7f8448019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f05a6811f8556f014e92674661e217e9bd5206c5c93a07dc145fdb176a716346f01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f29a795e7d98028946e947b75d54e9f044076e87a7b2883b47b675ef5f38bd66e019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f20439a0c84b322eb45a3857afc18f5826e8c7382c8a1585c507be199981fd22f019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f2e0ba8d94d9ecf4a94ec2050c7371ff1bb50f27799a84b6d4a2a6f2a0982c88701915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f143fd115ce08fb27ca38eb7cce822b4517822cd2109048d2e6d0ddcca17d71c8019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f0c64cbecb1c734b857968dbbdcf813cdf8611659323dbcbfc84323623be9caf1019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f028a305847c683f646fca925c163ff5ae74f348d62c2b670f1426cef9403da5301945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f2e4ef510ff0b6fda5fa940ab4c4380f26a6bcb64d89427b824d6755b5db9e30c019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017e81c95bc43384e663d79270c956ce3b8925b4f6d033b078b96384f50579400e019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f2ed5f0c91cbd9749187e2fade687e05ee2491b349c039a0bba8a9f4023a0bb3801915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f30509991f88da3504bbf374ed5aae2f03448a22c76234c8c990f01f33a735206019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f1c3f20fd55409a53221b7c4d49a356b9f0a1119fb2067b41a7529094424ec6ad019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f10b4e7f3ab5df003049514459b6e18eec46bb2213e8e131e170887b47ddcb96c01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f2a1982979c3ff7f43ddd543d891c2abddd80f804c077d775039aa3502e43adef019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f1c74ee64f15e1db6feddbead56d6d55dba431ebc396c9af95cad0f1315bd5c91019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f07533ec850ba7f98eab9303cace01b4b9e4f2e8b82708cfa9c2fe45a0ae146a001915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f21576b438e500449a151e4eeaf17b154285c68f42d42c1808a11abf3764c0750019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f2f17c0559b8fe79608ad5ca193d62f10bce8384c815f0906743d6930836d4a9e019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f2d477e3862d07708a79e8aae946170bc9775a4201318474ae665b0b1b7e2730e01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f162f5243967064c390e095577984f291afba2266c38f5abcd89be0f5b2747eab019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f2b4cb233ede9ba48264ecd2c8ae50d1ad7a8596a87f29f8a7777a70092393311019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f2c8fbcb2dd8573dc1dbaf8f4622854776db2eece6d85c4cf4254e7c35e03b07a01915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f1d6f347725e4816af2ff453f0cd56b199e1b61e9f601e9ade5e88db870949da9019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f204b0c397f4ebe71ebc2d8b3df5b913df9e6ac02b68d31324cd49af5c4565529019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f0c4cb9dc3c4fd8174f1149b3c63c3c2f9ecb827cd7dc25534ff8fb75bc79c50201945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f174ad61a1448c899a25416474f4930301e5c49475279e0639a616ddc45bc7b54019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f1a96177bcf4d8d89f759df4ec2f3cde2eaaa28c177cc0fa13a9816d49a38d2ef019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f066d04b24331d71cd0ef8054bc60c4ff05202c126a233c1a8242ace360b8a30a01915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f2a4c4fc6ec0b0cf52195782871c6dd3b381cc65f72e02ad527037a62aa1bd804019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f13ab2d136ccf37d447e9f2e14a7cedc95e727f8446f6d9d7e55afc01219fd649019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f1121552fca26061619d24d843dc82769c1b04fcec26f55194c2e3e869acc6a9a01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017eef653322b13d6c889bc81715c37d77a6cd267d595c4a8909a5546c7c97cff1019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f0e25483e45a665208b261d8ba74051e6400c776d652595d9845aca35d8a397d3019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f29f536dcb9dd7682245264659e15d88e395ac3d4dde92d8c46448db979eeba8901915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f2a56ef9f2c53febadfda33575dbdbd885a124e2780bbea170e456baace0fa5be019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f1c8361c78eb5cf5decfb7a2d17b5c409f2ae2999a46762e8ee416240a8cb9af1019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f151aff5f38b20a0fc0473089aaf0206b83e8e68a764507bfd3d0ab4be74319c501945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f04c6187e41ed881dc1b239c88f7f9d43a9f52fc8c8b6cdd1e76e47615b51f100019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f13b37bd80f4d27fb10d84331f6fb6d534b81c61ed15776449e801b7ddc9c2967019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f01a5c536273c2d9df578bfbd32c17b7a2ce3664c2a52032c9321ceb1c4e8a8e401915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f2ab3561834ca73835ad05f5d7acb950b4a9a2c666b9726da832239065b7c3b02019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f1d4d8ec291e720db200fe6d686c0d613acaf6af4e95d3bf69f7ed516a597b646019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f041294d2cc484d228f5784fe7919fd2bb925351240a04b711514c9c80b65af1d01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f154ac98e01708c611c4fa715991f004898f57939d126e392042971dd90e81fc6019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f0b339d8acca7d4f83eedd84093aef51050b3684c88f8b0b04524563bc6ea4da4019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f0955e49e6610c94254a4f84cfbab344598f0e71eaff4a7dd81ed95b50839c82e01915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f06746a6156eba54426b9e22206f15abca9a6f41e6f535c6f3525401ea0654626019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f0f18f5a0ecd1423c496f3820c549c27838e5790e2bd0a196ac917c7ff32077fb019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f04f6eeca1751f7308ac59eff5beb261e4bb563583ede7bc92a738223d6f76e1301945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f2b56973364c4c4f5c1a3ec4da3cdce038811eb116fb3e45bc1768d26fc0b3758019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f123769dd49d5b054dcd76b89804b1bcb8e1392b385716a5d83feb65d437f29ef019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f2147b424fc48c80a88ee52b91169aacea989f6446471150994257b2fb01c63e901915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f0fdc1f58548b85701a6c5505ea332a29647e6f34ad4243c2ea54ad897cebe54d019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f12373a8251fea004df68abcf0f7786d4bceff28c5dbbe0c3944f685cc0a0b1f2019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f21e4f4ea5f35f85bad7ea52ff742c9e8a642756b6af44203dd8a1f35c1a9003501945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f16243916d69d2ca3dfb4722224d4c462b57366492f45e90d8a81934f1bc3b147019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f1efbe46dd7a578b4f66f9adbc88b4378abc21566e1a0453ca13a4159cac04ac2019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f07ea5e8537cf5dd08886020e23a7f387d468d5525be66f853b672cc96a88969a01915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f05a8c4f9968b8aa3b7b478a30f9a5b63650f19a75e7ce11ca9fe16c0b76c00bc019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f20f057712cc21654fbfe59bd345e8dac3f7818c701b9c7882d9d57b72a32e83f019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f04a12ededa9dfd689672f8c67fee31636dcd8e88d01d49019bd90b33eb33db6901945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f27e88d8c15f37dcee44f1e5425a51decbd136ce5091a6767e49ec9544ccd101a019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f2feed17b84285ed9b8a5c8c5e95a41f66e096619a7703223176c41ee433de4d1019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f1ed7cc76edf45c7c404241420f729cf394e5942911312a0d6972b8bd53aff2b801915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f15742e99b9bfa323157ff8c586f5660eac6783476144cdcadf2874be45466b1a019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f1aac285387f65e82c895fc6887ddf40577107454c6ec0317284f033f27d0c785019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f25851c3c845d4790f9ddadbdb6057357832e2e7a49775f71ec75a96554d67c7701945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f15a5821565cc2ec2ce78457db197edf353b7ebba2c5523370ddccc3d9f146a67019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f2411d57a4813b9980efa7e31a1db5966dcf64f36044277502f15485f28c71727019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017e2e6f8d6520cd4713e335b8c0b6d2e647e9a98e12f4cd2558828b5ef6cb4c9b01915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f2ff7bc8f4380cde997da00b616b0fcd1af8f0e91e2fe1ed7398834609e0315d2019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017eb9831b948525595ee02724471bcd182e9521f6b7bb68f1e93be4febb0d3cbe019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f0a2f53768b8ebf6a86913b0e57c04e011ca408648a4743a87d77adbf0c9c351201945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017e248156142fd0373a479f91ff239e960f599ff7e94be69b7f2a290305e1198d019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f171d5620b87bfb1328cf8c02ab3f0c9a397196aa6a542c2350eb512a2b2bcda9019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f170a4f55536f7dc970087c7c10d6fad760c952172dd54dd99d1045e4ec34a80801915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f29aba33f799fe66c2ef3134aea04336ecc37e38c1cd211ba482eca17e2dbfae1019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f1e9bc179a4fdd758fdd1bb1945088d47e70d114a03f6a0e8b5ba650369e64973019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f1dd269799b660fad58f7f4892dfb0b5afeaad869a9c4b44f9c9e1c43bdaf8f0901945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f22cdbc8b70117ad1401181d02e15459e7ccd426fe869c7c95d1dd2cb0f24af38019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f0ef042e454771c533a9f57a55c503fcefd3150f52ed94a7cd5ba93b9c7dacefd019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f11609e06ad6c8fe2f287f3036037e8851318e8b08a0359a03b304ffca62e828401915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f1166d9e554616dba9e753eea427c17b7fecd58c076dfe42708b08f5b783aa9af019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f2de52989431a859593413026354413db177fbf4cd2ac0b56f855a888357ee466019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f3006eb4ffc7a85819a6da492f3a8ac1df51aee5b17b8e89d74bf01cf5f71e9ad01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f2af41fbb61ba8a80fdcf6fff9e3f6f422993fe8f0a4639f962344c8225145086019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f119e684de476155fe5a6b41a8ebc85db8718ab27889e85e781b214bace4827c3019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f1835b786e2e8925e188bea59ae363537b51248c23828f047cff784b97b3fd80001915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f28201a34c594dfa34d794996c6433a20d152bac2a7905c926c40e285ab32eeb6019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f083efd7a27d1751094e80fefaf78b000864c82eb571187724a761f88c22cc4e7019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f0b6f88a3577199526158e61ceea27be811c16df7774dd8519e079564f61fd13b01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f0ec868e6d15e51d9644f66e1d6471a94589511ca00d29e1014390e6ee4254f5b019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f2af33e3f866771271ac0c9b3ed2e1142ecd3e74b939cd40d00d937ab84c98591019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f0b520211f904b5e7d09b5d961c6ace7734568c547dd6858b364ce5e47951f17801915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f0b2d722d0919a1aad8db58f10062a92ea0c56ac4270e822cca228620188a1d40019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f1f790d4d7f8cf094d980ceb37c2453e957b54a9991ca38bbe0061d1ed6e562d4019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f0171eb95dfbf7d1eaea97cd385f780150885c16235a2a6a8da92ceb01e50423301945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f0c2d0e3b5fd57549329bf6885da66b9b790b40defd2c8650762305381b168873019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f1162fb28689c27154e5a8228b4e72b377cbcafa589e283c35d3803054407a18d019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f2f1459b65dee441b64ad386a91e8310f282c5a92a89e19921623ef8249711bc001915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f1e6ff3216b688c3d996d74367d5cd4c1bc489d46754eb712c243f70d1b53cfbb019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f01ca8be73832b8d0681487d27d157802d741a6f36cdc2a0576881f9326478875019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f1f7735706ffe9fc586f976d5bdf223dc680286080b10cea00b9b5de315f9650e01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f2522b60f4ea3307640a0c2dce041fba921ac10a3d5f096ef4745ca838285f019019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f23f0bee001b1029d5255075ddc957f833418cad4f52b6c3f8ce16c235572575b019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f2bc1ae8b8ddbb81fcaac2d44555ed5685d142633e9df905f66d9401093082d5901915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f0f9406b8296564a37304507b8dba3ed162371273a07b1fc98011fcd6ad72205f019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f2360a8eb0cc7defa67b72998de90714e17e75b174a52ee4acb126c8cd995f0a8019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f15871a5cddead976804c803cbaef255eb4815a5e96df8b006dcbbc2767f8894801945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f193a56766998ee9e0a8652dd2f3b1da0362f4f54f72379544f957ccdeefb420f019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f2a394a43934f86982f9be56ff4fab1703b2e63c8ad334834e4309805e777ae0f019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f1859954cfeb8695f3e8b635dcb345192892cd11223443ba7b4166e8876c0d14201915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f04e1181763050e58013444dbcb99f1902b11bc25d90bbdca408d3819f4fed32b019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f0fdb253dee83869d40c335ea64de8c5bb10eb82db08b5e8b1f5e5552bfd05f23019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f058cbe8a9a5027bdaa4efb623adead6275f08686f1c08984a9d7c5bae9b4f1c001945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f1382edce9971e186497eadb1aeb1f52b23b4b83bef023ab0d15228b4cceca59a019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f03464990f045c6ee0819ca51fd11b0be7f61b8eb99f14b77e1e6634601d9e8b5019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f23f7bfc8720dc296fff33b41f98ff83c6fcab4605db2eb5aaa5bc137aeb70a5801915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f0a59a158e3eec2117e6e94e7f0e9decf18c3ffd5e1531a9219636158bbaf62f2019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f06ec54c80381c052b58bf23b312ffd3ce2c4eba065420af8f4c23ed0075fd07b019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f118872dc832e0eb5476b56648e867ec8b09340f7a7bcb1b4962f0ff9ed1f9d0101945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f13d69fa127d834165ad5c7cba7ad59ed52e0b0f0e42d7fea95e1906b520921b1019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f169a177f63ea681270b1c6877a73d21bde143942fb71dc55fd8a49f19f10c77b019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f04ef51591c6ead97ef42f287adce40d93abeb032b922f66ffb7e9a5a7450544d01915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f256e175a1dc079390ecd7ca703fb2e3b19ec61805d4f03ced5f45ee6dd0f69ec019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f30102d28636abd5fe5f2af412ff6004f75cc360d3205dd2da002813d3e2ceeb2019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f10998e42dfcd3bbf1c0714bc73eb1bf40443a3fa99bef4a31fd31be182fcc79201945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f193edd8e9fcf3d7625fa7d24b598a1d89f3362eaf4d582efecad76f879e36860019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f18168afd34f2d915d0368ce80b7b3347d1c7a561ce611425f2664d7aa51f0b5d019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f29383c01ebd3b6ab0c017656ebe658b6a328ec77bc33626e29e2e95b33ea611101915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f10646d2f2603de39a1f4ae5e7771a64a702db6e86fb76ab600bf573f9010c711019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f0beb5e07d1b27145f575f1395a55bf132f90c25b40da7b3864d0242dcb1117fb019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f16d685252078c133dc0d3ecad62b5c8830f95bb2e54b59abdffbf018d96fa33601945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f0a6abd1d833938f33c74154e0404b4b40a555bbbec21ddfafd672dd62047f01a019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f1a679f5d36eb7b5c8ea12a4c2dedc8feb12dffeec450317270a6f19b34cf1860019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f0980fb233bd456c23974d50e0ebfde4726a423eada4e8f6ffbc7592e3f1b93d601915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f161b42232e61b84cbf1810af93a38fc0cece3d5628c9282003ebacb5c312c72b019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f0ada10a90c7f0520950f7d47a60d5e6a493f09787f1564e5d09203db47de1a0b019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f1a730d372310ba82320345a29ac4238ed3f07a8a2b4e121bb50ddb9af407f45101945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f2c8120f268ef054f817064c369dda7ea908377feaba5c4dffbda10ef58e8c556019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f1c7c8824f758753fa57c00789c684217b930e95313bcb73e6e7b8649a4968f70019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f2cd9ed31f5f8691c8e39e4077a74faa0f400ad8b491eb3f7b47b27fa3fd1cf7701915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f23ff4f9d46813457cf60d92f57618399a5e022ac321ca550854ae23918a22eea019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f09945a5d147a4f66ceece6405dddd9d0af5a2c5103529407dff1ea58f180426d019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f188d9c528025d4c2b67660c6b771b90f7c7da6eaa29d3f268a6dd223ec6fc63001945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f3050e37996596b7f81f68311431d8734dba7d926d3633595e0c0d8ddf4f0f47f019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f15af1169396830a91600ca8102c35c426ceae5461e3f95d89d829518d30afd78019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f1da6d09885432ea9a06d9f37f873d985dae933e351466b2904284da3320d8acc01915089848509905089848b838409099350898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f2796ea90d269af29f5f8acf33921124e4e4fad3dbe658945e546ee411ddaa9cb019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f202d7dd1da0f6b4b0325c8b3307742f01e15612ec8e9304a7cb0319e01d32d60019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f096d6790d05bb759156a952ba263d672a2d7f9c788f4c831a29dace4c0f8be5f01945089818209935089818b868709099050898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f054efa1f65b0fce283808965275d877b438da23ce5b13e1963798cb1447d25a4019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f1b162f83d917e93edb3308c29802deb9d8aa690113b2e14864ccf6e18e4165f1019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f21e5241e12564dd6fd9f1cdd2a0de39eedfefc1466cc568ec5ceb745a0506edc01915089848509905089848b83840909935089838409905089838b83840909925089828309905089828b838409099150898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f1cfb5662e8cf5ac9226a80ee17b36abecb73ab5f87e161927b4349e10e4bdf08019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f0f21177e302a771bbae6d8d1ecb373b62c99af346220ac0129c53f666eb24100019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f1671522374606992affb0dd7f71b12bec4236aede6290546bcef7e1f515c232001945089818209935089818b86870909905089868709935089868b86870909955089858609935089858b868709099450898986098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e088098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b840901017f0fa3ec5b9488259c2eb4cf24501bfad9be2ec9e42c5cc8ccd419d2a692cad870019350898886098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2388098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771840901017f193c0e04e0bd298357cb266c1506080ed36edce85c648cc085e8c57b1ab54bba019250898786098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291188098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7840901017f102adf8ef74735a27e9128306dcbc3c99f6f7291cd406578ce14ea2adaba68f801915089848509905089848b83840909935089838409905089838b83840909925089828309905089828b838409099150898983098a7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e085098b7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b870901017f0fe0af7858e49859e2a54d6f1ad945b1316aa24bfbdd23ae40a6d0cb70c3eab1019050898883098a7f2e2419f9ec02ec394c9871c832963dc1b89d743c8c7b964029b2311687b1fe2385098b7f2969f27eed31a480b9c36c764379dbca2cc8fdd1415c3dded62940bcde0bd771870901017f216f6717bbc7dedb08536a2220843f4e2da5f1daa9ebdefde8a5ea7344798d22019550898783098a7f176cc029695ad02582a70eff08a6fd99d057e12e58e7d7b6b16cdfabc8ee291185098b7f143021ec686a3f330d5f9e654638065ce6cd79e28c5b3753326244ee65a1b1a7870901017f1da55cc900f0d21f4a3e694391918a1b3c23b2ac773c6b3ef88e2e422832516101945089818209935089818b86870909905089868709935089868b86870909955089858609935089858b868709099450898a8a87098b7f16ed41e13bb9c0c66ae119424fddbcbc9314dc9fdbdeea55d6c64543dc4903e089098c7f109b7f411ba0e4c9b2b70caf5c36a7b194be7c11ad24378bfedb68592ba8118b850901010660005260206000f35b600060408284031215615b5057600080fd5b82601f830112615b5f57600080fd5b6040516040810181811067ffffffffffffffff82111715615ba9577f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b8060405250806040840185811115615bc057600080fd5b845b81811015615bda578035835260209283019201615bc2565b50919594505050505056" +const LazyIMT* = + "0x611e7861003a600b82828239805160001a60731461002d57634e487b7160e01b600052600060045260246000fd5b30600052607381538281f3fe73000000000000000000000000000000000000000030146080604052600436106100ad5760003560e01c80633c251db111610080578063899375d611610065578063899375d614610183578063b7ca3a2d146101c6578063ca9ecfd4146101d957600080fd5b80633c251db11461014357806361136cec1461016357600080fd5b80630224ef5e146100b257806309489a3c146100d45780630c26d683146100f457806339ebe6e314610122575b600080fd5b8180156100be57600080fd5b506100d26100cd366004611a23565b6101ec565b005b8180156100e057600080fd5b506100d26100ef366004611a5f565b6101fa565b610107610102366004611aa5565b61020a565b60405164ffffffffff90911681526020015b60405180910390f35b610135610130366004611ad8565b61021f565b604051908152602001610119565b610156610151366004611afb565b61022b565b6040516101199190611b2e565b81801561016f57600080fd5b506100d261017e366004611ad8565b610242565b81801561018f57600080fd5b506100d261019e366004611b72565b80547fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff169055565b6101356101d4366004611b72565b61024c565b6101356101e7366004611b8b565b610257565b6101f68282610262565b5050565b6102058383836104d9565b505050565b60006102168383610812565b90505b92915050565b60006102168383610830565b6060610238848484610987565b90505b9392505050565b6101f68282610d23565b600061021982610dbd565b600061021982610e15565b815465010000000000900464ffffffffff167f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001821061030e5760405162461bcd60e51b815260206004820152602a60248201527f4c617a79494d543a206c656166206d757374206265203c20534e41524b5f534360448201527f414c41525f4649454c440000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b825464ffffffffff908116908216106103695760405162461bcd60e51b815260206004820152601560248201527f4c617a79494d543a20747265652069732066756c6c00000000000000000000006044820152606401610305565b610374816001611bd5565b835464ffffffffff9190911665010000000000027fffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffffff9091161783558160005b818560010160006103c48487610812565b64ffffffffff16815260208101919091526040016000205560018316156104d25760006103fb826103f6600187611bfa565b610812565b60408051808201825264ffffffffff8316600090815260018a01602090815290839020548252810186905290517f561558fe00000000000000000000000000000000000000000000000000000000815291925073__$PoseidonT3$__9163561558fe9161047691600401611c18565b602060405180830381865af4158015610493573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104b79190611c49565b647fffffffff600195861c16949093509190910190506103b3565b5050505050565b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001821061056e5760405162461bcd60e51b815260206004820152602a60248201527f4c617a79494d543a206c656166206d757374206265203c20534e41524b5f534360448201527f414c41525f4649454c44000000000000000000000000000000000000000000006064820152608401610305565b825464ffffffffff65010000000000909104811690821681116105d35760405162461bcd60e51b815260206004820152601860248201527f4c617a79494d543a206c656166206d75737420657869737400000000000000006044820152606401610305565b8260005b818660010160006105e88488610812565b64ffffffffff1681526020019081526020016000208190555060008160016106109190611c62565b60ff168464ffffffffff16901c64ffffffffff16905060018564ffffffffff16901c64ffffffffff168111610645575061080a565b60018516600003610725576000610661836103f6886001611bd5565b60408051808201825286815264ffffffffff8316600090815260018c01602090815290839020549082015290517f561558fe00000000000000000000000000000000000000000000000000000000815291925073__$PoseidonT3$__9163561558fe916106dc91600401611c18565b602060405180830381865af41580156106f9573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071d9190611c49565b9350506107f6565b6000610736836103f6600189611bfa565b60408051808201825264ffffffffff8316600090815260018c01602090815290839020548252810187905290517f561558fe00000000000000000000000000000000000000000000000000000000815291925073__$PoseidonT3$__9163561558fe916107b191600401611c18565b602060405180830381865af41580156107ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107f29190611c49565b9350505b50647fffffffff600194851c1693016105d7565b505050505050565b60008161082660ff851663ffffffff611c7b565b6102169190611bd5565b6000808260ff16116108845760405162461bcd60e51b815260206004820152601a60248201527f4c617a79494d543a206465707468206d757374206265203e20300000000000006044820152606401610305565b602060ff831611156108fe5760405162461bcd60e51b815260206004820152602360248201527f4c617a79494d543a206465707468206d757374206265203c3d204d41585f444560448201527f50544800000000000000000000000000000000000000000000000000000000006064820152608401610305565b825465010000000000900464ffffffffff168061091f60ff85166002611db9565b64ffffffffff1610156109745760405162461bcd60e51b815260206004820152601860248201527f4c617a79494d543a20616d626967756f757320646570746800000000000000006044820152606401610305565b61097f8482856114b2565b949350505050565b825460609064ffffffffff65010000000000909104811690841681116109ef5760405162461bcd60e51b815260206004820152601860248201527f4c617a79494d543a206c656166206d75737420657869737400000000000000006044820152606401610305565b60015b64ffffffffff8216610a0860ff83166002611db9565b64ffffffffff161015610a275780610a1f81611dcf565b9150506109f2565b8060ff168460ff161015610a7d5760405162461bcd60e51b815260206004820152601460248201527f4c617a79494d543a2070726f6f662064657074680000000000000000000000006044820152606401610305565b60008460ff1667ffffffffffffffff811115610a9b57610a9b611dee565b604051908082528060200260200182016040528015610ac4578160200160208202803683370190505b509050610add8784610ad7600186611e1d565b846115d4565b60018616600003610b765764ffffffffff8316610afb876001611bd5565b64ffffffffff1610610b3557610b116000610e15565b81600081518110610b2457610b24611e36565b602002602001018181525050610bc4565b866001016000610b4d60008960016103f69190611bd5565b64ffffffffff1681526020019081526020016000205481600081518110610b2457610b24611e36565b866001016000610b8e600060018a6103f69190611bfa565b64ffffffffff1681526020019081526020016000205481600081518110610bb757610bb7611e36565b6020026020010181815250505b647fffffffff600196871c16955b8560ff168160ff161015610d185764ffffffffff80851660ff83161c1660018816600003610cb55780610c06896001611bd5565b64ffffffffff161015610c6657886001016000610c2a848b60016103f69190611bd5565b64ffffffffff16815260200190815260200160002054838360ff1681518110610c5557610c55611e36565b602002602001018181525050610d04565b64ffffffffff881660ff8316610c7d600188611bfa565b64ffffffffff16901c64ffffffffff1611610cb057610c9b82610e15565b838360ff1681518110610c5557610c55611e36565b610d04565b886001016000610ccc8460018c6103f69190611bfa565b64ffffffffff16815260200190815260200160002054838360ff1681518110610cf757610cf7611e36565b6020026020010181815250505b50647fffffffff600197881c169601610bd2565b509695505050505050565b602060ff82161115610d775760405162461bcd60e51b815260206004820152601760248201527f4c617a79494d543a205472656520746f6f206c617267650000000000000000006044820152606401610305565b610d88600160ff831681901b611e65565b82547fffffffffffffffffffffffffffffffffffffffffffff000000000000000000001664ffffffffff919091161790915550565b805460009065010000000000900464ffffffffff1660015b64ffffffffff8216610deb60ff83166002611db9565b64ffffffffff161015610e0a5780610e0281611dcf565b915050610dd5565b61097f8483836114b2565b60008160ff16600003610e2a57506000919050565b8160ff16600103610e5c57507f2098f5fb9e239eab3ceac3f27b81e481dc3124d55ffed523a839ee8446b64864919050565b8160ff16600203610e8e57507f1069673dcdb12263df301a6ff584a7ec261a44cb9dc68df067a4774460b1f1e1919050565b8160ff16600303610ec057507f18f43331537ee2af2e3d758d50f72106467c6eea50371dd528d57eb2b856d238919050565b8160ff16600403610ef257507f07f9d837cb17b0d36320ffe93ba52345f1b728571a568265caac97559dbc952a919050565b8160ff16600503610f2457507f2b94cf5e8746b3f5c9631f4c5df32907a699c58c94b2ad4d7b5cec1639183f55919050565b8160ff16600603610f5657507f2dee93c5a666459646ea7d22cca9e1bcfed71e6951b953611d11dda32ea09d78919050565b8160ff16600703610f8857507f078295e5a22b84e982cf601eb639597b8b0515a88cb5ac7fa8a4aabe3c87349d919050565b8160ff16600803610fba57507f2fa5e5f18f6027a6501bec864564472a616b2e274a41211a444cbe3a99f3cc61919050565b8160ff16600903610fec57507f0e884376d0d8fd21ecb780389e941f66e45e7acce3e228ab3e2156a614fcd747919050565b8160ff16600a0361101e57507f1b7201da72494f1e28717ad1a52eb469f95892f957713533de6175e5da190af2919050565b8160ff16600b0361105057507f1f8d8822725e36385200c0b201249819a6e6e1e4650808b5bebc6bface7d7636919050565b8160ff16600c0361108257507f2c5d82f66c914bafb9701589ba8cfcfb6162b0a12acf88a8d0879a0471b5f85a919050565b8160ff16600d036110b457507f14c54148a0940bb820957f5adf3fa1134ef5c4aaa113f4646458f270e0bfbfd0919050565b8160ff16600e036110e657507f190d33b12f986f961e10c0ee44d8b9af11be25588cad89d416118e4bf4ebe80c919050565b8160ff16600f0361111857507f22f98aa9ce704152ac17354914ad73ed1167ae6596af510aa5b3649325e06c92919050565b8160ff1660100361114a57507f2a7c7c9b6ce5880b9f6f228d72bf6a575a526f29c66ecceef8b753d38bba7323919050565b8160ff1660110361117c57507f2e8186e558698ec1c67af9c14d463ffc470043c9c2988b954d75dd643f36b992919050565b8160ff166012036111ae57507f0f57c5571e9a4eab49e2c8cf050dae948aef6ead647392273546249d1c1ff10f919050565b8160ff166013036111e057507f1830ee67b5fb554ad5f63d4388800e1cfe78e310697d46e43c9ce36134f72cca919050565b8160ff1660140361121257507f2134e76ac5d21aab186c2be1dd8f84ee880a1e46eaf712f9d371b6df22191f3e919050565b8160ff1660150361124457507f19df90ec844ebc4ffeebd866f33859b0c051d8c958ee3aa88f8f8df3db91a5b1919050565b8160ff1660160361127657507f18cca2a66b5c0787981e69aefd84852d74af0e93ef4912b4648c05f722efe52b919050565b8160ff166017036112a857507f2388909415230d1b4d1304d2d54f473a628338f2efad83fadf05644549d2538d919050565b8160ff166018036112da57507f27171fb4a97b6cc0e9e8f543b5294de866a2af2c9c8d0b1d96e673e4529ed540919050565b8160ff1660190361130c57507f2ff6650540f629fd5711a0bc74fc0d28dcb230b9392583e5f8d59696dde6ae21919050565b8160ff16601a0361133e57507f120c58f143d491e95902f7f5277778a2e0ad5168f6add75669932630ce611518919050565b8160ff16601b0361137057507f1f21feb70d3f21b07bf853d5e5db03071ec495a0a565a21da2d665d279483795919050565b8160ff16601c036113a257507f24be905fa71335e14c638cc0f66a8623a826e768068a9e968bb1a1dde18a72d2919050565b8160ff16601d036113d457507f0f8666b62ed17491c50ceadead57d4cd597ef3821d65c328744c74e553dac26d919050565b8160ff16601e0361140657507f0918d46bf52d98b034413f4a1a1c41594e7a7a3f6ae08cb43d1a2a230e1959ef919050565b8160ff16601f0361143857507f1bbeb01b4c479ecde76917645e404dfa2e26f90d0afc5a65128513ad375c5ff2919050565b8160ff1660200361146a57507f2f68a1c58e257e42a17a6c61dff5551ed560b9922ab119d5ac8e184c9734ead9919050565b60405162461bcd60e51b815260206004820152601e60248201527f4c617a79494d543a2064656661756c745a65726f2062616420696e64657800006044820152606401610305565b6000602060ff8316111561152e5760405162461bcd60e51b815260206004820152602360248201527f4c617a79494d543a206465707468206d757374206265203c3d204d41585f444560448201527f50544800000000000000000000000000000000000000000000000000000000006064820152608401610305565b8264ffffffffff1660000361154d5761154682610e15565b905061023b565b600061155a836001611c62565b60ff1667ffffffffffffffff81111561157557611575611dee565b60405190808252806020026020018201604052801561159e578160200160208202803683370190505b5090506115ad858585846115d4565b808360ff16815181106115c2576115c2611e36565b60200260200101519150509392505050565b602060ff8316111561164e5760405162461bcd60e51b815260206004820152602360248201527f4c617a79494d543a206465707468206d757374206265203c3d204d41585f444560448201527f50544800000000000000000000000000000000000000000000000000000000006064820152608401610305565b60008364ffffffffff16116116cb5760405162461bcd60e51b815260206004820152602560248201527f4c617a79494d543a206e756d626572206f66206c6561766573206d757374206260448201527f65203e20300000000000000000000000000000000000000000000000000000006064820152608401610305565b60006116d8600185611bfa565b905060018116600003611730578460010160006116f6600084610812565b64ffffffffff168152602001908152602001600020548260008151811061171f5761171f611e36565b60200260200101818152505061175a565b61173a6000610e15565b8260008151811061174d5761174d611e36565b6020026020010181815250505b60005b8360ff168160ff16101561080a57600182166000036118565773__$PoseidonT3$__63561558fe6040518060400160405280868560ff16815181106117b0576117b0611e36565b602002602001015181526020016117c685610e15565b8152506040518263ffffffff1660e01b81526004016117e59190611c18565b602060405180830381865af4158015611802573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118269190611c49565b83611832836001611c62565b60ff168151811061184557611845611e36565b602002602001018181525050611a10565b6000611863826001611c62565b60ff168664ffffffffff16901c64ffffffffff16905060018364ffffffffff16901c64ffffffffff168111156119085760008760010160006118bc8560016118ab9190611c62565b60018864ffffffffff16901c610812565b64ffffffffff16815260200190815260200160002054905080858460016118e39190611c62565b60ff16815181106118f6576118f6611e36565b60200260200101818152505050611a0e565b6000876001016000611921856001886103f69190611bfa565b64ffffffffff16815260200190815260200160002054905073__$PoseidonT3$__63561558fe6040518060400160405280848152602001888760ff168151811061197957611979611e36565b60200260200101518152506040518263ffffffff1660e01b81526004016119a09190611c18565b602060405180830381865af41580156119bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e19190611c49565b856119ed856001611c62565b60ff1681518110611a0057611a00611e36565b602002602001018181525050505b505b647fffffffff600192831c16910161175d565b60008060408385031215611a3657600080fd5b50508035926020909101359150565b803564ffffffffff81168114611a5a57600080fd5b919050565b600080600060608486031215611a7457600080fd5b8335925060208401359150611a8b60408501611a45565b90509250925092565b803560ff81168114611a5a57600080fd5b60008060408385031215611ab857600080fd5b611ac183611a94565b9150611acf60208401611a45565b90509250929050565b60008060408385031215611aeb57600080fd5b82359150611acf60208401611a94565b600080600060608486031215611b1057600080fd5b83359250611b2060208501611a45565b9150611a8b60408501611a94565b6020808252825182820181905260009190848201906040850190845b81811015611b6657835183529284019291840191600101611b4a565b50909695505050505050565b600060208284031215611b8457600080fd5b5035919050565b600060208284031215611b9d57600080fd5b61021682611a94565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b64ffffffffff818116838216019080821115611bf357611bf3611ba6565b5092915050565b64ffffffffff828116828216039080821115611bf357611bf3611ba6565b60408101818360005b6002811015611c40578151835260209283019290910190600101611c21565b50505092915050565b600060208284031215611c5b57600080fd5b5051919050565b60ff818116838216019081111561021957610219611ba6565b64ffffffffff818116838216028082169190828114611c9c57611c9c611ba6565b505092915050565b600181815b80851115611ce2578164ffffffffff04821115611cc857611cc8611ba6565b80851615611cd557918102915b93841c9390800290611ca9565b509250929050565b600082611cf957506001610219565b81611d0657506000610219565b8160018114611d1c5760028114611d2657611d58565b6001915050610219565b60ff841115611d3757611d37611ba6565b6001841b915064ffffffffff821115611d5257611d52611ba6565b50610219565b5060208310610133831016604e8410600b8410161715611d90575081810a64ffffffffff811115611d8b57611d8b611ba6565b610219565b611d9a8383611ca4565b8064ffffffffff04821115611db157611db1611ba6565b029392505050565b600064ffffffffff61097f818516828516611cea565b600060ff821660ff8103611de557611de5611ba6565b60010192915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60ff828116828216039081111561021957610219611ba6565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b8181038181111561021957610219611ba656" +const Erc1967Proxy* = + "0x60806040526040516103c73803806103c78339810160408190526100229161025e565b61002c8282610033565b5050610341565b61003c82610091565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a280511561008557610080828261010c565b505050565b61008d61017f565b5050565b806001600160a01b03163b5f036100cb57604051634c9c8ce360e01b81526001600160a01b03821660048201526024015b60405180910390fd5b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b60605f80846001600160a01b0316846040516101289190610326565b5f60405180830381855af49150503d805f8114610160576040519150601f19603f3d011682016040523d82523d5f602084013e610165565b606091505b5090925090506101768583836101a0565b95945050505050565b341561019e5760405163b398979f60e01b815260040160405180910390fd5b565b6060826101b5576101b0826101ff565b6101f8565b81511580156101cc57506001600160a01b0384163b155b156101f557604051639996b31560e01b81526001600160a01b03851660048201526024016100c2565b50805b9392505050565b80511561020f5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b634e487b7160e01b5f52604160045260245ffd5b5f5b8381101561025657818101518382015260200161023e565b50505f910152565b5f806040838503121561026f575f80fd5b82516001600160a01b0381168114610285575f80fd5b60208401519092506001600160401b03808211156102a1575f80fd5b818501915085601f8301126102b4575f80fd5b8151818111156102c6576102c6610228565b604051601f8201601f19908116603f011681019083821181831017156102ee576102ee610228565b81604052828152886020848701011115610306575f80fd5b61031783602083016020880161023c565b80955050505050509250929050565b5f825161033781846020870161023c565b9190910192915050565b607a8061034d5f395ff3fe6080604052600a600c565b005b60186014601a565b605d565b565b5f60587f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b905090565b365f80375f80365f845af43d5f803e8080156076573d5ff35b3d5ffd" +const Erc1967ProxyContractInput* = + "000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000248d8965bd0000000000000000000000000000000000000000000000000000000000000014" + +const WakuRlnV2Contract* = + "0x60a06040523060805234801561001457600080fd5b5061001d610022565b6100e1565b600054610100900460ff161561008e5760405162461bcd60e51b815260206004820152602760248201527f496e697469616c697a61626c653a20636f6e747261637420697320696e697469604482015266616c697a696e6760c81b606482015260840160405180910390fd5b60005460ff908116146100df576000805460ff191660ff9081179091556040519081527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15b565b6080516121ca6200011960003960008181610598015281816106330152818161076e01528181610804015261093301526121ca6000f3fe6080604052600436106101805760003560e01c806374e942fa116100d6578063af7b42101161007f578063e493ef8c11610059578063e493ef8c146104e2578063ebf0c71714610516578063f2fde38b1461052b57600080fd5b8063af7b421014610441578063d0383d6814610461578063d90d0ee61461048657600080fd5b806398366e35116100b057806398366e35146103b75780639ac21345146103de578063a45d5e591461042157600080fd5b806374e942fa146103355780638d8965bd146103625780638da5cb5b1461038257600080fd5b80634add651e11610138578063679537f911610112578063679537f9146102d35780636bdcc8ab14610300578063715018a61461032057600080fd5b80634add651e146102805780634f1ef2861461029d57806352d1902d146102b057600080fd5b806322d9730c1161016957806322d9730c146101e55780633659cfe6146102155780633c979b5f1461023757600080fd5b8063037a791a1461018557806309aeb04c146101c8575b600080fd5b34801561019157600080fd5b5060c9546101ae9068010000000000000000900463ffffffff1681565b60405163ffffffff90911681526020015b60405180910390f35b3480156101d457600080fd5b5060c9546101ae9063ffffffff1681565b3480156101f157600080fd5b50610205610200366004611c81565b61054b565b60405190151581526020016101bf565b34801561022157600080fd5b50610235610230366004611cc3565b610581565b005b34801561024357600080fd5b5060cc546102629064ffffffffff808216916501000000000090041682565b6040805164ffffffffff9384168152929091166020830152016101bf565b34801561028c57600080fd5b5060cb546101ae9063ffffffff1681565b6102356102ab366004611d5c565b610757565b3480156102bc57600080fd5b506102c5610919565b6040519081526020016101bf565b3480156102df57600080fd5b506102f36102ee366004611e34565b6109eb565b6040516101bf9190611e67565b34801561030c57600080fd5b5061020561031b366004611c81565b610b6a565b34801561032c57600080fd5b50610235610b81565b34801561034157600080fd5b50610355610350366004611ebe565b610b95565b6040516101bf9190611edb565b34801561036e57600080fd5b5061023561037d366004611f0d565b610cc4565b34801561038e57600080fd5b5060335460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101bf565b3480156103c357600080fd5b506103cc601481565b60405160ff90911681526020016101bf565b3480156103ea57600080fd5b506103fe6103f9366004611c81565b610f5f565b6040805163ffffffff9485168152939092166020840152908201526060016101bf565b34801561042d57600080fd5b5061020561043c366004611f0d565b610fd0565b34801561044d57600080fd5b5061023561045c366004611f28565b610ff5565b34801561046d57600080fd5b5060c9546101ae90640100000000900463ffffffff1681565b34801561049257600080fd5b506104c56104a1366004611c81565b60ca6020526000908152604090205463ffffffff8082169164010000000090041682565b6040805163ffffffff9384168152929091166020830152016101bf565b3480156104ee57600080fd5b506102c57f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000181565b34801561052257600080fd5b506102c5611090565b34801561053757600080fd5b50610235610546366004611cc3565b61112c565b6000811580159061057b57507f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f000000182105b92915050565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630036106315760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c000000000000000000000000000000000000000060648201526084015b60405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166106a67f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff161461072f5760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f787900000000000000000000000000000000000000006064820152608401610628565b610738816111c6565b60408051600080825260208201909252610754918391906111ce565b50565b73ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001630036108025760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f64656c656761746563616c6c00000000000000000000000000000000000000006064820152608401610628565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166108777f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff16146109005760405162461bcd60e51b815260206004820152602c60248201527f46756e6374696f6e206d7573742062652063616c6c6564207468726f7567682060448201527f6163746976652070726f787900000000000000000000000000000000000000006064820152608401610628565b610909826111c6565b610915828260016111ce565b5050565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146109c65760405162461bcd60e51b815260206004820152603860248201527f555550535570677261646561626c653a206d757374206e6f742062652063616c60448201527f6c6564207468726f7567682064656c656761746563616c6c00000000000000006064820152608401610628565b507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc90565b60608163ffffffff168363ffffffff161115610a43576040517f9ffcd53d00000000000000000000000000000000000000000000000000000000815263ffffffff808516600483015283166024820152604401610628565b60c95463ffffffff6801000000000000000090910481169083161115610aa5576040517f9ffcd53d00000000000000000000000000000000000000000000000000000000815263ffffffff808516600483015283166024820152604401610628565b6000610ab18484611f7a565b610abc906001611f9e565b63ffffffff1667ffffffffffffffff811115610ada57610ada611cde565b604051908082528060200260200182016040528015610b03578160200160208202803683370190505b509050835b8363ffffffff168163ffffffff1611610b6257610b248161139e565b82610b2f8784611f7a565b63ffffffff1681518110610b4557610b45611fbb565b602090810291909101015280610b5a81611fea565b915050610b08565b509392505050565b600080610b7683610f5f565b151595945050505050565b610b8961145c565b610b9360006114c3565b565b610b9d611c62565b610ba5611c62565b6040517f3c251db100000000000000000000000000000000000000000000000000000000815260cc600482015264ffffffffff841660248201526014604482015260009073__$LazyIMT$__90633c251db190606401600060405180830381865af4158015610c25573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201604052610c6b919081019061200d565b905060005b601460ff82161015610cbb57818160ff1681518110610c9157610c91611fbb565b6020026020010151838260ff1660148110610cae57610cae611fbb565b6020020152600101610c70565b50909392505050565b600054610100900460ff1615808015610ce45750600054600160ff909116105b80610cfe5750303b158015610cfe575060005460ff166001145b610d705760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201527f647920696e697469616c697a65640000000000000000000000000000000000006064820152608401610628565b600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790558015610dce57600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790555b610dd661153a565b610dde6115bf565b60c9805463ffffffff8481167fffffffffffffffffffffffffffffffffffffffffffffffff00000000000000009092169190911766100000000000001790915560cb80547fffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000016439092169190911790556040517f61136cec00000000000000000000000000000000000000000000000000000000815260cc60048201526014602482015273__$LazyIMT$__906361136cec9060440160006040518083038186803b158015610eb957600080fd5b505af4158015610ecd573d6000803e3d6000fd5b505060c980547fffffffffffffffffffffffffffffffffffffffff00000000ffffffffffffffff1690555050801561091557600080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff169055604051600181527f7f26b83ff96e1f2b6a682f133852f6798a09c465da95921460cefb38474024989060200160405180910390a15050565b600081815260ca6020908152604080832081518083019092525463ffffffff808216808452640100000000909204169282019290925282918291908203610fb157600080600093509350935050610fc9565b80516020820151610fc18161139e565b935093509350505b9193909250565b6000808263ffffffff1611801561057b57505060c95463ffffffff9081169116111590565b81610fff8161054b565b611038576040517f7f3e75af00000000000000000000000000000000000000000000000000000000815260048101829052602401610628565b8161104281610fd0565b611080576040517f6677a0c700000000000000000000000000000000000000000000000000000000815263ffffffff82166004820152602401610628565b61108a848461163c565b50505050565b6040517f39ebe6e300000000000000000000000000000000000000000000000000000000815260cc60048201526014602482015260009073__$LazyIMT$__906339ebe6e390604401602060405180830381865af4158015611103573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112791906120b3565b905090565b61113461145c565b73ffffffffffffffffffffffffffffffffffffffff81166111bd5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610628565b610754816114c3565b61075461145c565b7f4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd91435460ff16156112065761120183611911565b505050565b8273ffffffffffffffffffffffffffffffffffffffff166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa92505050801561128b575060408051601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0168201909252611288918101906120b3565b60015b6112fd5760405162461bcd60e51b815260206004820152602e60248201527f45524331393637557067726164653a206e657720696d706c656d656e7461746960448201527f6f6e206973206e6f7420555550530000000000000000000000000000000000006064820152608401610628565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81146113925760405162461bcd60e51b815260206004820152602960248201527f45524331393637557067726164653a20756e737570706f727465642070726f7860448201527f6961626c655555494400000000000000000000000000000000000000000000006064820152608401610628565b50611201838383611a01565b6040517f0c26d68300000000000000000000000000000000000000000000000000000000815260006004820181905263ffffffff831660248301529060cd90829073__$LazyIMT$__90630c26d68390604401602060405180830381865af415801561141b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061143f91906120cc565b64ffffffffff168152602001908152602001600020549050919050565b60335473ffffffffffffffffffffffffffffffffffffffff163314610b935760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610628565b6033805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b600054610100900460ff166115b75760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610628565b610b93611a26565b600054610100900460ff16610b935760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610628565b61164582610b6a565b1561167b576040517e0a60f700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60c95463ffffffff640100000000820481166801000000000000000090920416106116d2576040517f57f6953100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60408051808201825283815263ffffffff8316602082015290517f561558fe00000000000000000000000000000000000000000000000000000000815260009173__$PoseidonT3$__9163561558fe9161173a916004016120e9565b602060405180830381865af4158015611757573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061177b91906120b3565b60408051808201825263ffffffff858116825260c95468010000000000000000900416602082015290517f0224ef5e00000000000000000000000000000000000000000000000000000000815260cc6004820152602481018390529192509073__$LazyIMT$__90630224ef5e9060440160006040518083038186803b15801561181157600080fd5b505af4158015611825573d6000803e3d6000fd5b505050600085815260ca6020908152604091829020845181548684015163ffffffff908116640100000000027fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000909216928116929092171790915560c954835187815268010000000000000000909104909116918101919091527fb84da12e8207adb5ee3e5686338302ffe6634fbb95a9fd52f8a466ea2010152d92500160405180910390a1600160c960088282829054906101000a900463ffffffff166118ed9190611f9e565b92506101000a81548163ffffffff021916908363ffffffff16021790555050505050565b73ffffffffffffffffffffffffffffffffffffffff81163b61199b5760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201527f6f74206120636f6e7472616374000000000000000000000000000000000000006064820152608401610628565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b611a0a83611aac565b600082511180611a175750805b156112015761108a8383611af9565b600054610100900460ff16611aa35760405162461bcd60e51b815260206004820152602b60248201527f496e697469616c697a61626c653a20636f6e7472616374206973206e6f74206960448201527f6e697469616c697a696e670000000000000000000000000000000000000000006064820152608401610628565b610b93336114c3565b611ab581611911565b60405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b6060611b1e83836040518060600160405280602781526020016121a360279139611b25565b9392505050565b60606000808573ffffffffffffffffffffffffffffffffffffffff1685604051611b4f9190612135565b600060405180830381855af49150503d8060008114611b8a576040519150601f19603f3d011682016040523d82523d6000602084013e611b8f565b606091505b5091509150611ba086838387611baa565b9695505050505050565b60608315611c26578251600003611c1f5773ffffffffffffffffffffffffffffffffffffffff85163b611c1f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401610628565b5081611c30565b611c308383611c38565b949350505050565b815115611c485781518083602001fd5b8060405162461bcd60e51b81526004016106289190612151565b6040518061028001604052806014906020820280368337509192915050565b600060208284031215611c9357600080fd5b5035919050565b803573ffffffffffffffffffffffffffffffffffffffff81168114611cbe57600080fd5b919050565b600060208284031215611cd557600080fd5b611b1e82611c9a565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff81118282101715611d5457611d54611cde565b604052919050565b60008060408385031215611d6f57600080fd5b611d7883611c9a565b915060208084013567ffffffffffffffff80821115611d9657600080fd5b818601915086601f830112611daa57600080fd5b813581811115611dbc57611dbc611cde565b611dec847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601611d0d565b91508082528784828501011115611e0257600080fd5b80848401858401376000848284010152508093505050509250929050565b803563ffffffff81168114611cbe57600080fd5b60008060408385031215611e4757600080fd5b611e5083611e20565b9150611e5e60208401611e20565b90509250929050565b6020808252825182820181905260009190848201906040850190845b81811015611e9f57835183529284019291840191600101611e83565b50909695505050505050565b64ffffffffff8116811461075457600080fd5b600060208284031215611ed057600080fd5b8135611b1e81611eab565b6102808101818360005b6014811015611f04578151835260209283019290910190600101611ee5565b50505092915050565b600060208284031215611f1f57600080fd5b611b1e82611e20565b60008060408385031215611f3b57600080fd5b82359150611e5e60208401611e20565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b63ffffffff828116828216039080821115611f9757611f97611f4b565b5092915050565b63ffffffff818116838216019080821115611f9757611f97611f4b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600063ffffffff80831681810361200357612003611f4b565b6001019392505050565b6000602080838503121561202057600080fd5b825167ffffffffffffffff8082111561203857600080fd5b818501915085601f83011261204c57600080fd5b81518181111561205e5761205e611cde565b8060051b915061206f848301611d0d565b818152918301840191848101908884111561208957600080fd5b938501935b838510156120a75784518252938501939085019061208e565b98975050505050505050565b6000602082840312156120c557600080fd5b5051919050565b6000602082840312156120de57600080fd5b8151611b1e81611eab565b60408101818360005b6002811015611f045781518352602092830192909101906001016120f2565b60005b8381101561212c578181015183820152602001612114565b50506000910152565b60008251612147818460208701612111565b9190910192915050565b6020815260008251806020840152612170816040850160208701612111565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016040019291505056fe416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c206661696c6564" diff --git a/waku/waku_rln_relay/conversion_utils.nim b/waku/waku_rln_relay/conversion_utils.nim index 5744507f8a..afdae614d7 100644 --- a/waku/waku_rln_relay/conversion_utils.nim +++ b/waku/waku_rln_relay/conversion_utils.nim @@ -30,9 +30,8 @@ proc inHex*( valueHex = "0" & valueHex return toLowerAscii(valueHex) -when defined(rln_v2): - proc toUserMessageLimit*(v: UInt256): UserMessageLimit = - return cast[UserMessageLimit](v) +proc toUserMessageLimit*(v: UInt256): UserMessageLimit = + return cast[UserMessageLimit](v) proc encodeLengthPrefix*(input: openArray[byte]): seq[byte] = ## returns length prefixed version of the input @@ -56,75 +55,47 @@ proc serialize*(v: uint64): array[32, byte] = discard output.copyFrom(bytes) return output -when defined(rln_v2): - proc serialize*( - idSecretHash: IdentitySecretHash, - memIndex: MembershipIndex, - userMessageLimit: UserMessageLimit, - messageId: MessageId, - externalNullifier: ExternalNullifier, - msg: openArray[byte], - ): seq[byte] = - ## a private proc to convert RateLimitProof and the data to a byte seq - ## this conversion is used in the proofGen proc - ## the serialization is done as instructed in https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L146 - ## [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] - let memIndexBytes = toBytes(uint64(memIndex), Endianness.littleEndian) - let userMessageLimitBytes = userMessageLimit.serialize() - let messageIdBytes = messageId.serialize() - let lenPrefMsg = encodeLengthPrefix(msg) - let output = concat( - @idSecretHash, - @memIndexBytes, - @userMessageLimitBytes, - @messageIdBytes, - @externalNullifier, - lenPrefMsg, - ) - return output +proc serialize*( + idSecretHash: IdentitySecretHash, + memIndex: MembershipIndex, + userMessageLimit: UserMessageLimit, + messageId: MessageId, + externalNullifier: ExternalNullifier, + msg: openArray[byte], +): seq[byte] = + ## a private proc to convert RateLimitProof and the data to a byte seq + ## this conversion is used in the proofGen proc + ## the serialization is done as instructed in https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L146 + ## [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] + let memIndexBytes = toBytes(uint64(memIndex), Endianness.littleEndian) + let userMessageLimitBytes = userMessageLimit.serialize() + let messageIdBytes = messageId.serialize() + let lenPrefMsg = encodeLengthPrefix(msg) + let output = concat( + @idSecretHash, + @memIndexBytes, + @userMessageLimitBytes, + @messageIdBytes, + @externalNullifier, + lenPrefMsg, + ) + return output -else: - proc serialize*( - idSecretHash: IdentitySecretHash, - memIndex: MembershipIndex, - epoch: Epoch, - msg: openArray[byte], - ): seq[byte] = - ## a private proc to convert RateLimitProof and the data to a byte seq - ## this conversion is used in the proofGen proc - ## the serialization is done as instructed in https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L146 - ## [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal ] - let memIndexBytes = toBytes(uint64(memIndex), Endianness.littleEndian) - let lenPrefMsg = encodeLengthPrefix(msg) - let output = concat(@idSecretHash, @memIndexBytes, @epoch, lenPrefMsg) - return output proc serialize*(proof: RateLimitProof, data: openArray[byte]): seq[byte] = ## a private proc to convert RateLimitProof and data to a byte seq ## this conversion is used in the proof verification proc ## [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal ] let lenPrefMsg = encodeLengthPrefix(@data) - when defined(rln_v2): - var proofBytes = concat( - @(proof.proof), - @(proof.merkleRoot), - @(proof.externalNullifier), - @(proof.shareX), - @(proof.shareY), - @(proof.nullifier), - lenPrefMsg, - ) - else: - var proofBytes = concat( - @(proof.proof), - @(proof.merkleRoot), - @(proof.epoch), - @(proof.shareX), - @(proof.shareY), - @(proof.nullifier), - @(proof.rlnIdentifier), - lenPrefMsg, - ) + var proofBytes = concat( + @(proof.proof), + @(proof.merkleRoot), + @(proof.externalNullifier), + @(proof.shareX), + @(proof.shareY), + @(proof.nullifier), + lenPrefMsg, + ) return proofBytes diff --git a/waku/waku_rln_relay/group_manager/group_manager_base.nim b/waku/waku_rln_relay/group_manager/group_manager_base.nim index 6fce958300..97aaec0998 100644 --- a/waku/waku_rln_relay/group_manager/group_manager_base.nim +++ b/waku/waku_rln_relay/group_manager/group_manager_base.nim @@ -15,10 +15,7 @@ export options, chronos, results, protocol_types, protocol_metrics, deques type Membership* = object index*: MembershipIndex - when defined(rln_v2): - rateCommitment*: RateCommitment - else: - idCommitment*: IDCommitment + rateCommitment*: RawRateCommitment type OnRegisterCallback* = proc(registrations: seq[Membership]): Future[void] {.gcsafe.} type OnWithdrawCallback* = proc(withdrawals: seq[Membership]): Future[void] {.gcsafe.} @@ -35,8 +32,7 @@ type GroupManager* = ref object of RootObj latestIndex*: MembershipIndex validRoots*: Deque[MerkleNode] onFatalErrorAction*: OnFatalErrorHandler - when defined(rln_v2): - userMessageLimit*: Option[UserMessageLimit] + userMessageLimit*: Option[UserMessageLimit] # This proc is used to initialize the group manager # Any initialization logic should be implemented here @@ -53,61 +49,35 @@ method startGroupSync*( # This proc is used to register a new identity commitment into the merkle tree # The user may or may not have the identity secret to this commitment # It should be used when detecting new members in the group, and syncing the group state -when defined(rln_v2): - method register*( - g: GroupManager, rateCommitment: RateCommitment - ): Future[void] {.base, async: (raises: [Exception]).} = - raise newException( - CatchableError, "register proc for " & $g.type & " is not implemented yet" - ) - -else: - method register*( - g: GroupManager, idCommitment: IDCommitment - ): Future[void] {.base, async: (raises: [Exception]).} = - raise newException( - CatchableError, "register proc for " & $g.type & " is not implemented yet" - ) +method register*( + g: GroupManager, rateCommitment: RateCommitment +): Future[void] {.base, async: (raises: [Exception]).} = + raise newException( + CatchableError, "register proc for " & $g.type & " is not implemented yet" + ) # This proc is used to register a new identity commitment into the merkle tree # The user should have the identity secret to this commitment # It should be used when the user wants to join the group -when defined(rln_v2): - method register*( - g: GroupManager, - credentials: IdentityCredential, - userMessageLimit: UserMessageLimit, - ): Future[void] {.base, async: (raises: [Exception]).} = - raise newException( - CatchableError, "register proc for " & $g.type & " is not implemented yet" - ) +method register*( + g: GroupManager, + credentials: IdentityCredential, + userMessageLimit: UserMessageLimit, +): Future[void] {.base, async: (raises: [Exception]).} = + raise newException( + CatchableError, "register proc for " & $g.type & " is not implemented yet" + ) -else: - method register*( - g: GroupManager, credentials: IdentityCredential - ): Future[void] {.base, async: (raises: [Exception]).} = - raise newException( - CatchableError, "register proc for " & $g.type & " is not implemented yet" - ) # This proc is used to register a batch of new identity commitments into the merkle tree # The user may or may not have the identity secret to these commitments # It should be used when detecting a batch of new members in the group, and syncing the group state -when defined(rln_v2): - method registerBatch*( - g: GroupManager, rateCommitments: seq[RateCommitment] - ): Future[void] {.base, async: (raises: [Exception]).} = - raise newException( - CatchableError, "registerBatch proc for " & $g.type & " is not implemented yet" - ) - -else: - method registerBatch*( - g: GroupManager, idCommitments: seq[IDCommitment] - ): Future[void] {.base, async: (raises: [Exception]).} = - raise newException( - CatchableError, "registerBatch proc for " & $g.type & " is not implemented yet" - ) +method registerBatch*( + g: GroupManager, rateCommitments: seq[RawRateCommitment] +): Future[void] {.base, async: (raises: [Exception]).} = + raise newException( + CatchableError, "registerBatch proc for " & $g.type & " is not implemented yet" + ) # This proc is used to set a callback that will be called when a new identity commitment is registered # The callback may be called multiple times, and should be used to for any post processing @@ -133,25 +103,15 @@ method withdrawBatch*( ) # This proc is used to insert and remove a set of commitments from the merkle tree -when defined(rln_v2): - method atomicBatch*( - g: GroupManager, - rateCommitments: seq[RateCommitment], - toRemoveIndices: seq[MembershipIndex], - ): Future[void] {.base, async: (raises: [Exception]).} = - raise newException( - CatchableError, "atomicBatch proc for " & $g.type & " is not implemented yet" - ) +method atomicBatch*( + g: GroupManager, + rateCommitments: seq[RateCommitment], + toRemoveIndices: seq[MembershipIndex], +): Future[void] {.base, async: (raises: [Exception]).} = + raise newException( + CatchableError, "atomicBatch proc for " & $g.type & " is not implemented yet" + ) -else: - method atomicBatch*( - g: GroupManager, - idCommitments: seq[IDCommitment], - toRemoveIndices: seq[MembershipIndex], - ): Future[void] {.base, async: (raises: [Exception]).} = - raise newException( - CatchableError, "atomicBatch proc for " & $g.type & " is not implemented yet" - ) method stop*(g: GroupManager): Future[void] {.base, async.} = raise @@ -216,55 +176,34 @@ method verifyProof*( return err("proof verification failed: " & $proofVerifyRes.error()) return ok(proofVerifyRes.value()) -when defined(rln_v2): - method generateProof*( - g: GroupManager, - data: openArray[byte], - epoch: Epoch, - messageId: MessageId, - rlnIdentifier = DefaultRlnIdentifier, - ): GroupManagerResult[RateLimitProof] {.base, gcsafe, raises: [].} = - ## generates a proof for the given data and epoch - ## the proof is generated using the current merkle root - if g.idCredentials.isNone(): - return err("identity credentials are not set") - if g.membershipIndex.isNone(): - return err("membership index is not set") - if g.userMessageLimit.isNone(): - return err("user message limit is not set") - waku_rln_proof_generation_duration_seconds.nanosecondTime: - let proof = proofGen( - rlnInstance = g.rlnInstance, - data = data, - membership = g.idCredentials.get(), - index = g.membershipIndex.get(), - epoch = epoch, - userMessageLimit = g.userMessageLimit.get(), - messageId = messageId, - ).valueOr: - return err("proof generation failed: " & $error) - return ok(proof) +method generateProof*( + g: GroupManager, + data: openArray[byte], + epoch: Epoch, + messageId: MessageId, + rlnIdentifier = DefaultRlnIdentifier, +): GroupManagerResult[RateLimitProof] {.base, gcsafe, raises: [].} = + ## generates a proof for the given data and epoch + ## the proof is generated using the current merkle root + if g.idCredentials.isNone(): + return err("identity credentials are not set") + if g.membershipIndex.isNone(): + return err("membership index is not set") + if g.userMessageLimit.isNone(): + return err("user message limit is not set") + waku_rln_proof_generation_duration_seconds.nanosecondTime: + let proof = proofGen( + rlnInstance = g.rlnInstance, + data = data, + membership = g.idCredentials.get(), + index = g.membershipIndex.get(), + epoch = epoch, + userMessageLimit = g.userMessageLimit.get(), + messageId = messageId, + ).valueOr: + return err("proof generation failed: " & $error) + return ok(proof) -else: - method generateProof*( - g: GroupManager, data: openArray[byte], epoch: Epoch - ): GroupManagerResult[RateLimitProof] {.base, gcsafe, raises: [].} = - ## generates a proof for the given data and epoch - ## the proof is generated using the current merkle root - if g.idCredentials.isNone(): - return err("identity credentials are not set") - if g.membershipIndex.isNone(): - return err("membership index is not set") - waku_rln_proof_generation_duration_seconds.nanosecondTime: - let proof = proofGen( - rlnInstance = g.rlnInstance, - data = data, - memKeys = g.idCredentials.get(), - memIndex = g.membershipIndex.get(), - epoch = epoch, - ).valueOr: - return err("proof generation failed: " & $error) - return ok(proof) method isReady*(g: GroupManager): Future[bool] {.base, async.} = raise newException( diff --git a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim index f6ecdea2e3..a83ae9bb34 100644 --- a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim +++ b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim @@ -31,74 +31,34 @@ logScope: topics = "waku rln_relay onchain_group_manager" # using the when predicate does not work within the contract macro, hence need to dupe -when defined(rln_v2): - contract(WakuRlnRegistry): - # this describes the storage slot to use - proc usingStorageIndex(): Uint16 {.pure.} - # this map contains the address of a given storage slot - proc storages(index: Uint16): Address {.pure.} - # this serves as an entrypoint into the rln storage contract - proc register( - storageIndex: Uint16, idCommitment: Uint256, userMessageLimit: Uint256 - ) - - # this creates a new storage on the rln registry - proc newStorage(maxMessageLimit: Uint256) - # Initializes the implementation contract (only used in unit tests) - proc initialize() - - # membership contract interface - contract(RlnStorage): - # this event is raised when a new member is registered - proc MemberRegistered( - idCommitment: Uint256, userMessageLimit: Uint256, index: Uint256 - ) {.event.} - - # this constant contains the membership deposit of the contract - proc MEMBERSHIP_DEPOSIT(): Uint256 {.pure.} - # this map denotes existence of a given user - proc memberExists(idCommitment: Uint256): Uint256 {.view.} - # this constant describes the next index of a new member - proc idCommitmentIndex(): Uint256 {.view.} - # this constant describes the block number this contract was deployed on - proc deployedBlockNumber(): Uint256 {.view.} -else: - contract(WakuRlnRegistry): - # this describes the storage slot to use - proc usingStorageIndex(): Uint16 {.pure.} - # this map contains the address of a given storage slot - proc storages(index: Uint16): Address {.pure.} - # this serves as an entrypoint into the rln storage contract - proc register(storageIndex: Uint16, idCommitment: Uint256) - # this creates a new storage on the rln registry - proc newStorage() - - # membership contract interface - contract(RlnStorage): - # this event is raised when a new member is registered - proc MemberRegistered(idCommitment: Uint256, index: Uint256) {.event.} - # this constant contains the membership deposit of the contract - proc MEMBERSHIP_DEPOSIT(): Uint256 {.pure.} - # this map denotes existence of a given user - proc memberExists(idCommitment: Uint256): Uint256 {.view.} - # this constant describes the next index of a new member - proc idCommitmentIndex(): Uint256 {.view.} - # this constant describes the block number this contract was deployed on - proc deployedBlockNumber(): Uint256 {.view.} +contract(WakuRlnContract): + # this serves as an entrypoint into the rln membership set + proc register( + idCommitment: UInt256, userMessageLimit: UInt32 + ) + # Initializes the implementation contract (only used in unit tests) + proc initialize(maxMessageLimit: UInt256) + # this event is raised when a new member is registered + proc MemberRegistered( + rateCommitment: UInt256, index: Uint32 + ) {.event.} + + # this function denotes existence of a given user + proc memberExists(idCommitment: Uint256): UInt256 {.view.} + # this constant describes the next index of a new member + proc commitmentIndex(): UInt256 {.view.} + # this constant describes the block number this contract was deployed on + proc deployedBlockNumber(): UInt256 {.view.} type - RegistryContractWithSender = Sender[WakuRlnRegistry] - RlnContractWithSender = Sender[RlnStorage] + WakuRlnContractWithSender = Sender[WakuRlnContract] OnchainGroupManager* = ref object of GroupManager ethClientUrl*: string ethPrivateKey*: Option[string] ethContractAddress*: string ethRpc*: Option[Web3] - rlnContract*: Option[RlnContractWithSender] rlnContractDeployedBlockNumber*: BlockNumber - registryContract*: Option[RegistryContractWithSender] - usingStorageIndex: Option[Uint16] - membershipFee*: Option[Uint256] + wakuRlnContract*: Option[WakuRlnContractWithSender] latestProcessedBlock*: BlockNumber registrationTxHash*: Option[TxHash] chainId*: Option[Quantity] @@ -157,212 +117,109 @@ proc setMetadata*( return err("failed to persist rln metadata: " & getCurrentExceptionMsg()) return ok() -when defined(rln_v2): - method atomicBatch*( - g: OnchainGroupManager, - start: MembershipIndex, - rateCommitments = newSeq[RateCommitment](), - toRemoveIndices = newSeq[MembershipIndex](), - ): Future[void] {.async: (raises: [Exception]), base.} = - initializedGuard(g) - - # convert the rateCommitment struct to a leaf value - let leaves = rateCommitments.toLeaves().valueOr: - raise newException( - ValueError, "failed to convert rateCommitments to leaves: " & $error - ) - - waku_rln_membership_insertion_duration_seconds.nanosecondTime: - let operationSuccess = - g.rlnInstance.atomicWrite(some(start), leaves, toRemoveIndices) - if not operationSuccess: - raise newException(CatchableError, "atomic batch operation failed") - # TODO: when slashing is enabled, we need to track slashed members - waku_rln_number_registered_memberships.set(int64(g.rlnInstance.leavesSet())) - - if g.registerCb.isSome(): - var membersSeq = newSeq[Membership]() - for i in 0 ..< rateCommitments.len: - var index = start + MembershipIndex(i) - trace "registering member", rateCommitment = rateCommitments[i], index = index - let member = Membership(rateCommitment: rateCommitments[i], index: index) - membersSeq.add(member) - await g.registerCb.get()(membersSeq) - - g.validRootBuffer = g.slideRootQueue() - -else: - method atomicBatch*( - g: OnchainGroupManager, - start: MembershipIndex, - idCommitments = newSeq[IDCommitment](), - toRemoveIndices = newSeq[MembershipIndex](), - ): Future[void] {.async: (raises: [Exception]), base.} = - initializedGuard(g) - - waku_rln_membership_insertion_duration_seconds.nanosecondTime: - let operationSuccess = - g.rlnInstance.atomicWrite(some(start), idCommitments, toRemoveIndices) - if not operationSuccess: - raise newException(ValueError, "atomic batch operation failed") - # TODO: when slashing is enabled, we need to track slashed members - waku_rln_number_registered_memberships.set(int64(g.rlnInstance.leavesSet())) - - if g.registerCb.isSome(): - var membersSeq = newSeq[Membership]() - for i in 0 ..< idCommitments.len: - var index = start + MembershipIndex(i) - trace "registering member", idCommitment = idCommitments[i], index = index - let member = Membership(idCommitment: idCommitments[i], index: index) - membersSeq.add(member) - await g.registerCb.get()(membersSeq) - - g.validRootBuffer = g.slideRootQueue() - -when defined(rln_v2): - method register*( - g: OnchainGroupManager, rateCommitment: RateCommitment - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) +method atomicBatch*( + g: OnchainGroupManager, + start: MembershipIndex, + rateCommitments = newSeq[RawRateCommitment](), + toRemoveIndices = newSeq[MembershipIndex](), +): Future[void] {.async: (raises: [Exception]), base.} = + initializedGuard(g) - await g.registerBatch(@[rateCommitment]) + waku_rln_membership_insertion_duration_seconds.nanosecondTime: + let operationSuccess = + g.rlnInstance.atomicWrite(some(start), rateCommitments, toRemoveIndices) + if not operationSuccess: + raise newException(CatchableError, "atomic batch operation failed") + # TODO: when slashing is enabled, we need to track slashed members + waku_rln_number_registered_memberships.set(int64(g.rlnInstance.leavesSet())) -else: - method register*( - g: OnchainGroupManager, idCommitment: IDCommitment - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) + if g.registerCb.isSome(): + var membersSeq = newSeq[Membership]() + for i in 0 ..< rateCommitments.len: + var index = start + MembershipIndex(i) + debug "registering member to callback", rateCommitment = rateCommitments[i], index = index + let member = Membership(rateCommitment: rateCommitments[i], index: index) + membersSeq.add(member) + await g.registerCb.get()(membersSeq) - await g.registerBatch(@[idCommitment]) + g.validRootBuffer = g.slideRootQueue() -when defined(rln_v2): - method registerBatch*( - g: OnchainGroupManager, rateCommitments: seq[RateCommitment] - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) - - await g.atomicBatch(g.latestIndex, rateCommitments) - g.latestIndex += MembershipIndex(rateCommitments.len) +method register*( + g: OnchainGroupManager, rateCommitment: RateCommitment +): Future[void] {.async: (raises: [Exception]).} = + initializedGuard(g) -else: - method registerBatch*( - g: OnchainGroupManager, idCommitments: seq[IDCommitment] - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) + try: + let leaf = rateCommitment.toLeaf().get() + await g.registerBatch(@[leaf]) + except CatchableError: + raise newException(ValueError, getCurrentExceptionMsg()) - await g.atomicBatch(g.latestIndex, idCommitments) - g.latestIndex += MembershipIndex(idCommitments.len) -when defined(rln_v2): - method register*( - g: OnchainGroupManager, - identityCredential: IdentityCredential, - userMessageLimit: UserMessageLimit, - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) +method registerBatch*( + g: OnchainGroupManager, rateCommitments: seq[RawRateCommitment] +): Future[void] {.async: (raises: [Exception]).} = + initializedGuard(g) - let ethRpc = g.ethRpc.get() - let registryContract = g.registryContract.get() - let membershipFee = g.membershipFee.get() - - var gasPrice: int - g.retryWrapper(gasPrice, "Failed to get gas price"): - int(await ethRpc.provider.eth_gasPrice()) * 2 - let idCommitment = identityCredential.idCommitment.toUInt256() - - let storageIndex = g.usingStorageIndex.get() - debug "registering the member", - idCommitment = idCommitment, - storageIndex = storageIndex, - userMessageLimit = userMessageLimit - var txHash: TxHash - g.retryWrapper(txHash, "Failed to register the member"): - await registryContract - .register(storageIndex, idCommitment, u256(userMessageLimit)) - .send(gasPrice = gasPrice) - - # wait for the transaction to be mined - var tsReceipt: ReceiptObject - g.retryWrapper(tsReceipt, "Failed to get the transaction receipt"): - await ethRpc.getMinedTransactionReceipt(txHash) - debug "registration transaction mined", txHash = txHash - g.registrationTxHash = some(txHash) - # the receipt topic holds the hash of signature of the raised events - # TODO: make this robust. search within the event list for the event - let firstTopic = tsReceipt.logs[0].topics[0] - # the hash of the signature of MemberRegistered(uint256,uint256,uint256) event is equal to the following hex value - if firstTopic != - cast[FixedBytes[32]](keccak256.digest( - "MemberRegistered(uint256,uint256,uint256)" - ).data): - raise newException(ValueError, "unexpected event signature") - - # the arguments of the raised event i.e., MemberRegistered are encoded inside the data field - # data = pk encoded as 256 bits || index encoded as 256 bits || userMessageLimit encoded as 256 bits - let arguments = tsReceipt.logs[0].data - debug "tx log data", arguments = arguments - let - argumentsBytes = arguments - # In TX log data, uints are encoded in big endian - membershipIndex = UInt256.fromBytesBE(argumentsBytes[64 ..^ 1]) - - g.userMessageLimit = some(userMessageLimit) - g.membershipIndex = some(membershipIndex.toMembershipIndex()) - - # don't handle member insertion into the tree here, it will be handled by the event listener - return + await g.atomicBatch(g.latestIndex, rateCommitments) + g.latestIndex += MembershipIndex(rateCommitments.len) -else: - method register*( - g: OnchainGroupManager, credentials: IdentityCredential - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) +method register*( + g: OnchainGroupManager, + identityCredential: IdentityCredential, + userMessageLimit: UserMessageLimit, +): Future[void] {.async: (raises: [Exception]).} = + initializedGuard(g) - let ethRpc = g.ethRpc.get() - let registryContract = g.registryContract.get() - let membershipFee = g.membershipFee.get() - - var gasPrice: int - g.retryWrapper(gasPrice, "Failed to get gas price"): - int(await ethRpc.provider.eth_gasPrice()) * 2 - let idCommitment = credentials.idCommitment.toUInt256() - - let storageIndex = g.usingStorageIndex.get() - debug "registering the member", - idCommitment = idCommitment, storageIndex = storageIndex - var txHash: TxHash - g.retryWrapper(txHash, "Failed to register the member"): - await registryContract.register(storageIndex, idCommitment).send( - gasPrice = gasPrice - ) + let ethRpc = g.ethRpc.get() + let wakuRlnContract = g.wakuRlnContract.get() + + var gasPrice: int + g.retryWrapper(gasPrice, "Failed to get gas price"): + int(await ethRpc.provider.eth_gasPrice()) * 2 + let idCommitment = identityCredential.idCommitment.toUInt256() + + debug "registering the member", + idCommitment = idCommitment, + userMessageLimit = userMessageLimit + var txHash: TxHash + g.retryWrapper(txHash, "Failed to register the member"): + await wakuRlnContract + .register(idCommitment, userMessageLimit.stuint(32)) + .send(gasPrice = gasPrice) + + # wait for the transaction to be mined + var tsReceipt: ReceiptObject + g.retryWrapper(tsReceipt, "Failed to get the transaction receipt"): + await ethRpc.getMinedTransactionReceipt(txHash) + debug "registration transaction mined", txHash = txHash + g.registrationTxHash = some(txHash) + # the receipt topic holds the hash of signature of the raised events + # TODO: make this robust. search within the event list for the event + debug "ts receipt", tsReceipt + let firstTopic = tsReceipt.logs[0].topics[0] + # the hash of the signature of MemberRegistered(uint256,uint32) event is equal to the following hex value + if firstTopic != + cast[FixedBytes[32]](keccak256.digest( + "MemberRegistered(uint256,uint32)" + ).data): + raise newException(ValueError, "unexpected event signature") + + # the arguments of the raised event i.e., MemberRegistered are encoded inside the data field + # data = rateCommitment encoded as 256 bits || index encoded as 32 bits + let arguments = tsReceipt.logs[0].data + debug "tx log data", arguments = arguments + let + # In TX log data, uints are encoded in big endian + membershipIndex = UInt256.fromBytesBE(arguments[32 ..^ 1]) + + debug "parsed membershipIndex", membershipIndex + g.userMessageLimit = some(userMessageLimit) + g.membershipIndex = some(membershipIndex.toMembershipIndex()) + + # don't handle member insertion into the tree here, it will be handled by the event listener + return - # wait for the transaction to be mined - var tsReceipt: ReceiptObject - g.retryWrapper(tsReceipt, "Failed to get the transaction receipt"): - await ethRpc.getMinedTransactionReceipt(txHash) - debug "registration transaction mined", txHash = txHash - g.registrationTxHash = some(txHash) - # the receipt topic holds the hash of signature of the raised events - # TODO: make this robust. search within the event list for the event - let firstTopic = tsReceipt.logs[0].topics[0] - # the hash of the signature of MemberRegistered(uint256,uint256) event is equal to the following hex value - if firstTopic != - cast[FixedBytes[32]](keccak256.digest("MemberRegistered(uint256,uint256)").data): - raise newException(ValueError, "unexpected event signature") - - # the arguments of the raised event i.e., MemberRegistered are encoded inside the data field - # data = pk encoded as 256 bits || index encoded as 256 bits - let arguments = tsReceipt.logs[0].data - debug "tx log data", arguments = arguments - let - argumentsBytes = arguments - # In TX log data, uints are encoded in big endian - eventIndex = UInt256.fromBytesBE(argumentsBytes[32 ..^ 1]) - - g.membershipIndex = some(eventIndex.toMembershipIndex()) - - # don't handle member insertion into the tree here, it will be handled by the event listener - return method withdraw*( g: OnchainGroupManager, idCommitment: IDCommitment @@ -381,10 +238,8 @@ proc parseEvent( ): GroupManagerResult[Membership] = ## parses the `data` parameter of the `MemberRegistered` event `log` ## returns an error if it cannot parse the `data` parameter - var idComm: UInt256 + var rateCommitment: UInt256 var index: UInt256 - when defined(rln_v2): - var userMessageLimit: UInt256 var data: string # Remove the 0x prefix try: @@ -396,29 +251,17 @@ proc parseEvent( ) var offset = 0 try: - # Parse the idComm - offset += decode(data, offset, idComm) - when defined(rln_v2): - # Parse the userMessageLimit - offset += decode(data, offset, userMessageLimit) + # Parse the rateCommitment + offset += decode(data, offset, rateCommitment) # Parse the index offset += decode(data, offset, index) - when defined(rln_v2): - return ok( - Membership( - rateCommitment: RateCommitment( - idCommitment: idComm.toIDCommitment(), - userMessageLimit: userMessageLimit.toUserMessageLimit(), - ), - index: index.toMembershipIndex(), - ) - ) - else: - return ok( - Membership( - idCommitment: idComm.toIDCommitment(), index: index.toMembershipIndex() - ) + return ok( + Membership( + rateCommitment: rateCommitment.toRateCommitment(), + index: index.toMembershipIndex(), ) + ) + except CatchableError: return err("failed to parse the data field of the MemberRegistered event") @@ -456,11 +299,11 @@ proc getRawEvents( initializedGuard(g) let ethRpc = g.ethRpc.get() - let rlnContract = g.rlnContract.get() + let wakuRlnContract = g.wakuRlnContract.get() var events: JsonNode g.retryWrapper(events, "Failed to get the events"): - await rlnContract.getJsonLogs( + await wakuRlnContract.getJsonLogs( MemberRegistered, fromBlock = some(fromBlock.blockId()), toBlock = some(toBlock.blockId()), @@ -501,24 +344,15 @@ proc handleEvents( try: let startIndex = blockTable[blockNumber].filterIt(not it[1])[0][0].index let removalIndices = members.filterIt(it[1]).mapIt(it[0].index) - when defined(rln_v2): - let rateCommitments = members.mapIt(it[0].rateCommitment) - await g.atomicBatch( - start = startIndex, - rateCommitments = rateCommitments, - toRemoveIndices = removalIndices, - ) - g.latestIndex = startIndex + MembershipIndex(rateCommitments.len) - trace "new members added to the Merkle tree", commitments = rateCommitments - else: - let idCommitments = members.mapIt(it[0].idCommitment) - await g.atomicBatch( - start = startIndex, - idCommitments = idCommitments, - toRemoveIndices = removalIndices, - ) - g.latestIndex = startIndex + MembershipIndex(idCommitments.len) - trace "new members added to the Merkle tree", commitments = idCommitments + let rateCommitments = members.mapIt(it[0].rateCommitment) + await g.atomicBatch( + start = startIndex, + rateCommitments = rateCommitments, + toRemoveIndices = removalIndices, + ) + g.latestIndex = startIndex + MembershipIndex(rateCommitments.len) + trace "new members added to the Merkle tree", commitments = rateCommitments.mapIt(it.inHex) + except CatchableError: error "failed to insert members into the tree", error = getCurrentExceptionMsg() raise newException(ValueError, "failed to insert members into the tree") @@ -720,23 +554,11 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} ethRpc.defaultAccount = ethRpc.privateKey.get().toPublicKey().toCanonicalAddress().Address - let registryAddress = web3.fromHex(web3.Address, g.ethContractAddress) - let registryContract = ethRpc.contractSender(WakuRlnRegistry, registryAddress) - - # get the current storage index - var usingStorageIndex: Uint16 - g.retryWrapper(usingStorageIndex, "Failed to get the storage index"): - await registryContract.usingStorageIndex().call() - - g.usingStorageIndex = some(usingStorageIndex) - var rlnContractAddress: Address - g.retryWrapper(rlnContractAddress, "Failed to get the rln contract address"): - await registryContract.storages(usingStorageIndex).call() - let rlnContract = ethRpc.contractSender(RlnStorage, rlnContractAddress) - + let contractAddress = web3.fromHex(web3.Address, g.ethContractAddress) + let wakuRlnContract = ethRpc.contractSender(WakuRlnContract, contractAddress) + g.ethRpc = some(ethRpc) - g.rlnContract = some(rlnContract) - g.registryContract = some(registryContract) + g.wakuRlnContract = some(wakuRlnContract) if g.keystorePath.isSome() and g.keystorePassword.isSome(): if not fileExists(g.keystorePath.get()): @@ -759,11 +581,10 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} return err("failed to get the keystore credentials: " & $error) g.membershipIndex = some(keystoreCred.treeIndex) - when defined(rln_v2): - g.userMessageLimit = some(keystoreCred.userMessageLimit) + g.userMessageLimit = some(keystoreCred.userMessageLimit) # now we check on the contract if the commitment actually has a membership try: - let membershipExists = await rlnContract + let membershipExists = await wakuRlnContract .memberExists(keystoreCred.identityCredential.idCommitment.toUInt256()) .call() if membershipExists == 0: @@ -786,16 +607,10 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} g.latestProcessedBlock = metadata.lastProcessedBlock g.validRoots = metadata.validRoots.toDeque() - # check if the contract exists by calling a static function - var membershipFee: Uint256 - g.retryWrapper(membershipFee, "Failed to get the membership deposit"): - await rlnContract.MEMBERSHIP_DEPOSIT().call() - g.membershipFee = some(membershipFee) - var deployedBlockNumber: Uint256 g.retryWrapper(deployedBlockNumber, "Failed to get the deployed block number"): - await rlnContract.deployedBlockNumber().call() - debug "using rln storage", deployedBlockNumber, rlnContractAddress + await wakuRlnContract.deployedBlockNumber().call() + debug "using rln contract", deployedBlockNumber, rlnContractAddress = contractAddress g.rlnContractDeployedBlockNumber = cast[BlockNumber](deployedBlockNumber) g.latestProcessedBlock = max(g.latestProcessedBlock, g.rlnContractDeployedBlockNumber) diff --git a/waku/waku_rln_relay/group_manager/static/group_manager.nim b/waku/waku_rln_relay/group_manager/static/group_manager.nim index 084aba1af7..e8590325c9 100644 --- a/waku/waku_rln_relay/group_manager/static/group_manager.nim +++ b/waku/waku_rln_relay/group_manager/static/group_manager.nim @@ -33,25 +33,18 @@ method init*(g: StaticGroupManager): Future[GroupManagerResult[void]] {.async.} "Invalid membership index. Must be within 0 and " & $(groupSize - 1) & "but was " & $membershipIndex ) - when defined(rln_v2): - g.userMessageLimit = some(DefaultUserMessageLimit) + g.userMessageLimit = some(DefaultUserMessageLimit) g.idCredentials = some(groupKeys[membershipIndex]) # Seed the received commitments into the merkle tree - when defined(rln_v2): - let rateCommitments = groupKeys.mapIt( - RateCommitment( - idCommitment: it.idCommitment, userMessageLimit: g.userMessageLimit.get() - ) + let rateCommitments = groupKeys.mapIt( + RateCommitment( + idCommitment: it.idCommitment, userMessageLimit: g.userMessageLimit.get() ) - let leaves = rateCommitments.toLeaves().valueOr: - return err("Failed to convert rate commitments to leaves: " & $error) - let membersInserted = g.rlnInstance.insertMembers(g.latestIndex, leaves) - else: - let idCommitments = groupKeys.mapIt(it.idCommitment) - let membersInserted = g.rlnInstance.insertMembers(g.latestIndex, idCommitments) - if not membersInserted: - return err("Failed to insert members into the merkle tree") + ) + let leaves = rateCommitments.toLeaves().valueOr: + return err("Failed to convert rate commitments to leaves: " & $error) + let membersInserted = g.rlnInstance.insertMembers(g.latestIndex, leaves) discard g.slideRootQueue() @@ -68,127 +61,65 @@ method startGroupSync*( # No-op return ok() -when defined(rln_v2): - method register*( - g: StaticGroupManager, rateCommitment: RateCommitment - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) - - await g.registerBatch(@[rateCommitment]) - -else: - method register*( - g: StaticGroupManager, idCommitment: IDCommitment - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) - - await g.registerBatch(@[idCommitment]) - -when defined(rln_v2): - method registerBatch*( - g: StaticGroupManager, rateCommitments: seq[RateCommitment] - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) - - let leavesRes = rateCommitments.toLeaves() - if not leavesRes.isOk(): - raise newException(ValueError, "Failed to convert rate commitments to leaves") - let leaves = cast[seq[seq[byte]]](leavesRes.get()) - - let membersInserted = g.rlnInstance.insertMembers(g.latestIndex + 1, leaves) - if not membersInserted: - raise newException(ValueError, "Failed to insert members into the merkle tree") - - if g.registerCb.isSome(): - var memberSeq = newSeq[Membership]() - for i in 0 ..< rateCommitments.len: - memberSeq.add( - Membership( - rateCommitment: rateCommitments[i], - index: g.latestIndex + MembershipIndex(i) + 1, - ) - ) - await g.registerCb.get()(memberSeq) - - discard g.slideRootQueue() - - g.latestIndex += MembershipIndex(rateCommitments.len) - - return - -else: - method registerBatch*( - g: StaticGroupManager, idCommitments: seq[IDCommitment] - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) - - let membersInserted = g.rlnInstance.insertMembers(g.latestIndex + 1, idCommitments) - if not membersInserted: - raise newException(ValueError, "Failed to insert members into the merkle tree") - - if g.registerCb.isSome(): - var memberSeq = newSeq[Membership]() - for i in 0 ..< idCommitments.len: - memberSeq.add( - Membership( - idCommitment: idCommitments[i], - index: g.latestIndex + MembershipIndex(i) + 1, - ) - ) - await g.registerCb.get()(memberSeq) - - discard g.slideRootQueue() +method register*( + g: StaticGroupManager, rateCommitment: RateCommitment +): Future[void] {.async: (raises: [Exception]).} = + initializedGuard(g) - g.latestIndex += MembershipIndex(idCommitments.len) + let leaf = rateCommitment.toLeaf().get() - return + await g.registerBatch(@[leaf]) -when defined(rln_v2): - method withdraw*( - g: StaticGroupManager, idSecretHash: IdentitySecretHash - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) - let groupKeys = g.groupKeys +method registerBatch*( + g: StaticGroupManager, rateCommitments: seq[RawRateCommitment] +): Future[void] {.async: (raises: [Exception]).} = + initializedGuard(g) - for i in 0 ..< groupKeys.len: - if groupKeys[i].idSecretHash == idSecretHash: - let idCommitment = groupKeys[i].idCommitment - let index = MembershipIndex(i) - let rateCommitment = RateCommitment( - idCommitment: idCommitment, userMessageLimit: g.userMessageLimit.get() + let membersInserted = g.rlnInstance.insertMembers(g.latestIndex + 1, rateCommitments) + if not membersInserted: + raise newException(ValueError, "Failed to insert members into the merkle tree") + + if g.registerCb.isSome(): + var memberSeq = newSeq[Membership]() + for i in 0 ..< rateCommitments.len: + memberSeq.add( + Membership( + rateCommitment: rateCommitments[i], + index: g.latestIndex + MembershipIndex(i) + 1, ) - let memberRemoved = g.rlnInstance.removeMember(index) - if not memberRemoved: - raise newException(ValueError, "Failed to remove member from the merkle tree") - - if g.withdrawCb.isSome(): - let withdrawCb = g.withdrawCb.get() - await withdrawCb(@[Membership(rateCommitment: rateCommitment, index: index)]) - - return - -else: - method withdraw*( - g: StaticGroupManager, idSecretHash: IdentitySecretHash - ): Future[void] {.async: (raises: [Exception]).} = - initializedGuard(g) + ) + await g.registerCb.get()(memberSeq) - let groupKeys = g.groupKeys + discard g.slideRootQueue() - for i in 0 ..< groupKeys.len: - if groupKeys[i].idSecretHash == idSecretHash: - let idCommitment = groupKeys[i].idCommitment - let index = MembershipIndex(i) - let memberRemoved = g.rlnInstance.removeMember(index) - if not memberRemoved: - raise newException(ValueError, "Failed to remove member from the merkle tree") + g.latestIndex += MembershipIndex(rateCommitments.len) + return - if g.withdrawCb.isSome(): - let withdrawCb = g.withdrawCb.get() - await withdrawCb((@[Membership(idCommitment: idCommitment, index: index)])) +method withdraw*( + g: StaticGroupManager, idSecretHash: IdentitySecretHash +): Future[void] {.async: (raises: [Exception]).} = + initializedGuard(g) - return + let groupKeys = g.groupKeys + + for i in 0 ..< groupKeys.len: + if groupKeys[i].idSecretHash == idSecretHash: + let idCommitment = groupKeys[i].idCommitment + let index = MembershipIndex(i) + let rateCommitment = RateCommitment( + idCommitment: idCommitment, userMessageLimit: g.userMessageLimit.get() + ).toLeaf().valueOr: + raise newException(ValueError, "Failed to parse rateCommitment") + let memberRemoved = g.rlnInstance.removeMember(index) + if not memberRemoved: + raise newException(ValueError, "Failed to remove member from the merkle tree") + + if g.withdrawCb.isSome(): + let withdrawCb = g.withdrawCb.get() + await withdrawCb(@[Membership(rateCommitment: rateCommitment, index: index)]) + + return method withdrawBatch*( g: StaticGroupManager, idSecretHashes: seq[IdentitySecretHash] diff --git a/waku/waku_rln_relay/nonce_manager.nim b/waku/waku_rln_relay/nonce_manager.nim index bb17b696d8..6fe463ce1c 100644 --- a/waku/waku_rln_relay/nonce_manager.nim +++ b/waku/waku_rln_relay/nonce_manager.nim @@ -45,12 +45,13 @@ proc getNonce*(n: NonceManager): NonceManagerResult[Nonce] = if now - n.lastNonceTime >= n.epoch: retNonce = 0 + n.lastNonceTime = now + n.nextNonce = retNonce + 1 - n.lastNonceTime = now if retNonce >= n.nonceLimit: return err( - NonceManagerError( + NonceManagerError( kind: NonceLimitReached, error: "Nonce limit reached. Please wait for the next epoch. requested nonce: " & diff --git a/waku/waku_rln_relay/protocol_types.nim b/waku/waku_rln_relay/protocol_types.nim index 158f550b9a..7fa392247f 100644 --- a/waku/waku_rln_relay/protocol_types.nim +++ b/waku/waku_rln_relay/protocol_types.nim @@ -3,7 +3,7 @@ when (NimMajor, NimMinor) < (1, 4): else: {.push raises: [].} -import std/[options, tables, deques], stew/arrayops, chronos, web3, eth/keys +import std/[options, tables, deques], stew/arrayops, stint, chronos, web3, eth/keys import ../waku_core, ../waku_keystore, ../common/protobuf export waku_keystore, waku_core @@ -16,20 +16,20 @@ type RLNResult* = RlnRelayResult[ptr RLN] type MerkleNode* = array[32, byte] - # Each node of the Merkle tee is a Poseidon hash which is a 32 byte value + # Each node of the Merkle tree is a Poseidon hash which is a 32 byte value Nullifier* = array[32, byte] Epoch* = array[32, byte] RlnIdentifier* = array[32, byte] ZKSNARK* = array[128, byte] - -when defined(rln_v2): - type - MessageId* = uint64 - ExternalNullifier* = array[32, byte] - - type RateCommitment* = object + MessageId* = uint64 + ExternalNullifier* = array[32, byte] + RateCommitment* = object idCommitment*: IDCommitment userMessageLimit*: UserMessageLimit + RawRateCommitment* = seq[byte] + +proc toRateCommitment*(rateCommitmentUint: UInt256): RawRateCommitment = + return RawRateCommitment(@(rateCommitmentUint.toBytesLE())) # Custom data types defined for waku rln relay ------------------------- type RateLimitProof* = object @@ -51,9 +51,8 @@ type RateLimitProof* = object epoch*: Epoch ## Application specific RLN Identifier rlnIdentifier*: RlnIdentifier - when defined(rln_v2): - ## the external nullifier used for the generation of the `proof` (derived from poseidon([epoch, rln_identifier])) - externalNullifier*: ExternalNullifier + ## the external nullifier used for the generation of the `proof` (derived from poseidon([epoch, rln_identifier])) + externalNullifier*: ExternalNullifier type ProofMetadata* = object nullifier*: Nullifier diff --git a/waku/waku_rln_relay/rln/wrappers.nim b/waku/waku_rln_relay/rln/wrappers.nim index 1f26e2eec4..f6056c5bc8 100644 --- a/waku/waku_rln_relay/rln/wrappers.nim +++ b/waku/waku_rln_relay/rln/wrappers.nim @@ -161,32 +161,31 @@ proc poseidon*(data: seq[seq[byte]]): RlnRelayResult[array[32, byte]] = return ok(output) -when defined(rln_v2): - proc toLeaf*(rateCommitment: RateCommitment): RlnRelayResult[seq[byte]] = - let idCommitment = rateCommitment.idCommitment - 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) - for i in 0 ..< leaf.len: - retLeaf[i] = leaf[i] - return ok(retLeaf) - - proc toLeaves*(rateCommitments: seq[RateCommitment]): RlnRelayResult[seq[seq[byte]]] = - var leaves = newSeq[seq[byte]]() - for rateCommitment in rateCommitments: - let leaf = toLeaf(rateCommitment).valueOr: - return err("could not convert the rate commitment to a leaf: " & $error) - leaves.add(leaf) - return ok(leaves) +proc toLeaf*(rateCommitment: RateCommitment): RlnRelayResult[seq[byte]] = + let idCommitment = rateCommitment.idCommitment + 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) + for i in 0 ..< leaf.len: + retLeaf[i] = leaf[i] + return ok(retLeaf) + +proc toLeaves*(rateCommitments: seq[RateCommitment]): RlnRelayResult[seq[seq[byte]]] = + var leaves = newSeq[seq[byte]]() + for rateCommitment in rateCommitments: + let leaf = toLeaf(rateCommitment).valueOr: + return err("could not convert the rate commitment to a leaf: " & $error) + leaves.add(leaf) + return ok(leaves) proc extractMetadata*(proof: RateLimitProof): RlnRelayResult[ProofMetadata] = let externalNullifier = poseidon(@[@(proof.epoch), @(proof.rlnIdentifier)]).valueOr: @@ -200,151 +199,81 @@ proc extractMetadata*(proof: RateLimitProof): RlnRelayResult[ProofMetadata] = ) ) -when defined(rln_v2): - proc proofGen*( - rlnInstance: ptr RLN, - data: openArray[byte], - membership: IdentityCredential, - userMessageLimit: UserMessageLimit, - messageId: MessageId, - index: MembershipIndex, - epoch: Epoch, - rlnIdentifier = DefaultRlnIdentifier, - ): RateLimitProofResult = - # obtain the external nullifier - let externalNullifierRes = poseidon(@[@(epoch), @(rlnIdentifier)]) - - if externalNullifierRes.isErr(): - return err("could not construct the external nullifier") - - # serialize inputs - let serializedInputs = serialize( - idSecretHash = membership.idSecretHash, - memIndex = index, - userMessageLimit = userMessageLimit, - messageId = messageId, - externalNullifier = externalNullifierRes.get(), - msg = data, - ) - var inputBuffer = toBuffer(serializedInputs) - - debug "input buffer ", inputBuffer = repr(inputBuffer) - - # generate the proof - var proof: Buffer - let proofIsSuccessful = generate_proof(rlnInstance, addr inputBuffer, addr proof) - # check whether the generate_proof call is done successfully - if not proofIsSuccessful: - return err("could not generate the proof") - - var proofValue = cast[ptr array[320, byte]](proof.`ptr`) - let proofBytes: array[320, byte] = proofValue[] - debug "proof content", proofHex = proofValue[].toHex - - ## parse the proof as [ proof<128> | root<32> | external_nullifier<32> | share_x<32> | share_y<32> | nullifier<32> ] - - let - proofOffset = 128 - rootOffset = proofOffset + 32 - externalNullifierOffset = rootOffset + 32 - shareXOffset = externalNullifierOffset + 32 - shareYOffset = shareXOffset + 32 - nullifierOffset = shareYOffset + 32 - - var - zkproof: ZKSNARK - proofRoot, shareX, shareY: MerkleNode - externalNullifier: ExternalNullifier - nullifier: Nullifier - - discard zkproof.copyFrom(proofBytes[0 .. proofOffset - 1]) - discard proofRoot.copyFrom(proofBytes[proofOffset .. rootOffset - 1]) - discard - externalNullifier.copyFrom(proofBytes[rootOffset .. externalNullifierOffset - 1]) - discard shareX.copyFrom(proofBytes[externalNullifierOffset .. shareXOffset - 1]) - discard shareY.copyFrom(proofBytes[shareXOffset .. shareYOffset - 1]) - discard nullifier.copyFrom(proofBytes[shareYOffset .. nullifierOffset - 1]) - - let output = RateLimitProof( - proof: zkproof, - merkleRoot: proofRoot, - externalNullifier: externalNullifier, - epoch: epoch, - rlnIdentifier: rlnIdentifier, - shareX: shareX, - shareY: shareY, - nullifier: nullifier, - ) - return ok(output) - -else: - proc proofGen*( - rlnInstance: ptr RLN, - data: openArray[byte], - memKeys: IdentityCredential, - memIndex: MembershipIndex, - epoch: Epoch, - ): RateLimitProofResult = - # serialize inputs - let serializedInputs = serialize( - idSecretHash = memKeys.idSecretHash, - memIndex = memIndex, - epoch = epoch, - msg = data, - ) - var inputBuffer = toBuffer(serializedInputs) - - debug "input buffer ", inputBuffer = repr(inputBuffer) - - # generate the proof - var proof: Buffer - let proofIsSuccessful = generate_proof(rlnInstance, addr inputBuffer, addr proof) - # check whether the generate_proof call is done successfully - if not proofIsSuccessful: - return err("could not generate the proof") - - var proofValue = cast[ptr array[320, byte]](proof.`ptr`) - let proofBytes: array[320, byte] = proofValue[] - debug "proof content", proofHex = proofValue[].toHex - - ## parse the proof as [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> ] - - let - proofOffset = 128 - rootOffset = proofOffset + 32 - epochOffset = rootOffset + 32 - shareXOffset = epochOffset + 32 - shareYOffset = shareXOffset + 32 - nullifierOffset = shareYOffset + 32 - rlnIdentifierOffset = nullifierOffset + 32 - - var - zkproof: ZKSNARK - proofRoot, shareX, shareY: MerkleNode - epoch: Epoch - nullifier: Nullifier - rlnIdentifier: RlnIdentifier - - discard zkproof.copyFrom(proofBytes[0 .. proofOffset - 1]) - discard proofRoot.copyFrom(proofBytes[proofOffset .. rootOffset - 1]) - discard epoch.copyFrom(proofBytes[rootOffset .. epochOffset - 1]) - discard shareX.copyFrom(proofBytes[epochOffset .. shareXOffset - 1]) - discard shareY.copyFrom(proofBytes[shareXOffset .. shareYOffset - 1]) - discard nullifier.copyFrom(proofBytes[shareYOffset .. nullifierOffset - 1]) - discard - rlnIdentifier.copyFrom(proofBytes[nullifierOffset .. rlnIdentifierOffset - 1]) - - let output = RateLimitProof( - proof: zkproof, - merkleRoot: proofRoot, - epoch: epoch, - shareX: shareX, - shareY: shareY, - nullifier: nullifier, - rlnIdentifier: rlnIdentifier, - ) +proc proofGen*( + rlnInstance: ptr RLN, + data: openArray[byte], + membership: IdentityCredential, + userMessageLimit: UserMessageLimit, + messageId: MessageId, + index: MembershipIndex, + epoch: Epoch, + rlnIdentifier = DefaultRlnIdentifier, +): RateLimitProofResult = + # obtain the external nullifier + let externalNullifierRes = poseidon(@[@(epoch), @(rlnIdentifier)]) + + if externalNullifierRes.isErr(): + return err("could not construct the external nullifier") - return ok(output) + # serialize inputs + let serializedInputs = serialize( + idSecretHash = membership.idSecretHash, + memIndex = index, + userMessageLimit = userMessageLimit, + messageId = messageId, + externalNullifier = externalNullifierRes.get(), + msg = data, + ) + var inputBuffer = toBuffer(serializedInputs) + + debug "input buffer ", inputBuffer = repr(inputBuffer) + + # generate the proof + var proof: Buffer + let proofIsSuccessful = generate_proof(rlnInstance, addr inputBuffer, addr proof) + # check whether the generate_proof call is done successfully + if not proofIsSuccessful: + return err("could not generate the proof") + + var proofValue = cast[ptr array[320, byte]](proof.`ptr`) + let proofBytes: array[320, byte] = proofValue[] + debug "proof content", proofHex = proofValue[].toHex + + ## parse the proof as [ proof<128> | root<32> | external_nullifier<32> | share_x<32> | share_y<32> | nullifier<32> ] + + let + proofOffset = 128 + rootOffset = proofOffset + 32 + externalNullifierOffset = rootOffset + 32 + shareXOffset = externalNullifierOffset + 32 + shareYOffset = shareXOffset + 32 + nullifierOffset = shareYOffset + 32 + + var + zkproof: ZKSNARK + proofRoot, shareX, shareY: MerkleNode + externalNullifier: ExternalNullifier + nullifier: Nullifier + + discard zkproof.copyFrom(proofBytes[0 .. proofOffset - 1]) + discard proofRoot.copyFrom(proofBytes[proofOffset .. rootOffset - 1]) + discard + externalNullifier.copyFrom(proofBytes[rootOffset .. externalNullifierOffset - 1]) + discard shareX.copyFrom(proofBytes[externalNullifierOffset .. shareXOffset - 1]) + discard shareY.copyFrom(proofBytes[shareXOffset .. shareYOffset - 1]) + discard nullifier.copyFrom(proofBytes[shareYOffset .. nullifierOffset - 1]) + + let output = RateLimitProof( + proof: zkproof, + merkleRoot: proofRoot, + externalNullifier: externalNullifier, + epoch: epoch, + rlnIdentifier: rlnIdentifier, + shareX: shareX, + shareY: shareY, + nullifier: nullifier, + ) + return ok(output) # 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 @@ -357,14 +286,13 @@ proc proofVerify*( ## 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") + # 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(normalizedProof, data) proofBuffer = proofBytes.toBuffer() diff --git a/waku/waku_rln_relay/rln_relay.nim b/waku/waku_rln_relay/rln_relay.nim index c255505cd3..139c7aaf99 100644 --- a/waku/waku_rln_relay/rln_relay.nim +++ b/waku/waku_rln_relay/rln_relay.nim @@ -23,10 +23,8 @@ import ./conversion_utils, ./constants, ./protocol_types, - ./protocol_metrics - -when defined(rln_v2): - import ./nonce_manager + ./protocol_metrics, + ./nonce_manager import ../common/error_handling, @@ -47,8 +45,7 @@ type WakuRlnConfig* = object rlnRelayTreePath*: string rlnEpochSizeSec*: uint64 onFatalErrorAction*: OnFatalErrorHandler - when defined(rln_v2): - rlnRelayUserMessageLimit*: uint64 + rlnRelayUserMessageLimit*: uint64 proc createMembershipList*( rln: ptr RLN, n: int @@ -93,8 +90,7 @@ type WakuRLNRelay* = ref object of RootObj rlnMaxEpochGap*: uint64 groupManager*: GroupManager onFatalErrorAction*: OnFatalErrorHandler - when defined(rln_v2): - nonceManager*: NonceManager + nonceManager*: NonceManager proc calcEpoch*(rlnPeer: WakuRLNRelay, t: float64): Epoch = ## gets time `t` as `flaot64` with subseconds resolution in the fractional part @@ -307,14 +303,11 @@ proc appendRLNProof*( let input = msg.toRLNSignal() let epoch = rlnPeer.calcEpoch(senderEpochTime) - when defined(rln_v2): - let nonce = rlnPeer.nonceManager.getNonce().valueOr: - return err("could not get new message id to generate an rln proof: " & $error) - let proof = rlnPeer.groupManager.generateProof(input, epoch, nonce).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) + let nonce = rlnPeer.nonceManager.getNonce().valueOr: + return err("could not get new message id to generate an rln proof: " & $error) + let proof = rlnPeer.groupManager.generateProof(input, epoch, nonce).valueOr: + return err("could not generate rln-v2 proof: " & $error) + msg.proof = proof.encode().buffer return ok() @@ -445,28 +438,18 @@ proc mount( (await groupManager.startGroupSync()).isOkOr: return err("could not start the group sync: " & $error) - when defined(rln_v2): - return ok( - WakuRLNRelay( - groupManager: groupManager, - nonceManager: - NonceManager.init(conf.rlnRelayUserMessageLimit, conf.rlnEpochSizeSec.float), - rlnEpochSizeSec: conf.rlnEpochSizeSec, - rlnMaxEpochGap: - max(uint64(MaxClockGapSeconds / float64(conf.rlnEpochSizeSec)), 1), - onFatalErrorAction: conf.onFatalErrorAction, - ) - ) - else: - return ok( - WakuRLNRelay( - groupManager: groupManager, - rlnEpochSizeSec: conf.rlnEpochSizeSec, - rlnMaxEpochGap: - max(uint64(MaxClockGapSeconds / float64(conf.rlnEpochSizeSec)), 1), - onFatalErrorAction: conf.onFatalErrorAction, - ) + return ok( + WakuRLNRelay( + groupManager: groupManager, + nonceManager: + NonceManager.init(conf.rlnRelayUserMessageLimit, conf.rlnEpochSizeSec.float), + rlnEpochSizeSec: conf.rlnEpochSizeSec, + rlnMaxEpochGap: + max(uint64(MaxClockGapSeconds / float64(conf.rlnEpochSizeSec)), 1), + onFatalErrorAction: conf.onFatalErrorAction, ) + ) + proc isReady*(rlnPeer: WakuRLNRelay): Future[bool] {.async: (raises: [Exception]).} = ## returns true if the rln-relay protocol is ready to relay messages From bd064882f6842939623f7c341cb8f3aabe530696 Mon Sep 17 00:00:00 2001 From: Aaryamann Challani <43716372+rymnc@users.noreply.github.com> Date: Thu, 20 Jun 2024 18:16:16 +0530 Subject: [PATCH 02/11] chore(zerokit): bump submodule (#2830) --- vendor/zerokit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/zerokit b/vendor/zerokit index 85d71a5427..e6238fd722 160000 --- a/vendor/zerokit +++ b/vendor/zerokit @@ -1 +1 @@ -Subproject commit 85d71a5427ee78528d6420c04b67c7825e3c6e91 +Subproject commit e6238fd7228dd645eb7d6f3bf2077a8623c38fcf From 2f79d694955456868ad54b3aec662a67bbd440ff Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande Date: Thu, 20 Jun 2024 15:07:03 +0200 Subject: [PATCH 03/11] CHANGELOG.md add info for v0.30.0 --- CHANGELOG.md | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cea6a11bb1..604fcc0201 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,23 @@ -## v0.29.0 (2024-06-11) +## v0.30.0 (2024-06-20) + +### Features + +- rlnv2: clean fork of rlnv2 ([#2828](https://github.com/waku-org/nwaku/issues/2828)) ([a02832fe](https://github.com/waku-org/nwaku/commit/a02832fe)) + +### Changes + +- zerokit: bump submodule ([#2830](https://github.com/waku-org/nwaku/issues/2830)) ([bd064882](https://github.com/waku-org/nwaku/commit/bd064882)) + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | + +## v0.29.0 (2024-06-19) ## What's Changed From c56785327ae457aa0aaf2a3822d22f7090e2fce3 Mon Sep 17 00:00:00 2001 From: Aaryamann Challani <43716372+rymnc@users.noreply.github.com> Date: Mon, 24 Jun 2024 16:59:56 +0530 Subject: [PATCH 04/11] fix(rln-relay): clear nullifier log only if length is over max epoch gap (#2836) --- tests/waku_rln_relay/test_waku_rln_relay.nim | 37 ++++++++++++++++++++ waku/waku_rln_relay/rln_relay.nim | 9 ++--- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/tests/waku_rln_relay/test_waku_rln_relay.nim b/tests/waku_rln_relay/test_waku_rln_relay.nim index c8f655ad7d..611f3d80f8 100644 --- a/tests/waku_rln_relay/test_waku_rln_relay.nim +++ b/tests/waku_rln_relay/test_waku_rln_relay.nim @@ -886,3 +886,40 @@ suite "Waku rln relay": check: buckets.len == 5 buckets == [2.0, 4.0, 6.0, 8.0, 10.0] + + asyncTest "nullifierLog clearing only after epoch has passed": + let index = MembershipIndex(0) + + proc runTestForEpochSizeSec(rlnEpochSizeSec: uint) {.async.} = + let wakuRlnConfig = WakuRlnConfig( + rlnRelayDynamic: false, + rlnRelayCredIndex: some(index), + rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: rlnEpochSizeSec, + rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_4"), + ) + + let wakuRlnRelay = (await WakuRlnRelay.new(wakuRlnConfig)).valueOr: + raiseAssert $error + + let rlnMaxEpochGap = wakuRlnRelay.rlnMaxEpochGap + let testProofMetadata = default(ProofMetadata) + let testProofMetadataTable = {testProofMetadata.nullifier: testProofMetadata}.toTable() + + for i in 0..rlnMaxEpochGap: + # we add epochs to the nullifierLog + let testEpoch = wakuRlnRelay.calcEpoch(epochTime() + float(rlnEpochSizeSec * i)) + wakuRlnRelay.nullifierLog[testEpoch] = testProofMetadataTable + check: wakuRlnRelay.nullifierLog.len().uint == i + 1 + + check: wakuRlnRelay.nullifierLog.len().uint == rlnMaxEpochGap + 1 + + # clearing it now will remove 1 epoch + wakuRlnRelay.clearNullifierLog() + + check: wakuRlnRelay.nullifierLog.len().uint == rlnMaxEpochGap + + var testEpochSizes: seq[uint] = @[1,5,10,30,60] + for i in testEpochSizes: + await runTestForEpochSizeSec(i) + diff --git a/waku/waku_rln_relay/rln_relay.nim b/waku/waku_rln_relay/rln_relay.nim index 139c7aaf99..ab4ba10a6a 100644 --- a/waku/waku_rln_relay/rln_relay.nim +++ b/waku/waku_rln_relay/rln_relay.nim @@ -312,15 +312,16 @@ proc appendRLNProof*( msg.proof = proof.encode().buffer return ok() -proc clearNullifierLog(rlnPeer: WakuRlnRelay) = +proc clearNullifierLog*(rlnPeer: WakuRlnRelay) = # clear the first MaxEpochGap epochs of the nullifer log # if more than MaxEpochGap epochs are in the log # note: the epochs are ordered ascendingly - if rlnPeer.nullifierLog.len().uint < rlnPeer.rlnMaxEpochGap: + if rlnPeer.nullifierLog.len().uint <= rlnPeer.rlnMaxEpochGap: return - trace "clearing epochs from the nullifier log", count = rlnPeer.rlnMaxEpochGap - let epochsToClear = rlnPeer.nullifierLog.keys().toSeq()[0 ..< rlnPeer.rlnMaxEpochGap] + let countToClear = rlnPeer.nullifierLog.len().uint - rlnPeer.rlnMaxEpochGap + trace "clearing epochs from the nullifier log", count = countToClear + let epochsToClear = rlnPeer.nullifierLog.keys().toSeq()[0 ..< countToClear] for epoch in epochsToClear: rlnPeer.nullifierLog.del(epoch) From 7b97c8003c3ea858dfbbcda0f831452f1502f3f9 Mon Sep 17 00:00:00 2001 From: Alvaro Revuelta Date: Thu, 27 Jun 2024 11:45:21 +0200 Subject: [PATCH 05/11] chore: add TWN parameters for RLNv2 (#2843) --- tests/waku_rln_relay/test_waku_rln_relay.nim | 2 +- waku/factory/networks_config.nim | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/waku_rln_relay/test_waku_rln_relay.nim b/tests/waku_rln_relay/test_waku_rln_relay.nim index 611f3d80f8..454ec10a51 100644 --- a/tests/waku_rln_relay/test_waku_rln_relay.nim +++ b/tests/waku_rln_relay/test_waku_rln_relay.nim @@ -919,7 +919,7 @@ suite "Waku rln relay": check: wakuRlnRelay.nullifierLog.len().uint == rlnMaxEpochGap - var testEpochSizes: seq[uint] = @[1,5,10,30,60] + var testEpochSizes: seq[uint] = @[1,5,10,30,60,600] for i in testEpochSizes: await runTestForEpochSizeSec(i) diff --git a/waku/factory/networks_config.nim b/waku/factory/networks_config.nim index 9837cdaeb9..92a4956f5d 100644 --- a/waku/factory/networks_config.nim +++ b/waku/factory/networks_config.nim @@ -35,12 +35,11 @@ proc TheWakuNetworkConf*(T: type ClusterConf): ClusterConf = maxMessageSize: "150KiB", clusterId: 1, rlnRelay: true, - rlnRelayEthContractAddress: "0xF471d71E9b1455bBF4b85d475afb9BB0954A29c4", + rlnRelayEthContractAddress: "0x4976Df0f61135EF3E5720D92eadE2e5F47A68Ef9", rlnRelayDynamic: true, rlnRelayBandwidthThreshold: 0, - rlnEpochSizeSec: 1, - # parameter to be defined with rln_v2 - rlnRelayUserMessageLimit: 1, + rlnEpochSizeSec: 600, + rlnRelayUserMessageLimit: 20, pubsubTopics: @[ "/waku/2/rs/1/0", "/waku/2/rs/1/1", "/waku/2/rs/1/2", "/waku/2/rs/1/3", From dad054d6b357b1925271f17b7badcd1df91dc105 Mon Sep 17 00:00:00 2001 From: Alvaro Revuelta Date: Fri, 28 Jun 2024 09:25:10 +0200 Subject: [PATCH 06/11] fix(rln): nullifierlog vulnerability (#2855) --- waku/waku_rln_relay/rln_relay.nim | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/waku/waku_rln_relay/rln_relay.nim b/waku/waku_rln_relay/rln_relay.nim index ab4ba10a6a..85890a2cd2 100644 --- a/waku/waku_rln_relay/rln_relay.nim +++ b/waku/waku_rln_relay/rln_relay.nim @@ -144,7 +144,7 @@ proc updateLog*( try: # check if an identical record exists if rlnPeer.nullifierLog[epoch].hasKeyOrPut(proofMetadata.nullifier, proofMetadata): - # the above condition could be `discarded` but it is kept for clarity, that slashing will + # the above condition could be `discarded` but it is kept for clarity, that slashing will # be implemented here # TODO: slashing logic return ok() @@ -279,8 +279,10 @@ proc validateMessageAndUpdateLog*( if proofMetadataRes.isErr(): return MessageValidationResult.Invalid - # insert the message to the log (never errors) - discard rlnPeer.updateLog(msgProof.epoch, proofMetadataRes.get()) + # insert the message to the log (never errors) only if the + # message is valid. + if isValidMessage == MessageValidationResult.Valid: + discard rlnPeer.updateLog(msgProof.epoch, proofMetadataRes.get()) return isValidMessage @@ -308,22 +310,25 @@ proc appendRLNProof*( let proof = rlnPeer.groupManager.generateProof(input, epoch, nonce).valueOr: return err("could not generate rln-v2 proof: " & $error) - msg.proof = proof.encode().buffer return ok() proc clearNullifierLog*(rlnPeer: WakuRlnRelay) = # clear the first MaxEpochGap epochs of the nullifer log # if more than MaxEpochGap epochs are in the log - # note: the epochs are ordered ascendingly - if rlnPeer.nullifierLog.len().uint <= rlnPeer.rlnMaxEpochGap: - return - - let countToClear = rlnPeer.nullifierLog.len().uint - rlnPeer.rlnMaxEpochGap - trace "clearing epochs from the nullifier log", count = countToClear - let epochsToClear = rlnPeer.nullifierLog.keys().toSeq()[0 ..< countToClear] - for epoch in epochsToClear: - rlnPeer.nullifierLog.del(epoch) + let currentEpoch = fromEpoch(rlnPeer.getCurrentEpoch()) + + var epochsToRemove: seq[Epoch] = @[] + for epoch in rlnPeer.nullifierLog.keys(): + let epochInt = fromEpoch(epoch) + + # clean all epochs that are +- rlnMaxEpochGap from the current epoch + if (currentEpoch+rlnPeer.rlnMaxEpochGap) <= epochInt or epochInt <= (currentEpoch-rlnPeer.rlnMaxEpochGap): + epochsToRemove.add(epoch) + + for epochRemove in epochsToRemove: + trace "clearing epochs from the nullifier log", currentEpoch = currentEpoch, cleanedEpoch = fromEpoch(epochRemove) + rlnPeer.nullifierLog.del(epochRemove) proc generateRlnValidator*( wakuRlnRelay: WakuRLNRelay, spamHandler = none(SpamHandler) From 05356ab97f64dc99b8b043332c985ab6211d8f72 Mon Sep 17 00:00:00 2001 From: Aaryamann Challani <43716372+rymnc@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:49:16 +0530 Subject: [PATCH 07/11] chore(rln-relay): add chain-id flag to wakunode and restrict usage if mismatches rpc provider (#2858) --- .../test_rln_group_manager_onchain.nim | 19 ++++++++++++++- .../rln_keystore_generator.nim | 4 ++-- waku/factory/external_config.nim | 6 +++++ waku/factory/networks_config.nim | 2 ++ waku/factory/node_factory.nim | 1 + waku/factory/waku.nim | 1 + .../group_manager/on_chain/group_manager.nim | 23 ++++++++++++------- waku/waku_rln_relay/rln_relay.nim | 2 ++ 8 files changed, 47 insertions(+), 11 deletions(-) diff --git a/tests/waku_rln_relay/test_rln_group_manager_onchain.nim b/tests/waku_rln_relay/test_rln_group_manager_onchain.nim index 94b1ed213e..f87e6c7022 100644 --- a/tests/waku_rln_relay/test_rln_group_manager_onchain.nim +++ b/tests/waku_rln_relay/test_rln_group_manager_onchain.nim @@ -26,6 +26,8 @@ import ../testlib/common, ./utils +const CHAIN_ID = 1337 + proc generateCredentials(rlnInstance: ptr RLN): IdentityCredential = let credRes = membershipKeyGen(rlnInstance) return credRes.get() @@ -140,7 +142,7 @@ proc runAnvil(): Process = anvilPath, args = [ "--port", "8540", "--gas-limit", "300000000000000", "--balance", "1000000000", - "--chain-id", "1337", + "--chain-id", $CHAIN_ID, ], options = {poUsePath}, ) @@ -195,6 +197,7 @@ proc setup(): Future[OnchainGroupManager] {.async.} = let manager = OnchainGroupManager( ethClientUrl: EthClient, ethContractAddress: $contractAddress, + chainId: CHAIN_ID, ethPrivateKey: pk, rlnInstance: rlnInstance, ) @@ -218,6 +221,20 @@ suite "Onchain group manager": await manager.stop() + asyncTest "should error on initialization when chainId does not match": + let manager = await setup() + manager.chainId = CHAIN_ID + 1 + + (await manager.init()).isErrOr: + raiseAssert "Expected error when chainId does not match" + + asyncTest "should initialize when chainId is set to 0": + let manager = await setup() + manager.chainId = 0 + + (await manager.init()).isOkOr: + raiseAssert $error + asyncTest "should error on initialization when loaded metadata does not match": let manager = await setup() (await manager.init()).isOkOr: diff --git a/tools/rln_keystore_generator/rln_keystore_generator.nim b/tools/rln_keystore_generator/rln_keystore_generator.nim index 6c64ed6d2d..2157b1c1b3 100644 --- a/tools/rln_keystore_generator/rln_keystore_generator.nim +++ b/tools/rln_keystore_generator/rln_keystore_generator.nim @@ -76,7 +76,7 @@ proc doRlnKeystoreGenerator*(conf: WakuNodeConf) = debug "Transaction hash", txHash = groupManager.registrationTxHash.get() info "Your membership has been registered on-chain.", - chainId = $groupManager.chainId.get(), + chainId = $groupManager.chainId, contractAddress = conf.rlnRelayEthContractAddress, membershipIndex = groupManager.membershipIndex.get() info "Your user message limit is", userMessageLimit = conf.rlnRelayUserMessageLimit @@ -84,7 +84,7 @@ proc doRlnKeystoreGenerator*(conf: WakuNodeConf) = # 6. write to keystore let keystoreCred = KeystoreMembership( membershipContract: MembershipContract( - chainId: $groupManager.chainId.get(), address: conf.rlnRelayEthContractAddress + chainId: $groupManager.chainId, address: conf.rlnRelayEthContractAddress ), treeIndex: groupManager.membershipIndex.get(), identityCredential: credential, diff --git a/waku/factory/external_config.nim b/waku/factory/external_config.nim index bc3c08bb19..a4d487e6a6 100644 --- a/waku/factory/external_config.nim +++ b/waku/factory/external_config.nim @@ -76,6 +76,12 @@ type WakuNodeConf* = object name: "rln-relay-eth-contract-address" .}: string + rlnRelayChainId* {. + desc: "Chain ID of the provided contract (optional, will fetch from RPC provider if not used)", + defaultValue: 0, + name: "rln-relay-chain-id" + .}: uint + rlnRelayCredPassword* {. desc: "Password for encrypting RLN credentials", defaultValue: "", diff --git a/waku/factory/networks_config.nim b/waku/factory/networks_config.nim index 92a4956f5d..1c5ab00970 100644 --- a/waku/factory/networks_config.nim +++ b/waku/factory/networks_config.nim @@ -8,6 +8,7 @@ type ClusterConf* = object clusterId*: uint16 rlnRelay*: bool rlnRelayEthContractAddress*: string + rlnRelayChainId*: uint rlnRelayDynamic*: bool rlnRelayBandwidthThreshold*: int rlnEpochSizeSec*: uint64 @@ -37,6 +38,7 @@ proc TheWakuNetworkConf*(T: type ClusterConf): ClusterConf = rlnRelay: true, rlnRelayEthContractAddress: "0x4976Df0f61135EF3E5720D92eadE2e5F47A68Ef9", rlnRelayDynamic: true, + rlnRelayChainId: 2442, # https://chainlist.org/chain/2442 rlnRelayBandwidthThreshold: 0, rlnEpochSizeSec: 600, rlnRelayUserMessageLimit: 20, diff --git a/waku/factory/node_factory.nim b/waku/factory/node_factory.nim index 2bc468fb82..b74d1a3e74 100644 --- a/waku/factory/node_factory.nim +++ b/waku/factory/node_factory.nim @@ -199,6 +199,7 @@ proc setupProtocols( rlnRelayDynamic: conf.rlnRelayDynamic, rlnRelayCredIndex: conf.rlnRelayCredIndex, rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress, + rlnRelayChainId: conf.rlnRelayChainId, rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress), rlnRelayCredPath: conf.rlnRelayCredPath, rlnRelayCredPassword: conf.rlnRelayCredPassword, diff --git a/waku/factory/waku.nim b/waku/factory/waku.nim index a461f65c5e..dc3b013149 100644 --- a/waku/factory/waku.nim +++ b/waku/factory/waku.nim @@ -116,6 +116,7 @@ proc init*(T: type Waku, conf: WakuNodeConf): Result[Waku, string] = confCopy.clusterId = twnClusterConf.clusterId confCopy.rlnRelay = twnClusterConf.rlnRelay confCopy.rlnRelayEthContractAddress = twnClusterConf.rlnRelayEthContractAddress + confCopy.rlnRelayChainId = twnClusterConf.rlnRelayChainId confCopy.rlnRelayDynamic = twnClusterConf.rlnRelayDynamic confCopy.rlnRelayBandwidthThreshold = twnClusterConf.rlnRelayBandwidthThreshold confCopy.discv5Discovery = twnClusterConf.discv5Discovery diff --git a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim index a83ae9bb34..637bd13543 100644 --- a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim +++ b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim @@ -61,7 +61,7 @@ type wakuRlnContract*: Option[WakuRlnContractWithSender] latestProcessedBlock*: BlockNumber registrationTxHash*: Option[TxHash] - chainId*: Option[Quantity] + chainId*: uint keystorePath*: Option[string] keystorePassword*: Option[string] registrationHandler*: Option[RegistrationHandler] @@ -106,7 +106,7 @@ proc setMetadata*( let metadataSetRes = g.rlnInstance.setMetadata( RlnMetadata( lastProcessedBlock: normalizedBlock, - chainId: uint64(g.chainId.get()), + chainId: g.chainId, contractAddress: g.ethContractAddress, validRoots: g.validRoots.toSeq(), ) @@ -540,11 +540,18 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} g.retryWrapper(ethRpc, "Failed to connect to the Ethereum client"): await newWeb3(g.ethClientUrl) + var fetchedChainId: uint + g.retryWrapper(fetchedChainId, "Failed to get the chain id"): + uint(await ethRpc.provider.eth_chainId()) + # Set the chain id - var chainId: Quantity - g.retryWrapper(chainId, "Failed to get the chain id"): - await ethRpc.provider.eth_chainId() - g.chainId = some(chainId) + if g.chainId == 0: + warn "Chain ID not set in config, using RPC Provider's Chain ID", providerChainId = fetchedChainId + + if g.chainId != 0 and g.chainId != fetchedChainId: + return err("The RPC Provided a Chain ID which is different than the provided Chain ID: provided = " & $g.chainId & ", actual = " & $fetchedChainId) + + g.chainId = fetchedChainId if g.ethPrivateKey.isSome(): let pk = g.ethPrivateKey.get() @@ -567,7 +574,7 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} var keystoreQuery = KeystoreMembership( membershipContract: - MembershipContract(chainId: $g.chainId.get(), address: g.ethContractAddress) + MembershipContract(chainId: $g.chainId, address: g.ethContractAddress) ) if g.membershipIndex.isSome(): keystoreQuery.treeIndex = MembershipIndex(g.membershipIndex.get()) @@ -599,7 +606,7 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.} warn "could not initialize with persisted rln metadata" elif metadataGetOptRes.get().isSome(): let metadata = metadataGetOptRes.get().get() - if metadata.chainId != uint64(g.chainId.get()): + if metadata.chainId != uint(g.chainId): return err("persisted data: chain id mismatch") if metadata.contractAddress != g.ethContractAddress.toLower(): diff --git a/waku/waku_rln_relay/rln_relay.nim b/waku/waku_rln_relay/rln_relay.nim index 85890a2cd2..c7c320c275 100644 --- a/waku/waku_rln_relay/rln_relay.nim +++ b/waku/waku_rln_relay/rln_relay.nim @@ -40,6 +40,7 @@ type WakuRlnConfig* = object rlnRelayCredIndex*: Option[uint] rlnRelayEthContractAddress*: string rlnRelayEthClientAddress*: string + rlnRelayChainId*: uint rlnRelayCredPath*: string rlnRelayCredPassword*: string rlnRelayTreePath*: string @@ -429,6 +430,7 @@ proc mount( groupManager = OnchainGroupManager( ethClientUrl: string(conf.rlnRelayethClientAddress), ethContractAddress: $conf.rlnRelayEthContractAddress, + chainId: conf.rlnRelayChainId, rlnInstance: rlnInstance, registrationHandler: registrationHandler, keystorePath: rlnRelayCredPath, From b3041d53889680030b7d8ef47420a9494a70e9b3 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande Date: Mon, 1 Jul 2024 14:35:00 +0200 Subject: [PATCH 08/11] CHANGELOG.md: simply update the date to reflect the current release date --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 604fcc0201..c9f121761c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## v0.30.0 (2024-06-20) +## v0.30.0 (2024-07-01) ### Features From 799e08cbacecbe9adb6c5b3be37c365966183345 Mon Sep 17 00:00:00 2001 From: Ivan Folgueira Bande Date: Mon, 1 Jul 2024 17:14:38 +0200 Subject: [PATCH 09/11] CHANGELOG.md: add better details of version v0.30.0 --- CHANGELOG.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9f121761c..9fa1e73490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,23 @@ ## v0.30.0 (2024-07-01) -### Features +### Notes -- rlnv2: clean fork of rlnv2 ([#2828](https://github.com/waku-org/nwaku/issues/2828)) ([a02832fe](https://github.com/waku-org/nwaku/commit/a02832fe)) +* Before upgrading to this version, if you are currently using RLN, make sure to remove your existing `keystore` folder and `rln_tree` +and start your installation from scratch, as +explained in [nwaku-compose](https://github.com/waku-org/nwaku-compose/blob/1b56575df9ddb904af0941a19ea1df3d36bfddfa/README.md). + +### Release highlights + +* RLN_v2 is used. The maximum rate can be set to +`N` messages per epoch, instead of just one meessage per epoch. See [this](https://github.com/waku-org/nwaku/issues/2345) for more details. ### Changes +- rln-relay: add chain-id flag to wakunode and restrict usage if mismatches rpc provider ([#2858](https://github.com/waku-org/nwaku/pull/2858)) +- rln: nullifierlog vulnerability ([#2855](https://github.com/waku-org/nwaku/pull/2855)) +- chore: add TWN parameters for RLNv2 ([#2843](https://github.com/waku-org/nwaku/pull/2843)) +- fix(rln-relay): clear nullifier log only if length is over max epoch gap ([#2836](https://github.com/waku-org/nwaku/pull/2836)) +- rlnv2: clean fork of rlnv2 ([#2828](https://github.com/waku-org/nwaku/issues/2828)) ([a02832fe](https://github.com/waku-org/nwaku/commit/a02832fe)) - zerokit: bump submodule ([#2830](https://github.com/waku-org/nwaku/issues/2830)) ([bd064882](https://github.com/waku-org/nwaku/commit/bd064882)) This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): From 898dac0be8058a1166c03e8048ce04d25753fdd7 Mon Sep 17 00:00:00 2001 From: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> Date: Tue, 2 Jul 2024 10:29:08 +0200 Subject: [PATCH 10/11] Update CHANGELOG.md Co-authored-by: Aaryamann Challani <43716372+rymnc@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fa1e73490..98bd679401 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ explained in [nwaku-compose](https://github.com/waku-org/nwaku-compose/blob/1b56 ### Release highlights * RLN_v2 is used. The maximum rate can be set to -`N` messages per epoch, instead of just one meessage per epoch. See [this](https://github.com/waku-org/nwaku/issues/2345) for more details. +`N` messages per epoch, instead of just one message per epoch. See [this](https://github.com/waku-org/nwaku/issues/2345) for more details. ### Changes From a07655e8d011f802224b9b1b51aa1cc73c14f7f8 Mon Sep 17 00:00:00 2001 From: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> Date: Tue, 2 Jul 2024 10:29:20 +0200 Subject: [PATCH 11/11] Update CHANGELOG.md Co-authored-by: Aaryamann Challani <43716372+rymnc@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98bd679401..b5842b63ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ explained in [nwaku-compose](https://github.com/waku-org/nwaku-compose/blob/1b56 ### Changes - rln-relay: add chain-id flag to wakunode and restrict usage if mismatches rpc provider ([#2858](https://github.com/waku-org/nwaku/pull/2858)) -- rln: nullifierlog vulnerability ([#2855](https://github.com/waku-org/nwaku/pull/2855)) +- rln: fix nullifierlog vulnerability ([#2855](https://github.com/waku-org/nwaku/pull/2855)) - chore: add TWN parameters for RLNv2 ([#2843](https://github.com/waku-org/nwaku/pull/2843)) - fix(rln-relay): clear nullifier log only if length is over max epoch gap ([#2836](https://github.com/waku-org/nwaku/pull/2836)) - rlnv2: clean fork of rlnv2 ([#2828](https://github.com/waku-org/nwaku/issues/2828)) ([a02832fe](https://github.com/waku-org/nwaku/commit/a02832fe))