From adde56532b2577fc2c8298adfcdf49d780ec28fd Mon Sep 17 00:00:00 2001 From: Jazz Turner-Baggs <473256+jazzz@users.noreply.github.com> Date: Fri, 4 Jul 2025 22:17:31 -0700 Subject: [PATCH] Added Waku dependancies --- .gitignore | 2 + .gitmodules | 3 + README.md | 65 +++++++++++++++++++++ nim.cfg | 13 +++++ src/waku_vibe_template.nim | 115 +++++++++++++++++++++++++++++++++++++ vendor/waku | 1 + waku_vibe_template.nimble | 24 ++++++++ 7 files changed, 223 insertions(+) create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 README.md create mode 100644 nim.cfg create mode 100644 src/waku_vibe_template.nim create mode 160000 vendor/waku create mode 100644 waku_vibe_template.nimble diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ae969d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/waku_vibe_template +/waku_vibe_template.dSYM diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2b87c6e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/waku"] + path = vendor/waku + url = git@github.com:waku-org/nwaku.git diff --git a/README.md b/README.md new file mode 100644 index 0000000..94fd6bc --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# Nim Chat POC + +This is a technical proof of consuming the [chat_proto](https://github.com/waku-org/chat_proto/tree/base_types?tab=readme-ov-file) in nim. + + +## Message Flow + +To establish a secure conversation, Saro and Raya need to: +1. Exchange key material +2. Agree on a secret key, and location to communicate + +For this technical proof, recipient identity keys are exchanged out of bound via an invite link. More complex identity systems will be explored in the future. + +Key derivation and message framing is defined by Inbox spec + + + ```mermaid +sequenceDiagram + actor S as Saro + participant SI as Saro Inbox + participant C as Convo + participant RI as Raya Inbox + actor R as Raya + + + Note over SI,RI: All clients subscribe to their default Inbox + + SI ->> S: Subscribe + RI ->> R: Subscribe + + Note over R: Key Information is exchanged OOB + + Note over S: Conversation is created + C ->> S : Subscribe + S ->> RI : Send Invite `I1` + S ->> C : Send Message `M1` + + RI --) R : Recv `I1` + Note over R: Conversation is joined + C ->> R : Subscribe + C --) R: Recv `M1` + + R ->> C: Send M2 + C -->> S: Recv M2 + ``` + +## Running + + + +``` +# Run the default binary +nimble run +``` + + +## Limitations + +1. `.proto` files are included in this repo due to complications in importing nested packages using `?subdir=`. Once resolved there will be a single definition of protocol types. +1. Currently messages are not sent over the wire. They are simulated using a `TransportMessage`. + + +## License + +[MIT](https://choosealicense.com/licenses/mit/) \ No newline at end of file diff --git a/nim.cfg b/nim.cfg new file mode 100644 index 0000000..5d56899 --- /dev/null +++ b/nim.cfg @@ -0,0 +1,13 @@ +# Add custom paths to import modules +--path: "vendor/waku" + +# Compile with debug symbols +--debuginfo + +# Enable warnings +--warning[UnusedImport]: on + +# Enable experimental features +--experimental + +--passL: "./vendor/waku/librln_v0.7.0.a" diff --git a/src/waku_vibe_template.nim b/src/waku_vibe_template.nim new file mode 100644 index 0000000..fde45e7 --- /dev/null +++ b/src/waku_vibe_template.nim @@ -0,0 +1,115 @@ +import + std/[tables, sequtils], + stew/byteutils, + chronicles, + chronos, + confutils, + libp2p/crypto/crypto, + eth/keys, + eth/p2p/discoveryv5/enr + +import + waku/[ + common/logging, + node/peer_manager, + waku_core, + waku_node, + waku_enr, + discovery/waku_discv5, + factory/builder, + waku_relay, + waku_filter_v2/client, + ] + +# careful if running pub and sub in the same machine +const wakuPort = 50000 + +const clusterId = 1 +const shardId = @[0'u16] + +const + FilterPeer = + "/ip4/178.128.141.171/tcp/30303/p2p/16Uiu2HAkykgaECHswi3YKJ5dMLbq2kPVCo89fcyTd38UcQD6ej5W" + FilterPubsubTopic = PubsubTopic("/waku/2/rs/1/0") + FilterContentTopic = ContentTopic("/examples/1/light-pubsub-example/proto") + +proc messagePushHandler( + pubsubTopic: PubsubTopic, message: WakuMessage +) {.async, gcsafe.} = + let payloadStr = string.fromBytes(message.payload) + notice "message received", + payload = payloadStr, + pubsubTopic = pubsubTopic, + contentTopic = message.contentTopic, + timestamp = message.timestamp + +proc setupAndSubscribe(rng: ref HmacDrbgContext) {.async.} = + # use notice to filter all waku messaging + setupLog(logging.LogLevel.NOTICE, logging.LogFormat.TEXT) + + notice "starting subscriber", wakuPort = wakuPort + let + nodeKey = crypto.PrivateKey.random(Secp256k1, rng[])[] + 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 recordRes = enrBuilder.build() + let record = + if recordRes.isErr(): + error "failed to create enr record", error = recordRes.error + quit(QuitFailure) + else: + recordRes.get() + + var builder = WakuNodeBuilder.init() + builder.withNodeKey(nodeKey) + builder.withRecord(record) + builder.withNetworkConfigurationDetails(ip, Port(wakuPort)).tryGet() + let node = builder.build().tryGet() + + node.mountMetadata(clusterId).expect("failed to mount waku metadata protocol") + await node.mountFilterClient() + + await node.start() + + node.peerManager.start() + + node.wakuFilterClient.registerPushHandler(messagePushHandler) + + let filterPeer = parsePeerInfo(FilterPeer).get() + + while true: + notice "maintaining subscription" + # First use filter-ping to check if we have an active subscription + let pingRes = await node.wakuFilterClient.ping(filterPeer) + if pingRes.isErr(): + # No subscription found. Let's subscribe. + notice "no subscription found. Sending subscribe request" + + let subscribeRes = await node.wakuFilterClient.subscribe( + filterPeer, FilterPubsubTopic, @[FilterContentTopic] + ) + + if subscribeRes.isErr(): + notice "subscribe request failed. Quitting.", err = subscribeRes.error + break + else: + notice "subscribe request successful." + else: + notice "subscription found." + + await sleepAsync(60.seconds) # Subscription maintenance interval + +when isMainModule: + let rng = crypto.newRng() + asyncSpawn setupAndSubscribe(rng) + runForever() diff --git a/vendor/waku b/vendor/waku new file mode 160000 index 0000000..3fb21ae --- /dev/null +++ b/vendor/waku @@ -0,0 +1 @@ +Subproject commit 3fb21ae079f7c3390844c4f7a6841b5d34cb833a diff --git a/waku_vibe_template.nimble b/waku_vibe_template.nimble new file mode 100644 index 0000000..2207820 --- /dev/null +++ b/waku_vibe_template.nimble @@ -0,0 +1,24 @@ +# Package + +version = "0.1.0" +author = "jazzz" +description = "An example of the chat sdk in Nim" +license = "MIT" +srcDir = "src" +bin = @["waku_vibe_template"] + + +# Dependencies + +requires "nim >= 2.2.4" + +requires "protobuf_serialization >= 0.1.0" +requires "secp256k1 >= 0.6.0.3.2" +requires "blake2" +requires "chronicles" +requires "libp2p >= 1.11.0" +requires "nimchacha20poly1305" # TODO: remove +requires "confutils >= 0.1.0" +requires "eth >= 0.8.0" +requires "regex >= 0.26.3" +requires "web3 >= 0.7.0" \ No newline at end of file