Merge rust-bitcoin/rust-bitcoin#935: Add psbt BIP174 test vectors tests
b8bd31d5a8
Promote rust-miniscript finalizer (DanGould)16bf6f68dd
Test PSBT integration (DanGould)6b6ef528a4
Add OP_0 alias for OP_PUSHBYTES_0 (DanGould)72935a0f6e
Move test_data/* tests/data (Tobin Harding) Pull request description: resolves #892 * Initial patch adds OP_0 alias for OP_PUSHBYTES_0 as [approved here](https://github.com/rust-bitcoin/rust-bitcoin/pull/935#discussion_r854539416) * Second patch is the bulk of this work. It tests BIP 174 PSBT integration defined at [The BIP's Test Vectors Section](https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors) using #957 * Third patch points users to rust-miniscript for a more useful finalizer ACKs for top commit: tcharding: ACKb8bd31d5a8
sanket1729: ACKb8bd31d5a8
. Thanks for sticking with this PR. This looks awesome after #957 Tree-SHA512: dc68e524d4349530b082baf5032460fa56593b0ef192125c0b7d7e00954e5593f386b7f1984fc00106b4b9eafbf29cc80ab368dbd26b710eba0962dbd89e0013
This commit is contained in:
commit
21ae79bed4
|
@ -9,7 +9,7 @@ documentation = "https://docs.rs/bitcoin/"
|
||||||
description = "General purpose library for using and interoperating with Bitcoin and other cryptocurrencies."
|
description = "General purpose library for using and interoperating with Bitcoin and other cryptocurrencies."
|
||||||
keywords = [ "crypto", "bitcoin" ]
|
keywords = [ "crypto", "bitcoin" ]
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
exclude = ["test_data/"]
|
exclude = ["tests/"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
# Please don't forget to add relevant features to docs.rs below
|
# Please don't forget to add relevant features to docs.rs below
|
||||||
|
|
|
@ -234,6 +234,7 @@ impl WatchOnly {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finalizes the PSBT, in BIP174 parlance this is the 'Finalizer'.
|
/// Finalizes the PSBT, in BIP174 parlance this is the 'Finalizer'.
|
||||||
|
/// This is just an example. For a production-ready PSBT Finalizer, use [rust-miniscript](https://docs.rs/miniscript/latest/miniscript/psbt/trait.PsbtExt.html#tymethod.finalize)
|
||||||
fn finalize_psbt(&self, mut psbt: Psbt) -> Result<Psbt> {
|
fn finalize_psbt(&self, mut psbt: Psbt) -> Result<Psbt> {
|
||||||
use bitcoin::util::psbt::serialize::Serialize;
|
use bitcoin::util::psbt::serialize::Serialize;
|
||||||
|
|
||||||
|
|
|
@ -564,7 +564,7 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blockfilters() {
|
fn test_blockfilters() {
|
||||||
// test vectors from: https://github.com/jimpo/bitcoin/blob/c7efb652f3543b001b4dd22186a354605b14f47e/src/test/data/blockfilters.json
|
// test vectors from: https://github.com/jimpo/bitcoin/blob/c7efb652f3543b001b4dd22186a354605b14f47e/src/test/data/blockfilters.json
|
||||||
let data = include_str!("../test_data/blockfilters.json");
|
let data = include_str!("../tests/data/blockfilters.json");
|
||||||
|
|
||||||
let testdata = serde_json::from_str::<Value>(data).unwrap().as_array().unwrap().clone();
|
let testdata = serde_json::from_str::<Value>(data).unwrap().as_array().unwrap().clone();
|
||||||
for t in testdata.iter().skip(1) {
|
for t in testdata.iter().skip(1) {
|
||||||
|
|
|
@ -460,7 +460,7 @@ mod tests {
|
||||||
// Check testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b
|
// Check testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b
|
||||||
#[test]
|
#[test]
|
||||||
fn segwit_block_test() {
|
fn segwit_block_test() {
|
||||||
let segwit_block = include_bytes!("../../test_data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw").to_vec();
|
let segwit_block = include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw").to_vec();
|
||||||
|
|
||||||
let decode: Result<Block, _> = deserialize(&segwit_block);
|
let decode: Result<Block, _> = deserialize(&segwit_block);
|
||||||
|
|
||||||
|
@ -564,7 +564,7 @@ mod benches {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn bench_stream_reader(bh: &mut Bencher) {
|
pub fn bench_stream_reader(bh: &mut Bencher) {
|
||||||
let big_block = include_bytes!("../../test_data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
let big_block = include_bytes!("../../tests/data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
||||||
assert_eq!(big_block.len(), 1_381_836);
|
assert_eq!(big_block.len(), 1_381_836);
|
||||||
let big_block = black_box(big_block);
|
let big_block = black_box(big_block);
|
||||||
|
|
||||||
|
@ -577,7 +577,7 @@ mod benches {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn bench_block_serialize(bh: &mut Bencher) {
|
pub fn bench_block_serialize(bh: &mut Bencher) {
|
||||||
let raw_block = include_bytes!("../../test_data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
let raw_block = include_bytes!("../../tests/data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
||||||
|
|
||||||
let block: Block = deserialize(&raw_block[..]).unwrap();
|
let block: Block = deserialize(&raw_block[..]).unwrap();
|
||||||
|
|
||||||
|
@ -592,7 +592,7 @@ mod benches {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn bench_block_serialize_logic(bh: &mut Bencher) {
|
pub fn bench_block_serialize_logic(bh: &mut Bencher) {
|
||||||
let raw_block = include_bytes!("../../test_data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
let raw_block = include_bytes!("../../tests/data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
||||||
|
|
||||||
let block: Block = deserialize(&raw_block[..]).unwrap();
|
let block: Block = deserialize(&raw_block[..]).unwrap();
|
||||||
|
|
||||||
|
@ -604,7 +604,7 @@ mod benches {
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn bench_block_deserialize(bh: &mut Bencher) {
|
pub fn bench_block_deserialize(bh: &mut Bencher) {
|
||||||
let raw_block = include_bytes!("../../test_data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
let raw_block = include_bytes!("../../tests/data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
||||||
|
|
||||||
bh.iter(|| {
|
bh.iter(|| {
|
||||||
let block: Block = deserialize(&raw_block[..]).unwrap();
|
let block: Block = deserialize(&raw_block[..]).unwrap();
|
||||||
|
|
|
@ -755,6 +755,8 @@ impl serde::Serialize for All {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Push an empty array onto the stack.
|
||||||
|
pub static OP_0: All = OP_PUSHBYTES_0;
|
||||||
/// Empty stack is also FALSE.
|
/// Empty stack is also FALSE.
|
||||||
pub static OP_FALSE: All = OP_PUSHBYTES_0;
|
pub static OP_FALSE: All = OP_PUSHBYTES_0;
|
||||||
/// Number 1 is also TRUE.
|
/// Number 1 is also TRUE.
|
||||||
|
|
|
@ -497,7 +497,7 @@ mod test {
|
||||||
// TODO: Impl Rand traits here to easily generate random values.
|
// TODO: Impl Rand traits here to easily generate random values.
|
||||||
let version_msg: VersionMessage = deserialize(&Vec::from_hex("721101000100000000000000e6e0845300000000010000000000000000000000000000000000ffff0000000000000100000000000000fd87d87eeb4364f22cf54dca59412db7208d47d920cffce83ee8102f5361746f7368693a302e392e39392f2c9f040001").unwrap()).unwrap();
|
let version_msg: VersionMessage = deserialize(&Vec::from_hex("721101000100000000000000e6e0845300000000010000000000000000000000000000000000ffff0000000000000100000000000000fd87d87eeb4364f22cf54dca59412db7208d47d920cffce83ee8102f5361746f7368693a302e392e39392f2c9f040001").unwrap()).unwrap();
|
||||||
let tx: Transaction = deserialize(&Vec::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap()).unwrap();
|
let tx: Transaction = deserialize(&Vec::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap()).unwrap();
|
||||||
let block: Block = deserialize(&include_bytes!("../../test_data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw")[..]).unwrap();
|
let block: Block = deserialize(&include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw")[..]).unwrap();
|
||||||
let header: BlockHeader = deserialize(&Vec::from_hex("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b").unwrap()).unwrap();
|
let header: BlockHeader = deserialize(&Vec::from_hex("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b").unwrap()).unwrap();
|
||||||
let script: Script = deserialize(&Vec::from_hex("1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac").unwrap()).unwrap();
|
let script: Script = deserialize(&Vec::from_hex("1976a91431a420903c05a0a7de2de40c9f02ebedbacdc17288ac").unwrap()).unwrap();
|
||||||
let merkle_block: MerkleBlock = deserialize(&Vec::from_hex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101").unwrap()).unwrap();
|
let merkle_block: MerkleBlock = deserialize(&Vec::from_hex("0100000079cda856b143d9db2c1caff01d1aecc8630d30625d10e8b4b8b0000000000000b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f196367291b4d4c86041b8fa45d630100000001b50cc069d6a3e33e3ff84a5c41d9d3febe7c770fdcc96b2c3ff60abe184f19630101").unwrap()).unwrap();
|
||||||
|
|
|
@ -1127,7 +1127,7 @@ mod tests {
|
||||||
// These test vectors were stolen from libbtc, which is Copyright 2014 Jonas Schnelli MIT
|
// These test vectors were stolen from libbtc, which is Copyright 2014 Jonas Schnelli MIT
|
||||||
// They were transformed by replacing {...} with run_test_sighash(...), then the ones containing
|
// They were transformed by replacing {...} with run_test_sighash(...), then the ones containing
|
||||||
// OP_CODESEPARATOR in their pubkeys were removed
|
// OP_CODESEPARATOR in their pubkeys were removed
|
||||||
let data = include_str!("../test_data/legacy_sighash.json");
|
let data = include_str!("../tests/data/legacy_sighash.json");
|
||||||
|
|
||||||
let testdata = serde_json::from_str::<Value>(data).unwrap().as_array().unwrap().clone();
|
let testdata = serde_json::from_str::<Value>(data).unwrap().as_array().unwrap().clone();
|
||||||
for t in testdata.iter().skip(1) {
|
for t in testdata.iter().skip(1) {
|
||||||
|
@ -1479,7 +1479,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bip_341_read_json() -> serde_json::Value {
|
fn bip_341_read_json() -> serde_json::Value {
|
||||||
let json_str = include_str!("../test_data/bip341_tests.json");
|
let json_str = include_str!("../tests/data/bip341_tests.json");
|
||||||
serde_json::from_str(json_str).expect("JSON was not well-formatted")
|
serde_json::from_str(json_str).expect("JSON was not well-formatted")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn both_merkle_root_functions_return_the_same_result() {
|
fn both_merkle_root_functions_return_the_same_result() {
|
||||||
// testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b
|
// testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b
|
||||||
let segwit_block = include_bytes!("../../test_data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw");
|
let segwit_block = include_bytes!("../../tests/data/testnet_block_000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b.raw");
|
||||||
let block: Block = deserialize(&segwit_block[..]).expect("Failed to deserialize block");
|
let block: Block = deserialize(&segwit_block[..]).expect("Failed to deserialize block");
|
||||||
assert!(block.check_merkle_root()); // Sanity check.
|
assert!(block.check_merkle_root()); // Sanity check.
|
||||||
|
|
||||||
|
|
|
@ -1664,9 +1664,9 @@ mod tests {
|
||||||
// PSBTs taken from BIP 174 test vectors.
|
// PSBTs taken from BIP 174 test vectors.
|
||||||
#[test]
|
#[test]
|
||||||
fn combine_psbts() {
|
fn combine_psbts() {
|
||||||
let mut psbt1 = hex_psbt!(include_str!("../../../test_data/psbt1.hex")).unwrap();
|
let mut psbt1 = hex_psbt!(include_str!("../../../tests/data/psbt1.hex")).unwrap();
|
||||||
let psbt2 = hex_psbt!(include_str!("../../../test_data/psbt2.hex")).unwrap();
|
let psbt2 = hex_psbt!(include_str!("../../../tests/data/psbt2.hex")).unwrap();
|
||||||
let psbt_combined = hex_psbt!(include_str!("../../../test_data/psbt2.hex")).unwrap();
|
let psbt_combined = hex_psbt!(include_str!("../../../tests/data/psbt2.hex")).unwrap();
|
||||||
|
|
||||||
psbt1.combine(psbt2).expect("psbt combine to succeed");
|
psbt1.combine(psbt2).expect("psbt combine to succeed");
|
||||||
assert_eq!(psbt1, psbt_combined);
|
assert_eq!(psbt1, psbt_combined);
|
||||||
|
@ -1674,8 +1674,8 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn combine_psbts_commutative() {
|
fn combine_psbts_commutative() {
|
||||||
let mut psbt1 = hex_psbt!(include_str!("../../../test_data/psbt1.hex")).unwrap();
|
let mut psbt1 = hex_psbt!(include_str!("../../../tests/data/psbt1.hex")).unwrap();
|
||||||
let mut psbt2 = hex_psbt!(include_str!("../../../test_data/psbt2.hex")).unwrap();
|
let mut psbt2 = hex_psbt!(include_str!("../../../tests/data/psbt2.hex")).unwrap();
|
||||||
|
|
||||||
let psbt1_clone = psbt1.clone();
|
let psbt1_clone = psbt1.clone();
|
||||||
let psbt2_clone = psbt2.clone();
|
let psbt2_clone = psbt2.clone();
|
||||||
|
|
|
@ -1438,7 +1438,7 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bip_341_read_json() -> serde_json::Value {
|
fn bip_341_read_json() -> serde_json::Value {
|
||||||
let json_str = include_str!("../../test_data/bip341_tests.json");
|
let json_str = include_str!("../../tests/data/bip341_tests.json");
|
||||||
serde_json::from_str(json_str).expect("JSON was not well-formatted")
|
serde_json::from_str(json_str).expect("JSON was not well-formatted")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
Test vector data
|
||||||
|
================
|
||||||
|
|
||||||
|
This file contains data (hex strings) taken from BIP test vectors.
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000000000000000000
|
|
@ -0,0 +1 @@
|
||||||
|
0200000000010258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7500000000da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752aeffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d01000000232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f000400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00000000
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000af00102030405060708090f0102030405060708090a0b0c0d0e0f0af00102030405060708100f0102030405060708090a0b0c0d0e0f000af00102030405060708090f0102030405060708090a0b0c0d0e0f0af00102030405060708100f0102030405060708090a0b0c0d0e0f000af00102030405060708090f0102030405060708090a0b0c0d0e0f0af00102030405060708100f0102030405060708090a0b0c0d0e0f00
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000af00102030405060708090f0102030405060708090a0b0c0d0e0f000af00102030405060708090f0102030405060708090a0b0c0d0e0f000af00102030405060708090f0102030405060708090a0b0c0d0e0f00
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a0100000000000af00102030405060708100f0102030405060708090a0b0c0d0e0f000af00102030405060708100f0102030405060708090a0b0c0d0e0f000af00102030405060708100f0102030405060708090a0b0c0d0e0f00
|
|
@ -0,0 +1 @@
|
||||||
|
0200000000010158e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd7501000000171600145f275f436b09a8cc9a2eb2a2f528485c68a56323feffffff02d8231f1b0100000017a914aed962d6654f9a2b36608eb9d64d2b260db4f1118700c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88702483045022100a22edcc6e5bc511af4cc4ae0de0fcd75c7e04d8c1c3a8aa9d820ed4b967384ec02200642963597b9b1bc22c75e9f3e117284a962188bf5e8a74c895089046a20ad770121035509a48eb623e10aace8bfd0212fdb8a8e5af3c94b0b133b95e114cab89e4f7965000000
|
|
@ -0,0 +1 @@
|
||||||
|
0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f012202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000002202029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e887220203089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000220202dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8872202023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d2010103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e88701042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000
|
|
@ -0,0 +1 @@
|
||||||
|
70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000010304010000000104475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae2206029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f10d90c6a4f000000800000008000000080220602dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d710d90c6a4f0000008000000080010000800001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870103040100000001042200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903010547522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae2206023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7310d90c6a4f000000800000008003000080220603089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc10d90c6a4f00000080000000800200008000220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000
|
|
@ -0,0 +1,467 @@
|
||||||
|
//! Tests PSBT integration vectors from BIP 174
|
||||||
|
//! defined at <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#test-vectors>
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use bitcoin::bip32::{ExtendedPrivKey, ExtendedPubKey, Fingerprint, IntoDerivationPath, KeySource};
|
||||||
|
use bitcoin::blockdata::opcodes::OP_0;
|
||||||
|
use bitcoin::blockdata::script;
|
||||||
|
use bitcoin::consensus::encode::{deserialize, serialize_hex};
|
||||||
|
use bitcoin::hashes::hex::FromHex;
|
||||||
|
use bitcoin::psbt::{Psbt, PsbtSighashType};
|
||||||
|
use bitcoin::secp256k1::{self, Secp256k1};
|
||||||
|
use bitcoin::{
|
||||||
|
absolute, Amount, Denomination, Network, OutPoint, PrivateKey, PublicKey, Script, Sequence,
|
||||||
|
Transaction, TxIn, TxOut, Txid, Witness,
|
||||||
|
};
|
||||||
|
|
||||||
|
const NETWORK: Network = Network::Testnet;
|
||||||
|
|
||||||
|
macro_rules! hex_script {
|
||||||
|
($s:expr) => {
|
||||||
|
<Script as FromStr>::from_str($s).unwrap()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! hex_psbt {
|
||||||
|
($s:expr) => {
|
||||||
|
deserialize::<Psbt>(&<Vec<u8> as FromHex>::from_hex($s).unwrap())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bip174_psbt_workflow() {
|
||||||
|
let secp = Secp256k1::new();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 0: Create the extended private key from the test vector data.
|
||||||
|
//
|
||||||
|
|
||||||
|
let ext_priv = build_extended_private_key();
|
||||||
|
let ext_pub = ExtendedPubKey::from_priv(&secp, &ext_priv);
|
||||||
|
let parent_fingerprint = ext_pub.fingerprint();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 1: The creator.
|
||||||
|
//
|
||||||
|
|
||||||
|
let tx = create_transaction();
|
||||||
|
let psbt = create_psbt(tx);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 2: The first updater.
|
||||||
|
//
|
||||||
|
|
||||||
|
let psbt = update_psbt(psbt, parent_fingerprint);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 3: The second updater.
|
||||||
|
//
|
||||||
|
|
||||||
|
let psbt = update_psbt_with_sighash_all(psbt);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 4: The first signer.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Strings from BIP 174 test vector.
|
||||||
|
let test_vector = vec![
|
||||||
|
("cP53pDbR5WtAD8dYAW9hhTjuvvTVaEiQBdrz9XPrgLBeRFiyCbQr", "m/0h/0h/0h"), // from_priv, into_derivation_path?
|
||||||
|
("cR6SXDoyfQrcp4piaiHE97Rsgta9mNhGTen9XeonVgwsh4iSgw6d", "m/0h/0h/2h"),
|
||||||
|
];
|
||||||
|
|
||||||
|
// We pass the keys to the signer after doing verification to make explicit
|
||||||
|
// that signer is only using these two keys.
|
||||||
|
let keys = parse_and_verify_keys(&ext_priv, &test_vector);
|
||||||
|
let psbt_1 = signer_one_sign(psbt.clone(), keys);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 5: The second signer.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Strings from BIP 174 test vector.
|
||||||
|
let test_vector = vec![
|
||||||
|
("cT7J9YpCwY3AVRFSjN6ukeEeWY6mhpbJPxRaDaP5QTdygQRxP9Au", "m/0h/0h/1h"),
|
||||||
|
("cNBc3SWUip9PPm1GjRoLEJT6T41iNzCYtD7qro84FMnM5zEqeJsE", "m/0h/0h/3h"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let keys = parse_and_verify_keys(&ext_priv, &test_vector);
|
||||||
|
let psbt_2 = signer_two_sign(psbt, keys);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 6: Combiner the two signed PSBTs.
|
||||||
|
//
|
||||||
|
|
||||||
|
let combined = combine(psbt_1, psbt_2);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 7: Finalize the PSBT.
|
||||||
|
//
|
||||||
|
|
||||||
|
let finalized = finalize(combined);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 8: Extract the transaction.
|
||||||
|
//
|
||||||
|
|
||||||
|
let _tx = extract_transaction(finalized);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Step 9: Test lexicographical PSBT combiner.
|
||||||
|
//
|
||||||
|
// Combine would be done earlier, at Step 6, in typical workflow.
|
||||||
|
// We define it here to reflect the order of test vectors in BIP 174.
|
||||||
|
//
|
||||||
|
|
||||||
|
combine_lexicographically();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to build an extended private key from seed and also directly from a string.
|
||||||
|
fn build_extended_private_key() -> ExtendedPrivKey {
|
||||||
|
// Strings from BIP 174 test vector.
|
||||||
|
let extended_private_key = "tprv8ZgxMBicQKsPd9TeAdPADNnSyH9SSUUbTVeFszDE23Ki6TBB5nCefAdHkK8Fm3qMQR6sHwA56zqRmKmxnHk37JkiFzvncDqoKmPWubu7hDF";
|
||||||
|
let seed = "cUkG8i1RFfWGWy5ziR11zJ5V4U4W3viSFCfyJmZnvQaUsd1xuF3T";
|
||||||
|
|
||||||
|
let xpriv = ExtendedPrivKey::from_str(extended_private_key).unwrap();
|
||||||
|
|
||||||
|
let sk = PrivateKey::from_wif(seed).unwrap();
|
||||||
|
let seeded = ExtendedPrivKey::new_master(NETWORK, &sk.inner.secret_bytes()).unwrap();
|
||||||
|
assert_eq!(xpriv, seeded);
|
||||||
|
|
||||||
|
xpriv
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the initial transaction, called by the PSBT Creator.
|
||||||
|
fn create_transaction() -> Transaction {
|
||||||
|
// Strings from BIP 174 test vector.
|
||||||
|
let output_0 = TvOutput {
|
||||||
|
amount: "1.49990000",
|
||||||
|
script_pubkey: "0014d85c2b71d0060b09c9886aeb815e50991dda124d",
|
||||||
|
};
|
||||||
|
let output_1 = TvOutput {
|
||||||
|
amount: "1.00000000",
|
||||||
|
script_pubkey: "001400aea9a2e5f0f876a588df5546e8742d1d87008f",
|
||||||
|
};
|
||||||
|
let input_0 = TvInput {
|
||||||
|
txid: "75ddabb27b8845f5247975c8a5ba7c6f336c4570708ebe230caf6db5217ae858",
|
||||||
|
index: 0,
|
||||||
|
};
|
||||||
|
let input_1 = TvInput {
|
||||||
|
txid: "1dea7cd05979072a3578cab271c02244ea8a090bbb46aa680a65ecd027048d83",
|
||||||
|
index: 1,
|
||||||
|
};
|
||||||
|
struct TvOutput {
|
||||||
|
amount: &'static str,
|
||||||
|
script_pubkey: &'static str,
|
||||||
|
}
|
||||||
|
struct TvInput {
|
||||||
|
txid: &'static str,
|
||||||
|
index: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
Transaction {
|
||||||
|
version: 2,
|
||||||
|
lock_time: absolute::PackedLockTime::ZERO,
|
||||||
|
input: vec![
|
||||||
|
TxIn {
|
||||||
|
previous_output: OutPoint {
|
||||||
|
txid: Txid::from_hex(input_0.txid).expect("failed to parse txid"),
|
||||||
|
vout: input_0.index,
|
||||||
|
},
|
||||||
|
script_sig: Script::new(),
|
||||||
|
sequence: Sequence::MAX, // Disable nSequence.
|
||||||
|
witness: Witness::default(),
|
||||||
|
},
|
||||||
|
TxIn {
|
||||||
|
previous_output: OutPoint {
|
||||||
|
txid: Txid::from_hex(input_1.txid).expect("failed to parse txid"),
|
||||||
|
vout: input_1.index,
|
||||||
|
},
|
||||||
|
script_sig: Script::new(),
|
||||||
|
sequence: Sequence::MAX,
|
||||||
|
witness: Witness::default(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
output: vec![
|
||||||
|
TxOut {
|
||||||
|
value: Amount::from_str_in(output_0.amount, Denomination::Bitcoin)
|
||||||
|
.expect("failed to parse amount")
|
||||||
|
.to_sat(),
|
||||||
|
script_pubkey: Script::from_str(output_0.script_pubkey)
|
||||||
|
.expect("failed to parse script"),
|
||||||
|
},
|
||||||
|
TxOut {
|
||||||
|
value: Amount::from_str_in(output_1.amount, Denomination::Bitcoin)
|
||||||
|
.expect("failed to parse amount")
|
||||||
|
.to_sat(),
|
||||||
|
script_pubkey: Script::from_str(output_1.script_pubkey)
|
||||||
|
.expect("failed to parse script"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates the initial PSBT, called by the Creator. Verifies against BIP 174 test vector.
|
||||||
|
fn create_psbt(tx: Transaction) -> Psbt {
|
||||||
|
// String from BIP 174 test vector.
|
||||||
|
let expected_psbt_hex = include_str!("data/create_psbt_hex");
|
||||||
|
let expected_psbt = hex_psbt!(expected_psbt_hex).unwrap();
|
||||||
|
|
||||||
|
let psbt = Psbt::from_unsigned_tx(tx).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(psbt, expected_psbt);
|
||||||
|
psbt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates `psbt` according to the BIP, returns the newly updated PSBT. Verifies against BIP 174 test vector.
|
||||||
|
fn update_psbt(mut psbt: Psbt, fingerprint: Fingerprint) -> Psbt {
|
||||||
|
// Strings from BIP 174 test vector.
|
||||||
|
let previous_tx_0 = include_str!("data/previous_tx_0_hex");
|
||||||
|
let previous_tx_1 = include_str!("data/previous_tx_1_hex");
|
||||||
|
|
||||||
|
let redeem_script_0 = "5221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae";
|
||||||
|
let redeem_script_1 = "00208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903";
|
||||||
|
let witness_script = "522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae";
|
||||||
|
|
||||||
|
// Public key and its derivation path (these are the child pubkeys for our `ExtendedPrivKey`,
|
||||||
|
// can be verified by deriving the key using this derivation path).
|
||||||
|
let pk_path = vec![
|
||||||
|
("029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f", "m/0h/0h/0h"),
|
||||||
|
("02dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d7", "m/0h/0h/1h"),
|
||||||
|
("03089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc", "m/0h/0h/2h"),
|
||||||
|
("023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e73", "m/0h/0h/3h"),
|
||||||
|
("03a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca58771", "m/0h/0h/4h"),
|
||||||
|
("027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b50051096", "m/0h/0h/5h"),
|
||||||
|
];
|
||||||
|
|
||||||
|
let expected_psbt_hex = include_str!("data/update_1_psbt_hex");
|
||||||
|
let expected_psbt = hex_psbt!(expected_psbt_hex).unwrap();
|
||||||
|
|
||||||
|
let mut input_0 = psbt.inputs[0].clone();
|
||||||
|
|
||||||
|
let v = Vec::from_hex(previous_tx_1).unwrap();
|
||||||
|
let tx: Transaction = deserialize(&v).unwrap();
|
||||||
|
input_0.non_witness_utxo = Some(tx);
|
||||||
|
input_0.redeem_script = Some(hex_script!(redeem_script_0));
|
||||||
|
input_0.bip32_derivation = bip32_derivation(fingerprint, &pk_path, vec![0, 1]);
|
||||||
|
|
||||||
|
let mut input_1 = psbt.inputs[1].clone();
|
||||||
|
|
||||||
|
let v = Vec::from_hex(previous_tx_0).unwrap();
|
||||||
|
let tx: Transaction = deserialize(&v).unwrap();
|
||||||
|
input_1.witness_utxo = Some(tx.output[1].clone());
|
||||||
|
|
||||||
|
input_1.redeem_script = Some(hex_script!(redeem_script_1));
|
||||||
|
input_1.witness_script = Some(hex_script!(witness_script));
|
||||||
|
input_1.bip32_derivation = bip32_derivation(fingerprint, &pk_path, vec![2, 3]);
|
||||||
|
|
||||||
|
psbt.inputs = vec![input_0, input_1];
|
||||||
|
|
||||||
|
let mut output_0 = psbt.outputs[0].clone();
|
||||||
|
output_0.bip32_derivation = bip32_derivation(fingerprint, &pk_path, vec![4]);
|
||||||
|
|
||||||
|
let mut output_1 = psbt.outputs[1].clone();
|
||||||
|
output_1.bip32_derivation = bip32_derivation(fingerprint, &pk_path, vec![5]);
|
||||||
|
|
||||||
|
psbt.outputs = vec![output_0, output_1];
|
||||||
|
|
||||||
|
assert_eq!(psbt, expected_psbt);
|
||||||
|
psbt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `pk_path` holds tuples of `(public_key, derivation_path)`. `indecies` is used to access the
|
||||||
|
/// `pk_path` vector. `fingerprint` is from the parent extended public key.
|
||||||
|
fn bip32_derivation(
|
||||||
|
fingerprint: Fingerprint,
|
||||||
|
pk_path: &[(&str, &str)],
|
||||||
|
indecies: Vec<usize>,
|
||||||
|
) -> BTreeMap<secp256k1::PublicKey, KeySource> {
|
||||||
|
let mut tree = BTreeMap::new();
|
||||||
|
for i in indecies {
|
||||||
|
let pk = pk_path[i].0;
|
||||||
|
let path = pk_path[i].1;
|
||||||
|
|
||||||
|
let pk = PublicKey::from_str(pk).unwrap();
|
||||||
|
let path = path.into_derivation_path().unwrap();
|
||||||
|
|
||||||
|
tree.insert(pk.inner, (fingerprint, path));
|
||||||
|
}
|
||||||
|
tree
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Does the second update according to the BIP, returns the newly updated PSBT. Verifies against BIP 174 test vector.
|
||||||
|
fn update_psbt_with_sighash_all(mut psbt: Psbt) -> Psbt {
|
||||||
|
let expected_psbt_hex = include_str!("data/update_2_psbt_hex");
|
||||||
|
let expected_psbt = hex_psbt!(expected_psbt_hex).unwrap();
|
||||||
|
|
||||||
|
let ty = PsbtSighashType::from_str("SIGHASH_ALL").unwrap();
|
||||||
|
|
||||||
|
let mut input_0 = psbt.inputs[0].clone();
|
||||||
|
input_0.sighash_type = Some(ty);
|
||||||
|
let mut input_1 = psbt.inputs[1].clone();
|
||||||
|
input_1.sighash_type = Some(ty);
|
||||||
|
|
||||||
|
psbt.inputs = vec![input_0, input_1];
|
||||||
|
|
||||||
|
assert_eq!(psbt, expected_psbt);
|
||||||
|
psbt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifies the keys in the test vector are valid for the extended private key and derivation path.
|
||||||
|
fn parse_and_verify_keys(
|
||||||
|
ext_priv: &ExtendedPrivKey,
|
||||||
|
sk_path: &[(&str, &str)],
|
||||||
|
) -> BTreeMap<PublicKey, PrivateKey> {
|
||||||
|
let secp = &Secp256k1::new();
|
||||||
|
|
||||||
|
let mut key_map = BTreeMap::new();
|
||||||
|
for (secret_key, derivation_path) in sk_path.iter() {
|
||||||
|
let wif_priv = PrivateKey::from_wif(secret_key).expect("failed to parse key");
|
||||||
|
|
||||||
|
let path =
|
||||||
|
derivation_path.into_derivation_path().expect("failed to convert derivation path");
|
||||||
|
let derived_priv =
|
||||||
|
ext_priv.derive_priv(secp, &path).expect("failed to derive ext priv key").to_priv();
|
||||||
|
assert_eq!(wif_priv, derived_priv);
|
||||||
|
let derived_pub = derived_priv.public_key(secp);
|
||||||
|
key_map.insert(derived_pub, derived_priv);
|
||||||
|
}
|
||||||
|
key_map
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Does the first signing according to the BIP, returns the signed PSBT. Verifies against BIP 174 test vector.
|
||||||
|
fn signer_one_sign(psbt: Psbt, key_map: BTreeMap<bitcoin::PublicKey, PrivateKey>) -> Psbt {
|
||||||
|
let expected_psbt_hex = include_str!("data/sign_1_psbt_hex");
|
||||||
|
let expected_psbt = hex_psbt!(expected_psbt_hex).unwrap();
|
||||||
|
|
||||||
|
let psbt = sign(psbt, key_map);
|
||||||
|
|
||||||
|
assert_eq!(psbt, expected_psbt);
|
||||||
|
psbt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Does the second signing according to the BIP, returns the signed PSBT. Verifies against BIP 174 test vector.
|
||||||
|
fn signer_two_sign(psbt: Psbt, key_map: BTreeMap<bitcoin::PublicKey, PrivateKey>) -> Psbt {
|
||||||
|
let expected_psbt_hex = include_str!("data/sign_2_psbt_hex");
|
||||||
|
let expected_psbt = hex_psbt!(expected_psbt_hex).unwrap();
|
||||||
|
|
||||||
|
let psbt = sign(psbt, key_map);
|
||||||
|
|
||||||
|
assert_eq!(psbt, expected_psbt);
|
||||||
|
psbt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Does the combine according to the BIP, returns the combined PSBT. Verifies against BIP 174 test vector.
|
||||||
|
fn combine(mut this: Psbt, that: Psbt) -> Psbt {
|
||||||
|
let expected_psbt_hex = include_str!("data/combine_psbt_hex");
|
||||||
|
let expected_psbt = hex_psbt!(expected_psbt_hex).unwrap();
|
||||||
|
|
||||||
|
this.combine(that).expect("failed to combine PSBTs");
|
||||||
|
|
||||||
|
assert_eq!(this, expected_psbt);
|
||||||
|
this
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Does the finalize step according to the BIP, returns the combined PSBT. Verifies against BIP 174
|
||||||
|
/// test vector.
|
||||||
|
fn finalize(psbt: Psbt) -> Psbt {
|
||||||
|
let expected_psbt_hex = include_str!("data/finalize_psbt_hex");
|
||||||
|
let expected_psbt = hex_psbt!(expected_psbt_hex).unwrap();
|
||||||
|
|
||||||
|
let psbt = finalize_psbt(psbt);
|
||||||
|
|
||||||
|
assert_eq!(psbt, expected_psbt);
|
||||||
|
psbt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Does the transaction extractor step according to the BIP, returns the combined PSBT. Verifies
|
||||||
|
/// against BIP 174 test vector.
|
||||||
|
fn extract_transaction(psbt: Psbt) -> Transaction {
|
||||||
|
let expected_tx_hex = include_str!("data/extract_tx_hex");
|
||||||
|
|
||||||
|
let tx = psbt.extract_tx();
|
||||||
|
|
||||||
|
let got = serialize_hex(&tx);
|
||||||
|
assert_eq!(got, expected_tx_hex);
|
||||||
|
|
||||||
|
tx
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Combines two PSBTs lexicographically according to the BIP. Verifies against BIP 174 test vector.
|
||||||
|
fn combine_lexicographically() {
|
||||||
|
let psbt_1_hex = include_str!("data/lex_psbt_1_hex");
|
||||||
|
let psbt_2_hex = include_str!("data/lex_psbt_2_hex");
|
||||||
|
|
||||||
|
let expected_psbt_hex = include_str!("data/lex_combine_psbt_hex");
|
||||||
|
let expected_psbt = hex_psbt!(expected_psbt_hex).unwrap();
|
||||||
|
|
||||||
|
let v = Vec::from_hex(psbt_1_hex).unwrap();
|
||||||
|
let mut psbt_1: Psbt = deserialize(&v).expect("failed to deserialize psbt 1");
|
||||||
|
|
||||||
|
let v = Vec::from_hex(psbt_2_hex).unwrap();
|
||||||
|
let psbt_2: Psbt = deserialize(&v).expect("failed to deserialize psbt 2");
|
||||||
|
|
||||||
|
psbt_1.combine(psbt_2).expect("failed to combine PSBTs");
|
||||||
|
|
||||||
|
assert_eq!(psbt_1, expected_psbt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Signs `psbt` with `keys` if required.
|
||||||
|
fn sign(mut psbt: Psbt, keys: BTreeMap<bitcoin::PublicKey, PrivateKey>) -> Psbt {
|
||||||
|
let secp = Secp256k1::new();
|
||||||
|
psbt.sign(&keys, &secp).unwrap();
|
||||||
|
psbt
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finalizes a PSBT accord to the Input Finalizer role described in BIP 174.
|
||||||
|
/// This is just a test. For a production-ready PSBT Finalizer, use [rust-miniscript](https://docs.rs/miniscript/latest/miniscript/psbt/trait.PsbtExt.html#tymethod.finalize)
|
||||||
|
fn finalize_psbt(mut psbt: Psbt) -> Psbt {
|
||||||
|
use bitcoin::util::psbt::serialize::Serialize;
|
||||||
|
|
||||||
|
// Input 0: legacy UTXO
|
||||||
|
|
||||||
|
let sigs: Vec<_> = psbt.inputs[0].partial_sigs.values().collect();
|
||||||
|
let script_sig = script::Builder::new()
|
||||||
|
.push_opcode(OP_0) // OP_CHECKMULTISIG bug pops +1 value when evaluating so push OP_0.
|
||||||
|
.push_slice(&sigs[0].serialize())
|
||||||
|
.push_slice(&sigs[1].serialize())
|
||||||
|
.push_slice(&psbt.inputs[0].redeem_script.clone().unwrap().serialize())
|
||||||
|
.into_script();
|
||||||
|
|
||||||
|
psbt.inputs[0].final_script_sig = Some(script_sig);
|
||||||
|
|
||||||
|
psbt.inputs[0].partial_sigs = BTreeMap::new();
|
||||||
|
psbt.inputs[0].sighash_type = None;
|
||||||
|
psbt.inputs[0].redeem_script = None;
|
||||||
|
psbt.inputs[0].bip32_derivation = BTreeMap::new();
|
||||||
|
|
||||||
|
// Input 1: SegWit UTXO
|
||||||
|
|
||||||
|
let script_sig = script::Builder::new()
|
||||||
|
.push_slice(&psbt.inputs[1].redeem_script.clone().unwrap().serialize())
|
||||||
|
.into_script();
|
||||||
|
|
||||||
|
psbt.inputs[1].final_script_sig = Some(script_sig);
|
||||||
|
|
||||||
|
let script_witness = {
|
||||||
|
let sigs: Vec<_> = psbt.inputs[1].partial_sigs.values().collect();
|
||||||
|
let mut script_witness = Witness::new();
|
||||||
|
script_witness.push([]); // Push 0x00 to the stack.
|
||||||
|
script_witness.push(&sigs[1].serialize());
|
||||||
|
script_witness.push(&sigs[0].serialize());
|
||||||
|
script_witness.push(&psbt.inputs[1].witness_script.clone().unwrap().serialize());
|
||||||
|
|
||||||
|
script_witness
|
||||||
|
};
|
||||||
|
|
||||||
|
psbt.inputs[1].final_script_witness = Some(script_witness);
|
||||||
|
|
||||||
|
psbt.inputs[1].partial_sigs = BTreeMap::new();
|
||||||
|
psbt.inputs[1].sighash_type = None;
|
||||||
|
psbt.inputs[1].redeem_script = None;
|
||||||
|
psbt.inputs[1].witness_script = None;
|
||||||
|
psbt.inputs[1].bip32_derivation = BTreeMap::new();
|
||||||
|
|
||||||
|
psbt
|
||||||
|
}
|
Loading…
Reference in New Issue