Skip to content

Repository files navigation

DRS full-stack benchmark

Standalone, replicable benchmark harness for the Delegation Receipt Standard (DRS). It measures the published DRS stack end to end, the way real users run it — this repo imports no code from the DRS source tree:

  • Hostghcr.io/okeyamy/drs-verify (pinned by digest, = release v0.1.1) + Redis 7.4, via compose.bench.yml. Nothing is built locally.
  • Devs — 15 simulated developers, each with their own Ed25519 keypair, did:key identity, and delegation chain, issued with the published @okeyamy/drs-sdk from npm.
  • Load — k6 POSTs pre-signed bundles to POST /verify. Every request carries a unique JTI; each dev arrives from a distinct client IP (X-Forwarded-For + TRUST_PROXY=true), so per-IP rate limiting sees 15 clients, not one load generator.

Prerequisites

  • Docker (compose v2 plugin or standalone docker-compose v1 — both work)
  • Node.js ≥ 20
  • k6 ≥ v1 (tested with v2.0.0)
  • pnpm (or npm) to install the SDK

Run

git clone https://github.com/OkeyAmy/drs-bench
cd drs-bench
pnpm install          # pulls @okeyamy/drs-sdk from npm
./run.sh              # all scenarios (~12 min)
./run.sh s2           # or a single scenario

Raw output lands in results/: k6 summaries (*.json, *.log), /metrics snapshots before/after each scenario, container CPU/mem samples, and the machine description. Curated numbers go in RESULTS.md.

Scenarios

# What Why
S0 Fixture generation itself SDK issuance throughput (single process, real signatures)
S1 1 dev, 200 sequential requests at chain depth 1 / 4 / 16 Floor latency; CPU scaling with chain depth
S2 15 devs, 300 rps steady, 60 s, depth 4, Redis Realistic multi-tenant load
S3 Ramp 100 → 1500 rps, depth 4 Saturation point of one instance
S4 300 rps with 10 % replayed JTIs Replay storm: 409s must stay cheap
S5 S2 with in-memory nonce backend Isolates the Redis roundtrip cost
S6 300 rps through an org tool server (bundle in X-DRS-Bundle header, fail-closed gate, tool executes only on valid + binding:"match") The full canonical topology — what a dev actually experiences per tool call

Design constraints (verified against the code, not assumed)

  • Fixtures expire in 15 minutes. INVOCATION_STALE fires when now − iat > NONCE_STORE_TTL_SECS (900 s in the bench config), so run.sh regenerates fixtures immediately before each scenario.
  • Unique JTI per request. The nonce store burns each JTI on first use (409 on reuse), so the k6 script indexes bundles by global iteration number and never resends one — except deliberately, in S4.
  • Rate limits are raised (RATE_LIMIT_PER_IP=1000, RATE_LIMIT_GLOBAL=10000; defaults 100/1000). At defaults, the global limiter answers 429 at 1000 rps before the verifier is working hard — the bench measures the verifier, not the token bucket.
  • Bundles must fit the 64 KiB body cap. The generator asserts this; a depth-16 bundle measures ~12 KiB.
  • Issuance is single-threaded at ~290 bundles/s per Node process (measured with spike-issuance-rate.mjs), so generation shards across 5 parallel processes.

Interpreting results

Numbers are machine-relative — compare scenarios against each other on the same machine, not against another machine's absolute values. results/machine.txt records the hardware for each run.

About

Replicable full-stack benchmark for the Delegation Receipt Standard (DRS) — published artifacts only

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages