From fa0e6099d6e4da48f798b956947dac77358af80e Mon Sep 17 00:00:00 2001 From: "Paul H. Liu" Date: Thu, 19 Dec 2024 23:47:33 -0800 Subject: [PATCH] Fix tests --- rs/bitcoin/ckbtc/minter/src/address.rs | 31 +++--- rs/bitcoin/ckbtc/minter/src/tests.rs | 134 ++++++++++++------------- 2 files changed, 81 insertions(+), 84 deletions(-) diff --git a/rs/bitcoin/ckbtc/minter/src/address.rs b/rs/bitcoin/ckbtc/minter/src/address.rs index d503545900c..e35abe72962 100644 --- a/rs/bitcoin/ckbtc/minter/src/address.rs +++ b/rs/bitcoin/ckbtc/minter/src/address.rs @@ -446,7 +446,6 @@ mod tests { #[test] fn test_check_address() { use crate::address::ParseAddressError::BadWitnessLength; - use bitcoin::util::address::Payload; use bitcoin::Address; use std::str::FromStr; @@ -480,14 +479,15 @@ mod tests { "bc1q088j3hnr0htc8fjwhk337aply0w3fwj33a56fqkdqfpq8dupgx6q4l0e39", ]; for p2wsh_address in valid_p2wsh_addresses { - let expected_p2wsh_pkhash = match Address::from_str(p2wsh_address).unwrap().payload { - Payload::WitnessProgram { program, .. } => program, - _ => panic!("expected P2WSH address"), - }; + let expected_p2wsh_pkhash = Address::from_str(p2wsh_address) + .unwrap() + .assume_checked() + .witness_program() + .unwrap(); + let mut bytes = [0_u8; 32]; + bytes.copy_from_slice(expected_p2wsh_pkhash.program().as_bytes()); assert_eq!( - Ok(BitcoinAddress::P2wshV0( - expected_p2wsh_pkhash.try_into().unwrap() - )), + Ok(BitcoinAddress::P2wshV0(bytes)), BitcoinAddress::parse(p2wsh_address, Network::Mainnet) ); } @@ -504,14 +504,15 @@ mod tests { ]; for taproot_address in taproot_addresses { - let expected_taproot_pkhash = match Address::from_str(taproot_address).unwrap().payload - { - Payload::WitnessProgram { program, .. } => program, - _ => panic!("expected taproot address"), - }; - let expected_taproot_pkhash = expected_taproot_pkhash.try_into().unwrap(); + let expected_taproot_pkhash = Address::from_str(taproot_address) + .unwrap() + .assume_checked() + .witness_program() + .unwrap(); + let mut bytes = [0_u8; 32]; + bytes.copy_from_slice(expected_taproot_pkhash.program().as_bytes()); assert_eq!( - Ok(BitcoinAddress::P2trV1(expected_taproot_pkhash)), + Ok(BitcoinAddress::P2trV1(bytes)), BitcoinAddress::parse(taproot_address, Network::Mainnet) ); } diff --git a/rs/bitcoin/ckbtc/minter/src/tests.rs b/rs/bitcoin/ckbtc/minter/src/tests.rs index e492584e597..21ad6be500b 100644 --- a/rs/bitcoin/ckbtc/minter/src/tests.rs +++ b/rs/bitcoin/ckbtc/minter/src/tests.rs @@ -11,8 +11,7 @@ use crate::{ SubmittedBtcTransaction, }, }; -use bitcoin::network::constants::Network as BtcNetwork; -use bitcoin::util::psbt::serialize::{Deserialize, Serialize}; +use bitcoin::{hashes::Hash, network::Network as BtcNetwork}; use candid::Principal; use ic_base_types::{CanisterId, PrincipalId}; use ic_btc_interface::{Network, OutPoint, Satoshi, Txid, Utxo}; @@ -61,10 +60,10 @@ fn dummy_utxo_from_value(v: u64) -> Utxo { } } -fn address_to_script_pubkey(address: &BitcoinAddress) -> bitcoin::Script { +fn address_to_script_pubkey(address: &BitcoinAddress) -> bitcoin::ScriptBuf { let address_string = address.display(Network::Mainnet); let btc_address = bitcoin::Address::from_str(&address_string).unwrap(); - btc_address.script_pubkey() + btc_address.assume_checked().script_pubkey() } fn network_to_btc_network(network: Network) -> BtcNetwork { @@ -76,55 +75,42 @@ fn network_to_btc_network(network: Network) -> BtcNetwork { } fn address_to_btc_address(address: &BitcoinAddress, network: Network) -> bitcoin::Address { - use bitcoin::util::address::{Payload, WitnessVersion}; + use bitcoin::{WitnessProgram, WitnessVersion}; match address { - BitcoinAddress::P2wpkhV0(pkhash) => bitcoin::Address { - payload: Payload::WitnessProgram { - version: WitnessVersion::V0, - program: pkhash.to_vec(), - }, - network: network_to_btc_network(network), - }, - BitcoinAddress::P2wshV0(script_hash) => bitcoin::Address { - payload: Payload::WitnessProgram { - version: WitnessVersion::V0, - program: script_hash.to_vec(), - }, - network: network_to_btc_network(network), - }, - BitcoinAddress::P2pkh(pkhash) => bitcoin::Address { - payload: Payload::PubkeyHash(bitcoin::PubkeyHash::from_hash( - bitcoin::hashes::Hash::from_slice(pkhash).unwrap(), - )), - network: network_to_btc_network(network), - }, - BitcoinAddress::P2sh(script_hash) => bitcoin::Address { - payload: Payload::ScriptHash(bitcoin::ScriptHash::from_hash( - bitcoin::hashes::Hash::from_slice(script_hash).unwrap(), - )), - network: network_to_btc_network(network), - }, - BitcoinAddress::P2trV1(pkhash) => bitcoin::Address { - payload: Payload::WitnessProgram { - version: WitnessVersion::V1, - program: pkhash.to_vec(), - }, - network: network_to_btc_network(network), - }, + BitcoinAddress::P2wpkhV0(pkhash) => bitcoin::Address::from_witness_program( + WitnessProgram::new(WitnessVersion::V0, pkhash.as_slice()).unwrap(), + network_to_btc_network(network), + ), + BitcoinAddress::P2wshV0(script_hash) => bitcoin::Address::from_witness_program( + WitnessProgram::new(WitnessVersion::V0, script_hash.as_slice()).unwrap(), + network_to_btc_network(network), + ), + BitcoinAddress::P2pkh(pkhash) => bitcoin::Address::p2pkh( + bitcoin::PubkeyHash::from_slice(pkhash).unwrap(), + network_to_btc_network(network), + ), + BitcoinAddress::P2sh(script_hash) => bitcoin::Address::p2sh_from_hash( + bitcoin::ScriptHash::from_slice(script_hash).unwrap(), + network_to_btc_network(network), + ), + BitcoinAddress::P2trV1(pkhash) => bitcoin::Address::from_witness_program( + WitnessProgram::new(WitnessVersion::V1, pkhash.as_slice()).unwrap(), + network_to_btc_network(network), + ), } } fn as_txid(hash: &[u8; 32]) -> bitcoin::Txid { - bitcoin::Txid::from_hash(bitcoin::hashes::Hash::from_slice(hash).unwrap()) + bitcoin::Txid::from_slice(hash).unwrap() } -fn p2wpkh_script_code(pkhash: &[u8; 20]) -> bitcoin::Script { +fn p2wpkh_script_code(pkhash: &[u8; 20]) -> bitcoin::ScriptBuf { use bitcoin::blockdata::{opcodes, script::Builder}; Builder::new() .push_opcode(opcodes::all::OP_DUP) .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&pkhash[..]) + .push_slice(pkhash) .push_opcode(opcodes::all::OP_EQUALVERIFY) .push_opcode(opcodes::all::OP_CHECKSIG) .into_script() @@ -132,8 +118,8 @@ fn p2wpkh_script_code(pkhash: &[u8; 20]) -> bitcoin::Script { fn unsigned_tx_to_bitcoin_tx(tx: &tx::UnsignedTransaction) -> bitcoin::Transaction { bitcoin::Transaction { - version: tx::TX_VERSION as i32, - lock_time: tx.lock_time, + version: bitcoin::transaction::Version(tx::TX_VERSION as i32), + lock_time: bitcoin::absolute::LockTime::from_consensus(tx.lock_time), input: tx .inputs .iter() @@ -142,8 +128,8 @@ fn unsigned_tx_to_bitcoin_tx(tx: &tx::UnsignedTransaction) -> bitcoin::Transacti txid: as_txid(&txin.previous_output.txid.into()), vout: txin.previous_output.vout, }, - sequence: txin.sequence, - script_sig: bitcoin::Script::default(), + sequence: bitcoin::Sequence(txin.sequence), + script_sig: bitcoin::ScriptBuf::default(), witness: bitcoin::Witness::default(), }) .collect(), @@ -151,7 +137,7 @@ fn unsigned_tx_to_bitcoin_tx(tx: &tx::UnsignedTransaction) -> bitcoin::Transacti .outputs .iter() .map(|txout| bitcoin::TxOut { - value: txout.value, + value: bitcoin::Amount::from_sat(txout.value), script_pubkey: address_to_script_pubkey(&txout.address), }) .collect(), @@ -160,8 +146,8 @@ fn unsigned_tx_to_bitcoin_tx(tx: &tx::UnsignedTransaction) -> bitcoin::Transacti fn signed_tx_to_bitcoin_tx(tx: &tx::SignedTransaction) -> bitcoin::Transaction { bitcoin::Transaction { - version: tx::TX_VERSION as i32, - lock_time: tx.lock_time, + version: bitcoin::transaction::Version(tx::TX_VERSION as i32), + lock_time: bitcoin::absolute::LockTime::from_consensus(tx.lock_time), input: tx .inputs .iter() @@ -170,19 +156,19 @@ fn signed_tx_to_bitcoin_tx(tx: &tx::SignedTransaction) -> bitcoin::Transaction { txid: as_txid(&txin.previous_output.txid.into()), vout: txin.previous_output.vout, }, - sequence: txin.sequence, - script_sig: bitcoin::Script::default(), - witness: bitcoin::Witness::from_vec(vec![ - txin.signature.as_slice().to_vec(), - txin.pubkey.to_vec(), - ]), + sequence: bitcoin::Sequence(txin.sequence), + script_sig: bitcoin::ScriptBuf::default(), + witness: bitcoin::Witness::p2wpkh( + &bitcoin::ecdsa::Signature::from_slice(txin.signature.as_slice()).unwrap(), + &bitcoin::secp256k1::PublicKey::from_slice(txin.pubkey.as_ref()).unwrap(), + ), }) .collect(), output: tx .outputs .iter() .map(|txout| bitcoin::TxOut { - value: txout.value, + value: bitcoin::Amount::from_sat(txout.value), script_pubkey: address_to_script_pubkey(&txout.address), }) .collect(), @@ -625,18 +611,23 @@ proptest! { outputs in pvec(arb_tx_out(), 1..20), lock_time in any::(), ) { + use bitcoin::consensus::{Decodable, Encodable}; let arb_tx = tx::UnsignedTransaction { inputs, outputs, lock_time }; println!("{:?}", arb_tx); let btc_tx = unsigned_tx_to_bitcoin_tx(&arb_tx); - println!("{:?}", btc_tx.serialize()); + let mut btc_tx_bytes = Vec::new(); + btc_tx.consensus_encode(&mut btc_tx_bytes).unwrap(); + println!("{:?}", btc_tx_bytes); let tx_bytes = tx::encode_into(&arb_tx, Vec::::new()); println!("{:?}", tx_bytes); - let decoded_btc_tx = bitcoin::Transaction::deserialize(&tx_bytes).expect("failed to deserialize an unsigned transaction"); + let decoded_btc_tx = bitcoin::Transaction::consensus_decode(&mut (&tx_bytes as &[u8])).expect("failed to deserialize an unsigned transaction"); - prop_assert_eq!(btc_tx.serialize(), tx_bytes); + prop_assert_eq!(btc_tx_bytes, tx_bytes); prop_assert_eq!(&decoded_btc_tx, &btc_tx); - prop_assert_eq!(&arb_tx.txid().as_ref().to_vec(), &*btc_tx.txid()); + let arb_tx_txid = arb_tx.txid(); + let btc_tx_txid = btc_tx.compute_txid(); + prop_assert_eq!(arb_tx_txid.as_ref(), btc_tx_txid.as_ref() as &[u8]); } #[test] @@ -664,7 +655,7 @@ proptest! { let btc_tx = unsigned_tx_to_bitcoin_tx(&arb_tx); let sighasher = tx::TxSigHasher::new(&arb_tx); - let mut btc_sighasher = bitcoin::util::sighash::SighashCache::new(&btc_tx); + let mut btc_sighasher = bitcoin::sighash::SighashCache::new(&btc_tx); for (i, (utxo, _, pubkey)) in inputs_data.iter().enumerate() { let mut buf = Vec::::new(); @@ -674,12 +665,12 @@ proptest! { let mut btc_buf = Vec::::new(); let script_code = p2wpkh_script_code(&pkhash); - btc_sighasher.segwit_encode_signing_data_to(&mut btc_buf, i, &script_code, utxo.value, bitcoin::EcdsaSighashType::All) + btc_sighasher.segwit_v0_encode_signing_data_to(&mut btc_buf, i, &script_code, bitcoin::Amount::from_sat(utxo.value), bitcoin::EcdsaSighashType::All) .expect("failed to encode sighash data"); prop_assert_eq!(hex::encode(&buf), hex::encode(&btc_buf)); let sighash = sighasher.sighash(&arb_tx.inputs[i], &pkhash); - let btc_sighash = btc_sighasher.segwit_signature_hash(i, &script_code, utxo.value, bitcoin::EcdsaSighashType::All).unwrap(); + let btc_sighash = btc_sighasher.p2wpkh_signature_hash(i, &script_code, bitcoin::Amount::from_sat(utxo.value), bitcoin::EcdsaSighashType::All).unwrap(); prop_assert_eq!(hex::encode(sighash), hex::encode(btc_sighash)); } } @@ -690,18 +681,23 @@ proptest! { outputs in pvec(arb_tx_out(), 1..20), lock_time in any::(), ) { + use bitcoin::consensus::{Decodable, Encodable}; let arb_tx = tx::SignedTransaction { inputs, outputs, lock_time }; println!("{:?}", arb_tx); let btc_tx = signed_tx_to_bitcoin_tx(&arb_tx); - println!("{:?}", btc_tx.serialize()); + let mut btc_tx_bytes = Vec::new(); + btc_tx.consensus_encode(&mut btc_tx_bytes).unwrap(); + println!("{:?}", btc_tx_bytes); let tx_bytes = tx::encode_into(&arb_tx, Vec::::new()); println!("{:?}", tx_bytes); - let decoded_btc_tx = bitcoin::Transaction::deserialize(&tx_bytes).expect("failed to deserialize a signed transaction"); + let decoded_btc_tx = bitcoin::Transaction::consensus_decode(&mut (&tx_bytes as &[u8])).expect("failed to deserialize an unsigned transaction"); - prop_assert_eq!(btc_tx.serialize(), tx_bytes); + prop_assert_eq!(btc_tx_bytes, tx_bytes); prop_assert_eq!(&decoded_btc_tx, &btc_tx); - prop_assert_eq!(&arb_tx.wtxid(), &*btc_tx.wtxid()); + let arb_tx_txid = arb_tx.wtxid(); + let btc_tx_txid = btc_tx.compute_wtxid(); + prop_assert_eq!(arb_tx_txid.as_ref() as &[u8], btc_tx_txid.as_ref() as &[u8]); prop_assert_eq!(arb_tx.vsize(), btc_tx.vsize()); } @@ -1005,7 +1001,7 @@ proptest! { fn btc_address_parsing_model(mut pkbytes in pvec(any::(), 32)) { pkbytes.insert(0, 0x02); - let pk_result = bitcoin::PublicKey::from_slice(&pkbytes); + let pk_result = bitcoin::CompressedPublicKey::from_slice(&pkbytes); prop_assume!(pk_result.is_ok()); @@ -1020,7 +1016,7 @@ proptest! { BitcoinAddress::parse(&btc_addr.to_string(), *network) ); - let btc_addr = bitcoin::Address::p2wpkh(&pk, btc_net).unwrap(); + let btc_addr = bitcoin::Address::p2wpkh(&pk, btc_net); prop_assert_eq!( Ok(BitcoinAddress::P2wpkhV0(pkhash)), BitcoinAddress::parse(&btc_addr.to_string(), *network) @@ -1033,7 +1029,7 @@ proptest! { for network in [Network::Mainnet, Network::Testnet].iter() { let addr_str = address.display(*network); let btc_addr = address_to_btc_address(&address, *network); - prop_assert_eq!(btc_addr, bitcoin::Address::from_str(&addr_str).unwrap()); + prop_assert_eq!(btc_addr, bitcoin::Address::from_str(&addr_str).unwrap().assume_checked()); } }