feat: add per market ttl preflight - #904
Merged
greatest0fallt1me merged 1 commit intoJul 24, 2026
Merged
Conversation
|
@pheobeayo Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Contributor
|
Merged into master via admin resolver (-X theirs). |
4 tasks
Contributor
|
Merged — nice work on this one 🎯 |
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.
Pull Request Description
📋 Basic Information
Type of Change
DataKeyrepairRelated Issues
Closes #839 Related to #836 (documents the storage tiers this check operates on)
Priority Level
📝 Detailed Description
What does this PR do?
#839 asks for a storage-TTL preflight on
create_market. A preflight already exists:check_market_creation_rentatstorage.rs:41, wired into both creation paths (markets.rs:132,lib.rs:413), with three tests inmarket_creation_validation_tests.rsunder a// ── Storage Rent Pre-flight Tests ──header.Rather than reimplement it, this PR completes the parts that were scoped out. The code signposts them through two dead symbols:
Deliberately not touched: repairing these means restructuring imports and module declarations across a 7,700-line file, which is a different change from "preflight storage TTL pressure" and would likely conflict with several of the 40 open PRs.
Manual Testing Steps
lib.rscreate_marketend to end and enumerated everypersistent().set(...)reached during one call, followingrecord_market_createdandappend_recordinto their own modules to confirm each write's storage tier.grep -rn "InsufficientStorageRentBudget" --include=*.rsacross the crate — confirmed four occurrences, all declaration/display, zero constructors.grep -rn "MARKET_CREATION_PERSISTENT_KEYS" --include=*.rs— confirmed a single occurrence (its own declaration).effective_ttl * MARKET_CREATION_PERSISTENT_KEYSboundary values used in the tests againstu32::MAX.master; confirmed two hunks inmarkets.rs, two inlib.rs, and the intended edits instorage.rs.📚 Documentation
Documentation Updates
///with# Formulaand# Errors, matching the existing preflight's styleBreaking Changes
Breaking Changes:
Error::InsufficientStorageRentBudgetwas already a declared variant with a stable numeric code (523). This PR only makes it reachable, so clients switching on error codes see a code that was already in the enum. The newDataKeyvariants were already being constructed at call sites; the enum simply did not declare them.Migration Guide: Not applicable.
🔍 Code Quality
Code Review Checklist
ok_or(...)?on both fallible steps, nounwrap()Performance Impact
u32arithmetic operations and onemax_ttl()read percreate_market. Negligible.Security Review
🚀 Deployment & Integration
Deployment Notes
Integration Points
create_market; clients usingtry_create_marketmay now observe code 523📊 Impact Assessment
User Impact
create_marketcan now surfaceInsufficientStorageRentBudget(523). Two previously dead symbols are now live and meaningful.Business Impact
lib.rsbreakage, which remains outstanding.✅ Final Checklist
Pre-Submission
Review Readiness
📸 Screenshots (if applicable)
Not applicable.
🔗 Additional Resources
contracts/predictify-hybrid/src/storage.rs💬 Notes for Reviewers
Please pay special attention to:
The value
3forMARKET_CREATION_PERSISTENT_KEYS. Derived by reading the entrypoint's write path: market record, platform statistics, audit record. If any helper writes more entries than I traced, or a fourth write exists that I missed, the constant is too low and the check is correspondingly too weak. This is the single number most worth a second pair of eyes.Whether commit 1 (the
DataKeyrepair) belongs in this PR. It is scope creep beyond Add per-market TTL preflight #839, included only because nothing compiles without it. It is the first commit and touches nothing else, so it can be cherry-picked out or this PR rebased onto a separate fix. If a repair is already in flight among the open PRs, I will drop it.Keeping both checks vs. consolidating to one. See "Alternative Solutions Considered".
Questions for reviewers:
contracts/predictify-hybrid/src/markets.rsas the file to modify, and that file already containedcheck_market_creation_rent(env)?;at line 132 before this PR. I have read the issue as asking for completion of the scoped-out aggregate check rather than a reimplementation — please redirect me if that reading is wrong.lib.rsbreakage (236 errors) tracked anywhere? I could not find an issue for it, and it blocks any PR that needs to run the test suite.set_balancetier-helper cleanup stay in this PR, or move to its own? It is a separate commit and unrelated to the preflight beyond touching the same file.Thank you for your contribution to Predictify! 🚀
# Pull Request Description📋 Basic Information
Type of Change
DataKeyrepairRelated Issues
Closes #839
Related to #836 (documents the storage tiers this check operates on)
Priority Level
📝 Detailed Description
What does this PR do?
#839 asks for a storage-TTL preflight on
create_market. A preflight alreadyexists:
check_market_creation_rentatstorage.rs:41, wired into bothcreation paths (
markets.rs:132,lib.rs:413), with three tests inmarket_creation_validation_tests.rsunder a// ── Storage Rent Pre-flight Tests ──header.Rather than reimplement it, this PR completes the parts that were scoped out.
The code signposts them through two dead symbols:
MARKET_CREATION_PERSISTENT_KEYSstorage.rs:26, never read, and its value (1) was wrongError::InsufficientStorageRentBudgeterr.rs:239with display strings at:1555,:1666,:1787— never constructedTwo error variants existed for one concept, one unreachable. That reads as an
intended split:
InsufficientStorageRent— single-keyu32overflow (was implemented)InsufficientStorageRentBudget— aggregate multi-key budget (was not)Changes:
MARKET_CREATION_PERSISTENT_KEYS: 1 → 3. The entrypoint writes threepersistent entries per creation, not one:
lib.rs:418record_market_created→set_platform_statsstatistics.rs:58AuditTrailManager::append_recordaudit_trail.rs:114Each confirmed persistent by reading the function body. The
MarketCreator::create_markethelper writes only entry 1, so the constant isdocumented as an upper bound: a creation that succeeds on the helper path
cannot then fail partway through the entrypoint path.
New
check_market_creation_rent_budgetinstorage.rs, returningInsufficientStorageRentBudget.Wired into both call sites —
markets.rspropagates via?;lib.rspanics via
panic_with_error!because the entrypoint returnsSymbol, notResult.set_balancerouted through the tier helper instead of hardcoded TTLliterals (separate commit, droppable).
Prerequisite:
DataKeyrepaired so the crate compiles at all (separatecommit, droppable — see Notes for Reviewers).
Why is this change needed?
The existing check has two limits:
within
effective_ttl(~6.3M ledgers, ~365 days) ofu32::MAX— which iswhy the existing test must set
sequence_number: u32::MAX - 1_000totrigger it at all.
identical verdict.
The gap: a market record could be stored with a full TTL while its companion
statistics and audit entries could not be given one.
How was this tested?
cargo testcould not be run — the base branch does not compile. See "TestResults". The five tests below are added and are expected to pass once the base
builds.
Manual verification performed instead:
3.greped the whole crate to confirmInsufficientStorageRentBudgethad noconstructor and
MARKET_CREATION_PERSISTENT_KEYShad no reader.LEDGERS_PER_DAY = 17_280.-2paren deltain
lib.rsis pre-existing (unbalanced parens inside doc-comment prose),identical before and after these edits.
masterto confirm only the intended hunkschanged.
Alternative Solutions Considered
Replace
check_market_creation_rentinstead of adding alongside it. Theaggregate check mathematically subsumes it, making the original redundant at
both call sites. Kept because removing it would break the three existing tests
that assert
InsufficientStorageRentspecifically. Happy to consolidate to onecall and one error if preferred.
Reorder the fee charge. In
markets.rsthe preflight still runs afterprocess_creation_fee. Pre-existing ordering; a rent failure returnsErrsothe host rolls back the whole invocation and no funds are lost. Left unchanged
as out of scope.
Change the
lib.rsentrypoint to returnResult. Would allow propagationinstead of panicking. Not done — breaking signature change for every client.
Reimplement the preflight from scratch per the issue text. Rejected: it
already exists in the exact file #839 names.
🏗️ Smart Contract Specific
Contract Changes
check_market_creation_rent_budgetcreate_market(both paths),set_balanceDataKeyvariants (all previously constructed at call sites; no new on-chain key shapes)InsufficientStorageRentBudgetnow reachableOracle Integration
Not applicable — no oracle code touched.
Market Resolution Logic
Not applicable — no resolution code touched.
Security Considerations
checked_multhenchecked_add, no wrapping arithmetic, nounwrap()The change is strictly more conservative: it rejects a superset of what was
rejected before. No input previously accepted-and-fully-written is now
accepted-and-partially-written.
🧪 Testing
Test Coverage
u32::MAX, aggregate-overflow boundary, normal sequenceTests added to the
storage.rstest module under a new// ── Storage Rent Aggregate Budget Pre-flight Tests ──header:test_budget_check_accepts_normal_ledger_sequenceOktest_budget_check_rejects_aggregate_overflowInsufficientStorageRentBudgettest_budget_check_is_stricter_than_single_key_checkOk, aggregateErrtest_budget_check_rejects_at_u32_max_sequenceu32::MAX→Errtest_balance_ttl_honours_storage_config_overrideset_balancerespectsStorageConfigThe third is the important one: it pins the relationship between the two checks
and fails if the aggregate check is ever weakened to match the single-key one.
Test Results
Two independent pre-existing breakages:
1.
storage.rs—DataKey(fixed by commit 1 of this PR)Plus
AntiGriefFloor,GlobalConfig, andPlaceBetsIdemconstructed indisputes.rs, the governance tests, andbets.rsbut absent from the enum.2.
lib.rs— 236 errors (NOT addressed in this PR)Errordefined multiple timesuse err::Error;(L71) andpub use err::Error;(L155)CircuitBreaker/EventEmitterre-importedBetStatusis privatebets::BetStatusnotpubevents::ClaimInfocrate::types::ClaimInfocapability_bitmap_testsmoddeclared, file absentstatistics,graceful_degradation,market_id_generator,rate_limitercrate::x::…, never declaredmod x;— files existDeliberately not touched: repairing these means restructuring imports and module
declarations across a 7,700-line file, which is a different change from
"preflight storage TTL pressure" and would likely conflict with several of the
40 open PRs.
Manual Testing Steps
lib.rscreate_marketend to end and enumerated everypersistent().set(...)reached during one call, followingrecord_market_createdandappend_recordinto their own modules to confirmeach write's storage tier.
grep -rn "InsufficientStorageRentBudget" --include=*.rsacross the crate —confirmed four occurrences, all declaration/display, zero constructors.
grep -rn "MARKET_CREATION_PERSISTENT_KEYS" --include=*.rs— confirmed asingle occurrence (its own declaration).
effective_ttl * MARKET_CREATION_PERSISTENT_KEYSboundary valuesused in the tests against
u32::MAX.master; confirmed two hunks inmarkets.rs, two inlib.rs, and the intended edits instorage.rs.📚 Documentation
Documentation Updates
///with# Formulaand# Errors, matching the existing preflight's styleBreaking Changes
Breaking Changes:
Error::InsufficientStorageRentBudgetwas already a declared variant with astable numeric code (523). This PR only makes it reachable, so clients switching
on error codes see a code that was already in the enum. The new
DataKeyvariants were already being constructed at call sites; the enum simply did not
declare them.
Migration Guide: Not applicable.
🔍 Code Quality
Code Review Checklist
ok_or(...)?on both fallible steps, nounwrap()Performance Impact
u32arithmetic operations and onemax_ttl()read percreate_market. Negligible.Security Review
🚀 Deployment & Integration
Deployment Notes
real ledger sequence before mainnet.
unaffected.
Integration Points
create_market; clients usingtry_create_marketmay now observe code 523📊 Impact Assessment
User Impact
that would have produced a partially-provisioned market.
create_marketcan now surfaceInsufficientStorageRentBudget(523). Two previously dead symbols are nowlive and meaningful.
statistics and audit entries lack a full TTL.
Business Impact
surfaced later as missing audit or statistics data now fails fast at creation.
constant, and eliminates one hardcoded TTL literal. Does not address the
larger
lib.rsbreakage, which remains outstanding.✅ Final Checklist
Pre-Submission
Review Readiness
📸 Screenshots (if applicable)
Not applicable.
🔗 Additional Resources
contracts/predictify-hybrid/src/storage.rs[Soroban state archival & TTL](https://developers.stellar.org/docs/build/guides/archival)
💬 Notes for Reviewers
Please pay special attention to:
The value
3forMARKET_CREATION_PERSISTENT_KEYS. Derived by readingthe entrypoint's write path: market record, platform statistics, audit record.
If any helper writes more entries than I traced, or a fourth write exists that
I missed, the constant is too low and the check is correspondingly too weak.
This is the single number most worth a second pair of eyes.
Whether commit 1 (the
DataKeyrepair) belongs in this PR. It is scopecreep beyond Add per-market TTL preflight #839, included only because nothing compiles without it. It is
the first commit and touches nothing else, so it can be cherry-picked out or
this PR rebased onto a separate fix. If a repair is already in flight among
the open PRs, I will drop it.
Keeping both checks vs. consolidating to one. See "Alternative Solutions
Considered".
Questions for reviewers:
contracts/predictify-hybrid/src/markets.rsas the file to modify, and thatfile already contained
check_market_creation_rent(env)?;at line 132 beforethis PR. I have read the issue as asking for completion of the scoped-out
aggregate check rather than a reimplementation — please redirect me if that
reading is wrong.
lib.rsbreakage (236 errors) tracked anywhere? I could not find anissue for it, and it blocks any PR that needs to run the test suite.
set_balancetier-helper cleanup stay in this PR, or move to itsown? It is a separate commit and unrelated to the preflight beyond touching
the same file.
Thank you for your contribution to Predictify! 🚀