deploy: 6c8ab0ab0f76fe765d95ef2f7bfb88d691a18bf7

This commit is contained in:
staheri14 2022-06-17 22:29:14 +00:00
parent d1f7da16c7
commit 3300ada856
9 changed files with 403 additions and 173 deletions

View File

@ -511,12 +511,12 @@ proc processInput(rfd: AsyncFD, rng: ref BrHmacDrbgContext) {.async.} =
showChatPrompt(chat) showChatPrompt(chat)
# set up rln relay inputs # set up rln relay inputs
let (groupOpt, memKeyPairOpt, memIndexOpt) = rlnRelaySetUp(conf.rlnRelayMemIndex) let (groupOpt, memKeyPairOpt, memIndexOpt) = rlnRelayStaticSetUp(conf.rlnRelayMemIndex)
if memIndexOpt.isNone: if memIndexOpt.isNone:
error "failed to mount WakuRLNRelay" error "failed to mount WakuRLNRelay"
else: else:
# mount rlnrelay in offline mode (for now) # mount rlnrelay in offline mode (for now)
waitFor node.mountRlnRelay(groupOpt = groupOpt, memKeyPairOpt = memKeyPairOpt, memIndexOpt= memIndexOpt, onchainMode = false, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic, spamHandler = some(spamHandler)) node.mountRlnRelayStatic(group = groupOpt.get(), memKeyPair = memKeyPairOpt.get(), memIndex = memIndexOpt.get(), pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic, spamHandler = some(spamHandler))
debug "membership id key", idkey=memKeyPairOpt.get().idKey.toHex debug "membership id key", idkey=memKeyPairOpt.get().idKey.toHex
debug "membership id commitment key", idCommitmentkey=memKeyPairOpt.get().idCommitment.toHex debug "membership id commitment key", idCommitmentkey=memKeyPairOpt.get().idCommitment.toHex

View File

@ -45,10 +45,9 @@ procSuite "Waku rln relay":
# -------- mount rln-relay in the off-chain mode # -------- mount rln-relay in the off-chain mode
node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC]) node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
await node.mountRlnRelay(groupOpt = some(groupIDCommitments), node.mountRlnRelayStatic(group = groupIDCommitments,
memKeyPairOpt = some(groupKeyPairs[index]), memKeyPair = groupKeyPairs[index],
memIndexOpt = some(index), memIndex = index,
onchainMode = false,
pubsubTopic = RLNRELAY_PUBSUB_TOPIC, pubsubTopic = RLNRELAY_PUBSUB_TOPIC,
contentTopic = RLNRELAY_CONTENT_TOPIC) contentTopic = RLNRELAY_CONTENT_TOPIC)

View File

