mirror of
https://github.com/waku-org/nwaku.git
synced 2025-02-23 04:18:30 +00:00
Implement data structures and tests for checking transaction eligibility based on tx hash. This work will be continues in future PRs. All code added in this PR is only used in tests. * feat: add simple txid-based eligibility check with hard-coded params (#3166) * use new proc to generate eligibility status Co-authored-by: gabrielmer <101006718+gabrielmer@users.noreply.github.com> * minor fixes * add comments to clarify eligibility definition * use Address.fromHex conversion from eth-web3 * move isEligible to common * refactor: avoid result and unnecesary branching * define const for simple transfer gas usage * avoid unnecessary parentheses * chore: run nph linter manually * refactor, move all hard-coded constants to tests * use Result type in eligibility tests * use standard method of error handling * make try-block smaller * add a try-block in case of connection failure to web3 provider * make queries to web3 provider in parallel * move Web3 provider RPC URL into env variable * remove unused import * rename functions * use await in async proc Co-authored-by: gabrielmer <101006718+gabrielmer@users.noreply.github.com> * add timeout to tx receipt query * parallelize queries for tx and txreceipt * make test txids non public Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * use assert in txid i13n test Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * use parentheses when calling verb-methods without arguments Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * remove unused import Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * use init for stack-allocated objects * add txReceipt error message to error Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * introduce eligibility manager * [WIP] use Anvil for eligibility testing * add eligibility test with contract deployment tx * add eligibility test with contract call * add asyncSetup and asyncTeardown for eligibility tests * minor refactor * refactor tests for onchain group manager with asyncSetup and asyncTeardown * minor refactor * remove unnecessary defer in asyncTeardown Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * remove unnecessary call in test (moved to asyncTeardown) Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com> * add comment justidying the use of discard * rename file txid_proof to eligibility_manager --------- Co-authored-by: gabrielmer <101006718+gabrielmer@users.noreply.github.com> Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
758 lines
28 KiB
Nim
758 lines
28 KiB
Nim
{.used.}
|
|
|
|
import
|
|
std/[tempfiles, strutils, options],
|
|
stew/shims/net as stewNet,
|
|
stew/results,
|
|
testutils/unittests,
|
|
chronos,
|
|
libp2p/switch,
|
|
libp2p/protocols/pubsub/pubsub,
|
|
eth/keys
|
|
|
|
from std/times import epochTime
|
|
|
|
import
|
|
../../../waku/[
|
|
node/waku_node,
|
|
node/peer_manager,
|
|
waku_core,
|
|
waku_node,
|
|
common/error_handling,
|
|
waku_rln_relay,
|
|
waku_rln_relay/rln,
|
|
waku_rln_relay/protocol_types,
|
|
waku_keystore/keystore,
|
|
],
|
|
../waku_store/store_utils,
|
|
../waku_archive/archive_utils,
|
|
../testlib/[wakucore, wakunode, testasync, futures, common, assertions],
|
|
../resources/payloads,
|
|
../waku_rln_relay/[utils_static, utils_onchain]
|
|
|
|
from ../../waku/waku_noise/noise_utils import randomSeqByte
|
|
|
|
proc buildRandomIdentityCredentials(): IdentityCredential =
|
|
# We generate a random identity credential (inter-value constrains are not enforced, otherwise we need to load e.g. zerokit RLN keygen)
|
|
let
|
|
idTrapdoor = randomSeqByte(rng[], 32)
|
|
idNullifier = randomSeqByte(rng[], 32)
|
|
idSecretHash = randomSeqByte(rng[], 32)
|
|
idCommitment = randomSeqByte(rng[], 32)
|
|
|
|
IdentityCredential(
|
|
idTrapdoor: idTrapdoor,
|
|
idNullifier: idNullifier,
|
|
idSecretHash: idSecretHash,
|
|
idCommitment: idCommitment,
|
|
)
|
|
|
|
proc addMembershipCredentialsToKeystore(
|
|
credentials: IdentityCredential,
|
|
keystorePath: string,
|
|
appInfo: AppInfo,
|
|
rlnRelayEthContractAddress: string,
|
|
password: string,
|
|
membershipIndex: uint,
|
|
): KeystoreResult[void] =
|
|
let
|
|
contract = MembershipContract(chainId: "0x539", address: rlnRelayEthContractAddress)
|
|
# contract = MembershipContract(chainId: "1337", address: rlnRelayEthContractAddress)
|
|
index = MembershipIndex(membershipIndex)
|
|
membershipCredential = KeystoreMembership(
|
|
membershipContract: contract, treeIndex: index, identityCredential: credentials
|
|
)
|
|
|
|
addMembershipCredentials(
|
|
path = keystorePath,
|
|
membership = membershipCredential,
|
|
password = password,
|
|
appInfo = appInfo,
|
|
)
|
|
|
|
proc fatalErrorVoidHandler(errMsg: string) {.gcsafe, raises: [].} =
|
|
discard
|
|
|
|
proc getWakuRlnConfigOnChain*(
|
|
keystorePath: string,
|
|
appInfo: AppInfo,
|
|
rlnRelayEthContractAddress: string,
|
|
password: string,
|
|
credIndex: uint,
|
|
fatalErrorHandler: Option[OnFatalErrorHandler] = none(OnFatalErrorHandler),
|
|
ethClientAddress: Option[string] = none(string),
|
|
): WakuRlnConfig =
|
|
return WakuRlnConfig(
|
|
rlnRelayDynamic: true,
|
|
rlnRelayCredIndex: some(credIndex),
|
|
rlnRelayEthContractAddress: rlnRelayEthContractAddress,
|
|
rlnRelayEthClientAddress: ethClientAddress.get(EthClient),
|
|
rlnRelayTreePath: genTempPath("rln_tree", "wakunode_" & $credIndex),
|
|
rlnEpochSizeSec: 1,
|
|
onFatalErrorAction: fatalErrorHandler.get(fatalErrorVoidHandler),
|
|
# If these are used, initialisation fails with "failed to mount WakuRlnRelay: could not initialize the group manager: the commitment does not have a membership"
|
|
rlnRelayCredPath: keystorePath,
|
|
rlnRelayCredPassword: password,
|
|
)
|
|
|
|
proc setupRelayWithOnChainRln*(
|
|
node: WakuNode, shards: seq[RelayShard], wakuRlnConfig: WakuRlnConfig
|
|
) {.async.} =
|
|
await node.mountRelay(shards)
|
|
await node.mountRlnRelay(wakuRlnConfig)
|
|
|
|
suite "Waku RlnRelay - End to End - Static":
|
|
var
|
|
pubsubTopic {.threadvar.}: PubsubTopic
|
|
contentTopic {.threadvar.}: ContentTopic
|
|
|
|
var
|
|
server {.threadvar.}: WakuNode
|
|
client {.threadvar.}: WakuNode
|
|
|
|
var
|
|
serverRemotePeerInfo {.threadvar.}: RemotePeerInfo
|
|
clientPeerId {.threadvar.}: PeerId
|
|
|
|
asyncSetup:
|
|
pubsubTopic = DefaultPubsubTopic
|
|
contentTopic = DefaultContentTopic
|
|
|
|
let
|
|
serverKey = generateSecp256k1Key()
|
|
clientKey = generateSecp256k1Key()
|
|
|
|
server = newTestWakuNode(serverKey, ValidIpAddress.init("0.0.0.0"), Port(0))
|
|
client = newTestWakuNode(clientKey, ValidIpAddress.init("0.0.0.0"), Port(0))
|
|
|
|
await allFutures(server.start(), client.start())
|
|
|
|
serverRemotePeerInfo = server.switch.peerInfo.toRemotePeerInfo()
|
|
clientPeerId = client.switch.peerInfo.toRemotePeerInfo().peerId
|
|
|
|
asyncTeardown:
|
|
await allFutures(client.stop(), server.stop())
|
|
|
|
suite "Mount":
|
|
asyncTest "Can't mount if relay is not mounted":
|
|
# Given Relay and RLN are not mounted
|
|
check:
|
|
server.wakuRelay == nil
|
|
server.wakuRlnRelay == nil
|
|
|
|
# When RlnRelay is mounted
|
|
let catchRes = catch:
|
|
await server.setupStaticRln(1)
|
|
|
|
# Then Relay and RLN are not mounted,and the process fails
|
|
check:
|
|
server.wakuRelay == nil
|
|
server.wakuRlnRelay == nil
|
|
catchRes.error()[].msg ==
|
|
"WakuRelay protocol is not mounted, cannot mount WakuRlnRelay"
|
|
|
|
asyncTest "Pubsub topics subscribed before mounting RlnRelay are added to it":
|
|
# Given the node enables Relay and Rln while subscribing to a pubsub topic
|
|
await server.setupRelayWithStaticRln(1.uint, @[pubsubTopic])
|
|
await client.setupRelayWithStaticRln(2.uint, @[pubsubTopic])
|
|
check:
|
|
server.wakuRelay != nil
|
|
server.wakuRlnRelay != nil
|
|
client.wakuRelay != nil
|
|
client.wakuRlnRelay != nil
|
|
|
|
# And the nodes are connected
|
|
await client.connectToNodes(@[serverRemotePeerInfo])
|
|
|
|
# And the node registers the completion handler
|
|
var completionFuture = subscribeCompletionHandler(server, pubsubTopic)
|
|
|
|
# When the client sends a valid RLN message
|
|
let isCompleted1 =
|
|
await sendRlnMessage(client, pubsubTopic, contentTopic, completionFuture)
|
|
|
|
# Then the valid RLN message is relayed
|
|
check:
|
|
isCompleted1
|
|
completionFuture.read()
|
|
|
|
# When the client sends an invalid RLN message
|
|
completionFuture = newBoolFuture()
|
|
let isCompleted2 = await sendRlnMessageWithInvalidProof(
|
|
client, pubsubTopic, contentTopic, completionFuture
|
|
)
|
|
|
|
# Then the invalid RLN message is not relayed
|
|
check:
|
|
not isCompleted2
|
|
|
|
asyncTest "Pubsub topics subscribed after mounting RlnRelay are added to it":
|
|
# Given the node enables Relay and Rln without subscribing to a pubsub topic
|
|
await server.setupRelayWithStaticRln(1.uint, @[])
|
|
await client.setupRelayWithStaticRln(2.uint, @[])
|
|
|
|
# And the nodes are connected
|
|
await client.connectToNodes(@[serverRemotePeerInfo])
|
|
|
|
# await sleepAsync(FUTURE_TIMEOUT)
|
|
# And the node registers the completion handler
|
|
var completionFuture = subscribeCompletionHandler(server, pubsubTopic)
|
|
|
|
await sleepAsync(FUTURE_TIMEOUT)
|
|
# When the client sends a valid RLN message
|
|
let isCompleted1 =
|
|
await sendRlnMessage(client, pubsubTopic, contentTopic, completionFuture)
|
|
|
|
# Then the valid RLN message is relayed
|
|
check:
|
|
isCompleted1
|
|
completionFuture.read()
|
|
|
|
# When the client sends an invalid RLN message
|
|
completionFuture = newBoolFuture()
|
|
let isCompleted2 = await sendRlnMessageWithInvalidProof(
|
|
client, pubsubTopic, contentTopic, completionFuture
|
|
)
|
|
|
|
# Then the invalid RLN message is not relayed
|
|
check:
|
|
not isCompleted2
|
|
|
|
asyncTest "rln-relay-max-message-limit testing":
|
|
let
|
|
nodekey = generateSecp256k1Key()
|
|
node = newTestWakuNode(nodekey, parseIpAddress("0.0.0.0"), Port(0))
|
|
|
|
await node.mountRelay(@[DefaultRelayShard])
|
|
|
|
let contractAddress = await uploadRLNContract(EthClient)
|
|
let wakuRlnConfig = WakuRlnConfig(
|
|
rlnRelayDynamic: true,
|
|
rlnRelayCredIndex: some(0.uint),
|
|
rlnRelayUserMessageLimit: 111,
|
|
rlnRelayTreepath: genTempPath("rln_tree", "wakunode_0"),
|
|
rlnRelayEthClientAddress: EthClient,
|
|
rlnRelayEthContractAddress: $contractAddress,
|
|
rlnRelayChainId: 1337,
|
|
onFatalErrorAction: proc(errStr: string) =
|
|
raiseAssert errStr
|
|
,
|
|
)
|
|
|
|
try:
|
|
await node.mountRlnRelay(wakuRlnConfig)
|
|
except CatchableError as e:
|
|
check e.msg ==
|
|
"failed to mount WakuRlnRelay: rln-relay-user-message-limit can't exceed the MAX_MESSAGE_LIMIT in the rln contract"
|
|
|
|
suite "Analysis of Bandwith Limitations":
|
|
asyncTest "Valid Payload Sizes":
|
|
# Given the node enables Relay and Rln while subscribing to a pubsub topic
|
|
await server.setupRelayWithStaticRln(1.uint, @[pubsubTopic])
|
|
await client.setupRelayWithStaticRln(2.uint, @[pubsubTopic])
|
|
|
|
# And the nodes are connected
|
|
await client.connectToNodes(@[serverRemotePeerInfo])
|
|
|
|
# Register Relay Handler
|
|
var completionFut = newPushHandlerFuture()
|
|
proc relayHandler(
|
|
topic: PubsubTopic, msg: WakuMessage
|
|
): Future[void] {.async, gcsafe.} =
|
|
if topic == pubsubTopic:
|
|
completionFut.complete((topic, msg))
|
|
|
|
let subscriptionEvent = (kind: PubsubSub, topic: pubsubTopic)
|
|
server.subscribe(subscriptionEvent, some(relayHandler))
|
|
await sleepAsync(FUTURE_TIMEOUT)
|
|
|
|
# Generate Messages
|
|
let
|
|
epoch = epochTime()
|
|
payload1b = getByteSequence(1)
|
|
payload1kib = getByteSequence(1024)
|
|
overhead: uint64 = 419
|
|
payload150kib = getByteSequence((150 * 1024) - overhead)
|
|
payload150kibPlus = getByteSequence((150 * 1024) - overhead + 1)
|
|
|
|
var
|
|
message1b = WakuMessage(payload: @payload1b, contentTopic: contentTopic)
|
|
message1kib = WakuMessage(payload: @payload1kib, contentTopic: contentTopic)
|
|
message150kib = WakuMessage(payload: @payload150kib, contentTopic: contentTopic)
|
|
message151kibPlus =
|
|
WakuMessage(payload: @payload150kibPlus, contentTopic: contentTopic)
|
|
|
|
doAssert(
|
|
client.wakuRlnRelay
|
|
.appendRLNProof(
|
|
message1b, epoch + float64(client.wakuRlnRelay.rlnEpochSizeSec * 0)
|
|
)
|
|
.isOk()
|
|
)
|
|
doAssert(
|
|
client.wakuRlnRelay
|
|
.appendRLNProof(
|
|
message1kib, epoch + float64(client.wakuRlnRelay.rlnEpochSizeSec * 1)
|
|
)
|
|
.isOk()
|
|
)
|
|
doAssert(
|
|
client.wakuRlnRelay
|
|
.appendRLNProof(
|
|
message150kib, epoch + float64(client.wakuRlnRelay.rlnEpochSizeSec * 2)
|
|
)
|
|
.isOk()
|
|
)
|
|
doAssert(
|
|
client.wakuRlnRelay
|
|
.appendRLNProof(
|
|
message151kibPlus, epoch + float64(client.wakuRlnRelay.rlnEpochSizeSec * 3)
|
|
)
|
|
.isOk()
|
|
)
|
|
|
|
# When sending the 1B message
|
|
discard await client.publish(some(pubsubTopic), message1b)
|
|
discard await completionFut.withTimeout(FUTURE_TIMEOUT_LONG)
|
|
|
|
# Then the message is relayed
|
|
check completionFut.read() == (pubsubTopic, message1b)
|
|
# When sending the 1KiB message
|
|
completionFut = newPushHandlerFuture() # Reset Future
|
|
discard await client.publish(some(pubsubTopic), message1kib)
|
|
discard await completionFut.withTimeout(FUTURE_TIMEOUT_LONG)
|
|
|
|
# Then the message is relayed
|
|
check completionFut.read() == (pubsubTopic, message1kib)
|
|
|
|
# When sending the 150KiB message
|
|
completionFut = newPushHandlerFuture() # Reset Future
|
|
discard await client.publish(some(pubsubTopic), message150kib)
|
|
discard await completionFut.withTimeout(FUTURE_TIMEOUT_LONG)
|
|
|
|
# Then the message is relayed
|
|
check completionFut.read() == (pubsubTopic, message150kib)
|
|
|
|
# When sending the 150KiB plus message
|
|
completionFut = newPushHandlerFuture() # Reset Future
|
|
discard await client.publish(some(pubsubTopic), message151kibPlus)
|
|
|
|
# Then the message is not relayed
|
|
check not await completionFut.withTimeout(FUTURE_TIMEOUT_LONG)
|
|
|
|
asyncTest "Invalid Payload Sizes":
|
|
# Given the node enables Relay and Rln while subscribing to a pubsub topic
|
|
await server.setupRelayWithStaticRln(1.uint, @[pubsubTopic])
|
|
await client.setupRelayWithStaticRln(2.uint, @[pubsubTopic])
|
|
|
|
# And the nodes are connected
|
|
await client.connectToNodes(@[serverRemotePeerInfo])
|
|
|
|
# Register Relay Handler
|
|
var completionFut = newPushHandlerFuture()
|
|
proc relayHandler(
|
|
topic: PubsubTopic, msg: WakuMessage
|
|
): Future[void] {.async, gcsafe.} =
|
|
if topic == pubsubTopic:
|
|
completionFut.complete((topic, msg))
|
|
|
|
let subscriptionEvent = (kind: PubsubSub, topic: pubsubTopic)
|
|
server.subscribe(subscriptionEvent, some(relayHandler))
|
|
await sleepAsync(FUTURE_TIMEOUT)
|
|
|
|
# Generate Messages
|
|
let
|
|
epoch = epochTime()
|
|
overhead: uint64 = 419
|
|
payload150kibPlus = getByteSequence((150 * 1024) - overhead + 1)
|
|
|
|
var message151kibPlus =
|
|
WakuMessage(payload: @payload150kibPlus, contentTopic: contentTopic)
|
|
|
|
doAssert(
|
|
client.wakuRlnRelay
|
|
.appendRLNProof(
|
|
message151kibPlus, epoch + float64(client.wakuRlnRelay.rlnEpochSizeSec * 3)
|
|
)
|
|
.isOk()
|
|
)
|
|
|
|
# When sending the 150KiB plus message
|
|
completionFut = newPushHandlerFuture() # Reset Future
|
|
discard await client.publish(some(pubsubTopic), message151kibPlus)
|
|
|
|
# Then the message is not relayed
|
|
check not await completionFut.withTimeout(FUTURE_TIMEOUT_LONG)
|
|
|
|
suite "Waku RlnRelay - End to End - OnChain":
|
|
let runAnvil {.used.} = runAnvil()
|
|
|
|
var
|
|
pubsubTopic {.threadvar.}: PubsubTopic
|
|
contentTopic {.threadvar.}: ContentTopic
|
|
|
|
var
|
|
server {.threadvar.}: WakuNode
|
|
client {.threadvar.}: WakuNode
|
|
|
|
var
|
|
serverRemotePeerInfo {.threadvar.}: RemotePeerInfo
|
|
clientPeerId {.threadvar.}: PeerId
|
|
|
|
asyncSetup:
|
|
pubsubTopic = DefaultPubsubTopic
|
|
contentTopic = DefaultContentTopic
|
|
|
|
let
|
|
serverKey = generateSecp256k1Key()
|
|
clientKey = generateSecp256k1Key()
|
|
|
|
server = newTestWakuNode(serverKey, ValidIpAddress.init("0.0.0.0"), Port(0))
|
|
client = newTestWakuNode(clientKey, ValidIpAddress.init("0.0.0.0"), Port(0))
|
|
|
|
await allFutures(server.start(), client.start())
|
|
|
|
serverRemotePeerInfo = server.switch.peerInfo.toRemotePeerInfo()
|
|
clientPeerId = client.switch.peerInfo.toRemotePeerInfo().peerId
|
|
|
|
asyncTeardown:
|
|
await allFutures(client.stop(), server.stop())
|
|
|
|
suite "Smart Contract Availability and Interaction":
|
|
asyncTest "Invalid format contract":
|
|
let
|
|
# One character missing
|
|
invalidContractAddress = "0x000000000000000000000000000000000000000"
|
|
keystorePath =
|
|
genTempPath("rln_keystore", "test_wakunode_relay_rln-no_valid_contract")
|
|
appInfo = RlnAppInfo
|
|
password = "1234"
|
|
wakuRlnConfig1 = getWakuRlnConfigOnChain(
|
|
keystorePath, appInfo, invalidContractAddress, password, 0
|
|
)
|
|
wakuRlnConfig2 = getWakuRlnConfigOnChain(
|
|
keystorePath, appInfo, invalidContractAddress, password, 1
|
|
)
|
|
idCredential = buildRandomIdentityCredentials()
|
|
persistRes = addMembershipCredentialsToKeystore(
|
|
idCredential, keystorePath, appInfo, invalidContractAddress, password, 1
|
|
)
|
|
assertResultOk(persistRes)
|
|
|
|
# Given the node enables Relay and Rln while subscribing to a pubsub topic
|
|
try:
|
|
await server.setupRelayWithOnChainRln(@[pubsubTopic], wakuRlnConfig1)
|
|
assert false, "Relay should fail mounting when using an invalid contract"
|
|
except CatchableError:
|
|
assert true
|
|
|
|
try:
|
|
await client.setupRelayWithOnChainRln(@[pubsubTopic], wakuRlnConfig2)
|
|
assert false, "Relay should fail mounting when using an invalid contract"
|
|
except CatchableError:
|
|
assert true
|
|
|
|
asyncTest "Unregistered contract":
|
|
# This is a very slow test due to the retries RLN does. Might take upwards of 1m-2m to finish.
|
|
let
|
|
invalidContractAddress = "0x0000000000000000000000000000000000000000"
|
|
keystorePath =
|
|
genTempPath("rln_keystore", "test_wakunode_relay_rln-no_valid_contract")
|
|
appInfo = RlnAppInfo
|
|
password = "1234"
|
|
|
|
# Connect to the eth client
|
|
discard await newWeb3(EthClient)
|
|
|
|
var serverErrorFuture = Future[string].new()
|
|
proc serverFatalErrorHandler(errMsg: string) {.gcsafe, closure, raises: [].} =
|
|
serverErrorFuture.complete(errMsg)
|
|
|
|
var clientErrorFuture = Future[string].new()
|
|
proc clientFatalErrorHandler(errMsg: string) {.gcsafe, closure, raises: [].} =
|
|
clientErrorFuture.complete(errMsg)
|
|
|
|
let
|
|
wakuRlnConfig1 = getWakuRlnConfigOnChain(
|
|
keystorePath,
|
|
appInfo,
|
|
invalidContractAddress,
|
|
password,
|
|
0,
|
|
some(serverFatalErrorHandler),
|
|
)
|
|
wakuRlnConfig2 = getWakuRlnConfigOnChain(
|
|
keystorePath,
|
|
appInfo,
|
|
invalidContractAddress,
|
|
password,
|
|
1,
|
|
some(clientFatalErrorHandler),
|
|
)
|
|
|
|
# Given the node enable Relay and Rln while subscribing to a pubsub topic.
|
|
# The withTimeout call is a workaround for the test not to terminate with an exception.
|
|
# However, it doesn't reduce the retries against the blockchain that the mounting rln process attempts (until it accepts failure).
|
|
# Note: These retries might be an unintended library issue.
|
|
discard await server
|
|
.setupRelayWithOnChainRln(@[pubsubTopic], wakuRlnConfig1)
|
|
.withTimeout(FUTURE_TIMEOUT)
|
|
discard await client
|
|
.setupRelayWithOnChainRln(@[pubsubTopic], wakuRlnConfig2)
|
|
.withTimeout(FUTURE_TIMEOUT)
|
|
|
|
check:
|
|
(await serverErrorFuture.waitForResult()).get() ==
|
|
"Failed to get the storage index: No response from the Web3 provider"
|
|
(await clientErrorFuture.waitForResult()).get() ==
|
|
"Failed to get the storage index: No response from the Web3 provider"
|
|
|
|
asyncTest "Valid contract":
|
|
#[
|
|
# Notes
|
|
## Issues
|
|
### TreeIndex
|
|
For some reason the calls to `getWakuRlnConfigOnChain` need to be made with `treeIndex` = 0 and 1, in that order.
|
|
But the registration needs to be made with 1 and 2.
|
|
#### Solutions
|
|
Requires investigation
|
|
### Monkeypatching
|
|
Instead of running the idCredentials monkeypatch, passing the correct membershipIndex and keystorePath and keystorePassword should work.
|
|
#### Solutions
|
|
A) Using the register callback to fetch the correct membership
|
|
B) Using two different keystores, one for each rlnconfig. If there's only one key, it will fetch it regardless of membershipIndex.
|
|
##### A
|
|
- Register is not calling callback even though register is happening, this should happen.
|
|
- This command should be working, but it doesn't on the current HEAD of the branch, it does work on master, which suggest there's something wrong with the branch.
|
|
- nim c -r --out:build/onchain -d:chronicles_log_level=NOTICE --verbosity:0 --hints:off -d:git_version="v0.27.0-rc.0-3-gaa9c30" -d:release --passL:librln_v0.3.7.a --passL:-lm tests/waku_rln_relay/test_rln_group_manager_onchain.nim && onchain_group_test
|
|
- All modified files are tests/*, which is a bit weird. Might be interesting re-creating the branch slowly, and checking out why this is happening.
|
|
##### B
|
|
Untested
|
|
]#
|
|
|
|
let
|
|
onChainGroupManager = await setup()
|
|
contractAddress = onChainGroupManager.ethContractAddress
|
|
keystorePath =
|
|
genTempPath("rln_keystore", "test_wakunode_relay_rln-valid_contract")
|
|
appInfo = RlnAppInfo
|
|
password = "1234"
|
|
rlnInstance = onChainGroupManager.rlnInstance
|
|
assertResultOk(createAppKeystore(keystorePath, appInfo))
|
|
|
|
# Generate configs before registering the credentials. Otherwise the file gets cleared up.
|
|
let
|
|
wakuRlnConfig1 =
|
|
getWakuRlnConfigOnChain(keystorePath, appInfo, contractAddress, password, 0)
|
|
wakuRlnConfig2 =
|
|
getWakuRlnConfigOnChain(keystorePath, appInfo, contractAddress, password, 1)
|
|
|
|
# Generate credentials
|
|
let
|
|
idCredential1 = rlnInstance.membershipKeyGen().get()
|
|
idCredential2 = rlnInstance.membershipKeyGen().get()
|
|
|
|
discard await onChainGroupManager.init()
|
|
try:
|
|
# Register credentials in the chain
|
|
waitFor onChainGroupManager.register(idCredential1)
|
|
waitFor onChainGroupManager.register(idCredential2)
|
|
except Exception:
|
|
assert false, "Failed to register credentials: " & getCurrentExceptionMsg()
|
|
|
|
# Add credentials to keystore
|
|
let
|
|
persistRes1 = addMembershipCredentialsToKeystore(
|
|
idCredential1, keystorePath, appInfo, contractAddress, password, 0
|
|
)
|
|
persistRes2 = addMembershipCredentialsToKeystore(
|
|
idCredential2, keystorePath, appInfo, contractAddress, password, 1
|
|
)
|
|
|
|
assertResultOk(persistRes1)
|
|
assertResultOk(persistRes2)
|
|
|
|
await onChainGroupManager.stop()
|
|
|
|
# Given the node enables Relay and Rln while subscribing to a pubsub topic
|
|
await server.setupRelayWithOnChainRln(@[pubsubTopic], wakuRlnConfig1)
|
|
await client.setupRelayWithOnChainRln(@[pubsubTopic], wakuRlnConfig2)
|
|
|
|
try:
|
|
(await server.wakuRlnRelay.groupManager.startGroupSync()).isOkOr:
|
|
raiseAssert $error
|
|
(await client.wakuRlnRelay.groupManager.startGroupSync()).isOkOr:
|
|
raiseAssert $error
|
|
|
|
# Test Hack: Monkeypatch the idCredentials into the groupManager
|
|
server.wakuRlnRelay.groupManager.idCredentials = some(idCredential1)
|
|
client.wakuRlnRelay.groupManager.idCredentials = some(idCredential2)
|
|
except Exception, CatchableError:
|
|
assert false, "exception raised: " & getCurrentExceptionMsg()
|
|
|
|
# And the nodes are connected
|
|
let serverRemotePeerInfo = server.switch.peerInfo.toRemotePeerInfo()
|
|
await client.connectToNodes(@[serverRemotePeerInfo])
|
|
|
|
# And the node registers the completion handler
|
|
var completionFuture = subscribeCompletionHandler(server, pubsubTopic)
|
|
|
|
# When the client sends a valid RLN message
|
|
let isCompleted =
|
|
await sendRlnMessage(client, pubsubTopic, contentTopic, completionFuture)
|
|
|
|
# Then the valid RLN message is relayed
|
|
check isCompleted
|
|
assertResultOk(await completionFuture.waitForResult())
|
|
|
|
asyncTest "Not enough gas":
|
|
let
|
|
onChainGroupManager = await setupOnchainGroupManager(amountWei = 0.u256)
|
|
contractAddress = onChainGroupManager.ethContractAddress
|
|
keystorePath =
|
|
genTempPath("rln_keystore", "test_wakunode_relay_rln-valid_contract")
|
|
appInfo = RlnAppInfo
|
|
password = "1234"
|
|
rlnInstance = onChainGroupManager.rlnInstance
|
|
assertResultOk(createAppKeystore(keystorePath, appInfo))
|
|
|
|
# Generate credentials
|
|
let idCredential = rlnInstance.membershipKeyGen().get()
|
|
|
|
discard await onChainGroupManager.init()
|
|
var errorFuture = Future[string].new()
|
|
onChainGroupManager.onFatalErrorAction = proc(
|
|
errMsg: string
|
|
) {.gcsafe, closure.} =
|
|
errorFuture.complete(errMsg)
|
|
try:
|
|
# Register credentials in the chain
|
|
waitFor onChainGroupManager.register(idCredential)
|
|
assert false, "Should have failed to register credentials given there is 0 gas"
|
|
except Exception:
|
|
assert true
|
|
|
|
check (await errorFuture.waitForResult()).get() ==
|
|
"Failed to register the member: {\"code\":-32003,\"message\":\"Insufficient funds for gas * price + value\"}"
|
|
await onChainGroupManager.stop()
|
|
|
|
suite "RLN Relay Configuration and Parameters":
|
|
asyncTest "RLN Relay Credential Path":
|
|
let
|
|
onChainGroupManager = await setup()
|
|
contractAddress = onChainGroupManager.ethContractAddress
|
|
keystorePath =
|
|
genTempPath("rln_keystore", "test_wakunode_relay_rln-valid_contract")
|
|
appInfo = RlnAppInfo
|
|
password = "1234"
|
|
rlnInstance = onChainGroupManager.rlnInstance
|
|
assertResultOk(createAppKeystore(keystorePath, appInfo))
|
|
|
|
# Generate configs before registering the credentials. Otherwise the file gets cleared up.
|
|
let
|
|
wakuRlnConfig1 =
|
|
getWakuRlnConfigOnChain(keystorePath, appInfo, contractAddress, password, 0)
|
|
wakuRlnConfig2 =
|
|
getWakuRlnConfigOnChain(keystorePath, appInfo, contractAddress, password, 1)
|
|
|
|
# Given the node enables Relay and Rln while subscribing to a pubsub topic
|
|
await server.setupRelayWithOnChainRln(@[pubsubTopic], wakuRlnConfig1)
|
|
await client.setupRelayWithOnChainRln(@[pubsubTopic], wakuRlnConfig2)
|
|
|
|
try:
|
|
(await server.wakuRlnRelay.groupManager.startGroupSync()).isOkOr:
|
|
raiseAssert $error
|
|
(await client.wakuRlnRelay.groupManager.startGroupSync()).isOkOr:
|
|
raiseAssert $error
|
|
|
|
# Test Hack: Monkeypatch the idCredentials into the groupManager
|
|
echo server.wakuRlnRelay.groupManager.idCredentials
|
|
echo client.wakuRlnRelay.groupManager.idCredentials
|
|
except Exception, CatchableError:
|
|
assert false, "exception raised: " & getCurrentExceptionMsg()
|
|
|
|
# And the nodes are connected
|
|
let serverRemotePeerInfo = server.switch.peerInfo.toRemotePeerInfo()
|
|
await client.connectToNodes(@[serverRemotePeerInfo])
|
|
|
|
# And the node registers the completion handler
|
|
var completionFuture = subscribeCompletionHandler(server, pubsubTopic)
|
|
|
|
# When the client attempts to send a message
|
|
try:
|
|
let isCompleted =
|
|
await sendRlnMessage(client, pubsubTopic, contentTopic, completionFuture)
|
|
assert false, "Should have failed to send a message"
|
|
except AssertionDefect as e:
|
|
# Then the message is not relayed
|
|
assert e.msg.endsWith("identity credentials are not set")
|
|
|
|
suite "RLN Relay Resilience, Security and Compatibility":
|
|
asyncTest "Key Management and Integrity":
|
|
let
|
|
onChainGroupManager = await setup()
|
|
contractAddress = onChainGroupManager.ethContractAddress
|
|
keystorePath =
|
|
genTempPath("rln_keystore", "test_wakunode_relay_rln-valid_contract")
|
|
appInfo = RlnAppInfo
|
|
password = "1234"
|
|
rlnInstance = onChainGroupManager.rlnInstance
|
|
assertResultOk(createAppKeystore(keystorePath, appInfo))
|
|
|
|
# Generate configs before registering the credentials. Otherwise the file gets cleared up.
|
|
let
|
|
wakuRlnConfig1 =
|
|
getWakuRlnConfigOnChain(keystorePath, appInfo, contractAddress, password, 0)
|
|
wakuRlnConfig2 =
|
|
getWakuRlnConfigOnChain(keystorePath, appInfo, contractAddress, password, 1)
|
|
|
|
# Generate credentials
|
|
let
|
|
idCredential1 = rlnInstance.membershipKeyGen().get()
|
|
idCredential2 = rlnInstance.membershipKeyGen().get()
|
|
|
|
discard await onChainGroupManager.init()
|
|
try:
|
|
# Register credentials in the chain
|
|
waitFor onChainGroupManager.register(idCredential1)
|
|
waitFor onChainGroupManager.register(idCredential2)
|
|
except Exception:
|
|
assert false, "Failed to register credentials: " & getCurrentExceptionMsg()
|
|
|
|
# Add credentials to keystore
|
|
let
|
|
persistRes1 = addMembershipCredentialsToKeystore(
|
|
idCredential1, keystorePath, appInfo, contractAddress, password, 0
|
|
)
|
|
persistRes2 = addMembershipCredentialsToKeystore(
|
|
idCredential2, keystorePath, appInfo, contractAddress, password, 1
|
|
)
|
|
|
|
assertResultOk(persistRes1)
|
|
assertResultOk(persistRes2)
|
|
|
|
# await onChainGroupManager.stop()
|
|
|
|
let
|
|
registryContract = onChainGroupManager.registryContract.get()
|
|
storageIndex = (await registryContract.usingStorageIndex().call())
|
|
rlnContractAddress = await registryContract.storages(storageIndex).call()
|
|
contract = onChainGroupManager.ethRpc.get().contractSender(
|
|
RlnStorage, rlnContractAddress
|
|
)
|
|
contract2 = onChainGroupManager.rlnContract.get()
|
|
|
|
echo "###"
|
|
echo await (contract.memberExists(idCredential1.idCommitment.toUInt256()).call())
|
|
echo await (contract.memberExists(idCredential2.idCommitment.toUInt256()).call())
|
|
echo await (contract2.memberExists(idCredential1.idCommitment.toUInt256()).call())
|
|
echo await (contract2.memberExists(idCredential2.idCommitment.toUInt256()).call())
|
|
echo "###"
|
|
|
|
################################
|
|
## Terminating/removing Anvil
|
|
################################
|
|
|
|
# We stop Anvil daemon
|
|
stopAnvil(runAnvil)
|