Large-scale evaluation harness for TopDisc topic discovery on discv5. Runs thousands of real discv5 nodes in one process over a simulated network, and turns the traces into figures.
cmd/simnet— the testbed binary: workloads, connection model, churn driversscenarios/— scenarios (YAML): a testbed-agnosticscenario:plus atestbed:section for how this harness runs itfigures/— trace processing and figure generationdocs/TRACES.md— every trace field and which figure it drives
Two forks, both pinned in go.mod:
datahop/simnet— in-process packet network. Forked frommarcopolo/simnetfor node-count scaling and a drop-on-full link queue; without the latter a saturated link blocks the router shard and discovery freezes network-wide.datahop/go-ethereum— the TopDisc implementation, plus the instrumentation the testbed reads (per-message-type wire counters, registrar wait-time quotes, search provenance).
go build -o simnet ./cmd/simnet
./simnet scenarios/default.yamlThe binary takes exactly one argument, the config. It creates
<name>-<timestamp>/, writes the resolved run.yaml and run.log there,
and puts the traces next to them. ./simnet reference prints every
parameter with its default and meaning.
A config is the complete description of a test: every parameter the binary
accepts has a documented YAML field. scenarios/reference.yaml lists all of
them with their defaults (./simnet reference regenerates it). Each
run directory gets a run.yaml with every parameter filled in from what the
binary reported it actually ran with, so that file alone reproduces the run —
nothing about the machine or the checkout is recorded, because those are
given by where you run it and what you check out.
Figures, once a run has finished:
python3 figures/figures.py <run>/metrics.json --out-dir figs --label baseline
python3 figures/figures_overhead.py <run>/series.json \
--metrics <run>/metrics.json --overhead <run>/oh.json --out-dir figs --label baselinedocs/PARAMETERS.md lists every evaluation parameter and scenario of the
Phase 3 plan with its scenario key and status per backend; docs/FIGURES.md
does the same for every figure and metric, with the trace fields each one
needs.
testbed.backend in the scenario picks where the same scenario runs:
| backend | what runs | how |
|---|---|---|
simnet |
in-process discv5 nodes over the simulated network | ./testbed <scenario> execs ./simnet |
local |
one real geth p2p.Server process per node on this host (RLPx peer slots filled from topic search) |
go build -o topdisc-node ./cmd/node, then ./testbed <scenario> |
cloud |
the same processes across hosts provisioned by Terraform on AWS or, via Distem, on Grid'5000 (deploy/) |
./testbed <scenario> on the coordinator host, driving one hostagent per host |
local and cloud accept testbed.wan (Linux only): each node gets its own
network namespace with a netem qdisc, so pairs see WAN-like RTTs and a
per-node rate cap instead of loopback. scenarios/local-100*.yaml and
scenarios/cloud-*.yaml are the reference scenarios for those backends;
pkg/host is the per-host runner both share, cmd/hostagent exposes it
over HTTP for the cloud coordinator.
10,000 nodes needs roughly 80 GB of RAM and finishes in about 25 minutes on 24
cores. Check the [buf] lines in the run log before trusting any timing: they
report router and link buffer occupancy, and a run that reaches 100% has
queueing delay folded into its measurements.
Without -conn-model a searcher consumes discovery results forever, so load
grows without bound and never settles. With it, each node has geth's peer slots
(MaxPeers 50, DialRatio 3, so 16 dialled and 34 accepted) and stops
searching once its outbound slots are full — which is what a real node does, and
what gives a churn-free run a steady state.
Two churn models sit on top:
-session-churngives each node a session length drawn from a measured discv5 crawl: 42.3% outlast the run, the rest fall off geometrically from a mode at the resolution floor. A departing node drops every connection, stops accepting dials for-session-churn-gap, then returns and refills.-disconnect-interval/-disconnect-fracdrop a fraction of live connections per tick, without any node leaving. Transient link failure.
The -vanilla-frac workload runs part of the network on stock upstream geth to
measure incremental deployment. It needs a second copy of go-ethereum whose
module path is renamed, so it is behind a build tag:
go build -tags vanilla -o simnet-vanilla ./cmd/simnetDefault builds stub it out.