[REAL DoS] Reserve source capacity for admitted positions - #142
[REAL DoS] Reserve source capacity for admitted positions#142aeyakovenko wants to merge 4 commits into
Conversation
|
Independent clean-room LiteSVM confirmation against the exact binaries, extended to remove the owner-footgun ambiguity. I changed only a temporary harness at wrapper head RED, exact Meta pin
GREEN, exact wrapper
Command used for both binaries: This is a real public-interface DoS: an unaffiliated taker can trap an already-authorized passive LP; it does not require the victim owner to submit the unsafe trade. |
|
Added a generalized admission-to-continuation theorem in
All 5 non-vacuity covers are reachable, including latent-domain rejection before the physical table is full and exact-boundary materialization. Mutation checks showed the theorem fails if either the candidate reservation or existing latent reservations are omitted. Removing the production guard makes the existing attach integration regression fail, tying the theorem to the real transition. Verification:
No layout, wrapper-facing API, or spec change. |
|
Independent Meta LiteSVM follow-up found the max-source conversion path that this PR explicitly leaves separate. Public red test: aeyakovenko/percolator-meta@1e1a33f The fixture creates every claim through signed Results at the chain's 1,400,000-CU ceiling:
The failed conversion rolls market and portfolio bytes back. The owner can withdraw the original 1,000,000-unit principal, but cannot withdraw any of the 32 earned, source-backed units, and the remaining positive-claim portfolio cannot close. There is no domain-selective public conversion wire, so the supported state has no bounded live owner path to recover earned value. This is a separate real public-interface LoF, not a reason to weaken this admission fix. A fix needs either a transaction-bounded domain-local conversion cursor/chunk or a proven full conversion below the ceiling at all supported source shapes, while preserving the caller cap and PR #267/#140's domain-local burn semantics. I left the Meta branch red and opened no Meta PR pending that upstream fix. |
What changed
Reserve sparse source-domain capacity before admitting each new position. Capacity now accounts for both occupied historical claims and every active leg whose favorable K/F source domain has not been materialized yet.
The focused engine regression covers three boundaries: a full table rejects a missing favorable domain without mutation, a full table permits a domain already represented, and an active leg reserves its still-empty favorable domain.
Root cause and impact
attach_leg_at_slotchecked the 16-leg limit but did not reserve one of the portfolio's 32 sparse source slots for the leg's first favorable settlement. A user could publicly accumulate claims in all 32 domains, retain an old claim-bearing exposure, and open a new asset whose favorable domain was absent. After an honest mark move, settlement needed a 33rd source entry and returnedLockActive.The paired public LiteSVM red test shows that auto-crank, source-claim conversion, closing either position through
TradeNoCpi, andRebalanceReduceall fail with rollback. The live portfolio has no bounded owner or permissionless keeper continuation; only privileged asset shutdown followed by forfeiture can rescue it.This is also a concrete gap in the conditional no-DoS proof claim: the selector's refresh witness exists at the kernel level, but the real dispatch body fails at source insertion. The capacity invariant closes that monolithic gate-reachability case for newly admitted positions.
Verification
cargo test --all-targets -- --test-threads=1cargo test --features fuzz --all-targets -- --test-threads=1cargo kani -Z function-contracts --features fuzz,contracts --harness composition_attach_body_frame_division_stubbed --output-format terse143e68c4917ed0400a27b952f036a5677047cd84at the no-continuation assertion.BatchTradeNoCpi: 1,308,173 CUBatchTradeCpi: 1,339,517 CUBatchTradeCpiwith four maximum tail accounts: 1,343,687 CU