[5/n][guardian-integration] soft-reserve RPC + pre-commit integration#464
Closed
0xsiddharthks wants to merge 1 commit intosiddharth/guardian-wid-cachefrom
Closed
[5/n][guardian-integration] soft-reserve RPC + pre-commit integration#4640xsiddharthks wants to merge 1 commit intosiddharth/guardian-wid-cachefrom
0xsiddharthks wants to merge 1 commit intosiddharth/guardian-wid-cachefrom
Conversation
This was referenced Apr 17, 2026
6d3c9ff to
229cd1e
Compare
The hard-reserve path added in #423/PR-2 only debits the bucket AFTER MPC — which means a leader can spend minutes doing committee fan-out + MPC signing only to discover the guardian is out of capacity. Add a pre-commit soft reserve so that over-limit withdrawals abort cheaply and do not churn leader iterations. Guardian side (`hashi-types` + `hashi-guardian`): - Extend RateLimiter with pending_reserves: HashMap<wid, PendingReserve>, a soft_reserve method (idempotent on wid, monotonic timestamp, capacity = refill - sum(pending)), and expire_pending for TTL sweep (SOFT_RESERVE_TTL_SECS = 5 min). - consume now takes wid as well and drops any matching pending entry so a hard reserve converts the soft reserve atomically. - Add SoftReserveWithdrawal RPC and handler. Soft reserves do not require a committee signature — the TTL bounds DoS blast radius and wid idempotency handles retries. - Spawn a 1-second TTL sweep task in main so expired reservations free capacity promptly. Hashi side: - Add GuardianClient::soft_reserve_withdrawal wrapper. - In leader::process_approved_withdrawal_request_batch, probe the guardian immediately after coin selection (build_withdrawal_tx_ commitment) and before the committee BLS fan-out for commit. Rate-limited / unavailable aborts the iteration; next leader tick retries with the same wid so the reservation is reused. - Extract compute_withdrawal_wid helper so both touchpoints derive the same deterministic identifier from request_ids. Move package: no changes.
cadedf6 to
791b34a
Compare
Contributor
Author
|
Folded into #423. The soft pre-MPC and hard post-MPC guardian touchpoints now ship together as a single MVP integration PR. See The soft-reserve commit (791b34a) was cherry-picked onto Branch |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR-2 (hard reserve post-MPC) means an over-limit withdrawal only surfaces AFTER we've done committee fan-out + MPC signing — minutes of wasted work per leader iteration. This PR adds a lightweight pre-commit soft reserve so over-limit withdrawals abort cheaply.
Guardian changes (
hashi-types+hashi-guardian)RateLimitergainspending_reserves: HashMap<wid, PendingReserve>and asoft_reserve(wid, timestamp, amount, now)method. Idempotent on wid (repeat probes return the existing reservation with a refreshed TTL). Capacity check:refill_capacity(timestamp) - Σ pending.amount_sats ≥ amount.consumenow takeswidand drops any matching pending entry — a hard reserve atomically converts a soft reserve.expire_pending(now)drops stale entries;SOFT_RESERVE_TTL_SECS = 5 min. A 1s sweep task runs in `main.rs`.SoftReserveWithdrawalRPC. No committee signature required for soft reserves — the TTL bounds DoS blast radius and wid idempotency handles retries.Hashi changes
GuardianClient::soft_reserve_withdrawalwrapper.leader::soft_reserve_withdrawal_through_guardianprobes the guardian after coin selection and before the committee BLS fan-out for commit. Rate-limited / unavailable → abort iteration; next tick retries with the same wid (guardian returns the same reservation).compute_withdrawal_widextracted into `withdrawals.rs` so both touchpoints derive the same deterministic id.Move package
No changes.
Tests
test_soft_reserve_is_idempotent_on_wid— repeat probes return existing reservation, TTL refreshedtest_soft_reserve_rejects_over_commitment_across_wids— pending amounts subtract from capacitytest_soft_reserve_enforces_monotonic_timestamp— out-of-order timestamps rejectedtest_expire_pending_drops_stale_reservations— TTL sweep drops past-due entriestest_consume_removes_matching_soft_reserve— hard reserve atomically drops pendingtest_soft_reserve_leaves_room_for_hard_reserve_of_same_wid— end-to-end: soft-reserve capacity, then hard-reserve succeedsconsume(wid, seq, …)signatureFollow-ups
LimiterState+ pending/recent maps from S3 on boot (PR-5 in the stack).