Repository navigation
fix: ensure task_id is monotonic (incrementing) (#13) - #321
Open
Rodrigoue9 wants to merge 1 commit into
Open
Rodrigoue9 wants to merge 1 commit into
Rodrigoue9 wants to merge 1 commit into
Conversation
Enforce strictly incrementing sequential task IDs via DataKey::TaskCounter to prevent ID collisions, gaps, and ID reuse.
Rodrigoue9
force-pushed
the
fix/issue-13-monotonic-task-id
branch
from
October 3, 2026 16:03
7b91e59 to
c7d47f3
Compare
This was referenced Oct 7, 2026
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
What was wrong
Previously,
VeroContractallowed callers with theTaskManagerrole to specify arbitrary, sparsetask_idvalues when registering tasks. This exposed the protocol to task ID collisions, out-of-order IDs, sequence gaps, and potential ID resurrection attacks if a purged task ID were re-registered after removal from storage.What was done & Alternatives Considered
This pull request resolves Issue #13 by introducing a strictly monotonic sequential counter stored in instance storage (
DataKey::TaskCounter). Task registration now enforces that each incomingtask_idstrictly equalscurrent_counter + 1. The counter starts at 0 (meaning the first registered task is ID 1) and advances strictly by 1 per task. The counter is preserved across task lifecycle transitions (includingpurge_task), permanently preventing ID reuse or resurrection.task_idinsideregister_taskwithout requiring caller to pass it. Rejected because altering the signatureregister_task(admin, task_id, min_votes)would break public ABI compatibility, existingBatchCall::RegisterTaskenum variants, and external client integrations. Enforcing sequential IDs againstcurrent_counter + 1satisfies the monotonic guarantee while preserving backward-compatible signatures.task_id > last_id. Rejected because the issue acceptance criteria strictly specified "IDs increment by exactly 1" to ensure dense contiguous sequencing.What to look at
purge_taskremoves the task data but intentionally leavesDataKey::TaskCounteruntouched, ensuring purged IDs cannot be revived.register_tasks, sequence checks are performed up-front before the reentrancy lock, and state changes (includingDataKey::TaskCounter) are applied atomically. A gap or out-of-order ID anywhere in a batch aborts the entire registration without updating the counter.get_task_counter(env: Env) -> u64to allow clients and frontends to determine the next expected task ID before submitting transactions.archive_task_auth.rs,consensus_delegation.rs,integration.rs, andmulti_contract_isolation.rsthat previously used arbitrary mock IDs (e.g. 42, 100) were updated to use sequential IDs (1, 2, 3) to comply with the monotonic invariant.How verified
tests/monotonic_task_id.rscovering counter initialization, sequential increments, gap rejection, zero ID rejection, duplicate/lower ID rejection, full lifecycle transitions, purge non-reuse, multi-contract isolation, batch atomic rollback, and RBAC/pause validation.test_register_tasks_batch_monotonicinsrc/task.rs.cargo fmt --all -- --check: 100% compliant.cargo clippy --workspace --all-targets -- -D clippy::all: 0 warnings, 0 errors.Related Issue
Closes #13
Changes Made
src/contracts/storage_layout.rs):DataKey::TaskCountervariant in instance storage tracking the highest registered task sequence ID.src/task.rs):pub fn get_task_counter(env: &Env) -> u64readingDataKey::TaskCounter(defaulting to 0).register_tasksto validate that incoming task IDs strictly increment by 1 fromcurrent_counter.test_register_tasks_batch_monotonicverifying sequential batches, internal gap rejection, and out-of-order rejection.src/contracts/proxy_entry/entry_tasks.rs):pub fn get_task_counter(env: Env) -> u64.tests/monotonic_task_id.rs):tests/archive_task_auth.rs,tests/consensus_delegation.rs,tests/integration.rs, andtests/multi_contract_isolation.rsto start sequentially from ID 1.Testing Performed
cargo test --test monotonic_task_id: 10/10 tests passed.cargo test --lib task::tests: passed.cargo fmt --all -- --check: formatting 100% compliant.cargo clippy --workspace --all-targets -- -D clippy::all: 0 warnings, 0 errors.Checklist
Closes #13.cargo fmt --check.cargo clippy -- -D warningswhere applicable.