@ -155,7 +155,6 @@ procSuite "Waku-rln-relay":
rlnInstance.isOk == true rlnInstance.isOk == true
var rln = rlnInstance.value var rln = rlnInstance.value
# create rln membership key pair
let keyPair = rln.membershipKeyGen() let keyPair = rln.membershipKeyGen()
check: check:
keyPair.isSome keyPair.isSome
@ -273,7 +272,8 @@ procSuite "Waku-rln-relay":
check: check:
is_successful is_successful
asyncTest "mounting waku rln-relay":
asyncTest "mounting waku rln-relay: check correct Merkle tree construction in the static/off-chain group management":
# preparation ------------------------------ # preparation ------------------------------
let let
nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[] nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[]
@ -281,17 +281,6 @@ procSuite "Waku-rln-relay":
Port(60000)) Port(60000))
await node.start() await node.start()
# deploy the contract
let membershipContractAddress = await uploadRLNContract(ETH_CLIENT)
# prepare rln-relay inputs
let
web3 = await newWeb3(ETH_CLIENT)
accounts = await web3.provider.eth_accounts()
# choose one of the existing account for the rln-relay peer
ethAccountAddress = accounts[0]
await web3.close()
# create current peer's pk # create current peer's pk
var rlnInstance = createRLNInstance() var rlnInstance = createRLNInstance()
check: check:
@ -321,18 +310,16 @@ procSuite "Waku-rln-relay":
member_is_added = rln.insertMember(memberKeypair.get().idCommitment) member_is_added = rln.insertMember(memberKeypair.get().idCommitment)
doAssert(member_is_added) doAssert(member_is_added)
debug "member key", key = memberKeypair.get().idCommitment.toHex debug "member key", key = memberKeypair.get().idCommitment.toHex
let expectedRoot = rln.getMerkleRoot().value().toHex let expectedRoot = rln.getMerkleRoot().value().toHex
debug "expected root ", expectedRoot debug "expected root ", expectedRoot
# test ------------------------------ # test ------------------------------
# start rln-relay # start rln-relay
node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC]) node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
await node.mountRlnRelay(ethClientAddrOpt = some(EthClient), node.mountRlnRelayStatic(group = group,
ethAccAddrOpt = some(ethAccountAddress), memKeyPair = keypair.get(),
memContractAddOpt = some(membershipContractAddress), memIndex = index,
groupOpt = some(group),
memKeyPairOpt = some(keypair.get()),
memIndexOpt = some(index),
pubsubTopic = RLNRELAY_PUBSUB_TOPIC, pubsubTopic = RLNRELAY_PUBSUB_TOPIC,
contentTopic = RLNRELAY_CONTENT_TOPIC) contentTopic = RLNRELAY_CONTENT_TOPIC)
let calculatedRoot = node.wakuRlnRelay.rlnInstance.getMerkleRoot().value().toHex let calculatedRoot = node.wakuRlnRelay.rlnInstance.getMerkleRoot().value().toHex
@ -342,3 +329,144 @@ procSuite "Waku-rln-relay":
expectedRoot == calculatedRoot expectedRoot == calculatedRoot
await node.stop() await node.stop()
asyncTest "mounting waku rln-relay: check correct Merkle tree construction in the dynamic/onchain group management":
# preparation ------------------------------
let
nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[]
node = WakuNode.new(nodeKey, ValidIpAddress.init("0.0.0.0"), Port(60000))
await node.start()
# deploy the contract
let contractAddress = await uploadRLNContract(ETH_CLIENT)
# prepare rln-relay inputs
let
web3 = await newWeb3(ETH_CLIENT)
accounts = await web3.provider.eth_accounts()
# choose one of the existing accounts for the rln-relay peer
ethAccountAddress = accounts[0]
web3.defaultAccount = accounts[0]
# create an rln instance
var rlnInstance = createRLNInstance()
check:
rlnInstance.isOk == true
var rln = rlnInstance.value
# create two rln key pairs
let
keyPair1 = rln.membershipKeyGen()
keyPair2 = rln.membershipKeyGen()
check:
keyPair1.isSome
keyPair2.isSome
let
pk1 = keyPair1.get().idCommitment.toUInt256()
pk2 = keyPair2.get().idCommitment.toUInt256()
debug "member key1", key = keyPair1.get().idCommitment.toHex
debug "member key2", key = keyPair2.get().idCommitment.toHex
# add the rln keys to the Merkle tree
let
member_is_added1 = rln.insertMember(keyPair1.get().idCommitment)
member_is_added2 = rln.insertMember(keyPair2.get().idCommitment)
doAssert(member_is_added1)
doAssert(member_is_added2)
# get the Merkle root
let expectedRoot = rln.getMerkleRoot().value().toHex
# prepare a contract sender to interact with it
var contractObj = web3.contractSender(MembershipContract,
contractAddress) # creates a Sender object with a web3 field and contract address of type Address
# register the members to the contract
let tx1Hash = await contractObj.register(pk1).send(value = MEMBERSHIP_FEE)
debug "a member is registered", tx1 = tx1Hash
# register another member to the contract
let tx2Hash = await contractObj.register(pk2).send(value = MEMBERSHIP_FEE)
debug "a member is registered", tx2 = tx2Hash
# test ------------------------------
# start rln-relay
node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
await node.mountRlnRelayDynamic(ethClientAddr = EthClient,
ethAccAddr = ethAccountAddress,
memContractAddr = contractAddress,
memKeyPair = keyPair1,
memIndex = some(MembershipIndex(0)),
pubsubTopic = RLNRELAY_PUBSUB_TOPIC,
contentTopic = RLNRELAY_CONTENT_TOPIC)
await sleepAsync(2000) # wait for the event to reach the group handler
# rln pks are inserted into the rln peer's Merkle tree and the resulting root
# is expected to be the same as the calculatedRoot i.e., the one calculated outside of the mountRlnRelayDynamic proc
let calculatedRoot = node.wakuRlnRelay.rlnInstance.getMerkleRoot().value().toHex
debug "calculated root ", calculatedRoot=calculatedRoot
debug "expected root ", expectedRoot=expectedRoot
check:
expectedRoot == calculatedRoot
await web3.close()
await node.stop()
asyncTest "mounting waku rln-relay: check correct registration of peers without rln-relay credentials in dynamic/on-chain mode":
# deploy the contract
let contractAddress = await uploadRLNContract(ETH_CLIENT)
# prepare rln-relay inputs
let
web3 = await newWeb3(ETH_CLIENT)
accounts = await web3.provider.eth_accounts()
# choose two of the existing accounts for the rln-relay peers
ethAccountAddress1 = accounts[0]
ethAccountAddress2 = accounts[1]
await web3.close()
# prepare two nodes
let
nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[]
node = WakuNode.new(nodeKey, ValidIpAddress.init("0.0.0.0"), Port(60000))
await node.start()
let
nodeKey2 = crypto.PrivateKey.random(Secp256k1, rng[])[]
node2 = WakuNode.new(nodeKey2, ValidIpAddress.init("0.0.0.0"), Port(60001))
await node2.start()
# start rln-relay on the first node, leave rln-relay credentials empty
node.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
await node.mountRlnRelayDynamic(ethClientAddr = EthClient,
ethAccAddr = ethAccountAddress1,
memContractAddr = contractAddress,
memKeyPair = none(MembershipKeyPair),
memIndex = none(MembershipIndex),
pubsubTopic = RLNRELAY_PUBSUB_TOPIC,
contentTopic = RLNRELAY_CONTENT_TOPIC)
# start rln-relay on the second node, leave rln-relay credentials empty
node2.mountRelay(@[RLNRELAY_PUBSUB_TOPIC])
await node2.mountRlnRelayDynamic(ethClientAddr = EthClient,
ethAccAddr = ethAccountAddress2,
memContractAddr = contractAddress,
memKeyPair = none(MembershipKeyPair),
memIndex = none(MembershipIndex),
pubsubTopic = RLNRELAY_PUBSUB_TOPIC,
contentTopic = RLNRELAY_CONTENT_TOPIC)
# the two nodes should be registered into the contract
# since nodes are spun up sequentially
# the first node has index 0 whereas the second node gets index 1
check:
node.wakuRlnRelay.membershipIndex == MembershipIndex(0)
node2.wakuRlnRelay.membershipIndex == MembershipIndex(1)
await node.stop()
await node2.stop()

