| name | add-epoch-test |
| description | Set up a new epoch_pots integration test with ground truth fixtures from DBSync |
Add an Epoch Pots Test
Epoch pots tests compare dolos ledger output against DBSync ground truth for a specific epoch. Each test needs: fixture CSVs from DBSync, a fixtures directory, and a test entry using the epoch_test! macro.
Key Concepts
- subject_epoch: The epoch being tested. Dolos runs up to
subject_epoch + 1 so that the subject epoch completes fully.
- performance_epoch:
subject_epoch - 2. This is the epoch whose rewards, delegation, and stake snapshots are compared. Cardano uses a 2-epoch lag for reward distribution.
- snapshot_epoch: Same as performance_epoch. Used in delegation/stake fixture filenames (e.g.,
delegation-248.csv for subject epoch 250).
- seed: A pre-built dolos state directory that the test copies and resumes from, to avoid replaying the entire chain. Seeds are configured in
xtask.toml under [seeds].
Step 1: Verify a seed exists
Check xtask.toml for seeds and the constant arrays in tests/epoch_pots/main.rs:
const MAINNET_SEED_EPOCHS: &[u64] = &[200, 270, 300, 340];
const PREVIEW_SEED_EPOCHS: &[u64] = &[500, 700];
const PREPROD_SEED_EPOCHS: &[u64] = &[200];
The test picks the nearest lower seed. If no seed is available at or below the subject epoch, you need to create one first (see "Creating a new seed" below).
Step 2: Generate ground truth fixtures
Run the xtask ground-truth generate command. The output goes directly into the fixtures directory:
mkdir -p tests/epoch_pots/fixtures/{network}-{subject_epoch}
cargo run -p xtask -- ground-truth generate \
--network {network} \
--subject-epoch {subject_epoch} \
--output-dir tests/epoch_pots/fixtures/{network}-{subject_epoch}
This queries DBSync (connection from xtask.toml [dbsync] section) and writes:
| File | Content |
|---|
epochs.csv | Treasury, reserves, rewards, utxo, fees, nonce, block_count for epochs 1..=subject |
pparams.csv | Protocol parameters for epochs 1..=subject |
eras.csv | Era boundaries (protocol version, start epoch, lengths) |
delegation-{perf}.csv | Per-pool total stake at performance_epoch |
stake-{perf}.csv | Per-account stake/pool pairs at performance_epoch |
rewards.csv | Per-account rewards (leader/member) at performance_epoch |
Where {perf} = subject_epoch - 2.
You can regenerate individual datasets with --only-* flags:
cargo run -p xtask -- ground-truth generate \
--network mainnet --subject-epoch 450 \
--output-dir tests/epoch_pots/fixtures/mainnet-450 \
--only-rewards
Available flags: --only-eras, --only-epochs, --only-pparams, --only-delegation, --only-stake, --only-rewards.
Step 3: Add the test entry
Edit tests/epoch_pots/main.rs. Add an epoch_test! invocation in the test functions section at the bottom, maintaining order by epoch number:
epoch_test!(test_{network}_{subject}, fixtures_{network}_{subject}, "{network}", {subject}, {perf});
Example for mainnet epoch 450 (performance epoch 448):
epoch_test!(test_mainnet_450, fixtures_mainnet_450, "mainnet", 450, 448);
The macro arguments are:
- Test function name:
test_{network}_{subject_epoch}
- Fixture module name:
fixtures_{network}_{subject_epoch} (unused legacy, but must be unique)
- Network string:
"mainnet", "preprod", or "preview"
- Subject epoch number
- Snapshot/performance epoch number (
subject - 2)
Step 4: Verify it compiles
cargo test --test epoch_pots --no-run
Step 5: Run the test
DOLOS_SEED_DIR=/path/to/seeds cargo test --test epoch_pots test_{network}_{subject} --release -- --nocapture
The test:
- Copies the nearest seed's
state/ to a temp directory
- Replays from the Mithril snapshot immutable files up to
subject_epoch + 1
- Dumps dolos epochs, pparams, eras, delegation, stake, and rewards CSVs
- Compares each against the ground truth fixtures
- Reports diffs (up to 20 per dataset)
Set EPOCH_POTS_KEEP_DIR=1 to preserve the temp directory for debugging.
Step 6: Run all tests to check for regressions
DOLOS_SEED_DIR=/path/to/seeds cargo test --test epoch_pots --release -- --nocapture
Creating a new seed
If no seed covers the target epoch range, create one. A seed is just the dolos state/ directory at a specific epoch.
- Create a test instance that stops at the seed epoch:
cargo xtask test-instance create --network mainnet --epoch {seed_epoch}
-
Wait for it to sync (exits with "forced stop epoch reached").
-
Copy the state to the seeds directory:
mkdir -p /path/to/seeds/mainnet-{seed_epoch}
cp -r {instances_root}/test-mainnet-{seed_epoch}/data/state /path/to/seeds/mainnet-{seed_epoch}/state
- Update
xtask.toml to register the seed:
[seeds]
mainnet = "/path/to/seeds/mainnet-{seed_epoch}"
- Add the seed epoch to the constant array in
tests/epoch_pots/main.rs:
const MAINNET_SEED_EPOCHS: &[u64] = &[200, 270, 300, 340, {seed_epoch}];
Fixture directory structure
tests/epoch_pots/fixtures/{network}-{subject_epoch}/
├── epochs.csv # Multi-row: all epochs 1..=subject
├── pparams.csv # Multi-row: all epochs 1..=subject
├── eras.csv # Era boundaries
├── delegation-{perf}.csv # Per-pool totals
├── stake-{perf}.csv # Per-account stake (can be very large)
└── rewards.csv # Per-account rewards
Common issues
DBSync timeout on large queries: Stake and rewards queries for mainnet can be very large. If they timeout, retry or use --only-stake / --only-rewards separately.
Missing seed: If the test panics with "no seed available for {network} <= {epoch}", you need to create a seed at or below the subject epoch.
Large fixture files: Stake CSVs for mainnet can be 100MB+. These are checked into the repo under tests/epoch_pots/fixtures/. Consider whether the epoch is worth testing (milestone epochs, era boundaries, known bug points are good candidates).