fix(contract): handle u64::MAX ID overflow - reject with ContractFull error + event (#615) - #680
Conversation
Sequential u64 ID counters (badges, streams, ownership records, campaigns, disputes, and distribution history) incremented with `counter + 1` panic on the next allocation once they reach u64::MAX. Add a guard before every increment that rejects the operation with a new descriptive ContractFull error and emits a contract_full event instead of panicking on arithmetic overflow. Applies the guard to: - soulbound-badge: mint_badge (BadgeCounter) - nft-stream: create_stream (StreamCounter) + mint_ownership_record (OwnershipCounter) - campaign-funding: create_campaign (CampaignCount) - payment-stream: create_stream_internal (StreamCount) + resolve_dispute (DisputeCount) - dispute-arbiter: create_dispute (DisputeCount) - distributor: record_history (hist_cnt) Also fixes pre-existing blockers that prevented `cargo test --all` from compiling: missing commas in the workspace Cargo.toml members list, duplicate imports in payment-stream tests, incorrect .unwrap() usage in dispute-arbiter tests, and stale should_panic expectations in campaign-funding tests that no longer match the host error format. Closes Fundable-Protocol#615 Generated with Codebuff 🤖 Co-Authored-By: Codebuff <noreply@codebuff.com>
|
@vijay11149 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! 🚀 |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Utilitycoder
left a comment
There was a problem hiding this comment.
Please fix up the merge conflict and update your PR. Kindly ensure you offramp with Fundable at https://stellar.fundable.finance/offramp
Utilitycoder
left a comment
There was a problem hiding this comment.
Please fix up the merge conflict and update your PR. Kindly ensure you offramp with Fundable at https://stellar.fundable.finance/offramp
|
all done sir |
|
all done now |
Summary
Fixes #615 — bug(contract): Tree ID overflow. Sequential
u64ID counters across the contracts were incremented withcounter + 1with no upper-bound check. When a counter reachesu64::MAX, the next allocation panics on arithmetic overflow (the release profile enablesoverflow-checks = true), bricking the contract's ability to create any new records.This PR adds a
u64::MAXguard before every counter increment. When the limit is hit, the contract now rejects the operation gracefully with a descriptiveContractFullerror code and emits aContractFullevent — instead of panicking.Root cause
Every ID-allocating function reads a stored
u64counter and unconditionally doescounter + 1:Changes
soulbound-badgemint_badgeBadgeCounternft-streamcreate_stream,mint_ownership_recordStreamCounter,OwnershipCountercampaign-fundingcreate_campaignCampaignCountpayment-streamcreate_stream_internal,resolve_disputeStreamCount,DisputeCountdispute-arbitercreate_disputeDisputeCountdistributorrecord_historyhist_cntFor each guarded site:
u64::MAXcheck — if the counter equalsu64::MAX, the operation is rejected before the increment.ContractFullerror code — new descriptive variant appended to each contract's error enum:soulbound-badge→Error::ContractFull = 11nft-stream→Error::ContractFull = 11campaign-funding→Error::ContractFull = 17payment-stream→Error::ContractFull = 32dispute-arbiter→ArbiterError::ContractFull = 10distributor→ descriptive panic message (contract has no error-code enum; message is surfaced to the caller for logging)ContractFullevent — newContractFullEvent(topiccontract_full, with the exhausted resource + timestamp) published before rejecting, so indexers/loggers can observe the contract reaching capacity.nft-stream::mint_ownership_recordnow returnsResult<u64, Error>so the error propagates out ofcreate_streamasErr(Error::ContractFull)instead of panicking.Acceptance criteria
counter == u64::MAXbefore incrementing and returns theContractFullerror instead of overflowing.ContractFullEventis emitted with the resource + timestamp so off-chain loggers/indexers can record the rejection; client-sidetry_*calls surface the exact error code.Tests
New tests for every guarded site, driving the counter to
u64::MAXand asserting the graceful rejection:soulbound-badge:test_mint_rejected_when_badge_counter_fullnft-stream:test_create_stream_success,test_create_stream_rejected_when_stream_counter_full,test_create_stream_rejected_when_ownership_counter_full(first-ever test module for this contract)campaign-funding:test_create_campaign_rejected_when_counter_fullpayment-stream:test_create_stream_rejected_when_stream_count_full,test_resolve_dispute_rejected_when_dispute_count_fulldispute-arbiter:test_create_dispute_rejected_when_count_fulldistributor:test_distribute_rejected_when_history_index_fullCI verification:
cargo test --all→ 182 tests pass across all 6 contract crates;cargo clippy --all --all-targets→ 0 errors.Pre-existing fixes required to run CI
cargo test --alldid not compile onmainbefore this PR. To land a green CI run (required by the task), the following pre-existing blockers were fixed (all test/build-only, no behavior change):contracts/Cargo.toml— missing commas in the workspacememberslist made the manifest unparseable;campaign-fundingandsoulbound-badgewere not even built.payment-stream/src/test.rs— duplicateusestatements (E0252 compile error).dispute-arbitertests —.unwrap()calls on client methods that already unwrap the contract'sResult(E0599).campaign-fundingtests — 14#[should_panic(expected = "VariantName")]expectations updated to the actual host error formatError(Contract, #N).Notes
ContractFullEventevents are emitted before the error is returned; on-chain event visibility follows normal Soroban semantics (events from failed invocations are only surfaced via diagnostics — the event definition + emission makes the signal available to indexers that subscribe to successful calls and serves as documentation of the contract's capacity limit).Closes #615