initial commit

This commit is contained in:
Marcin Czenko 2026-05-04 01:30:25 +02:00
commit 6750b2340f
No known key found for this signature in database
GPG Key ID: A0449219BDBA98AE
5 changed files with 168 additions and 0 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
mix_ping
mix_ping_quic
nimcache/
nimbledeps/
.agents/
.codex
nimble.paths
nimble.develop

47
README.md Normal file
View File

@ -0,0 +1,47 @@
# libp2p Mix Example
Standalone Nim example for running a libp2p Mix protocol ping simulation.
## Quick Start
Prerequisites:
- Nim 2.0 or newer
- Nimble
- Git
From a fresh clone:
```bash
nimble setup -l
nim c -r mix_ping.nim
```
`nimble setup -l` enables project-local dependency mode, installs dependencies
under `nimbledeps/`, and generates `nimble.paths` and `nimble.develop`.
## Local Files
The repository uses `config.nims` to keep Nim build output in the local
`nimcache/` directory and to include `nimble.paths` when it exists.
These files and directories are local artifacts and should not be committed:
- `nimbledeps/`
- `nimble.paths`
- `nimble.develop`
- `nimcache/`
- `mix_ping`
## Clean Rebuild
To verify the project can be rebuilt from committed files:
```bash
rm -rf nimbledeps nimble.paths nimble.develop nimcache mix_ping
nimble setup -l
nim c -r mix_ping.nim
```
If `nimble setup -l` reports that it cannot determine the VCS revision, make at
least one Git commit first, then rerun the command.

6
config.nims Normal file
View File

@ -0,0 +1,6 @@
switch("nimcache", "nimcache")
# begin Nimble config (version 2)
when withDir(thisDir(), system.fileExists("nimble.paths")):
include "nimble.paths"
# end Nimble config

11
libp2p_mix_example.nimble Normal file
View File

@ -0,0 +1,11 @@
version = "0.1.0"
author = "local"
description = "Standalone libp2p mix protocol example"
license = "MIT"
srcDir = "."
requires "nim >= 2.0.0"
requires "libp2p >= 1.15.3"
requires "chronicles >= 0.11.0"
requires "chronos >= 4.2.2"
requires "results >= 0.5.0"

96
mix_ping.nim Normal file
View File

@ -0,0 +1,96 @@
# SPDX-License-Identifier: Apache-2.0 OR MIT
# Copyright (c) Status Research & Development GmbH
## Mix Protocol Ping Example
##
## This example demonstrates using the Mix protocol with the Ping protocol.
## It creates a set of mix nodes that form an anonymous overlay network,
## then sends a ping through the mix network to a destination node and
## receives the response via Single Use Reply Blocks (SURBs).
{.used.}
import chronicles, chronos, results
import std/[strformat, sequtils]
import libp2p/[
protocols/mix,
protocols/mix/mix_protocol,
protocols/mix/curve25519,
protocols/ping,
peerid,
multiaddress,
switch,
builders,
crypto/crypto,
crypto/secp,
]
const NumMixNodes = 10
proc createSwitch(
multiAddr: MultiAddress, libp2pPrivKey: Opt[SkPrivateKey] = Opt.none(SkPrivateKey)
): Switch =
var rng = newRng()
let skkey = libp2pPrivKey.valueOr(SkKeyPair.random(rng[]).seckey)
let privKey = PrivateKey(scheme: Secp256k1, skkey: skkey)
newStandardSwitchBuilder(privKey = Opt.some(privKey), addrs = multiAddr).build()
proc mixPingSimulation() {.async: (raises: [Exception]).} =
let mixNodeInfos = MixNodeInfo.generateRandomMany(NumMixNodes)
var switches: seq[Switch] = @[]
var mixProtos: seq[MixProtocol] = @[]
# Set up mix protocols on each mix node
for nodeInfo in mixNodeInfos:
var switch = createSwitch(nodeInfo.multiAddr, Opt.some(nodeInfo.libp2pPrivKey))
let proto = MixProtocol.new(nodeInfo, switch)
# Populate nodePool with all other nodes' public info
proto.nodePool.add(mixNodeInfos.includeAllExcept(nodeInfo))
# Register how to read ping responses (32 bytes exactly)
proto.registerDestReadBehavior(PingCodec, readExactly(32))
switch.mount(proto)
switches.add(switch)
mixProtos.add(proto)
defer:
await switches.mapIt(it.stop()).allFutures()
# Create a destination node (not part of the mix network)
let destNode = createSwitch(MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet())
defer:
await destNode.stop()
let pingProto = Ping.new()
destNode.mount(pingProto)
# Start all switches
await switches.mapIt(it.start()).allFutures()
await destNode.start()
# Pick sender (first mix node) and send ping through the mix network
let senderIndex = 0
info "Sending ping through mix network",
sender = switches[senderIndex].peerInfo.peerId,
destination = destNode.peerInfo.peerId
# Create a connection through the mix network
let conn = mixProtos[senderIndex]
.toConnection(
MixDestination.init(destNode.peerInfo.peerId, destNode.peerInfo.addrs[0]),
PingCodec,
MixParameters(expectReply: Opt.some(true), numSurbs: Opt.some(byte(1))),
)
.expect("could not build connection")
# Send ping and wait for response through the mix network
let response = await pingProto.ping(conn)
await conn.close()
info "Ping response received through mix network", rtt = response
when isMainModule:
waitFor(mixPingSimulation())