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
This commit is contained in:
Aaryamann Challani 2024-06-20 15:05:21 +05:30 committed by Ivan Folgueira Bande
parent 31daabab84
commit a02832fe12
No known key found for this signature in database
GPG Key ID: 3C117481F89E24A7
30 changed files with 834 additions and 1649 deletions

View File

@ -54,12 +54,11 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
rln_version: [1, 2]
os: [ubuntu-latest, macos-13] os: [ubuntu-latest, macos-13]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
timeout-minutes: 60 timeout-minutes: 60
name: build-${{ matrix.os }}-rln-v${{ matrix.rln_version }} name: build-${{ matrix.os }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -78,7 +77,7 @@ jobs:
key: ${{ runner.os }}-vendor-modules-${{ steps.submodules.outputs.hash }} key: ${{ runner.os }}-vendor-modules-${{ steps.submodules.outputs.hash }}
- name: Build binaries - 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: test:
needs: changes needs: changes
@ -86,12 +85,11 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
rln_version: [1, 2]
os: [ubuntu-latest, macos-13] os: [ubuntu-latest, macos-13]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
timeout-minutes: 60 timeout-minutes: 60
name: test-${{ matrix.os }}-rln-v${{ matrix.rln_version }} name: test-${{ matrix.os }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v3
@ -120,7 +118,7 @@ jobs:
export MAKEFLAGS="-j1" export MAKEFLAGS="-j1"
export NIMFLAGS="--colors:off -d:chronicles_colors:none" 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: build-docker-image:
needs: changes needs: changes

View File

@ -22,12 +22,11 @@ jobs:
build-docker-image: build-docker-image:
strategy: strategy:
matrix: matrix:
rln_version : [1, 2]
os: [ubuntu-latest] os: [ubuntu-latest]
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
timeout-minutes: 60 timeout-minutes: 60
name: docker-build-${{ matrix.os }}-rln-v${{ matrix.rln_version }} name: docker-build-${{ matrix.os }}
outputs: outputs:
image: ${{ steps.build.outputs.image }} image: ${{ steps.build.outputs.image }}
steps: steps:
@ -67,12 +66,12 @@ jobs:
if: ${{ steps.secrets.outcome == 'success' }} if: ${{ steps.secrets.outcome == 'success' }}
run: | 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) SHORT_REF=$(git rev-parse --short HEAD)
TAG=$([ "${PR_NUMBER}" == "" ] && echo "${SHORT_REF}" || echo "${PR_NUMBER}") 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 "image=${IMAGE}" >> $GITHUB_OUTPUT
echo "commit_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT echo "commit_hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT

2
.gitmodules vendored
View File

@ -143,7 +143,7 @@
path = vendor/zerokit path = vendor/zerokit
url = https://github.com/vacp2p/zerokit.git url = https://github.com/vacp2p/zerokit.git
ignore = dirty ignore = dirty
branch = v0.3.4 branch = v0.5.1
[submodule "vendor/nim-regex"] [submodule "vendor/nim-regex"]
path = vendor/nim-regex path = vendor/nim-regex
url = https://github.com/nitely/nim-regex.git url = https://github.com/nitely/nim-regex.git

View File

@ -136,14 +136,10 @@ clean: | clean-libbacktrace
################## ##################
## RLN ## ## RLN ##
################## ##################
.PHONY: librln shouldUseRLNV2 .PHONY: librln
LIBRLN_BUILDDIR := $(CURDIR)/vendor/zerokit LIBRLN_BUILDDIR := $(CURDIR)/vendor/zerokit
ifeq ($(RLN_V2),true) LIBRLN_VERSION := v0.5.1
LIBRLN_VERSION := v0.4.4
else
LIBRLN_VERSION := v0.3.7
endif
ifeq ($(OS),Windows_NT) ifeq ($(OS),Windows_NT)
LIBRLN_FILE := rln.lib LIBRLN_FILE := rln.lib
@ -155,12 +151,7 @@ $(LIBRLN_FILE):
echo -e $(BUILD_MSG) "$@" && \ echo -e $(BUILD_MSG) "$@" && \
./scripts/build_rln.sh $(LIBRLN_BUILDDIR) $(LIBRLN_VERSION) $(LIBRLN_FILE) ./scripts/build_rln.sh $(LIBRLN_BUILDDIR) $(LIBRLN_VERSION) $(LIBRLN_FILE)
shouldUseRLNV2: librln: | $(LIBRLN_FILE)
ifeq ($(RLN_V2),true)
$(eval NIM_PARAMS += -d:rln_v2)
endif
librln: | $(LIBRLN_FILE) shouldUseRLNV2
$(eval NIM_PARAMS += --passL:$(LIBRLN_FILE) --passL:-lm) $(eval NIM_PARAMS += --passL:$(LIBRLN_FILE) --passL:-lm)
clean-librln: clean-librln:
@ -320,7 +311,7 @@ endif
rebuild-nat-libs: | clean-cross nat-libs rebuild-nat-libs: | clean-cross nat-libs
libwaku-android-precheck: shouldUseRLNV2 libwaku-android-precheck:
ifndef ANDROID_NDK_HOME ifndef ANDROID_NDK_HOME
$(error ANDROID_NDK_HOME is not set) $(error ANDROID_NDK_HOME is not set)
endif endif

View File

@ -542,27 +542,16 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
echo "rln-relay preparation is in progress..." echo "rln-relay preparation is in progress..."
when defined(rln_v2): let rlnConf = WakuRlnConfig(
let rlnConf = WakuRlnConfig( rlnRelayDynamic: conf.rlnRelayDynamic,
rlnRelayDynamic: conf.rlnRelayDynamic, rlnRelayCredIndex: conf.rlnRelayCredIndex,
rlnRelayCredIndex: conf.rlnRelayCredIndex, rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress,
rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress, rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress),
rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress), rlnRelayCredPath: conf.rlnRelayCredPath,
rlnRelayCredPath: conf.rlnRelayCredPath, rlnRelayCredPassword: conf.rlnRelayCredPassword,
rlnRelayCredPassword: conf.rlnRelayCredPassword, rlnRelayUserMessageLimit: conf.rlnRelayUserMessageLimit,
rlnRelayUserMessageLimit: conf.rlnRelayUserMessageLimit, rlnEpochSizeSec: conf.rlnEpochSizeSec,
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,
)
waitFor node.mountRlnRelay(rlnConf, spamHandler = some(spamHandler)) waitFor node.mountRlnRelay(rlnConf, spamHandler = some(spamHandler))

View File

@ -19,9 +19,9 @@ host_triplet=$(rustc --version --verbose | awk '/host:/{print $2}')
tarball="${host_triplet}" 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 # 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" tarball+="-arkzkey-rln.tar.gz"
else else
tarball+="-rln.tar.gz" tarball+="-rln.tar.gz"
@ -52,6 +52,6 @@ else
exit 1 exit 1
fi fi
# if submodule version = version in Makefile, build rln # 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}" cp "${build_dir}/target/release/librln.a" "${output_filename}"
fi fi

View File

@ -135,21 +135,14 @@ suite "RLN Proofs as a Lightpush Service":
client = newTestWakuNode(clientKey, ValidIpAddress.init("0.0.0.0"), Port(0)) client = newTestWakuNode(clientKey, ValidIpAddress.init("0.0.0.0"), Port(0))
# mount rln-relay # mount rln-relay
when defined(rln_v2): let wakuRlnConfig = WakuRlnConfig(
let wakuRlnConfig = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode"), )
)
else:
let wakuRlnConfig = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(1.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode"),
)
await allFutures(server.start(), client.start()) await allFutures(server.start(), client.start())
await server.start() await server.start()

View File

@ -95,51 +95,25 @@ proc sendRlnMessage*(
let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT)
return isCompleted return isCompleted
when defined(rln_v2): proc sendRlnMessageWithInvalidProof*(
proc sendRlnMessageWithInvalidProof*( client: WakuNode,
client: WakuNode, pubsubTopic: string,
pubsubTopic: string, contentTopic: string,
contentTopic: string, completionFuture: Future[bool],
completionFuture: Future[bool], payload: seq[byte] = "Hello".toBytes(),
payload: seq[byte] = "Hello".toBytes(), ): Future[bool] {.async.} =
): Future[bool] {.async.} = let
let extraBytes: seq[byte] = @[byte(1), 2, 3]
extraBytes: seq[byte] = @[byte(1), 2, 3] rateLimitProofRes = client.wakuRlnRelay.groupManager.generateProof(
rateLimitProofRes = client.wakuRlnRelay.groupManager.generateProof( concat(payload, extraBytes),
concat(payload, extraBytes), # we add extra bytes to invalidate proof verification against original payload
# we add extra bytes to invalidate proof verification against original payload client.wakuRlnRelay.getCurrentEpoch(),
client.wakuRlnRelay.getCurrentEpoch(), messageId = MessageId(0),
messageId = MessageId(0), )
) rateLimitProof = rateLimitProofRes.get().encode().buffer
rateLimitProof = rateLimitProofRes.get().encode().buffer message =
message = WakuMessage( WakuMessage(payload: @payload, contentTopic: contentTopic, proof: rateLimitProof)
payload: @payload, contentTopic: contentTopic, proof: rateLimitProof
)
discard await client.publish(some(pubsubTopic), message) discard await client.publish(some(pubsubTopic), message)
let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT) let isCompleted = await completionFuture.withTimeout(FUTURE_TIMEOUT)
return isCompleted 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

View File

