419 lines
14 KiB
Rust
419 lines
14 KiB
Rust
//! Regression tests for _most_ types that implement `serde::Serialize`.
|
|
//!
|
|
//! For remaining types see: ./serde_opcodes.rs
|
|
//!
|
|
//! If you find a type defined in `rust-bitcoin` that implements `Serialize` and does _not_ have a
|
|
//! regression test please add it.
|
|
//!
|
|
//! Types/tests were found using, and are ordered by, the output of: `git grep -l Serialize`.
|
|
//!
|
|
|
|
// In tests below `deserialize` is consensus deserialize while `serialize` is serde serialize, that
|
|
// is why we have two different serialized data files for tests that use binary serialized input.
|
|
//
|
|
// To create a file with the expected serialized data do something like:
|
|
//
|
|
// use std::fs::File;
|
|
// use std::io::Write;
|
|
// let script = Script::from(vec![0u8, 1u8, 2u8]);
|
|
// let got = serialize(&script).unwrap();
|
|
// let mut file = File::create("/tmp/script_bincode").unwrap();
|
|
// file.write_all(&got).unwrap();
|
|
|
|
#![cfg(feature = "serde")]
|
|
|
|
use std::collections::BTreeMap;
|
|
use std::str::FromStr;
|
|
|
|
use bincode::serialize;
|
|
use bitcoin::blockdata::locktime::{absolute, relative};
|
|
use bitcoin::blockdata::witness::Witness;
|
|
use bitcoin::consensus::encode::deserialize;
|
|
use bitcoin::hashes::hex::FromHex;
|
|
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
|
use bitcoin::sighash::{EcdsaSighashType, SchnorrSighashType};
|
|
use bitcoin::util::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, KeySource};
|
|
use bitcoin::util::psbt::raw::{self, Key, Pair, ProprietaryKey};
|
|
use bitcoin::util::psbt::{Input, Output, Psbt, PsbtSighashType};
|
|
use bitcoin::util::schnorr::UntweakedPublicKey;
|
|
use bitcoin::util::taproot::{ControlBlock, LeafVersion, TaprootBuilder, TaprootSpendInfo};
|
|
use bitcoin::{
|
|
Address, Block, EcdsaSig, Network, OutPoint, PrivateKey, PublicKey, SchnorrSig, Script,
|
|
Sequence, Target, Transaction, TxIn, TxOut, Txid, Work,
|
|
};
|
|
use secp256k1::Secp256k1;
|
|
|
|
/// Implicitly does regression test for `BlockHeader` also.
|
|
#[test]
|
|
fn serde_regression_block() {
|
|
let segwit = include_bytes!(
|
|
"data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw"
|
|
);
|
|
let block: Block = deserialize(segwit).unwrap();
|
|
let got = serialize(&block).unwrap();
|
|
// The cast is required because Rust 1.41.1 throws the following error without it:
|
|
// the trait `std::array::LengthAtMost32` is not implemented for `[u8; 5123]`
|
|
let want = include_bytes!("data/serde/block_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_absolute_lock_time_height() {
|
|
let t = absolute::LockTime::from_height(741521).expect("valid height");
|
|
let got = serialize(&t).unwrap();
|
|
let want = include_bytes!("data/serde/absolute_lock_time_blocks_bincode") as &[_];
|
|
assert_eq!(got, want);
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_absolute_lock_time_time() {
|
|
let seconds: u32 = 1653195600; // May 22nd, 5am UTC.
|
|
let t = absolute::LockTime::from_time(seconds).expect("valid time");
|
|
let got = serialize(&t).unwrap();
|
|
|
|
let want = include_bytes!("data/serde/absolute_lock_time_seconds_bincode") as &[_];
|
|
assert_eq!(got, want);
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_relative_lock_time_height() {
|
|
let t = relative::LockTime::from(relative::Height::from(0xCAFE_u16));
|
|
let got = serialize(&t).unwrap();
|
|
|
|
let want = include_bytes!("data/serde/relative_lock_time_blocks_bincode") as &[_];
|
|
assert_eq!(got, want);
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_relative_lock_time_time() {
|
|
let t = relative::LockTime::from(relative::Time::from_512_second_intervals(0xFACE_u16));
|
|
let got = serialize(&t).unwrap();
|
|
|
|
let want = include_bytes!("data/serde/relative_lock_time_seconds_bincode") as &[_];
|
|
assert_eq!(got, want);
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_script() {
|
|
let script = Script::from(vec![0u8, 1u8, 2u8]);
|
|
let got = serialize(&script).unwrap();
|
|
let want = include_bytes!("data/serde/script_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_txin() {
|
|
let ser = include_bytes!("data/serde/txin_ser");
|
|
let txin: TxIn = deserialize(ser).unwrap();
|
|
|
|
let got = serialize(&txin).unwrap();
|
|
let want = include_bytes!("data/serde/txin_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_txout() {
|
|
let txout =
|
|
TxOut { value: 0xDEADBEEFCAFEBABE, script_pubkey: Script::from(vec![0u8, 1u8, 2u8]) };
|
|
let got = serialize(&txout).unwrap();
|
|
let want = include_bytes!("data/serde/txout_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_transaction() {
|
|
let ser = include_bytes!("data/serde/transaction_ser");
|
|
let tx: Transaction = deserialize(ser).unwrap();
|
|
let got = serialize(&tx).unwrap();
|
|
let want = include_bytes!("data/serde/transaction_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_witness() {
|
|
let w0 = Vec::from_hex("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105")
|
|
.unwrap();
|
|
let w1 = Vec::from_hex("000000").unwrap();
|
|
let vec = vec![w0, w1];
|
|
let witness = Witness::from_vec(vec);
|
|
|
|
let got = serialize(&witness).unwrap();
|
|
let want = include_bytes!("data/serde/witness_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_address() {
|
|
let s = include_str!("data/serde/public_key_hex");
|
|
let pk = PublicKey::from_str(s.trim()).unwrap();
|
|
let addr = Address::p2pkh(&pk, Network::Bitcoin);
|
|
|
|
let got = serialize(&addr).unwrap();
|
|
let want = include_bytes!("data/serde/address_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_extended_priv_key() {
|
|
let s = include_str!("data/serde/extended_priv_key");
|
|
let key = ExtendedPrivKey::from_str(s.trim()).unwrap();
|
|
let got = serialize(&key).unwrap();
|
|
let want = include_bytes!("data/serde/extended_priv_key_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_extended_pub_key() {
|
|
let s = include_str!("data/serde/extended_pub_key");
|
|
let key = ExtendedPubKey::from_str(s.trim()).unwrap();
|
|
let got = serialize(&key).unwrap();
|
|
let want = include_bytes!("data/serde/extended_pub_key_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_ecdsa_sig() {
|
|
let s = include_str!("data/serde/ecdsa_sig_hex");
|
|
let sig = EcdsaSig {
|
|
sig: secp256k1::ecdsa::Signature::from_str(s.trim()).unwrap(),
|
|
hash_ty: EcdsaSighashType::All,
|
|
};
|
|
|
|
let got = serialize(&sig).unwrap();
|
|
let want = include_bytes!("data/serde/ecdsa_sig_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_control_block() {
|
|
let s = include_str!("data/serde/control_block_hex");
|
|
let block = ControlBlock::from_slice(&Vec::<u8>::from_hex(s.trim()).unwrap()).unwrap();
|
|
let got = serialize(&block).unwrap();
|
|
|
|
let want = include_bytes!("data/serde/control_block_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_child_number() {
|
|
let num = ChildNumber::Normal { index: 0xDEADBEEF };
|
|
let got = serialize(&num).unwrap();
|
|
let want = include_bytes!("data/serde/child_number_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_private_key() {
|
|
let sk = PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap();
|
|
let got = serialize(&sk).unwrap();
|
|
let want = include_bytes!("data/serde/private_key_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_public_key() {
|
|
let s = include_str!("data/serde/public_key_hex");
|
|
let pk = PublicKey::from_str(s.trim()).unwrap();
|
|
let got = serialize(&pk).unwrap();
|
|
let want = include_bytes!("data/serde/public_key_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_psbt() {
|
|
let tx = Transaction {
|
|
version: 1,
|
|
lock_time: absolute::PackedLockTime::ZERO,
|
|
input: vec![TxIn {
|
|
previous_output: OutPoint {
|
|
txid: Txid::from_hex(
|
|
"e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389",
|
|
)
|
|
.unwrap(),
|
|
vout: 1,
|
|
},
|
|
script_sig: Script::from_str("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
|
|
sequence: Sequence::from_consensus(4294967295),
|
|
witness: Witness::from_vec(vec![Vec::from_hex(
|
|
"03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105",
|
|
)
|
|
.unwrap()]),
|
|
}],
|
|
output: vec![TxOut {
|
|
value: 190303501938,
|
|
script_pubkey: Script::from_str("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587")
|
|
.unwrap(),
|
|
}],
|
|
};
|
|
let unknown: BTreeMap<raw::Key, Vec<u8>> =
|
|
vec![(raw::Key { type_value: 1, key: vec![0, 1] }, vec![3, 4, 5])].into_iter().collect();
|
|
let key_source = ("deadbeef".parse().unwrap(), "m/0'/1".parse().unwrap());
|
|
let keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = vec![(
|
|
"0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
|
|
key_source.clone(),
|
|
)]
|
|
.into_iter()
|
|
.collect();
|
|
|
|
let proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = vec![(
|
|
raw::ProprietaryKey {
|
|
prefix: "prefx".as_bytes().to_vec(),
|
|
subtype: 42,
|
|
key: "test_key".as_bytes().to_vec(),
|
|
},
|
|
vec![5, 6, 7],
|
|
)]
|
|
.into_iter()
|
|
.collect();
|
|
|
|
let psbt = Psbt {
|
|
version: 0,
|
|
xpub: {
|
|
let s = include_str!("data/serde/extended_pub_key");
|
|
let xpub = ExtendedPubKey::from_str(s.trim()).unwrap();
|
|
vec![(xpub, key_source)].into_iter().collect()
|
|
},
|
|
unsigned_tx: {
|
|
let mut unsigned = tx.clone();
|
|
unsigned.input[0].script_sig = Script::new();
|
|
unsigned.input[0].witness = Witness::default();
|
|
unsigned
|
|
},
|
|
proprietary: proprietary.clone(),
|
|
unknown: unknown.clone(),
|
|
|
|
inputs: vec![Input {
|
|
non_witness_utxo: Some(tx),
|
|
witness_utxo: Some(TxOut {
|
|
value: 190303501938,
|
|
script_pubkey: Script::from_str("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
|
}),
|
|
sighash_type: Some(PsbtSighashType::from(EcdsaSighashType::from_str("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY").unwrap())),
|
|
redeem_script: Some(vec![0x51].into()),
|
|
witness_script: None,
|
|
partial_sigs: vec![(
|
|
"0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
|
|
"304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe701".parse().unwrap(),
|
|
)].into_iter().collect(),
|
|
bip32_derivation: keypaths.clone().into_iter().collect(),
|
|
final_script_witness: Some(Witness::from_vec(vec![vec![1, 3], vec![5]])),
|
|
ripemd160_preimages: vec![(ripemd160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
|
|
sha256_preimages: vec![(sha256::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
|
|
hash160_preimages: vec![(hash160::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
|
|
hash256_preimages: vec![(sha256d::Hash::hash(&[]), vec![1, 2])].into_iter().collect(),
|
|
proprietary: proprietary.clone(),
|
|
unknown: unknown.clone(),
|
|
..Default::default()
|
|
}],
|
|
outputs: vec![Output {
|
|
bip32_derivation: keypaths.into_iter().collect(),
|
|
proprietary,
|
|
unknown,
|
|
..Default::default()
|
|
}],
|
|
};
|
|
|
|
let got = serialize(&psbt).unwrap();
|
|
let want = include_bytes!("data/serde/psbt_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_raw_pair() {
|
|
let pair = Pair {
|
|
key: Key { type_value: 1u8, key: vec![0u8, 1u8, 2u8, 3u8] },
|
|
value: vec![0u8, 1u8, 2u8, 3u8],
|
|
};
|
|
let got = serialize(&pair).unwrap();
|
|
let want = include_bytes!("data/serde/raw_pair_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_proprietary_key() {
|
|
let key = ProprietaryKey {
|
|
prefix: vec![0u8, 1u8, 2u8, 3u8],
|
|
subtype: 1u8,
|
|
key: vec![0u8, 1u8, 2u8, 3u8],
|
|
};
|
|
let got = serialize(&key).unwrap();
|
|
let want = include_bytes!("data/serde/proprietary_key_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_schnorr_sig() {
|
|
let s = include_str!("data/serde/schnorr_sig_hex");
|
|
let sig = SchnorrSig {
|
|
sig: secp256k1::schnorr::Signature::from_str(s.trim()).unwrap(),
|
|
hash_ty: SchnorrSighashType::All,
|
|
};
|
|
|
|
let got = serialize(&sig).unwrap();
|
|
let want = include_bytes!("data/serde/schnorr_sig_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_taproot_builder() {
|
|
let ver = LeafVersion::from_consensus(0).unwrap();
|
|
let script = Script::from(vec![0u8, 1u8, 2u8]);
|
|
let builder = TaprootBuilder::new().add_leaf_with_ver(1, script, ver).unwrap();
|
|
|
|
let got = serialize(&builder).unwrap();
|
|
let want = include_bytes!("data/serde/taproot_builder_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_taproot_spend_info() {
|
|
let secp = Secp256k1::verification_only();
|
|
let internal_key = UntweakedPublicKey::from_str(
|
|
"93c7378d96518a75448821c4f7c8f4bae7ce60f804d03d1f0628dd5dd0f5de51",
|
|
)
|
|
.unwrap();
|
|
|
|
let script_weights = vec![
|
|
(10, Script::from_hex("51").unwrap()), // semantics of script don't matter for this test
|
|
(20, Script::from_hex("52").unwrap()),
|
|
(20, Script::from_hex("53").unwrap()),
|
|
(30, Script::from_hex("54").unwrap()),
|
|
(19, Script::from_hex("55").unwrap()),
|
|
];
|
|
let tree_info =
|
|
TaprootSpendInfo::with_huffman_tree(&secp, internal_key, script_weights).unwrap();
|
|
|
|
let got = serialize(&tree_info).unwrap();
|
|
let want = include_bytes!("data/serde/taproot_spend_info_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
// Used to get a 256 bit integer as a byte array.
|
|
fn le_bytes() -> [u8; 32] {
|
|
let x: u128 = 0xDEAD_BEEF_CAFE_BABE_DEAD_BEEF_CAFE_BABE;
|
|
let y: u128 = 0xCAFE_DEAD_BABE_BEEF_CAFE_DEAD_BABE_BEEF;
|
|
|
|
let mut bytes = [0_u8; 32];
|
|
|
|
bytes[..16].copy_from_slice(&x.to_le_bytes());
|
|
bytes[16..].copy_from_slice(&y.to_le_bytes());
|
|
|
|
bytes
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_work() {
|
|
let work = Work::from_le_bytes(le_bytes());
|
|
let got = serialize(&work).unwrap();
|
|
let want = include_bytes!("data/serde/u256_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_target() {
|
|
let target = Target::from_le_bytes(le_bytes());
|
|
let got = serialize(&target).unwrap();
|
|
let want = include_bytes!("data/serde/u256_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|