View File

@ -725,36 +725,33 @@ procSuite "WakuNode":
# set up three nodes # set up three nodes
# node1 # node1
node1.mountRelay(@[rlnRelayPubSubTopic]) node1.mountRelay(@[rlnRelayPubSubTopic])
let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = rlnRelaySetUp(1) # set up rln relay inputs let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = rlnRelayStaticSetUp(1) # set up rln relay inputs
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
waitFor node1.mountRlnRelay(groupOpt = groupOpt1, node1.mountRlnRelayStatic(group = groupOpt1.get(),
memKeyPairOpt = memKeyPairOpt1, memKeyPair = memKeyPairOpt1.get(),
memIndexOpt= memIndexOpt1, memIndex = memIndexOpt1.get(),
onchainMode = false,
pubsubTopic = rlnRelayPubSubTopic, pubsubTopic = rlnRelayPubSubTopic,
contentTopic = contentTopic) contentTopic = contentTopic)
await node1.start() await node1.start()
# node 2 # node 2
node2.mountRelay(@[rlnRelayPubSubTopic]) node2.mountRelay(@[rlnRelayPubSubTopic])
let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = rlnRelaySetUp(2) # set up rln relay inputs let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = rlnRelayStaticSetUp(2) # set up rln relay inputs
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
waitFor node2.mountRlnRelay(groupOpt = groupOpt2, node2.mountRlnRelayStatic(group = groupOpt2.get(),
memKeyPairOpt = memKeyPairOpt2, memKeyPair = memKeyPairOpt2.get(),
memIndexOpt= memIndexOpt2, memIndex = memIndexOpt2.get(),
onchainMode = false,
pubsubTopic = rlnRelayPubSubTopic, pubsubTopic = rlnRelayPubSubTopic,
contentTopic = contentTopic) contentTopic = contentTopic)
await node2.start() await node2.start()
# node 3 # node 3
node3.mountRelay(@[rlnRelayPubSubTopic]) node3.mountRelay(@[rlnRelayPubSubTopic])
let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = rlnRelaySetUp(3) # set up rln relay inputs let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = rlnRelayStaticSetUp(3) # set up rln relay inputs
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
waitFor node3.mountRlnRelay(groupOpt = groupOpt3, node3.mountRlnRelayStatic(group = groupOpt3.get(),
memKeyPairOpt = memKeyPairOpt3, memKeyPair = memKeyPairOpt3.get(),
memIndexOpt= memIndexOpt3, memIndex = memIndexOpt3.get(),
onchainMode = false,
pubsubTopic = rlnRelayPubSubTopic, pubsubTopic = rlnRelayPubSubTopic,
contentTopic = contentTopic) contentTopic = contentTopic)
await node3.start() await node3.start()
@ -818,36 +815,33 @@ procSuite "WakuNode":
# set up three nodes # set up three nodes
# node1 # node1
node1.mountRelay(@[rlnRelayPubSubTopic]) node1.mountRelay(@[rlnRelayPubSubTopic])
let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = rlnRelaySetUp(1) # set up rln relay inputs let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = rlnRelayStaticSetUp(1) # set up rln relay inputs
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
waitFor node1.mountRlnRelay(groupOpt = groupOpt1, node1.mountRlnRelayStatic(group = groupOpt1.get(),
memKeyPairOpt = memKeyPairOpt1, memKeyPair = memKeyPairOpt1.get(),
memIndexOpt= memIndexOpt1, memIndex = memIndexOpt1.get(),
onchainMode = false,
pubsubTopic = rlnRelayPubSubTopic, pubsubTopic = rlnRelayPubSubTopic,
contentTopic = contentTopic) contentTopic = contentTopic)
await node1.start() await node1.start()
# node 2 # node 2
node2.mountRelay(@[rlnRelayPubSubTopic]) node2.mountRelay(@[rlnRelayPubSubTopic])
let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = rlnRelaySetUp(2) # set up rln relay inputs let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = rlnRelayStaticSetUp(2) # set up rln relay inputs
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
waitFor node2.mountRlnRelay(groupOpt = groupOpt2, node2.mountRlnRelayStatic(group = groupOpt2.get(),
memKeyPairOpt = memKeyPairOpt2, memKeyPair = memKeyPairOpt2.get(),
memIndexOpt= memIndexOpt2, memIndex = memIndexOpt2.get(),
onchainMode = false,
pubsubTopic = rlnRelayPubSubTopic, pubsubTopic = rlnRelayPubSubTopic,
contentTopic = contentTopic) contentTopic = contentTopic)
await node2.start() await node2.start()
# node 3 # node 3
node3.mountRelay(@[rlnRelayPubSubTopic]) node3.mountRelay(@[rlnRelayPubSubTopic])
let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = rlnRelaySetUp(3) # set up rln relay inputs let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = rlnRelayStaticSetUp(3) # set up rln relay inputs
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
waitFor node3.mountRlnRelay(groupOpt = groupOpt3, node3.mountRlnRelayStatic(group = groupOpt3.get(),
memKeyPairOpt = memKeyPairOpt3, memKeyPair = memKeyPairOpt3.get(),
memIndexOpt= memIndexOpt3, memIndex= memIndexOpt3.get(),
onchainMode = false,
pubsubTopic = rlnRelayPubSubTopic, pubsubTopic = rlnRelayPubSubTopic,
contentTopic = contentTopic) contentTopic = contentTopic)
await node3.start() await node3.start()
@ -926,36 +920,33 @@ procSuite "WakuNode":
# set up three nodes # set up three nodes
# node1 # node1
node1.mountRelay(@[rlnRelayPubSubTopic]) node1.mountRelay(@[rlnRelayPubSubTopic])
let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = rlnRelaySetUp(1) # set up rln relay inputs let (groupOpt1, memKeyPairOpt1, memIndexOpt1) = rlnRelayStaticSetUp(1) # set up rln relay inputs
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
waitFor node1.mountRlnRelay(groupOpt = groupOpt1, node1.mountRlnRelayStatic(group = groupOpt1.get(),
memKeyPairOpt = memKeyPairOpt1, memKeyPair = memKeyPairOpt1.get(),
memIndexOpt= memIndexOpt1, memIndex = memIndexOpt1.get(),
onchainMode = false,
pubsubTopic = rlnRelayPubSubTopic, pubsubTopic = rlnRelayPubSubTopic,
contentTopic = contentTopic) contentTopic = contentTopic)
await node1.start() await node1.start()
# node 2 # node 2
node2.mountRelay(@[rlnRelayPubSubTopic]) node2.mountRelay(@[rlnRelayPubSubTopic])
let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = rlnRelaySetUp(2) # set up rln relay inputs let (groupOpt2, memKeyPairOpt2, memIndexOpt2) = rlnRelayStaticSetUp(2) # set up rln relay inputs
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
waitFor node2.mountRlnRelay(groupOpt = groupOpt2, node2.mountRlnRelayStatic(group = groupOpt2.get(),
memKeyPairOpt = memKeyPairOpt2, memKeyPair = memKeyPairOpt2.get(),
memIndexOpt= memIndexOpt2, memIndex = memIndexOpt2.get(),
onchainMode = false,
pubsubTopic = rlnRelayPubSubTopic, pubsubTopic = rlnRelayPubSubTopic,
contentTopic = contentTopic) contentTopic = contentTopic)
await node2.start() await node2.start()
# node 3 # node 3
node3.mountRelay(@[rlnRelayPubSubTopic]) node3.mountRelay(@[rlnRelayPubSubTopic])
let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = rlnRelaySetUp(3) # set up rln relay inputs let (groupOpt3, memKeyPairOpt3, memIndexOpt3) = rlnRelayStaticSetUp(3) # set up rln relay inputs
# mount rlnrelay in off-chain mode # mount rlnrelay in off-chain mode
waitFor node3.mountRlnRelay(groupOpt = groupOpt3, node3.mountRlnRelayStatic(group = groupOpt3.get(),
memKeyPairOpt = memKeyPairOpt3, memKeyPair = memKeyPairOpt3.get(),
memIndexOpt= memIndexOpt3, memIndex = memIndexOpt3.get(),
onchainMode = false,
pubsubTopic = rlnRelayPubSubTopic, pubsubTopic = rlnRelayPubSubTopic,
contentTopic = contentTopic) contentTopic = contentTopic)
await node3.start() await node3.start()

