2024-02-02 08:56:41 +00:00
{. used . }
import
2024-08-02 14:43:22 +00:00
std / [ tempfiles , strutils , options ] ,
2024-02-02 08:56:41 +00:00
stew / shims / net as stewNet ,
2024-08-02 14:43:22 +00:00
stew / results ,
2024-02-02 08:56:41 +00:00
testutils / unittests ,
chronos ,
libp2p / switch ,
2024-08-02 14:43:22 +00:00
libp2p / protocols / pubsub / pubsub ,
eth / keys
2024-02-02 08:56:41 +00:00
from std / times import epochTime
import
2024-08-02 14:43:22 +00:00
.. / .. / .. / 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 ,
] ,
2024-02-02 08:56:41 +00:00
.. / waku_store / store_utils ,
.. / waku_archive / archive_utils ,
2024-08-02 14:43:22 +00:00
.. / 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 * (
2024-09-10 21:07:12 +00:00
node : WakuNode , shards : seq [ RelayShard ] , wakuRlnConfig : WakuRlnConfig
2024-08-02 14:43:22 +00:00
) {. async . } =
2024-09-10 21:07:12 +00:00
await node . mountRelay ( shards )
2024-08-02 14:43:22 +00:00
await node . mountRlnRelay ( wakuRlnConfig )
suite " Waku RlnRelay - End to End - Static " :
2024-02-02 08:56:41 +00:00
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
2024-03-15 23:08:47 +00:00
let catchRes = catch :
2024-08-02 14:43:22 +00:00
await server . setupStaticRln ( 1 )
2024-02-02 08:56:41 +00:00
# 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
2024-08-02 14:43:22 +00:00
await server . setupRelayWithStaticRln ( 1 . uint , @ [ pubsubTopic ] )
await client . setupRelayWithStaticRln ( 2 . uint , @ [ pubsubTopic ] )
2024-02-02 08:56:41 +00:00
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
2024-03-15 23:08:47 +00:00
let isCompleted1 =
await sendRlnMessage ( client , pubsubTopic , contentTopic , completionFuture )
2024-02-02 08:56:41 +00:00
# Then the valid RLN message is relayed
check :
isCompleted1
completionFuture . read ( )
# When the client sends an invalid RLN message
completionFuture = newBoolFuture ( )
2024-03-15 23:08:47 +00:00
let isCompleted2 = await sendRlnMessageWithInvalidProof (
client , pubsubTopic , contentTopic , completionFuture
)
2024-02-02 08:56:41 +00:00
# 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
2024-08-02 14:43:22 +00:00
await server . setupRelayWithStaticRln ( 1 . uint , @ [ ] )
await client . setupRelayWithStaticRln ( 2 . uint , @ [ ] )
2024-02-02 08:56:41 +00:00
# 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
2024-03-15 23:08:47 +00:00
let isCompleted1 =
await sendRlnMessage ( client , pubsubTopic , contentTopic , completionFuture )
2024-02-02 08:56:41 +00:00
# Then the valid RLN message is relayed
check :
isCompleted1
completionFuture . read ( )
# When the client sends an invalid RLN message
completionFuture = newBoolFuture ( )
2024-03-15 23:08:47 +00:00
let isCompleted2 = await sendRlnMessageWithInvalidProof (
client , pubsubTopic , contentTopic , completionFuture
)
2024-02-02 08:56:41 +00:00
# Then the invalid RLN message is not relayed
check :
not isCompleted2
2024-07-26 11:27:34 +00:00
asyncTest " rln-relay-max-message-limit testing " :
let
nodekey = generateSecp256k1Key ( )
node = newTestWakuNode ( nodekey , parseIpAddress ( " 0.0.0.0 " ) , Port ( 0 ) )
2024-09-10 21:07:12 +00:00
await node . mountRelay ( @ [ DefaultRelayShard ] )
2024-07-26 11:27:34 +00:00
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 "
2024-02-02 08:56:41 +00:00
suite " Analysis of Bandwith Limitations " :
asyncTest " Valid Payload Sizes " :
# Given the node enables Relay and Rln while subscribing to a pubsub topic
2024-08-02 14:43:22 +00:00
await server . setupRelayWithStaticRln ( 1 . uint , @ [ pubsubTopic ] )
await client . setupRelayWithStaticRln ( 2 . uint , @ [ pubsubTopic ] )
2024-02-02 08:56:41 +00:00
# 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 (
2024-03-15 23:08:47 +00:00
client . wakuRlnRelay
2024-05-13 15:43:14 +00:00
. appendRLNProof (
message1b , epoch + float64 ( client . wakuRlnRelay . rlnEpochSizeSec * 0 )
)
2024-03-15 23:08:47 +00:00
. isOk ( )
2024-02-02 08:56:41 +00:00
)
doAssert (
2024-03-15 23:08:47 +00:00
client . wakuRlnRelay
2024-05-13 15:43:14 +00:00
. appendRLNProof (
message1kib , epoch + float64 ( client . wakuRlnRelay . rlnEpochSizeSec * 1 )
)
2024-03-15 23:08:47 +00:00
. isOk ( )
2024-02-02 08:56:41 +00:00
)
doAssert (
2024-03-15 23:08:47 +00:00
client . wakuRlnRelay
2024-05-13 15:43:14 +00:00
. appendRLNProof (
message150kib , epoch + float64 ( client . wakuRlnRelay . rlnEpochSizeSec * 2 )
)
2024-03-15 23:08:47 +00:00
. isOk ( )
2024-02-02 08:56:41 +00:00
)
doAssert (
2024-03-15 23:08:47 +00:00
client . wakuRlnRelay
. appendRLNProof (
2024-05-13 15:43:14 +00:00
message151kibPlus , epoch + float64 ( client . wakuRlnRelay . rlnEpochSizeSec * 3 )
2024-03-15 23:08:47 +00:00
)
. isOk ( )
2024-02-02 08:56:41 +00:00
)
# 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
2024-08-02 14:43:22 +00:00
await server . setupRelayWithStaticRln ( 1 . uint , @ [ pubsubTopic ] )
await client . setupRelayWithStaticRln ( 2 . uint , @ [ pubsubTopic ] )
2024-02-02 08:56:41 +00:00
# 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 )
2024-03-15 23:08:47 +00:00
var message151kibPlus =
WakuMessage ( payload : @ payload150kibPlus , contentTopic : contentTopic )
2024-02-02 08:56:41 +00:00
doAssert (
2024-05-13 15:43:14 +00:00
client . wakuRlnRelay
. appendRLNProof (
message151kibPlus , epoch + float64 ( client . wakuRlnRelay . rlnEpochSizeSec * 3 )
2024-02-02 08:56:41 +00:00
)
2024-05-13 15:43:14 +00:00
. isOk ( )
2024-02-02 08:56:41 +00:00
)
# 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 )
2024-08-02 14:43:22 +00:00
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 o n l y o n e k e y , i t w i l l f e t c h i t r e g a r d l e s s o f m e m b e r s h i p I n d e x .
##### A
- Register is not calling callback even though register is happening , this should happen .
- This command should be working , but it doesn ' t o n t h e c u r r e n t H E A D o f t h e b r a n c h , i t d o e s w o r k o n m a s t e r , w h i c h s u g g e s t t h e r e ' 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 setup ( ethAmount = 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 )