deploy: d851d4842489b1cf0cfeb65a9bd03689ce09d991

This commit is contained in:
staheri14 2022-02-16 23:22:59 +00:00
parent 58b03b8c84
commit 5a2680dba8
7 changed files with 83 additions and 29 deletions

View File

@ -129,6 +129,32 @@ proc showChatPrompt(c: Chat) =
except IOError: except IOError:
discard discard
proc getChatLine(c: Chat, msg:WakuMessage): Result[string, string]=
when PayloadV1:
# Use Waku v1 payload encoding/encryption
let
keyInfo = KeyInfo(kind: Symmetric, symKey: c.symKey)
decodedPayload = decodePayload(decoded.get(), keyInfo)
if decodedPayload.isOK():
let
pb = Chat2Message.init(decodedPayload.get().payload)
chatLine = if pb.isOk: pb[].toString()
else: string.fromBytes(decodedPayload.get().payload)
return ok(chatLine)
else:
debug "Invalid encoded WakuMessage payload",
error = decodedPayload.error
return err("Invalid encoded WakuMessage payload")
else:
# No payload encoding/encryption from Waku
let
pb = Chat2Message.init(msg.payload)
chatLine = if pb.isOk: pb[].toString()
else: string.fromBytes(msg.payload)
return ok(chatline)
proc printReceivedMessage(c: Chat, msg: WakuMessage) = proc printReceivedMessage(c: Chat, msg: WakuMessage) =
when PayloadV1: when PayloadV1:
# Use Waku v1 payload encoding/encryption # Use Waku v1 payload encoding/encryption
@ -225,6 +251,8 @@ proc publish(c: Chat, line: string) =
debug "could not append rate limit proof to the message", success=success debug "could not append rate limit proof to the message", success=success
else: else:
debug "rate limit proof is appended to the message", success=success debug "rate limit proof is appended to the message", success=success
# TODO move it to log after doogfooding
echo "--rln epoch: ", fromEpoch(message.proof.epoch)
if not c.node.wakuLightPush.isNil(): if not c.node.wakuLightPush.isNil():
# Attempt lightpush # Attempt lightpush
asyncSpawn c.node.lightpush(DefaultTopic, message, handler) asyncSpawn c.node.lightpush(DefaultTopic, message, handler)
@ -245,6 +273,7 @@ proc publish(c: Chat, line: string) =
debug "could not append rate limit proof to the message", success=success debug "could not append rate limit proof to the message", success=success
else: else:
debug "rate limit proof is appended to the message", success=success debug "rate limit proof is appended to the message", success=success
echo "--rln epoch: ", fromEpoch(message.proof.epoch)
if not c.node.wakuLightPush.isNil(): if not c.node.wakuLightPush.isNil():
# Attempt lightpush # Attempt lightpush
@ -372,7 +401,6 @@ proc processInput(rfd: AsyncFD, rng: ref BrHmacDrbgContext) {.async.} =
prompt: false, prompt: false,
contentTopic: conf.contentTopic, contentTopic: conf.contentTopic,
symKey: generateSymKey(conf.contentTopic)) symKey: generateSymKey(conf.contentTopic))
if conf.staticnodes.len > 0: if conf.staticnodes.len > 0:
await connectToNodes(chat, conf.staticnodes) await connectToNodes(chat, conf.staticnodes)
elif conf.dnsDiscovery and conf.dnsDiscoveryUrl != "": elif conf.dnsDiscovery and conf.dnsDiscoveryUrl != "":
@ -495,16 +523,24 @@ proc processInput(rfd: AsyncFD, rng: ref BrHmacDrbgContext) {.async.} =
if conf.rlnRelay: if conf.rlnRelay:
info "WakuRLNRelay is enabled" info "WakuRLNRelay is enabled"
proc spamHandler(wakuMessage: WakuMessage) {.gcsafe, closure.} =
debug "spam handler is called"
let chatLineResult = chat.getChatLine(wakuMessage)
if chatLineResult.isOk():
echo "A spam message is found and discarded : ", chatLineResult.value
else:
echo "A spam message is found and discarded"
# set up rln relay inputs # set up rln relay inputs
let (groupOpt, memKeyPairOpt, memIndexOpt) = rlnRelaySetUp(conf.rlnRelayMemIndex) let (groupOpt, memKeyPairOpt, memIndexOpt) = rlnRelaySetUp(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) waitFor node.mountRlnRelay(groupOpt = groupOpt, memKeyPairOpt = memKeyPairOpt, memIndexOpt= memIndexOpt, onchainMode = false, pubsubTopic = conf.rlnRelayPubsubTopic, contentTopic = conf.rlnRelayContentTopic, spamHandler = some(spamHandler))
trace "membership id key", idkey=memKeyPairOpt.get().idKey.toHex debug "membership id key", idkey=memKeyPairOpt.get().idKey.toHex
trace "membership id commitment key", idCommitmentkey=memKeyPairOpt.get().idCommitment.toHex debug "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 # 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 # no error should happen as it is already captured in the unit tests
@ -514,8 +550,8 @@ proc processInput(rfd: AsyncFD, rng: ref BrHmacDrbgContext) {.async.} =
expectedRoot = STATIC_GROUP_MERKLE_ROOT expectedRoot = STATIC_GROUP_MERKLE_ROOT
if root != expectedRoot: if root != expectedRoot:
error "root mismatch: something went wrong not in Merkle tree construction" error "root mismatch: something went wrong not in Merkle tree construction"
trace "the calculated root", root debug "the calculated root", root
trace "WakuRLNRelay is mounted successfully", pubsubtopic=conf.rlnRelayPubsubTopic, contentTopic=conf.rlnRelayContentTopic debug "WakuRLNRelay is mounted successfully", pubsubtopic=conf.rlnRelayPubsubTopic, contentTopic=conf.rlnRelayContentTopic
await chat.readWriteLoop() await chat.readWriteLoop()

