From ab712ea8d5ce30efb644fd8f966165fcfd375b88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pavl=C3=ADn?= Date: Wed, 12 Jun 2024 12:25:10 +0200 Subject: [PATCH 1/5] WIP: add network spammer code --- apps/wakunode2/spammer.nim | 59 ++++++++++++++++++++++++++++++++++++ apps/wakunode2/wakunode2.nim | 7 +++++ 2 files changed, 66 insertions(+) create mode 100644 apps/wakunode2/spammer.nim diff --git a/apps/wakunode2/spammer.nim b/apps/wakunode2/spammer.nim new file mode 100644 index 0000000000..70e52b9cc4 --- /dev/null +++ b/apps/wakunode2/spammer.nim @@ -0,0 +1,59 @@ +when (NimMajor, NimMinor) < (1, 4): + {.push raises: [Defect].} +else: + {.push raises: [].} + +import + chronos, + chronicles, + confutils, + confutils/defs, + confutils/std/net, + confutils/toml/defs as confTomlDefs, + confutils/toml/std/net as confTomlNet, + stew/[byteutils, results], + std/times, + libp2p/protocols/pubsub/gossipsub + +import + ../../waku/factory/waku, + ../../waku/waku_core, + ../../waku/node/waku_node, + ../../waku/common/confutils/envvar/defs as confEnvvarDefs, + ../../waku/common/confutils/envvar/std/net as confEnvvarNet + +type SpammerConfig* = object + enable* {.desc: "Enable spammer", defaultValue: false, name: "spammer".}: bool + msgRate* {. + desc: "Number of messages published per second", + defaultValue: 10, + name: "spammer-msg-rate" + .}: uint64 + +proc runSpammer*( + waku: Waku, contentTopic: ContentTopic = "/spammer/0/test/plain" +) {.async.} = + try: + var conf = SpammerConfig.load() + + if not conf.enable: + return + var ephemeral = true + while true: + var message = WakuMessage( + payload: toBytes("Hello World!"), + contentTopic: contentTopic, + # meta: metaBytes, + version: 2, + timestamp: getNanosecondTime(getTime().toUnixFloat()), + ephemeral: ephemeral, + ) + + let pubRes = await waku.node.publish(none(PubsubTopic), message) + if pubRes.isErr(): + error "failed to publish", msg = pubRes.error + #echo await (waku.node.isReady()) + await sleepAsync(80) + except CatchableError: + error "Failed to load config", err = err(getCurrentExceptionMsg()) + quit(QuitFailure) diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index 474eef1f7a..59effec131 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -12,6 +12,7 @@ import system/ansi_c, libp2p/crypto/crypto import + ./spammer, ../../tools/rln_keystore_generator/rln_keystore_generator, ../../tools/rln_db_inspector/rln_db_inspector, ../../waku/common/logging, @@ -132,4 +133,10 @@ when isMainModule: info "Node setup complete" + if not conf.rlnRelay: + error "RLN not configured!" + quit(QuitFailure) + + asyncSpawn runSpammer(waku) + runForever() From 8aa76dc537d50a8d5f2811800451332596f6f696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pavl=C3=ADn?= Date: Mon, 17 Jun 2024 11:18:25 +0200 Subject: [PATCH 2/5] spammer is publishing messages at given rats --- apps/wakunode2/spammer.nim | 108 ++++++++++++++++++++----------- apps/wakunode2/wakunode2.nim | 6 +- waku/factory/external_config.nim | 18 ++++++ 3 files changed, 88 insertions(+), 44 deletions(-) diff --git a/apps/wakunode2/spammer.nim b/apps/wakunode2/spammer.nim index 70e52b9cc4..3b12d2383a 100644 --- a/apps/wakunode2/spammer.nim +++ b/apps/wakunode2/spammer.nim @@ -6,54 +6,84 @@ else: import chronos, chronicles, - confutils, - confutils/defs, - confutils/std/net, - confutils/toml/defs as confTomlDefs, - confutils/toml/std/net as confTomlNet, stew/[byteutils, results], std/times, - libp2p/protocols/pubsub/gossipsub + libp2p/protocols/pubsub/gossipsub, + strutils import ../../waku/factory/waku, + ../../waku/factory/external_config, ../../waku/waku_core, + ../../waku/waku_relay, ../../waku/node/waku_node, - ../../waku/common/confutils/envvar/defs as confEnvvarDefs, - ../../waku/common/confutils/envvar/std/net as confEnvvarNet + ../../waku/node/peer_manager/peer_manager, + ../../waku/waku_rln_relay/rln_relay, + ../../tests/waku_rln_relay/rln/waku_rln_relay_utils -type SpammerConfig* = object - enable* {.desc: "Enable spammer", defaultValue: false, name: "spammer".}: bool - msgRate* {. - desc: "Number of messages published per second", - defaultValue: 10, - name: "spammer-msg-rate" - .}: uint64 +proc send( + waku: Waku, contentTopic: ContentTopic +): Future[Result[void, string]] {.async.} = + var ephemeral = true + + var message = WakuMessage( + payload: toBytes("Hello World!" & intToStr(int(getTime().toUnix()))), + contentTopic: contentTopic, + # meta: metaBytes, + version: 2, + timestamp: getNanosecondTime(getTime().toUnixFloat()), + ephemeral: ephemeral, + ) + + let rlnRes = + waku.node.wakuRlnRelay.unsafeAppendRLNProof(message, float64(getTime().toUnix())) + if rlnRes.isOk: + let pubRes = await waku.node.publish(none(PubsubTopic), message) + if pubRes.isErr(): + error "failed to publish", msg = pubRes.error + return err(pubRes.error) + else: + error "failed to append RLNProof", err = rlnRes.error + return err(rlnRes.error) + + return ok() proc runSpammer*( - waku: Waku, contentTopic: ContentTopic = "/spammer/0/test/plain" + waku: Waku, conf: WakuNodeConf, contentTopic: ContentTopic = "/spammer/0/test/plain" ) {.async.} = - try: - var conf = SpammerConfig.load() - - if not conf.enable: - return - var ephemeral = true - while true: - var message = WakuMessage( - payload: toBytes("Hello World!"), - contentTopic: contentTopic, - # meta: metaBytes, - version: 2, - timestamp: getNanosecondTime(getTime().toUnixFloat()), - ephemeral: ephemeral, - ) - - let pubRes = await waku.node.publish(none(PubsubTopic), message) - if pubRes.isErr(): - error "failed to publish", msg = pubRes.error - #echo await (waku.node.isReady()) - await sleepAsync(80) - except CatchableError: - error "Failed to load config", err = err(getCurrentExceptionMsg()) + if not conf.enable: + return + + if not conf.rlnRelay: + error "RLN not configured!" quit(QuitFailure) + + var gotPeers = false + while not gotPeers: + var (inRelayPeers, outRelayPeers) = + waku.node.peerManager.connectedPeers(WakuRelayCodec) + + var numPeers = len(inRelayPeers) + len(outRelayPeers) + if numPeers > 0: + gotPeers = true + info "Waiting for peers", numPeers = numPeers + await sleepAsync(1000) + #var rate = int(float(1000) / float(conf.msgRate)) + #var delayBetweenMsg = + # float(conf.rlnEpochSizeSec * 1000) / + # (float(conf.rlnRelayUserMessageLimit) * conf.msgRateMultiplier) + + info "Sending message with delay", delay = conf.delay + + while true: + var start = getTime().toUnix() + + (await send(waku, contentTopic)).isOkOr: + error "Failed to publish", err = error + + #echo await (waku.node.isReady()) + var current = getTime().toUnix() + var tillNextMsg = int(int64(conf.delay) - (current - start)) + info "Published messages", sleep = tillNextMsg + + await sleepAsync(tillNextMsg) diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index 59effec131..a4cfafd757 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -133,10 +133,6 @@ when isMainModule: info "Node setup complete" - if not conf.rlnRelay: - error "RLN not configured!" - quit(QuitFailure) - - asyncSpawn runSpammer(waku) + asyncSpawn runSpammer(waku, conf) runForever() diff --git a/waku/factory/external_config.nim b/waku/factory/external_config.nim index bc3c08bb19..d2b201ed63 100644 --- a/waku/factory/external_config.nim +++ b/waku/factory/external_config.nim @@ -595,6 +595,24 @@ type WakuNodeConf* = object name: "request-rate-period" .}: int64 + enable* {.desc: "Enable spammer", defaultValue: false, name: "spammer".}: bool + # msgRate* {. + # desc: "Number of messages published per epoch", + # defaultValue: 10, + # name: "spammer-msg-rate" + # .}: int + + # msgRateMultiplier* {. + # desc: "Multiply max message per epoch to publish spam", + # defaultValue: 1, + # name: "spammer-msg-multiplier" + # .}: float + delay* {. + desc: "Delay between spawning a publish method (in miliseconds)", + defaultValue: 0, + name: "spammer-delay-between-msg" + .}: int + ## Parsing # NOTE: Keys are different in nim-libp2p From 68869a9b4778618bbef525737ece46314d5f742e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=A1clav=20Pavl=C3=ADn?= Date: Wed, 19 Jun 2024 13:51:49 +0200 Subject: [PATCH 3/5] add burst and auto-registration --- apps/wakunode2/spammer.nim | 61 ++++++++++++++----- apps/wakunode2/wakunode2.nim | 2 + .../rln_keystore_generator.nim | 9 +-- waku/factory/external_config.nim | 11 +++- 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/apps/wakunode2/spammer.nim b/apps/wakunode2/spammer.nim index 3b12d2383a..afab84b336 100644 --- a/apps/wakunode2/spammer.nim +++ b/apps/wakunode2/spammer.nim @@ -48,42 +48,71 @@ proc send( return ok() +proc burstPublish( + waku: Waku, conf: WakuNodeConf, contentTopic: ContentTopic +) {.async.} = + var futures: seq[Future[Result[void, string]]] + var i: uint64 = 0 + var start = getTime().toUnixFloat() + + while i < conf.rlnRelayUserMessageLimit: + futures.add(send(waku, contentTopic)) + inc i + + let results = await allFinished(futures) + + var current = getTime().toUnixFloat() + var tillNextBurst = + int(int64(conf.rlnEpochSizeSec * 1000) - int64((current - start) * 1000)) + info "Published messages", + sleep = tillNextBurst, msgCount = conf.rlnRelayUserMessageLimit + + await sleepAsync(tillNextBurst) + +proc iterativePublish( + waku: Waku, conf: WakuNodeConf, contentTopic: ContentTopic +) {.async.} = + var start = getTime().toUnixFloat() + + (await send(waku, contentTopic)).isOkOr: + error "Failed to publish", err = error + + #echo await (waku.node.isReady()) + var current = getTime().toUnixFloat() + var tillNextMsg = int(int64(conf.spammerDelay) - int64((current - start) * 1000)) + info "Published message", sleep = tillNextMsg + + await sleepAsync(tillNextMsg) + proc runSpammer*( waku: Waku, conf: WakuNodeConf, contentTopic: ContentTopic = "/spammer/0/test/plain" ) {.async.} = - if not conf.enable: + if not conf.spammerEnable: return if not conf.rlnRelay: error "RLN not configured!" quit(QuitFailure) - var gotPeers = false - while not gotPeers: + while true: var (inRelayPeers, outRelayPeers) = waku.node.peerManager.connectedPeers(WakuRelayCodec) var numPeers = len(inRelayPeers) + len(outRelayPeers) if numPeers > 0: - gotPeers = true + break info "Waiting for peers", numPeers = numPeers await sleepAsync(1000) + #var rate = int(float(1000) / float(conf.msgRate)) #var delayBetweenMsg = # float(conf.rlnEpochSizeSec * 1000) / # (float(conf.rlnRelayUserMessageLimit) * conf.msgRateMultiplier) - info "Sending message with delay", delay = conf.delay + info "Sending message with delay", delay = conf.spammerDelay while true: - var start = getTime().toUnix() - - (await send(waku, contentTopic)).isOkOr: - error "Failed to publish", err = error - - #echo await (waku.node.isReady()) - var current = getTime().toUnix() - var tillNextMsg = int(int64(conf.delay) - (current - start)) - info "Published messages", sleep = tillNextMsg - - await sleepAsync(tillNextMsg) + if conf.spammerBurst: + await burstPublish(waku, conf, contentTopic) + else: + await iterativePublish(waku, conf, contentTopic) diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index a4cfafd757..9c180a769e 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -53,6 +53,8 @@ when isMainModule: of inspectRlnDb: doInspectRlnDb(conf) of noCommand: + if conf.spammerEnable: + doRlnKeystoreGenerator(conf, false) # NOTE: {.threadvar.} is used to make the global variable GC safe for the closure uses it # It will always be called from main thread anyway. # Ref: https://nim-lang.org/docs/manual.html#threads-gc-safety diff --git a/tools/rln_keystore_generator/rln_keystore_generator.nim b/tools/rln_keystore_generator/rln_keystore_generator.nim index 6c64ed6d2d..1285604dcf 100644 --- a/tools/rln_keystore_generator/rln_keystore_generator.nim +++ b/tools/rln_keystore_generator/rln_keystore_generator.nim @@ -15,7 +15,7 @@ import logScope: topics = "rln_keystore_generator" -proc doRlnKeystoreGenerator*(conf: WakuNodeConf) = +proc doRlnKeystoreGenerator*(conf: WakuNodeConf, quitOnSucces: bool = true) = # 1. load configuration trace "configuration", conf = $conf @@ -42,7 +42,7 @@ proc doRlnKeystoreGenerator*(conf: WakuNodeConf) = idSecretHash = credential.idSecretHash.inHex(), idCommitment = credential.idCommitment.inHex() - if not conf.execute: + if quitOnSucces and not conf.execute: info "not executing, exiting" quit(0) @@ -91,7 +91,6 @@ proc doRlnKeystoreGenerator*(conf: WakuNodeConf) = userMessageLimit: conf.rlnRelayUserMessageLimit, ) - let persistRes = addMembershipCredentials( conf.rlnRelayCredPath, keystoreCred, conf.rlnRelayCredPassword, RLNAppInfo ) @@ -106,4 +105,6 @@ proc doRlnKeystoreGenerator*(conf: WakuNodeConf) = except CatchableError: error "failure while stopping OnchainGroupManager", error = getCurrentExceptionMsg() quit(0) # 0 because we already registered on-chain - quit(0) + + if quitOnSucces: + quit(0) diff --git a/waku/factory/external_config.nim b/waku/factory/external_config.nim index d2b201ed63..954e17c9b3 100644 --- a/waku/factory/external_config.nim +++ b/waku/factory/external_config.nim @@ -595,7 +595,8 @@ type WakuNodeConf* = object name: "request-rate-period" .}: int64 - enable* {.desc: "Enable spammer", defaultValue: false, name: "spammer".}: bool + spammerEnable* {.desc: "Enable spammer", defaultValue: false, name: "spammer".}: + bool # msgRate* {. # desc: "Number of messages published per epoch", # defaultValue: 10, @@ -607,12 +608,18 @@ type WakuNodeConf* = object # defaultValue: 1, # name: "spammer-msg-multiplier" # .}: float - delay* {. + spammerDelay* {. desc: "Delay between spawning a publish method (in miliseconds)", defaultValue: 0, name: "spammer-delay-between-msg" .}: int + spammerBurst* {. + desc: "Send messages in burst instead of one by one", + defaultValue: false, + name: "spammer-burst" + .}: bool + ## Parsing # NOTE: Keys are different in nim-libp2p From f8d09d0181cd261618399a4cd6f8cad6fa5a4887 Mon Sep 17 00:00:00 2001 From: stubbsta Date: Thu, 20 Jun 2024 12:08:35 +0200 Subject: [PATCH 4/5] nonce to reset if limit is reached --- waku/waku_rln_relay/nonce_manager.nim | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/waku/waku_rln_relay/nonce_manager.nim b/waku/waku_rln_relay/nonce_manager.nim index 6fe463ce1c..c8ea2e8aa1 100644 --- a/waku/waku_rln_relay/nonce_manager.nim +++ b/waku/waku_rln_relay/nonce_manager.nim @@ -49,14 +49,16 @@ proc getNonce*(n: NonceManager): NonceManagerResult[Nonce] = n.nextNonce = retNonce + 1 + # This is modified for spam testing purposes, once the limit is reached the nonce value is reset to 0 if retNonce >= n.nonceLimit: - return err( - NonceManagerError( - kind: NonceLimitReached, - error: - "Nonce limit reached. Please wait for the next epoch. requested nonce: " & - $retNonce & " & nonceLimit: " & $n.nonceLimit, - ) - ) + retNonce = 0 + # return err( + # NonceManagerError( + # kind: NonceLimitReached, + # error: + # "Nonce limit reached. Please wait for the next epoch. requested nonce: " & + # $retNonce & " & nonceLimit: " & $n.nonceLimit, + # ) + # ) return ok(retNonce) From 3a286843607fbd705bcaabbd41816a81261efa8b Mon Sep 17 00:00:00 2001 From: stubbsta Date: Thu, 20 Jun 2024 13:38:49 +0200 Subject: [PATCH 5/5] use normal appendRLNProof instead of unsafe --- apps/wakunode2/spammer.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wakunode2/spammer.nim b/apps/wakunode2/spammer.nim index afab84b336..596c8a62ab 100644 --- a/apps/wakunode2/spammer.nim +++ b/apps/wakunode2/spammer.nim @@ -36,7 +36,7 @@ proc send( ) let rlnRes = - waku.node.wakuRlnRelay.unsafeAppendRLNProof(message, float64(getTime().toUnix())) + waku.node.wakuRlnRelay.appendRLNProof(message, float64(getTime().toUnix())) if rlnRes.isOk: let pubRes = await waku.node.publish(none(PubsubTopic), message) if pubRes.isErr():