Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog.d/core-edge-pins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added

- **Consensus tests pin retarget compact form, exception-block script execution, the anchored script skip, and several block and script edges against Bitcoin Core.**
61 changes: 61 additions & 0 deletions crates/rbitcoin-consensus/src/block/finality_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -341,3 +341,64 @@ fn structural_bip68_height_lock_skips_missing_coin_mtp() {
super::structural_bip68(&query, &block, &ctx, &spends, &create_heights, &mut cache)
.expect("height-type lock must not read the coin median");
}

/// BIP68 walks `txdata[1..]`. A coinbase whose relative lock would fail still connects.
#[test]
fn bip68_skips_a_coinbase_whose_relative_lock_would_fail() {
use crate::{accept_and_connect_block, prepare_regtest_candidate, ConsensusError};

let coinbase = bare_tx(2, LockTime::ZERO, Sequence::from_consensus(200));
assert!(
!sequence_locks_satisfied(&coinbase, &[], &[], 1, 0),
"the same lock fails closed when the coinbase is treated as a normal tx"
);

let (_dir, q) = rbitcoin_query::testutil::tiny_query_labeled("bip68-coinbase");
let params = crate::params::ChainParams::regtest();
let genesis = bitcoin::blockdata::constants::genesis_block(bitcoin::Network::Regtest);
accept_and_connect_block(
&q,
&params,
rbitcoin_primitives::Height::GENESIS,
&genesis,
crate::Milestone::NONE,
)
.unwrap();
let mut block = crate::mine_empty_regtest(genesis.block_hash(), genesis.header.time + 600, 1);
block.txdata[0].version = bitcoin::transaction::Version::TWO;
block.txdata[0].input[0].sequence = Sequence::from_consensus(200);
prepare_regtest_candidate(&mut block, genesis.block_hash(), genesis.header.time + 600);
accept_and_connect_block(
&q,
&params,
rbitcoin_primitives::Height(1),
&block,
crate::Milestone::NONE,
)
.expect("coinbase sequence is not a BIP68 input");
assert_eq!(q.tip_height(), Some(rbitcoin_primitives::Height(1)));

let params = Box::leak(Box::new(crate::params::ChainParams::regtest()));
let ctx = super::ValidationContext::at(
params,
rbitcoin_primitives::Height(6),
crate::milestone::Milestone::NONE,
);
let (_dir, query) = rbitcoin_query::testutil::tiny_query_labeled("bip68-noncb");
let create = rbitcoin_primitives::Fk(3);
let mut create_heights = rbitcoin_query::FkMap::default();
create_heights.insert(create, 5);
let block = csv_block(vec![
bare_tx(1, LockTime::ZERO, Sequence::MAX),
bare_tx(2, LockTime::ZERO, Sequence::from_consensus(200)),
]);
let spends = [([0u8; 32], 0u32, rbitcoin_primitives::Fk::NULL, create, 0u32)];
let mut cache = rbitcoin_query::U32Map::default();
cache.insert(5, 1_500_000);
let err = super::structural_bip68(&query, &block, &ctx, &spends, &create_heights, &mut cache)
.expect_err("the same lock rejects a non-coinbase");
assert!(
matches!(err, ConsensusError::BadTx(s) if s.contains("nonfinal")),
"{err:?}"
);
}
41 changes: 41 additions & 0 deletions crates/rbitcoin-consensus/src/block/sigop_cost_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,47 @@ fn witness_p2wpkh_counts_one() {
assert_eq!(witness_sigop_count(&tx, &spks(&prevouts)), 1);
}

/// Empty P2WSH has no witness script to count. A v1 program is not P2WPKH or P2WSH.
#[test]
fn witness_empty_p2wsh_and_v1_program_cost_zero() {
let spend = |spk: Vec<u8>| {
let prevouts = vec![TxOut {
value: Amount::from_sat(10),
script_pubkey: ScriptBuf::from_bytes(spk),
}];
let tx = Transaction {
version: TxVersion::TWO,
lock_time: LockTime::ZERO,
input: vec![TxIn {
previous_output: OutPoint {
txid: Txid::from_byte_array([5; 32]),
vout: 0,
},
script_sig: ScriptBuf::new(),
sequence: Sequence::MAX,
witness: Witness::new(),
}],
output: vec![TxOut {
value: Amount::from_sat(1),
script_pubkey: ScriptBuf::from_bytes(vec![0x51]),
}],
};
(tx, prevouts)
};

let mut p2wsh = vec![0x00, 0x20];
p2wsh.extend([0u8; 32]);
let (tx, prevouts) = spend(p2wsh);
assert_eq!(witness_sigop_count(&tx, &spks(&prevouts)), 0);
assert_eq!(tx_sigop_cost(&tx, &spks(&prevouts), true, true), 0);

let mut v1 = vec![0x51, 0x20];
v1.extend([0xab; 32]);
let (tx, prevouts) = spend(v1);
assert_eq!(witness_sigop_count(&tx, &spks(&prevouts)), 0);
assert_eq!(tx_sigop_cost(&tx, &spks(&prevouts), true, true), 0);
}

#[test]
fn witness_sigops_gated_on_witness_flag() {
let mut spk = vec![0x00, 0x14];
Expand Down
Loading
Loading