Skip to content

cardano-adversary

N2N adversary daemon for fault-injection testing (for example under Antithesis). It listens on a Unix-domain control socket and answers one NDJSON request per connection, driving adversarial Node-to-Node ChainSync connections against configured block producers.

CLI

cardano-adversary \
  --control-socket PATH \
  --network-magic  INT \
  [--producer-host HOST]... \
  [--producer-port INT] \
  [--chain-points-file PATH]
Flag Default Purpose
--control-socket Bind path for the NDJSON control socket. Required.
--network-magic Cardano network magic for the N2N handshake. Required.
--producer-host (none) Producer hostname the chain_sync_flap endpoint targets. Repeatable.
--producer-port 3001 N2N port for chain_sync_flap.
--chain-points-file (unset) File of chain points written by tracer-sidecar; re-read on every chain_sync_flap request.

cardano-adversary --help prints the same summary. The daemon installs a SIGTERM handler, unlinks the socket on shutdown, and exits cleanly.

Control wire (NDJSON)

One request line per connection, one response line, then EOF. The full schema is the contract at specs/036-cardano-adversary/contracts/control-wire.md.

ready

REQ:  {"ready": null}
RESP: {"ready": <bool>,
       "details": {"n2nHandshakeOk": <bool>,
                   "configuredHosts": [<host>, ...]}}

configuredHosts echoes the --producer-host values.

chain_sync_flap

Opens n_conns concurrent adversarial ChainSync connections against the configured producers, each starting from a randomised chain point sampled (seeded by seed) from the chain-points file and pulling at most limit blocks before disconnecting.

REQ:  {"chain_sync_flap": {"seed": <u64>, "limit": <u32>, "n_conns": <u16>}}
RESP: {"ok": true,
       "details": {"connections": <int>,
                   "peerNames": [<host>, ...],
                   "limit": <u32>}}

Structured failures keep ok: false with a reason:

reason Cause
no-producers No --producer-host was configured.
no-chain-points-file The --chain-points-file is unset or missing on disk.
no-chain-points-yet The file exists but holds no usable chain points yet.

Wire-level problems return {"error": "<reason>"} (for example malformed JSON or an unknown top-level key).

Random source

Every adversarial decision draws from Cardano.Node.Client.Adversary.RandomSource. The default implementation shells out to the antithesis_random CLI when it is on PATH (so the Antithesis hypervisor can bias choices) and falls back to System.Random for local development when it is not. The per-request seed field is turned into a StdGen so a request is reproducible from its seed.