diff --git a/src/rest.rs b/src/rest.rs index 5493a0fc0..eeba1fe8e 100644 --- a/src/rest.rs +++ b/src/rest.rs @@ -9,8 +9,8 @@ use crate::new_index::{compute_script_hash, Query, SpendingInput, Utxo}; use crate::util::optional_value_for_newer_blocks; use crate::util::{ create_socket, electrum_merkle, extract_tx_prevouts, get_innerscripts, get_tx_fee, has_prevout, - is_coinbase, BlockHeaderMeta, BlockId, FullHash, ScriptToAddr, ScriptToAsm, TransactionStatus, - DEFAULT_BLOCKHASH, + is_coinbase, BlockHeaderMeta, BlockId, FullHash, IsProvablyUnspendable, ScriptToAddr, + ScriptToAsm, TransactionStatus, DEFAULT_BLOCKHASH, }; #[cfg(not(feature = "liquid"))] use bitcoin::consensus::encode; @@ -334,30 +334,7 @@ impl TxOutValue { let script_asm = script.to_asm(); let script_addr = script.to_address_str(config.network_type); - // TODO should the following something to put inside rust-elements lib? - let script_type = if is_fee { - "fee" - } else if script.is_empty() { - "empty" - } else if script.is_op_return() { - "op_return" - } else if script.is_p2pk() { - "p2pk" - } else if script.is_p2pkh() { - "p2pkh" - } else if script.is_p2sh() { - "p2sh" - } else if script.is_p2wpkh() { - "v0_p2wpkh" - } else if script.is_p2wsh() { - "v0_p2wsh" - } else if script.is_p2tr() { - "v1_p2tr" - } else if script.is_op_return() { - "provably_unspendable" - } else { - "unknown" - }; + let script_type = script_type(script, is_fee); #[cfg(feature = "liquid")] let pegout = PegoutValue::from_txout(txout, config.network_type, config.parent_network); @@ -380,6 +357,34 @@ impl TxOutValue { } } +fn script_type(script: &Script, is_fee: bool) -> &'static str { + // OP_RETURN has a dedicated API type and must precede the broader + // provably-unspendable check. + if is_fee { + "fee" + } else if script.is_empty() { + "empty" + } else if script.is_op_return() { + "op_return" + } else if script.is_p2pk() { + "p2pk" + } else if script.is_p2pkh() { + "p2pkh" + } else if script.is_p2sh() { + "p2sh" + } else if script.is_p2wpkh() { + "v0_p2wpkh" + } else if script.is_p2wsh() { + "v0_p2wsh" + } else if script.is_p2tr() { + "v1_p2tr" + } else if script.is_provably_unspendable_() { + "provably_unspendable" + } else { + "unknown" + } +} + #[derive(Serialize)] struct UtxoValue { txid: Txid, @@ -1621,8 +1626,12 @@ impl From for HttpError { #[cfg(test)] mod tests { - use crate::rest::{is_block_template_request, HttpError}; - use crate::{errors, errors::ErrorKind}; + use crate::{ + chain::Script, + errors, + errors::ErrorKind, + rest::{is_block_template_request, script_type, HttpError}, + }; use http_body_util::BodyExt; use hyper::{Method, StatusCode}; use serde_json::Value; @@ -1739,6 +1748,25 @@ mod tests { assert!(err.is_err()); } + #[test] + fn test_script_type_unspendable_classification() { + let op_return = Script::from(vec![0x6a]); + assert_eq!(script_type(&op_return, false), "op_return"); + + #[cfg(not(feature = "liquid"))] + let provably_unspendable = Script::from(vec![0x50]); // OP_RESERVED + #[cfg(feature = "liquid")] + let provably_unspendable = Script::from(vec![0x51; 10_001]); + assert_eq!( + script_type(&provably_unspendable, false), + "provably_unspendable" + ); + + // OP_TRUE is spendable but does not match a recognized output type. + let unknown = Script::from(vec![0x51]); + assert_eq!(script_type(&unknown, false), "unknown"); + } + #[test] fn test_getblocktemplate_rpc_error() { let err: errors::Error = errors::ErrorKind::RpcError( diff --git a/src/util/mod.rs b/src/util/mod.rs index d5e8f1be8..25403e526 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -10,7 +10,7 @@ pub use self::block::{ BlockHeaderMeta, BlockId, BlockMeta, BlockStatus, HeaderEntry, HeaderList, DEFAULT_BLOCKHASH, }; pub use self::fees::get_tx_fee; -pub use self::script::{get_innerscripts, ScriptToAddr, ScriptToAsm}; +pub use self::script::{get_innerscripts, IsProvablyUnspendable, ScriptToAddr, ScriptToAsm}; pub use self::transaction::{ extract_tx_prevouts, get_prev_outpoints, has_prevout, is_coinbase, is_spendable, serialize_outpoint, TransactionStatus, TxInput, diff --git a/src/util/script.rs b/src/util/script.rs index 9f44c4ea6..16e66263c 100644 --- a/src/util/script.rs +++ b/src/util/script.rs @@ -11,6 +11,37 @@ pub struct InnerScripts { pub witness_script: Option