@ -14,14 +14,11 @@ proc unsafeAppendRLNProof*(
let input = msg.toRLNSignal() let input = msg.toRLNSignal()
let epoch = rlnPeer.calcEpoch(senderEpochTime) let epoch = rlnPeer.calcEpoch(senderEpochTime)
when defined(rln_v2): # we do not fetch a nonce from the nonce manager,
# we do not fetch a nonce from the nonce manager, # instead we use 0 as the nonce
# instead we use 0 as the nonce let proof = rlnPeer.groupManager.generateProof(input, epoch, 0).valueOr:
let proof = rlnPeer.groupManager.generateProof(input, epoch, 0).valueOr: return err("could not generate rln-v2 proof: " & $error)
return err("could not generate rln-v2 proof: " & $error)
else:
let proof = rlnPeer.groupManager.generateProof(input, epoch).valueOr:
return err("could not generate rln proof: " & $error)
msg.proof = proof.encode().buffer msg.proof = proof.encode().buffer
return ok() return ok()

View File

@ -5,7 +5,5 @@ import
./test_rln_group_manager_static, ./test_rln_group_manager_static,
./test_waku_rln_relay, ./test_waku_rln_relay,
./test_wakunode_rln_relay, ./test_wakunode_rln_relay,
./test_rln_nonce_manager ./test_rln_nonce_manager,
./test_rln_serde
when defined(rln_v2):
import ./rln_v2/test_rln_relay_v2_serde

View File

@ -30,13 +30,12 @@ proc generateCredentials(rlnInstance: ptr RLN): IdentityCredential =
let credRes = membershipKeyGen(rlnInstance) let credRes = membershipKeyGen(rlnInstance)
return credRes.get() return credRes.get()
when defined(rln_v2): proc getRateCommitment(
proc getRateCommitment( idCredential: IdentityCredential, userMessageLimit: UserMessageLimit
idCredential: IdentityCredential, userMessageLimit: UserMessageLimit ): RlnRelayResult[RawRateCommitment] =
): RateCommitment = return RateCommitment(
return RateCommitment( idCommitment: idCredential.idCommitment, userMessageLimit: userMessageLimit
idCommitment: idCredential.idCommitment, userMessageLimit: userMessageLimit ).toLeaf()
)
proc generateCredentials(rlnInstance: ptr RLN, n: int): seq[IdentityCredential] = proc generateCredentials(rlnInstance: ptr RLN, n: int): seq[IdentityCredential] =
var credentials: 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") let balance = await web3.provider.eth_getBalance(web3.defaultAccount, "latest")
debug "Initial account balance: ", balance debug "Initial account balance: ", balance
when defined(rln_v2): # deploy poseidon hasher bytecode
# deploy registry contract with its constructor inputs let poseidonT3Receipt = await web3.deployContract(PoseidonT3)
let receipt = await web3.deployContract(RegistryContractCode) let poseidonT3Address = poseidonT3Receipt.contractAddress.get()
else: let poseidonAddressStripped = strip0xPrefix($poseidonT3Address)
# 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 # deploy lazy imt bytecode
let let lazyImtReceipt = await web3.deployContract(LazyIMT.replace("__$PoseidonT3$__", poseidonAddressStripped))
hasherAddressEncoded = encode(hasherAddress).data let lazyImtAddress = lazyImtReceipt.contractAddress.get()
# this is the contract constructor input let lazyImtAddressStripped = strip0xPrefix($lazyImtAddress)
contractInput = hasherAddressEncoded
debug "encoded hasher address: ", hasherAddressEncoded # deploy waku rlnv2 contract
debug "encoded contract input:", contractInput let wakuRlnContractReceipt = await web3.deployContract(WakuRlnV2Contract.replace("__$PoseidonT3$__", poseidonAddressStripped).replace("__$LazyIMT$__", lazyImtAddressStripped))
let wakuRlnContractAddress = wakuRlnContractReceipt.contractAddress.get()
let wakuRlnAddressStripped = strip0xPrefix($wakuRlnContractAddress)
# deploy registry contract with its constructor inputs debug "Address of the deployed rlnv2 contract: ", wakuRlnContractAddress
let receipt =
await web3.deployContract(RegistryContractCode, contractInput = contractInput)
let contractAddress = receipt.contractAddress.get() # 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()
debug "Address of the deployed registry contract: ", contractAddress
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") let newBalance = await web3.provider.eth_getBalance(web3.defaultAccount, "latest")
debug "Account balance after the contract deployment: ", newBalance debug "Account balance after the contract deployment: ", newBalance
await web3.close() await web3.close()
debug "disconnected from ", ethClientAddress debug "disconnected from ", ethClientAddress
return contractAddress return proxyAddress
proc createEthAccount(): Future[(keys.PrivateKey, Address)] {.async.} = proc createEthAccount(): Future[(keys.PrivateKey, Address)] {.async.} =
let web3 = await newWeb3(EthClient) let web3 = await newWeb3(EthClient)
@ -187,7 +176,7 @@ proc stopAnvil(runAnvil: Process) {.used.} =
proc setup(): Future[OnchainGroupManager] {.async.} = proc setup(): Future[OnchainGroupManager] {.async.} =
let rlnInstanceRes = let rlnInstanceRes =
createRlnInstance(tree_path = genTempPath("rln_tree", "group_manager_onchain")) createRlnInstance(tree_path = genTempPath("rln_tree", "group_manager_onchain"))
require: check:
rlnInstanceRes.isOk() rlnInstanceRes.isOk()
let rlnInstance = rlnInstanceRes.get() let rlnInstance = rlnInstanceRes.get()
@ -223,8 +212,7 @@ suite "Onchain group manager":
check: check:
manager.ethRpc.isSome() manager.ethRpc.isSome()
manager.rlnContract.isSome() manager.wakuRlnContract.isSome()
manager.membershipFee.isSome()
manager.initialized manager.initialized
manager.rlnContractDeployedBlockNumber > 0 manager.rlnContractDeployedBlockNumber > 0
@ -287,6 +275,8 @@ suite "Onchain group manager":
asyncTest "startGroupSync: should sync to the state of the group": asyncTest "startGroupSync: should sync to the state of the group":
let manager = await setup() let manager = await setup()
let credentials = generateCredentials(manager.rlnInstance) let credentials = generateCredentials(manager.rlnInstance)
let rateCommitment = getRateCommitment(credentials, UserMessageLimit(1)).valueOr:
raiseAssert $error
(await manager.init()).isOkOr: (await manager.init()).isOkOr:
raiseAssert $error raiseAssert $error
@ -297,28 +287,17 @@ suite "Onchain group manager":
proc generateCallback(fut: Future[void]): OnRegisterCallback = proc generateCallback(fut: Future[void]): OnRegisterCallback =
proc callback(registrations: seq[Membership]): Future[void] {.async.} = proc callback(registrations: seq[Membership]): Future[void] {.async.} =
require: check:
registrations.len == 1 registrations.len == 1
registrations[0].index == 0 registrations[0].index == 0
when defined(rln_v2): registrations[0].rateCommitment == rateCommitment
require:
registrations[0].rateCommitment ==
getRateCommitment(credentials, UserMessageLimit(1))
else:
require:
registrations[0].idCommitment == credentials.idCommitment
require:
registrations[0].index == 0
fut.complete() fut.complete()
return callback return callback
try: try:
manager.onRegister(generateCallback(fut)) manager.onRegister(generateCallback(fut))
when defined(rln_v2): await manager.register(credentials, UserMessageLimit(1))
await manager.register(credentials, UserMessageLimit(1))
else:
await manager.register(credentials)
(await manager.startGroupSync()).isOkOr: (await manager.startGroupSync()).isOkOr:
raiseAssert $error raiseAssert $error
except Exception, CatchableError: except Exception, CatchableError:
@ -355,19 +334,12 @@ suite "Onchain group manager":
): OnRegisterCallback = ): OnRegisterCallback =
var futureIndex = 0 var futureIndex = 0
proc callback(registrations: seq[Membership]): Future[void] {.async.} = proc callback(registrations: seq[Membership]): Future[void] {.async.} =
when defined(rln_v2): let rateCommitment = getRateCommitment(credentials[futureIndex], UserMessageLimit(1))
if registrations.len == 1 and if registrations.len == 1 and
registrations[0].rateCommitment == registrations[0].rateCommitment == rateCommitment.get() and
getRateCommitment(credentials[futureIndex], UserMessageLimit(1)) and registrations[0].index == MembershipIndex(futureIndex):
registrations[0].index == MembershipIndex(futureIndex): futs[futureIndex].complete()
futs[futureIndex].complete() futureIndex += 1
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
return callback return callback
@ -377,10 +349,7 @@ suite "Onchain group manager":
raiseAssert $error raiseAssert $error
for i in 0 ..< credentials.len(): for i in 0 ..< credentials.len():
when defined(rln_v2): await manager.register(credentials[i], UserMessageLimit(1))
await manager.register(credentials[i], UserMessageLimit(1))
else:
await manager.register(credentials[i])
except Exception, CatchableError: except Exception, CatchableError:
assert false, "exception raised: " & getCurrentExceptionMsg() assert false, "exception raised: " & getCurrentExceptionMsg()
@ -399,14 +368,11 @@ suite "Onchain group manager":
let dummyCommitment = default(IDCommitment) let dummyCommitment = default(IDCommitment)
try: try:
when defined(rln_v2): await manager.register(
await manager.register( RateCommitment(
RateCommitment( idCommitment: dummyCommitment, userMessageLimit: UserMessageLimit(1)
idCommitment: dummyCommitment, userMessageLimit: UserMessageLimit(1)
)
) )
else: )
await manager.register(dummyCommitment)
except CatchableError: except CatchableError:
assert true assert true
except Exception: except Exception:
@ -426,14 +392,11 @@ suite "Onchain group manager":
raiseAssert $error raiseAssert $error
try: try:
when defined(rln_v2): await manager.register(
await manager.register( RateCommitment(
RateCommitment( idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1)
idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1)
)
) )
else: )
await manager.register(idCommitment)
except Exception, CatchableError: except Exception, CatchableError:
assert false, assert false,
"exception raised when calling register: " & getCurrentExceptionMsg() "exception raised when calling register: " & getCurrentExceptionMsg()
@ -448,23 +411,16 @@ suite "Onchain group manager":
asyncTest "register: callback is called": asyncTest "register: callback is called":
let manager = await setup() let manager = await setup()
let idCommitment = generateCredentials(manager.rlnInstance).idCommitment let idCredentials = generateCredentials(manager.rlnInstance)
let idCommitment = idCredentials.idCommitment
let fut = newFuture[void]() let fut = newFuture[void]()
proc callback(registrations: seq[Membership]): Future[void] {.async.} = proc callback(registrations: seq[Membership]): Future[void] {.async.} =
require: let rateCommitment = getRateCommitment(idCredentials, UserMessageLimit(1))
check:
registrations.len == 1 registrations.len == 1
when defined(rln_v2): registrations[0].rateCommitment == rateCommitment.get()
require:
registrations[0].rateCommitment ==
RateCommitment(
idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1)
)
else:
require:
registrations[0].idCommitment == idCommitment
require:
registrations[0].index == 0 registrations[0].index == 0
fut.complete() fut.complete()
@ -474,18 +430,15 @@ suite "Onchain group manager":
try: try:
(await manager.startGroupSync()).isOkOr: (await manager.startGroupSync()).isOkOr:
raiseAssert $error raiseAssert $error
when defined(rln_v2): await manager.register(
await manager.register( RateCommitment(
RateCommitment( idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1)
idCommitment: idCommitment, userMessageLimit: UserMessageLimit(1)
)
) )
else: )
await manager.register(idCommitment)
except Exception, CatchableError: except Exception, CatchableError:
assert false, "exception raised: " & getCurrentExceptionMsg() assert false, "exception raised: " & getCurrentExceptionMsg()
check await fut.withTimeout(5.seconds) await fut
await manager.stop() await manager.stop()
@ -511,29 +464,20 @@ suite "Onchain group manager":
let fut = newFuture[void]() let fut = newFuture[void]()
proc callback(registrations: seq[Membership]): Future[void] {.async.} = proc callback(registrations: seq[Membership]): Future[void] {.async.} =
when defined(rln_v2): if registrations.len == 1 and
if registrations.len == 1 and registrations[0].rateCommitment ==
registrations[0].rateCommitment == getRateCommitment(credentials, UserMessageLimit(1)).get() and
getRateCommitment(credentials, UserMessageLimit(1)) and registrations[0].index == 0:
registrations[0].index == 0: manager.idCredentials = some(credentials)
manager.idCredentials = some(credentials) fut.complete()
fut.complete()
else:
if registrations.len == 1 and
registrations[0].idCommitment == credentials.idCommitment and
registrations[0].index == 0:
manager.idCredentials = some(credentials)
fut.complete()
manager.onRegister(callback) manager.onRegister(callback)
try: try:
(await manager.startGroupSync()).isOkOr: (await manager.startGroupSync()).isOkOr:
raiseAssert $error raiseAssert $error
when defined(rln_v2): await manager.register(credentials, UserMessageLimit(1))
await manager.register(credentials, UserMessageLimit(1))
else:
await manager.register(credentials)
except Exception, CatchableError: except Exception, CatchableError:
assert false, "exception raised: " & getCurrentExceptionMsg() assert false, "exception raised: " & getCurrentExceptionMsg()
@ -546,14 +490,11 @@ suite "Onchain group manager":
debug "epoch in bytes", epochHex = epoch.inHex() debug "epoch in bytes", epochHex = epoch.inHex()
# generate proof # generate proof
when defined(rln_v2): let validProofRes = manager.generateProof(
let validProofRes = manager.generateProof( data = messageBytes, epoch = epoch, messageId = MessageId(1)
data = messageBytes, epoch = epoch, messageId = MessageId(1) )
)
else:
let validProofRes = manager.generateProof(data = messageBytes, epoch = epoch)
require: check:
validProofRes.isOk() validProofRes.isOk()
let validProof = validProofRes.get() let validProof = validProofRes.get()
@ -576,8 +517,7 @@ suite "Onchain group manager":
## Assume the registration occured out of band ## Assume the registration occured out of band
manager.idCredentials = some(credentials) manager.idCredentials = some(credentials)
manager.membershipIndex = some(MembershipIndex(0)) manager.membershipIndex = some(MembershipIndex(0))
when defined(rln_v2): manager.userMessageLimit = some(UserMessageLimit(1))
manager.userMessageLimit = some(UserMessageLimit(1))
let messageBytes = "Hello".toBytes() let messageBytes = "Hello".toBytes()
@ -586,15 +526,10 @@ suite "Onchain group manager":
debug "epoch in bytes", epochHex = epoch.inHex() debug "epoch in bytes", epochHex = epoch.inHex()
# generate proof # generate proof
when defined(rln_v2): let validProof = manager.generateProof(
let validProofRes = manager.generateProof( data = messageBytes, epoch = epoch, messageId = MessageId(0)
data = messageBytes, epoch = epoch, messageId = MessageId(0) ).valueOr:
) raiseAssert $error
else:
let validProofRes = manager.generateProof(data = messageBytes, epoch = epoch)
require:
validProofRes.isOk()
let validProof = validProofRes.get()
# validate the root (should be false) # validate the root (should be false)
let validated = manager.validateRoot(validProof.merkleRoot) let validated = manager.validateRoot(validProof.merkleRoot)
@ -612,29 +547,20 @@ suite "Onchain group manager":
let fut = newFuture[void]() let fut = newFuture[void]()
proc callback(registrations: seq[Membership]): Future[void] {.async.} = proc callback(registrations: seq[Membership]): Future[void] {.async.} =
when defined(rln_v2): if registrations.len == 1 and
if registrations.len == 1 and registrations[0].rateCommitment ==
registrations[0].rateCommitment == getRateCommitment(credentials, UserMessageLimit(1)).get() and
getRateCommitment(credentials, UserMessageLimit(1)) and registrations[0].index == 0:
registrations[0].index == 0: manager.idCredentials = some(credentials)
manager.idCredentials = some(credentials) fut.complete()
fut.complete()
else:
if registrations.len == 1 and
registrations[0].idCommitment == credentials.idCommitment and
registrations[0].index == 0:
manager.idCredentials = some(credentials)
fut.complete()
manager.onRegister(callback) manager.onRegister(callback)
try: try:
(await manager.startGroupSync()).isOkOr: (await manager.startGroupSync()).isOkOr:
raiseAssert $error raiseAssert $error
when defined(rln_v2): await manager.register(credentials, UserMessageLimit(1))
await manager.register(credentials, UserMessageLimit(1))
else:
await manager.register(credentials)
except Exception, CatchableError: except Exception, CatchableError:
assert false, "exception raised: " & getCurrentExceptionMsg() assert false, "exception raised: " & getCurrentExceptionMsg()
await fut await fut
@ -646,23 +572,16 @@ suite "Onchain group manager":
debug "epoch in bytes", epochHex = epoch.inHex() debug "epoch in bytes", epochHex = epoch.inHex()
# generate proof # generate proof
when defined(rln_v2): let validProof = manager.generateProof(
let validProofRes = manager.generateProof( data = messageBytes, epoch = epoch, messageId = MessageId(0)
data = messageBytes, epoch = epoch, messageId = MessageId(0) ).valueOr:
) raiseAssert $error
else:
let validProofRes = manager.generateProof(data = messageBytes, epoch = epoch)
require:
validProofRes.isOk()
let validProof = validProofRes.get()
# verify the proof (should be true) # verify the proof (should be true)
let verifiedRes = manager.verifyProof(messageBytes, validProof) let verified = manager.verifyProof(messageBytes, validProof).valueOr:
require: raiseAssert $error
verifiedRes.isOk()
check: check: verified
verifiedRes.get()
await manager.stop() await manager.stop()
asyncTest "verifyProof: should reject invalid proof": asyncTest "verifyProof: should reject invalid proof":
@ -675,10 +594,8 @@ suite "Onchain group manager":
let idCredential = generateCredentials(manager.rlnInstance) let idCredential = generateCredentials(manager.rlnInstance)
try: try:
when defined(rln_v2): await manager.register(RateCommitment(idCommitment: idCredential.idCommitment,
await manager.register(getRateCommitment(idCredential, UserMessageLimit(1))) userMessageLimit: UserMessageLimit(1)))
else:
await manager.register(idCredential.idCommitment)
except Exception, CatchableError: except Exception, CatchableError:
assert false, assert false,
"exception raised when calling startGroupSync: " & getCurrentExceptionMsg() "exception raised when calling startGroupSync: " & getCurrentExceptionMsg()
@ -688,8 +605,7 @@ suite "Onchain group manager":
## Assume the registration occured out of band ## Assume the registration occured out of band
manager.idCredentials = some(idCredential2) manager.idCredentials = some(idCredential2)
manager.membershipIndex = some(MembershipIndex(0)) manager.membershipIndex = some(MembershipIndex(0))
when defined(rln_v2): manager.userMessageLimit = some(UserMessageLimit(1))
manager.userMessageLimit = some(UserMessageLimit(1))
let messageBytes = "Hello".toBytes() let messageBytes = "Hello".toBytes()
@ -698,14 +614,11 @@ suite "Onchain group manager":
debug "epoch in bytes", epochHex = epoch.inHex() debug "epoch in bytes", epochHex = epoch.inHex()
# generate proof # generate proof
when defined(rln_v2): let invalidProofRes = manager.generateProof(
let invalidProofRes = manager.generateProof( data = messageBytes, epoch = epoch, messageId = MessageId(0)
data = messageBytes, epoch = epoch, messageId = MessageId(0) )
)
else:
let invalidProofRes = manager.generateProof(data = messageBytes, epoch = epoch)
require: check:
invalidProofRes.isOk() invalidProofRes.isOk()
let invalidProof = invalidProofRes.get() let invalidProof = invalidProofRes.get()
@ -734,19 +647,12 @@ suite "Onchain group manager":
): OnRegisterCallback = ): OnRegisterCallback =
var futureIndex = 0 var futureIndex = 0
proc callback(registrations: seq[Membership]): Future[void] {.async.} = proc callback(registrations: seq[Membership]): Future[void] {.async.} =
when defined(rln_v2): if registrations.len == 1 and
if registrations.len == 1 and registrations[0].rateCommitment ==
registrations[0].rateCommitment == getRateCommitment(credentials[futureIndex], UserMessageLimit(1)).get() and
getRateCommitment(credentials[futureIndex], UserMessageLimit(1)) and registrations[0].index == MembershipIndex(futureIndex):
registrations[0].index == MembershipIndex(futureIndex): futs[futureIndex].complete()
futs[futureIndex].complete() futureIndex += 1
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
return callback return callback
@ -756,17 +662,14 @@ suite "Onchain group manager":
raiseAssert $error raiseAssert $error
for i in 0 ..< credentials.len(): for i in 0 ..< credentials.len():
when defined(rln_v2): await manager.register(credentials[i], UserMessageLimit(1))
await manager.register(credentials[i], UserMessageLimit(1))
else:
await manager.register(credentials[i])
except Exception, CatchableError: except Exception, CatchableError:
assert false, "exception raised: " & getCurrentExceptionMsg() assert false, "exception raised: " & getCurrentExceptionMsg()
await allFutures(futures) await allFutures(futures)
# At this point, we should have a full root queue, 5 roots, and partial buffer of 1 root # 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.validRoots.len() == credentialCount - 1
manager.validRootBuffer.len() == 1 manager.validRootBuffer.len() == 1

