Skip to content

feat(contract): ADR 0012 + implementation: reclaim storage for settled escrows - #259

Open
Cmitchelle7 wants to merge 1 commit into
DocForum:mainfrom
Cmitchelle7:feat/adr-implementation-reclaim-storage-for-settled
Open

Cmitchelle7 wants to merge 1 commit into
DocForum:mainfrom
Cmitchelle7:feat/adr-implementation-reclaim-storage-for-settled

Conversation

@Cmitchelle7

@Cmitchelle7 Cmitchelle7 commented Oct 24, 2026 •

Copy link
Copy Markdown

Closes #48.

Settled escrows stayed in persistent storage forever. ADR 0013 compares delete / keep-only-Status / keep-everything and picks keep only the existing Status entry.

Behaviour

  • Every terminal transition of an ordinary escrow (release, refund, quorum variants, timeout refund, cancel, and settle_many) goes through settle(). It now removes the persistent EscrowData and keeps only the DataKey::Status entry (the lightweight status read added in feat(perf): profile and optimize status reads #260), before the payout. The existing ESCROW state event carries the history.
  • get_status is unchanged and still answers for settled ids, so NotFound now means "never created".
  • get_escrow returns NotFound for a settled id. Breaking; SDK minor via changeset.
  • release / refund / top_up / accept / cancel / rotate_releaser on a settled id still return NotFunded. A non-releaser now gets NotFunded instead of Unauthorized there, since the releaser set is gone. Funded escrows are unchanged.
  • Ids are never reused.
  • Pooled escrows (feat(contract): pooled escrows funded by multiple payers with pro-rata refunds #257) are not reclaimed: contributions, pull-based refunds and get_pooled read their record after settlement. Covered by a test and the ADR.

Rent measured: the 628-byte record is reclaimed per settled escrow; a 28-byte Status entry remains. cargo test --test reclaim_storage status_entry -- --nocapture prints it.

Known gap: the state event omits refund_to and release_not_before. Widening it breaks the indexer's fixed 12-field decoder, so it is left as a separate change (noted in the ADR and ROADMAP).

Why this supersedes the earlier version: main added the Status entry (#260), which already is the minimal tombstone, so this no longer introduces a SettledEscrow type. Rebuilt on current main; ADR renumbered to 0013.

Tests: 220 contract tests pass, including 12 new in tests/reclaim_storage.rs. cancel.rs, model.rs and the liabilities.rs oracle were updated for the documented read behaviour. Snapshots (escrow and releaser-account) and bindings are regenerated with the pinned Stellar CLI 28.1.0. SDK typecheck, build and offline tests pass; the resource-baseline check passes.

Out of scope: TTL/rent policy (#10), testnet redeploy, SDK tarball publish.

@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 24, 2026
@github-actions

Copy link
Copy Markdown

@Cmitchelle7 This PR now has merge conflicts with main, most likely because #260 (feat(perf): profile and optimize status reads) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

@github-actions github-actions Bot removed the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 24, 2026
@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Cmitchelle7 pls fix CI

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Cmitchelle7 CI is failing on this branch against the latest main, so it can't be merged yet. The errors from the latest run:

Soroban contract (test + wasm build)

thread 'race_cancel_lands_first_then_accept_fails_and_payer_keeps_the_funds' (5507) panicked at tests/cancel.rs:138:5:
test result: FAILED. 17 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.17s
error: test failed, to rerun pass `--test cancel`

race_cancel_lands_first_then_accept_fails_and_payer_keeps_the_funds panics at tests/cancel.rs:138. Run cargo test --test cancel in contracts/escrow on top of the latest main to see the assertion. main's cancel and accept paths have changed since this branch was created.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Cmitchelle7 CI is failing in cargo test (Soroban contract job):

thread 'race_cancel_lands_first_then_accept_fails_and_payer_keeps_the_funds' panicked at tests/cancel.rs:138:5:
assertion failed: matches!(f.client.try_get_escrow(&f.escrow_id), Err(Ok(Error::NotFound)))
test result: FAILED. 17 passed; 1 failed

The test expects the escrow to be gone after cancel, but get_escrow still finds it. Either the contract or the assertion needs updating to match current main behaviour. Please run cargo test in contracts/escrow, commit any updated test_snapshots/, and push.

@github-actions github-actions Bot added the needs-rebase Has merge conflicts with main; the author needs to rebase label Oct 27, 2026
@github-actions

Copy link
Copy Markdown

@Cmitchelle7 This PR now has merge conflicts with main, most likely because #242 (feat(contract): per-token liability accounting and solvency view) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Cmitchelle7 Heads-up: #268 just changed how contract PRs work in this repo. Your PR changes contracts/escrow/src/lib.rs, so CI's new "Contract changes use a fragment, not a version bump" step will fail it until you make these changes (details in contract-changes.d/README.md):

  1. Don't edit CONTRACT_VERSION when you merge main (currently 2.3.0). Keep main's line as it is.

  2. Add a fragment, e.g. contract-changes.d/<issue>-feat-contract-adr-0012-implementation-re.md:

    bump: minor
    ---
    Issue #NN: one-paragraph summary of the contract change.

    Use patch for a behaviour fix with no interface change, minor for new entry points, arguments, events or errors, and major for breaking changes.

  3. If you add any new Error variants, give them provisional codes (issue number × 100 + n, e.g. NN00) and never renumber existing ones.

This should also make your next merge from main much easier: the version line was the one thing every contract PR conflicted on.

…d escrows (DocForum#48)

Every terminal transition of an ordinary escrow goes through settle(): it now
removes the persistent EscrowData and keeps only the DataKey::Status entry (the
lightweight status read from the status-read optimization), before the payout,
then publishes the existing ESCROW state event. get_status is unchanged and
answers for settled ids (NotFound now means never created); get_escrow is
funded-only; release, refund, top_up, accept, cancel and rotate_releaser on a
settled id return NotFunded via load() (a non-releaser no longer gets
Unauthorized there, since the releaser set is gone). settle_many inherits this
through settle().

Pooled escrows are deliberately not reclaimed: contributions, pull-based
refunds and get_pooled read their record after settlement (ADR 0011).

Measured: the 628-byte record is reclaimed per settled escrow; a 28-byte Status
entry remains. Includes ADR 0013, a changelog.d fragment, a changeset,
regenerated SDK bindings (pinned Stellar CLI 28.1.0) and the affected
snapshots (escrow and releaser-account). The liabilities oracle now walks ids
with get_status.
@Cmitchelle7
Cmitchelle7 force-pushed the feat/adr-implementation-reclaim-storage-for-settled branch from 6af6151 to 0bc8184 Compare October 30, 2026 12:06
@afeezorobsco-cyber

Copy link
Copy Markdown
Contributor

@Cmitchelle7 Thanks for the rebase. Two checks fail on 0bc8184:

  1. Soroban contract: contracts/escrow/src/lib.rs changed, but no fragment was added under contract-changes.d/. Add contract-changes.d/48-reclaim-settled-escrow-storage.md as described in contract-changes.d/README.md (and in my earlier comment). Don't bump CONTRACT_VERSION; the maintainer fold does that.
  2. Contract cargo-fuzz: the lifecycle target panics with Error(Contract, #1) from get_escrow. contracts/escrow/fuzz/fuzz_targets/lifecycle.rs calls client.get_escrow(&escrow_id) at line 201 after release/refund, and the escrow no longer exists once your PR reclaims storage for settled escrows. Update the fuzz target (e.g. try_get_escrow, expecting not-found after settlement) in this PR.

@github-actions github-actions Bot added needs-rebase Has merge conflicts with main; the author needs to rebase and removed needs-rebase Has merge conflicts with main; the author needs to rebase labels Oct 30, 2026
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

@Cmitchelle7 This PR now has merge conflicts with main, most likely because #271 (chore(contract): fold contract changes into 2.5.0 and fold changelog) was just merged, so it can't be merged until it's rebased:

git fetch upstream            # upstream = https://github.com/DocForum/docforum-escrow.git
git rebase upstream/main
# resolve the conflicts, re-run the tests, then:
git push --force-with-lease

The usual culprits are shared docs like ROADMAP.md and ARCHITECTURE*.md. If the conflict is in the ROADMAP.md changelog, move your entry into a new file under changelog.d/ (see changelog.d/README.md) rather than resolving it in place, so it can't conflict again. CI re-runs when you push, and the needs-rebase label is removed automatically once the conflicts are resolved.

Automated message. It won't repeat unless the PR conflicts again after your next push.

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

Labels

needs-rebase Has merge conflicts with main; the author needs to rebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Phase E5] ADR + implementation: reclaim storage for settled escrows

2 participants