Skip to content

Commit

Permalink
Fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
ninegua committed Dec 20, 2024
1 parent fb0fe54 commit fa0e609
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 84 deletions.
31 changes: 16 additions & 15 deletions rs/bitcoin/ckbtc/minter/src/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
);
}
Expand All @@ -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)
);
}
Expand Down
134 changes: 65 additions & 69 deletions rs/bitcoin/ckbtc/minter/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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 {
Expand All @@ -76,64 +75,51 @@ 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()
}

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()
Expand All @@ -142,16 +128,16 @@ 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(),
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(),
Expand All @@ -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()
Expand All @@ -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(),
Expand Down Expand Up @@ -625,18 +611,23 @@ proptest! {
outputs in pvec(arb_tx_out(), 1..20),
lock_time in any::<u32>(),
) {
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::<u8>::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]
Expand Down Expand Up @@ -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::<u8>::new();
Expand All @@ -674,12 +665,12 @@ proptest! {

let mut btc_buf = Vec::<u8>::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));
}
}
Expand All @@ -690,18 +681,23 @@ proptest! {
outputs in pvec(arb_tx_out(), 1..20),
lock_time in any::<u32>(),
) {
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::<u8>::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());
}

Expand Down Expand Up @@ -1005,7 +1001,7 @@ proptest! {
fn btc_address_parsing_model(mut pkbytes in pvec(any::<u8>(), 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());

Expand All @@ -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)
Expand All @@ -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());
}
}

Expand Down

0 comments on commit fa0e609

Please sign in to comment.