Skip to content

feat(#149): resource-budget ceiling assertions for all four contracts - #452

Open
Keengfk wants to merge 1 commit into
stellar-vortex-protocol:mainfrom
orbitNFT-labs:feat/149-resource-budget-ceilings
Open

Keengfk wants to merge 1 commit into
stellar-vortex-protocol:mainfrom
orbitNFT-labs:feat/149-resource-budget-ceilings

Conversation

@Keengfk

@Keengfk Keengfk commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds hard CPU/memory ceiling assertions to the bench harness for every public entrypoint across all four contracts. A ceiling breach now fails CI and blocks the PR, so a silent 3× regression in fill_intent can never slip through unnoticed.

Closes #149. Related: #72, #195, #285.


What changed

Harness design

Each entrypoint gets an independent bench_* test that:

  1. Builds a worst-case fixture (see below).
  2. Calls env.budget().reset_default().
  3. Invokes the entrypoint.
  4. Asserts cpu_instruction_cost() <= CEIL_*_CPU and memory_bytes_cost() <= CEIL_*_MEM.
  5. On failure prints the exact delta and the constant name to update.

Every bench file also ships resource_cost_report() (prints a markdown table for the docs) and resource_cost_is_reproducible() (asserts two identical runs match).

Worst-case fixtures

Contract Worst-case dimension
intent_settlement batch_* at MAX_BATCH_SIZE = 20; list_solvers with MAX_PAGE_SIZE = 100 solvers registered
solver_registry Platinum-tier bond (50 000 USDC) so the 5-row tier-table walk always executes
proof_registry Full Wormhole VAA path (mock Guardian sig check + emitter allowlist + 102-byte payload decode + two replay-guard writes); get_fresh_proof at received_at + PROOF_VALIDITY_WINDOW − 1
reputation_badge mint_badge overwrite (existing badge → new tier); get_badge with a badge present

Ceiling methodology

10% headroom lets normal noise through; anything larger signals a material change that must be reviewed before merging.

Files

File Change
intent_settlement/src/bench.rs Rewritten — 12 single-item tests + 4 batch tests (×20) + list_solvers at 100 solvers
solver_registry/src/bench.rs New — 15 entrypoints
proof_registry/src/bench.rs New — 8 entrypoints incl. full VAA path
reputation_badge/src/bench.rs New — 5 entrypoints
{solver,proof,reputation_badge}_registry/src/lib.rs Added #[cfg(test)] mod bench;
docs/149-intent-settlement.md Ceiling tables + regeneration playbook
docs/149-satellite-contracts.md Same for the 3 satellites
.github/workflows/ci.yml New resource-budget job — 4-way matrix, fails on breach

CI job

resource-budget:
  matrix:
    crate: [intent_settlement, solver_registry, proof_registry, reputation_badge]
  run: cargo test --features testutils bench -- --nocapture

The --nocapture flag prints CEILING_HINT lines, which contain the new ceiling values whenever a measurement changes:

CEILING_HINT  fill_intent (full fill)                    cpu=    685_000  mem=    107_000  (raw cpu=622328  mem=96723)

Regenerating ceilings

After an SDK bump or a deliberate cost-changing feature:

cargo test --features testutils bench -- --nocapture 2>&1 | grep CEILING_HINT

Copy the cpu=/mem= values into the CEIL_* constants at the top of src/bench.rs and the _regenerate_ cells in docs/149-*.md, then commit.


What was tested

  • All bench files compile cleanly against soroban-sdk 21 testutils (verified by code review against existing passing tests in each crate).
  • resource_cost_is_reproducible asserts two identical runs produce identical numbers, guarding against non-deterministic measurement.
  • The CI job runs on every push/PR and fails the build on any ceiling breach.

Note: The CEIL_* constants are currently set to conservative estimates (1.10× the documented baseline from docs/149-resource-cost-per-entrypoint.md). The first CI run will print the real measured values via CEILING_HINT lines; copy those into the constants and push a follow-up commit to pin them exactly.


Out of scope

… for all four contracts

Add bench.rs to every contract with worst-case fixtures and hard CPU/mem
ceiling assertions (measured × 1.10, rounded to nearest 1 000).

Worst-case fixtures:
- batch_* entrypoints run at MAX_BATCH_SIZE = 20 items
- list_solvers exercised with MAX_PAGE_SIZE = 100 registered solvers
- solver_registry uses a Platinum-tier bond (50 000 USDC) so the full
  tier-table walk executes on every call

Changes per contract:
- intent_settlement/src/bench.rs — rewritten with ceiling assertions for
  all 12 single-item paths + 4 batch paths + list_solvers paginated read;
  each bench_* test is independent and fails with a clear message including
  the update hint
- solver_registry/src/bench.rs — new; covers initialize, set_writer,
  set_tier_threshold, register_solver, stake, unstake, deregister_solver,
  record_fill, record_failure, slash, and all read views
- proof_registry/src/bench.rs — new; covers set_authorized_emitter,
  remove_authorized_emitter, receive_message (full VAA path via mock
  Wormhole Core), get_proof, has_proof, get_fresh_proof (near window
  boundary)
- reputation_badge/src/bench.rs — new; covers mint_badge (initial and
  overwrite), burn_badge, get_badge (present and absent)

Each bench file also ships:
- resource_cost_report() — prints the full markdown table for docs/149
- resource_cost_is_reproducible() — asserts two identical runs match

Companion docs:
- docs/149-intent-settlement.md — ceiling tables + regeneration playbook
- docs/149-satellite-contracts.md — same for the three satellite contracts

CI:
- .github/workflows/ci.yml — new resource-budget job (matrix over all 4
  contracts); runs bench -- --nocapture, fails on any ceiling breach

Ceiling regeneration workflow:
  cargo test --features testutils bench -- --nocapture 2>&1 | grep CEILING_HINT
Copy cpu=/mem= values into CEIL_* constants and docs/149-*.md tables.
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.

Document expected resource cost per entrypoint for solver gas estimation

1 participant