mirror of
https://github.com/logos-messaging/logos-delivery.git
synced 2026-06-06 22:19:30 +00:00
Combines five dep-and-build changes that all flow from the libp2p v2.0.0
upgrade and the move to the extracted libp2p_mix / mix-rln plugin stack:
waku.nimble:
* libp2p: ff8d51857 -> c43199378 (release/v2.0.0 tip; sha-pinned until
vacp2p cuts a v2.0.0 tag).
* Drop the bare `zlib < 0.2` cap — no longer needed by the upgraded
libp2p.
* websock: bare ">= 0.4.0" — replaces the d4cd68b URL+SHA workaround
that pinned through a libp2p commit-specific websock SHA.
* nim-json-rpc: switch to chaitanyaprem/nim-json-rpc#f05fad25 — relaxes
websock cap to allow >=0.4.0. TODO: revert to status-im/nim-json-rpc
once status-im/nim-json-rpc#277 merges and a tag is cut.
* lsquic: bare ">= 0.4.1" (drops URL form).
* Add mix-rln-spam-protection-plugin pin (23b278b4) and nim-libp2p-mix
pin (50c4ab4f — PR #14 HEAD); the plugin pins the same libp2p_mix
SHA so the diamond dep collapses to a single source.
waku/factory/waku.nim:
* Explicit HPService.setup(switch) / AutonatService.setup(switch)
calls. libp2p v2.0.0's Service lifecycle refactor (libp2p#2462)
removed switch.start's auto-setup loop, so any caller that assigns
directly to switch.services (we do) is responsible for calling
setup() themselves. Without it, AutonatService.addressMapper stays
nil and peerInfo.expandAddrs SIGSEGVs during start(). Wrapped in
try/except for ServiceSetupError so a setup failure surfaces as a
logged error rather than a crash.
Build / scripts:
* scripts/build_rln_mix.sh removed and Makefile simplified — librln
is now a single shared archive built from zerokit's `stateless`
features (no separate librln_mix archive).
* simulations/mixnet/build_setup.sh + setup_credentials.nim updated
to use librln_v2.0.2.a directly and run RLN keystore setup before
nodes start.
Validated:
* Cold local-cache nimble setup --localdeps -y.
* wakunode2 and chat2mix link cleanly.
* Mixnet roundtrip sim: [PASS] bob received message from alice.
* RLN proof generation + verification on every in-path mix node:
5 gen_called == 5 verified, 0 SPAM_PROOF_* errors.
202 lines
7.1 KiB
Nim
202 lines
7.1 KiB
Nim
import
|
|
std/[tables, times, sequtils, strutils],
|
|
stew/byteutils,
|
|
chronicles,
|
|
results,
|
|
chronos,
|
|
confutils,
|
|
libp2p/crypto/crypto,
|
|
libp2p/crypto/curve25519,
|
|
libp2p_mix,
|
|
libp2p_mix/curve25519,
|
|
libp2p/multiaddress,
|
|
eth/keys,
|
|
eth/p2p/discoveryv5/enr,
|
|
metrics,
|
|
metrics/chronos_httpserver
|
|
|
|
import
|
|
waku/[
|
|
common/logging,
|
|
node/peer_manager,
|
|
waku_core,
|
|
waku_core/codecs,
|
|
waku_node,
|
|
waku_enr,
|
|
discovery/waku_discv5,
|
|
factory/builder,
|
|
waku_lightpush/client,
|
|
],
|
|
./lightpush_publisher_mix_config,
|
|
./lightpush_publisher_mix_metrics
|
|
|
|
const clusterId = 66
|
|
const shardId = @[0'u16]
|
|
|
|
const
|
|
LightpushPubsubTopic = PubsubTopic("/waku/2/rs/66/0")
|
|
LightpushContentTopic = ContentTopic("/examples/1/light-pubsub-mix-example/proto")
|
|
|
|
proc splitPeerIdAndAddr(maddr: string): (string, string) =
|
|
let parts = maddr.split("/p2p/")
|
|
if parts.len != 2:
|
|
error "Invalid multiaddress format", parts = parts
|
|
return
|
|
|
|
let
|
|
address = parts[0]
|
|
peerId = parts[1]
|
|
return (address, peerId)
|
|
|
|
proc setupAndPublish(rng: ref HmacDrbgContext, conf: LightPushMixConf) {.async.} =
|
|
# use notice to filter all waku messaging
|
|
setupLog(logging.LogLevel.DEBUG, logging.LogFormat.TEXT)
|
|
notice "starting publisher", wakuPort = conf.port
|
|
|
|
let
|
|
nodeKey = crypto.PrivateKey.random(Secp256k1, rng[]).get()
|
|
ip = parseIpAddress("0.0.0.0")
|
|
flags = CapabilitiesBitfield.init(relay = true)
|
|
|
|
let relayShards = RelayShards.init(clusterId, shardId).valueOr:
|
|
error "Relay shards initialization failed", error = error
|
|
quit(QuitFailure)
|
|
|
|
var enrBuilder = EnrBuilder.init(nodeKey)
|
|
enrBuilder.withWakuRelaySharding(relayShards).expect(
|
|
"Building ENR with relay sharding failed"
|
|
)
|
|
|
|
let record = enrBuilder.build().valueOr:
|
|
error "failed to create enr record", error = error
|
|
quit(QuitFailure)
|
|
|
|
setLogLevel(logging.LogLevel.TRACE)
|
|
var builder = WakuNodeBuilder.init()
|
|
builder.withNodeKey(nodeKey)
|
|
builder.withRecord(record)
|
|
builder.withNetworkConfigurationDetails(ip, Port(conf.port)).tryGet()
|
|
|
|
let node = builder.build().tryGet()
|
|
|
|
node.mountMetadata(clusterId, shardId).expect(
|
|
"failed to mount waku metadata protocol"
|
|
)
|
|
node.mountLightPushClient()
|
|
try:
|
|
await node.mountPeerExchange(some(uint16(clusterId)))
|
|
except CatchableError:
|
|
error "failed to mount waku peer-exchange protocol",
|
|
error = getCurrentExceptionMsg()
|
|
return
|
|
|
|
let (destPeerAddr, destPeerId) = splitPeerIdAndAddr(conf.destPeerAddr)
|
|
let (pxPeerAddr, pxPeerId) = splitPeerIdAndAddr(conf.pxAddr)
|
|
info "dest peer address", destPeerAddr = destPeerAddr, destPeerId = destPeerId
|
|
info "peer exchange address", pxPeerAddr = pxPeerAddr, pxPeerId = pxPeerId
|
|
let pxPeerInfo =
|
|
RemotePeerInfo.init(destPeerId, @[MultiAddress.init(destPeerAddr).get()])
|
|
node.peerManager.addServicePeer(pxPeerInfo, WakuPeerExchangeCodec)
|
|
|
|
let pxPeerInfo1 =
|
|
RemotePeerInfo.init(pxPeerId, @[MultiAddress.init(pxPeerAddr).get()])
|
|
node.peerManager.addServicePeer(pxPeerInfo1, WakuPeerExchangeCodec)
|
|
|
|
if not conf.mixDisabled:
|
|
let (mixPrivKey, mixPubKey) = generateKeyPair().valueOr:
|
|
error "failed to generate mix key pair", error = error
|
|
return
|
|
(await node.mountMix(clusterId, mixPrivKey, conf.mixnodes)).isOkOr:
|
|
error "failed to mount waku mix protocol: ", error = $error
|
|
return
|
|
|
|
let dPeerId = PeerId.init(destPeerId).valueOr:
|
|
error "Failed to initialize PeerId", error = error
|
|
return
|
|
|
|
await node.mountRendezvousClient(clusterId)
|
|
await node.start()
|
|
node.peerManager.start()
|
|
node.startPeerExchangeLoop()
|
|
try:
|
|
startMetricsHttpServer("0.0.0.0", Port(8008))
|
|
except Exception:
|
|
error "failed to start metrics server: ", error = getCurrentExceptionMsg()
|
|
(await node.fetchPeerExchangePeers()).isOkOr:
|
|
warn "Cannot fetch peers from peer exchange", cause = error
|
|
|
|
if not conf.mixDisabled:
|
|
while node.getMixNodePoolSize() < conf.minMixPoolSize:
|
|
info "waiting for mix nodes to be discovered",
|
|
currentpoolSize = node.getMixNodePoolSize()
|
|
await sleepAsync(1000)
|
|
notice "publisher service started with mix node pool size ",
|
|
currentpoolSize = node.getMixNodePoolSize()
|
|
|
|
var i = 0
|
|
while i < conf.numMsgs:
|
|
var conn: Connection
|
|
if conf.mixDisabled:
|
|
let connOpt = await node.peerManager.dialPeer(dPeerId, WakuLightPushCodec)
|
|
if connOpt.isNone():
|
|
error "failed to dial peer with WakuLightPushCodec", target_peer_id = dPeerId
|
|
return
|
|
conn = connOpt.get()
|
|
else:
|
|
conn = node.wakuMix.toConnection(
|
|
MixDestination.exitNode(dPeerId), # destination lightpush peer
|
|
WakuLightPushCodec, # protocol codec which will be used over the mix connection
|
|
MixParameters(expectReply: Opt.some(true), numSurbs: Opt.some(byte(1))),
|
|
# mix parameters indicating we expect a single reply
|
|
).valueOr:
|
|
error "failed to create mix connection", error = error
|
|
return
|
|
i = i + 1
|
|
let text =
|
|
"""Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam venenatis magna ut tortor faucibus, in vestibulum nibh commodo. Aenean eget vestibulum augue. Nullam suscipit urna non nunc efficitur, at iaculis nisl consequat. Mauris quis ultrices elit. Suspendisse lobortis odio vitae laoreet facilisis. Cras ornare sem felis, at vulputate magna aliquam ac. Duis quis est ultricies, euismod nulla ac, interdum dui. Maecenas sit amet est vitae enim commodo gravida. Proin vitae elit nulla. Donec tempor dolor lectus, in faucibus velit elementum quis. Donec non mauris eu nibh faucibus cursus ut egestas dolor. Aliquam venenatis ligula id velit pulvinar malesuada. Vestibulum scelerisque, justo non porta gravida, nulla justo tempor purus, at sollicitudin erat erat vel libero.
|
|
Fusce nec eros eu metus tristique aliquet.
|
|
This is message #""" &
|
|
$i & """ sent from a publisher using mix. End of transmission."""
|
|
let message = WakuMessage(
|
|
payload: toBytes(text), # content of the message
|
|
contentTopic: LightpushContentTopic, # content topic to publish to
|
|
ephemeral: true, # tell store nodes to not store it
|
|
timestamp: getNowInNanosecondTime(),
|
|
) # current timestamp
|
|
|
|
let res =
|
|
await node.wakuLightpushClient.publish(some(LightpushPubsubTopic), message, conn)
|
|
|
|
let startTime = getNowInNanosecondTime()
|
|
|
|
(
|
|
await node.wakuLightpushClient.publishWithConn(
|
|
LightpushPubsubTopic, message, conn, dPeerId
|
|
)
|
|
).isOkOr:
|
|
error "failed to publish message via mix", error = error.desc
|
|
lp_mix_failed.inc(labelValues = ["publish_error"])
|
|
return
|
|
|
|
let latency = float64(getNowInNanosecondTime() - startTime) / 1_000_000.0
|
|
lp_mix_latency.observe(latency)
|
|
lp_mix_success.inc()
|
|
notice "published message",
|
|
text = text,
|
|
timestamp = message.timestamp,
|
|
latency = latency,
|
|
psTopic = LightpushPubsubTopic,
|
|
contentTopic = LightpushContentTopic
|
|
|
|
if conf.mixDisabled:
|
|
await conn.close()
|
|
await sleepAsync(conf.msgIntervalMilliseconds)
|
|
info "Sent all messages via mix"
|
|
quit(0)
|
|
|
|
when isMainModule:
|
|
let conf = LightPushMixConf.load()
|
|
let rng = crypto.newRng()
|
|
asyncSpawn setupAndPublish(rng, conf)
|
|
runForever()
|