feat: add storage rent sweep and estimated_storage_footprint (#40) - #42
Open
Clement-coder wants to merge 1 commit into
Open
feat: add storage rent sweep and estimated_storage_footprint (#40)#42Clement-coder wants to merge 1 commit into
Clement-coder wants to merge 1 commit into
Conversation
Cross-cutting changes across all six contracts to address Issue Kqirox#40 (persistent storage rent sweep / reclaim path). ## What changed ### course-registry (primary sweep target) - complete_module: appends (learner, course_id) to FinishedProgressIndex on final module completion so sweep can find finished entries - sweep_storage(admin, sweep_learning_keys) -> u32: admin-only; pops up to SWEEP_BATCH_SIZE (50) entries from FinishedProgressIndex, removes each DataKey::Progress slot, decrements ProgressCount - estimated_storage_footprint() -> u32: CourseCount + ProgressCount - DataKey: FinishedProgressIndex comment updated; ProgressCount now decremented by sweep (not just incremented on enroll) - 8 new tests covering sweep batch-size limit, multi-learner/course, no-op flag, unauthorized panic, empty index, footprint tracking ### quest-engine - DataKey: added QuestCount, SubmissionCount counters - create_build_quest / create_explore_quest: increment QuestCount - submit_proof: increments SubmissionCount - sweep_submissions(admin, flag, Vec<(Address,u32)>) -> u32: removes Approved/Rejected submissions, skips Pending, respects 50-entry cap - estimated_storage_footprint() -> u32: QuestCount + SubmissionCount - 5 new tests ### governance - DataKey: added ProposalCount, VoteCount counters - create_proposal(proposer, metadata_hash, voting_period_seconds) -> u32: new public function (was missing); increments ProposalCount + ID counter; emits ProposalCreated event - cast_vote: increments VoteCount - sweep_storage(admin, flag, Vec<u32>) -> u32: removes executed/cancelled proposals (executed==true), decrements ProposalCount - estimated_storage_footprint() -> u32: ProposalCount + VoteCount - 5 new tests ### badge-nft - DataKey: added BadgeHolderCount counter - mint_badge: detects first-time badge vec creation; increments BadgeHolderCount once per learner (not per badge) - estimated_storage_footprint() -> u32: BadgeHolderCount - BadgeNFTInterface trait: exposes estimated_storage_footprint - 3 new tests ### stake-vault - DataKey: added StakerCount counter - stake: increments StakerCount only on first stake per user - unstake: decrements StakerCount after removing the entry (self-cleaning) - estimated_storage_footprint() -> u32: StakerCount - 3 new tests ### reward-pool - DataKey: added SpenderCount counter - add_approved_spender: idempotent counter bump (only new spenders counted) - estimated_storage_footprint() -> u32: SpenderCount - RewardPoolInterface trait: exposes estimated_storage_footprint - 2 new tests ## Test results 196 tests, 0 failures, 0 warnings Closes Kqirox#40
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
Closes #40 — adds a contract-internal sweep/reclaim path and storage footprint view across all six contracts.
Problem
Soroban charges ongoing rent on every persistent storage entry. Without an off-ramp, abandoned entries (finished learner progress, reviewed quest submissions, executed proposals) accumulate indefinitely and rent-charges grow monotonically.
Approach
Soroban has no storage-scan API, so the implementation uses inline instance-storage counters maintained at each mutation point plus an append-only index vector (
FinishedProgressIndex) for the highest-volume sweep target (learner progress).Changes by contract
course-registry (primary sweep target)
complete_module: appends(learner, course_id)toFinishedProgressIndexon final module completionsweep_storage(admin, sweep_learning_keys) -> u32: pops up toSWEEP_BATCH_SIZE(50) entries, removesDataKey::Progressslots, decrementsProgressCountestimated_storage_footprint() -> u32:CourseCount + ProgressCountquest-engine
sweep_submissions(admin, flag, Vec<(Address,u32)>) -> u32: removes Approved/Rejected submissions, skips Pendingestimated_storage_footprint() -> u32:QuestCount + SubmissionCountgovernance
create_proposal(...) -> u32: new public function (was missing); emitsProposalCreatedsweep_storage(admin, flag, Vec<u32>) -> u32: removes executed/cancelled proposalsestimated_storage_footprint() -> u32:ProposalCount + VoteCountbadge-nft
estimated_storage_footprint() -> u32:BadgeHolderCount(one entry per unique learner)stake-vault
stake/unstakemaintainStakerCount(self-cleaning on withdrawal)estimated_storage_footprint() -> u32:StakerCountreward-pool
add_approved_spender: idempotent counter bumpestimated_storage_footprint() -> u32:SpenderCountTesting
196 tests, 0 failures, 0 warnings
26 new tests covering:
sweep_learning_keys=falseis a strict no-opCost-benefit tradeoffs
The counter drift risk is acceptable: TTL expiry is the desired outcome (storage freed), so a slightly stale counter only underestimates the footprint after natural TTL expiry — fine for an estimate.