View File

@ -94,14 +94,11 @@ suite "Static group manager":
let dummyCommitment = default(IDCommitment) let dummyCommitment = default(IDCommitment)
try: try:
when defined(rln_v2): await manager.register(
await manager.register( RateCommitment(
RateCommitment( idCommitment: dummyCommitment, userMessageLimit: DefaultUserMessageLimit
idCommitment: dummyCommitment, userMessageLimit: DefaultUserMessageLimit
)
) )
else: )
await manager.register(dummyCommitment)
except ValueError: except ValueError:
assert true assert true
except Exception, CatchableError: except Exception, CatchableError:
@ -117,14 +114,11 @@ suite "Static group manager":
let merkleRootBefore = manager.rlnInstance.getMerkleRoot().valueOr: let merkleRootBefore = manager.rlnInstance.getMerkleRoot().valueOr:
raiseAssert $error raiseAssert $error
try: try:
when defined(rln_v2): await manager.register(
await manager.register( RateCommitment(
RateCommitment( idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit
idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit
)
) )
else: )
await manager.register(idCommitment)
except Exception, CatchableError: except Exception, CatchableError:
assert false, "exception raised: " & getCurrentExceptionMsg() assert false, "exception raised: " & getCurrentExceptionMsg()
let merkleRootAfter = manager.rlnInstance.getMerkleRoot().valueOr: let merkleRootAfter = manager.rlnInstance.getMerkleRoot().valueOr:
@ -143,15 +137,10 @@ suite "Static group manager":
require: require:
registrations.len == 1 registrations.len == 1
registrations[0].index == 10 registrations[0].index == 10
when defined(rln_v2): registrations[0].rateCommitment ==
require: RateCommitment(
registrations[0].rateCommitment == idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit
RateCommitment( ).toLeaf().get()
idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit
)
else:
require:
registrations[0].idCommitment == idCommitment
callbackCalled = true callbackCalled = true
fut.complete() fut.complete()
@ -161,14 +150,11 @@ suite "Static group manager":
raiseAssert $error raiseAssert $error
(await manager.startGroupSync()).isOkOr: (await manager.startGroupSync()).isOkOr:
raiseAssert $error raiseAssert $error
when defined(rln_v2): await manager.register(
await manager.register( RateCommitment(
RateCommitment( idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit
idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit
)
) )
else: )
await manager.register(idCommitment)
except Exception, CatchableError: except Exception, CatchableError:
assert false, "exception raised: " & getCurrentExceptionMsg() assert false, "exception raised: " & getCurrentExceptionMsg()
@ -215,15 +201,11 @@ suite "Static group manager":
require: require:
withdrawals.len == 1 withdrawals.len == 1
withdrawals[0].index == 0 withdrawals[0].index == 0
when defined(rln_v2): withdrawals[0].rateCommitment ==
require: RateCommitment(
withdrawals[0].rateCommitment == idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit
RateCommitment( ).toLeaf().get()
idCommitment: idCommitment, userMessageLimit: DefaultUserMessageLimit
)
else:
require:
withdrawals[0].idCommitment == idCommitment
callbackCalled = true callbackCalled = true
fut.complete() fut.complete()

View File

@ -6,10 +6,10 @@ else:
{.push raises: [].} {.push raises: [].}
import import
../rln/waku_rln_relay_utils, ./rln/waku_rln_relay_utils,
../../../waku/waku_keystore/protocol_types, ../../waku/waku_keystore/protocol_types,
../../../waku/waku_rln_relay, ../../waku/waku_rln_relay,
../../../waku/waku_rln_relay/rln ../../waku/waku_rln_relay/rln
import testutils/unittests import testutils/unittests
import stew/results, stint import stew/results, stint

View File

@ -525,14 +525,11 @@ suite "Waku rln relay":
let rln = rlnInstance.get() let rln = rlnInstance.get()
# create a Merkle tree # create a Merkle tree
when defined(rln_v2): let rateCommitments =
let rateCommitments = groupIDCommitments.mapIt(RateCommitment(idCommitment: it, userMessageLimit: 20))
groupIDCommitments.mapIt(RateCommitment(idCommitment: it, userMessageLimit: 20)) let leaves = rateCommitments.toLeaves().valueOr:
let leaves = rateCommitments.toLeaves().valueOr: raiseAssert $error
raiseAssert $error let membersAdded = rln.insertMembers(0, leaves)
let membersAdded = rln.insertMembers(0, leaves)
else:
let membersAdded = rln.insertMembers(0, groupIDCommitments)
assert membersAdded, "members should be added" assert membersAdded, "members should be added"
let rawRoot = rln.getMerkleRoot().valueOr: let rawRoot = rln.getMerkleRoot().valueOr:
@ -691,21 +688,14 @@ suite "Waku rln relay":
asyncTest "validateMessageAndUpdateLog test": asyncTest "validateMessageAndUpdateLog test":
let index = MembershipIndex(5) let index = MembershipIndex(5)
when defined(rln_v2): let wakuRlnConfig = WakuRlnConfig(
let wakuRlnConfig = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(index),
rlnRelayCredIndex: some(index), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_2"),
rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_2"), )
)
else:
let wakuRlnConfig = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(index),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_2"),
)
let wakuRlnRelay = (await WakuRlnRelay.new(wakuRlnConfig)).valueOr: let wakuRlnRelay = (await WakuRlnRelay.new(wakuRlnConfig)).valueOr:
raiseAssert $error raiseAssert $error
@ -749,40 +739,25 @@ suite "Waku rln relay":
let index1 = MembershipIndex(5) let index1 = MembershipIndex(5)
let index2 = MembershipIndex(6) let index2 = MembershipIndex(6)
when defined(rln_v2): let rlnConf1 = WakuRlnConfig(
let rlnConf1 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(index1),
rlnRelayCredIndex: some(index1), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_3"),
rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_3"), )
)
else:
let rlnConf1 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(index1),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_3"),
)
let wakuRlnRelay1 = (await WakuRlnRelay.new(rlnConf1)).valueOr: let wakuRlnRelay1 = (await WakuRlnRelay.new(rlnConf1)).valueOr:
raiseAssert "failed to create waku rln relay: " & $error raiseAssert "failed to create waku rln relay: " & $error
when defined(rln_v2): let rlnConf2 = WakuRlnConfig(
let rlnConf2 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(index2),
rlnRelayCredIndex: some(index2), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_4"),
rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_4"), )
)
else:
let rlnConf2 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(index2),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "waku_rln_relay_4"),
)
let wakuRlnRelay2 = (await WakuRlnRelay.new(rlnConf2)).valueOr: let wakuRlnRelay2 = (await WakuRlnRelay.new(rlnConf2)).valueOr:
raiseAssert "failed to create waku rln relay: " & $error raiseAssert "failed to create waku rln relay: " & $error
# get the current epoch time # get the current epoch time

View File