View File

@ -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-az447-649: # Libtool was configured on host fv-az241-328:
# 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,

View File

@ -8,6 +8,7 @@ import
libp2p/crypto/secp, libp2p/crypto/secp,
nimcrypto/utils, nimcrypto/utils,
eth/keys, eth/keys,
web3,
../protocol/waku_rln_relay/waku_rln_relay_types, ../protocol/waku_rln_relay/waku_rln_relay_types,
../protocol/waku_message ../protocol/waku_message
@ -129,6 +130,36 @@ type
defaultValue: "/toy-chat/2/luzhou/proto" defaultValue: "/toy-chat/2/luzhou/proto"
name: "rln-relay-content-topic" }: ContentTopic name: "rln-relay-content-topic" }: ContentTopic
rlnRelayDynamic* {.
desc: "Enable waku-rln-relay with on-chain dynamic group management: true|false",
defaultValue: false
name: "rln-relay-dynamic" }: bool
rlnRelayIdKey* {.
desc: "Rln relay identity secret key as a Hex string",
defaultValue: ""
name: "rln-relay-id" }: string
rlnRelayIdCommitmentKey* {.
desc: "Rln relay identity commitment key as a Hex string",
defaultValue: ""
name: "rln-relay-id-commitment" }: string
rlnRelayEthAccount* {.
desc: "Ethereum testnet account address",
defaultValue: ""
name: "eth-account-address" }: string
rlnRelayEthClientAddress* {.
desc: "Ethereum testnet client address e.g., ws://localhost:8540/",
defaultValue: "ws://localhost:8540/"
name: "eth-client-address" }: string
rlnRelayEthMemContractAddress* {.
desc: "Address of membership contract on an Ethereum testnet",
defaultValue: ""
name: "eth-mem-contract-address" }: string
staticnodes* {. staticnodes* {.
desc: "Peer multiaddr to directly connect with. Argument may be repeated." desc: "Peer multiaddr to directly connect with. Argument may be repeated."
name: "staticnode" }: seq[string] name: "staticnode" }: seq[string]