View File

@ -241,7 +241,7 @@ type
rlnRelayContentTopic* {. rlnRelayContentTopic* {.
desc: "the pubsub topic for which rln-relay gets enabled", desc: "the pubsub topic for which rln-relay gets enabled",
defaultValue: "waku/2/rln-relay/proto" defaultValue: "/toy-chat/2/luzhou/proto"
name: "rln-relay-content-topic" }: ContentTopic name: "rln-relay-content-topic" }: ContentTopic
rlnRelayPubsubTopic* {. rlnRelayPubsubTopic* {.

View File

@ -911,12 +911,12 @@ procSuite "WakuNode":
wm1 = WakuMessage(payload: "message 1".toBytes(), contentTopic: contentTopic) wm1 = WakuMessage(payload: "message 1".toBytes(), contentTopic: contentTopic)
proofAdded1 = node3.wakuRlnRelay.appendRLNProof(wm1, time) proofAdded1 = node3.wakuRlnRelay.appendRLNProof(wm1, time)
# another message in the same epoch as wm1, it will break the messaging rate limit # another message in the same epoch as wm1, it will break the messaging rate limit
wm2 = WakuMessage(payload: "message2".toBytes(), contentTopic: contentTopic) wm2 = WakuMessage(payload: "message 2".toBytes(), contentTopic: contentTopic)
proofAdded2 = node3.wakuRlnRelay.appendRLNProof(wm2, time) proofAdded2 = node3.wakuRlnRelay.appendRLNProof(wm2, time)
# wm3 points to the next epoch # wm3 points to the next epoch
wm3 = WakuMessage(payload: "message 3".toBytes(), contentTopic: contentTopic) wm3 = WakuMessage(payload: "message 3".toBytes(), contentTopic: contentTopic)
proofAdded3 = node3.wakuRlnRelay.appendRLNProof(wm3, time+EPOCH_UNIT_SECONDS) proofAdded3 = node3.wakuRlnRelay.appendRLNProof(wm3, time+EPOCH_UNIT_SECONDS)
wm4 = WakuMessage(payload: "message4".toBytes(), contentTopic: contentTopic) wm4 = WakuMessage(payload: "message 4".toBytes(), contentTopic: contentTopic)
# check proofs are added correctly # check proofs are added correctly
check: check:
@ -966,9 +966,7 @@ procSuite "WakuNode":
res2 = await completionFut2.withTimeout(10.seconds) res2 = await completionFut2.withTimeout(10.seconds)
check: check:
res1 or res2 == true # either of the wm1 and wm2 is relayed
(res1 and res2) == false # either of the wm1 and wm2 is found as spam hence not relayed (res1 and res2) == false # either of the wm1 and wm2 is found as spam hence not relayed
(await completionFut2.withTimeout(10.seconds)) == true
(await completionFut3.withTimeout(10.seconds)) == true (await completionFut3.withTimeout(10.seconds)) == true
(await completionFut4.withTimeout(10.seconds)) == false (await completionFut4.withTimeout(10.seconds)) == false

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-az190-599: # Libtool was configured on host fv-az272-316:
# 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

@ -470,30 +470,34 @@ proc mountStore*(node: WakuNode, store: MessageStore = nil, persistMessages: boo
node.switch.mount(node.wakuStore, protocolMatcher(WakuStoreCodec)) node.switch.mount(node.wakuStore, protocolMatcher(WakuStoreCodec))
when defined(rln): when defined(rln):
proc addRLNRelayValidator*(node: WakuNode, pubsubTopic: string, contentTopic: ContentTopic) = proc addRLNRelayValidator*(node: WakuNode, pubsubTopic: string, contentTopic: ContentTopic, spamHandler: Option[SpamHandler] = none(SpamHandler)) =
## this procedure is a thin wrapper for the pubsub addValidator method ## this procedure is a thin wrapper for the pubsub addValidator method
## it sets a validator for the waku messages published on the supplied pubsubTopic and contentTopic ## it sets a validator for the waku messages published on the supplied pubsubTopic and contentTopic
## if contentTopic is empty, then validation takes place for All the messages published on the given pubsubTopic ## if contentTopic is empty, then validation takes place for All the messages published on the given pubsubTopic
## the message validation logic is according to https://rfc.vac.dev/spec/17/ ## the message validation logic is according to https://rfc.vac.dev/spec/17/
proc validator(topic: string, message: messages.Message): Future[pubsub.ValidationResult] {.async.} = proc validator(topic: string, message: messages.Message): Future[pubsub.ValidationResult] {.async.} =
debug "rln-relay topic validator is called"
let msg = WakuMessage.init(message.data) let msg = WakuMessage.init(message.data)
if msg.isOk(): if msg.isOk():
let wakumessage = msg.value() let wakumessage = msg.value()
# check the contentTopic # check the contentTopic
if (wakumessage.contentTopic != "") and (contentTopic != "") and (wakumessage.contentTopic != contentTopic): if (wakumessage.contentTopic != "") and (contentTopic != "") and (wakumessage.contentTopic != contentTopic):
trace "content topic did not match:", contentTopic=wakumessage.contentTopic, payload=string.fromBytes(wakumessage.payload) debug "content topic did not match:", contentTopic=wakumessage.contentTopic, payload=string.fromBytes(wakumessage.payload)
return pubsub.ValidationResult.Accept return pubsub.ValidationResult.Accept
# validate the message # validate the message
let validationRes = node.wakuRlnRelay.validateMessage(wakumessage) let validationRes = node.wakuRlnRelay.validateMessage(wakumessage)
case validationRes: case validationRes:
of Valid: of Valid:
trace "message validity is verified, relaying:", wakumessage=wakumessage, payload=string.fromBytes(wakumessage.payload) debug "message validity is verified, relaying:", wakumessage=wakumessage, payload=string.fromBytes(wakumessage.payload)
return pubsub.ValidationResult.Accept return pubsub.ValidationResult.Accept
of Invalid: of Invalid:
trace "message validity could not be verified, discarding:", wakumessage=wakumessage, payload=string.fromBytes(wakumessage.payload) debug "message validity could not be verified, discarding:", wakumessage=wakumessage, payload=string.fromBytes(wakumessage.payload)
return pubsub.ValidationResult.Reject return pubsub.ValidationResult.Reject
of Spam: of Spam:
trace "A spam message is found! yay! discarding:", wakumessage=wakumessage, payload=string.fromBytes(wakumessage.payload) debug "A spam message is found! yay! discarding:", wakumessage=wakumessage, payload=string.fromBytes(wakumessage.payload)
if spamHandler.isSome:
let handler = spamHandler.get
handler(wakumessage)
return pubsub.ValidationResult.Reject return pubsub.ValidationResult.Reject
# set a validator for the supplied pubsubTopic # set a validator for the supplied pubsubTopic
let pb = PubSub(node.wakuRelay) let pb = PubSub(node.wakuRelay)
@ -508,7 +512,8 @@ when defined(rln):
memIndexOpt: Option[MembershipIndex] = none(MembershipIndex), memIndexOpt: Option[MembershipIndex] = none(MembershipIndex),
onchainMode: bool = true, onchainMode: bool = true,
pubsubTopic: string, pubsubTopic: string,
contentTopic: ContentTopic) {.async.} = contentTopic: ContentTopic,
spamHandler: Option[SpamHandler] = none(SpamHandler)) {.async.} =
# 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 # check whether inputs are provided
@ -601,8 +606,8 @@ when defined(rln):
# 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
addRLNRelayValidator(node, pubsubTopic, contentTopic) addRLNRelayValidator(node, pubsubTopic, contentTopic, spamHandler)
debug "rln relay topic validator is mounted successfully", pubsubTopic=pubsubTopic debug "rln relay topic validator is mounted successfully", pubsubTopic=pubsubTopic, contentTopic=contentTopic
node.wakuRlnRelay = rlnPeer node.wakuRlnRelay = rlnPeer

View File

@ -116,8 +116,8 @@ const
# the root is created locally, using createMembershipList proc from waku_rln_relay_utils module, and the result is hardcoded in here # the root is created locally, using createMembershipList proc from waku_rln_relay_utils module, and the result is hardcoded in here
STATIC_GROUP_MERKLE_ROOT* = "a1877a553eff12e1b21632a0545a916a5c5b8060ad7cc6c69956741134397b2d" STATIC_GROUP_MERKLE_ROOT* = "a1877a553eff12e1b21632a0545a916a5c5b8060ad7cc6c69956741134397b2d"
const EPOCH_UNIT_SECONDS* = float64(2) const EPOCH_UNIT_SECONDS* = float64(10) # the rln-relay epoch length in seconds
const MAX_CLOCK_GAP_SECONDS* = 20.0 # the maximum clock difference between peers const MAX_CLOCK_GAP_SECONDS* = 20.0 # the maximum clock difference between peers in seconds
# maximum allowed gap between the epochs of messages' RateLimitProofs # maximum allowed gap between the epochs of messages' RateLimitProofs
const MAX_EPOCH_GAP* = int64(MAX_CLOCK_GAP_SECONDS/EPOCH_UNIT_SECONDS) const MAX_EPOCH_GAP* = int64(MAX_CLOCK_GAP_SECONDS/EPOCH_UNIT_SECONDS)

View File

@ -16,6 +16,8 @@ logScope:
type RLNResult* = Result[RLN[Bn256], string] type RLNResult* = Result[RLN[Bn256], string]
type MerkleNodeResult* = Result[MerkleNode, string] type MerkleNodeResult* = Result[MerkleNode, string]
type RateLimitProofResult* = Result[RateLimitProof, string] type RateLimitProofResult* = Result[RateLimitProof, string]
type SpamHandler* = proc(wakuMessage: WakuMessage): void {.gcsafe, closure, raises: [Defect].}
# membership contract interface # membership contract interface
contract(MembershipContract): contract(MembershipContract):
# TODO define a return type of bool for register method to signify a successful registration # TODO define a return type of bool for register method to signify a successful registration
@ -157,6 +159,8 @@ proc proofGen*(rlnInstance: RLN[Bn256], data: openArray[byte], memKeys: Membersh
msg = data) msg = data)
var inputBuffer = toBuffer(serializedInputs) var inputBuffer = toBuffer(serializedInputs)
debug "input buffer ", inputBuffer
# generate the proof # generate the proof
var proof: Buffer var proof: Buffer
let proofIsSuccessful = generate_proof(rlnInstance, addr inputBuffer, addr proof) let proofIsSuccessful = generate_proof(rlnInstance, addr inputBuffer, addr proof)
@ -445,16 +449,19 @@ proc validateMessage*(rlnPeer: WakuRLNRelay, msg: WakuMessage, timeOption: Optio
# get current rln epoch # get current rln epoch
epoch = getCurrentEpoch() epoch = getCurrentEpoch()
debug "current epoch", currentEpoch=fromEpoch(epoch)
let let
msgEpoch = msg.proof.epoch msgEpoch = msg.proof.epoch
# calculate the gaps # calculate the gaps
gap = compare(epoch, msgEpoch) gap = compare(epoch, msgEpoch)
debug "message epoch", msgEpoch=fromEpoch(msgEpoch)
# validate the epoch # validate the epoch
if abs(gap) >= MAX_EPOCH_GAP: if abs(gap) >= MAX_EPOCH_GAP:
# message's epoch is too old or too ahead # message's epoch is too old or too ahead
# accept messages whose epoch is within +-MAX_EPOCH_GAP from the current epoch # accept messages whose epoch is within +-MAX_EPOCH_GAP from the current epoch
debug "invalid message: epoch gap exceeds a threshold",gap=gap debug "invalid message: epoch gap exceeds a threshold",gap=gap, payload=string.fromBytes(msg.payload)
return MessageValidationResult.Invalid return MessageValidationResult.Invalid
# verify the proof # verify the proof
@ -463,31 +470,39 @@ proc validateMessage*(rlnPeer: WakuRLNRelay, msg: WakuMessage, timeOption: Optio
input = concat(msg.payload, contentTopicBytes) input = concat(msg.payload, contentTopicBytes)
if not rlnPeer.rlnInstance.proofVerify(input, msg.proof): if not rlnPeer.rlnInstance.proofVerify(input, msg.proof):
# invalid proof # invalid proof
debug "invalid message: invalid proof" debug "invalid message: invalid proof", payload=string.fromBytes(msg.payload)
return MessageValidationResult.Invalid return MessageValidationResult.Invalid
# check if double messaging has happened # check if double messaging has happened
let hasDup = rlnPeer.hasDuplicate(msg) let hasDup = rlnPeer.hasDuplicate(msg)
if hasDup.isOk and hasDup.value == true: if hasDup.isOk and hasDup.value == true:
debug "invalid message: message is a spam" debug "invalid message: message is a spam", payload=string.fromBytes(msg.payload)
return MessageValidationResult.Spam return MessageValidationResult.Spam
# insert the message to the log # insert the message to the log
# the result of `updateLog` is discarded because message insertion is guaranteed by the implementation i.e., # the result of `updateLog` is discarded because message insertion is guaranteed by the implementation i.e.,
# it will never error out # it will never error out
discard rlnPeer.updateLog(msg) discard rlnPeer.updateLog(msg)
debug "message is valid", payload=string.fromBytes(msg.payload)
return MessageValidationResult.Valid return MessageValidationResult.Valid
proc toRLNSignal*(wakumessage: WakuMessage): seq[byte] =
## it is a utility proc that prepares the `data` parameter of the proof generation procedure i.e., `proofGen` that resides in the current module
## it extracts the `contentTopic` and the `payload` of the supplied `wakumessage` and serializes them into a byte sequence
let
contentTopicBytes = wakumessage.contentTopic.toBytes
output = concat(wakumessage.payload, contentTopicBytes)
return output
proc appendRLNProof*(rlnPeer: WakuRLNRelay, msg: var WakuMessage, senderEpochTime: float64): bool = proc appendRLNProof*(rlnPeer: WakuRLNRelay, msg: var WakuMessage, senderEpochTime: float64): bool =
## returns true if it can create and append a `RateLimitProof` to the supplied `msg` ## returns true if it can create and append a `RateLimitProof` to the supplied `msg`
## returns false otherwise ## returns false otherwise
## `senderEpochTime` indicates the number of seconds passed since Unix epoch. The fractional part holds sub-seconds. ## `senderEpochTime` indicates the number of seconds passed since Unix epoch. The fractional part holds sub-seconds.
## The `epoch` field of `RateLimitProof` is derived from the provided `senderEpochTime` (using `calcEpoch()`) ## The `epoch` field of `RateLimitProof` is derived from the provided `senderEpochTime` (using `calcEpoch()`)
let let input = msg.toRLNSignal()
contentTopicBytes = msg.contentTopic.toBytes
input = concat(msg.payload, contentTopicBytes)
var proof: RateLimitProofResult = proofGen(rlnInstance = rlnPeer.rlnInstance, data = input, var proof: RateLimitProofResult = proofGen(rlnInstance = rlnPeer.rlnInstance, data = input,
memKeys = rlnPeer.membershipKeyPair, memKeys = rlnPeer.membershipKeyPair,