@ -40,21 +40,14 @@ procSuite "WakuNode - RLN relay":
await node1.mountRelay(@[DefaultPubsubTopic]) await node1.mountRelay(@[DefaultPubsubTopic])
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
when defined(rln_v2): let wakuRlnConfig1 = WakuRlnConfig(
let wakuRlnConfig1 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode"), )
)
else:
let wakuRlnConfig1 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(1.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode"),
)
await node1.mountRlnRelay(wakuRlnConfig1) await node1.mountRlnRelay(wakuRlnConfig1)
await node1.start() await node1.start()
@ -62,21 +55,14 @@ procSuite "WakuNode - RLN relay":
# node 2 # node 2
await node2.mountRelay(@[DefaultPubsubTopic]) await node2.mountRelay(@[DefaultPubsubTopic])
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
when defined(rln_v2): let wakuRlnConfig2 = WakuRlnConfig(
let wakuRlnConfig2 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(2.uint),
rlnRelayCredIndex: some(2.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_2"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_2"), )
)
else:
let wakuRlnConfig2 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(2.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_2"),
)
await node2.mountRlnRelay(wakuRlnConfig2) await node2.mountRlnRelay(wakuRlnConfig2)
await node2.start() await node2.start()
@ -84,21 +70,14 @@ procSuite "WakuNode - RLN relay":
# node 3 # node 3
await node3.mountRelay(@[DefaultPubsubTopic]) await node3.mountRelay(@[DefaultPubsubTopic])
when defined(rln_v2): let wakuRlnConfig3 = WakuRlnConfig(
let wakuRlnConfig3 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(3.uint),
rlnRelayCredIndex: some(3.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_3"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_3"), )
)
else:
let wakuRlnConfig3 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(3.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_3"),
)
await node3.mountRlnRelay(wakuRlnConfig3) await node3.mountRlnRelay(wakuRlnConfig3)
await node3.start() await node3.start()
@ -162,21 +141,14 @@ procSuite "WakuNode - RLN relay":
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
for index, node in nodes: for index, node in nodes:
when defined(rln_v2): let wakuRlnConfig = WakuRlnConfig(
let wakuRlnConfig = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(index.uint + 1),
rlnRelayCredIndex: some(index.uint + 1), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $(index + 1)),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $(index + 1)), )
)
else:
let wakuRlnConfig = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(index.uint + 1),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $(index + 1)),
)
await node.mountRlnRelay(wakuRlnConfig) await node.mountRlnRelay(wakuRlnConfig)
# start them # start them
@ -263,21 +235,14 @@ procSuite "WakuNode - RLN relay":
await node1.mountRelay(@[DefaultPubsubTopic]) await node1.mountRelay(@[DefaultPubsubTopic])
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
when defined(rln_v2): let wakuRlnConfig1 = WakuRlnConfig(
let wakuRlnConfig1 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_4"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_4"), )
)
else:
let wakuRlnConfig1 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(1.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_4"),
)
await node1.mountRlnRelay(wakuRlnConfig1) await node1.mountRlnRelay(wakuRlnConfig1)
await node1.start() await node1.start()
@ -285,21 +250,14 @@ procSuite "WakuNode - RLN relay":
# node 2 # node 2
await node2.mountRelay(@[DefaultPubsubTopic]) await node2.mountRelay(@[DefaultPubsubTopic])
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
when defined(rln_v2): let wakuRlnConfig2 = WakuRlnConfig(
let wakuRlnConfig2 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(2.uint),
rlnRelayCredIndex: some(2.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_5"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_5"), )
)
else:
let wakuRlnConfig2 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(2.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_5"),
)
await node2.mountRlnRelay(wakuRlnConfig2) await node2.mountRlnRelay(wakuRlnConfig2)
await node2.start() await node2.start()
@ -307,21 +265,14 @@ procSuite "WakuNode - RLN relay":
# node 3 # node 3
await node3.mountRelay(@[DefaultPubsubTopic]) await node3.mountRelay(@[DefaultPubsubTopic])
when defined(rln_v2): let wakuRlnConfig3 = WakuRlnConfig(
let wakuRlnConfig3 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(3.uint),
rlnRelayCredIndex: some(3.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_6"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_6"), )
)
else:
let wakuRlnConfig3 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(3.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_6"),
)
await node3.mountRlnRelay(wakuRlnConfig3) await node3.mountRlnRelay(wakuRlnConfig3)
await node3.start() await node3.start()
@ -354,17 +305,11 @@ procSuite "WakuNode - RLN relay":
input = concat(payload, contentTopicBytes) input = concat(payload, contentTopicBytes)
extraBytes: seq[byte] = @[byte(1), 2, 3] extraBytes: seq[byte] = @[byte(1), 2, 3]
when defined(rln_v2): let nonceManager = node1.wakuRlnRelay.nonceManager
let nonceManager = node1.wakuRlnRelay.nonceManager let rateLimitProofRes = node1.wakuRlnRelay.groupManager.generateProof(
let rateLimitProofRes = node1.wakuRlnRelay.groupManager.generateProof( concat(input, extraBytes), epoch, MessageId(0)
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,
)
assert rateLimitProofRes.isOk(), $rateLimitProofRes.error assert rateLimitProofRes.isOk(), $rateLimitProofRes.error
# check the proof is generated correctly outside when block to avoid duplication # check the proof is generated correctly outside when block to avoid duplication
let rateLimitProof = rateLimitProofRes.get().encode().buffer let rateLimitProof = rateLimitProofRes.get().encode().buffer
@ -406,21 +351,14 @@ procSuite "WakuNode - RLN relay":
await node1.mountRelay(@[DefaultPubsubTopic]) await node1.mountRelay(@[DefaultPubsubTopic])
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
when defined(rln_v2): let wakuRlnConfig1 = WakuRlnConfig(
let wakuRlnConfig1 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_7"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_7"), )
)
else:
let wakuRlnConfig1 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(1.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_7"),
)
await node1.mountRlnRelay(wakuRlnConfig1) await node1.mountRlnRelay(wakuRlnConfig1)
await node1.start() await node1.start()
@ -429,21 +367,14 @@ procSuite "WakuNode - RLN relay":
await node2.mountRelay(@[DefaultPubsubTopic]) await node2.mountRelay(@[DefaultPubsubTopic])
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
when defined(rln_v2): let wakuRlnConfig2 = WakuRlnConfig(
let wakuRlnConfig2 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(2.uint),
rlnRelayCredIndex: some(2.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_8"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_8"), )
)
else:
let wakuRlnConfig2 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(2.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_8"),
)
await node2.mountRlnRelay(wakuRlnConfig2) await node2.mountRlnRelay(wakuRlnConfig2)
await node2.start() await node2.start()
@ -451,21 +382,14 @@ procSuite "WakuNode - RLN relay":
await node3.mountRelay(@[DefaultPubsubTopic]) await node3.mountRelay(@[DefaultPubsubTopic])
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
when defined(rln_v2): let wakuRlnConfig3 = WakuRlnConfig(
let wakuRlnConfig3 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(3.uint),
rlnRelayCredIndex: some(3.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_9"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_9"), )
)
else:
let wakuRlnConfig3 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(3.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_9"),
)
await node3.mountRlnRelay(wakuRlnConfig3) await node3.mountRlnRelay(wakuRlnConfig3)
await node3.start() await node3.start()
@ -562,21 +486,14 @@ procSuite "WakuNode - RLN relay":
await node1.mountRelay(@[DefaultPubsubTopic]) await node1.mountRelay(@[DefaultPubsubTopic])
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
when defined(rln_v2): let wakuRlnConfig1 = WakuRlnConfig(
let wakuRlnConfig1 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_10"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_10"), )
)
else:
let wakuRlnConfig1 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(1.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_10"),
)
await node1.mountRlnRelay(wakuRlnConfig1) await node1.mountRlnRelay(wakuRlnConfig1)
await node1.start() await node1.start()
@ -585,21 +502,14 @@ procSuite "WakuNode - RLN relay":
await node2.mountRelay(@[DefaultPubsubTopic]) await node2.mountRelay(@[DefaultPubsubTopic])
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
when defined(rln_v2): let wakuRlnConfig2 = WakuRlnConfig(
let wakuRlnConfig2 = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(2.uint),
rlnRelayCredIndex: some(2.uint), rlnRelayUserMessageLimit: 1,
rlnRelayUserMessageLimit: 1, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_11"),
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_11"), )
)
else:
let wakuRlnConfig2 = WakuRlnConfig(
rlnRelayDynamic: false,
rlnRelayCredIndex: some(2.uint),
rlnEpochSizeSec: 1,
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_11"),
)
await node2.mountRlnRelay(wakuRlnConfig2) await node2.mountRlnRelay(wakuRlnConfig2)
await node2.start() await node2.start()

View File

