fix(utxo): require admin key for rollback_genesis (bounty #2819) - #8393
Conversation
|
Welcome to RustChain! Thanks for your first pull request. Before we review, please make sure:
Bounty tiers: Micro (1-10 RTC) | Standard (20-50) | Major (75-100) | Critical (100-150) A maintainer will review your PR soon. Thanks for contributing! |
rollback_genesis() was a destructive state mutation reachable with no authorization: it deletes every genesis box and transaction and evicts pending mempool claims that depend on them. Any code path importing the module, or the --rollback CLI flag, could wipe the UTXO genesis set. Add an authorization gate keyed on RC_ADMIN_KEY: - Fail closed: an unset key refuses (operator never intended rollback to be possible) - Missing key arg refused - Wrong key refused via constant-time hmac.compare_digest - CLI gains --admin-key; unauthenticated rollback exits 1 Update all existing rollback test suites to pass the key and add a TestRollbackAuthorization class covering the four auth outcomes.
6627758 to
d618b91
Compare
|
@Skywalkingzulu1 — verdict on the #2819 claim first, then the PR. Not payable under #2819. The hardening itself is fine. Requiring |
RTC RewardThis merged PR earned 5 RTC — sent to |
…s CI) (#8467) #8393 set os.environ["RC_ADMIN_KEY"] = "test-rollback-admin-key-2819" at import time. That value is 28 chars; the node sys.exit(1)s on a key < 32 chars, so every later test module that imports the node aborted pytest collection and the CI "test" job has failed on every PR since 9/14. The overwrite also leaked into later tests that send conftest's key (401s). Use the suite-wide key from tests/conftest.py (setdefault, so the file still runs standalone) and pass that same value to rollback_genesis(). Local run of the exact CI command (CI env + tests/requirements.txt): before: collection INTERNALERROR (SystemExit: 1), 0 tests run after: 4009 passed, 2 failed The 2 remaining failures (test_utxo_dual_write_double_spend, test_utxo_transfer_spends_account_mirror) fail standalone on main and are unrelated: mirror boxes are now filtered before the 409 ACCOUNT_MIRROR_BOX_NOT_SPENDABLE check, so the endpoint returns 400 "Insufficient UTXO balance" instead. The box is still not spent. Signed-off-by: Scott <scottbphone12@gmail.com> Co-authored-by: Scott <scottbphone12@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
ollback_genesis() in
ode/utxo_genesis_migration.py\ was a destructive state mutation reachable with no authorization. It deletes every genesis box and transaction and evicts pending mempool claims that depend on them. Any code path importing the module, or the --rollback\ CLI flag, could wipe the UTXO genesis set and its pending spends.
Fix
ollback_genesis(db_path, admin_key=None)\ now calls the gate first, before any state mutation
Tests
ode/test_rollback_atomicity.py,
ode/test_utxo_2819_rollback_mempool_and_bounded_select.py,
ode/test_genesis_race.py, and \ ests/test_utxo_security_audit.py\ to pass the key
Verification
ode/test_genesis_race.py: both scenarios pass
ode/test_utxo_db.py: 107 passed
This finding is distinct from the three existing open #2819 PRs (#8388 receiver-side mirror provenance, #8332 red-team audit report, #8302 fee/output/conservation invariants) — none of them cover the rollback authorization gap.
Co-authored-by: Thamsanqa Skenjana tahmiix@gmail.com