View File

@ -6,6 +6,7 @@ import
stew/shims/net as stewNet, stew/shims/net as stewNet,
stew/byteutils, stew/byteutils,
eth/keys, eth/keys,
nimcrypto,
eth/p2p/discoveryv5/enr, eth/p2p/discoveryv5/enr,
libp2p/crypto/crypto, libp2p/crypto/crypto,
libp2p/protocols/ping, libp2p/protocols/ping,
@ -38,7 +39,7 @@ when defined(rln):
import import
libp2p/protocols/pubsub/rpc/messages, libp2p/protocols/pubsub/rpc/messages,
libp2p/protocols/pubsub/pubsub, libp2p/protocols/pubsub/pubsub,
web3, web3, web3/ethtypes,
../protocol/waku_rln_relay/[rln, waku_rln_relay_utils] ../protocol/waku_rln_relay/[rln, waku_rln_relay_utils]
declarePublicCounter waku_node_messages, "number of messages received", ["type"] declarePublicCounter waku_node_messages, "number of messages received", ["type"]
@ -543,20 +544,17 @@ when defined(rln):
let pb = PubSub(node.wakuRelay) let pb = PubSub(node.wakuRelay)
pb.addValidator(pubsubTopic, validator) pb.addValidator(pubsubTopic, validator)
proc mountRlnRelay*(node: WakuNode, proc mountRlnRelayStatic*(node: WakuNode,
ethClientAddrOpt: Option[string] = none(string), group: seq[IDCommitment],
ethAccAddrOpt: Option[web3.Address] = none(web3.Address), memKeyPair: MembershipKeyPair,
memContractAddOpt: Option[web3.Address] = none(web3.Address), memIndex: MembershipIndex,
groupOpt: Option[seq[IDCommitment]] = none(seq[IDCommitment]),
memKeyPairOpt: Option[MembershipKeyPair] = none(MembershipKeyPair),
memIndexOpt: Option[MembershipIndex] = none(MembershipIndex),
onchainMode: bool = true,
pubsubTopic: string, pubsubTopic: string,
contentTopic: ContentTopic, contentTopic: ContentTopic,
spamHandler: Option[SpamHandler] = none(SpamHandler)) {.async.} = spamHandler: Option[SpamHandler] = none(SpamHandler)) {.raises: [Defect, IOError].}=
# TODO return a bool value to indicate the success of the call # TODO return a bool value to indicate the success of the call
# check whether inputs are provided
debug "mounting rln-relay in off-chain/static mode"
# check whether inputs are provided
# relay protocol is the prerequisite of rln-relay # relay protocol is the prerequisite of rln-relay
if node.wakuRelay.isNil: if node.wakuRelay.isNil:
error "Failed to mount WakuRLNRelay. Relay protocol is not mounted." error "Failed to mount WakuRLNRelay. Relay protocol is not mounted."
@ -565,41 +563,8 @@ when defined(rln):
if pubsubTopic notin node.wakuRelay.defaultTopics: if pubsubTopic notin node.wakuRelay.defaultTopics:
error "Failed to mount WakuRLNRelay. The relay protocol does not support the configured pubsub topic.", pubsubTopic=pubsubTopic error "Failed to mount WakuRLNRelay. The relay protocol does not support the configured pubsub topic.", pubsubTopic=pubsubTopic
return return
if onchainMode:
if memContractAddOpt.isNone():
error "failed to mount rln relay: membership contract address is not provided"
return
if ethClientAddrOpt.isNone():
error "failed to mount rln relay: Ethereum client address is not provided"
return
if ethAccAddrOpt.isNone():
error "failed to mount rln relay: Ethereum account address is not provided"
return
else:
if groupOpt.isNone():
error "failed to mount rln relay: group information is not provided"
return
if memKeyPairOpt.isNone(): debug "rln-relay input validation passed"
error "failed to mount rln relay: membership key of the node is not provided"
return
if memIndexOpt.isNone():
error "failed to mount rln relay: membership index is not provided"
return
var
ethClientAddr: string
ethAccAddr: web3.Address
memContractAdd: web3.Address
if onchainMode:
ethClientAddr = ethClientAddrOpt.get()
ethAccAddr = ethAccAddrOpt.get()
memContractAdd = memContractAddOpt.get()
let
group = groupOpt.get()
memKeyPair = memKeyPairOpt.get()
memIndex = memIndexOpt.get()
# check the peer's index and the inclusion of user's identity commitment in the group # check the peer's index and the inclusion of user's identity commitment in the group
doAssert((memKeyPair.idCommitment) == group[int(memIndex)]) doAssert((memKeyPair.idCommitment) == group[int(memIndex)])
@ -609,40 +574,94 @@ when defined(rln):
doAssert(rlnInstance.isOk) doAssert(rlnInstance.isOk)
var rln = rlnInstance.value var rln = rlnInstance.value
# generate the membership keys if none is provided
# in a happy path, this condition never gets through for a static group of users
# the node should pass its keys i.e., memKeyPairOpt to the function
if not memKeyPairOpt.isSome:
let membershipKeyPair = rln.membershipKeyGen()
# check whether keys are generated
doAssert(membershipKeyPair.isSome())
debug "the membership key for the rln relay is generated", idKey=membershipKeyPair.get().idKey.toHex, idCommitment=membershipKeyPair.get().idCommitment.toHex
# add members to the Merkle tree # add members to the Merkle tree
for index in 0..group.len-1: for index in 0..group.len-1:
let member = group[index] let member = group[index]
let member_is_added = rln.insertMember(member) let member_is_added = rln.insertMember(member)
doAssert(member_is_added) doAssert(member_is_added)
# create the WakuRLNRelay # create the WakuRLNRelay
var rlnPeer = WakuRLNRelay(membershipKeyPair: memKeyPair, var rlnPeer = WakuRLNRelay(membershipKeyPair: memKeyPair,
membershipIndex: memIndex, membershipIndex: memIndex,
membershipContractAddress: memContractAdd, rlnInstance: rln,
pubsubTopic: pubsubTopic,
contentTopic: contentTopic)
# 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
# the topic validator checks for the correct non-spamming proof of the message
node.addRLNRelayValidator(pubsubTopic, contentTopic, spamHandler)
debug "rln relay topic validator is mounted successfully", pubsubTopic=pubsubTopic, contentTopic=contentTopic
node.wakuRlnRelay = rlnPeer
proc mountRlnRelayDynamic*(node: WakuNode,
ethClientAddr: string = "",
ethAccAddr: web3.Address,
memContractAddr: web3.Address,
memKeyPair: Option[MembershipKeyPair] = none(MembershipKeyPair),
memIndex: Option[MembershipIndex] = none(MembershipIndex),
pubsubTopic: string,
contentTopic: ContentTopic,
spamHandler: Option[SpamHandler] = none(SpamHandler)) {.async.} =
debug "mounting rln-relay in on-chain/dynamic mode"
# TODO return a bool value to indicate the success of the call
# relay protocol is the prerequisite of rln-relay
if node.wakuRelay.isNil:
error "Failed to mount WakuRLNRelay. Relay protocol is not mounted."
return
# check whether the pubsub topic is supported at the relay level
if pubsubTopic notin node.wakuRelay.defaultTopics:
error "Failed to mount WakuRLNRelay. The relay protocol does not support the configured pubsub topic.", pubsubTopic=pubsubTopic
return
debug "rln-relay input validation passed"
# create an RLN instance
var rlnInstance = createRLNInstance()
doAssert(rlnInstance.isOk)
var rln = rlnInstance.value
# prepare rln membership key pair
var
keyPair: MembershipKeyPair
rlnIndex: MembershipIndex
if memKeyPair.isNone: # if non provided, create one and register to the contract
trace "no rln-relay key is provided, generating one"
let keyPairOpt = rln.membershipKeyGen()
doAssert(keyPairOpt.isSome)
keyPair = keyPairOpt.get()
# register the rln-relay peer to the membership contract
let regIndexRes = await register(idComm = keyPair.idCommitment, ethAccountAddress = ethAccAddr, ethClientAddress = ethClientAddr, membershipContractAddress = memContractAddr)
# check whether registration is done
doAssert(regIndexRes.isOk())
rlnIndex = regIndexRes.value
debug "peer is successfully registered into the membership contract", rlnIndex=rlnIndex, idComm=keyPair.idCommitment.toHex(), idKey=keyPair.idKey.toHex()
else:
keyPair = memKeyPair.get()
rlnIndex = memIndex.get()
# create the WakuRLNRelay
var rlnPeer = WakuRLNRelay(membershipKeyPair: keyPair,
membershipIndex: rlnIndex,
membershipContractAddress: memContractAddr,
ethClientAddress: ethClientAddr, ethClientAddress: ethClientAddr,
ethAccountAddress: ethAccAddr, ethAccountAddress: ethAccAddr,
rlnInstance: rln, rlnInstance: rln,
pubsubTopic: pubsubTopic, pubsubTopic: pubsubTopic,
contentTopic: contentTopic) contentTopic: contentTopic)
if onchainMode:
# register the rln-relay peer to the membership contract
let isSuccessful = await rlnPeer.register()
# check whether registration is done
doAssert(isSuccessful)
debug "peer is successfully registered into the membership contract"
proc handler(pubkey: Uint256, index: Uint256) =
debug "a new key is added", pubkey=pubkey
# assuming all the members arrive in order
let pk = pubkey.toIDCommitment()
let isSuccessful = rlnPeer.rlnInstance.insertMember(pk)
debug "received pk", pk=pk.toHex, index =index
doAssert(isSuccessful)
asyncSpawn rlnPeer.handleGroupUpdates(handler)
debug "dynamic group management is started"
# 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
# the topic validator checks for the correct non-spamming proof of the message # the topic validator checks for the correct non-spamming proof of the message
@ -1207,29 +1226,51 @@ when isMainModule:
when defined(rln): when defined(rln):
if conf.rlnRelay: if conf.rlnRelay:
info "WakuRLNRelay is enabled" if not conf.rlnRelayDynamic:
info " setting up waku-rln-relay in on-chain mode... "
# set up rln relay inputs
let (groupOpt, memKeyPairOpt, memIndexOpt) = rlnRelayStaticSetUp(conf.rlnRelayMemIndex)
if memIndexOpt.isNone:
error "failed to mount WakuRLNRelay"
else:
# mount rlnrelay in off-chain mode with a static group of users
node.mountRlnRelayStatic(group = groupOpt.get(), memKeyPair = memKeyPairOpt.get(), memIndex= memIndexOpt.get(), pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic)
# set up rln relay inputs info "membership id key", idkey=memKeyPairOpt.get().idKey.toHex
let (groupOpt, memKeyPairOpt, memIndexOpt) = rlnRelaySetUp(conf.rlnRelayMemIndex) info "membership id commitment key", idCommitmentkey=memKeyPairOpt.get().idCommitment.toHex
if memIndexOpt.isNone:
error "failed to mount WakuRLNRelay" # 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
# TODO have added this check to account for unseen corner cases, will remove it later
let
root = node.wakuRlnRelay.rlnInstance.getMerkleRoot.value.toHex()
expectedRoot = STATIC_GROUP_MERKLE_ROOT
if root != expectedRoot:
error "root mismatch: something went wrong not in Merkle tree construction"
debug "the calculated root", root
info "WakuRLNRelay is mounted successfully", pubsubtopic=conf.rlnRelayPubsubTopic, contentTopic=conf.rlnRelayContentTopic
else: else:
# mount rlnrelay in offline mode (for now) info " setting up waku-rln-relay in on-chain mode... "
waitFor node.mountRlnRelay(groupOpt = groupOpt, memKeyPairOpt = memKeyPairOpt, memIndexOpt= memIndexOpt, onchainMode = false, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic)
info "membership id key", idkey=memKeyPairOpt.get().idKey.toHex # read related inputs to run rln-relay in on-chain mode and do type conversion when needed
info "membership id commitment key", idCommitmentkey=memKeyPairOpt.get().idCommitment.toHex
# 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
# TODO have added this check to account for unseen corner cases, will remove it later
let let
root = node.wakuRlnRelay.rlnInstance.getMerkleRoot.value.toHex() ethAccountAddr = web3.fromHex(web3.Address, conf.rlnRelayEthAccount)
expectedRoot = STATIC_GROUP_MERKLE_ROOT ethClientAddr = conf.rlnRelayEthClientAddress
if root != expectedRoot: ethMemContractAddress = web3.fromHex(web3.Address, conf.rlnRelayEthMemContractAddress)
error "root mismatch: something went wrong not in Merkle tree construction" rlnRelayId = conf.rlnRelayIdKey
debug "the calculated root", root rlnRelayIdCommitmentKey = conf.rlnRelayIdCommitmentKey
info "WakuRLNRelay is mounted successfully", pubsubtopic=conf.rlnRelayPubsubTopic, contentTopic=conf.rlnRelayContentTopic rlnRelayIndex = conf.rlnRelayMemIndex
# check if the peer has provided its rln credentials
if rlnRelayIdCommitmentKey != "" and rlnRelayId != "":
# type conversation from hex strings to MembershipKeyPair
let keyPair = @[(rlnRelayId, rlnRelayIdCommitmentKey)]
let memKeyPair = keyPair.toMembershipKeyPairs()[0]
# mount the rln relay protocol in the on-chain/dynamic mode
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, memKeyPair = some(memKeyPair), memIndex = some(rlnRelayIndex), ethAccAddr = ethAccountAddr, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic)
else:
# no rln credential is provided
# mount the rln relay protocol in the on-chain/dynamic mode
waitFor node.mountRlnRelayDynamic(memContractAddr = ethMemContractAddress, ethClientAddr = ethClientAddr, ethAccAddr = ethAccountAddr, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic)
if conf.swap: if conf.swap:
mountSwap(node) mountSwap(node)

