2022-09-06 18:43:46 +00:00
{. used . }
import
std / sequtils ,
stew / byteutils ,
2022-11-04 09:52:08 +00:00
stew / shims / net as stewNet ,
2022-09-06 18:43:46 +00:00
testutils / unittests ,
2022-11-04 09:52:08 +00:00
chronicles ,
chronos ,
2022-09-06 18:43:46 +00:00
libp2p / crypto / crypto ,
libp2p / peerid ,
libp2p / multiaddress ,
libp2p / switch ,
libp2p / protocols / pubsub / pubsub ,
eth / keys
import
2022-11-04 09:52:08 +00:00
.. / .. / waku / v2 / node / waku_node ,
.. / .. / waku / v2 / protocol / waku_message ,
2022-11-21 14:15:03 +00:00
.. / .. / waku / v2 / protocol / waku_rln_relay ,
2023-02-08 15:26:23 +00:00
.. / .. / waku / v2 / protocol / waku_keystore ,
2022-11-04 09:52:08 +00:00
.. / .. / waku / v2 / utils / peers
2022-09-06 18:43:46 +00:00
from std / times import epochTime
2023-02-10 16:55:47 +00:00
2022-09-30 12:43:42 +00:00
const RlnRelayPubsubTopic = " waku/2/rlnrelay/proto "
2022-09-06 18:43:46 +00:00
procSuite " WakuNode - RLN relay " :
let rng = keys . newRng ( )
asyncTest " testing rln-relay with valid proof " :
let
# publisher node
nodeKey1 = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2022-11-03 13:47:56 +00:00
node1 = WakuNode . new ( nodeKey1 , ValidIpAddress . init ( " 0.0.0.0 " ) , Port ( 60300 ) )
2022-09-06 18:43:46 +00:00
# Relay node
nodeKey2 = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2022-11-03 13:47:56 +00:00
node2 = WakuNode . new ( nodeKey2 , ValidIpAddress . init ( " 0.0.0.0 " ) , Port ( 60302 ) )
2022-09-06 18:43:46 +00:00
# Subscriber
nodeKey3 = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2022-11-03 13:47:56 +00:00
node3 = WakuNode . new ( nodeKey3 , ValidIpAddress . init ( " 0.0.0.0 " ) , Port ( 60303 ) )
2022-09-06 18:43:46 +00:00
2022-09-30 12:43:42 +00:00
rlnRelayPubSubTopic = RlnRelayPubsubTopic
2022-09-06 18:43:46 +00:00
contentTopic = ContentTopic ( " /waku/2/default-content/proto " )
# set up three nodes
# node1
2023-02-10 16:55:47 +00:00
await node1 . mountRelay ( @ [ DefaultPubsubTopic , rlnRelayPubSubTopic ] )
2022-11-04 03:00:42 +00:00
2022-09-06 18:43:46 +00:00
# mount rlnrelay in off-chain mode
2022-12-13 09:26:24 +00:00
await node1 . mountRlnRelay ( WakuRlnConfig ( rlnRelayDynamic : false ,
rlnRelayPubsubTopic : rlnRelayPubSubTopic ,
rlnRelayContentTopic : contentTopic ,
rlnRelayMembershipIndex : MembershipIndex ( 1 ) ,
) )
2022-11-04 03:00:42 +00:00
2022-09-06 18:43:46 +00:00
await node1 . start ( )
# node 2
2023-02-10 16:55:47 +00:00
await node2 . mountRelay ( @ [ DefaultPubsubTopic , rlnRelayPubSubTopic ] )
2022-09-06 18:43:46 +00:00
# mount rlnrelay in off-chain mode
2022-12-13 09:26:24 +00:00
await node2 . mountRlnRelay ( WakuRlnConfig ( rlnRelayDynamic : false ,
rlnRelayPubsubTopic : rlnRelayPubSubTopic ,
rlnRelayContentTopic : contentTopic ,
rlnRelayMembershipIndex : MembershipIndex ( 2 ) ,
) )
2022-11-04 03:00:42 +00:00
2022-09-06 18:43:46 +00:00
await node2 . start ( )
# node 3
2023-02-10 16:55:47 +00:00
await node3 . mountRelay ( @ [ DefaultPubsubTopic , rlnRelayPubSubTopic ] )
2022-11-04 03:00:42 +00:00
2022-12-13 09:26:24 +00:00
await node3 . mountRlnRelay ( WakuRlnConfig ( rlnRelayDynamic : false ,
rlnRelayPubsubTopic : rlnRelayPubSubTopic ,
rlnRelayContentTopic : contentTopic ,
rlnRelayMembershipIndex : MembershipIndex ( 3 ) ,
) )
2022-11-04 03:00:42 +00:00
2022-09-06 18:43:46 +00:00
await node3 . start ( )
# connect them together
await node1 . connectToNodes ( @ [ node2 . switch . peerInfo . toRemotePeerInfo ( ) ] )
await node3 . connectToNodes ( @ [ node2 . switch . peerInfo . toRemotePeerInfo ( ) ] )
var completionFut = newFuture [ bool ] ( )
proc relayHandler ( topic : string , data : seq [ byte ] ) {. async , gcsafe . } =
2022-11-07 15:24:16 +00:00
let msg = WakuMessage . decode ( data )
2022-09-06 18:43:46 +00:00
if msg . isOk ( ) :
debug " The received topic: " , topic
if topic = = rlnRelayPubSubTopic :
completionFut . complete ( true )
# mount the relay handler
node3 . subscribe ( rlnRelayPubSubTopic , relayHandler )
await sleepAsync ( 2000 . millis )
# prepare the message payload
let payload = " Hello " . toBytes ( )
# prepare the epoch
var message = WakuMessage ( payload : @ payload , contentTopic : contentTopic )
doAssert ( node1 . wakuRlnRelay . appendRLNProof ( message , epochTime ( ) ) )
## node1 publishes a message with a rate limit proof, the message is then relayed to node2 which in turn
## verifies the rate limit proof of the message and relays the message to node3
## verification at node2 occurs inside a topic validator which is installed as part of the waku-rln-relay mount proc
await node1 . publish ( rlnRelayPubSubTopic , message )
await sleepAsync ( 2000 . millis )
check :
( await completionFut . withTimeout ( 10 . seconds ) ) = = true
await node1 . stop ( )
await node2 . stop ( )
await node3 . stop ( )
asyncTest " testing rln-relay with invalid proof " :
let
# publisher node
nodeKey1 = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2022-11-03 13:47:56 +00:00
node1 = WakuNode . new ( nodeKey1 , ValidIpAddress . init ( " 0.0.0.0 " ) , Port ( 60310 ) )
2022-09-06 18:43:46 +00:00
# Relay node
nodeKey2 = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2022-11-03 13:47:56 +00:00
node2 = WakuNode . new ( nodeKey2 , ValidIpAddress . init ( " 0.0.0.0 " ) , Port ( 60312 ) )
2022-09-06 18:43:46 +00:00
# Subscriber
nodeKey3 = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2022-11-03 13:47:56 +00:00
node3 = WakuNode . new ( nodeKey3 , ValidIpAddress . init ( " 0.0.0.0 " ) , Port ( 60313 ) )
2022-09-06 18:43:46 +00:00
2022-09-30 12:43:42 +00:00
rlnRelayPubSubTopic = RlnRelayPubsubTopic
2022-09-06 18:43:46 +00:00
contentTopic = ContentTopic ( " /waku/2/default-content/proto " )
2022-12-13 09:26:24 +00:00
# set up three nodes
# node1
2022-09-06 18:43:46 +00:00
# set up three nodes
# node1
2023-02-10 16:55:47 +00:00
await node1 . mountRelay ( @ [ DefaultPubsubTopic , rlnRelayPubSubTopic ] )
2022-11-04 03:00:42 +00:00
2022-09-06 18:43:46 +00:00
# mount rlnrelay in off-chain mode
2022-12-13 09:26:24 +00:00
await node1 . mountRlnRelay ( WakuRlnConfig ( rlnRelayDynamic : false ,
rlnRelayPubsubTopic : rlnRelayPubSubTopic ,
rlnRelayContentTopic : contentTopic ,
rlnRelayMembershipIndex : MembershipIndex ( 1 ) ,
) )
2022-09-06 18:43:46 +00:00
await node1 . start ( )
# node 2
2023-02-10 16:55:47 +00:00
await node2 . mountRelay ( @ [ DefaultPubsubTopic , rlnRelayPubSubTopic ] )
2022-09-06 18:43:46 +00:00
# mount rlnrelay in off-chain mode
2022-12-13 09:26:24 +00:00
await node2 . mountRlnRelay ( WakuRlnConfig ( rlnRelayDynamic : false ,
rlnRelayPubsubTopic : rlnRelayPubSubTopic ,
rlnRelayContentTopic : contentTopic ,
rlnRelayMembershipIndex : MembershipIndex ( 2 ) ,
) )
2022-09-06 18:43:46 +00:00
await node2 . start ( )
# node 3
2023-02-10 16:55:47 +00:00
await node3 . mountRelay ( @ [ DefaultPubsubTopic , rlnRelayPubSubTopic ] )
2022-11-04 03:00:42 +00:00
2022-12-13 09:26:24 +00:00
await node3 . mountRlnRelay ( WakuRlnConfig ( rlnRelayDynamic : false ,
rlnRelayPubsubTopic : rlnRelayPubSubTopic ,
rlnRelayContentTopic : contentTopic ,
rlnRelayMembershipIndex : MembershipIndex ( 3 ) ,
) )
2022-09-06 18:43:46 +00:00
await node3 . start ( )
# connect them together
await node1 . connectToNodes ( @ [ node2 . switch . peerInfo . toRemotePeerInfo ( ) ] )
await node3 . connectToNodes ( @ [ node2 . switch . peerInfo . toRemotePeerInfo ( ) ] )
# define a custom relay handler
var completionFut = newFuture [ bool ] ( )
proc relayHandler ( topic : string , data : seq [ byte ] ) {. async , gcsafe . } =
2022-11-07 15:24:16 +00:00
let msg = WakuMessage . decode ( data )
2022-09-06 18:43:46 +00:00
if msg . isOk ( ) :
debug " The received topic: " , topic
if topic = = rlnRelayPubSubTopic :
completionFut . complete ( true )
# mount the relay handler
node3 . subscribe ( rlnRelayPubSubTopic , relayHandler )
await sleepAsync ( 2000 . millis )
# prepare the message payload
let payload = " Hello " . toBytes ( )
# prepare the epoch
let epoch = getCurrentEpoch ( )
# prepare the proof
let
contentTopicBytes = contentTopic . toBytes
input = concat ( payload , contentTopicBytes )
2023-02-10 16:55:47 +00:00
extraBytes : seq [ byte ] = @ [ byte ( 1 ) , 2 , 3 ]
2022-10-07 19:24:54 +00:00
rateLimitProofRes = node1 . wakuRlnRelay . rlnInstance . proofGen ( data = concat ( input , extraBytes ) , # we add extra bytes to invalidate proof verification against original payload
2022-12-14 11:28:09 +00:00
memKeys = node1 . wakuRlnRelay . identityCredential ,
2022-10-07 19:24:54 +00:00
memIndex = MembershipIndex ( 1 ) ,
2022-09-06 18:43:46 +00:00
epoch = epoch )
2022-11-22 17:29:43 +00:00
require :
rateLimitProofRes . isOk ( )
let rateLimitProof = rateLimitProofRes . get ( ) . encode ( ) . buffer
2022-09-06 18:43:46 +00:00
let message = WakuMessage ( payload : @ payload ,
contentTopic : contentTopic ,
proof : rateLimitProof )
## node1 publishes a message with an invalid rln proof, the message is then relayed to node2 which in turn
## attempts to verify the rate limit proof and fails hence does not relay the message to node3, thus the relayHandler of node3
## never gets called
## verification at node2 occurs inside a topic validator which is installed as part of the waku-rln-relay mount proc
await node1 . publish ( rlnRelayPubSubTopic , message )
await sleepAsync ( 2000 . millis )
check :
# the relayHandler of node3 never gets called
( await completionFut . withTimeout ( 10 . seconds ) ) = = false
await node1 . stop ( )
await node2 . stop ( )
await node3 . stop ( )
asyncTest " testing rln-relay double-signaling detection " :
let
# publisher node
nodeKey1 = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2022-11-03 13:47:56 +00:00
node1 = WakuNode . new ( nodeKey1 , ValidIpAddress . init ( " 0.0.0.0 " ) , Port ( 60320 ) )
2022-09-06 18:43:46 +00:00
# Relay node
nodeKey2 = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2022-11-03 13:47:56 +00:00
node2 = WakuNode . new ( nodeKey2 , ValidIpAddress . init ( " 0.0.0.0 " ) , Port ( 60322 ) )
2022-09-06 18:43:46 +00:00
# Subscriber
nodeKey3 = crypto . PrivateKey . random ( Secp256k1 , rng [ ] ) [ ]
2022-11-03 13:47:56 +00:00
node3 = WakuNode . new ( nodeKey3 , ValidIpAddress . init ( " 0.0.0.0 " ) , Port ( 60323 ) )
2022-09-06 18:43:46 +00:00
2022-09-30 12:43:42 +00:00
rlnRelayPubSubTopic = RlnRelayPubsubTopic
2022-09-06 18:43:46 +00:00
contentTopic = ContentTopic ( " /waku/2/default-content/proto " )
# set up three nodes
# node1
2023-02-10 16:55:47 +00:00
await node1 . mountRelay ( @ [ DefaultPubsubTopic , rlnRelayPubSubTopic ] )
2022-12-13 09:26:24 +00:00
2022-09-06 18:43:46 +00:00
# mount rlnrelay in off-chain mode
2022-12-13 09:26:24 +00:00
await node1 . mountRlnRelay ( WakuRlnConfig ( rlnRelayDynamic : false ,
rlnRelayPubsubTopic : rlnRelayPubSubTopic ,
rlnRelayContentTopic : contentTopic ,
rlnRelayMembershipIndex : MembershipIndex ( 1 ) ,
) )
2022-11-04 03:00:42 +00:00
2022-09-06 18:43:46 +00:00
await node1 . start ( )
# node 2
2023-02-10 16:55:47 +00:00
await node2 . mountRelay ( @ [ DefaultPubsubTopic , rlnRelayPubSubTopic ] )
2022-12-13 09:26:24 +00:00
2022-09-06 18:43:46 +00:00
# mount rlnrelay in off-chain mode
2022-12-13 09:26:24 +00:00
await node2 . mountRlnRelay ( WakuRlnConfig ( rlnRelayDynamic : false ,
rlnRelayPubsubTopic : rlnRelayPubSubTopic ,
rlnRelayContentTopic : contentTopic ,
rlnRelayMembershipIndex : MembershipIndex ( 2 ) ,
) )
2022-11-04 03:00:42 +00:00
2022-09-06 18:43:46 +00:00
await node2 . start ( )
# node 3
2023-02-10 16:55:47 +00:00
await node3 . mountRelay ( @ [ DefaultPubsubTopic , rlnRelayPubSubTopic ] )
2022-12-13 09:26:24 +00:00
2022-09-06 18:43:46 +00:00
# mount rlnrelay in off-chain mode
2022-12-13 09:26:24 +00:00
await node3 . mountRlnRelay ( WakuRlnConfig ( rlnRelayDynamic : false ,
rlnRelayPubsubTopic : rlnRelayPubSubTopic ,
rlnRelayContentTopic : contentTopic ,
rlnRelayMembershipIndex : MembershipIndex ( 3 ) ,
) )
2022-11-04 03:00:42 +00:00
2022-09-06 18:43:46 +00:00
await node3 . start ( )
# connect the nodes together node1 <-> node2 <-> node3
await node1 . connectToNodes ( @ [ node2 . switch . peerInfo . toRemotePeerInfo ( ) ] )
await node3 . connectToNodes ( @ [ node2 . switch . peerInfo . toRemotePeerInfo ( ) ] )
# get the current epoch time
let time = epochTime ( )
# create some messages with rate limit proofs
var
wm1 = WakuMessage ( payload : " message 1 " . toBytes ( ) , contentTopic : contentTopic )
proofAdded1 = node3 . wakuRlnRelay . appendRLNProof ( wm1 , time )
# another message in the same epoch as wm1, it will break the messaging rate limit
wm2 = WakuMessage ( payload : " message 2 " . toBytes ( ) , contentTopic : contentTopic )
proofAdded2 = node3 . wakuRlnRelay . appendRLNProof ( wm2 , time )
# wm3 points to the next epoch
wm3 = WakuMessage ( payload : " message 3 " . toBytes ( ) , contentTopic : contentTopic )
2022-09-30 12:43:42 +00:00
proofAdded3 = node3 . wakuRlnRelay . appendRLNProof ( wm3 , time + EpochUnitSeconds )
2022-09-06 18:43:46 +00:00
wm4 = WakuMessage ( payload : " message 4 " . toBytes ( ) , contentTopic : contentTopic )
# check proofs are added correctly
check :
proofAdded1
proofAdded2
proofAdded3
# relay handler for node3
var completionFut1 = newFuture [ bool ] ( )
var completionFut2 = newFuture [ bool ] ( )
var completionFut3 = newFuture [ bool ] ( )
var completionFut4 = newFuture [ bool ] ( )
proc relayHandler ( topic : string , data : seq [ byte ] ) {. async , gcsafe . } =
2022-11-07 15:24:16 +00:00
let msg = WakuMessage . decode ( data )
2022-09-06 18:43:46 +00:00
if msg . isOk ( ) :
let wm = msg . value ( )
debug " The received topic: " , topic
if topic = = rlnRelayPubSubTopic :
if wm = = wm1 :
completionFut1 . complete ( true )
if wm = = wm2 :
completionFut2 . complete ( true )
if wm = = wm3 :
completionFut3 . complete ( true )
if wm = = wm4 :
completionFut4 . complete ( true )
# mount the relay handler for node3
node3 . subscribe ( rlnRelayPubSubTopic , relayHandler )
await sleepAsync ( 2000 . millis )
## node1 publishes and relays 4 messages to node2
## verification at node2 occurs inside a topic validator which is installed as part of the waku-rln-relay mount proc
## node2 relays either of wm1 or wm2 to node3, depending on which message arrives at node2 first
## node2 should detect either of wm1 or wm2 as spam and not relay it
## node2 should relay wm3 to node3
## node2 should not relay wm4 because it has no valid rln proof
await node1 . publish ( rlnRelayPubSubTopic , wm1 )
await node1 . publish ( rlnRelayPubSubTopic , wm2 )
await node1 . publish ( rlnRelayPubSubTopic , wm3 )
await node1 . publish ( rlnRelayPubSubTopic , wm4 )
await sleepAsync ( 2000 . millis )
let
res1 = await completionFut1 . withTimeout ( 10 . seconds )
res2 = await completionFut2 . withTimeout ( 10 . seconds )
check :
( res1 and res2 ) = = false # either of the wm1 and wm2 is found as spam hence not relayed
( await completionFut3 . withTimeout ( 10 . seconds ) ) = = true
( await completionFut4 . withTimeout ( 10 . seconds ) ) = = false
await node1 . stop ( )
await node2 . stop ( )
2023-02-10 16:55:47 +00:00
await node3 . stop ( )