Skip to content

test(fuzz): extend fuzz coverage to escrow_contract and threshold_window - #22

Merged
Meshmulla merged 1 commit into
stellar-kracken:mainfrom
priscaenoch:feature/5-fuzz-escrow-threshold
Jul 27, 2026
Merged

test(fuzz): extend fuzz coverage to escrow_contract and threshold_window#22
Meshmulla merged 1 commit into
stellar-kracken:mainfrom
priscaenoch:feature/5-fuzz-escrow-threshold

Conversation

@priscaenoch

Copy link
Copy Markdown
Contributor

Summary

Closes #5

Extends fuzz testing beyond the relay contract to the two other critical contracts called out in the issue: escrow_contract and threshold_window. Both new suites follow the existing pattern in soroban/tests/relay_contract_fuzz.rs (deterministic, seed-driven pseudo-fuzzing via a small xorshift PRNG, no new dependencies), but the invariants asserted are built around the guarantees each module is supposed to provide, not around mirroring the relay tests' implementation details — per the guidance in the issue thread.

soroban/tests/threshold_window_fuzz.rs

threshold_window's functions are plain (non-contract) entrypoints that validate input via panic! rather than returning Result, so these tests use catch_unwind and assert every panic is one of the module's known validation messages — anything else would indicate a real bug.

  • fuzz_create_window_validates_inputs_without_unexpected_panics — fuzzes window_id/length/threshold_bps across valid and invalid combinations (empty id, zero length, out-of-range bps), asserting classification coverage and that any panic is a known one.
  • fuzz_evaluate_threshold_matches_expected_deviation_and_never_panics — fuzzes signed reference_value/current_value pairs (bounded to avoid overflowing the module's own unchecked arithmetic) and checks the returned deviation/breach classification against an independently computed expected value.
  • fuzz_max_windows_cap_and_removal_keep_state_consistent — drives window creation to the MAX_WINDOWS cap and back down through a pseudo-random removal pattern, checking the window list stays consistent throughout.

escrow_contract/tests/escrow_contract_fuzz.rs

All calls go through try_* client methods, so a host-level panic surfaces as Err(Err(_)) instead of crashing the test process — treated as a bug rather than a classification.

  • fuzz_create_escrow_classifies_invalid_amount_and_metadata_without_panicking — fuzzes amount (zero, negative, i128::MAX to exercise the overflow-safe checked_mul fee path) and metadata length (including the 512-byte boundary), asserting each lands in the correct EscrowError bucket.
  • fuzz_release_never_exceeds_balance_and_blocks_after_finalization — confirms released_amount never exceeds the releasable total (no negative/over-released balances) and that a fully released escrow can never be released or refunded again (no invalid state transitions).
  • fuzz_batch_release_keeps_uniform_escrows_in_lockstep_without_overdraw — confirms a batch of uniform escrows stays in lockstep and no escrow is ever overdrawn.

CI wiring

Iteration count defaults to a small value and is overridable via FUZZ_ITERATIONS for longer local campaigns (documented in each file's header). Adds a new bounded fuzz job to .github/workflows/ci.yml that runs the relay, threshold_window, and escrow_contract fuzz suites with a capped iteration count (FUZZ_ITERATIONS=200) on every push/PR, keeping it fast while still exercising all three suites continuously.

No bugs were found in the existing contract logic during this work, so there are no follow-up issues to file per the acceptance criteria.

Testing/validation performed

All performed locally against a fresh stable Rust toolchain (matching what CI installs):

  • cargo fmt --all -- --check — passes
  • cargo clippy --all-targets --all-features -- -D warnings — passes (no warnings)
  • cargo build --release --target wasm32-unknown-unknown — passes
  • cargo test (full workspace) — all tests pass, including the 6 new fuzz tests
  • FUZZ_ITERATIONS=3000 cargo test --test threshold_window_fuzz --test escrow_contract_fuzz — all pass, verifying the "longer local campaign" path is not just documented but actually correct at scale

Issue

#5

Adds deterministic, seed-driven fuzz tests for the two critical contracts
that previously had no fuzz coverage beyond the relay contract, mirroring
the pattern in soroban/tests/relay_contract_fuzz.rs rather than any
implementation detail of the contracts under test:

- soroban/tests/threshold_window_fuzz.rs: create_window is fuzzed across
  valid/invalid window_id, length, and threshold_bps combinations via
  catch_unwind (threshold_window's functions panic directly rather than
  returning Result), asserting every panic message is one of the module's
  known validation messages; evaluate_threshold is fuzzed across signed
  reference/current value pairs and checked against an independently
  computed expected deviation; and a dedicated test drives window
  creation to the MAX_WINDOWS cap and back down through removal,
  checking the window list stays consistent throughout.

- escrow_contract/tests/escrow_contract_fuzz.rs: create_escrow is fuzzed
  across invalid amounts (zero, negative, i128::MAX to exercise the
  overflow-safe checked_mul fee path) and oversized metadata via
  try_create_escrow; release_escrow is fuzzed to confirm released_amount
  never exceeds the releasable total and that a fully released escrow
  can never be released or refunded again; batch_release is fuzzed
  across uniform escrows to confirm they stay in lockstep without any
  one escrow being overdrawn.

Iteration count defaults to a small, CI-cheap value and is overridable
via the FUZZ_ITERATIONS env var for longer local campaigns; verified at
FUZZ_ITERATIONS=3000 with no failures.

Wires a new bounded "fuzz" CI job (.github/workflows/ci.yml) that runs
the relay, threshold_window, and escrow_contract fuzz suites with a
capped iteration count on every push/PR.

Closes stellar-kracken#5
@Meshmulla
Meshmulla merged commit d5783e4 into stellar-kracken:main Jul 27, 2026
3 checks passed
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.

Extend fuzz testing beyond the relay contract (escrow, threshold_window)

2 participants