Repository navigation
test: pin the first two-phase cargo-mutants misses - #975
Conversation
average-gary
left a comment
There was a problem hiding this comment.
Reviewed for correctness and performance. Nothing blocking: production always passes Some(&meta.pres) (confirm_run/phases.rs:174), so the changed no-pres branch only runs in unit tests or on a corrupt short pres. The production path performs the same; tx_to_apply drops a redundant 32-byte compare per input.
Inline: error-type mismatch plus stale comments in assemble_tx_value_out, a dead branch left in bip34_height_script, assert messages that read backwards, and a coinbase test that can't fail.
Optional, existing code outside this diff: phases.rs:190 checks meta.pres.len() == block.txdata.len() only after assemble_block_prevouts. A short pres uses the no-pres path for the extra txs before the corrupt-store error fires. Moving that check above the call means the fallback never runs in production.
Checked and fine: the over-budget ping test. V2SessionReader is cancel-safe (state lives on self.state), and over_budget is recomputed every 50ms heartbeat, so the 200ms timeout can't tear a frame. The getblocktxn depth 10/11 boundary matches peer.rs:3344.
🤖 Generated with Claude Code
| return Err(ConsensusError::BadTx("negative output")); | ||
| let sats_u = o.value.to_sat(); | ||
| if exceeds_max_money(sats_u) { | ||
| return Err(ConsensusError::BadTx("bad-txns-vout-toolarge")); |
There was a problem hiding this comment.
The structure gate rejects the same condition as BadBlock("bad-txns-vout-toolarge") (line 245). This branch returns BadTx, so the two paths give different reject types for the same input. Suggest BadBlock to match.
This also makes two comments stale: line 241 ("Only money-range gate") and the exceeds_max_money doc ("That cast is not a second range check"). Both need updating now that this branch range-checks too.
| super::assemble_tx_value_out(&one(max_money), 0, None).unwrap(), | ||
| max_money as i64 | ||
| ); | ||
| assert!(super::assemble_tx_value_out(&one(max_money + 1), 0, None).is_err()); |
There was a problem hiding this comment.
is_err() would also pass on the old "negative output" / overflow errors. Suggest matches!(.., Err(ConsensusError::BadBlock("bad-txns-vout-toolarge"))) (or whatever variant line 1469 settles on), so the reject reason is pinned too.
| num.push(0x00); | ||
| } | ||
| } else { | ||
| num.push(0); |
There was a problem hiding this comment.
With the negative path gone this else is dead: n >= 17 here, so num is never empty. That's a fresh unkillable mutant in a PR that's killing them. abs / as i64 aren't needed anymore either. Possible form: loop on the u32, then if num.last().unwrap() & 0x80 != 0 { num.push(0) }.
| assert_eq!(tx_invs(&mut eq_ann), vec![relayed.compute_wtxid()]); | ||
| assert!( | ||
| hi_ann.try_recv().is_err(), | ||
| "a fee above the filter is not announced" |
There was a problem hiding this comment.
The message reads backwards. The peer's filter is rate + 1, so it's the filter that sits above the fee ("a filter above the fee is not announced"). The same goes for lines 376 and 389.
| }; | ||
| let apply = tx_to_apply(&non_cb, non_cb.compute_txid().to_byte_array()).unwrap(); | ||
| assert_eq!(apply.inputs[0].prev_index, 3); | ||
| // A zero txid with a real vout is not a coinbase. `OutPoint::is_null` |
There was a problem hiding this comment.
The removed clause (txid == 0 && vout == MAX) was exactly OutPoint::is_null(), so the deletion changes no behaviour and this case passes on both versions. The deletion is right (the original mutant was equivalent), but this test doesn't pin anything. Optional: drop it.
Fee-filter equality, getblocktxn depth 10, txid notfound, and the send-budget read pause now fail if the comparison flips. Dead BIP34 negative-height encoding and the redundant coinbase clause are gone. Co-authored-by: Cursor <cursoragent@cursor.com>
An over-max output with no precompute row now fails as bad-txns-vout-toolarge, the same block error as the structure gate. The BIP34 height encoder no longer keeps a dead empty-body branch. Co-authored-by: Cursor <cursoragent@cursor.com>
a4e10f6 to
9ea1e67
Compare
test: pin the misses from the two nights after #975
Summary
getblocktxndepth 10, txidnotfound, the send-budget read pause, and the comparison sites in BIP68, median time, prevout lookup, script jobs, and IBD batch meters.OutPoint::is_null. The no-precompute value sum uses the money-range check.Test plan
cargo test -p rbitcoin-consensus --lib -- --quietrbitcoin-nettests for the fee-filter journey,getblocktxndepth, txidnotfound, and the over-budget read pausefmt,clippy -D warnings,cargo deny,ast-grep,cargo test --workspace,ci-os-smoke)qc,test,windows,macos,coverageMade with Cursor