View File

@ -74,7 +74,7 @@ type WakuRLNRelay* = ref object
# this field is required for signing transactions # this field is required for signing transactions
# TODO may need to erase this ethAccountPrivateKey when is not used # TODO may need to erase this ethAccountPrivateKey when is not used
# TODO may need to make ethAccountPrivateKey mandatory # TODO may need to make ethAccountPrivateKey mandatory
ethAccountPrivateKey*: Option[PrivateKey] ethAccountPrivateKey*: PrivateKey
rlnInstance*: RLN[Bn256] rlnInstance*: RLN[Bn256]
pubsubTopic*: string # the pubsub topic for which rln relay is mounted pubsubTopic*: string # the pubsub topic for which rln relay is mounted
# contentTopic should be of type waku_message.ContentTopic, however, due to recursive module dependency, the underlying type of ContentTopic is used instead # contentTopic should be of type waku_message.ContentTopic, however, due to recursive module dependency, the underlying type of ContentTopic is used instead

View File

@ -4,6 +4,7 @@ import
std/sequtils, tables, times, std/sequtils, tables, times,
chronicles, options, chronos, stint, chronicles, options, chronos, stint,
web3, json, web3, json,
eth/keys,
stew/results, stew/results,
stew/[byteutils, arrayops, endians2], stew/[byteutils, arrayops, endians2],
rln, rln,
@ -65,6 +66,7 @@ proc createRLNInstance*(d: int = MERKLE_TREE_DEPTH): RLNResult
return err("error in parameters generation") return err("error in parameters generation")
return ok(rlnInstance) return ok(rlnInstance)
proc membershipKeyGen*(ctxPtr: RLN[Bn256]): Option[MembershipKeyPair] = proc membershipKeyGen*(ctxPtr: RLN[Bn256]): Option[MembershipKeyPair] =
## generates a MembershipKeyPair that can be used for the registration into the rln membership contract ## generates a MembershipKeyPair that can be used for the registration into the rln membership contract
@ -99,28 +101,65 @@ proc membershipKeyGen*(ctxPtr: RLN[Bn256]): Option[MembershipKeyPair] =
return some(keypair) return some(keypair)
proc toUInt256*(idCommitment: IDCommitment): UInt256 = proc toUInt256*(idCommitment: IDCommitment): UInt256 =
let pk = cast[UInt256](idCommitment) let pk = UInt256.fromBytesBE(idCommitment)
return pk return pk
proc toIDCommitment*(idCommitment: UInt256): IDCommitment = proc toIDCommitment*(idCommitmentUint: UInt256): IDCommitment =
let pk = cast[IDCommitment](idCommitment) let pk = IDCommitment(idCommitmentUint.toBytesBE())
return pk return pk
proc toMembershipIndex(v: UInt256): MembershipIndex =
let result: MembershipIndex = cast[MembershipIndex](v)
return result
proc register*(idComm: IDCommitment, ethAccountAddress: Address, ethClientAddress: string, membershipContractAddress: Address): Future[Result[MembershipIndex, string]] {.async.} =
# TODO may need to also get eth Account Private Key as PrivateKey
## registers the idComm into the membership contract whose address is in rlnPeer.membershipContractAddress
let web3 = await newWeb3(ethClientAddress)
web3.defaultAccount = ethAccountAddress
# when the private key is set in a web3 instance, the send proc (sender.register(pk).send(MEMBERSHIP_FEE))
# does the signing using the provided key
# web3.privateKey = some(ethAccountPrivateKey)
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
let
pk = idComm.toUInt256()
txHash = await sender.register(pk).send(MEMBERSHIP_FEE)
tsReceipt = await web3.getMinedTransactionReceipt(txHash)
# the receipt topic holds the hash of signature of the raised events
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[0..65] != "0x5a92c2530f207992057b9c3e544108ffce3beda4a63719f316967c49bf6159d2":
return err("invalid event signature hash")
# 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.hexToSeqByte()
eventIdCommUint = UInt256.fromBytesBE(argumentsBytes[0..31])
eventIndex = UInt256.fromBytesBE(argumentsBytes[32..^1])
eventIdComm = eventIdCommUint.toIDCommitment()
debug "the identity commitment key extracted from tx log", eventIdComm=eventIdComm
debug "the index of registered identity commitment key", eventIndex=eventIndex
if eventIdComm != idComm:
return err("invalid id commitment key")
await web3.close()
return ok(toMembershipIndex(eventIndex))
proc register*(rlnPeer: WakuRLNRelay): Future[bool] {.async.} = proc register*(rlnPeer: WakuRLNRelay): Future[bool] {.async.} =
## registers the public key of the rlnPeer which is rlnPeer.membershipKeyPair.publicKey ## registers the public key of the rlnPeer which is rlnPeer.membershipKeyPair.publicKey
## into the membership contract whose address is in rlnPeer.membershipContractAddress ## into the membership contract whose address is in rlnPeer.membershipContractAddress
let web3 = await newWeb3(rlnPeer.ethClientAddress) let pk = rlnPeer.membershipKeyPair.idCommitment
web3.defaultAccount = rlnPeer.ethAccountAddress discard await register(idComm = pk, ethAccountAddress = rlnPeer.ethAccountAddress, ethClientAddress = rlnPeer.ethClientAddress, membershipContractAddress = rlnPeer.membershipContractAddress )
# when the private key is set in a web3 instance, the send proc (sender.register(pk).send(MEMBERSHIP_FEE))
# does the signing using the provided key
web3.privateKey = rlnPeer.ethAccountPrivateKey
var sender = web3.contractSender(MembershipContract,
rlnPeer.membershipContractAddress) # creates a Sender object with a web3 field and contract address of type Address
let pk = rlnPeer.membershipKeyPair.idCommitment.toUInt256()
discard await sender.register(pk).send(MEMBERSHIP_FEE)
debug "pk", pk = pk
# TODO check the receipt and then return true/false
await web3.close()
return true return true
proc appendLength*(input: openArray[byte]): seq[byte] = proc appendLength*(input: openArray[byte]): seq[byte] =
@ -343,7 +382,7 @@ proc createMembershipList*(n: int): (seq[(string, string)], string) {.raises: [
let root = rln.getMerkleRoot().value.toHex let root = rln.getMerkleRoot().value.toHex
return (output, root) return (output, root)
proc rlnRelaySetUp*(rlnRelayMemIndex: MembershipIndex): (Option[seq[ proc rlnRelayStaticSetUp*(rlnRelayMemIndex: MembershipIndex): (Option[seq[
IDCommitment]], Option[MembershipKeyPair], Option[ IDCommitment]], Option[MembershipKeyPair], Option[
MembershipIndex]) {.raises: [Defect, ValueError].} = MembershipIndex]) {.raises: [Defect, ValueError].} =
let let
@ -579,6 +618,7 @@ proc subscribeToGroupEvents(ethClientUri: string, contractAddress: Address, bloc
debug "onRegister", pubkey = pubkey, index = index debug "onRegister", pubkey = pubkey, index = index
handler(pubkey, index) handler(pubkey, index)
except Exception as err: except Exception as err:
# chronos still raises exceptions which inherit directly from Exception
doAssert false, err.msg doAssert false, err.msg
do (err: CatchableError): do (err: CatchableError):
echo "Error from subscription: ", err.msg echo "Error from subscription: ", err.msg