mirror of
https://github.com/waku-org/nwaku.git
synced 2025-02-05 11:34:45 +00:00
deploy: 07833ce313a2e861676912bdfc0faaae6aa9ace3
This commit is contained in:
parent
b55851e990
commit
b877072d75
8
.gitignore
vendored
8
.gitignore
vendored
@ -43,3 +43,11 @@ testPath.txt
|
|||||||
|
|
||||||
# Nimbus Build System
|
# Nimbus Build System
|
||||||
nimbus-build-system.paths
|
nimbus-build-system.paths
|
||||||
|
|
||||||
|
# sqlite db
|
||||||
|
*.db
|
||||||
|
*.db-shm
|
||||||
|
*.db-wal
|
||||||
|
*.sqlite3
|
||||||
|
*.sqlite3-shm
|
||||||
|
*.sqlite3-wal
|
@ -214,6 +214,19 @@ suite "Waku rln relay":
|
|||||||
check:
|
check:
|
||||||
deletionSuccess
|
deletionSuccess
|
||||||
|
|
||||||
|
test "insertMembers rln utils":
|
||||||
|
# create an RLN instance which also includes an empty Merkle tree
|
||||||
|
let rlnInstance = createRLNInstance()
|
||||||
|
require:
|
||||||
|
rlnInstance.isOk()
|
||||||
|
let rln = rlnInstance.get()
|
||||||
|
# generate a key pair
|
||||||
|
let keyPairRes = rln.membershipKeyGen()
|
||||||
|
require:
|
||||||
|
keypairRes.isOk()
|
||||||
|
check:
|
||||||
|
rln.insertMembers(0, @[keyPairRes.get().idCommitment])
|
||||||
|
|
||||||
test "insertMember rln utils":
|
test "insertMember rln utils":
|
||||||
# create an RLN instance which also includes an empty Merkle tree
|
# create an RLN instance which also includes an empty Merkle tree
|
||||||
let rlnInstance = createRLNInstance()
|
let rlnInstance = createRLNInstance()
|
||||||
@ -330,7 +343,7 @@ suite "Waku rln relay":
|
|||||||
let keyPairRes = rln.membershipKeyGen()
|
let keyPairRes = rln.membershipKeyGen()
|
||||||
require:
|
require:
|
||||||
keyPairRes.isOk()
|
keyPairRes.isOk()
|
||||||
let memberInserted = rln.insertMember(keypairRes.get().idCommitment)
|
let memberInserted = rln.insertMembers(0, @[keypairRes.get().idCommitment])
|
||||||
require:
|
require:
|
||||||
memberInserted
|
memberInserted
|
||||||
|
|
||||||
@ -502,7 +515,7 @@ suite "Waku rln relay":
|
|||||||
|
|
||||||
let
|
let
|
||||||
# peer's index in the Merkle Tree
|
# peer's index in the Merkle Tree
|
||||||
index = 5
|
index = 5'u
|
||||||
# create a membership key pair
|
# create a membership key pair
|
||||||
memKeysRes = membershipKeyGen(rln)
|
memKeysRes = membershipKeyGen(rln)
|
||||||
|
|
||||||
@ -511,21 +524,23 @@ suite "Waku rln relay":
|
|||||||
|
|
||||||
let memKeys = memKeysRes.get()
|
let memKeys = memKeysRes.get()
|
||||||
|
|
||||||
|
var members = newSeq[IDCommitment]()
|
||||||
# Create a Merkle tree with random members
|
# Create a Merkle tree with random members
|
||||||
for i in 0..10:
|
for i in 0'u..10'u:
|
||||||
var memberAdded: bool = false
|
|
||||||
if (i == index):
|
if (i == index):
|
||||||
# insert the current peer's pk
|
# insert the current peer's pk
|
||||||
memberAdded = rln.insertMember(memKeys.idCommitment)
|
members.add(memKeys.idCommitment)
|
||||||
else:
|
else:
|
||||||
# create a new key pair
|
# create a new key pair
|
||||||
let memberKeysRes = rln.membershipKeyGen()
|
let memberKeysRes = rln.membershipKeyGen()
|
||||||
require:
|
require:
|
||||||
memberKeysRes.isOk()
|
memberKeysRes.isOk()
|
||||||
memberAdded = rln.insertMember(memberKeysRes.get().idCommitment)
|
members.add(memberKeysRes.get().idCommitment)
|
||||||
# check the member is added
|
|
||||||
|
# Batch the insert
|
||||||
|
let batchInsertRes = rln.insertMembers(0, members)
|
||||||
require:
|
require:
|
||||||
memberAdded
|
batchInsertRes
|
||||||
|
|
||||||
# prepare the message
|
# prepare the message
|
||||||
let messageBytes = "Hello".toBytes()
|
let messageBytes = "Hello".toBytes()
|
||||||
@ -545,7 +560,8 @@ suite "Waku rln relay":
|
|||||||
|
|
||||||
# verify the proof
|
# verify the proof
|
||||||
let verified = rln.proofVerify(data = messageBytes,
|
let verified = rln.proofVerify(data = messageBytes,
|
||||||
proof = proof)
|
proof = proof,
|
||||||
|
validRoots = @[rln.getMerkleRoot().value()])
|
||||||
|
|
||||||
# Ensure the proof verification did not error out
|
# Ensure the proof verification did not error out
|
||||||
|
|
||||||
@ -561,7 +577,7 @@ suite "Waku rln relay":
|
|||||||
|
|
||||||
let
|
let
|
||||||
# peer's index in the Merkle Tree
|
# peer's index in the Merkle Tree
|
||||||
index = 5
|
index = 5'u
|
||||||
# create a membership key pair
|
# create a membership key pair
|
||||||
memKeysRes = membershipKeyGen(rln)
|
memKeysRes = membershipKeyGen(rln)
|
||||||
|
|
||||||
@ -571,17 +587,17 @@ suite "Waku rln relay":
|
|||||||
let memKeys = memKeysRes.get()
|
let memKeys = memKeysRes.get()
|
||||||
|
|
||||||
# Create a Merkle tree with random members
|
# Create a Merkle tree with random members
|
||||||
for i in 0..10:
|
for i in 0'u..10'u:
|
||||||
var memberAdded: bool = false
|
var memberAdded: bool = false
|
||||||
if (i == index):
|
if (i == index):
|
||||||
# insert the current peer's pk
|
# insert the current peer's pk
|
||||||
memberAdded = rln.insertMember(memKeys.idCommitment)
|
memberAdded = rln.insertMembers(i, @[memKeys.idCommitment])
|
||||||
else:
|
else:
|
||||||
# create a new key pair
|
# create a new key pair
|
||||||
let memberKeysRes = rln.membershipKeyGen()
|
let memberKeysRes = rln.membershipKeyGen()
|
||||||
require:
|
require:
|
||||||
memberKeysRes.isOk()
|
memberKeysRes.isOk()
|
||||||
memberAdded = rln.insertMember(memberKeysRes.get().idCommitment)
|
memberAdded = rln.insertMembers(i, @[memberKeysRes.get().idCommitment])
|
||||||
# check the member is added
|
# check the member is added
|
||||||
require:
|
require:
|
||||||
memberAdded
|
memberAdded
|
||||||
@ -628,7 +644,7 @@ suite "Waku rln relay":
|
|||||||
|
|
||||||
let
|
let
|
||||||
# peer's index in the Merkle Tree.
|
# peer's index in the Merkle Tree.
|
||||||
index = 5
|
index = 5'u
|
||||||
# create a membership key pair
|
# create a membership key pair
|
||||||
memKeysRes = membershipKeyGen(rlnRelay.rlnInstance)
|
memKeysRes = membershipKeyGen(rlnRelay.rlnInstance)
|
||||||
|
|
||||||
@ -637,23 +653,26 @@ suite "Waku rln relay":
|
|||||||
|
|
||||||
let memKeys = memKeysRes.get()
|
let memKeys = memKeysRes.get()
|
||||||
|
|
||||||
let membershipCount = AcceptableRootWindowSize + 5
|
let membershipCount: uint = AcceptableRootWindowSize + 5'u
|
||||||
|
|
||||||
# Create a Merkle tree with random members
|
var members = newSeq[MembershipKeyPair]()
|
||||||
for i in 0..membershipCount:
|
|
||||||
var memberIsAdded: RlnRelayResult[void]
|
# Generate membership keys
|
||||||
|
for i in 0'u..membershipCount:
|
||||||
if (i == index):
|
if (i == index):
|
||||||
# insert the current peer's pk
|
# insert the current peer's pk
|
||||||
memberIsAdded = rlnRelay.insertMember(memKeys.idCommitment)
|
members.add(memKeys)
|
||||||
else:
|
else:
|
||||||
# create a new key pair
|
# create a new key pair
|
||||||
let memberKeysRes = rlnRelay.rlnInstance.membershipKeyGen()
|
let memberKeysRes = rlnRelay.rlnInstance.membershipKeyGen()
|
||||||
require:
|
require:
|
||||||
memberKeysRes.isOk()
|
memberKeysRes.isOk()
|
||||||
memberIsAdded = rlnRelay.insertMember(memberKeysRes.get().idCommitment)
|
members.add(memberKeysRes.get())
|
||||||
# require that the member is added
|
|
||||||
|
# Batch inserts into the tree
|
||||||
|
let insertedRes = rlnRelay.insertMembers(0, members.mapIt(it.idCommitment))
|
||||||
require:
|
require:
|
||||||
memberIsAdded.isOk()
|
insertedRes.isOk()
|
||||||
|
|
||||||
# Given:
|
# Given:
|
||||||
# This step includes constructing a valid message with the latest merkle root
|
# This step includes constructing a valid message with the latest merkle root
|
||||||
@ -686,11 +705,12 @@ suite "Waku rln relay":
|
|||||||
|
|
||||||
# Progress the local tree by removing members
|
# Progress the local tree by removing members
|
||||||
for i in 0..AcceptableRootWindowSize - 2:
|
for i in 0..AcceptableRootWindowSize - 2:
|
||||||
discard rlnRelay.removeMember(MembershipIndex(i))
|
let res = rlnRelay.removeMember(MembershipIndex(i))
|
||||||
# Ensure the local tree root has changed
|
# Ensure the local tree root has changed
|
||||||
let currentMerkleRoot = rlnRelay.rlnInstance.getMerkleRoot()
|
let currentMerkleRoot = rlnRelay.rlnInstance.getMerkleRoot()
|
||||||
|
|
||||||
require:
|
require:
|
||||||
|
res.isOk()
|
||||||
currentMerkleRoot.isOk()
|
currentMerkleRoot.isOk()
|
||||||
currentMerkleRoot.value() != validProof.merkleRoot
|
currentMerkleRoot.value() != validProof.merkleRoot
|
||||||
|
|
||||||
@ -720,7 +740,7 @@ suite "Waku rln relay":
|
|||||||
|
|
||||||
let
|
let
|
||||||
# peer's index in the Merkle Tree.
|
# peer's index in the Merkle Tree.
|
||||||
index = 6
|
index = 6'u
|
||||||
# create a membership key pair
|
# create a membership key pair
|
||||||
memKeysRes = membershipKeyGen(rlnRelay.rlnInstance)
|
memKeysRes = membershipKeyGen(rlnRelay.rlnInstance)
|
||||||
|
|
||||||
@ -729,20 +749,20 @@ suite "Waku rln relay":
|
|||||||
|
|
||||||
let memKeys = memKeysRes.get()
|
let memKeys = memKeysRes.get()
|
||||||
|
|
||||||
let membershipCount = AcceptableRootWindowSize + 5
|
let membershipCount: uint = AcceptableRootWindowSize + 5'u
|
||||||
|
|
||||||
# Create a Merkle tree with random members
|
# Create a Merkle tree with random members
|
||||||
for i in 0..membershipCount:
|
for i in 0'u..membershipCount:
|
||||||
var memberIsAdded: RlnRelayResult[void]
|
var memberIsAdded: RlnRelayResult[void]
|
||||||
if (i == index):
|
if (i == index):
|
||||||
# insert the current peer's pk
|
# insert the current peer's pk
|
||||||
memberIsAdded = rlnRelay.insertMember(memKeys.idCommitment)
|
memberIsAdded = rlnRelay.insertMembers(i, @[memKeys.idCommitment])
|
||||||
else:
|
else:
|
||||||
# create a new key pair
|
# create a new key pair
|
||||||
let memberKeysRes = rlnRelay.rlnInstance.membershipKeyGen()
|
let memberKeysRes = rlnRelay.rlnInstance.membershipKeyGen()
|
||||||
require:
|
require:
|
||||||
memberKeysRes.isOk()
|
memberKeysRes.isOk()
|
||||||
memberIsAdded = rlnRelay.insertMember(memberKeysRes.get().idCommitment)
|
memberIsAdded = rlnRelay.insertMembers(i, @[memberKeysRes.get().idCommitment])
|
||||||
# require that the member is added
|
# require that the member is added
|
||||||
require:
|
require:
|
||||||
memberIsAdded.isOk()
|
memberIsAdded.isOk()
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
{.used.}
|
{.used.}
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[options, osproc, streams, strutils],
|
std/[options, osproc, streams, strutils, sequtils],
|
||||||
testutils/unittests, chronos, chronicles, stint, web3, json,
|
testutils/unittests, chronos, chronicles, stint, web3, json,
|
||||||
stew/byteutils, stew/shims/net as stewNet,
|
stew/byteutils, stew/shims/net as stewNet,
|
||||||
libp2p/crypto/crypto,
|
libp2p/crypto/crypto,
|
||||||
@ -279,13 +279,15 @@ procSuite "Waku-rln-relay":
|
|||||||
debug "membership commitment key", pk2 = pk2
|
debug "membership commitment key", pk2 = pk2
|
||||||
|
|
||||||
var events = [newFuture[void](), newFuture[void]()]
|
var events = [newFuture[void](), newFuture[void]()]
|
||||||
proc handler(pubkey: Uint256, index: Uint256): RlnRelayResult[void] =
|
var futIndex = 0
|
||||||
debug "handler is called", pubkey = pubkey, index = index
|
var handler: GroupUpdateHandler
|
||||||
if pubkey == pk:
|
handler = proc (blockNumber: BlockNumber,
|
||||||
events[0].complete()
|
members: seq[MembershipTuple]): RlnRelayResult[void] =
|
||||||
if pubkey == pk2:
|
debug "handler is called", members = members
|
||||||
events[1].complete()
|
events[futIndex].complete()
|
||||||
let isSuccessful = rlnPeer.rlnInstance.insertMember(pubkey.toIDCommitment())
|
futIndex += 1
|
||||||
|
let index = members[0].index
|
||||||
|
let isSuccessful = rlnPeer.rlnInstance.insertMembers(index, members.mapIt(it.idComm))
|
||||||
check:
|
check:
|
||||||
isSuccessful
|
isSuccessful
|
||||||
return ok()
|
return ok()
|
||||||
@ -305,7 +307,7 @@ procSuite "Waku-rln-relay":
|
|||||||
let tx2 = await contractObj.register(pk2).send(value = MembershipFee)
|
let tx2 = await contractObj.register(pk2).send(value = MembershipFee)
|
||||||
debug "a member is registered", tx2 = tx2
|
debug "a member is registered", tx2 = tx2
|
||||||
|
|
||||||
# wait for all the events to be received by the rlnPeer
|
# wait for the events to be processed
|
||||||
await all(events)
|
await all(events)
|
||||||
|
|
||||||
# release resources -----------------------
|
# release resources -----------------------
|
||||||
@ -405,12 +407,12 @@ procSuite "Waku-rln-relay":
|
|||||||
|
|
||||||
# Create a group of 10 members
|
# Create a group of 10 members
|
||||||
var group = newSeq[IDCommitment]()
|
var group = newSeq[IDCommitment]()
|
||||||
for i in 0..10:
|
for i in 0'u..10'u:
|
||||||
var memberAdded: bool = false
|
var memberAdded: bool = false
|
||||||
if (uint(i) == index):
|
if (i == index):
|
||||||
# insert the current peer's pk
|
# insert the current peer's pk
|
||||||
group.add(keyPair.idCommitment)
|
group.add(keyPair.idCommitment)
|
||||||
memberAdded = rln.insertMember(keyPair.idCommitment)
|
memberAdded = rln.insertMembers(i, @[keyPair.idCommitment])
|
||||||
doAssert(memberAdded)
|
doAssert(memberAdded)
|
||||||
debug "member key", key = keyPair.idCommitment.inHex
|
debug "member key", key = keyPair.idCommitment.inHex
|
||||||
else:
|
else:
|
||||||
@ -419,7 +421,7 @@ procSuite "Waku-rln-relay":
|
|||||||
memberKeyPairRes.isOk()
|
memberKeyPairRes.isOk()
|
||||||
let memberKeyPair = memberKeyPairRes.get()
|
let memberKeyPair = memberKeyPairRes.get()
|
||||||
group.add(memberKeyPair.idCommitment)
|
group.add(memberKeyPair.idCommitment)
|
||||||
let memberAdded = rln.insertMember(memberKeyPair.idCommitment)
|
let memberAdded = rln.insertMembers(i, @[memberKeyPair.idCommitment])
|
||||||
require:
|
require:
|
||||||
memberAdded
|
memberAdded
|
||||||
debug "member key", key = memberKeyPair.idCommitment.inHex
|
debug "member key", key = memberKeyPair.idCommitment.inHex
|
||||||
@ -491,8 +493,8 @@ procSuite "Waku-rln-relay":
|
|||||||
|
|
||||||
# add the rln keys to the Merkle tree
|
# add the rln keys to the Merkle tree
|
||||||
let
|
let
|
||||||
memberIsAdded1 = rln.insertMember(keyPair1.idCommitment)
|
memberIsAdded1 = rln.insertMembers(0, @[keyPair1.idCommitment])
|
||||||
memberIsAdded2 = rln.insertMember(keyPair2.idCommitment)
|
memberIsAdded2 = rln.insertMembers(1, @[keyPair2.idCommitment])
|
||||||
|
|
||||||
require:
|
require:
|
||||||
memberIsAdded1
|
memberIsAdded1
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# libtool - Provide generalized library-building support services.
|
# libtool - Provide generalized library-building support services.
|
||||||
# Generated automatically by config.status (libbacktrace) version-unused
|
# Generated automatically by config.status (libbacktrace) version-unused
|
||||||
# Libtool was configured on host fv-az198-447:
|
# Libtool was configured on host fv-az284-568:
|
||||||
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
|
# NOTE: Changes made to this file will be lost: look at ltmain.sh.
|
||||||
#
|
#
|
||||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
|
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
|
||||||
|
18
vendor/zerokit/CHANGELOG.md
vendored
18
vendor/zerokit/CHANGELOG.md
vendored
@ -1,8 +1,24 @@
|
|||||||
|
## Upcoming release
|
||||||
|
|
||||||
|
Release highlights:
|
||||||
|
- Allows consumers of zerokit RLN to set leaves to the Merkle Tree from an arbitrary index. Useful for batching updates to the Merkle Tree.
|
||||||
|
|
||||||
|
The full list of changes is below.
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Creation of `set_leaves_from`, which allows consumers to add leaves to a tree from a given starting index. `init_tree_with_leaves` internally uses `set_leaves_from`, with index 0.
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
- Renaming of `set_leaves` to `init_tree_with_leaves`, which is a more accurate representation of the function's utility.
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- None
|
||||||
|
|
||||||
## 2022-09-19 v0.1
|
## 2022-09-19 v0.1
|
||||||
|
|
||||||
Initial beta release.
|
Initial beta release.
|
||||||
|
|
||||||
This release contain:
|
This release contains:
|
||||||
|
|
||||||
- RLN Module with API to manage, compute and verify [RLN](https://rfc.vac.dev/spec/32/) zkSNARK proofs and RLN primitives.
|
- RLN Module with API to manage, compute and verify [RLN](https://rfc.vac.dev/spec/32/) zkSNARK proofs and RLN primitives.
|
||||||
- This can be consumed either as a Rust API or as a C FFI. The latter means it can be easily consumed through other environments, such as [Go](https://github.com/status-im/go-zerokit-rln/blob/master/rln/librln.h) or [Nim](https://github.com/status-im/nwaku/blob/4745c7872c69b5fd5c6ddab36df9c5c3d55f57c3/waku/v2/protocol/waku_rln_relay/waku_rln_relay_types.nim).
|
- This can be consumed either as a Rust API or as a C FFI. The latter means it can be easily consumed through other environments, such as [Go](https://github.com/status-im/go-zerokit-rln/blob/master/rln/librln.h) or [Nim](https://github.com/status-im/nwaku/blob/4745c7872c69b5fd5c6ddab36df9c5c3d55f57c3/waku/v2/protocol/waku_rln_relay/waku_rln_relay_types.nim).
|
||||||
|
@ -58,12 +58,20 @@ proc set_leaf*(ctx: ptr RLN, index: uint, input_buffer: ptr Buffer): bool {.impo
|
|||||||
## the input_buffer holds a serialized leaf of 32 bytes
|
## the input_buffer holds a serialized leaf of 32 bytes
|
||||||
## the return bool value indicates the success or failure of the operation
|
## the return bool value indicates the success or failure of the operation
|
||||||
|
|
||||||
proc set_leaves*(ctx: ptr RLN, input_buffer: ptr Buffer): bool {.importc: "set_leaves".}
|
proc init_tree_with_leaves*(ctx: ptr RLN, input_buffer: ptr Buffer): bool {.importc: "init_tree_with_leaves".}
|
||||||
## sets multiple leaves in the tree stored by ctx to the value passed by input_buffer
|
## sets multiple leaves in the tree stored by ctx to the value passed by input_buffer
|
||||||
## the input_buffer holds a serialized vector of leaves (32 bytes each)
|
## the input_buffer holds a serialized vector of leaves (32 bytes each)
|
||||||
|
## the input_buffer size is prefixed by a 8 bytes integer indicating the number of leaves
|
||||||
## leaves are set one after each other starting from index 0
|
## leaves are set one after each other starting from index 0
|
||||||
## the return bool value indicates the success or failure of the operation
|
## the return bool value indicates the success or failure of the operation
|
||||||
|
|
||||||
|
proc set_leaves_from*(ctx: ptr RLN, index: uint, input_buffer: ptr Buffer): bool {.importc: "set_leaves_from".}
|
||||||
|
## sets multiple leaves in the tree stored by ctx to the value passed by input_buffer
|
||||||
|
## the input_buffer holds a serialized vector of leaves (32 bytes each)
|
||||||
|
## the input_buffer size is prefixed by a 8 bytes integer indicating the number of leaves
|
||||||
|
## leaves are set one after each other starting from index `index`
|
||||||
|
## the return bool value indicates the success or failure of the operation
|
||||||
|
|
||||||
proc reset_tree*(ctx: ptr RLN, tree_height: uint): bool {.importc: "set_tree".}
|
proc reset_tree*(ctx: ptr RLN, tree_height: uint): bool {.importc: "set_tree".}
|
||||||
## resets the tree stored by ctx to the the empty tree (all leaves set to 0) of height tree_height
|
## resets the tree stored by ctx to the the empty tree (all leaves set to 0) of height tree_height
|
||||||
## the return bool value indicates the success or failure of the operation
|
## the return bool value indicates the success or failure of the operation
|
||||||
|
@ -95,6 +95,7 @@ type WakuRLNRelay* = ref object
|
|||||||
lastEpoch*: Epoch # the epoch of the last published rln message
|
lastEpoch*: Epoch # the epoch of the last published rln message
|
||||||
validMerkleRoots*: Deque[MerkleNode] # An array of valid merkle roots, which are updated in a FIFO fashion
|
validMerkleRoots*: Deque[MerkleNode] # An array of valid merkle roots, which are updated in a FIFO fashion
|
||||||
lastSeenMembershipIndex*: MembershipIndex # the last seen membership index
|
lastSeenMembershipIndex*: MembershipIndex # the last seen membership index
|
||||||
|
lastProcessedBlock*: BlockNumber # the last processed block number
|
||||||
|
|
||||||
type
|
type
|
||||||
MessageValidationResult* {.pure.} = enum
|
MessageValidationResult* {.pure.} = enum
|
||||||
|
@ -7,6 +7,7 @@ import
|
|||||||
std/[sequtils, tables, times, os, deques],
|
std/[sequtils, tables, times, os, deques],
|
||||||
chronicles, options, chronos, stint,
|
chronicles, options, chronos, stint,
|
||||||
confutils,
|
confutils,
|
||||||
|
strutils,
|
||||||
web3, json,
|
web3, json,
|
||||||
web3/ethtypes,
|
web3/ethtypes,
|
||||||
eth/keys,
|
eth/keys,
|
||||||
@ -41,7 +42,9 @@ type WakuRlnConfig* = object
|
|||||||
type
|
type
|
||||||
SpamHandler* = proc(wakuMessage: WakuMessage): void {.gcsafe, closure, raises: [Defect].}
|
SpamHandler* = proc(wakuMessage: WakuMessage): void {.gcsafe, closure, raises: [Defect].}
|
||||||
RegistrationHandler* = proc(txHash: string): void {.gcsafe, closure, raises: [Defect].}
|
RegistrationHandler* = proc(txHash: string): void {.gcsafe, closure, raises: [Defect].}
|
||||||
GroupUpdateHandler* = proc(pubkey: Uint256, index: Uint256): RlnRelayResult[void] {.gcsafe.}
|
GroupUpdateHandler* = proc(blockNumber: BlockNumber,
|
||||||
|
members: seq[MembershipTuple]): RlnRelayResult[void] {.gcsafe.}
|
||||||
|
MembershipTuple* = tuple[index: MembershipIndex, idComm: IDCommitment]
|
||||||
|
|
||||||
# membership contract interface
|
# membership contract interface
|
||||||
contract(MembershipContract):
|
contract(MembershipContract):
|
||||||
@ -158,7 +161,7 @@ proc register*(idComm: IDCommitment, ethAccountAddress: Option[Address], ethAcco
|
|||||||
# web3.privateKey = some(ethAccountPrivateKey)
|
# web3.privateKey = some(ethAccountPrivateKey)
|
||||||
var sender = web3.contractSender(MembershipContract, membershipContractAddress) # creates a Sender object with a web3 field and contract address of type Address
|
var sender = web3.contractSender(MembershipContract, membershipContractAddress) # creates a Sender object with a web3 field and contract address of type Address
|
||||||
|
|
||||||
debug "registering an id commitment", idComm=idComm.inHex
|
debug "registering an id commitment", idComm=idComm.inHex()
|
||||||
let pk = idComm.toUInt256()
|
let pk = idComm.toUInt256()
|
||||||
|
|
||||||
var txHash: TxHash
|
var txHash: TxHash
|
||||||
@ -185,7 +188,7 @@ proc register*(idComm: IDCommitment, ethAccountAddress: Option[Address], ethAcco
|
|||||||
eventIdCommUint = UInt256.fromBytesBE(argumentsBytes[0..31])
|
eventIdCommUint = UInt256.fromBytesBE(argumentsBytes[0..31])
|
||||||
eventIndex = UInt256.fromBytesBE(argumentsBytes[32..^1])
|
eventIndex = UInt256.fromBytesBE(argumentsBytes[32..^1])
|
||||||
eventIdComm = eventIdCommUint.toIDCommitment()
|
eventIdComm = eventIdCommUint.toIDCommitment()
|
||||||
debug "the identity commitment key extracted from tx log", eventIdComm=eventIdComm.inHex
|
debug "the identity commitment key extracted from tx log", eventIdComm=eventIdComm.inHex()
|
||||||
debug "the index of registered identity commitment key", eventIndex=eventIndex
|
debug "the index of registered identity commitment key", eventIndex=eventIndex
|
||||||
|
|
||||||
if eventIdComm != idComm:
|
if eventIdComm != idComm:
|
||||||
@ -353,16 +356,51 @@ proc proofVerify*(rlnInstance: ptr RLN,
|
|||||||
|
|
||||||
if not validProof:
|
if not validProof:
|
||||||
return ok(false)
|
return ok(false)
|
||||||
|
else:
|
||||||
return ok(true)
|
return ok(true)
|
||||||
|
|
||||||
proc insertMember*(rlnInstance: ptr RLN, idComm: IDCommitment): bool =
|
proc insertMember*(rlnInstance: ptr RLN, idComm: IDCommitment): bool =
|
||||||
|
## inserts a member to the tree
|
||||||
|
## returns true if the member is inserted successfully
|
||||||
|
## returns false if the member could not be inserted
|
||||||
var pkBuffer = toBuffer(idComm)
|
var pkBuffer = toBuffer(idComm)
|
||||||
let pkBufferPtr = addr pkBuffer
|
let pkBufferPtr = addr pkBuffer
|
||||||
|
|
||||||
# add the member to the tree
|
# add the member to the tree
|
||||||
var member_is_added = update_next_member(rlnInstance, pkBufferPtr)
|
let memberAdded = update_next_member(rlnInstance, pkBufferPtr)
|
||||||
return member_is_added
|
return memberAdded
|
||||||
|
|
||||||
|
proc serializeIdCommitments*(idComms: seq[IDCommitment]): seq[byte] =
|
||||||
|
## serializes a seq of IDCommitments to a byte seq
|
||||||
|
## the serialization is based on https://github.com/status-im/nwaku/blob/37bd29fbc37ce5cf636734e7dd410b1ed27b88c8/waku/v2/protocol/waku_rln_relay/rln.nim#L142
|
||||||
|
## the order of serialization is |id_commitment_len<8>|id_commitment<var>|
|
||||||
|
var idCommsBytes = newSeq[byte]()
|
||||||
|
|
||||||
|
# serialize the idComms, with its length prefixed
|
||||||
|
let len = toBytes(uint64(idComms.len), Endianness.littleEndian)
|
||||||
|
idCommsBytes.add(len)
|
||||||
|
|
||||||
|
for idComm in idComms:
|
||||||
|
idCommsBytes = concat(idCommsBytes, @idComm)
|
||||||
|
|
||||||
|
return idCommsBytes
|
||||||
|
|
||||||
|
proc insertMembers*(rlnInstance: ptr RLN,
|
||||||
|
index: MembershipIndex,
|
||||||
|
idComms: seq[IDCommitment]): bool =
|
||||||
|
## Insert multiple members i.e., identity commitments
|
||||||
|
## returns true if the insertion is successful
|
||||||
|
## returns false if any of the insertions fails
|
||||||
|
## Note: This proc is atomic, i.e., if any of the insertions fails, all the previous insertions are rolled back
|
||||||
|
|
||||||
|
# serialize the idComms
|
||||||
|
let idCommsBytes = serializeIdCommitments(idComms)
|
||||||
|
|
||||||
|
var idCommsBuffer = idCommsBytes.toBuffer()
|
||||||
|
let idCommsBufferPtr = addr idCommsBuffer
|
||||||
|
# add the member to the tree
|
||||||
|
let membersAdded = set_leaves_from(rlnInstance, index, idCommsBufferPtr)
|
||||||
|
return membersAdded
|
||||||
|
|
||||||
proc removeMember*(rlnInstance: ptr RLN, index: MembershipIndex): bool =
|
proc removeMember*(rlnInstance: ptr RLN, index: MembershipIndex): bool =
|
||||||
let deletion_success = delete_member(rlnInstance, index)
|
let deletion_success = delete_member(rlnInstance, index)
|
||||||
@ -392,14 +430,16 @@ proc updateValidRootQueue*(wakuRlnRelay: WakuRLNRelay, root: MerkleNode): void =
|
|||||||
# Push the next root into the queue
|
# Push the next root into the queue
|
||||||
wakuRlnRelay.validMerkleRoots.addLast(root)
|
wakuRlnRelay.validMerkleRoots.addLast(root)
|
||||||
|
|
||||||
proc insertMember*(wakuRlnRelay: WakuRLNRelay, idComm: IDCommitment): RlnRelayResult[void] =
|
proc insertMembers*(wakuRlnRelay: WakuRLNRelay,
|
||||||
## inserts a new id commitment into the local merkle tree, and adds the changed root to the
|
index: MembershipIndex,
|
||||||
|
idComms: seq[IDCommitment]): RlnRelayResult[void] =
|
||||||
|
## inserts a sequence of id commitments into the local merkle tree, and adds the changed root to the
|
||||||
## queue of valid roots
|
## queue of valid roots
|
||||||
## Returns an error if the insertion fails
|
## Returns an error if the insertion fails
|
||||||
waku_rln_membership_insertion_duration_seconds.nanosecondTime:
|
waku_rln_membership_insertion_duration_seconds.nanosecondTime:
|
||||||
let actionSucceeded = wakuRlnRelay.rlnInstance.insertMember(idComm)
|
let actionSucceeded = wakuRlnRelay.rlnInstance.insertMembers(index, idComms)
|
||||||
if not actionSucceeded:
|
if not actionSucceeded:
|
||||||
return err("could not insert id commitment into the merkle tree")
|
return err("could not insert id commitments into the merkle tree")
|
||||||
|
|
||||||
let rootAfterUpdate = ?wakuRlnRelay.rlnInstance.getMerkleRoot()
|
let rootAfterUpdate = ?wakuRlnRelay.rlnInstance.getMerkleRoot()
|
||||||
wakuRlnRelay.updateValidRootQueue(rootAfterUpdate)
|
wakuRlnRelay.updateValidRootQueue(rootAfterUpdate)
|
||||||
@ -453,12 +493,10 @@ proc calcMerkleRoot*(list: seq[IDCommitment]): RlnRelayResult[string] =
|
|||||||
let rln = rlnInstance.get()
|
let rln = rlnInstance.get()
|
||||||
|
|
||||||
# create a Merkle tree
|
# create a Merkle tree
|
||||||
for i in 0..list.len-1:
|
let membersAdded = rln.insertMembers(0, list)
|
||||||
var member_is_added = false
|
if not membersAdded:
|
||||||
member_is_added = rln.insertMember(list[i])
|
return err("could not insert members into the tree")
|
||||||
doAssert(member_is_added)
|
let root = rln.getMerkleRoot().value().inHex()
|
||||||
|
|
||||||
let root = rln.getMerkleRoot().value().inHex
|
|
||||||
return ok(root)
|
return ok(root)
|
||||||
|
|
||||||
proc createMembershipList*(n: int): RlnRelayResult[(
|
proc createMembershipList*(n: int): RlnRelayResult[(
|
||||||
@ -476,6 +514,7 @@ proc createMembershipList*(n: int): RlnRelayResult[(
|
|||||||
let rln = rlnInstance.get()
|
let rln = rlnInstance.get()
|
||||||
|
|
||||||
var output = newSeq[(string, string)]()
|
var output = newSeq[(string, string)]()
|
||||||
|
var idCommitments = newSeq[IDCommitment]()
|
||||||
for i in 0..n-1:
|
for i in 0..n-1:
|
||||||
|
|
||||||
# generate a key pair
|
# generate a key pair
|
||||||
@ -483,16 +522,17 @@ proc createMembershipList*(n: int): RlnRelayResult[(
|
|||||||
if keypairRes.isErr():
|
if keypairRes.isErr():
|
||||||
return err("could not generate a key pair: " & keypairRes.error())
|
return err("could not generate a key pair: " & keypairRes.error())
|
||||||
let keypair = keypairRes.get()
|
let keypair = keypairRes.get()
|
||||||
let keyTuple = (keypair.idKey.inHex, keypair.idCommitment.inHex)
|
let keyTuple = (keypair.idKey.inHex(), keypair.idCommitment.inHex())
|
||||||
output.add(keyTuple)
|
output.add(keyTuple)
|
||||||
|
|
||||||
# insert the key to the Merkle tree
|
idCommitments.add(keypair.idCommitment)
|
||||||
let inserted = rln.insertMember(keypair.idCommitment)
|
|
||||||
if not inserted:
|
|
||||||
return err("could not insert the key into the Merkle tree")
|
|
||||||
|
|
||||||
|
# Insert members into tree
|
||||||
|
let membersAdded = rln.insertMembers(0, idCommitments)
|
||||||
|
if not membersAdded:
|
||||||
|
return err("could not insert members into the tree")
|
||||||
|
|
||||||
let root = rln.getMerkleRoot().value().inHex
|
let root = rln.getMerkleRoot().value().inHex()
|
||||||
return ok((output, root))
|
return ok((output, root))
|
||||||
|
|
||||||
proc rlnRelayStaticSetUp*(rlnRelayMembershipIndex: MembershipIndex): RlnRelayResult[(Option[seq[
|
proc rlnRelayStaticSetUp*(rlnRelayMembershipIndex: MembershipIndex): RlnRelayResult[(Option[seq[
|
||||||
@ -663,14 +703,14 @@ proc validateMessage*(rlnPeer: WakuRLNRelay, msg: WakuMessage,
|
|||||||
if gap > MaxEpochGap:
|
if gap > MaxEpochGap:
|
||||||
# message's epoch is too old or too ahead
|
# message's epoch is too old or too ahead
|
||||||
# accept messages whose epoch is within +-MaxEpochGap from the current epoch
|
# accept messages whose epoch is within +-MaxEpochGap from the current epoch
|
||||||
debug "invalid message: epoch gap exceeds a threshold", gap = gap,
|
warn "invalid message: epoch gap exceeds a threshold", gap = gap,
|
||||||
payload = string.fromBytes(msg.payload)
|
payload = string.fromBytes(msg.payload)
|
||||||
waku_rln_invalid_messages_total.inc(labelValues=["invalid_epoch"])
|
waku_rln_invalid_messages_total.inc(labelValues=["invalid_epoch"])
|
||||||
return MessageValidationResult.Invalid
|
return MessageValidationResult.Invalid
|
||||||
|
|
||||||
## TODO: FIXME after resolving this issue https://github.com/status-im/nwaku/issues/1247
|
## TODO: FIXME after resolving this issue https://github.com/status-im/nwaku/issues/1247
|
||||||
if not rlnPeer.validateRoot(msg.proof.merkleRoot):
|
if not rlnPeer.validateRoot(msg.proof.merkleRoot):
|
||||||
debug "invalid message: provided root does not belong to acceptable window of roots", provided=msg.proof.merkleRoot, validRoots=rlnPeer.validMerkleRoots.mapIt(it.inHex)
|
debug "invalid message: provided root does not belong to acceptable window of roots", provided=msg.proof.merkleRoot, validRoots=rlnPeer.validMerkleRoots.mapIt(it.inHex())
|
||||||
waku_rln_invalid_messages_total.inc(labelValues=["invalid_root"])
|
waku_rln_invalid_messages_total.inc(labelValues=["invalid_root"])
|
||||||
# return MessageValidationResult.Invalid
|
# return MessageValidationResult.Invalid
|
||||||
|
|
||||||
@ -685,6 +725,7 @@ proc validateMessage*(rlnPeer: WakuRLNRelay, msg: WakuMessage,
|
|||||||
|
|
||||||
if proofVerificationRes.isErr():
|
if proofVerificationRes.isErr():
|
||||||
waku_rln_errors_total.inc(labelValues=["proof_verification"])
|
waku_rln_errors_total.inc(labelValues=["proof_verification"])
|
||||||
|
warn "invalid message: proof verification failed", payload = string.fromBytes(msg.payload)
|
||||||
return MessageValidationResult.Invalid
|
return MessageValidationResult.Invalid
|
||||||
if not proofVerificationRes.value():
|
if not proofVerificationRes.value():
|
||||||
# invalid proof
|
# invalid proof
|
||||||
@ -741,11 +782,9 @@ proc appendRLNProof*(rlnPeer: WakuRLNRelay, msg: var WakuMessage,
|
|||||||
proc addAll*(wakuRlnRelay: WakuRLNRelay, list: seq[IDCommitment]): RlnRelayResult[void] =
|
proc addAll*(wakuRlnRelay: WakuRLNRelay, list: seq[IDCommitment]): RlnRelayResult[void] =
|
||||||
# add members to the Merkle tree of the `rlnInstance`
|
# add members to the Merkle tree of the `rlnInstance`
|
||||||
## Returns an error if it cannot add any member to the Merkle tree
|
## Returns an error if it cannot add any member to the Merkle tree
|
||||||
for i in 0..list.len-1:
|
let membersAdded = wakuRlnRelay.insertMembers(0, list)
|
||||||
let member = list[i]
|
if not membersAdded.isOk():
|
||||||
let memberAdded = wakuRlnRelay.insertMember(member)
|
return err("failed to add members to the Merkle tree")
|
||||||
if not memberAdded.isOk():
|
|
||||||
return err(memberAdded.error())
|
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
proc generateGroupUpdateHandler(rlnPeer: WakuRLNRelay): GroupUpdateHandler =
|
proc generateGroupUpdateHandler(rlnPeer: WakuRLNRelay): GroupUpdateHandler =
|
||||||
@ -753,53 +792,84 @@ proc generateGroupUpdateHandler(rlnPeer: WakuRLNRelay): GroupUpdateHandler =
|
|||||||
## TODO: check the index and the pubkey depending on
|
## TODO: check the index and the pubkey depending on
|
||||||
## the group update operation
|
## the group update operation
|
||||||
var handler: GroupUpdateHandler
|
var handler: GroupUpdateHandler
|
||||||
handler = proc(pubkey: Uint256, index: Uint256): RlnRelayResult[void] =
|
handler = proc(blockNumber: BlockNumber, members: seq[MembershipTuple]): RlnRelayResult[void] =
|
||||||
var pk: IDCommitment
|
let startingIndex = members[0].index
|
||||||
try:
|
debug "starting index", startingIndex = startingIndex, members = members.mapIt(it.idComm.inHex())
|
||||||
pk = pubkey.toIDCommitment()
|
let isSuccessful = rlnPeer.insertMembers(startingIndex, members.mapIt(it.idComm))
|
||||||
except:
|
|
||||||
return err("invalid pubkey")
|
|
||||||
let isSuccessful = rlnPeer.insertMember(pk)
|
|
||||||
if isSuccessful.isErr():
|
if isSuccessful.isErr():
|
||||||
return err("failed to add a new member to the Merkle tree")
|
return err("failed to add new members to the Merkle tree")
|
||||||
else:
|
else:
|
||||||
debug "new member added to the Merkle tree", pubkey=pubkey, index=index
|
debug "new members added to the Merkle tree", pubkeys=members.mapIt(it.idComm.inHex()) , startingIndex=startingIndex
|
||||||
debug "acceptable window", validRoots=rlnPeer.validMerkleRoots.mapIt(it.inHex)
|
debug "acceptable window", validRoots=rlnPeer.validMerkleRoots.mapIt(it.inHex())
|
||||||
let membershipIndex = index.toMembershipIndex()
|
let lastIndex = members[0].index + members.len.uint - 1
|
||||||
if rlnPeer.lastSeenMembershipIndex != membershipIndex + 1:
|
let indexGap = startingIndex - rlnPeer.lastSeenMembershipIndex
|
||||||
warn "membership index gap, may have lost connection", gap = membershipIndex - rlnPeer.lastSeenMembershipIndex
|
if not (toSeq(startingIndex..lastIndex) == members.mapIt(it.index)):
|
||||||
rlnPeer.lastSeenMembershipIndex = membershipIndex
|
return err("the indexes of the new members are not in order")
|
||||||
|
if indexGap != 1.uint:
|
||||||
|
warn "membership index gap, may have lost connection", lastIndex, currIndex=rlnPeer.lastSeenMembershipIndex, indexGap = indexGap
|
||||||
|
rlnPeer.lastSeenMembershipIndex = lastIndex
|
||||||
|
rlnPeer.lastProcessedBlock = blockNumber
|
||||||
|
debug "last processed block", blockNumber = blockNumber
|
||||||
return ok()
|
return ok()
|
||||||
return handler
|
return handler
|
||||||
|
|
||||||
proc subscribeToMemberRegistrations(web3: Web3,
|
proc parse*(event: type MemberRegistered,
|
||||||
|
log: JsonNode): RlnRelayResult[MembershipTuple] =
|
||||||
|
## parses the `data` parameter of the `MemberRegistered` event `log`
|
||||||
|
## returns an error if it cannot parse the `data` parameter
|
||||||
|
var pubkey: UInt256
|
||||||
|
var index: UInt256
|
||||||
|
var data: string
|
||||||
|
# Remove the 0x prefix
|
||||||
|
try:
|
||||||
|
data = strip0xPrefix(log["data"].getStr())
|
||||||
|
except CatchableError:
|
||||||
|
return err("failed to parse the data field of the MemberRegistered event: " & getCurrentExceptionMsg())
|
||||||
|
var offset = 0
|
||||||
|
try:
|
||||||
|
# Parse the pubkey
|
||||||
|
offset += decode(data, offset, pubkey)
|
||||||
|
# Parse the index
|
||||||
|
offset += decode(data, offset, index)
|
||||||
|
return ok((index: index.toMembershipIndex(),
|
||||||
|
idComm: pubkey.toIDCommitment()))
|
||||||
|
except:
|
||||||
|
return err("failed to parse the data field of the MemberRegistered event")
|
||||||
|
|
||||||
|
type BlockTable = OrderedTable[BlockNumber, seq[MembershipTuple]]
|
||||||
|
proc getHistoricalEvents*(ethClientUri: string,
|
||||||
contractAddress: Address,
|
contractAddress: Address,
|
||||||
fromBlock: string = "0x0",
|
fromBlock: string = "0x0",
|
||||||
handler: GroupUpdateHandler): Future[Subscription] {.async, gcsafe.} =
|
toBlock: string = "latest"): Future[RlnRelayResult[BlockTable]] {.async, gcsafe.} =
|
||||||
## subscribes to member registrations, on a given membership group contract
|
## `ethClientUri` is the URI of the Ethereum client
|
||||||
## `fromBlock` indicates the block number from which the subscription starts
|
## `contractAddress` is the address of the contract
|
||||||
## `handler` is a callback that is called when a new member is registered
|
## `fromBlock` is the block number from which the events are fetched
|
||||||
## the callback is called with the pubkey and the index of the new member
|
## `toBlock` is the block number to which the events are fetched
|
||||||
## TODO: need a similar proc for member deletions
|
## returns a table that maps block numbers to the list of members registered in that block
|
||||||
var contractObj = web3.contractSender(MembershipContract, contractAddress)
|
## returns an error if it cannot retrieve the historical events
|
||||||
|
let web3 = await newWeb3(ethClientUri)
|
||||||
|
let contract = web3.contractSender(MembershipContract, contractAddress)
|
||||||
|
# Get the historical events, and insert memberships into the tree
|
||||||
|
let historicalEvents = await contract.getJsonLogs(MemberRegistered,
|
||||||
|
fromBlock=some(fromBlock.blockId()),
|
||||||
|
toBlock=some(toBlock.blockId()))
|
||||||
|
# Create a table that maps block numbers to the list of members registered in that block
|
||||||
|
var blockTable = OrderedTable[BlockNumber, seq[MembershipTuple]]()
|
||||||
|
for log in historicalEvents:
|
||||||
|
# batch according to log.blockNumber
|
||||||
|
let blockNumber = parseHexInt(log["blockNumber"].getStr()).uint
|
||||||
|
let parsedEventRes = parse(MemberRegistered, log)
|
||||||
|
|
||||||
let onMemberRegistered = proc (pubkey: Uint256, index: Uint256) {.gcsafe.} =
|
if parsedEventRes.isErr():
|
||||||
debug "onRegister", pubkey = pubkey, index = index
|
error "failed to parse the MemberRegistered event", error=parsedEventRes.error()
|
||||||
var groupUpdateRes: RlnRelayResult[void]
|
return err("failed to parse the MemberRegistered event")
|
||||||
try:
|
let parsedEvent = parsedEventRes.get()
|
||||||
groupUpdateRes = handler(pubkey, index)
|
# Add the parsed event to the table
|
||||||
except Exception as err:
|
if blockTable.hasKey(blockNumber):
|
||||||
error "failed to handle group update", err = err.msg
|
blockTable[blockNumber].add(parsedEvent)
|
||||||
if groupUpdateRes.isErr():
|
else:
|
||||||
error "Error handling new member registration", err=groupUpdateRes.error()
|
blockTable[blockNumber] = @[parsedEvent]
|
||||||
|
return ok(blockTable)
|
||||||
let onError = proc (err: CatchableError) =
|
|
||||||
error "Error in subscription", err=err.msg
|
|
||||||
|
|
||||||
return await contractObj.subscribe(MemberRegistered,
|
|
||||||
%*{"fromBlock": fromBlock, "address": contractAddress},
|
|
||||||
onMemberRegistered,
|
|
||||||
onError)
|
|
||||||
|
|
||||||
proc subscribeToGroupEvents*(ethClientUri: string,
|
proc subscribeToGroupEvents*(ethClientUri: string,
|
||||||
ethAccountAddress: Option[Address] = none(Address),
|
ethAccountAddress: Option[Address] = none(Address),
|
||||||
@ -809,25 +879,61 @@ proc subscribeToGroupEvents*(ethClientUri: string,
|
|||||||
## connects to the eth client whose URI is supplied as `ethClientUri`
|
## connects to the eth client whose URI is supplied as `ethClientUri`
|
||||||
## subscribes to the `MemberRegistered` event emitted from the `MembershipContract` which is available on the supplied `contractAddress`
|
## subscribes to the `MemberRegistered` event emitted from the `MembershipContract` which is available on the supplied `contractAddress`
|
||||||
## it collects all the events starting from the given `blockNumber`
|
## it collects all the events starting from the given `blockNumber`
|
||||||
## for every received event, it calls the `handler`
|
## for every received block, it calls the `handler`
|
||||||
let web3 = await newWeb3(ethClientUri)
|
let web3 = await newWeb3(ethClientUri)
|
||||||
var latestBlock: Quantity
|
let contract = web3.contractSender(MembershipContract, contractAddress)
|
||||||
|
|
||||||
|
let blockTableRes = await getHistoricalEvents(ethClientUri,
|
||||||
|
contractAddress,
|
||||||
|
fromBlock=blockNumber)
|
||||||
|
if blockTableRes.isErr():
|
||||||
|
error "failed to retrieve historical events", error=blockTableRes.error
|
||||||
|
return
|
||||||
|
let blockTable = blockTableRes.get()
|
||||||
|
# Update MT by batch
|
||||||
|
for blockNumber, members in blockTable.pairs():
|
||||||
|
debug "updating the Merkle tree", blockNumber=blockNumber, members=members
|
||||||
|
let res = handler(blockNumber, members)
|
||||||
|
if res.isErr():
|
||||||
|
error "failed to update the Merkle tree", error=res.error
|
||||||
|
|
||||||
|
# We don't need the block table after this point
|
||||||
|
discard blockTable
|
||||||
|
|
||||||
|
var latestBlock: BlockNumber
|
||||||
|
let handleLog = proc(blockHeader: BlockHeader) {.async, gcsafe.} =
|
||||||
|
try:
|
||||||
|
let membershipRegistrationLogs = await contract.getJsonLogs(MemberRegistered,
|
||||||
|
blockHash = some(blockheader.hash))
|
||||||
|
if membershipRegistrationLogs.len == 0:
|
||||||
|
return
|
||||||
|
var members: seq[MembershipTuple]
|
||||||
|
for log in membershipRegistrationLogs:
|
||||||
|
let parsedEventRes = parse(MemberRegistered, log)
|
||||||
|
if parsedEventRes.isErr():
|
||||||
|
fatal "failed to parse the MemberRegistered event", error=parsedEventRes.error()
|
||||||
|
return
|
||||||
|
let parsedEvent = parsedEventRes.get()
|
||||||
|
members.add(parsedEvent)
|
||||||
|
let res = handler(blockHeader.number.uint, members)
|
||||||
|
if res.isErr():
|
||||||
|
error "failed to update the Merkle tree", error=res.error
|
||||||
|
except CatchableError:
|
||||||
|
warn "failed to get logs", error=getCurrentExceptionMsg()
|
||||||
|
return
|
||||||
let newHeadCallback = proc (blockheader: BlockHeader) {.gcsafe.} =
|
let newHeadCallback = proc (blockheader: BlockHeader) {.gcsafe.} =
|
||||||
latestBlock = blockheader.number
|
latestBlock = blockheader.number.uint
|
||||||
debug "block received", blockNumber = latestBlock
|
debug "block received", blockNumber = latestBlock
|
||||||
|
# get logs from the last block
|
||||||
|
try:
|
||||||
|
asyncSpawn handleLog(blockHeader)
|
||||||
|
except CatchableError:
|
||||||
|
warn "failed to handle log: ", error=getCurrentExceptionMsg()
|
||||||
|
|
||||||
let newHeadErrorHandler = proc (err: CatchableError) {.gcsafe.} =
|
let newHeadErrorHandler = proc (err: CatchableError) {.gcsafe.} =
|
||||||
error "Error from subscription: ", err=err.msg
|
error "Error from subscription: ", err=err.msg
|
||||||
discard await web3.subscribeForBlockHeaders(newHeadCallback, newHeadErrorHandler)
|
discard await web3.subscribeForBlockHeaders(newHeadCallback, newHeadErrorHandler)
|
||||||
|
|
||||||
proc startSubscription(web3: Web3) {.async, gcsafe.} =
|
|
||||||
# subscribe to the MemberRegistered events
|
|
||||||
# TODO: can do similarly for deletion events, though it is not yet supported
|
|
||||||
# TODO: add block number for reconnection logic
|
|
||||||
discard await subscribeToMemberRegistrations(web3 = web3,
|
|
||||||
contractAddress = contractAddress,
|
|
||||||
handler = handler)
|
|
||||||
|
|
||||||
await startSubscription(web3)
|
|
||||||
web3.onDisconnect = proc() =
|
web3.onDisconnect = proc() =
|
||||||
debug "connection to ethereum node dropped", lastBlock = latestBlock
|
debug "connection to ethereum node dropped", lastBlock = latestBlock
|
||||||
|
|
||||||
@ -925,11 +1031,9 @@ proc mountRlnRelayStatic*(node: WakuNode,
|
|||||||
contentTopic: contentTopic)
|
contentTopic: contentTopic)
|
||||||
|
|
||||||
# add members to the Merkle tree
|
# add members to the Merkle tree
|
||||||
for index in 0..group.len-1:
|
let membersAdded = rlnPeer.insertMembers(0, group)
|
||||||
let member = group[index]
|
if membersAdded.isErr():
|
||||||
let memberAdded = rlnPeer.insertMember(member)
|
return err("member addition to the Merkle tree failed: " & membersAdded.error)
|
||||||
if memberAdded.isErr():
|
|
||||||
return err("member addition to the Merkle tree failed: " & memberAdded.error())
|
|
||||||
|
|
||||||
# adds a topic validator for the supplied pubsub topic at the relay protocol
|
# adds a topic validator for the supplied pubsub topic at the relay protocol
|
||||||
# messages published on this pubsub topic will be relayed upon a successful validation, otherwise they will be dropped
|
# messages published on this pubsub topic will be relayed upon a successful validation, otherwise they will be dropped
|
||||||
@ -1096,8 +1200,8 @@ proc mount(node: WakuNode,
|
|||||||
if mountRes.isErr():
|
if mountRes.isErr():
|
||||||
return err("Failed to mount WakuRLNRelay: " & mountRes.error())
|
return err("Failed to mount WakuRLNRelay: " & mountRes.error())
|
||||||
|
|
||||||
info "membership id key", idkey=memKeyPairOpt.get().idKey.inHex
|
info "membership id key", idkey=memKeyPairOpt.get().idKey.inHex()
|
||||||
info "membership id commitment key", idCommitmentkey=memKeyPairOpt.get().idCommitment.inHex
|
info "membership id commitment key", idCommitmentkey=memKeyPairOpt.get().idCommitment.inHex()
|
||||||
|
|
||||||
# check the correct construction of the tree by comparing the calculated root against the expected root
|
# check the correct construction of the tree by comparing the calculated root against the expected root
|
||||||
# no error should happen as it is already captured in the unit tests
|
# no error should happen as it is already captured in the unit tests
|
||||||
@ -1111,7 +1215,7 @@ proc mount(node: WakuNode,
|
|||||||
|
|
||||||
let root = rootRes.value()
|
let root = rootRes.value()
|
||||||
|
|
||||||
if root.inHex != expectedRoot:
|
if root.inHex() != expectedRoot:
|
||||||
error "root mismatch: something went wrong not in Merkle tree construction"
|
error "root mismatch: something went wrong not in Merkle tree construction"
|
||||||
debug "the calculated root", root
|
debug "the calculated root", root
|
||||||
info "WakuRLNRelay is mounted successfully", pubsubtopic=conf.rlnRelayPubsubTopic, contentTopic=conf.rlnRelayContentTopic
|
info "WakuRLNRelay is mounted successfully", pubsubtopic=conf.rlnRelayPubsubTopic, contentTopic=conf.rlnRelayContentTopic
|
||||||
|
Loading…
x
Reference in New Issue
Block a user