You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Why this matters now:
Issue #52 fixed CreatorTasks(Address) from an unbounded Vec to indexed persistent entries. The exact same bug exists in DataKey::UserVerifications(Address) in reward-engine/src/storage.rs. A user who submits many proofs accumulates an ever-growing Vec<u64> that is read in full on every push_user_verification_key call, and eventually the serialized Vec will exceed transaction limits, permanently bricking that user's ability to submit new proofs. This directly blocks the mainnet launch goal.
Problem / What: push_user_verification_key reads the entire Vec<u64> for a user from persistent storage, appends one entry, and writes it back. read_user_verification_tasks loads the entire Vec to serve any paginated query. As a user accumulates verifications (one per task attempt), the Vec grows without bound. At ~100+ entries, the Soroban 100-entry footprint limit will be approached; beyond that the transaction will panic with a resource exhaustion error. The fix pattern is identical to #52: replace with UserVerificationCount(Address) + UserVerification(Address, u64) indexed storage.
Key Challenges:
Must migrate the storage layout without breaking existing on-chain data (any deployed instance with existing UserVerifications Vecs needs a migration strategy or clear deprecation path).
get_verifications_by_user slicing logic must be rewritten to use indexed reads.
The old DataKey::UserVerifications(Address) variant must be retained in the enum to prevent key-space collisions on deployed contracts.
Why this matters now:
Issue #52 fixed
CreatorTasks(Address)from an unbounded Vec to indexed persistent entries. The exact same bug exists inDataKey::UserVerifications(Address)inreward-engine/src/storage.rs. A user who submits many proofs accumulates an ever-growingVec<u64>that is read in full on everypush_user_verification_keycall, and eventually the serialized Vec will exceed transaction limits, permanently bricking that user's ability to submit new proofs. This directly blocks the mainnet launch goal.Problem / What:
push_user_verification_keyreads the entireVec<u64>for a user from persistent storage, appends one entry, and writes it back.read_user_verification_tasksloads the entire Vec to serve any paginated query. As a user accumulates verifications (one per task attempt), the Vec grows without bound. At ~100+ entries, the Soroban 100-entry footprint limit will be approached; beyond that the transaction will panic with a resource exhaustion error. The fix pattern is identical to #52: replace withUserVerificationCount(Address)+UserVerification(Address, u64)indexed storage.Key Challenges:
UserVerificationsVecs needs a migration strategy or clear deprecation path).get_verifications_by_userslicing logic must be rewritten to use indexed reads.DataKey::UserVerifications(Address)variant must be retained in the enum to prevent key-space collisions on deployed contracts.test_500_task_regression_creation_succeedspattern fromCreatorTasksVec in task-registry grows unboundedly; prolific sponsors can cause storage exhaustion #52).Acceptance Criteria:
push_user_verification_keydoes exactly 1 persistent read + 2 persistent writes regardless of existing verification count (O(1)).get_verifications_by_user(user, cursor, limit)reads onlylimitindexed entries, not the full history.DataKey::UserVerifications(Address)is marked deprecated in the enum with a comment explaining the migration.get_verifications_by_usertests still pass.Relevant files/functions:
contracts/reward-engine/src/storage.rs—push_user_verification_key,read_user_verification_tasks,DataKey::UserVerificationscontracts/reward-engine/src/verification.rs—RewardEngine::get_verifications_by_userOut of scope: Changing verification business logic, TTL management (Issue 1),
VerificationListfix (Issue 3).