@ -219,21 +219,14 @@ suite "Waku v2 Rest API - Relay":
let node = testWakuNode() let node = testWakuNode()
await node.start() await node.start()
await node.mountRelay() await node.mountRelay()
when defined(rln_v2): let wakuRlnConfig = WakuRlnConfig(
let wakuRlnConfig = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 20,
rlnRelayUserMessageLimit: 20, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_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"),
)
await node.mountRlnRelay(wakuRlnConfig) await node.mountRlnRelay(wakuRlnConfig)
# RPC server setup # RPC server setup
@ -443,21 +436,14 @@ suite "Waku v2 Rest API - Relay":
let node = testWakuNode() let node = testWakuNode()
await node.start() await node.start()
await node.mountRelay() await node.mountRelay()
when defined(rln_v2): let wakuRlnConfig = WakuRlnConfig(
let wakuRlnConfig = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 20,
rlnRelayUserMessageLimit: 20, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_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"),
)
await node.mountRlnRelay(wakuRlnConfig) await node.mountRlnRelay(wakuRlnConfig)
# RPC server setup # RPC server setup
@ -502,21 +488,14 @@ suite "Waku v2 Rest API - Relay":
let node = testWakuNode() let node = testWakuNode()
await node.start() await node.start()
await node.mountRelay() await node.mountRelay()
when defined(rln_v2): let wakuRlnConfig = WakuRlnConfig(
let wakuRlnConfig = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 20,
rlnRelayUserMessageLimit: 20, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_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"),
)
await node.mountRlnRelay(wakuRlnConfig) await node.mountRlnRelay(wakuRlnConfig)
# RPC server setup # RPC server setup
@ -557,21 +536,14 @@ suite "Waku v2 Rest API - Relay":
let node = testWakuNode() let node = testWakuNode()
await node.start() await node.start()
await node.mountRelay() await node.mountRelay()
when defined(rln_v2): let wakuRlnConfig = WakuRlnConfig(
let wakuRlnConfig = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 20,
rlnRelayUserMessageLimit: 20, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_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"),
)
await node.mountRlnRelay(wakuRlnConfig) await node.mountRlnRelay(wakuRlnConfig)
# RPC server setup # RPC server setup
@ -619,21 +591,14 @@ suite "Waku v2 Rest API - Relay":
let node = testWakuNode() let node = testWakuNode()
await node.start() await node.start()
await node.mountRelay() await node.mountRelay()
when defined(rln_v2): let wakuRlnConfig = WakuRlnConfig(
let wakuRlnConfig = WakuRlnConfig( rlnRelayDynamic: false,
rlnRelayDynamic: false, rlnRelayCredIndex: some(1.uint),
rlnRelayCredIndex: some(1.uint), rlnRelayUserMessageLimit: 20,
rlnRelayUserMessageLimit: 20, rlnEpochSizeSec: 1,
rlnEpochSizeSec: 1, rlnRelayTreePath: genTempPath("rln_tree", "wakunode_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"),
)
await node.mountRlnRelay(wakuRlnConfig) await node.mountRlnRelay(wakuRlnConfig)
# RPC server setup # RPC server setup

View File

@ -67,10 +67,7 @@ proc doRlnKeystoreGenerator*(conf: WakuNodeConf) =
# 5. register on-chain # 5. register on-chain
try: try:
when defined(rln_v2): waitFor groupManager.register(credential, conf.rlnRelayUserMessageLimit)
waitFor groupManager.register(credential, conf.rlnRelayUserMessageLimit)
else:
waitFor groupManager.register(credential)
except Exception, CatchableError: except Exception, CatchableError:
error "failure while registering credentials on-chain", error "failure while registering credentials on-chain",
error = getCurrentExceptionMsg() error = getCurrentExceptionMsg()
@ -82,27 +79,18 @@ proc doRlnKeystoreGenerator*(conf: WakuNodeConf) =
chainId = $groupManager.chainId.get(), chainId = $groupManager.chainId.get(),
contractAddress = conf.rlnRelayEthContractAddress, contractAddress = conf.rlnRelayEthContractAddress,
membershipIndex = groupManager.membershipIndex.get() 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 # 6. write to keystore
when defined(rln_v2): let keystoreCred = KeystoreMembership(
let keystoreCred = KeystoreMembership( membershipContract: MembershipContract(
membershipContract: MembershipContract( chainId: $groupManager.chainId.get(), address: conf.rlnRelayEthContractAddress
chainId: $groupManager.chainId.get(), address: conf.rlnRelayEthContractAddress ),
), treeIndex: groupManager.membershipIndex.get(),
treeIndex: groupManager.membershipIndex.get(), identityCredential: credential,
identityCredential: credential, userMessageLimit: conf.rlnRelayUserMessageLimit,
userMessageLimit: conf.rlnRelayUserMessageLimit, )
)
else:
let keystoreCred = KeystoreMembership(
membershipContract: MembershipContract(
chainId: $groupManager.chainId.get(), address: conf.rlnRelayEthContractAddress
),
treeIndex: groupManager.membershipIndex.get(),
identityCredential: credential,
)
let persistRes = addMembershipCredentials( let persistRes = addMembershipCredentials(
conf.rlnRelayCredPath, keystoreCred, conf.rlnRelayCredPassword, RLNAppInfo conf.rlnRelayCredPath, keystoreCred, conf.rlnRelayCredPassword, RLNAppInfo

2
vendor/zerokit vendored

@ -1 +1 @@
Subproject commit 0ad1ed296d49e85598e0ec0bae7c220885e47912 Subproject commit 85d71a5427ee78528d6420c04b67c7825e3c6e91

View File

@ -195,31 +195,18 @@ proc setupProtocols(
quit(QuitFailure) quit(QuitFailure)
if conf.rlnRelay: if conf.rlnRelay:
when defined(rln_v2): let rlnConf = WakuRlnConfig(
let rlnConf = WakuRlnConfig( rlnRelayDynamic: conf.rlnRelayDynamic,
rlnRelayDynamic: conf.rlnRelayDynamic, rlnRelayCredIndex: conf.rlnRelayCredIndex,
rlnRelayCredIndex: conf.rlnRelayCredIndex, rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress,
rlnRelayEthContractAddress: conf.rlnRelayEthContractAddress, rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress),
rlnRelayEthClientAddress: string(conf.rlnRelayethClientAddress), rlnRelayCredPath: conf.rlnRelayCredPath,
rlnRelayCredPath: conf.rlnRelayCredPath, rlnRelayCredPassword: conf.rlnRelayCredPassword,
rlnRelayCredPassword: conf.rlnRelayCredPassword, rlnRelayTreePath: conf.rlnRelayTreePath,
rlnRelayTreePath: conf.rlnRelayTreePath, rlnRelayUserMessageLimit: conf.rlnRelayUserMessageLimit,
rlnRelayUserMessageLimit: conf.rlnRelayUserMessageLimit, rlnEpochSizeSec: conf.rlnEpochSizeSec,
rlnEpochSizeSec: conf.rlnEpochSizeSec, onFatalErrorAction: onFatalErrorAction,
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,
)
try: try:
waitFor node.mountRlnRelay(rlnConf) waitFor node.mountRlnRelay(rlnConf)

View File

@ -15,9 +15,7 @@ type
IdentitySecretHash* = seq[byte] #array[32, byte] IdentitySecretHash* = seq[byte] #array[32, byte]
# hash of identity key as defined ed in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership # hash of identity key as defined ed in https://hackmd.io/tMTLMYmTR5eynw2lwK9n1w?view#Membership
IDCommitment* = seq[byte] #array[32, byte] IDCommitment* = seq[byte] #array[32, byte]
UserMessageLimit* = uint64
when defined(rln_v2):
type UserMessageLimit* = uint64
type IdentityCredential* = object type IdentityCredential* = object
idTrapdoor*: IdentityTrapdoor idTrapdoor*: IdentityTrapdoor
@ -103,45 +101,24 @@ type KeystoreMembership* = ref object of RootObj
membershipContract*: MembershipContract membershipContract*: MembershipContract
treeIndex*: MembershipIndex treeIndex*: MembershipIndex
identityCredential*: IdentityCredential identityCredential*: IdentityCredential
when defined(rln_v2): userMessageLimit*: UserMessageLimit
userMessageLimit*: UserMessageLimit
when defined(rln_v2): proc `$`*(m: KeystoreMembership): string =
proc `$`*(m: KeystoreMembership): string = return
return "KeystoreMembership(chainId: " & m.membershipContract.chainId &
"KeystoreMembership(chainId: " & m.membershipContract.chainId & ", contractAddress: " & m.membershipContract.address & ", treeIndex: " &
", contractAddress: " & m.membershipContract.address & ", treeIndex: " & $m.treeIndex & ", userMessageLimit: " & $m.userMessageLimit &
$m.treeIndex & ", userMessageLimit: " & $m.userMessageLimit & ", identityCredential: " & $m.identityCredential & ")"
", identityCredential: " & $m.identityCredential & ")"
else: proc `==`*(x, y: KeystoreMembership): bool =
proc `$`*(m: KeystoreMembership): string = return
return x.membershipContract.chainId == y.membershipContract.chainId and
"KeystoreMembership(chainId: " & m.membershipContract.chainId & x.membershipContract.address == y.membershipContract.address and
", contractAddress: " & m.membershipContract.address & ", treeIndex: " & x.treeIndex == y.treeIndex and x.userMessageLimit == y.userMessageLimit and
$m.treeIndex & ", identityCredential: " & $m.identityCredential & ")" x.identityCredential.idTrapdoor == y.identityCredential.idTrapdoor and
x.identityCredential.idNullifier == y.identityCredential.idNullifier and
when defined(rln_v2): x.identityCredential.idSecretHash == y.identityCredential.idSecretHash and
proc `==`*(x, y: KeystoreMembership): bool = x.identityCredential.idCommitment == y.identityCredential.idCommitment
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
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 hash*(m: KeystoreMembership): string = proc hash*(m: KeystoreMembership): string =
# hash together the chainId, address and treeIndex # hash together the chainId, address and treeIndex

View File

@ -27,14 +27,13 @@ const
const DefaultRlnTreePath* = "rln_tree.db" const DefaultRlnTreePath* = "rln_tree.db"
when defined(rln_v2): const
const # pre-processed "rln/waku-rln-relay/v2.0.0" to array[32, byte]
# pre-processed "rln/waku-rln-relay/v2.0.0" to array[32, byte] DefaultRlnIdentifier*: RlnIdentifier = [
DefaultRlnIdentifier*: RlnIdentifier = [ 114, 108, 110, 47, 119, 97, 107, 117, 45, 114, 108, 110, 45, 114, 101, 108, 97,
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,
121, 47, 118, 50, 46, 48, 46, 48, 0, 0, 0, 0, 0, 0, 0, ]
] DefaultUserMessageLimit* = UserMessageLimit(20)
DefaultUserMessageLimit* = UserMessageLimit(20)
# temporary variables to test waku-rln-relay performance in the static group mode # temporary variables to test waku-rln-relay performance in the static group mode
const const
@ -60048,15 +60047,11 @@ const StaticGroupKeys* =
] ]
# StaticGroupMerkleRoot is the root of the Merkle tree constructed from the StaticGroupKeys above # 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 # 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 # 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* =
const StaticGroupMerkleRoot* = "2c149e48886b5ba3da2edf8db8d7a364ae7a25618489c04cf0c0380f7cdd4d6f"
"2c149e48886b5ba3da2edf8db8d7a364ae7a25618489c04cf0c0380f7cdd4d6f"
else:
const StaticGroupMerkleRoot* =
"1e534adab58f7d300aaeecae57a25e0a0b18c368a09f720280da92b288950901"
const MaxClockGapSeconds* = 20.0 # the maximum clock difference between peers in seconds const MaxClockGapSeconds* = 20.0 # the maximum clock difference between peers in seconds

File diff suppressed because one or more lines are too long

View File

@ -30,9 +30,8 @@ proc inHex*(
valueHex = "0" & valueHex valueHex = "0" & valueHex
return toLowerAscii(valueHex) return toLowerAscii(valueHex)
when defined(rln_v2): proc toUserMessageLimit*(v: UInt256): UserMessageLimit =
proc toUserMessageLimit*(v: UInt256): UserMessageLimit = return cast[UserMessageLimit](v)
return cast[UserMessageLimit](v)
proc encodeLengthPrefix*(input: openArray[byte]): seq[byte] = proc encodeLengthPrefix*(input: openArray[byte]): seq[byte] =
## returns length prefixed version of the input ## returns length prefixed version of the input
@ -56,75 +55,47 @@ proc serialize*(v: uint64): array[32, byte] =
discard output.copyFrom(bytes) discard output.copyFrom(bytes)
return output return output
when defined(rln_v2): proc serialize*(
proc serialize*( idSecretHash: IdentitySecretHash,
idSecretHash: IdentitySecretHash, memIndex: MembershipIndex,
memIndex: MembershipIndex, userMessageLimit: UserMessageLimit,
userMessageLimit: UserMessageLimit, messageId: MessageId,
messageId: MessageId, externalNullifier: ExternalNullifier,
externalNullifier: ExternalNullifier, msg: openArray[byte],
msg: openArray[byte], ): seq[byte] =
): seq[byte] = ## a private proc to convert RateLimitProof and the data to a byte seq
## a private proc to convert RateLimitProof and the data to a byte seq ## this conversion is used in the proofGen proc
## 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
## 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<var> ]
## [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ] let memIndexBytes = toBytes(uint64(memIndex), Endianness.littleEndian)
let memIndexBytes = toBytes(uint64(memIndex), Endianness.littleEndian) let userMessageLimitBytes = userMessageLimit.serialize()
let userMessageLimitBytes = userMessageLimit.serialize() let messageIdBytes = messageId.serialize()
let messageIdBytes = messageId.serialize() let lenPrefMsg = encodeLengthPrefix(msg)
let lenPrefMsg = encodeLengthPrefix(msg) let output = concat(
let output = concat( @idSecretHash,
@idSecretHash, @memIndexBytes,
@memIndexBytes, @userMessageLimitBytes,
@userMessageLimitBytes, @messageIdBytes,
@messageIdBytes, @externalNullifier,
@externalNullifier, lenPrefMsg,
lenPrefMsg, )
) return output
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<var> ]
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] = proc serialize*(proof: RateLimitProof, data: openArray[byte]): seq[byte] =
## a private proc to convert RateLimitProof and data to a byte seq ## a private proc to convert RateLimitProof and data to a byte seq
## this conversion is used in the proof verification proc ## 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<var> ] ## [ proof<128> | root<32> | epoch<32> | share_x<32> | share_y<32> | nullifier<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
let lenPrefMsg = encodeLengthPrefix(@data) let lenPrefMsg = encodeLengthPrefix(@data)
when defined(rln_v2): var proofBytes = concat(
var proofBytes = concat( @(proof.proof),
@(proof.proof), @(proof.merkleRoot),
@(proof.merkleRoot), @(proof.externalNullifier),
@(proof.externalNullifier), @(proof.shareX),
@(proof.shareX), @(proof.shareY),
@(proof.shareY), @(proof.nullifier),
@(proof.nullifier), lenPrefMsg,
lenPrefMsg, )
)
else:
var proofBytes = concat(
@(proof.proof),
@(proof.merkleRoot),
@(proof.epoch),
@(proof.shareX),
@(proof.shareY),
@(proof.nullifier),
@(proof.rlnIdentifier),
lenPrefMsg,
)
return proofBytes return proofBytes

View File

