nwaku/tests/wakunode2/test_validators.nim

266 lines
9.8 KiB
Nim
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{.used.}
import
std/[sequtils, sysrand, math],
stew/shims/net as stewNet,
testutils/unittests,
chronos,
libp2p/crypto/crypto,
libp2p/crypto/secp,
libp2p/multiaddress,
libp2p/protocols/pubsub/pubsub,
libp2p/protocols/pubsub/gossipsub,
libp2p/multihash,
secp256k1
import
../../apps/wakunode2/wakunode2_validator_signed,
../../waku/v2/waku_core,
../../waku/v2/node/peer_manager,
../../waku/v2/waku_node,
../../waku/v2/waku_relay,
../v2/testlib/wakucore,
../v2/testlib/wakunode
suite "WakuNode2 - Validators":
asyncTest "Spam protected topic accepts signed messages":
# Create 5 nodes
let nodes = toSeq(0..<5).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
# Protected topic and key to sign
let spamProtectedTopic = PubSubTopic("some-spam-protected-topic")
let secretKey = SkSecretKey.fromHex("5526a8990317c9b7b58d07843d270f9cd1d9aaee129294c1c478abf7261dd9e6").expect("valid key")
let publicKey = secretKey.toPublicKey()
let topicsPrivateKeys = {spamProtectedTopic: secretKey}.toTable
let topicsPublicKeys = {spamProtectedTopic: publicKey}.toTable
# Start all the nodes and mount relay with protected topic
await allFutures(nodes.mapIt(it.start()))
# Mount relay for all nodes
await allFutures(nodes.mapIt(it.mountRelay()))
# Add signed message validator to all nodes. They will only route signed messages
for node in nodes:
for topic, publicKey in topicsPublicKeys:
node.wakuRelay.addSignedTopicValidator(PubsubTopic(topic), publicKey)
# Connect the nodes in a full mesh
for i in 0..<5:
for j in 0..<5:
if i == j:
continue
let connOk = await nodes[i].peerManager.connectRelay(nodes[j].switch.peerInfo.toRemotePeerInfo())
require connOk
# Connection triggers different actions, wait for them
await sleepAsync(500.millis)
var msgReceived = 0
proc handler(pubsubTopic: PubsubTopic, data: WakuMessage) {.async, gcsafe.} =
msgReceived += 1
# Subscribe all nodes to the same topic/handler
for node in nodes: node.wakuRelay.subscribe(spamProtectedTopic, handler)
await sleepAsync(500.millis)
# Each node publishes 10 signed messages
for i in 0..<5:
for j in 0..<10:
var msg = WakuMessage(
payload: urandom(1*(10^3)), contentTopic: spamProtectedTopic,
version: 2, timestamp: now(), ephemeral: true)
# Include signature
msg.meta = secretKey.sign(SkMessage(spamProtectedTopic.msgHash(msg))).toRaw()[0..63]
await nodes[i].publish(spamProtectedTopic, msg)
# Wait for gossip
await sleepAsync(2.seconds)
# 50 messages were sent to 5 peers = 250 messages
check:
msgReceived == 250
# No invalid messages were received by any peer
for i in 0..<5:
for k, v in nodes[i].wakuRelay.peerStats.mpairs:
check:
v.topicInfos[spamProtectedTopic].invalidMessageDeliveries == 0.0
# Stop all nodes
await allFutures(nodes.mapIt(it.stop()))
asyncTest "Spam protected topic rejects non-signed and wrongly-signed messages":
# Create 5 nodes
let nodes = toSeq(0..<5).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
# Protected topic and key to sign
let spamProtectedTopic = PubSubTopic("some-spam-protected-topic")
let secretKey = SkSecretKey.fromHex("5526a8990317c9b7b58d07843d270f9cd1d9aaee129294c1c478abf7261dd9e6").expect("valid key")
let publicKey = secretKey.toPublicKey()
let topicsPrivateKeys = {spamProtectedTopic: secretKey}.toTable
let topicsPublicKeys = {spamProtectedTopic: publicKey}.toTable
# Non whitelisted secret key
let wrongSecretKey = SkSecretKey.fromHex("32ad0cc8edeb9f8a3e8635c5fe5bd200b9247a33da5e7171bd012691805151f3").expect("valid key")
# Start all the nodes and mount relay with protected topic
await allFutures(nodes.mapIt(it.start()))
# Mount relay with spam protected topics
await allFutures(nodes.mapIt(it.mountRelay()))
# Add signed message validator to all nodes. They will only route signed messages
for node in nodes:
for topic, publicKey in topicsPublicKeys:
node.wakuRelay.addSignedTopicValidator(PubsubTopic(topic), publicKey)
# Connect the nodes in a full mesh
for i in 0..<5:
for j in 0..<5:
if i == j:
continue
let connOk = await nodes[i].peerManager.connectRelay(nodes[j].switch.peerInfo.toRemotePeerInfo())
require connOk
var msgReceived = 0
proc handler(pubsubTopic: PubsubTopic, msg: WakuMessage) {.async, gcsafe.} =
msgReceived += 1
# Connection triggers different actions, wait for them
await sleepAsync(500.millis)
# Subscribe all nodes to the same topic/handler
for node in nodes: node.wakuRelay.subscribe(spamProtectedTopic, handler)
await sleepAsync(500.millis)
# Each node sends 10 messages, signed but with a non-whitelisted key (total = 50)
for i in 0..<5:
for j in 0..<10:
var msg = WakuMessage(
payload: urandom(1*(10^3)), contentTopic: spamProtectedTopic,
version: 2, timestamp: now(), ephemeral: true)
# Sign the message with a wrong key
msg.meta = wrongSecretKey.sign(SkMessage(spamProtectedTopic.msgHash(msg))).toRaw()[0..63]
await nodes[i].publish(spamProtectedTopic, msg)
# Each node sends 10 messages that are not signed (total = 50)
for i in 0..<5:
for j in 0..<10:
let unsignedMessage = WakuMessage(
payload: urandom(1*(10^3)), contentTopic: spamProtectedTopic,
version: 2, timestamp: now(), ephemeral: true)
await nodes[i].publish(spamProtectedTopic, unsignedMessage)
# Wait for gossip
await sleepAsync(2.seconds)
# Since we have a full mesh with 5 nodes and each one publishes 50+50 msgs
# there are 500 messages being sent.
# 100 are received ok in the handler (first hop)
# 400 are are wrong so rejected (rejected not relayed)
check:
msgReceived == 100
var msgRejected = 0
for i in 0..<5:
for k, v in nodes[i].wakuRelay.peerStats.mpairs:
msgRejected += v.topicInfos[spamProtectedTopic].invalidMessageDeliveries.int
check:
msgRejected == 400
await allFutures(nodes.mapIt(it.stop()))
asyncTest "Spam protected topic rejects a spammer node":
# Create 5 nodes
let nodes = toSeq(0..<5).mapIt(newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0)))
# Protected topic and key to sign
let spamProtectedTopic = PubSubTopic("some-spam-protected-topic")
let secretKey = SkSecretKey.fromHex("5526a8990317c9b7b58d07843d270f9cd1d9aaee129294c1c478abf7261dd9e6").expect("valid key")
let publicKey = secretKey.toPublicKey()
let topicsPrivateKeys = {spamProtectedTopic: secretKey}.toTable
let topicsPublicKeys = {spamProtectedTopic: publicKey}.toTable
# Non whitelisted secret key
let wrongSecretKey = SkSecretKey.fromHex("32ad0cc8edeb9f8a3e8635c5fe5bd200b9247a33da5e7171bd012691805151f3").expect("valid key")
# Start all the nodes and mount relay with protected topic
await allFutures(nodes.mapIt(it.start()))
# Mount relay for all nodes
await allFutures(nodes.mapIt(it.mountRelay()))
var msgReceived = 0
proc handler(pubsubTopic: PubsubTopic, msg: WakuMessage) {.async, gcsafe.} =
msgReceived += 1
# Subscribe all nodes to the same topic/handler
for node in nodes: node.wakuRelay.subscribe(spamProtectedTopic, handler)
await sleepAsync(500.millis)
# Add signed message validator to all nodes. They will only route signed messages
for node in nodes:
for topic, publicKey in topicsPublicKeys:
node.wakuRelay.addSignedTopicValidator(PubsubTopic(topic), publicKey)
# nodes[0] is connected only to nodes[1]
let connOk1 = await nodes[0].peerManager.connectRelay(nodes[1].switch.peerInfo.toRemotePeerInfo())
require connOk1
# rest of nodes[1..4] are connected in a full mesh
for i in 1..<5:
for j in 1..<5:
if i == j:
continue
let connOk2 = await nodes[i].peerManager.connectRelay(nodes[j].switch.peerInfo.toRemotePeerInfo())
require connOk2
# Connection triggers different actions, wait for them
await sleepAsync(500.millis)
# nodes[0] spams 50 non signed messages (nodes[0] just knows of nodes[1])
for j in 0..<50:
let unsignedMessage = WakuMessage(
payload: urandom(1*(10^3)), contentTopic: spamProtectedTopic,
version: 2, timestamp: now(), ephemeral: true)
await nodes[0].publish(spamProtectedTopic, unsignedMessage)
# nodes[0] spams 50 wrongly signed messages (nodes[0] just knows of nodes[1])
for j in 0..<50:
var msg = WakuMessage(
payload: urandom(1*(10^3)), contentTopic: spamProtectedTopic,
version: 2, timestamp: now(), ephemeral: true)
# Sign the message with a wrong key
msg.meta = wrongSecretKey.sign(SkMessage(spamProtectedTopic.msgHash(msg))).toRaw()[0..63]
await nodes[0].publish(spamProtectedTopic, msg)
# Wait for gossip
await sleepAsync(2.seconds)
# only 100 messages are received (50 + 50) which demonstrate
# nodes[1] doest gossip invalid messages.
check:
msgReceived == 100
# peer1 got invalid messages from peer0
let p0Id = nodes[0].peerInfo.peerId
check:
nodes[1].wakuRelay.peerStats[p0Id].topicInfos[spamProtectedTopic].invalidMessageDeliveries == 100.0
# peer1 did not gossip further, so no other node rx invalid messages
for i in 0..<5:
for k, v in nodes[i].wakuRelay.peerStats.mpairs:
if k == p0Id and i == 1:
continue
check:
v.topicInfos[spamProtectedTopic].invalidMessageDeliveries == 0.0
# Stop all nodes
await allFutures(nodes.mapIt(it.stop()))