Skip to content

feat(escrow): explicit storage TTL management - #1764

Merged
mikewheeleer merged 2 commits into
Talenttrust:mainfrom
OkeA-dev:feat/storage-ttl-management
Oct 25, 2026
Merged

mikewheeleer merged 2 commits into
Talenttrust:mainfrom
OkeA-dev:feat/storage-ttl-management

Conversation

@OkeA-dev

Copy link
Copy Markdown
Contributor

Summary

Implements explicit storage TTL management for the escrow contract so live state is never left to archive while the protocol is in use.

Closes #1710

Changes

  • bump_instance is now called from every public mutating entry point: deposit_funds, release_milestone, open_dispute, resolve_dispute, cancel_contract, issue_reputation, void_rating, plus initialize, set_paused and create_contract which already did it. This keeps the instance (holding Admin, Paused, NextId) alive during normal use.
  • Added extend_escrow_ttl(id) — permissionless; extends the escrow entry and its Rating(id) side key (when present) to PERSISTENT_TTL_EXTEND, and bumps the instance TTL. Returns ContractNotFound (5) when the escrow does not exist.
  • Added extend_reputation_ttl(freelancer) — permissionless; extends Reputation(freelancer) and the instance TTL. Returns ReputationNotFound (20) when no reputation record exists.
  • Read-only getters are unchanged and never bump TTL.
  • README.md: documented the new functions and added a Storage TTL policy section (thresholds, who pays, archival behaviour, errors).
  • No TTL constants were changed. No unrelated refactors.

Security checklist

  • Can a permissionless TTL extension change any state other than TTL? No. Both functions only call extend_ttl on existing keys and bump_instance; they perform no set/remove. The tests assert the escrow/reputation values are byte-for-byte identical before and after the call.
  • Authorization: both keep-alive functions deliberately require no auth. Tests run them with env.mock_auths(&[]) to prove no authorization is needed.
  • Events: no events are emitted by either keep-alive function, so indexers cannot mistake them for lifecycle changes.
  • Missing records: fail explicitly (ContractNotFound / ReputationNotFound) instead of creating empty entries.
  • Caller pays: the caller pays the transaction fee and the storage rent implied by the TTL extension.

Acceptance evidence

TTL tests

contracts/escrow/src/test.rs uses env.as_contract(..) with instance().get_ttl() / persistent().get_ttl(&key):

  • initialize_bumps_instance_ttl
  • every_mutating_entry_point_bumps_instance_ttl — covers set_paused, create_contract, deposit_funds, release_milestone, open_dispute, resolve_dispute, cancel_contract, issue_reputation, void_rating; each call is made after the instance is aged below PERSISTENT_TTL_THRESHOLD and must leave TTL >= threshold.
  • extend_escrow_ttl_raises_contract_rating_and_instance_ttl
  • extend_reputation_ttl_raises_reputation_and_instance_ttl
  • extend_escrow_ttl_missing_id_returns_contract_not_found
  • extend_reputation_ttl_missing_record_returns_reputation_not_found
  • getters_do_not_extend_ttl — all getters leave instance/persistent TTL unchanged.
  • extended_escrow_survives_past_unbumped_expiry — archival simulation.

How the archival scenario is simulated

The test creates two identical escrows and ages the ledger until each has PERSISTENT_TTL_THRESHOLD / 2 ledgers left. It calls extend_escrow_ttl on one, then advances remaining + 1 ledgers. The un-bumped escrow (main behaviour) is now archived — the test host escalates archived storage access to a panic, which the test catches to prove the entry is unreachable; on the real network the call would not be admitted. The escrow kept alive by extend_escrow_ttl (this branch) is still readable and returns its data.

Build / wasm size

cargo build --target wasm32v1-none --release
  • Before (main): 38,481 bytes
  • After (this branch): 39,753 bytes
  • Delta: +1,272 bytes (~3.3%), far below the 128 KB network limit.

cargo clippy --all-targets is clean. No existing test was deleted or weakened; existing tests are unchanged.

Full cargo test output

    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.59s
     Running unittests src/lib.rs (target/debug/deps/escrow-a002c7a24891b423)

running 21 tests
test test::extend_reputation_ttl_missing_record_returns_reputation_not_found ... ok
test test::extend_escrow_ttl_missing_id_returns_contract_not_found ... ok
test test::extend_reputation_ttl_raises_reputation_and_instance_ttl ... ok
test test::cancel_unfunded_escrow_does_not_count_cancellation ... ok
test test::extend_escrow_ttl_raises_contract_rating_and_instance_ttl ... ok
test test::initialize_bumps_instance_ttl ... ok
test test::extended_escrow_survives_past_unbumped_expiry ... ok
test test::dispute_split_and_cancel ... ok
test test::full_happy_path ... ok
test test::initialize_only_once ... ok
test test::pause_blocks_mutations ... ok
test test::dispute_outcomes_freelancer_client_and_exact_threshold ... ok
test test::ratings_issued_before_upgrade_return_rating_not_found ... ok
test test::getters_do_not_extend_ttl ... ok
test test::non_admin_cannot_void_rating ... ok
test test::rejects_overfunding_and_double_release ... ok
test test::rate_then_void_restores_reputation_and_prevents_rerating ... ok
test test::void_unrated_escrow_fails_with_rating_not_found ... ok
test test::rate_resolved_escrow_succeeds_once_and_cancelled_rejected ... ok
test test::void_one_of_three_ratings_preserves_others ... ok
test test::every_mutating_entry_point_bumps_instance_ttl ... ok

test result: ok. 21 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 1.21s

@mikewheeleer

Copy link
Copy Markdown
Contributor

hey @OkeA-dev 👋 this PR scans clean and CI is green, but it now has merge conflicts with main — please rebase on the latest main and push, and we'll merge it 🙌

# Conflicts:
#	README.md
#	contracts/escrow/src/lib.rs
#	contracts/escrow/src/test.rs
@mikewheeleer
mikewheeleer merged commit c3fd2a4 into Talenttrust:main Oct 25, 2026
2 checks passed
@mikewheeleer

Copy link
Copy Markdown
Contributor

well done — thanks for this!

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.

Prevent escrow and instance storage archival with explicit TTL management

2 participants