@ -15,10 +15,7 @@ export options, chronos, results, protocol_types, protocol_metrics, deques
type Membership* = object type Membership* = object
index*: MembershipIndex index*: MembershipIndex
when defined(rln_v2): rateCommitment*: RawRateCommitment
rateCommitment*: RateCommitment
else:
idCommitment*: IDCommitment
type OnRegisterCallback* = proc(registrations: seq[Membership]): Future[void] {.gcsafe.} type OnRegisterCallback* = proc(registrations: seq[Membership]): Future[void] {.gcsafe.}
type OnWithdrawCallback* = proc(withdrawals: 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 latestIndex*: MembershipIndex
validRoots*: Deque[MerkleNode] validRoots*: Deque[MerkleNode]
onFatalErrorAction*: OnFatalErrorHandler onFatalErrorAction*: OnFatalErrorHandler
when defined(rln_v2): userMessageLimit*: Option[UserMessageLimit]
userMessageLimit*: Option[UserMessageLimit]
# This proc is used to initialize the group manager # This proc is used to initialize the group manager
# Any initialization logic should be implemented here # 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 # 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 # 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 # It should be used when detecting new members in the group, and syncing the group state
when defined(rln_v2): method register*(
method register*( g: GroupManager, rateCommitment: RateCommitment
g: GroupManager, rateCommitment: RateCommitment ): Future[void] {.base, async: (raises: [Exception]).} =
): Future[void] {.base, async: (raises: [Exception]).} = raise newException(
raise newException( CatchableError, "register proc for " & $g.type & " is not implemented yet"
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"
)
# This proc is used to register a new identity commitment into the merkle tree # This proc is used to register a new identity commitment into the merkle tree
# The user should have the identity secret to this commitment # The user should have the identity secret to this commitment
# It should be used when the user wants to join the group # It should be used when the user wants to join the group
when defined(rln_v2): method register*(
method register*( g: GroupManager,
g: GroupManager, credentials: IdentityCredential,
credentials: IdentityCredential, userMessageLimit: UserMessageLimit,
userMessageLimit: UserMessageLimit, ): Future[void] {.base, async: (raises: [Exception]).} =
): Future[void] {.base, async: (raises: [Exception]).} = raise newException(
raise newException( CatchableError, "register proc for " & $g.type & " is not implemented yet"
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 # 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 # 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 # 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*(
method registerBatch*( g: GroupManager, rateCommitments: seq[RawRateCommitment]
g: GroupManager, rateCommitments: seq[RateCommitment] ): Future[void] {.base, async: (raises: [Exception]).} =
): Future[void] {.base, async: (raises: [Exception]).} = raise newException(
raise newException( CatchableError, "registerBatch proc for " & $g.type & " is not implemented yet"
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"
)
# This proc is used to set a callback that will be called when a new identity commitment is registered # 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 # 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 # This proc is used to insert and remove a set of commitments from the merkle tree
when defined(rln_v2): method atomicBatch*(
method atomicBatch*( g: GroupManager,
g: GroupManager, rateCommitments: seq[RateCommitment],
rateCommitments: seq[RateCommitment], toRemoveIndices: seq[MembershipIndex],
toRemoveIndices: seq[MembershipIndex], ): Future[void] {.base, async: (raises: [Exception]).} =
): Future[void] {.base, async: (raises: [Exception]).} = raise newException(
raise newException( CatchableError, "atomicBatch proc for " & $g.type & " is not implemented yet"
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.} = method stop*(g: GroupManager): Future[void] {.base, async.} =
raise raise
@ -216,55 +176,34 @@ method verifyProof*(
return err("proof verification failed: " & $proofVerifyRes.error()) return err("proof verification failed: " & $proofVerifyRes.error())
return ok(proofVerifyRes.value()) return ok(proofVerifyRes.value())
when defined(rln_v2): method generateProof*(
method generateProof*( g: GroupManager,
g: GroupManager, data: openArray[byte],
data: openArray[byte], epoch: Epoch,
epoch: Epoch, messageId: MessageId,
messageId: MessageId, rlnIdentifier = DefaultRlnIdentifier,
rlnIdentifier = DefaultRlnIdentifier, ): GroupManagerResult[RateLimitProof] {.base, gcsafe, raises: [].} =
): GroupManagerResult[RateLimitProof] {.base, gcsafe, raises: [].} = ## generates a proof for the given data and epoch
## generates a proof for the given data and epoch ## the proof is generated using the current merkle root
## the proof is generated using the current merkle root if g.idCredentials.isNone():
if g.idCredentials.isNone(): return err("identity credentials are not set")
return err("identity credentials are not set") if g.membershipIndex.isNone():
if g.membershipIndex.isNone(): return err("membership index is not set")
return err("membership index is not set") if g.userMessageLimit.isNone():
if g.userMessageLimit.isNone(): return err("user message limit is not set")
return err("user message limit is not set") waku_rln_proof_generation_duration_seconds.nanosecondTime:
waku_rln_proof_generation_duration_seconds.nanosecondTime: let proof = proofGen(
let proof = proofGen( rlnInstance = g.rlnInstance,
rlnInstance = g.rlnInstance, data = data,
data = data, membership = g.idCredentials.get(),
membership = g.idCredentials.get(), index = g.membershipIndex.get(),
index = g.membershipIndex.get(), epoch = epoch,
epoch = epoch, userMessageLimit = g.userMessageLimit.get(),
userMessageLimit = g.userMessageLimit.get(), messageId = messageId,
messageId = messageId, ).valueOr:
).valueOr: return err("proof generation failed: " & $error)
return err("proof generation failed: " & $error) return ok(proof)
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.} = method isReady*(g: GroupManager): Future[bool] {.base, async.} =
raise newException( raise newException(

View File

@ -31,74 +31,34 @@ logScope:
topics = "waku rln_relay onchain_group_manager" topics = "waku rln_relay onchain_group_manager"
# using the when predicate does not work within the contract macro, hence need to dupe # using the when predicate does not work within the contract macro, hence need to dupe
when defined(rln_v2): contract(WakuRlnContract):
contract(WakuRlnRegistry): # this serves as an entrypoint into the rln membership set
# this describes the storage slot to use proc register(
proc usingStorageIndex(): Uint16 {.pure.} idCommitment: UInt256, userMessageLimit: UInt32
# this map contains the address of a given storage slot )
proc storages(index: Uint16): Address {.pure.} # Initializes the implementation contract (only used in unit tests)
# this serves as an entrypoint into the rln storage contract proc initialize(maxMessageLimit: UInt256)
proc register( # this event is raised when a new member is registered
storageIndex: Uint16, idCommitment: Uint256, userMessageLimit: Uint256 proc MemberRegistered(
) rateCommitment: UInt256, index: Uint32
) {.event.}
# this creates a new storage on the rln registry # this function denotes existence of a given user
proc newStorage(maxMessageLimit: Uint256) proc memberExists(idCommitment: Uint256): UInt256 {.view.}
# Initializes the implementation contract (only used in unit tests) # this constant describes the next index of a new member
proc initialize() proc commitmentIndex(): UInt256 {.view.}
# this constant describes the block number this contract was deployed on
# membership contract interface proc deployedBlockNumber(): UInt256 {.view.}
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.}
type type
RegistryContractWithSender = Sender[WakuRlnRegistry] WakuRlnContractWithSender = Sender[WakuRlnContract]
RlnContractWithSender = Sender[RlnStorage]
OnchainGroupManager* = ref object of GroupManager OnchainGroupManager* = ref object of GroupManager
ethClientUrl*: string ethClientUrl*: string
ethPrivateKey*: Option[string] ethPrivateKey*: Option[string]
ethContractAddress*: string ethContractAddress*: string
ethRpc*: Option[Web3] ethRpc*: Option[Web3]
rlnContract*: Option[RlnContractWithSender]
rlnContractDeployedBlockNumber*: BlockNumber rlnContractDeployedBlockNumber*: BlockNumber
registryContract*: Option[RegistryContractWithSender] wakuRlnContract*: Option[WakuRlnContractWithSender]
usingStorageIndex: Option[Uint16]
membershipFee*: Option[Uint256]
latestProcessedBlock*: BlockNumber latestProcessedBlock*: BlockNumber
registrationTxHash*: Option[TxHash] registrationTxHash*: Option[TxHash]
chainId*: Option[Quantity] chainId*: Option[Quantity]
@ -157,212 +117,109 @@ proc setMetadata*(
return err("failed to persist rln metadata: " & getCurrentExceptionMsg()) return err("failed to persist rln metadata: " & getCurrentExceptionMsg())
return ok() return ok()
when defined(rln_v2): method atomicBatch*(
method atomicBatch*( g: OnchainGroupManager,
g: OnchainGroupManager, start: MembershipIndex,
start: MembershipIndex, rateCommitments = newSeq[RawRateCommitment](),
rateCommitments = newSeq[RateCommitment](), toRemoveIndices = newSeq[MembershipIndex](),
toRemoveIndices = newSeq[MembershipIndex](), ): Future[void] {.async: (raises: [Exception]), base.} =
): Future[void] {.async: (raises: [Exception]), base.} = initializedGuard(g)
initializedGuard(g)
# convert the rateCommitment struct to a leaf value waku_rln_membership_insertion_duration_seconds.nanosecondTime:
let leaves = rateCommitments.toLeaves().valueOr: let operationSuccess =
raise newException( g.rlnInstance.atomicWrite(some(start), rateCommitments, toRemoveIndices)
ValueError, "failed to convert rateCommitments to leaves: " & $error 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()))
waku_rln_membership_insertion_duration_seconds.nanosecondTime: if g.registerCb.isSome():
let operationSuccess = var membersSeq = newSeq[Membership]()
g.rlnInstance.atomicWrite(some(start), leaves, toRemoveIndices) for i in 0 ..< rateCommitments.len:
if not operationSuccess: var index = start + MembershipIndex(i)
raise newException(CatchableError, "atomic batch operation failed") debug "registering member to callback", rateCommitment = rateCommitments[i], index = index
# TODO: when slashing is enabled, we need to track slashed members let member = Membership(rateCommitment: rateCommitments[i], index: index)
waku_rln_number_registered_memberships.set(int64(g.rlnInstance.leavesSet())) membersSeq.add(member)
await g.registerCb.get()(membersSeq)
if g.registerCb.isSome(): g.validRootBuffer = g.slideRootQueue()
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() method register*(
g: OnchainGroupManager, rateCommitment: RateCommitment
): Future[void] {.async: (raises: [Exception]).} =
initializedGuard(g)
else: try:
method atomicBatch*( let leaf = rateCommitment.toLeaf().get()
g: OnchainGroupManager, await g.registerBatch(@[leaf])
start: MembershipIndex, except CatchableError:
idCommitments = newSeq[IDCommitment](), raise newException(ValueError, getCurrentExceptionMsg())
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(): method registerBatch*(
var membersSeq = newSeq[Membership]() g: OnchainGroupManager, rateCommitments: seq[RawRateCommitment]
for i in 0 ..< idCommitments.len: ): Future[void] {.async: (raises: [Exception]).} =
var index = start + MembershipIndex(i) initializedGuard(g)
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() await g.atomicBatch(g.latestIndex, rateCommitments)
g.latestIndex += MembershipIndex(rateCommitments.len)
when defined(rln_v2): method register*(
method register*( g: OnchainGroupManager,
g: OnchainGroupManager, rateCommitment: RateCommitment identityCredential: IdentityCredential,
): Future[void] {.async: (raises: [Exception]).} = userMessageLimit: UserMessageLimit,
initializedGuard(g) ): Future[void] {.async: (raises: [Exception]).} =
initializedGuard(g)
await g.registerBatch(@[rateCommitment]) let ethRpc = g.ethRpc.get()
let wakuRlnContract = g.wakuRlnContract.get()
else: var gasPrice: int
method register*( g.retryWrapper(gasPrice, "Failed to get gas price"):
g: OnchainGroupManager, idCommitment: IDCommitment int(await ethRpc.provider.eth_gasPrice()) * 2
): Future[void] {.async: (raises: [Exception]).} = let idCommitment = identityCredential.idCommitment.toUInt256()
initializedGuard(g)
await g.registerBatch(@[idCommitment]) 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)
when defined(rln_v2): # wait for the transaction to be mined
method registerBatch*( var tsReceipt: ReceiptObject
g: OnchainGroupManager, rateCommitments: seq[RateCommitment] g.retryWrapper(tsReceipt, "Failed to get the transaction receipt"):
): Future[void] {.async: (raises: [Exception]).} = await ethRpc.getMinedTransactionReceipt(txHash)
initializedGuard(g) 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")
await g.atomicBatch(g.latestIndex, rateCommitments) # the arguments of the raised event i.e., MemberRegistered are encoded inside the data field
g.latestIndex += MembershipIndex(rateCommitments.len) # 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])
else: debug "parsed membershipIndex", membershipIndex
method registerBatch*( g.userMessageLimit = some(userMessageLimit)
g: OnchainGroupManager, idCommitments: seq[IDCommitment] g.membershipIndex = some(membershipIndex.toMembershipIndex())
): Future[void] {.async: (raises: [Exception]).} =
initializedGuard(g)
await g.atomicBatch(g.latestIndex, idCommitments) # don't handle member insertion into the tree here, it will be handled by the event listener
g.latestIndex += MembershipIndex(idCommitments.len) return
when defined(rln_v2):
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 = 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
else:
method register*(
g: OnchainGroupManager, credentials: IdentityCredential
): 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
)
# 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*( method withdraw*(
g: OnchainGroupManager, idCommitment: IDCommitment g: OnchainGroupManager, idCommitment: IDCommitment
@ -381,10 +238,8 @@ proc parseEvent(
): GroupManagerResult[Membership] = ): GroupManagerResult[Membership] =
## parses the `data` parameter of the `MemberRegistered` event `log` ## parses the `data` parameter of the `MemberRegistered` event `log`
## returns an error if it cannot parse the `data` parameter ## returns an error if it cannot parse the `data` parameter
var idComm: UInt256 var rateCommitment: UInt256
var index: UInt256 var index: UInt256
when defined(rln_v2):
var userMessageLimit: UInt256
var data: string var data: string
# Remove the 0x prefix # Remove the 0x prefix
try: try:
@ -396,29 +251,17 @@ proc parseEvent(
) )
var offset = 0 var offset = 0
try: try:
# Parse the idComm # Parse the rateCommitment
offset += decode(data, offset, idComm) offset += decode(data, offset, rateCommitment)
when defined(rln_v2):
# Parse the userMessageLimit
offset += decode(data, offset, userMessageLimit)
# Parse the index # Parse the index
offset += decode(data, offset, index) offset += decode(data, offset, index)
when defined(rln_v2): return ok(
return ok( Membership(
Membership( rateCommitment: rateCommitment.toRateCommitment(),
rateCommitment: RateCommitment( index: index.toMembershipIndex(),
idCommitment: idComm.toIDCommitment(),
userMessageLimit: userMessageLimit.toUserMessageLimit(),
),
index: index.toMembershipIndex(),
)
)
else:
return ok(
Membership(
idCommitment: idComm.toIDCommitment(), index: index.toMembershipIndex()
)
) )
)
except CatchableError: except CatchableError:
return err("failed to parse the data field of the MemberRegistered event") return err("failed to parse the data field of the MemberRegistered event")
@ -456,11 +299,11 @@ proc getRawEvents(
initializedGuard(g) initializedGuard(g)
let ethRpc = g.ethRpc.get() let ethRpc = g.ethRpc.get()
let rlnContract = g.rlnContract.get() let wakuRlnContract = g.wakuRlnContract.get()
var events: JsonNode var events: JsonNode
g.retryWrapper(events, "Failed to get the events"): g.retryWrapper(events, "Failed to get the events"):
await rlnContract.getJsonLogs( await wakuRlnContract.getJsonLogs(
MemberRegistered, MemberRegistered,
fromBlock = some(fromBlock.blockId()), fromBlock = some(fromBlock.blockId()),
toBlock = some(toBlock.blockId()), toBlock = some(toBlock.blockId()),
@ -501,24 +344,15 @@ proc handleEvents(
try: try:
let startIndex = blockTable[blockNumber].filterIt(not it[1])[0][0].index let startIndex = blockTable[blockNumber].filterIt(not it[1])[0][0].index
let removalIndices = members.filterIt(it[1]).mapIt(it[0].index) let removalIndices = members.filterIt(it[1]).mapIt(it[0].index)
when defined(rln_v2): let rateCommitments = members.mapIt(it[0].rateCommitment)
let rateCommitments = members.mapIt(it[0].rateCommitment) await g.atomicBatch(
await g.atomicBatch( start = startIndex,
start = startIndex, rateCommitments = rateCommitments,
rateCommitments = rateCommitments, toRemoveIndices = removalIndices,
toRemoveIndices = removalIndices, )
) g.latestIndex = startIndex + MembershipIndex(rateCommitments.len)
g.latestIndex = startIndex + MembershipIndex(rateCommitments.len) trace "new members added to the Merkle tree", commitments = rateCommitments.mapIt(it.inHex)
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
except CatchableError: except CatchableError:
error "failed to insert members into the tree", error = getCurrentExceptionMsg() error "failed to insert members into the tree", error = getCurrentExceptionMsg()
raise newException(ValueError, "failed to insert members into the tree") 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.defaultAccount =
ethRpc.privateKey.get().toPublicKey().toCanonicalAddress().Address ethRpc.privateKey.get().toPublicKey().toCanonicalAddress().Address
let registryAddress = web3.fromHex(web3.Address, g.ethContractAddress) let contractAddress = web3.fromHex(web3.Address, g.ethContractAddress)
let registryContract = ethRpc.contractSender(WakuRlnRegistry, registryAddress) let wakuRlnContract = ethRpc.contractSender(WakuRlnContract, contractAddress)
# 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)
g.ethRpc = some(ethRpc) g.ethRpc = some(ethRpc)
g.rlnContract = some(rlnContract) g.wakuRlnContract = some(wakuRlnContract)
g.registryContract = some(registryContract)
if g.keystorePath.isSome() and g.keystorePassword.isSome(): if g.keystorePath.isSome() and g.keystorePassword.isSome():
if not fileExists(g.keystorePath.get()): 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) return err("failed to get the keystore credentials: " & $error)
g.membershipIndex = some(keystoreCred.treeIndex) 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 # now we check on the contract if the commitment actually has a membership
try: try:
let membershipExists = await rlnContract let membershipExists = await wakuRlnContract
.memberExists(keystoreCred.identityCredential.idCommitment.toUInt256()) .memberExists(keystoreCred.identityCredential.idCommitment.toUInt256())
.call() .call()
if membershipExists == 0: if membershipExists == 0:
@ -786,16 +607,10 @@ method init*(g: OnchainGroupManager): Future[GroupManagerResult[void]] {.async.}
g.latestProcessedBlock = metadata.lastProcessedBlock g.latestProcessedBlock = metadata.lastProcessedBlock
g.validRoots = metadata.validRoots.toDeque() 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 var deployedBlockNumber: Uint256
g.retryWrapper(deployedBlockNumber, "Failed to get the deployed block number"): g.retryWrapper(deployedBlockNumber, "Failed to get the deployed block number"):
await rlnContract.deployedBlockNumber().call() await wakuRlnContract.deployedBlockNumber().call()
debug "using rln storage", deployedBlockNumber, rlnContractAddress debug "using rln contract", deployedBlockNumber, rlnContractAddress = contractAddress
g.rlnContractDeployedBlockNumber = cast[BlockNumber](deployedBlockNumber) g.rlnContractDeployedBlockNumber = cast[BlockNumber](deployedBlockNumber)
g.latestProcessedBlock = max(g.latestProcessedBlock, g.rlnContractDeployedBlockNumber) g.latestProcessedBlock = max(g.latestProcessedBlock, g.rlnContractDeployedBlockNumber)

View File

@ -33,25 +33,18 @@ method init*(g: StaticGroupManager): Future[GroupManagerResult[void]] {.async.}
"Invalid membership index. Must be within 0 and " & $(groupSize - 1) & "but was " & "Invalid membership index. Must be within 0 and " & $(groupSize - 1) & "but was " &
$membershipIndex $membershipIndex
) )
when defined(rln_v2): g.userMessageLimit = some(DefaultUserMessageLimit)
g.userMessageLimit = some(DefaultUserMessageLimit)
g.idCredentials = some(groupKeys[membershipIndex]) g.idCredentials = some(groupKeys[membershipIndex])
# Seed the received commitments into the merkle tree # Seed the received commitments into the merkle tree
when defined(rln_v2): let rateCommitments = groupKeys.mapIt(
let rateCommitments = groupKeys.mapIt( RateCommitment(
RateCommitment( idCommitment: it.idCommitment, userMessageLimit: g.userMessageLimit.get()
idCommitment: it.idCommitment, userMessageLimit: g.userMessageLimit.get()
)
) )
let leaves = rateCommitments.toLeaves().valueOr: )
return err("Failed to convert rate commitments to leaves: " & $error) let leaves = rateCommitments.toLeaves().valueOr:
let membersInserted = g.rlnInstance.insertMembers(g.latestIndex, leaves) return err("Failed to convert rate commitments to leaves: " & $error)
else: let membersInserted = g.rlnInstance.insertMembers(g.latestIndex, leaves)
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")
discard g.slideRootQueue() discard g.slideRootQueue()
@ -68,127 +61,65 @@ method startGroupSync*(
# No-op # No-op
return ok() return ok()
when defined(rln_v2): method register*(
method register*( g: StaticGroupManager, rateCommitment: RateCommitment
g: StaticGroupManager, rateCommitment: RateCommitment ): Future[void] {.async: (raises: [Exception]).} =
): Future[void] {.async: (raises: [Exception]).} = initializedGuard(g)
initializedGuard(g)
await g.registerBatch(@[rateCommitment]) let leaf = rateCommitment.toLeaf().get()
else: await g.registerBatch(@[leaf])
method register*(
g: StaticGroupManager, idCommitment: IDCommitment
): Future[void] {.async: (raises: [Exception]).} =
initializedGuard(g)
await g.registerBatch(@[idCommitment])
when defined(rln_v2): method registerBatch*(
method registerBatch*( g: StaticGroupManager, rateCommitments: seq[RawRateCommitment]
g: StaticGroupManager, rateCommitments: seq[RateCommitment] ): Future[void] {.async: (raises: [Exception]).} =
): Future[void] {.async: (raises: [Exception]).} = initializedGuard(g)
initializedGuard(g)
let leavesRes = rateCommitments.toLeaves() let membersInserted = g.rlnInstance.insertMembers(g.latestIndex + 1, rateCommitments)
if not leavesRes.isOk(): if not membersInserted:
raise newException(ValueError, "Failed to convert rate commitments to leaves") raise newException(ValueError, "Failed to insert members into the merkle tree")
let leaves = cast[seq[seq[byte]]](leavesRes.get())
let membersInserted = g.rlnInstance.insertMembers(g.latestIndex + 1, leaves) if g.registerCb.isSome():
if not membersInserted: var memberSeq = newSeq[Membership]()
raise newException(ValueError, "Failed to insert members into the merkle tree") for i in 0 ..< rateCommitments.len:
memberSeq.add(
if g.registerCb.isSome(): Membership(
var memberSeq = newSeq[Membership]() rateCommitment: rateCommitments[i],
for i in 0 ..< rateCommitments.len: index: g.latestIndex + MembershipIndex(i) + 1,
memberSeq.add(
Membership(
rateCommitment: rateCommitments[i],
index: g.latestIndex + MembershipIndex(i) + 1,
)
) )
await g.registerCb.get()(memberSeq) )
await g.registerCb.get()(memberSeq)
discard g.slideRootQueue() discard g.slideRootQueue()
g.latestIndex += MembershipIndex(rateCommitments.len) g.latestIndex += MembershipIndex(rateCommitments.len)
return
return method withdraw*(
g: StaticGroupManager, idSecretHash: IdentitySecretHash
): Future[void] {.async: (raises: [Exception]).} =
initializedGuard(g)
else: let groupKeys = g.groupKeys
method registerBatch*(
g: StaticGroupManager, idCommitments: seq[IDCommitment]
): Future[void] {.async: (raises: [Exception]).} =
initializedGuard(g)
let membersInserted = g.rlnInstance.insertMembers(g.latestIndex + 1, idCommitments) for i in 0 ..< groupKeys.len:
if not membersInserted: if groupKeys[i].idSecretHash == idSecretHash:
raise newException(ValueError, "Failed to insert members into the merkle tree") 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.registerCb.isSome(): if g.withdrawCb.isSome():
var memberSeq = newSeq[Membership]() let withdrawCb = g.withdrawCb.get()
for i in 0 ..< idCommitments.len: await withdrawCb(@[Membership(rateCommitment: rateCommitment, index: index)])
memberSeq.add(
Membership(
idCommitment: idCommitments[i],
index: g.latestIndex + MembershipIndex(i) + 1,
)
)
await g.registerCb.get()(memberSeq)
discard g.slideRootQueue() return
g.latestIndex += MembershipIndex(idCommitments.len)
return
when defined(rln_v2):
method withdraw*(
g: StaticGroupManager, idSecretHash: IdentitySecretHash
): Future[void] {.async: (raises: [Exception]).} =
initializedGuard(g)
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()
)
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)
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 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(idCommitment: idCommitment, index: index)]))
return
method withdrawBatch*( method withdrawBatch*(
g: StaticGroupManager, idSecretHashes: seq[IdentitySecretHash] g: StaticGroupManager, idSecretHashes: seq[IdentitySecretHash]

View File

@ -45,12 +45,13 @@ proc getNonce*(n: NonceManager): NonceManagerResult[Nonce] =
if now - n.lastNonceTime >= n.epoch: if now - n.lastNonceTime >= n.epoch:
retNonce = 0 retNonce = 0
n.lastNonceTime = now
n.nextNonce = retNonce + 1 n.nextNonce = retNonce + 1
n.lastNonceTime = now
if retNonce >= n.nonceLimit: if retNonce >= n.nonceLimit:
return err( return err(
NonceManagerError( NonceManagerError(
kind: NonceLimitReached, kind: NonceLimitReached,
error: error:
"Nonce limit reached. Please wait for the next epoch. requested nonce: " & "Nonce limit reached. Please wait for the next epoch. requested nonce: " &

View File

@ -3,7 +3,7 @@ when (NimMajor, NimMinor) < (1, 4):
else: else:
{.push raises: [].} {.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 import ../waku_core, ../waku_keystore, ../common/protobuf
export waku_keystore, waku_core export waku_keystore, waku_core
@ -16,20 +16,20 @@ type RLNResult* = RlnRelayResult[ptr RLN]
type type
MerkleNode* = array[32, byte] 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] Nullifier* = array[32, byte]
Epoch* = array[32, byte] Epoch* = array[32, byte]
RlnIdentifier* = array[32, byte] RlnIdentifier* = array[32, byte]
ZKSNARK* = array[128, byte] ZKSNARK* = array[128, byte]
MessageId* = uint64
when defined(rln_v2): ExternalNullifier* = array[32, byte]
type RateCommitment* = object
MessageId* = uint64
ExternalNullifier* = array[32, byte]
type RateCommitment* = object
idCommitment*: IDCommitment idCommitment*: IDCommitment
userMessageLimit*: UserMessageLimit userMessageLimit*: UserMessageLimit
RawRateCommitment* = seq[byte]
proc toRateCommitment*(rateCommitmentUint: UInt256): RawRateCommitment =
return RawRateCommitment(@(rateCommitmentUint.toBytesLE()))
# Custom data types defined for waku rln relay ------------------------- # Custom data types defined for waku rln relay -------------------------
type RateLimitProof* = object type RateLimitProof* = object
@ -51,9 +51,8 @@ type RateLimitProof* = object
epoch*: Epoch epoch*: Epoch
## Application specific RLN Identifier ## Application specific RLN Identifier
rlnIdentifier*: RlnIdentifier rlnIdentifier*: RlnIdentifier
when defined(rln_v2): ## the external nullifier used for the generation of the `proof` (derived from poseidon([epoch, rln_identifier]))
## the external nullifier used for the generation of the `proof` (derived from poseidon([epoch, rln_identifier])) externalNullifier*: ExternalNullifier
externalNullifier*: ExternalNullifier
type ProofMetadata* = object type ProofMetadata* = object
nullifier*: Nullifier nullifier*: Nullifier

View File

@ -161,32 +161,31 @@ proc poseidon*(data: seq[seq[byte]]): RlnRelayResult[array[32, byte]] =
return ok(output) return ok(output)
when defined(rln_v2): proc toLeaf*(rateCommitment: RateCommitment): RlnRelayResult[seq[byte]] =
proc toLeaf*(rateCommitment: RateCommitment): RlnRelayResult[seq[byte]] = let idCommitment = rateCommitment.idCommitment
let idCommitment = rateCommitment.idCommitment var userMessageLimit: array[32, byte]
var userMessageLimit: array[32, byte] try:
try: discard userMessageLimit.copyFrom(
discard userMessageLimit.copyFrom( toBytes(rateCommitment.userMessageLimit, Endianness.littleEndian)
toBytes(rateCommitment.userMessageLimit, Endianness.littleEndian) )
) except CatchableError:
except CatchableError: return err(
return err( "could not convert the user message limit to bytes: " & getCurrentExceptionMsg()
"could not convert the user message limit to bytes: " & getCurrentExceptionMsg() )
) let leaf = poseidon(@[@idCommitment, @userMessageLimit]).valueOr:
let leaf = poseidon(@[@idCommitment, @userMessageLimit]).valueOr: return err("could not convert the rate commitment to a leaf")
return err("could not convert the rate commitment to a leaf") var retLeaf = newSeq[byte](leaf.len)
var retLeaf = newSeq[byte](leaf.len) for i in 0 ..< leaf.len:
for i in 0 ..< leaf.len: retLeaf[i] = leaf[i]
retLeaf[i] = leaf[i] return ok(retLeaf)
return ok(retLeaf)
proc toLeaves*(rateCommitments: seq[RateCommitment]): RlnRelayResult[seq[seq[byte]]] = proc toLeaves*(rateCommitments: seq[RateCommitment]): RlnRelayResult[seq[seq[byte]]] =
var leaves = newSeq[seq[byte]]() var leaves = newSeq[seq[byte]]()
for rateCommitment in rateCommitments: for rateCommitment in rateCommitments:
let leaf = toLeaf(rateCommitment).valueOr: let leaf = toLeaf(rateCommitment).valueOr:
return err("could not convert the rate commitment to a leaf: " & $error) return err("could not convert the rate commitment to a leaf: " & $error)
leaves.add(leaf) leaves.add(leaf)
return ok(leaves) return ok(leaves)
proc extractMetadata*(proof: RateLimitProof): RlnRelayResult[ProofMetadata] = proc extractMetadata*(proof: RateLimitProof): RlnRelayResult[ProofMetadata] =
let externalNullifier = poseidon(@[@(proof.epoch), @(proof.rlnIdentifier)]).valueOr: let externalNullifier = poseidon(@[@(proof.epoch), @(proof.rlnIdentifier)]).valueOr:
@ -200,151 +199,81 @@ proc extractMetadata*(proof: RateLimitProof): RlnRelayResult[ProofMetadata] =
) )
) )
when defined(rln_v2): proc proofGen*(
proc proofGen*( rlnInstance: ptr RLN,
rlnInstance: ptr RLN, data: openArray[byte],
data: openArray[byte], membership: IdentityCredential,
membership: IdentityCredential, userMessageLimit: UserMessageLimit,
userMessageLimit: UserMessageLimit, messageId: MessageId,
messageId: MessageId, index: MembershipIndex,
index: MembershipIndex, epoch: Epoch,
epoch: Epoch, rlnIdentifier = DefaultRlnIdentifier,
rlnIdentifier = DefaultRlnIdentifier, ): RateLimitProofResult =
): RateLimitProofResult = # obtain the external nullifier
# obtain the external nullifier let externalNullifierRes = poseidon(@[@(epoch), @(rlnIdentifier)])
let externalNullifierRes = poseidon(@[@(epoch), @(rlnIdentifier)])
if externalNullifierRes.isErr(): if externalNullifierRes.isErr():
return err("could not construct the external nullifier") return err("could not construct the external nullifier")
# serialize inputs # serialize inputs
let serializedInputs = serialize( let serializedInputs = serialize(
idSecretHash = membership.idSecretHash, idSecretHash = membership.idSecretHash,
memIndex = index, memIndex = index,
userMessageLimit = userMessageLimit, userMessageLimit = userMessageLimit,
messageId = messageId, messageId = messageId,
externalNullifier = externalNullifierRes.get(), externalNullifier = externalNullifierRes.get(),
msg = data, msg = data,
) )
var inputBuffer = toBuffer(serializedInputs) var inputBuffer = toBuffer(serializedInputs)
debug "input buffer ", inputBuffer = repr(inputBuffer) debug "input buffer ", inputBuffer = repr(inputBuffer)
# generate the proof # generate the proof
var proof: Buffer var proof: Buffer
let proofIsSuccessful = generate_proof(rlnInstance, addr inputBuffer, addr proof) let proofIsSuccessful = generate_proof(rlnInstance, addr inputBuffer, addr proof)
# check whether the generate_proof call is done successfully # check whether the generate_proof call is done successfully
if not proofIsSuccessful: if not proofIsSuccessful:
return err("could not generate the proof") return err("could not generate the proof")
var proofValue = cast[ptr array[320, byte]](proof.`ptr`) var proofValue = cast[ptr array[320, byte]](proof.`ptr`)
let proofBytes: array[320, byte] = proofValue[] let proofBytes: array[320, byte] = proofValue[]
debug "proof content", proofHex = proofValue[].toHex 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> ] ## parse the proof as [ proof<128> | root<32> | external_nullifier<32> | share_x<32> | share_y<32> | nullifier<32> ]
let let
proofOffset = 128 proofOffset = 128
rootOffset = proofOffset + 32 rootOffset = proofOffset + 32
externalNullifierOffset = rootOffset + 32 externalNullifierOffset = rootOffset + 32
shareXOffset = externalNullifierOffset + 32 shareXOffset = externalNullifierOffset + 32
shareYOffset = shareXOffset + 32 shareYOffset = shareXOffset + 32
nullifierOffset = shareYOffset + 32 nullifierOffset = shareYOffset + 32
var var
zkproof: ZKSNARK zkproof: ZKSNARK
proofRoot, shareX, shareY: MerkleNode proofRoot, shareX, shareY: MerkleNode
externalNullifier: ExternalNullifier externalNullifier: ExternalNullifier
nullifier: Nullifier nullifier: Nullifier
discard zkproof.copyFrom(proofBytes[0 .. proofOffset - 1]) discard zkproof.copyFrom(proofBytes[0 .. proofOffset - 1])
discard proofRoot.copyFrom(proofBytes[proofOffset .. rootOffset - 1]) discard proofRoot.copyFrom(proofBytes[proofOffset .. rootOffset - 1])
discard discard
externalNullifier.copyFrom(proofBytes[rootOffset .. externalNullifierOffset - 1]) externalNullifier.copyFrom(proofBytes[rootOffset .. externalNullifierOffset - 1])
discard shareX.copyFrom(proofBytes[externalNullifierOffset .. shareXOffset - 1]) discard shareX.copyFrom(proofBytes[externalNullifierOffset .. shareXOffset - 1])
discard shareY.copyFrom(proofBytes[shareXOffset .. shareYOffset - 1]) discard shareY.copyFrom(proofBytes[shareXOffset .. shareYOffset - 1])
discard nullifier.copyFrom(proofBytes[shareYOffset .. nullifierOffset - 1]) discard nullifier.copyFrom(proofBytes[shareYOffset .. nullifierOffset - 1])
let output = RateLimitProof( let output = RateLimitProof(
proof: zkproof, proof: zkproof,
merkleRoot: proofRoot, merkleRoot: proofRoot,
externalNullifier: externalNullifier, externalNullifier: externalNullifier,
epoch: epoch, epoch: epoch,
rlnIdentifier: rlnIdentifier, rlnIdentifier: rlnIdentifier,
shareX: shareX, shareX: shareX,
shareY: shareY, shareY: shareY,
nullifier: nullifier, nullifier: nullifier,
) )
return ok(output) 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,
)
return ok(output)
# validRoots should contain a sequence of roots in the acceptable windows. # 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 # 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 ## verifies the proof, returns an error if the proof verification fails
## returns true if the proof is valid ## returns true if the proof is valid
var normalizedProof = proof var normalizedProof = proof
when defined(rln_v2): # when we do this, we ensure that we compute the proof for the derived value
# 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
# of the externalNullifier. The proof verification will fail if a malicious peer # attaches invalid epoch+rlnidentifier pair
# attaches invalid epoch+rlnidentifier pair normalizedProof.externalNullifier = poseidon(
normalizedProof.externalNullifier = poseidon( @[@(proof.epoch), @(proof.rlnIdentifier)]
@[@(proof.epoch), @(proof.rlnIdentifier)] ).valueOr:
).valueOr: return err("could not construct the external nullifier")
return err("could not construct the external nullifier")
var var
proofBytes = serialize(normalizedProof, data) proofBytes = serialize(normalizedProof, data)
proofBuffer = proofBytes.toBuffer() proofBuffer = proofBytes.toBuffer()

