400 lines
14 KiB
Rust
400 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 = ScriptBuf::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::bip32::{ChildNumber, KeySource, Xpriv, Xpub};
|
|
use bitcoin::blockdata::locktime::{absolute, relative};
|
|
use bitcoin::blockdata::witness::Witness;
|
|
use bitcoin::consensus::encode::deserialize;
|
|
use bitcoin::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
|
use bitcoin::hex::FromHex;
|
|
use bitcoin::psbt::raw::{self, Key, Pair, ProprietaryKey};
|
|
use bitcoin::psbt::{Input, Output, Psbt, PsbtSighashType};
|
|
use bitcoin::sighash::{EcdsaSighashType, TapSighashType};
|
|
use bitcoin::taproot::{self, ControlBlock, LeafVersion, TapTree, TaprootBuilder};
|
|
use bitcoin::{
|
|
ecdsa, transaction, Address, Amount, Block, NetworkKind, OutPoint, PrivateKey, PublicKey,
|
|
ScriptBuf, Sequence, Target, Transaction, TxIn, TxOut, Txid, Work,
|
|
};
|
|
|
|
/// 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();
|
|
let want = include_bytes!("data/serde/block_bincode");
|
|
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 = ScriptBuf::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: Amount::from_sat(0xDEADBEEFCAFEBABE),
|
|
script_pubkey: ScriptBuf::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_slice(&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, NetworkKind::Main);
|
|
|
|
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 = Xpriv::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 = Xpub::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 = ecdsa::Signature {
|
|
signature: secp256k1::ecdsa::Signature::from_str(s.trim()).unwrap(),
|
|
sighash_type: 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::decode(&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: transaction::Version::ONE,
|
|
lock_time: absolute::LockTime::ZERO,
|
|
input: vec![TxIn {
|
|
previous_output: OutPoint {
|
|
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389"
|
|
.parse::<Txid>()
|
|
.unwrap(),
|
|
vout: 1,
|
|
},
|
|
script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985")
|
|
.unwrap(),
|
|
sequence: Sequence::from_consensus(4294967295),
|
|
witness: Witness::from_slice(&[Vec::from_hex(
|
|
"03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105",
|
|
)
|
|
.unwrap()]),
|
|
}],
|
|
output: vec![TxOut {
|
|
value: Amount::from_sat(190_303_501_938),
|
|
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587")
|
|
.unwrap(),
|
|
}],
|
|
};
|
|
let unknown: BTreeMap<raw::Key, Vec<u8>> =
|
|
vec![(raw::Key { type_value: 9, key: vec![0, 1] }, vec![3, 4, 5])].into_iter().collect();
|
|
let key_source = ("deadbeef".parse().unwrap(), "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 = Xpub::from_str(s.trim()).unwrap();
|
|
vec![(xpub, key_source)].into_iter().collect()
|
|
},
|
|
unsigned_tx: {
|
|
let mut unsigned = tx.clone();
|
|
unsigned.input[0].script_sig = ScriptBuf::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: Amount::from_sat(190_303_501_938),
|
|
script_pubkey: ScriptBuf::from_hex("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_slice(&[vec![1, 3], vec![5]])),
|
|
ripemd160_preimages: vec![(ripemd160::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(),
|
|
sha256_preimages: vec![(sha256::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(),
|
|
hash160_preimages: vec![(hash160::Hash::hash(&[1, 2]), vec![1, 2])].into_iter().collect(),
|
|
hash256_preimages: vec![(sha256d::Hash::hash(&[1, 2]), 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()
|
|
}],
|
|
};
|
|
|
|
// Sanity, check we can roundtrip BIP-174 serialize.
|
|
let serialized = psbt.serialize();
|
|
Psbt::deserialize(&serialized).unwrap();
|
|
|
|
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_taproot_sig() {
|
|
let s = include_str!("data/serde/taproot_sig_hex");
|
|
let sig = taproot::Signature {
|
|
signature: secp256k1::schnorr::Signature::from_str(s.trim()).unwrap(),
|
|
sighash_type: TapSighashType::All,
|
|
};
|
|
|
|
let got = serialize(&sig).unwrap();
|
|
let want = include_bytes!("data/serde/taproot_sig_bincode") as &[_];
|
|
assert_eq!(got, want)
|
|
}
|
|
|
|
#[test]
|
|
fn serde_regression_taptree() {
|
|
let ver = LeafVersion::from_consensus(0).unwrap();
|
|
let script = ScriptBuf::from(vec![0u8, 1u8, 2u8]);
|
|
let mut builder = TaprootBuilder::new().add_leaf_with_ver(1, script.clone(), ver).unwrap();
|
|
builder = builder.add_leaf(1, script).unwrap();
|
|
let tree = TapTree::try_from(builder).unwrap();
|
|
|
|
let got = serialize(&tree).unwrap();
|
|
let want = include_bytes!("data/serde/taptree_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)
|
|
}
|