Every disclosed Bitcoin / Bitcoin Core consensus bug class, mapped to the equivalent attack on the eWatts reference implementation and closed. Last pass: 2026-09-12.
The reference implementation in Rust is tested against the attack classes that forced hard forks or emergency releases in Bitcoin. Each class gets a test that rebuilds the exploit against the real eWatts types and asserts the outcome. The suite is a regression gate: if any fix is reverted, the suite fails.
cargo test --test bitcoin_parity_suite -- --nocapture
# 12 tests, all must report DEFENDED
Ordered by severity. Each row is one confirmed exploit before the fix.
| Class | Severity | Root cause | Fix | Where |
|---|---|---|---|---|
| CVE-2018-17144 | Critical | A transaction could reference the same UTXO twice (same or different key image). The input counted twice, so 5,000 in produced 9,000 out. Value was minted from a duplicated input. | Reject duplicate (previous_tx_hash, output_index) pairs inside a single transaction, in both the pre-check and the spend path. |
state.rs fixed |
| CVE-2010-5139 | Critical | A transaction with no inputs, placed outside index 0, was applied as if it were the coinbase. Arbitrary value minted with no UTXO consumed. | Only the coinbase (index 0) may have empty inputs. Any other no-input transaction is rejected at validation and at apply time. | state.rs fixed |
| CVE-2010-5139 | Critical | Coinbase output sum used unchecked u64 addition. Two large outputs overflowed the sum: panic in debug, wrap in release, breaking the emission guard. |
Checked arithmetic (try_fold) for every emission and coinbase sum, in both state and consensus. |
state.rs, consensus.rs fixed |
| CVE-2012-2459 | High | Merkle root self-paired the odd leaf, so [A,B,C] and [A,B,C,C] hashed to the same root. Two different bodies, one header commitment. |
RFC 6962-style body root: domain-separated leaves (tx vs commitment), domain-separated internal nodes, odd node carried up instead of duplicated. Duplicating a transaction now changes the root. | block.rs fixed |
| CVE-2024-52912 | High | No timestamp rule. A block could carry any timestamp, including u64::MAX/2 or a value before its parent, allowing timewarp and difficulty manipulation across the window. |
Median-time-past over the last 11 blocks, plus a bounded future drift of 2 hours relative to the parent, enforced in consensus. | consensus.rs fixed |
| CVE-2019-25220 | High | The difficulty and timestamp gate lived only on the P2P ingress path. Any other writer (orphan resolution, sync ingest, reload) could persist a block that failed consensus, enabling low-difficulty chain spam. | A cheap parent-linked gate (difficulty equals parent, timestamp rule) now runs inside ChainStore::add_block for every writer, plus an add_block_validated entry point for full validation. |
chain.rs fixed |
| CVE-2024-35202 | Medium | Compact block reconstruction dropped the body commitments and skipped the merkle root check, returning a body that could not hash to its own header. | Commitments travel in the compact block and are restored; reconstruction verifies the body root against the header and rejects a mismatch. | p2p.rs fixed |
| CVE-2025-54605 | Medium | The raw block save path wrote anything it was handed, including blocks that fail consensus, filling disk with invalid data. | The persistence boundary validates the block (body root, proof binding, emission bounds) before writing. Invalid blocks never reach disk, from any path. | store.rs fixed |
| Body commitments | High | The commitment set (bandwidth declarations that drive emission) was not covered by the merkle root or the proof hash. A relay could swap a validly signed commitment for another and change who gets paid, unauthenticated. | The body root now commits the transactions and the commitments, with separate leaf domains. The same root binds the header, so swapping a commitment changes the header. | block.rs, consensus.rs, main.rs fixed |
Output from the parity suite after the fixes. Each line is one attack class, rebuilt against the current code.
[CVE-2018-17144] duplicate input in one tx -> DEFENDED (validate + spend rejected) [CVE-2018-17144b] same utxo spent twice in a block -> DEFENDED (second spend: UTXO not found) [CVE-2010-5139] no-input tx outside index 0 -> DEFENDED (only the coinbase may create value) [CVE-2010-5139] coinbase output sum overflow -> DEFENDED (Coinbase amount overflow) [CVE-2012-2459] duplicate tx vs merkle root -> DEFENDED (roots differ) [CVE-2019-25220] low-difficulty block to store -> DEFENDED (consensus + store both reject) [CVE-2024-52912] timestamp rule -> DEFENDED (future drift + median-time-past) [CVE-2024-35202] compact reconstruction -> DEFENDED (body committed, commitments carried) [CVE-2025-54605] raw save path -> DEFENDED (invalid block not persisted) [CVE-2025-46598] output count amplification -> DEFENDED (linear, ~1ms for 50k outputs) [CVE-2024-52911] validation cache (N/A) -> DEFENDED (no script engine, no tx cache) [body-commitments] commitments in the body root -> DEFENDED (swapped commitment rejected)
Full report: repository, audit/BITCOIN-PARITY-2026-09-12.md.
Consensus-level value creation, input double-spending, body authentication, timewarp, chain ingest gating, and persistence boundaries. These are the classes that have cost Bitcoin hard forks.