Merge rust-bitcoin/rust-bitcoin#4316: Improve the script hex APIs
5d5a19793a
Run the formatter (Tobin C. Harding)2b72f1f30b
Make Lower/Upper hex print scripts with len prefix (Tobin C. Harding)c27b95fb0d
Make script to/from hex use consensus encoding (Tobin C. Harding)f4bc58dc48
bitcoin: Add a script encoding example (Tobin C. Harding) Pull request description: Done while investigating #3910 - this PR is quite invasive. - Patch 1 adds an example that shows the current behaviour of various API calls for converting scripts to/from hex. - Patch 2 adds a pair of functions that do not use the length prefix and makes script to/from_hex use the prefix. - Patch 3 makes `LowerHex` and `UpperHex` use the len prefix also - Patch 4 runs the formatter Explicitly keeps serde untouched - i.e., without the len prefix ACKs for top commit: apoelstra: ACK 5d5a19793aae73ff09d7064455a1a995eb796c28; successfully ran local tests Tree-SHA512: dbbec372ea7b01818fce68ffb807a4531f068e10147e8bedf37b77f66a068a628e380549c379c061b868973e97806ada59729248b03bbd1cf6809f6098170cb6
This commit is contained in:
commit
a9ddac178d
|
@ -94,5 +94,9 @@ name = "sighash"
|
||||||
name = "io"
|
name = "io"
|
||||||
required-features = ["std"]
|
required-features = ["std"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "script"
|
||||||
|
required-features = ["std"]
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(fuzzing)', 'cfg(kani)'] }
|
unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(fuzzing)', 'cfg(kani)'] }
|
||||||
|
|
|
@ -275,7 +275,7 @@ fn input_derivation_path() -> Result<DerivationPath> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn previous_output() -> TxOut {
|
fn previous_output() -> TxOut {
|
||||||
let script_pubkey = ScriptBuf::from_hex(INPUT_UTXO_SCRIPT_PUBKEY)
|
let script_pubkey = ScriptBuf::from_hex_no_length_prefix(INPUT_UTXO_SCRIPT_PUBKEY)
|
||||||
.expect("failed to parse input utxo scriptPubkey");
|
.expect("failed to parse input utxo scriptPubkey");
|
||||||
let amount = INPUT_UTXO_VALUE.parse::<Amount>().expect("failed to parse input utxo value");
|
let amount = INPUT_UTXO_VALUE.parse::<Amount>().expect("failed to parse input utxo value");
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
//! Demonstrates the API for parsing and formatting Bitcoin scripts.
|
||||||
|
//!
|
||||||
|
//! Bitcoin script is conceptually a vector of bytes. As such it is consensus encoded with a compact
|
||||||
|
//! size encoded length prefix. See [CompactSize].
|
||||||
|
//!
|
||||||
|
//! [`CompactSize`]: <https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer>
|
||||||
|
|
||||||
|
use bitcoin::consensus::encode;
|
||||||
|
use bitcoin::key::WPubkeyHash;
|
||||||
|
use bitcoin::script::{self, ScriptBufExt, ScriptExt};
|
||||||
|
use bitcoin::ScriptBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let pk = "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb".parse::<WPubkeyHash>().unwrap();
|
||||||
|
|
||||||
|
// TL;DR Use `to_hex_string` and `from_hex`.
|
||||||
|
let script_code = script::p2wpkh_script_code(pk);
|
||||||
|
let hex = script_code.to_hex_string();
|
||||||
|
let decoded = ScriptBuf::from_hex(&hex).unwrap();
|
||||||
|
assert_eq!(decoded, script_code);
|
||||||
|
|
||||||
|
// Writes the script as human-readable eg, OP_DUP OP_HASH160 OP_PUSHBYTES_20 ...
|
||||||
|
println!("human-readable script: {}", script_code);
|
||||||
|
|
||||||
|
// We do not implement parsing scripts from human-readable format.
|
||||||
|
// let decoded = s.parse::<ScriptBuf>().unwrap();
|
||||||
|
|
||||||
|
// This is equivalent to consensus encoding i.e., includes the length prefix.
|
||||||
|
let hex_lower_hex_trait = format!("{:x}", script_code);
|
||||||
|
println!("hex created using `LowerHex`: {}", hex_lower_hex_trait);
|
||||||
|
|
||||||
|
// The `deserialize_hex` function requires the length prefix.
|
||||||
|
assert_eq!(encode::deserialize_hex::<ScriptBuf>(&hex_lower_hex_trait).unwrap(), script_code);
|
||||||
|
// And so does `from_hex`.
|
||||||
|
assert_eq!(ScriptBuf::from_hex(&hex_lower_hex_trait).unwrap(), script_code);
|
||||||
|
|
||||||
|
// And we also provide an explicit constructor that does not use the length prefix.
|
||||||
|
let other = ScriptBuf::from_hex_no_length_prefix(&hex_lower_hex_trait).unwrap();
|
||||||
|
// Without a prefix the script parses but its not the one we meant.
|
||||||
|
assert_ne!(other, script_code);
|
||||||
|
|
||||||
|
// This is consensus encoding i.e., includes the length prefix.
|
||||||
|
let hex_inherent = script_code.to_hex_string(); // Defined in `ScriptExt`.
|
||||||
|
println!("hex created using inherent `to_hex_string`: {}", hex_inherent);
|
||||||
|
|
||||||
|
// The inverse of `to_hex_string` is `from_hex`.
|
||||||
|
let decoded = ScriptBuf::from_hex(&hex_inherent).unwrap(); // Defined in `ScriptBufExt`.
|
||||||
|
assert_eq!(decoded, script_code);
|
||||||
|
// We can also parse the output of `to_hex_string` using `deserialize_hex`.
|
||||||
|
let decoded = encode::deserialize_hex::<ScriptBuf>(&hex_inherent).unwrap();
|
||||||
|
assert_eq!(decoded, script_code);
|
||||||
|
|
||||||
|
// We also support encode/decode using `consensus::encode` functions.
|
||||||
|
let encoded = encode::serialize_hex(&script_code);
|
||||||
|
println!("hex created using consensus::encode::serialize_hex: {}", encoded);
|
||||||
|
|
||||||
|
let decoded: ScriptBuf = encode::deserialize_hex(&encoded).unwrap();
|
||||||
|
assert_eq!(decoded, script_code);
|
||||||
|
// And we can mix these to calls because both include the length prefix.
|
||||||
|
let decoded = ScriptBuf::from_hex(&encoded).unwrap();
|
||||||
|
assert_eq!(decoded, script_code);
|
||||||
|
|
||||||
|
// Encode/decode using a byte vector.
|
||||||
|
let encoded = encode::serialize(&script_code);
|
||||||
|
assert_eq!(&encoded[1..], script_code.as_bytes()); // Shows that prefix is the first byte.
|
||||||
|
let decoded: ScriptBuf = encode::deserialize(&encoded).unwrap();
|
||||||
|
assert_eq!(decoded, script_code);
|
||||||
|
|
||||||
|
// to/from bytes excludes the prefix, these are not encoding/decoding functions so this is sane.
|
||||||
|
let bytes = script_code.to_bytes();
|
||||||
|
let got = ScriptBuf::from_bytes(bytes);
|
||||||
|
assert_eq!(got, script_code);
|
||||||
|
}
|
|
@ -257,7 +257,7 @@ fn generate_bip86_key_spend_tx(
|
||||||
|
|
||||||
let mut input = Input {
|
let mut input = Input {
|
||||||
witness_utxo: {
|
witness_utxo: {
|
||||||
let script_pubkey = ScriptBuf::from_hex(input_utxo.script_pubkey)
|
let script_pubkey = ScriptBuf::from_hex_no_length_prefix(input_utxo.script_pubkey)
|
||||||
.expect("failed to parse input utxo scriptPubkey");
|
.expect("failed to parse input utxo scriptPubkey");
|
||||||
Some(TxOut { value: from_amount, script_pubkey })
|
Some(TxOut { value: from_amount, script_pubkey })
|
||||||
},
|
},
|
||||||
|
@ -275,7 +275,7 @@ fn generate_bip86_key_spend_tx(
|
||||||
for input in [&input_utxo].iter() {
|
for input in [&input_utxo].iter() {
|
||||||
input_txouts.push(TxOut {
|
input_txouts.push(TxOut {
|
||||||
value: input.amount,
|
value: input.amount,
|
||||||
script_pubkey: ScriptBuf::from_hex(input.script_pubkey)?,
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(input.script_pubkey)?,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,7 +333,7 @@ fn generate_bip86_key_spend_tx(
|
||||||
tx.verify(|_| {
|
tx.verify(|_| {
|
||||||
Some(TxOut {
|
Some(TxOut {
|
||||||
value: from_amount,
|
value: from_amount,
|
||||||
script_pubkey: ScriptBuf::from_hex(input_utxo.script_pubkey).unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(input_utxo.script_pubkey).unwrap(),
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.expect("failed to verify transaction");
|
.expect("failed to verify transaction");
|
||||||
|
|
|
@ -1053,7 +1053,10 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr.script_pubkey(),
|
addr.script_pubkey(),
|
||||||
ScriptBuf::from_hex("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac").unwrap()
|
ScriptBuf::from_hex_no_length_prefix(
|
||||||
|
"76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
assert_eq!(&addr.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
|
assert_eq!(&addr.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM");
|
||||||
assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
|
assert_eq!(addr.address_type(), Some(AddressType::P2pkh));
|
||||||
|
@ -1082,7 +1085,8 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
addr.script_pubkey(),
|
addr.script_pubkey(),
|
||||||
ScriptBuf::from_hex("a914162c5ea71c0b23f5b9022ef047c4a86470a5b07087").unwrap(),
|
ScriptBuf::from_hex_no_length_prefix("a914162c5ea71c0b23f5b9022ef047c4a86470a5b07087")
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
assert_eq!(&addr.to_string(), "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k");
|
assert_eq!(&addr.to_string(), "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k");
|
||||||
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
|
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
|
||||||
|
@ -1091,7 +1095,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn p2sh_parse() {
|
fn p2sh_parse() {
|
||||||
let script = ScriptBuf::from_hex("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae").unwrap();
|
let script = ScriptBuf::from_hex_no_length_prefix("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae").unwrap();
|
||||||
let addr = Address::p2sh(&script, NetworkKind::Test).unwrap();
|
let addr = Address::p2sh(&script, NetworkKind::Test).unwrap();
|
||||||
assert_eq!(&addr.to_string(), "2N3zXjbwdTcPsJiy8sUK9FhWJhqQCxA8Jjr");
|
assert_eq!(&addr.to_string(), "2N3zXjbwdTcPsJiy8sUK9FhWJhqQCxA8Jjr");
|
||||||
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
|
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
|
||||||
|
@ -1100,7 +1104,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn p2sh_parse_for_large_script() {
|
fn p2sh_parse_for_large_script() {
|
||||||
let script = ScriptBuf::from_hex("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123").unwrap();
|
let script = ScriptBuf::from_hex_no_length_prefix("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae12123122313123123ac1231231231231313123131231231231313212313213123123").unwrap();
|
||||||
let res = Address::p2sh(&script, NetworkKind::Test);
|
let res = Address::p2sh(&script, NetworkKind::Test);
|
||||||
assert_eq!(res.unwrap_err().invalid_size(), script.len())
|
assert_eq!(res.unwrap_err().invalid_size(), script.len())
|
||||||
}
|
}
|
||||||
|
@ -1120,7 +1124,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn p2wsh() {
|
fn p2wsh() {
|
||||||
// stolen from Bitcoin transaction 5df912fda4becb1c29e928bec8d64d93e9ba8efa9b5b405bd683c86fd2c65667
|
// stolen from Bitcoin transaction 5df912fda4becb1c29e928bec8d64d93e9ba8efa9b5b405bd683c86fd2c65667
|
||||||
let script = ScriptBuf::from_hex("52210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae").unwrap();
|
let script = ScriptBuf::from_hex_no_length_prefix("52210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae").unwrap();
|
||||||
let addr = Address::p2wsh(&script, KnownHrp::Mainnet).expect("script is valid");
|
let addr = Address::p2wsh(&script, KnownHrp::Mainnet).expect("script is valid");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
&addr.to_string(),
|
&addr.to_string(),
|
||||||
|
@ -1145,7 +1149,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn p2shwsh() {
|
fn p2shwsh() {
|
||||||
// stolen from Bitcoin transaction f9ee2be4df05041d0e0a35d7caa3157495ca4f93b233234c9967b6901dacf7a9
|
// stolen from Bitcoin transaction f9ee2be4df05041d0e0a35d7caa3157495ca4f93b233234c9967b6901dacf7a9
|
||||||
let script = ScriptBuf::from_hex("522103e5529d8eaa3d559903adb2e881eb06c86ac2574ffa503c45f4e942e2a693b33e2102e5f10fcdcdbab211e0af6a481f5532536ec61a5fdbf7183770cf8680fe729d8152ae").unwrap();
|
let script = ScriptBuf::from_hex_no_length_prefix("522103e5529d8eaa3d559903adb2e881eb06c86ac2574ffa503c45f4e942e2a693b33e2102e5f10fcdcdbab211e0af6a481f5532536ec61a5fdbf7183770cf8680fe729d8152ae").unwrap();
|
||||||
let addr = Address::p2shwsh(&script, NetworkKind::Main).expect("script is valid");
|
let addr = Address::p2shwsh(&script, NetworkKind::Main).expect("script is valid");
|
||||||
assert_eq!(&addr.to_string(), "36EqgNnsWW94SreZgBWc1ANC6wpFZwirHr");
|
assert_eq!(&addr.to_string(), "36EqgNnsWW94SreZgBWc1ANC6wpFZwirHr");
|
||||||
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
|
assert_eq!(addr.address_type(), Some(AddressType::P2sh));
|
||||||
|
@ -1234,7 +1238,10 @@ mod tests {
|
||||||
assert_eq!(addr.to_string(), into.to_string());
|
assert_eq!(addr.to_string(), into.to_string());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
into.script_pubkey(),
|
into.script_pubkey(),
|
||||||
ScriptBuf::from_hex("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac").unwrap()
|
ScriptBuf::from_hex_no_length_prefix(
|
||||||
|
"76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let addr =
|
let addr =
|
||||||
|
@ -1248,7 +1255,8 @@ mod tests {
|
||||||
assert_eq!(addr.to_string(), into.to_string());
|
assert_eq!(addr.to_string(), into.to_string());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
into.script_pubkey(),
|
into.script_pubkey(),
|
||||||
ScriptBuf::from_hex("a914162c5ea71c0b23f5b9022ef047c4a86470a5b07087").unwrap()
|
ScriptBuf::from_hex_no_length_prefix("a914162c5ea71c0b23f5b9022ef047c4a86470a5b07087")
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
|
|
||||||
let addr: Address<NetworkUnchecked> =
|
let addr: Address<NetworkUnchecked> =
|
||||||
|
@ -1278,7 +1286,7 @@ mod tests {
|
||||||
assert_eq!(addr.to_string(), into.to_string());
|
assert_eq!(addr.to_string(), into.to_string());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
into.script_pubkey(),
|
into.script_pubkey(),
|
||||||
ScriptBuf::from_hex(
|
ScriptBuf::from_hex_no_length_prefix(
|
||||||
"00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"
|
"00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -1297,7 +1305,8 @@ mod tests {
|
||||||
assert_eq!(addr.to_string(), into.to_string());
|
assert_eq!(addr.to_string(), into.to_string());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
into.script_pubkey(),
|
into.script_pubkey(),
|
||||||
ScriptBuf::from_hex("001454d26dddb59c7073c6a197946ea1841951fa7a74").unwrap()
|
ScriptBuf::from_hex_no_length_prefix("001454d26dddb59c7073c6a197946ea1841951fa7a74")
|
||||||
|
.unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1476,13 +1485,15 @@ mod tests {
|
||||||
fn fail_address_from_script() {
|
fn fail_address_from_script() {
|
||||||
use crate::witness_program;
|
use crate::witness_program;
|
||||||
|
|
||||||
let bad_p2wpkh = ScriptBuf::from_hex("0014dbc5b0a8f9d4353b4b54c3db48846bb15abfec").unwrap();
|
let bad_p2wpkh =
|
||||||
let bad_p2wsh = ScriptBuf::from_hex(
|
ScriptBuf::from_hex_no_length_prefix("15000014dbc5b0a8f9d4353b4b54c3db48846bb15abfec")
|
||||||
|
.unwrap();
|
||||||
|
let bad_p2wsh = ScriptBuf::from_hex_no_length_prefix(
|
||||||
"00202d4fa2eb233d008cc83206fa2f4f2e60199000f5b857a835e3172323385623",
|
"00202d4fa2eb233d008cc83206fa2f4f2e60199000f5b857a835e3172323385623",
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let invalid_segwitv0_script =
|
let invalid_segwitv0_script =
|
||||||
ScriptBuf::from_hex("001161458e330389cd0437ee9fe3641d70cc18").unwrap();
|
ScriptBuf::from_hex_no_length_prefix("001161458e330389cd0437ee9fe3641d70cc18").unwrap();
|
||||||
let expected = Err(FromScriptError::UnrecognizedScript);
|
let expected = Err(FromScriptError::UnrecognizedScript);
|
||||||
|
|
||||||
assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), expected);
|
assert_eq!(Address::from_script(&bad_p2wpkh, Network::Bitcoin), expected);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
|
use hex::DisplayHex as _;
|
||||||
use internals::ToU64 as _;
|
use internals::ToU64 as _;
|
||||||
|
|
||||||
use super::witness_version::WitnessVersion;
|
use super::witness_version::WitnessVersion;
|
||||||
|
@ -9,11 +10,11 @@ use super::{
|
||||||
Builder, Instruction, InstructionIndices, Instructions, PushBytes, RedeemScriptSizeError,
|
Builder, Instruction, InstructionIndices, Instructions, PushBytes, RedeemScriptSizeError,
|
||||||
ScriptHash, WScriptHash, WitnessScriptSizeError,
|
ScriptHash, WScriptHash, WitnessScriptSizeError,
|
||||||
};
|
};
|
||||||
use crate::consensus::Encodable;
|
use crate::consensus::{self, Encodable};
|
||||||
use crate::opcodes::all::*;
|
use crate::opcodes::all::*;
|
||||||
use crate::opcodes::{self, Opcode};
|
use crate::opcodes::{self, Opcode};
|
||||||
use crate::policy::{DUST_RELAY_TX_FEE, MAX_OP_RETURN_RELAY};
|
use crate::policy::{DUST_RELAY_TX_FEE, MAX_OP_RETURN_RELAY};
|
||||||
use crate::prelude::{sink, DisplayHex, String, ToString};
|
use crate::prelude::{sink, String, ToString};
|
||||||
use crate::taproot::{LeafVersion, TapLeafHash};
|
use crate::taproot::{LeafVersion, TapLeafHash};
|
||||||
use crate::{Amount, FeeRate};
|
use crate::{Amount, FeeRate};
|
||||||
|
|
||||||
|
@ -374,12 +375,16 @@ crate::internal_macros::define_extension_trait! {
|
||||||
#[deprecated(since = "TBD", note = "use `to_string()` instead")]
|
#[deprecated(since = "TBD", note = "use `to_string()` instead")]
|
||||||
fn to_asm_string(&self) -> String { self.to_string() }
|
fn to_asm_string(&self) -> String { self.to_string() }
|
||||||
|
|
||||||
/// Formats the script as lower-case hex.
|
/// Consensus encodes the script as lower-case hex.
|
||||||
|
fn to_hex_string(&self) -> String { consensus::encode::serialize_hex(self) }
|
||||||
|
|
||||||
|
/// Consensus encodes the script as lower-case hex.
|
||||||
///
|
///
|
||||||
/// This is a more convenient and performant way to write `format!("{:x}", script)`.
|
/// This is **not** consensus encoding, you likely want to use `to_hex_string`. The returned
|
||||||
/// For better performance you should generally prefer displaying the script but if `String` is
|
/// hex string will not include the length prefix.
|
||||||
/// required (this is common in tests) this method can be used.
|
fn to_hex_string_no_length_prefix(&self) -> String {
|
||||||
fn to_hex_string(&self) -> String { self.as_bytes().to_lower_hex_string() }
|
self.as_bytes().to_lower_hex_string()
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the first opcode of the script (if there is any).
|
/// Returns the first opcode of the script (if there is any).
|
||||||
fn first_opcode(&self) -> Option<Opcode> {
|
fn first_opcode(&self) -> Option<Opcode> {
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
|
|
||||||
use hex::FromHex;
|
use hex::FromHex as _;
|
||||||
use internals::ToU64 as _;
|
use internals::ToU64 as _;
|
||||||
|
|
||||||
use super::{opcode_to_verify, Builder, Instruction, PushBytes, ScriptExtPriv as _};
|
use super::{opcode_to_verify, Builder, Instruction, PushBytes, ScriptExtPriv as _};
|
||||||
|
use crate::consensus;
|
||||||
use crate::opcodes::all::*;
|
use crate::opcodes::all::*;
|
||||||
use crate::opcodes::{self, Opcode};
|
use crate::opcodes::{self, Opcode};
|
||||||
use crate::prelude::Vec;
|
use crate::prelude::Vec;
|
||||||
|
@ -27,7 +28,17 @@ crate::internal_macros::define_extension_trait! {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new [`ScriptBuf`] from a hex string.
|
/// Constructs a new [`ScriptBuf`] from a hex string.
|
||||||
fn from_hex(s: &str) -> Result<ScriptBuf, hex::HexToBytesError> {
|
///
|
||||||
|
/// The input string is expected to be consensus encoded i.e., includes the length prefix.
|
||||||
|
fn from_hex(s: &str) -> Result<ScriptBuf, consensus::FromHexError> {
|
||||||
|
consensus::encode::deserialize_hex(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Constructs a new [`ScriptBuf`] from a hex string.
|
||||||
|
///
|
||||||
|
/// This is **not** consensus encoding. If your hex string is a consensus encode script then
|
||||||
|
/// use `ScriptBuf::from_hex`.
|
||||||
|
fn from_hex_no_length_prefix(s: &str) -> Result<ScriptBuf, hex::HexToBytesError> {
|
||||||
let v = Vec::from_hex(s)?;
|
let v = Vec::from_hex(s)?;
|
||||||
Ok(ScriptBuf::from_bytes(v))
|
Ok(ScriptBuf::from_bytes(v))
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,7 +203,10 @@ fn script_builder() {
|
||||||
.push_opcode(OP_EQUALVERIFY)
|
.push_opcode(OP_EQUALVERIFY)
|
||||||
.push_opcode(OP_CHECKSIG)
|
.push_opcode(OP_CHECKSIG)
|
||||||
.into_script();
|
.into_script();
|
||||||
assert_eq!(script.to_hex_string(), "76a91416e1ae70ff0fa102905d4af297f6912bda6cce1988ac");
|
assert_eq!(
|
||||||
|
script.to_hex_string_no_length_prefix(),
|
||||||
|
"76a91416e1ae70ff0fa102905d4af297f6912bda6cce1988ac"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -236,7 +239,7 @@ fn script_generators() {
|
||||||
let op_return = ScriptBuf::new_op_return(data);
|
let op_return = ScriptBuf::new_op_return(data);
|
||||||
assert!(op_return.is_op_return());
|
assert!(op_return.is_op_return());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
op_return.to_hex_string(),
|
op_return.to_hex_string_no_length_prefix(),
|
||||||
"6a24aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a"
|
"6a24aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -244,42 +247,42 @@ fn script_generators() {
|
||||||
#[test]
|
#[test]
|
||||||
fn script_builder_verify() {
|
fn script_builder_verify() {
|
||||||
let simple = Builder::new().push_verify().into_script();
|
let simple = Builder::new().push_verify().into_script();
|
||||||
assert_eq!(simple.to_hex_string(), "69");
|
assert_eq!(simple.to_hex_string_no_length_prefix(), "69");
|
||||||
let simple2 = Builder::from(vec![]).push_verify().into_script();
|
let simple2 = Builder::from(vec![]).push_verify().into_script();
|
||||||
assert_eq!(simple2.to_hex_string(), "69");
|
assert_eq!(simple2.to_hex_string_no_length_prefix(), "69");
|
||||||
|
|
||||||
let nonverify = Builder::new().push_verify().push_verify().into_script();
|
let nonverify = Builder::new().push_verify().push_verify().into_script();
|
||||||
assert_eq!(nonverify.to_hex_string(), "6969");
|
assert_eq!(nonverify.to_hex_string_no_length_prefix(), "6969");
|
||||||
let nonverify2 = Builder::from(vec![0x69]).push_verify().into_script();
|
let nonverify2 = Builder::from(vec![0x69]).push_verify().into_script();
|
||||||
assert_eq!(nonverify2.to_hex_string(), "6969");
|
assert_eq!(nonverify2.to_hex_string_no_length_prefix(), "6969");
|
||||||
|
|
||||||
let equal = Builder::new().push_opcode(OP_EQUAL).push_verify().into_script();
|
let equal = Builder::new().push_opcode(OP_EQUAL).push_verify().into_script();
|
||||||
assert_eq!(equal.to_hex_string(), "88");
|
assert_eq!(equal.to_hex_string_no_length_prefix(), "88");
|
||||||
let equal2 = Builder::from(vec![0x87]).push_verify().into_script();
|
let equal2 = Builder::from(vec![0x87]).push_verify().into_script();
|
||||||
assert_eq!(equal2.to_hex_string(), "88");
|
assert_eq!(equal2.to_hex_string_no_length_prefix(), "88");
|
||||||
|
|
||||||
let numequal = Builder::new().push_opcode(OP_NUMEQUAL).push_verify().into_script();
|
let numequal = Builder::new().push_opcode(OP_NUMEQUAL).push_verify().into_script();
|
||||||
assert_eq!(numequal.to_hex_string(), "9d");
|
assert_eq!(numequal.to_hex_string_no_length_prefix(), "9d");
|
||||||
let numequal2 = Builder::from(vec![0x9c]).push_verify().into_script();
|
let numequal2 = Builder::from(vec![0x9c]).push_verify().into_script();
|
||||||
assert_eq!(numequal2.to_hex_string(), "9d");
|
assert_eq!(numequal2.to_hex_string_no_length_prefix(), "9d");
|
||||||
|
|
||||||
let checksig = Builder::new().push_opcode(OP_CHECKSIG).push_verify().into_script();
|
let checksig = Builder::new().push_opcode(OP_CHECKSIG).push_verify().into_script();
|
||||||
assert_eq!(checksig.to_hex_string(), "ad");
|
assert_eq!(checksig.to_hex_string_no_length_prefix(), "ad");
|
||||||
let checksig2 = Builder::from(vec![0xac]).push_verify().into_script();
|
let checksig2 = Builder::from(vec![0xac]).push_verify().into_script();
|
||||||
assert_eq!(checksig2.to_hex_string(), "ad");
|
assert_eq!(checksig2.to_hex_string_no_length_prefix(), "ad");
|
||||||
|
|
||||||
let checkmultisig = Builder::new().push_opcode(OP_CHECKMULTISIG).push_verify().into_script();
|
let checkmultisig = Builder::new().push_opcode(OP_CHECKMULTISIG).push_verify().into_script();
|
||||||
assert_eq!(checkmultisig.to_hex_string(), "af");
|
assert_eq!(checkmultisig.to_hex_string_no_length_prefix(), "af");
|
||||||
let checkmultisig2 = Builder::from(vec![0xae]).push_verify().into_script();
|
let checkmultisig2 = Builder::from(vec![0xae]).push_verify().into_script();
|
||||||
assert_eq!(checkmultisig2.to_hex_string(), "af");
|
assert_eq!(checkmultisig2.to_hex_string_no_length_prefix(), "af");
|
||||||
|
|
||||||
let trick_slice = Builder::new()
|
let trick_slice = Builder::new()
|
||||||
.push_slice([0xae]) // OP_CHECKMULTISIG
|
.push_slice([0xae]) // OP_CHECKMULTISIG
|
||||||
.push_verify()
|
.push_verify()
|
||||||
.into_script();
|
.into_script();
|
||||||
assert_eq!(trick_slice.to_hex_string(), "01ae69");
|
assert_eq!(trick_slice.to_hex_string_no_length_prefix(), "01ae69");
|
||||||
let trick_slice2 = Builder::from(vec![0x01, 0xae]).push_verify().into_script();
|
let trick_slice2 = Builder::from(vec![0x01, 0xae]).push_verify().into_script();
|
||||||
assert_eq!(trick_slice2.to_hex_string(), "01ae69");
|
assert_eq!(trick_slice2.to_hex_string_no_length_prefix(), "01ae69");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -373,7 +376,7 @@ fn non_minimal_scriptints() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn script_hashes() {
|
fn script_hashes() {
|
||||||
let script = ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap();
|
let script = ScriptBuf::from_hex_no_length_prefix("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
script.script_hash().unwrap().to_string(),
|
script.script_hash().unwrap().to_string(),
|
||||||
"8292bcfbef1884f73c813dfe9c82fd7e814291ea"
|
"8292bcfbef1884f73c813dfe9c82fd7e814291ea"
|
||||||
|
@ -383,10 +386,12 @@ fn script_hashes() {
|
||||||
"3e1525eb183ad4f9b3c5fa3175bdca2a52e947b135bbb90383bf9f6408e2c324"
|
"3e1525eb183ad4f9b3c5fa3175bdca2a52e947b135bbb90383bf9f6408e2c324"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ScriptBuf::from_hex("20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac")
|
ScriptBuf::from_hex_no_length_prefix(
|
||||||
.unwrap()
|
"20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac"
|
||||||
.tapscript_leaf_hash()
|
)
|
||||||
.to_string(),
|
.unwrap()
|
||||||
|
.tapscript_leaf_hash()
|
||||||
|
.to_string(),
|
||||||
"5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21"
|
"5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -394,40 +399,50 @@ fn script_hashes() {
|
||||||
#[test]
|
#[test]
|
||||||
fn provably_unspendable() {
|
fn provably_unspendable() {
|
||||||
// p2pk
|
// p2pk
|
||||||
assert!(!ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap().is_op_return());
|
assert!(!ScriptBuf::from_hex_no_length_prefix("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap().is_op_return());
|
||||||
assert!(!ScriptBuf::from_hex("4104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").unwrap().is_op_return());
|
assert!(!ScriptBuf::from_hex_no_length_prefix("4104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").unwrap().is_op_return());
|
||||||
// p2pkhash
|
// p2pkhash
|
||||||
assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac")
|
assert!(!ScriptBuf::from_hex_no_length_prefix(
|
||||||
.unwrap()
|
"76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac"
|
||||||
.is_op_return());
|
)
|
||||||
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87")
|
.unwrap()
|
||||||
.unwrap()
|
.is_op_return());
|
||||||
.is_op_return());
|
assert!(ScriptBuf::from_hex_no_length_prefix(
|
||||||
|
"6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.is_op_return());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn op_return() {
|
fn op_return() {
|
||||||
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87")
|
assert!(ScriptBuf::from_hex_no_length_prefix(
|
||||||
.unwrap()
|
"6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87"
|
||||||
.is_op_return());
|
)
|
||||||
assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac")
|
.unwrap()
|
||||||
.unwrap()
|
.is_op_return());
|
||||||
.is_op_return());
|
assert!(!ScriptBuf::from_hex_no_length_prefix(
|
||||||
assert!(!ScriptBuf::from_hex("").unwrap().is_op_return());
|
"76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.is_op_return());
|
||||||
|
assert!(!ScriptBuf::from_hex_no_length_prefix("").unwrap().is_op_return());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn standard_op_return() {
|
fn standard_op_return() {
|
||||||
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87")
|
assert!(ScriptBuf::from_hex_no_length_prefix(
|
||||||
|
"6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.is_standard_op_return());
|
||||||
|
assert!(ScriptBuf::from_hex_no_length_prefix("6a48656c6c6f2c2074686973206973206d7920666972737420636f6e747269627574696f6e20746f207275737420626974636f696e2e20506c6561736520617070726f7665206d79205052206672656e")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_standard_op_return());
|
.is_standard_op_return());
|
||||||
assert!(ScriptBuf::from_hex("6a48656c6c6f2c2074686973206973206d7920666972737420636f6e747269627574696f6e20746f207275737420626974636f696e2e20506c6561736520617070726f7665206d79205052206672656e")
|
assert!(ScriptBuf::from_hex_no_length_prefix("6a48656c6c6f2c2074686973206973206d7920666972737420636f6e747269627574696f6e20746f207275737420626974636f696e2e20506c6561736520617070726f7665206d79205052206672656e21")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_standard_op_return());
|
.is_standard_op_return());
|
||||||
assert!(ScriptBuf::from_hex("6a48656c6c6f2c2074686973206973206d7920666972737420636f6e747269627574696f6e20746f207275737420626974636f696e2e20506c6561736520617070726f7665206d79205052206672656e21")
|
assert!(!ScriptBuf::from_hex_no_length_prefix("6a48656c6c6f2c2074686973206973206d7920666972737420636f6e747269627574696f6e20746f207275737420626974636f696e2e20506c6561736520617070726f7665206d79205052206672656e21524f42")
|
||||||
.unwrap()
|
|
||||||
.is_standard_op_return());
|
|
||||||
assert!(!ScriptBuf::from_hex("6a48656c6c6f2c2074686973206973206d7920666972737420636f6e747269627574696f6e20746f207275737420626974636f696e2e20506c6561736520617070726f7665206d79205052206672656e21524f42")
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_standard_op_return());
|
.is_standard_op_return());
|
||||||
}
|
}
|
||||||
|
@ -437,46 +452,48 @@ fn multisig() {
|
||||||
// First multisig? 1-of-2
|
// First multisig? 1-of-2
|
||||||
// In block 164467, txid 60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1
|
// In block 164467, txid 60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1
|
||||||
assert!(
|
assert!(
|
||||||
ScriptBuf::from_hex("514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae")
|
ScriptBuf::from_hex_no_length_prefix("514104cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4410461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af52ae")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_multisig()
|
.is_multisig()
|
||||||
);
|
);
|
||||||
// 2-of-2
|
// 2-of-2
|
||||||
assert!(
|
assert!(
|
||||||
ScriptBuf::from_hex("5221021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f452ae")
|
ScriptBuf::from_hex_no_length_prefix("5221021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f452ae")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_multisig()
|
.is_multisig()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Extra opcode after OP_CHECKMULTISIG
|
// Extra opcode after OP_CHECKMULTISIG
|
||||||
assert!(
|
assert!(
|
||||||
!ScriptBuf::from_hex("5221021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f452ae52")
|
!ScriptBuf::from_hex_no_length_prefix("5221021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f452ae52")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_multisig()
|
.is_multisig()
|
||||||
);
|
);
|
||||||
// Required sigs > num pubkeys
|
// Required sigs > num pubkeys
|
||||||
assert!(
|
assert!(
|
||||||
!ScriptBuf::from_hex("5321021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f452ae")
|
!ScriptBuf::from_hex_no_length_prefix("5321021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f452ae")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_multisig()
|
.is_multisig()
|
||||||
);
|
);
|
||||||
// Num pubkeys != pushnum
|
// Num pubkeys != pushnum
|
||||||
assert!(
|
assert!(
|
||||||
!ScriptBuf::from_hex("5221021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f453ae")
|
!ScriptBuf::from_hex_no_length_prefix("5221021c4ac2ecebc398e390e07f045aac5cc421f82f0739c1ce724d3d53964dc6537d21023a2e9155e0b62f76737605504819a2b4e5ce20653f6c397d7a178ae42ba702f453ae")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_multisig()
|
.is_multisig()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Taproot hash from another test
|
// Taproot hash from another test
|
||||||
assert!(!ScriptBuf::from_hex(
|
assert!(!ScriptBuf::from_hex_no_length_prefix(
|
||||||
"20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac"
|
"20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac"
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_multisig());
|
.is_multisig());
|
||||||
// OP_RETURN from another test
|
// OP_RETURN from another test
|
||||||
assert!(!ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87")
|
assert!(!ScriptBuf::from_hex_no_length_prefix(
|
||||||
.unwrap()
|
"6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87"
|
||||||
.is_multisig());
|
)
|
||||||
|
.unwrap()
|
||||||
|
.is_multisig());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -484,7 +501,7 @@ fn multisig() {
|
||||||
fn script_json_serialize() {
|
fn script_json_serialize() {
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
let original = ScriptBuf::from_hex("827651a0698faaa9a8a7a687").unwrap();
|
let original = ScriptBuf::from_hex_no_length_prefix("827651a0698faaa9a8a7a687").unwrap();
|
||||||
let json = serde_json::to_value(&original).unwrap();
|
let json = serde_json::to_value(&original).unwrap();
|
||||||
assert_eq!(json, serde_json::Value::String("827651a0698faaa9a8a7a687".to_owned()));
|
assert_eq!(json, serde_json::Value::String("827651a0698faaa9a8a7a687".to_owned()));
|
||||||
let des = serde_json::from_value::<ScriptBuf>(json).unwrap();
|
let des = serde_json::from_value::<ScriptBuf>(json).unwrap();
|
||||||
|
@ -494,27 +511,36 @@ fn script_json_serialize() {
|
||||||
#[test]
|
#[test]
|
||||||
fn script_asm() {
|
fn script_asm() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ScriptBuf::from_hex("6363636363686868686800").unwrap().to_string(),
|
ScriptBuf::from_hex_no_length_prefix("6363636363686868686800").unwrap().to_string(),
|
||||||
"OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"
|
"OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"
|
||||||
);
|
);
|
||||||
assert_eq!(ScriptBuf::from_hex("2102715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699ac").unwrap().to_string(),
|
assert_eq!(ScriptBuf::from_hex_no_length_prefix("2102715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699ac").unwrap().to_string(),
|
||||||
"OP_PUSHBYTES_33 02715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699 OP_CHECKSIG");
|
"OP_PUSHBYTES_33 02715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699 OP_CHECKSIG");
|
||||||
// Elements Alpha peg-out transaction with some signatures removed for brevity. Mainly to test PUSHDATA1
|
// Elements Alpha peg-out transaction with some signatures removed for brevity. Mainly to test PUSHDATA1
|
||||||
assert_eq!(ScriptBuf::from_hex("0047304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401004cf1552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae").unwrap().to_string(),
|
assert_eq!(ScriptBuf::from_hex_no_length_prefix("0047304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401004cf1552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae").unwrap().to_string(),
|
||||||
"OP_0 OP_PUSHBYTES_71 304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401 OP_0 OP_PUSHDATA1 552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae");
|
"OP_0 OP_PUSHBYTES_71 304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401 OP_0 OP_PUSHDATA1 552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae");
|
||||||
// Various weird scripts found in transaction 6d7ed9914625c73c0288694a6819196a27ef6c08f98e1270d975a8e65a3dc09a
|
// Various weird scripts found in transaction 6d7ed9914625c73c0288694a6819196a27ef6c08f98e1270d975a8e65a3dc09a
|
||||||
// which triggered overflow bugs on 32-bit machines in script formatting in the past.
|
// which triggered overflow bugs on 32-bit machines in script formatting in the past.
|
||||||
assert_eq!(ScriptBuf::from_hex("01").unwrap().to_string(), "OP_PUSHBYTES_1 <push past end>");
|
|
||||||
assert_eq!(ScriptBuf::from_hex("0201").unwrap().to_string(), "OP_PUSHBYTES_2 <push past end>");
|
|
||||||
assert_eq!(ScriptBuf::from_hex("4c").unwrap().to_string(), "<unexpected end>");
|
|
||||||
assert_eq!(ScriptBuf::from_hex("4c0201").unwrap().to_string(), "OP_PUSHDATA1 <push past end>");
|
|
||||||
assert_eq!(ScriptBuf::from_hex("4d").unwrap().to_string(), "<unexpected end>");
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ScriptBuf::from_hex("4dffff01").unwrap().to_string(),
|
ScriptBuf::from_hex_no_length_prefix("01").unwrap().to_string(),
|
||||||
|
"OP_PUSHBYTES_1 <push past end>"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ScriptBuf::from_hex_no_length_prefix("0201").unwrap().to_string(),
|
||||||
|
"OP_PUSHBYTES_2 <push past end>"
|
||||||
|
);
|
||||||
|
assert_eq!(ScriptBuf::from_hex_no_length_prefix("4c").unwrap().to_string(), "<unexpected end>");
|
||||||
|
assert_eq!(
|
||||||
|
ScriptBuf::from_hex_no_length_prefix("4c0201").unwrap().to_string(),
|
||||||
|
"OP_PUSHDATA1 <push past end>"
|
||||||
|
);
|
||||||
|
assert_eq!(ScriptBuf::from_hex_no_length_prefix("4d").unwrap().to_string(), "<unexpected end>");
|
||||||
|
assert_eq!(
|
||||||
|
ScriptBuf::from_hex_no_length_prefix("4dffff01").unwrap().to_string(),
|
||||||
"OP_PUSHDATA2 <push past end>"
|
"OP_PUSHDATA2 <push past end>"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ScriptBuf::from_hex("4effffffff01").unwrap().to_string(),
|
ScriptBuf::from_hex_no_length_prefix("4effffffff01").unwrap().to_string(),
|
||||||
"OP_PUSHDATA4 <push past end>"
|
"OP_PUSHDATA4 <push past end>"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -522,69 +548,83 @@ fn script_asm() {
|
||||||
#[test]
|
#[test]
|
||||||
fn script_buf_collect() {
|
fn script_buf_collect() {
|
||||||
assert_eq!(&core::iter::empty::<Instruction<'_>>().collect::<ScriptBuf>(), Script::new());
|
assert_eq!(&core::iter::empty::<Instruction<'_>>().collect::<ScriptBuf>(), Script::new());
|
||||||
let script = ScriptBuf::from_hex("0047304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401004cf1552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae").unwrap();
|
let script = ScriptBuf::from_hex_no_length_prefix("0047304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401004cf1552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae").unwrap();
|
||||||
assert_eq!(script.instructions().collect::<Result<ScriptBuf, _>>().unwrap(), script);
|
assert_eq!(script.instructions().collect::<Result<ScriptBuf, _>>().unwrap(), script);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn script_p2sh_p2p2k_template() {
|
fn script_p2sh_p2p2k_template() {
|
||||||
// random outputs I picked out of the mempool
|
// random outputs I picked out of the mempool
|
||||||
assert!(ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac")
|
assert!(ScriptBuf::from_hex_no_length_prefix(
|
||||||
.unwrap()
|
"76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac"
|
||||||
.is_p2pkh());
|
)
|
||||||
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac")
|
.unwrap()
|
||||||
.unwrap()
|
.is_p2pkh());
|
||||||
.is_p2sh());
|
assert!(!ScriptBuf::from_hex_no_length_prefix(
|
||||||
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ad")
|
"76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac"
|
||||||
.unwrap()
|
)
|
||||||
.is_p2pkh());
|
.unwrap()
|
||||||
assert!(!ScriptBuf::from_hex("").unwrap().is_p2pkh());
|
.is_p2sh());
|
||||||
assert!(ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
|
assert!(!ScriptBuf::from_hex_no_length_prefix(
|
||||||
.unwrap()
|
"76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ad"
|
||||||
.is_p2sh());
|
)
|
||||||
assert!(!ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
|
.unwrap()
|
||||||
.unwrap()
|
.is_p2pkh());
|
||||||
.is_p2pkh());
|
assert!(!ScriptBuf::from_hex_no_length_prefix("").unwrap().is_p2pkh());
|
||||||
assert!(!ScriptBuf::from_hex("a314acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
|
assert!(ScriptBuf::from_hex_no_length_prefix("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_p2sh());
|
.is_p2sh());
|
||||||
|
assert!(!ScriptBuf::from_hex_no_length_prefix(
|
||||||
|
"a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.is_p2pkh());
|
||||||
|
assert!(!ScriptBuf::from_hex_no_length_prefix(
|
||||||
|
"a314acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.is_p2sh());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn script_p2pk() {
|
fn script_p2pk() {
|
||||||
assert!(ScriptBuf::from_hex(
|
assert!(ScriptBuf::from_hex_no_length_prefix(
|
||||||
"21021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac"
|
"21021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac"
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.is_p2pk());
|
.is_p2pk());
|
||||||
assert!(ScriptBuf::from_hex("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac").unwrap().is_p2pk());
|
assert!(ScriptBuf::from_hex_no_length_prefix("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac").unwrap().is_p2pk());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn p2sh_p2wsh_conversion() {
|
fn p2sh_p2wsh_conversion() {
|
||||||
// Test vectors taken from Core tests/data/script_tests.json
|
// Test vectors taken from Core tests/data/script_tests.json
|
||||||
// bare p2wsh
|
// bare p2wsh
|
||||||
let witness_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
|
let witness_script = ScriptBuf::from_hex_no_length_prefix("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
|
||||||
let expected_without =
|
let expected_without = ScriptBuf::from_hex_no_length_prefix(
|
||||||
ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64")
|
"0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64",
|
||||||
.unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
assert!(witness_script.to_p2wsh().unwrap().is_p2wsh());
|
assert!(witness_script.to_p2wsh().unwrap().is_p2wsh());
|
||||||
assert_eq!(witness_script.to_p2wsh().unwrap(), expected_without);
|
assert_eq!(witness_script.to_p2wsh().unwrap(), expected_without);
|
||||||
|
|
||||||
// p2sh
|
// p2sh
|
||||||
let redeem_script = ScriptBuf::from_hex("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8").unwrap();
|
let redeem_script = ScriptBuf::from_hex_no_length_prefix("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8").unwrap();
|
||||||
let expected_p2shout =
|
let expected_p2shout =
|
||||||
ScriptBuf::from_hex("a91491b24bf9f5288532960ac687abb035127b1d28a587").unwrap();
|
ScriptBuf::from_hex_no_length_prefix("a91491b24bf9f5288532960ac687abb035127b1d28a587")
|
||||||
|
.unwrap();
|
||||||
assert!(redeem_script.to_p2sh().unwrap().is_p2sh());
|
assert!(redeem_script.to_p2sh().unwrap().is_p2sh());
|
||||||
assert_eq!(redeem_script.to_p2sh().unwrap(), expected_p2shout);
|
assert_eq!(redeem_script.to_p2sh().unwrap(), expected_p2shout);
|
||||||
|
|
||||||
// p2sh-p2wsh
|
// p2sh-p2wsh
|
||||||
let witness_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
|
let witness_script = ScriptBuf::from_hex_no_length_prefix("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
|
||||||
let expected_without =
|
let expected_without = ScriptBuf::from_hex_no_length_prefix(
|
||||||
ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64")
|
"0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64",
|
||||||
.unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
let expected_out =
|
let expected_out =
|
||||||
ScriptBuf::from_hex("a914f386c2ba255cc56d20cfa6ea8b062f8b5994551887").unwrap();
|
ScriptBuf::from_hex_no_length_prefix("a914f386c2ba255cc56d20cfa6ea8b062f8b5994551887")
|
||||||
|
.unwrap();
|
||||||
assert!(witness_script.to_p2sh().unwrap().is_p2sh());
|
assert!(witness_script.to_p2sh().unwrap().is_p2sh());
|
||||||
assert_eq!(witness_script.to_p2wsh().unwrap(), expected_without);
|
assert_eq!(witness_script.to_p2wsh().unwrap(), expected_without);
|
||||||
assert_eq!(witness_script.to_p2wsh().unwrap().to_p2sh().unwrap(), expected_out);
|
assert_eq!(witness_script.to_p2wsh().unwrap().to_p2sh().unwrap(), expected_out);
|
||||||
|
@ -600,12 +640,12 @@ macro_rules! unwrap_all {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn iterator() {
|
fn iterator() {
|
||||||
let zero = ScriptBuf::from_hex("00").unwrap();
|
let zero = ScriptBuf::from_hex_no_length_prefix("00").unwrap();
|
||||||
let zeropush = ScriptBuf::from_hex("0100").unwrap();
|
let zeropush = ScriptBuf::from_hex_no_length_prefix("0100").unwrap();
|
||||||
|
|
||||||
let nonminimal = ScriptBuf::from_hex("4c0169b2").unwrap(); // PUSHDATA1 for no reason
|
let nonminimal = ScriptBuf::from_hex_no_length_prefix("4c0169b2").unwrap(); // PUSHDATA1 for no reason
|
||||||
let minimal = ScriptBuf::from_hex("0169b2").unwrap(); // minimal
|
let minimal = ScriptBuf::from_hex_no_length_prefix("0169b2").unwrap(); // minimal
|
||||||
let nonminimal_alt = ScriptBuf::from_hex("026900b2").unwrap(); // non-minimal number but minimal push (should be OK)
|
let nonminimal_alt = ScriptBuf::from_hex_no_length_prefix("026900b2").unwrap(); // non-minimal number but minimal push (should be OK)
|
||||||
|
|
||||||
let v_zero: Result<Vec<_>, Error> = zero.instruction_indices_minimal().collect();
|
let v_zero: Result<Vec<_>, Error> = zero.instruction_indices_minimal().collect();
|
||||||
let v_zeropush: Result<Vec<_>, Error> = zeropush.instruction_indices_minimal().collect();
|
let v_zeropush: Result<Vec<_>, Error> = zeropush.instruction_indices_minimal().collect();
|
||||||
|
|
|
@ -1832,7 +1832,7 @@ mod tests {
|
||||||
|
|
||||||
let leaf_hash = match (script_hex, script_leaf_hash) {
|
let leaf_hash = match (script_hex, script_leaf_hash) {
|
||||||
(Some(script_hex), _) => {
|
(Some(script_hex), _) => {
|
||||||
let script_inner = ScriptBuf::from_hex(script_hex).unwrap();
|
let script_inner = ScriptBuf::from_hex_no_length_prefix(script_hex).unwrap();
|
||||||
Some(ScriptPath::with_defaults(&script_inner).leaf_hash())
|
Some(ScriptPath::with_defaults(&script_inner).leaf_hash())
|
||||||
}
|
}
|
||||||
(_, Some(script_leaf_hash)) => Some(script_leaf_hash.parse::<TapLeafHash>().unwrap()),
|
(_, Some(script_leaf_hash)) => Some(script_leaf_hash.parse::<TapLeafHash>().unwrap()),
|
||||||
|
@ -2089,7 +2089,9 @@ mod tests {
|
||||||
),
|
),
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let spk = ScriptBuf::from_hex("00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1").unwrap();
|
let spk =
|
||||||
|
ScriptBuf::from_hex_no_length_prefix("00141d0f172a0ecb48aee1be1f2687d2963ae33f71a1")
|
||||||
|
.unwrap();
|
||||||
let value = Amount::from_sat_u32(600_000_000);
|
let value = Amount::from_sat_u32(600_000_000);
|
||||||
|
|
||||||
let mut cache = SighashCache::new(&tx);
|
let mut cache = SighashCache::new(&tx);
|
||||||
|
@ -2130,7 +2132,8 @@ mod tests {
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
let redeem_script =
|
let redeem_script =
|
||||||
ScriptBuf::from_hex("001479091972186c449eb1ded22b78e40d009bdf0089").unwrap();
|
ScriptBuf::from_hex_no_length_prefix("001479091972186c449eb1ded22b78e40d009bdf0089")
|
||||||
|
.unwrap();
|
||||||
let value = Amount::from_sat_u32(1_000_000_000);
|
let value = Amount::from_sat_u32(1_000_000_000);
|
||||||
|
|
||||||
let mut cache = SighashCache::new(&tx);
|
let mut cache = SighashCache::new(&tx);
|
||||||
|
@ -2171,7 +2174,7 @@ mod tests {
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let witness_script = ScriptBuf::from_hex(
|
let witness_script = ScriptBuf::from_hex_no_length_prefix(
|
||||||
"56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28\
|
"56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28\
|
||||||
bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b\
|
bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b\
|
||||||
9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58\
|
9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58\
|
||||||
|
|
|
@ -1336,7 +1336,7 @@ mod tests {
|
||||||
}],
|
}],
|
||||||
output: vec![TxOut {
|
output: vec![TxOut {
|
||||||
value: Amount::from_sat(output).unwrap(),
|
value: Amount::from_sat(output).unwrap(),
|
||||||
script_pubkey: ScriptBuf::from_hex(
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(
|
||||||
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
|
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -1350,7 +1350,7 @@ mod tests {
|
||||||
inputs: vec![Input {
|
inputs: vec![Input {
|
||||||
witness_utxo: Some(TxOut {
|
witness_utxo: Some(TxOut {
|
||||||
value: Amount::from_sat(input).unwrap(),
|
value: Amount::from_sat(input).unwrap(),
|
||||||
script_pubkey: ScriptBuf::from_hex(
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(
|
||||||
"a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
|
"a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -1463,10 +1463,16 @@ mod tests {
|
||||||
|
|
||||||
let expected: Output = Output {
|
let expected: Output = Output {
|
||||||
redeem_script: Some(
|
redeem_script: Some(
|
||||||
ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
|
ScriptBuf::from_hex_no_length_prefix(
|
||||||
|
"76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
),
|
),
|
||||||
witness_script: Some(
|
witness_script: Some(
|
||||||
ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
|
ScriptBuf::from_hex_no_length_prefix(
|
||||||
|
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
),
|
),
|
||||||
bip32_derivation: hd_keypaths,
|
bip32_derivation: hd_keypaths,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -1497,14 +1503,14 @@ mod tests {
|
||||||
output: vec![
|
output: vec![
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat_u32(99_999_699),
|
value: Amount::from_sat_u32(99_999_699),
|
||||||
script_pubkey: ScriptBuf::from_hex(
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(
|
||||||
"76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac",
|
"76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac",
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
},
|
},
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat_u32(100_000_000),
|
value: Amount::from_sat_u32(100_000_000),
|
||||||
script_pubkey: ScriptBuf::from_hex(
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(
|
||||||
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
|
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -1561,8 +1567,10 @@ mod tests {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
vout: 1,
|
vout: 1,
|
||||||
},
|
},
|
||||||
script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985")
|
script_sig: ScriptBuf::from_hex_no_length_prefix(
|
||||||
.unwrap(),
|
"160014be18d152a9b012039daf3da7de4f53349eecb985",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
sequence: Sequence::MAX,
|
sequence: Sequence::MAX,
|
||||||
witness: Witness::from_slice(&[hex!(
|
witness: Witness::from_slice(&[hex!(
|
||||||
"03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105"
|
"03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105"
|
||||||
|
@ -1570,7 +1578,7 @@ mod tests {
|
||||||
}],
|
}],
|
||||||
output: vec![TxOut {
|
output: vec![TxOut {
|
||||||
value: Amount::from_sat(190_303_501_938).unwrap(),
|
value: Amount::from_sat(190_303_501_938).unwrap(),
|
||||||
script_pubkey: ScriptBuf::from_hex(
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(
|
||||||
"a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
|
"a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
@ -1621,7 +1629,7 @@ mod tests {
|
||||||
non_witness_utxo: Some(tx),
|
non_witness_utxo: Some(tx),
|
||||||
witness_utxo: Some(TxOut {
|
witness_utxo: Some(TxOut {
|
||||||
value: Amount::from_sat(190_303_501_938).unwrap(),
|
value: Amount::from_sat(190_303_501_938).unwrap(),
|
||||||
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
||||||
}),
|
}),
|
||||||
sighash_type: Some("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse::<PsbtSighashType>().unwrap()),
|
sighash_type: Some("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse::<PsbtSighashType>().unwrap()),
|
||||||
redeem_script: Some(vec![0x51].into()),
|
redeem_script: Some(vec![0x51].into()),
|
||||||
|
@ -1746,11 +1754,11 @@ mod tests {
|
||||||
output: vec![
|
output: vec![
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat_u32(99_999_699),
|
value: Amount::from_sat_u32(99_999_699),
|
||||||
script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
|
||||||
},
|
},
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat_u32(100_000_000),
|
value: Amount::from_sat_u32(100_000_000),
|
||||||
script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -1770,7 +1778,7 @@ mod tests {
|
||||||
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
|
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
|
||||||
vout: 1,
|
vout: 1,
|
||||||
},
|
},
|
||||||
script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
|
script_sig: ScriptBuf::from_hex_no_length_prefix("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
|
||||||
sequence: Sequence::MAX,
|
sequence: Sequence::MAX,
|
||||||
witness: Witness::from_slice(&[
|
witness: Witness::from_slice(&[
|
||||||
hex!("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01").as_slice(),
|
hex!("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01").as_slice(),
|
||||||
|
@ -1782,7 +1790,7 @@ mod tests {
|
||||||
txid: "b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886".parse().unwrap(),
|
txid: "b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886".parse().unwrap(),
|
||||||
vout: 1,
|
vout: 1,
|
||||||
},
|
},
|
||||||
script_sig: ScriptBuf::from_hex("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
|
script_sig: ScriptBuf::from_hex_no_length_prefix("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
|
||||||
sequence: Sequence::MAX,
|
sequence: Sequence::MAX,
|
||||||
witness: Witness::from_slice(&[
|
witness: Witness::from_slice(&[
|
||||||
hex!("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01").as_slice(),
|
hex!("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01").as_slice(),
|
||||||
|
@ -1793,11 +1801,11 @@ mod tests {
|
||||||
output: vec![
|
output: vec![
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat_u32(200_000_000),
|
value: Amount::from_sat_u32(200_000_000),
|
||||||
script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
|
||||||
},
|
},
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat(190_303_501_938).unwrap(),
|
value: Amount::from_sat(190_303_501_938).unwrap(),
|
||||||
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
@ -1838,8 +1846,10 @@ mod tests {
|
||||||
assert!(&psbt.inputs[0].final_script_sig.is_some());
|
assert!(&psbt.inputs[0].final_script_sig.is_some());
|
||||||
|
|
||||||
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
|
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
|
||||||
let expected_out =
|
let expected_out = ScriptBuf::from_hex_no_length_prefix(
|
||||||
ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
|
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(redeem_script.is_p2wpkh());
|
assert!(redeem_script.is_p2wpkh());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1884,8 +1894,10 @@ mod tests {
|
||||||
assert!(&psbt.inputs[1].final_script_sig.is_none());
|
assert!(&psbt.inputs[1].final_script_sig.is_none());
|
||||||
|
|
||||||
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
|
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
|
||||||
let expected_out =
|
let expected_out = ScriptBuf::from_hex_no_length_prefix(
|
||||||
ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
|
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(redeem_script.is_p2wpkh());
|
assert!(redeem_script.is_p2wpkh());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1909,8 +1921,10 @@ mod tests {
|
||||||
assert!(&psbt.inputs[0].final_script_sig.is_none());
|
assert!(&psbt.inputs[0].final_script_sig.is_none());
|
||||||
|
|
||||||
let redeem_script = psbt.inputs[0].redeem_script.as_ref().unwrap();
|
let redeem_script = psbt.inputs[0].redeem_script.as_ref().unwrap();
|
||||||
let expected_out =
|
let expected_out = ScriptBuf::from_hex_no_length_prefix(
|
||||||
ScriptBuf::from_hex("a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87").unwrap();
|
"a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
assert!(redeem_script.is_p2wsh());
|
assert!(redeem_script.is_p2wsh());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -2079,11 +2093,11 @@ mod tests {
|
||||||
output: vec![
|
output: vec![
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat_u32(99_999_699),
|
value: Amount::from_sat_u32(99_999_699),
|
||||||
script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
|
||||||
},
|
},
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat_u32(100_000_000),
|
value: Amount::from_sat_u32(100_000_000),
|
||||||
script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -2103,7 +2117,7 @@ mod tests {
|
||||||
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
|
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
|
||||||
vout: 1,
|
vout: 1,
|
||||||
},
|
},
|
||||||
script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
|
script_sig: ScriptBuf::from_hex_no_length_prefix("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
|
||||||
sequence: Sequence::MAX,
|
sequence: Sequence::MAX,
|
||||||
witness: Witness::from_slice(&[
|
witness: Witness::from_slice(&[
|
||||||
hex!("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01").as_slice(),
|
hex!("304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c01").as_slice(),
|
||||||
|
@ -2115,7 +2129,7 @@ mod tests {
|
||||||
txid: "b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886".parse().unwrap(),
|
txid: "b490486aec3ae671012dddb2bb08466bef37720a533a894814ff1da743aaf886".parse().unwrap(),
|
||||||
vout: 1,
|
vout: 1,
|
||||||
},
|
},
|
||||||
script_sig: ScriptBuf::from_hex("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
|
script_sig: ScriptBuf::from_hex_no_length_prefix("160014fe3e9ef1a745e974d902c4355943abcb34bd5353").unwrap(),
|
||||||
sequence: Sequence::MAX,
|
sequence: Sequence::MAX,
|
||||||
witness: Witness::from_slice(&[
|
witness: Witness::from_slice(&[
|
||||||
hex!("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01").as_slice(),
|
hex!("3045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01").as_slice(),
|
||||||
|
@ -2126,11 +2140,11 @@ mod tests {
|
||||||
output: vec![
|
output: vec![
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat_u32(200_000_000),
|
value: Amount::from_sat_u32(200_000_000),
|
||||||
script_pubkey: ScriptBuf::from_hex("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("76a91485cff1097fd9e008bb34af709c62197b38978a4888ac").unwrap(),
|
||||||
},
|
},
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_sat(190_303_501_938).unwrap(),
|
value: Amount::from_sat(190_303_501_938).unwrap(),
|
||||||
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -414,7 +414,7 @@ mod tests {
|
||||||
let mut val = opcode;
|
let mut val = opcode;
|
||||||
let mut builder = TaprootBuilder::new();
|
let mut builder = TaprootBuilder::new();
|
||||||
for depth in depth_map {
|
for depth in depth_map {
|
||||||
let script = ScriptBuf::from_hex(&format!("{:02x}", val)).unwrap();
|
let script = ScriptBuf::from_hex_no_length_prefix(&format!("{:02x}", val)).unwrap();
|
||||||
builder = builder.add_leaf(*depth, script).unwrap();
|
builder = builder.add_leaf(*depth, script).unwrap();
|
||||||
let (new_val, _) = val.overflowing_add(1);
|
let (new_val, _) = val.overflowing_add(1);
|
||||||
val = new_val;
|
val = new_val;
|
||||||
|
@ -429,7 +429,7 @@ mod tests {
|
||||||
builder = builder
|
builder = builder
|
||||||
.add_leaf_with_ver(
|
.add_leaf_with_ver(
|
||||||
3,
|
3,
|
||||||
ScriptBuf::from_hex("b9").unwrap(),
|
ScriptBuf::from_hex_no_length_prefix("b9").unwrap(),
|
||||||
LeafVersion::from_consensus(0xC2).unwrap(),
|
LeafVersion::from_consensus(0xC2).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -443,7 +443,7 @@ mod tests {
|
||||||
builder = builder
|
builder = builder
|
||||||
.add_leaf_with_ver(
|
.add_leaf_with_ver(
|
||||||
3,
|
3,
|
||||||
ScriptBuf::from_hex("b9").unwrap(),
|
ScriptBuf::from_hex_no_length_prefix("b9").unwrap(),
|
||||||
LeafVersion::from_consensus(0xC2).unwrap(),
|
LeafVersion::from_consensus(0xC2).unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -1781,7 +1781,7 @@ mod test {
|
||||||
) {
|
) {
|
||||||
let out_pk = out_spk_hex[4..].parse::<XOnlyPublicKey>().unwrap();
|
let out_pk = out_spk_hex[4..].parse::<XOnlyPublicKey>().unwrap();
|
||||||
let out_pk = TweakedPublicKey::dangerous_assume_tweaked(out_pk);
|
let out_pk = TweakedPublicKey::dangerous_assume_tweaked(out_pk);
|
||||||
let script = ScriptBuf::from_hex(script_hex).unwrap();
|
let script = ScriptBuf::from_hex_no_length_prefix(script_hex).unwrap();
|
||||||
let control_block = ControlBlock::from_hex(control_block_hex).unwrap();
|
let control_block = ControlBlock::from_hex(control_block_hex).unwrap();
|
||||||
assert_eq!(control_block_hex, control_block.serialize().to_lower_hex_string());
|
assert_eq!(control_block_hex, control_block.serialize().to_lower_hex_string());
|
||||||
assert!(control_block.verify_taproot_commitment(secp, out_pk.to_inner(), &script));
|
assert!(control_block.verify_taproot_commitment(secp, out_pk.to_inner(), &script));
|
||||||
|
@ -1847,11 +1847,11 @@ mod test {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let script_weights = [
|
let script_weights = [
|
||||||
(10, ScriptBuf::from_hex("51").unwrap()), // semantics of script don't matter for this test
|
(10, ScriptBuf::from_hex_no_length_prefix("51").unwrap()), // semantics of script don't matter for this test
|
||||||
(20, ScriptBuf::from_hex("52").unwrap()),
|
(20, ScriptBuf::from_hex_no_length_prefix("52").unwrap()),
|
||||||
(20, ScriptBuf::from_hex("53").unwrap()),
|
(20, ScriptBuf::from_hex_no_length_prefix("53").unwrap()),
|
||||||
(30, ScriptBuf::from_hex("54").unwrap()),
|
(30, ScriptBuf::from_hex_no_length_prefix("54").unwrap()),
|
||||||
(19, ScriptBuf::from_hex("55").unwrap()),
|
(19, ScriptBuf::from_hex_no_length_prefix("55").unwrap()),
|
||||||
];
|
];
|
||||||
let tree_info =
|
let tree_info =
|
||||||
TaprootSpendInfo::with_huffman_tree(&secp, internal_key, script_weights.clone())
|
TaprootSpendInfo::with_huffman_tree(&secp, internal_key, script_weights.clone())
|
||||||
|
@ -1872,7 +1872,10 @@ mod test {
|
||||||
*length,
|
*length,
|
||||||
tree_info
|
tree_info
|
||||||
.script_map
|
.script_map
|
||||||
.get(&(ScriptBuf::from_hex(script).unwrap(), LeafVersion::TapScript))
|
.get(&(
|
||||||
|
ScriptBuf::from_hex_no_length_prefix(script).unwrap(),
|
||||||
|
LeafVersion::TapScript
|
||||||
|
))
|
||||||
.expect("Present Key")
|
.expect("Present Key")
|
||||||
.iter()
|
.iter()
|
||||||
.next()
|
.next()
|
||||||
|
@ -1913,11 +1916,11 @@ mod test {
|
||||||
// / \ / \
|
// / \ / \
|
||||||
// A B C / \
|
// A B C / \
|
||||||
// D E
|
// D E
|
||||||
let a = ScriptBuf::from_hex("51").unwrap();
|
let a = ScriptBuf::from_hex_no_length_prefix("51").unwrap();
|
||||||
let b = ScriptBuf::from_hex("52").unwrap();
|
let b = ScriptBuf::from_hex_no_length_prefix("52").unwrap();
|
||||||
let c = ScriptBuf::from_hex("53").unwrap();
|
let c = ScriptBuf::from_hex_no_length_prefix("53").unwrap();
|
||||||
let d = ScriptBuf::from_hex("54").unwrap();
|
let d = ScriptBuf::from_hex_no_length_prefix("54").unwrap();
|
||||||
let e = ScriptBuf::from_hex("55").unwrap();
|
let e = ScriptBuf::from_hex_no_length_prefix("55").unwrap();
|
||||||
let builder = builder.add_leaf(2, a.clone()).unwrap();
|
let builder = builder.add_leaf(2, a.clone()).unwrap();
|
||||||
let builder = builder.add_leaf(2, b.clone()).unwrap();
|
let builder = builder.add_leaf(2, b.clone()).unwrap();
|
||||||
let builder = builder.add_leaf(2, c.clone()).unwrap();
|
let builder = builder.add_leaf(2, c.clone()).unwrap();
|
||||||
|
@ -2025,7 +2028,8 @@ mod test {
|
||||||
builder = process_script_trees(leaf, builder, leaves, depth + 1);
|
builder = process_script_trees(leaf, builder, leaves, depth + 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let script = ScriptBuf::from_hex(v["script"].as_str().unwrap()).unwrap();
|
let script =
|
||||||
|
ScriptBuf::from_hex_no_length_prefix(v["script"].as_str().unwrap()).unwrap();
|
||||||
let ver =
|
let ver =
|
||||||
LeafVersion::from_consensus(v["leafVersion"].as_u64().unwrap() as u8).unwrap();
|
LeafVersion::from_consensus(v["leafVersion"].as_u64().unwrap() as u8).unwrap();
|
||||||
leaves.push((script.clone(), ver));
|
leaves.push((script.clone(), ver));
|
||||||
|
@ -2079,8 +2083,10 @@ mod test {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_tweak =
|
let expected_tweak =
|
||||||
arr["intermediary"]["tweak"].as_str().unwrap().parse::<TapTweakHash>().unwrap();
|
arr["intermediary"]["tweak"].as_str().unwrap().parse::<TapTweakHash>().unwrap();
|
||||||
let expected_spk =
|
let expected_spk = ScriptBuf::from_hex_no_length_prefix(
|
||||||
ScriptBuf::from_hex(arr["expected"]["scriptPubKey"].as_str().unwrap()).unwrap();
|
arr["expected"]["scriptPubKey"].as_str().unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let expected_addr = arr["expected"]["bip350Address"]
|
let expected_addr = arr["expected"]["bip350Address"]
|
||||||
.as_str()
|
.as_str()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -22,7 +22,9 @@ fn hex_psbt(s: &str) -> Psbt {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn hex_script(s: &str) -> ScriptBuf { ScriptBuf::from_hex(s).expect("valid hex digits") }
|
fn hex_script(s: &str) -> ScriptBuf {
|
||||||
|
ScriptBuf::from_hex_no_length_prefix(s).expect("valid hex digits")
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bip174_psbt_workflow() {
|
fn bip174_psbt_workflow() {
|
||||||
|
@ -181,13 +183,13 @@ fn create_transaction() -> Transaction {
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_str_in(output_0.amount, Denomination::Bitcoin)
|
value: Amount::from_str_in(output_0.amount, Denomination::Bitcoin)
|
||||||
.expect("failed to parse amount"),
|
.expect("failed to parse amount"),
|
||||||
script_pubkey: ScriptBuf::from_hex(output_0.script_pubkey)
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(output_0.script_pubkey)
|
||||||
.expect("failed to parse script"),
|
.expect("failed to parse script"),
|
||||||
},
|
},
|
||||||
TxOut {
|
TxOut {
|
||||||
value: Amount::from_str_in(output_1.amount, Denomination::Bitcoin)
|
value: Amount::from_str_in(output_1.amount, Denomination::Bitcoin)
|
||||||
.expect("failed to parse amount"),
|
.expect("failed to parse amount"),
|
||||||
script_pubkey: ScriptBuf::from_hex(output_1.script_pubkey)
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(output_1.script_pubkey)
|
||||||
.expect("failed to parse script"),
|
.expect("failed to parse script"),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -226,8 +226,10 @@ fn serde_regression_psbt() {
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
vout: 1,
|
vout: 1,
|
||||||
},
|
},
|
||||||
script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985")
|
script_sig: ScriptBuf::from_hex_no_length_prefix(
|
||||||
.unwrap(),
|
"160014be18d152a9b012039daf3da7de4f53349eecb985",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
sequence: Sequence::from_consensus(4294967295),
|
sequence: Sequence::from_consensus(4294967295),
|
||||||
witness: Witness::from_slice(&[Vec::from_hex(
|
witness: Witness::from_slice(&[Vec::from_hex(
|
||||||
"03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105",
|
"03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105",
|
||||||
|
@ -236,8 +238,10 @@ fn serde_regression_psbt() {
|
||||||
}],
|
}],
|
||||||
output: vec![TxOut {
|
output: vec![TxOut {
|
||||||
value: Amount::from_sat(190_303_501_938).unwrap(),
|
value: Amount::from_sat(190_303_501_938).unwrap(),
|
||||||
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587")
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix(
|
||||||
.unwrap(),
|
"a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
}],
|
}],
|
||||||
};
|
};
|
||||||
let unknown: BTreeMap<raw::Key, Vec<u8>> =
|
let unknown: BTreeMap<raw::Key, Vec<u8>> =
|
||||||
|
@ -283,7 +287,7 @@ fn serde_regression_psbt() {
|
||||||
non_witness_utxo: Some(tx),
|
non_witness_utxo: Some(tx),
|
||||||
witness_utxo: Some(TxOut {
|
witness_utxo: Some(TxOut {
|
||||||
value: Amount::from_sat(190_303_501_938).unwrap(),
|
value: Amount::from_sat(190_303_501_938).unwrap(),
|
||||||
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
script_pubkey: ScriptBuf::from_hex_no_length_prefix("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
||||||
}),
|
}),
|
||||||
sighash_type: Some(PsbtSighashType::from("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse::<EcdsaSighashType>().unwrap())),
|
sighash_type: Some(PsbtSighashType::from("SIGHASH_SINGLE|SIGHASH_ANYONECANPAY".parse::<EcdsaSighashType>().unwrap())),
|
||||||
redeem_script: Some(vec![0x51].into()),
|
redeem_script: Some(vec![0x51].into()),
|
||||||
|
|
|
@ -431,9 +431,12 @@ impl fmt::Display for ScriptBuf {
|
||||||
|
|
||||||
#[cfg(feature = "hex")]
|
#[cfg(feature = "hex")]
|
||||||
impl fmt::LowerHex for Script {
|
impl fmt::LowerHex for Script {
|
||||||
|
// Currently we drop all formatter options.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::LowerHex::fmt(&self.as_bytes().as_hex(), f)
|
let compact = internals::compact_size::encode(self.as_bytes().len());
|
||||||
|
write!(f, "{:x}", compact.as_slice().as_hex())?;
|
||||||
|
write!(f, "{:x}", self.as_bytes().as_hex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
@ -451,9 +454,12 @@ internals::impl_to_hex_from_lower_hex!(ScriptBuf, |script_buf: &Self| script_buf
|
||||||
|
|
||||||
#[cfg(feature = "hex")]
|
#[cfg(feature = "hex")]
|
||||||
impl fmt::UpperHex for Script {
|
impl fmt::UpperHex for Script {
|
||||||
|
// Currently we drop all formatter options.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
fmt::UpperHex::fmt(&self.as_bytes().as_hex(), f)
|
let compact = internals::compact_size::encode(self.as_bytes().len());
|
||||||
|
write!(f, "{:X}", compact.as_slice().as_hex())?;
|
||||||
|
write!(f, "{:X}", self.as_bytes().as_hex())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -505,7 +511,8 @@ impl serde::Serialize for Script {
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
if serializer.is_human_readable() {
|
if serializer.is_human_readable() {
|
||||||
serializer.collect_str(&format_args!("{:x}", self))
|
// Do not call LowerHex because we don't want to add the len prefix.
|
||||||
|
serializer.collect_str(&format_args!("{}", self.as_bytes().as_hex()))
|
||||||
} else {
|
} else {
|
||||||
serializer.serialize_bytes(self.as_bytes())
|
serializer.serialize_bytes(self.as_bytes())
|
||||||
}
|
}
|
||||||
|
@ -796,8 +803,8 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(feature = "hex")]
|
#[cfg(feature = "hex")]
|
||||||
{
|
{
|
||||||
assert_eq!(format!("{:x}", script), "00a1b2");
|
assert_eq!(format!("{:x}", script), "0300a1b2");
|
||||||
assert_eq!(format!("{:X}", script), "00A1B2");
|
assert_eq!(format!("{:X}", script), "0300A1B2");
|
||||||
}
|
}
|
||||||
assert!(!format!("{:?}", script).is_empty());
|
assert!(!format!("{:?}", script).is_empty());
|
||||||
}
|
}
|
||||||
|
@ -809,8 +816,8 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(feature = "hex")]
|
#[cfg(feature = "hex")]
|
||||||
{
|
{
|
||||||
assert_eq!(format!("{:x}", script_buf), "00a1b2");
|
assert_eq!(format!("{:x}", script_buf), "0300a1b2");
|
||||||
assert_eq!(format!("{:X}", script_buf), "00A1B2");
|
assert_eq!(format!("{:X}", script_buf), "0300A1B2");
|
||||||
}
|
}
|
||||||
assert!(!format!("{:?}", script_buf).is_empty());
|
assert!(!format!("{:?}", script_buf).is_empty());
|
||||||
}
|
}
|
||||||
|
@ -928,7 +935,7 @@ mod tests {
|
||||||
fn script_to_hex() {
|
fn script_to_hex() {
|
||||||
let script = Script::from_bytes(&[0xa1, 0xb2, 0xc3]);
|
let script = Script::from_bytes(&[0xa1, 0xb2, 0xc3]);
|
||||||
let hex = script.to_hex();
|
let hex = script.to_hex();
|
||||||
assert_eq!(hex, "a1b2c3");
|
assert_eq!(hex, "03a1b2c3");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -937,6 +944,6 @@ mod tests {
|
||||||
fn scriptbuf_to_hex() {
|
fn scriptbuf_to_hex() {
|
||||||
let script = ScriptBuf::from_bytes(vec![0xa1, 0xb2, 0xc3]);
|
let script = ScriptBuf::from_bytes(vec![0xa1, 0xb2, 0xc3]);
|
||||||
let hex = script.to_hex();
|
let hex = script.to_hex();
|
||||||
assert_eq!(hex, "a1b2c3");
|
assert_eq!(hex, "03a1b2c3");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue