Skip to content

feat: add comprehensive invariant tests for Zenith contracts#94

Open
init4samwise wants to merge 2 commits intomainfrom
samwise/eng-1533-invariant-tests
Open

feat: add comprehensive invariant tests for Zenith contracts#94
init4samwise wants to merge 2 commits intomainfrom
samwise/eng-1533-invariant-tests

Conversation

@init4samwise
Copy link

Summary

Adds comprehensive invariant tests covering fund safety, liveness, and sequencing integrity across the Signet/Zenith contract suite.

Changes

Created 5 new test files in test/invariant/:

File Coverage
ZenithInvariant.t.sol Sequencing contract - block submission bounds, chain uniqueness
PassageInvariant.t.sol Host-side passage - ETH/token entry accounting
RollupPassageInvariant.t.sol Rollup-side passage - exits/burns accounting
OrdersInvariant.t.sol Order handling - RollupOrders/HostOrders fund tracking
TransactorInvariant.t.sol L1→L2 transactions - gas tracking, forwarding

Invariants Tested (35 total)

Fund Safety:

  • ETH/token balance accounting matches entered minus withdrawn
  • Token exits equal tokens burned
  • Orders balances match initiated minus swept
  • HostOrders/Transactor hold no funds (pass-through design)

Liveness:

  • Can always receive ETH, exit tokens, initiate/fill orders
  • System can make progress

Sequencing & Settlement:

  • Only one rollup block per host block per chain
  • Block submissions bounded by block progression
  • Gas limits enforced

Access Control:

  • Admin addresses immutable

Testing

All 35 invariants pass with 50 runs × 20 call depth per invariant (5,000 fuzzing calls each).

Closes ENG-1533

Adds 35 invariant tests covering fund safety, liveness, and sequencing
integrity across the contract suite:

- ZenithInvariant.t.sol: sequencing contract invariants
- PassageInvariant.t.sol: host-side passage (ETH/token entry)
- RollupPassageInvariant.t.sol: rollup-side passage (exits/burns)
- OrdersInvariant.t.sol: order handling (RollupOrders, HostOrders)
- TransactorInvariant.t.sol: L1→L2 transaction handling

All tests pass with 50 runs × 20 call depth per invariant.

Closes ENG-1533
@prestwich
Copy link
Member

[Claude Code]

CI Performance Investigation

The solidity-base job took ~3 hours to complete. Here's the breakdown of invariant test suite runtimes:

Suite Started Finished Duration
PassageInvariant 18:43 18:43 ~36s
RollupPassageInvariant 18:43 18:44 ~93s
ZenithInvariant 18:44 18:45 ~106s
TransactorInvariant 18:45 21:42 ~2h 57m
OrdersInvariant 21:42 21:42 ~17s

TransactorInvariant alone consumed ~2h 57m of the total run. All other suites finished within ~2 minutes each.

Run Configuration Mismatch

The PR description states "50 runs × 20 call depth" but CI actually ran with 256 runs × 500 call depth (128,000 calls per invariant). With 9 tests in TransactorInvariant, that's 1,152,000 total fuzz calls for this suite. The handler is likely much more expensive per call than the others. Consider setting a lighter CI profile (matching the intended 50 × 20) and reserving deep fuzzing for nightly/manual runs.

Failing Invariants

Two invariants failed:

1. invariant_withdrawalBounded (PassageInvariant.t.sol)

More ETH withdrawn than entered: 4949719072411001312510 < 4965098576059291827157

The fuzzer found a sequence where total withdrawals exceeded total entries. The counterexample shows a withdrawEth call with an enormous value (9.558e58), suggesting the handler isn't clamping withdrawal amounts to the available balance. Failed on run 20/256.

2. invariant_hostOrdersNoFunds (OrdersInvariant.t.sol)

This invariant asserts HostOrders holds no funds (pass-through design). The fuzzer found that after a fillTokenOutput(200, 9822, ...) call, the contract retained some token balance. Failed on run 107/256.

Both failures look like test handler bugs (unbounded inputs, incorrect pass-through modeling) rather than contract bugs — but worth verifying.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants