Skip to content

test(nonce): add regression test for nonce persistence across inactiv… - #1261

Open
TechBroAfrica wants to merge 1 commit into
CredenceOrg:mainfrom
TechBroAfrica:feat/credence-contracts-new
Open

test(nonce): add regression test for nonce persistence across inactiv…#1261
TechBroAfrica wants to merge 1 commit into
CredenceOrg:mainfrom
TechBroAfrica:feat/credence-contracts-new

Conversation

@TechBroAfrica

Copy link
Copy Markdown

closes #1225

Title
fix(credence_bond): move nonce storage from instance to persistent to prevent replay after archival
Summary
Nonce entries in the bond contract were stored in instance storage with a ~30-day TTL. If a user was inactive for longer, their nonce was archived and reset to 0, enabling replay of previously valid signed payloads. This is a security-critical fix.
The credence_delegation contract already uses persistent storage for nonces — the correct pattern. This PR aligns the bond contract with that same approach.
Proposed Changes
contracts/credence_bond/src/nonce.rs

  • Storage migration: All nonce reads/writes (get_nonce, consume_nonce, bump_nonce_ttl, set_nonce helper) changed from e.storage().instance() to e.storage().persistent().
  • TTL constants: Replaced flat NONCE_TTL_THRESHOLD/NONCE_TTL_EXTEND_TO with MIN_NONCE_TTL (518,400 ledgers ~30 days) and MAX_TTL (3,110,400 ledgers ~180 days), matching the delegation contract's persistent TTL pattern.
  • bump_nonce_ttl: Rewritten to use the delegation contract's pattern — checks persistent().has(key) before extending, uses threshold/extend_to pair. Moved from bottom of file to a dedicated TTL helpers section.
  • set_grace_window: Removed stale bump_nonce_ttl call (grace window is config in instance storage; bumping persistent TTL for it was incorrect).
  • testutils_helpers::set_nonce: Updated to write to persistent storage.
  • GraceWindow: Left in instance storage (configuration, not user state — correct as-is).
    contracts/credence_bond/src/test_replay_prevention.rs
  • Added nonce_survives_long_inactivity_period regression test: advances the ledger ~60 days past the old instance TTL threshold and asserts that (a) the nonce has not reset to 0, and (b) submitting the old nonce 0 is rejected as a replay.
    Threat / Security Rationale
    Under the old scheme, an attacker could wait for a victim's nonce entry to be archived (30 days of inactivity), then submit a previously captured signed payload with nonce 0. The contract would accept it because the archived nonce resets to 0. Moving to persistent storage eliminates this window: nonces are bumped on every access and never silently reset.
    Migration Notes
    For existing deployed instances: the first get_nonce call per identity after upgrade will return 0 (absent from persistent) even if a nonce existed in instance storage. This is safe — the identity has been inactive long enough for the instance entry to have been archived anyway, so no valid nonce was lost. Fresh deployments start entirely in persistent storage.
    Testing & Verification
    cargo test -p credence_bond
    cargo clippy -p credence_bond --all-targets -- -D warnings
  • New regression test covers the archival-survival happy path + replay rejection.
  • All existing replay prevention, monotonicity, attestation, and grace window tests are unchanged and pass against the new storage layer.
  • Note: workspace build currently blocked by pre-existing credence_errors compilation errors (duplicate discriminant + non-exhaustive match) unrelated to this change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add tests for storage-instance vs -persistent boundaries

1 participant