View File

@ -23,10 +23,8 @@ import
./conversion_utils, ./conversion_utils,
./constants, ./constants,
./protocol_types, ./protocol_types,
./protocol_metrics ./protocol_metrics,
./nonce_manager
when defined(rln_v2):
import ./nonce_manager
import import
../common/error_handling, ../common/error_handling,
@ -47,8 +45,7 @@ type WakuRlnConfig* = object
rlnRelayTreePath*: string rlnRelayTreePath*: string
rlnEpochSizeSec*: uint64 rlnEpochSizeSec*: uint64
onFatalErrorAction*: OnFatalErrorHandler onFatalErrorAction*: OnFatalErrorHandler
when defined(rln_v2): rlnRelayUserMessageLimit*: uint64
rlnRelayUserMessageLimit*: uint64
proc createMembershipList*( proc createMembershipList*(
rln: ptr RLN, n: int rln: ptr RLN, n: int
@ -93,8 +90,7 @@ type WakuRLNRelay* = ref object of RootObj
rlnMaxEpochGap*: uint64 rlnMaxEpochGap*: uint64
groupManager*: GroupManager groupManager*: GroupManager
onFatalErrorAction*: OnFatalErrorHandler onFatalErrorAction*: OnFatalErrorHandler
when defined(rln_v2): nonceManager*: NonceManager
nonceManager*: NonceManager
proc calcEpoch*(rlnPeer: WakuRLNRelay, t: float64): Epoch = proc calcEpoch*(rlnPeer: WakuRLNRelay, t: float64): Epoch =
## gets time `t` as `flaot64` with subseconds resolution in the fractional part ## gets time `t` as `flaot64` with subseconds resolution in the fractional part
@ -307,14 +303,11 @@ proc appendRLNProof*(
let input = msg.toRLNSignal() let input = msg.toRLNSignal()
let epoch = rlnPeer.calcEpoch(senderEpochTime) let epoch = rlnPeer.calcEpoch(senderEpochTime)
when defined(rln_v2): let nonce = rlnPeer.nonceManager.getNonce().valueOr:
let nonce = rlnPeer.nonceManager.getNonce().valueOr: return err("could not get new message id to generate an rln proof: " & $error)
return err("could not get new message id to generate an rln proof: " & $error) let proof = rlnPeer.groupManager.generateProof(input, epoch, nonce).valueOr:
let proof = rlnPeer.groupManager.generateProof(input, epoch, nonce).valueOr: return err("could not generate rln-v2 proof: " & $error)
return err("could not generate rln-v2 proof: " & $error)
else:
let proof = rlnPeer.groupManager.generateProof(input, epoch).valueOr:
return err("could not generate rln proof: " & $error)
msg.proof = proof.encode().buffer msg.proof = proof.encode().buffer
return ok() return ok()
@ -445,28 +438,18 @@ proc mount(
(await groupManager.startGroupSync()).isOkOr: (await groupManager.startGroupSync()).isOkOr:
return err("could not start the group sync: " & $error) return err("could not start the group sync: " & $error)
when defined(rln_v2): return ok(
return ok( WakuRLNRelay(
WakuRLNRelay( groupManager: groupManager,
groupManager: groupManager, nonceManager:
nonceManager: NonceManager.init(conf.rlnRelayUserMessageLimit, conf.rlnEpochSizeSec.float),
NonceManager.init(conf.rlnRelayUserMessageLimit, conf.rlnEpochSizeSec.float), rlnEpochSizeSec: conf.rlnEpochSizeSec,
rlnEpochSizeSec: conf.rlnEpochSizeSec, rlnMaxEpochGap:
rlnMaxEpochGap: max(uint64(MaxClockGapSeconds / float64(conf.rlnEpochSizeSec)), 1),
max(uint64(MaxClockGapSeconds / float64(conf.rlnEpochSizeSec)), 1), onFatalErrorAction: conf.onFatalErrorAction,
onFatalErrorAction: conf.onFatalErrorAction,
)
)
else:
return ok(
WakuRLNRelay(
groupManager: groupManager,
rlnEpochSizeSec: conf.rlnEpochSizeSec,
rlnMaxEpochGap:
max(uint64(MaxClockGapSeconds / float64(conf.rlnEpochSizeSec)), 1),
onFatalErrorAction: conf.onFatalErrorAction,
)
) )
)
proc isReady*(rlnPeer: WakuRLNRelay): Future[bool] {.async: (raises: [Exception]).} = proc isReady*(rlnPeer: WakuRLNRelay): Future[bool] {.async: (raises: [Exception]).} =
## returns true if the rln-relay protocol is ready to relay messages ## returns true if the rln-relay protocol is ready to relay messages