Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 55 additions & 26 deletions src/rest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -380,6 +357,35 @@ impl TxOutValue {
}
}

#[allow(deprecated)]
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,
Expand Down Expand Up @@ -1621,8 +1627,12 @@ impl From<address::AddressError> 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;
Expand Down Expand Up @@ -1739,6 +1749,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(
Expand Down