diff --git a/CHANGELOG.md b/CHANGELOG.md index ec377ef5b..151392f1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +## v0.35.1 (2025-03-30) + +### Bug fixes + +* Update RLN references ([3287](https://github.com/waku-org/nwaku/pull/3287)) ([ea961fa](https://github.com/waku-org/nwaku/pull/3287/commits/ea961faf4ed4f8287a2043a6b5d84b660745072b)) + +**Info:** before upgrading to this version, make sure you delete the previous rln_tree folder, i.e., +the one that is passed through this CLI: `--rln-relay-tree-path`. + +This release supports the following [libp2p protocols](https://docs.libp2p.io/concepts/protocols/): +| Protocol | Spec status | Protocol id | +| ---: | :---: | :--- | +| [`11/WAKU2-RELAY`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/11/relay.md) | `stable` | `/vac/waku/relay/2.0.0` | +| [`12/WAKU2-FILTER`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/12/filter.md) | `draft` | `/vac/waku/filter/2.0.0-beta1`
`/vac/waku/filter-subscribe/2.0.0-beta1`
`/vac/waku/filter-push/2.0.0-beta1` | +| [`13/WAKU2-STORE`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/13/store.md) | `draft` | `/vac/waku/store/2.0.0-beta4` | +| [`19/WAKU2-LIGHTPUSH`](https://github.com/vacp2p/rfc-index/blob/main/waku/standards/core/19/lightpush.md) | `draft` | `/vac/waku/lightpush/2.0.0-beta1` | +| [`66/WAKU2-METADATA`](https://github.com/waku-org/specs/blob/master/standards/core/metadata.md) | `raw` | `/vac/waku/metadata/1.0.0` | +| [`WAKU-SYNC`](https://github.com/waku-org/specs/blob/feat--waku-sync/standards/core/sync.md) | `draft` | `/vac/waku/sync/1.0.0` | + ## v0.35.0 (2025-03-03) ### Notes diff --git a/apps/sonda/docker-compose.yml b/apps/sonda/docker-compose.yml index 2141bbfc8..c6235ef32 100644 --- a/apps/sonda/docker-compose.yml +++ b/apps/sonda/docker-compose.yml @@ -9,7 +9,7 @@ x-logging: &logging x-rln-relay-eth-client-address: &rln_relay_eth_client_address ${RLN_RELAY_ETH_CLIENT_ADDRESS:-} # Add your RLN_RELAY_ETH_CLIENT_ADDRESS after the "-" x-rln-environment: &rln_env - RLN_RELAY_CONTRACT_ADDRESS: ${RLN_RELAY_CONTRACT_ADDRESS:-0xCB33Aa5B38d79E3D9Fa8B10afF38AA201399a7e3} + RLN_RELAY_CONTRACT_ADDRESS: ${RLN_RELAY_CONTRACT_ADDRESS:-0xfe7a9eabcE779a090FD702346Fd0bFAc02ce6Ac8} RLN_RELAY_CRED_PATH: ${RLN_RELAY_CRED_PATH:-} # Optional: Add your RLN_RELAY_CRED_PATH after the "-" RLN_RELAY_CRED_PASSWORD: ${RLN_RELAY_CRED_PASSWORD:-} # Optional: Add your RLN_RELAY_CRED_PASSWORD after the "-" diff --git a/apps/sonda/register_rln.sh b/apps/sonda/register_rln.sh index ab660f1d8..aca1007a8 100755 --- a/apps/sonda/register_rln.sh +++ b/apps/sonda/register_rln.sh @@ -24,7 +24,7 @@ fi docker run -v $(pwd)/keystore:/keystore/:Z harbor.status.im/wakuorg/nwaku:v0.30.1 generateRlnKeystore \ --rln-relay-eth-client-address=${RLN_RELAY_ETH_CLIENT_ADDRESS} \ --rln-relay-eth-private-key=${ETH_TESTNET_KEY} \ ---rln-relay-eth-contract-address=0xCB33Aa5B38d79E3D9Fa8B10afF38AA201399a7e3 \ +--rln-relay-eth-contract-address=0xfe7a9eabcE779a090FD702346Fd0bFAc02ce6Ac8 \ --rln-relay-cred-path=/keystore/keystore.json \ --rln-relay-cred-password="${RLN_RELAY_CRED_PASSWORD}" \ --rln-relay-user-message-limit=20 \ diff --git a/library/libwaku.h b/library/libwaku.h index d49a40076..3c15b36f9 100644 --- a/library/libwaku.h +++ b/library/libwaku.h @@ -168,6 +168,10 @@ int waku_get_peerids_from_peerstore(void* ctx, WakuCallBack callback, void* userData); +int waku_get_connected_peers_info(void* ctx, + WakuCallBack callback, + void* userData); + int waku_get_peerids_by_protocol(void* ctx, const char* protocol, WakuCallBack callback, diff --git a/library/libwaku.nim b/library/libwaku.nim index f7c14c061..ebe730da8 100644 --- a/library/libwaku.nim +++ b/library/libwaku.nim @@ -692,6 +692,20 @@ proc waku_get_peerids_from_peerstore( userData, ) +proc waku_get_connected_peers_info( + ctx: ptr WakuContext, callback: WakuCallBack, userData: pointer +): cint {.dynlib, exportc.} = + initializeLibrary() + checkLibwakuParams(ctx, callback, userData) + + handleRequest( + ctx, + RequestType.PEER_MANAGER, + PeerManagementRequest.createShared(PeerManagementMsgType.GET_CONNECTED_PEERS_INFO), + callback, + userData, + ) + proc waku_get_connected_peers( ctx: ptr WakuContext, callback: WakuCallBack, userData: pointer ): cint {.dynlib, exportc.} = diff --git a/library/waku_thread/inter_thread_communication/requests/peer_manager_request.nim b/library/waku_thread/inter_thread_communication/requests/peer_manager_request.nim index 73b5a320d..d8a0a57af 100644 --- a/library/waku_thread/inter_thread_communication/requests/peer_manager_request.nim +++ b/library/waku_thread/inter_thread_communication/requests/peer_manager_request.nim @@ -1,5 +1,5 @@ import std/[sequtils, strutils] -import chronicles, chronos, results, options +import chronicles, chronos, results, options, json import ../../../../waku/factory/waku, ../../../../waku/node/waku_node, @@ -9,6 +9,7 @@ import type PeerManagementMsgType* {.pure.} = enum CONNECT_TO GET_ALL_PEER_IDS + GET_CONNECTED_PEERS_INFO GET_PEER_IDS_BY_PROTOCOL DISCONNECT_PEER_BY_ID DIAL_PEER @@ -22,6 +23,10 @@ type PeerManagementRequest* = object protocol: cstring peerId: cstring +type PeerInfo = object + protocols: seq[string] + addresses: seq[string] + proc createShared*( T: type PeerManagementRequest, op: PeerManagementMsgType, @@ -83,6 +88,24 @@ proc process*( let peerIDs = waku.node.peerManager.wakuPeerStore.peers().mapIt($it.peerId).join(",") return ok(peerIDs) + of GET_CONNECTED_PEERS_INFO: + ## returns a JSON string mapping peerIDs to objects with protocols and addresses + + var peersMap = initTable[string, PeerInfo]() + let peers = waku.node.peerManager.wakuPeerStore.peers().filterIt( + it.connectedness == Connected + ) + + # Build a map of peer IDs to peer info objects + for peer in peers: + let peerIdStr = $peer.peerId + peersMap[peerIdStr] = + PeerInfo(protocols: peer.protocols, addresses: peer.addrs.mapIt($it)) + + # Convert the map to JSON string + let jsonObj = %*peersMap + let jsonStr = $jsonObj + return ok(jsonStr) of GET_PEER_IDS_BY_PROTOCOL: ## returns a comma-separated string of peerIDs that mount the given protocol let connectedPeers = waku.node.peerManager.wakuPeerStore diff --git a/waku/factory/networks_config.nim b/waku/factory/networks_config.nim index 03890de55..bcef0dd77 100644 --- a/waku/factory/networks_config.nim +++ b/waku/factory/networks_config.nim @@ -22,7 +22,7 @@ proc TheWakuNetworkConf*(T: type ClusterConf): ClusterConf = maxMessageSize: "150KiB", clusterId: 1, rlnRelay: true, - rlnRelayEthContractAddress: "0xB9cd878C90E49F797B4431fBF4fb333108CB90e6", + rlnRelayEthContractAddress: "0xfe7a9eabcE779a090FD702346Fd0bFAc02ce6Ac8", rlnRelayDynamic: true, rlnRelayChainId: 59141, rlnRelayBandwidthThreshold: 0, diff --git a/waku/waku_rln_relay/group_manager/group_manager_base.nim b/waku/waku_rln_relay/group_manager/group_manager_base.nim index 7911463a1..ae47f682c 100644 --- a/waku/waku_rln_relay/group_manager/group_manager_base.nim +++ b/waku/waku_rln_relay/group_manager/group_manager_base.nim @@ -155,7 +155,6 @@ method validateRoot*( first = false rootsStr.add("]") debug "Valid Merkle roots in validateRoot", roots = rootsStr, root_to_validate = root - # Check if the root is in the valid roots queue if g.indexOfRoot(root) >= 0: return true diff --git a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim index 98af95a1f..c263fe500 100644 --- a/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim +++ b/waku/waku_rln_relay/group_manager/on_chain/group_manager.nim @@ -50,8 +50,8 @@ contract(WakuRlnContract): # this constant describes max message limit of rln contract proc maxMembershipRateLimit(): UInt256 {.view.} # this function returns the merkleProof for a given index - # proc getMerkleProof(index: UInt40): seq[Uint256] {.view.} - # # this function returns the Merkle root + proc getMerkleProof(index: EthereumUInt40): seq[array[32, byte]] {.view.} + # this function returns the Merkle root proc root(): Uint256 {.view.} type @@ -68,7 +68,7 @@ type keystorePassword*: Option[string] registrationHandler*: Option[RegistrationHandler] latestProcessedBlock*: BlockNumber - merkleProofCache*: seq[UInt256] + merkleProofCache*: seq[array[32, byte]] proc setMetadata*( g: OnchainGroupManager, lastProcessedBlock = none(BlockNumber) @@ -95,20 +95,11 @@ proc setMetadata*( proc fetchMerkleProofElements*( g: OnchainGroupManager -): Future[Result[seq[UInt256], string]] {.async.} = +): Future[Result[seq[array[32, byte]], string]] {.async.} = try: let membershipIndex = g.membershipIndex.get() - let commitmentIndexInvocation = g.wakuRlnContract.get().nextFreeIndex() - let currentCommitmentIndex = await commitmentIndexInvocation.call() - let membershipIndexUint256 = stuint(membershipIndex, 256) let index40 = stuint(membershipIndex, 40) - if membershipIndexUint256 >= currentCommitmentIndex: - return err( - "Invalid membership index: " & $membershipIndex & - " is >= current commitment index: " & currentCommitmentIndex.toHex() - ) - let methodSig = "getMerkleProof(uint40)" let methodIdDigest = keccak.keccak256.digest(methodSig) let methodId = methodIdDigest.data[0 .. 3] @@ -129,13 +120,18 @@ proc fetchMerkleProofElements*( let responseBytes = await g.ethRpc.get().provider.eth_call(tx, "latest") - var merkleProof: seq[UInt256] - - for i in 0 .. 19: - let startindex = 32 + (i * 32) # skip initial 32 bytes for the array offset - if startindex + 32 <= responseBytes.len: - let elementbytes = responseBytes[startindex ..< startindex + 32] - merkleProof.add(UInt256.fromBytesBE(elementbytes)) + var merkleProof = newSeqOfCap[array[32, byte]](20) + for i in 0 ..< 20: + let startIndex = 32 + (i * 32) # Skip first 32 bytes (ABI encoding offset) + if startIndex + 32 <= responseBytes.len: + var element: array[32, byte] + for j in 0 ..< 32: + if startIndex + j < responseBytes.len: + element[j] = responseBytes[startIndex + j] + merkleProof.add(element) + else: + var element: array[32, byte] + merkleProof.add(element) return ok(merkleProof) except CatchableError: @@ -143,50 +139,6 @@ proc fetchMerkleProofElements*( errMsg = getCurrentExceptionMsg(), index = g.membershipIndex.get() return err("Failed to fetch Merkle proof elements: " & getCurrentExceptionMsg()) -# proc fetchMerkleProofElements*( -# g: OnchainGroupManager -# ): Future[Result[seq[UInt256], string]] {.async.} = -# try: -# let membershipIndex = g.membershipIndex.get() -# -# # First check if the index is valid and within range -# let commitmentIndexInvocation = g.wakuRlnContract.get().commitmentIndex() -# let currentCommitmentIndex = await commitmentIndexInvocation.call() -# let membershipIndexUint256 = stuint(membershipIndex, 256) -# let index40 = stuint(membershipIndex, 40) -# -# debug "------ checking if membership index is validity ------", -# membershipIndex = membershipIndex, -# membershipIndexHEX = membershipIndex.toHex(), -# membershipIndexUint256 = membershipIndexUint256, -# membershipIndexUint256HEX = membershipIndexUint256.toHex(), -# currentCommitmentIndex = currentCommitmentIndex, -# currentCommitmentIndexHEX = currentCommitmentIndex.toHex(), -# index40 = index40, -# index40HEX = index40.toHex() -# -# # Ensure the membershipIndex is less than the total number of commitments -# if membershipIndexUint256 >= currentCommitmentIndex: -# error "Invalid membership index", -# membershipIndex = membershipIndex, -# currentCommitmentIndex = currentCommitmentIndex.toHex() -# return err( -# "Invalid membership index: " & $membershipIndex & -# " is >= current commitment index: " & currentCommitmentIndex.toHex() -# ) -# -# let merkleProofInvocation = -# g.wakuRlnContract.get().merkleProofElements(membershipIndexUint256) -# let merkleProof = await merkleProofInvocation.call() -# -# debug "------ Merkle proof ------", merkleProof = merkleProof -# -# return ok(merkleProof) -# except CatchableError: -# error "------ Failed to fetch Merkle proof elements ------", -# errMsg = getCurrentExceptionMsg(), index = g.membershipIndex.get() -# return err("Failed to fetch Merkle proof elements: " & getCurrentExceptionMsg()) - proc fetchMerkleRoot*( g: OnchainGroupManager ): Future[Result[Uint256, string]] {.async.} = @@ -370,14 +322,19 @@ method withdrawBatch*( proc toArray32*(s: seq[byte]): array[32, byte] = var output: array[32, byte] - discard output.copyFrom(s) + for i in 0 ..< 32: + output[i] = 0 + let len = min(s.len, 32) + for i in 0 ..< len: + output[i] = s[s.len - 1 - i] return output -proc toArray32Seq*(values: seq[UInt256]): seq[array[32, byte]] = - ## Converts a MerkleProof (array of 20 UInt256 values) to a sequence of 32-byte arrays - result = newSeqOfCap[array[32, byte]](values.len) - for value in values: - result.add(value.toBytesLE()) +proc indexToPath(index: uint64): seq[byte] = + # Fixed tree height of 32 for RLN + const treeHeight = 20 + result = newSeq[byte](treeHeight) + for i in 0 ..< treeHeight: + result[i] = byte((index shr i) and 1) method generateProof*( g: OnchainGroupManager, @@ -402,32 +359,6 @@ method generateProof*( let externalNullifierRes = poseidon(@[@(epoch), @(rlnIdentifier)]) - try: - let rootRes = waitFor g.fetchMerkleRoot() - if rootRes.isErr(): - return err("Failed to fetch Merkle root: " & rootRes.error) - debug "Merkle root fetched", root = rootRes.get().toHex - except CatchableError: - error "Failed to fetch Merkle root", error = getCurrentExceptionMsg() - return err("Failed to fetch Merkle root: " & getCurrentExceptionMsg()) - - # Check if contract knows about the member - try: - let idCommitment = g.idCredentials.get().idCommitment.toUInt256() - let memberExistsRes = - waitFor g.wakuRlnContract.get().isInMembershipSet(idCommitment).call() - - if memberExistsRes == false: - error "------ Member does not exist in contract ------", - idCommitment = idCommitment.toHex(), membershipIndex = g.membershipIndex.get() - return err("Member ID commitment not found in contract: " & idCommitment.toHex()) - - debug "------ Member exists in contract ------", - idCommitment = idCommitment.toHex(), membershipIndex = g.membershipIndex.get() - except CatchableError as e: - error "------ Failed to check if member exists ------", error = e.msg - # Continue execution even if this check fails - try: let proofResult = waitFor g.fetchMerkleProofElements() if proofResult.isErr(): @@ -443,12 +374,30 @@ method generateProof*( identity_secret: g.idCredentials.get().idSecretHash.toArray32(), user_message_limit: serialize(g.userMessageLimit.get()), message_id: serialize(messageId), - path_elements: toArray32Seq(g.merkleProofCache), - identity_path_index: @(toBytes(g.membershipIndex.get(), littleEndian)), + path_elements: g.merkleProofCache, + identity_path_index: indexToPath(g.membershipIndex.get()), x: toArray32(data), external_nullifier: externalNullifierRes.get(), ) + debug "------ Generating proof with witness ------", + identity_secret = inHex(witness.identity_secret), + user_message_limit = inHex(witness.user_message_limit), + message_id = inHex(witness.message_id), + path_elements = witness.path_elements.map(inHex), + identity_path_index = witness.identity_path_index.mapIt($it).join(", "), + x = inHex(witness.x), + external_nullifier = inHex(witness.external_nullifier) + + debug "------ Witness parameters ------", + identity_secret_len = witness.identity_secret.len, + user_message_limit_len = witness.user_message_limit.len, + message_id_len = witness.message_id.len, + path_elements_count = witness.path_elements.len, + identity_path_index_len = witness.identity_path_index.len, + x_len = witness.x.len, + external_nullifier_len = witness.external_nullifier.len + let serializedWitness = serialize(witness) var inputBuffer = toBuffer(serializedWitness) @@ -458,6 +407,8 @@ method generateProof*( generate_proof_with_witness(g.rlnInstance, addr inputBuffer, addr outputBuffer) if not success: return err("Failed to generate proof") + else: + debug "------ Proof generated successfully --------" # Parse the proof into a RateLimitProof object var proofValue = cast[ptr array[320, byte]](outputBuffer.`ptr`)