From 392fa6c250dfa84bec57422859f87e074753bbc8 Mon Sep 17 00:00:00 2001 From: moisesPomilio <93723302+moisesPompilio@users.noreply.github.com> Date: Wed, 29 Oct 2025 22:40:05 -0300 Subject: [PATCH 1/2] feat(rpc): add corepc-types dependency and update GetTxOut struct usage --- Cargo.lock | 14 ++++ crates/floresta-node/Cargo.toml | 1 + .../floresta-node/src/json_rpc/blockchain.rs | 66 +++++-------------- tests/floresta-cli/gettxout.py | 2 +- 4 files changed, 31 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 13a35be7d..9b9000132 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,6 +372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda569d741b895131a88ee5589a467e73e9c4718e958ac9308e4f7dc44b6945" dependencies = [ "base58ck", + "base64 0.21.7", "bech32 0.11.0", "bitcoin-internals 0.3.0", "bitcoin-io 0.1.3", @@ -747,6 +748,17 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "corepc-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22db78b0223b66f82f92b14345f06307078f76d94b18280431ea9bc6cd9cbb6" +dependencies = [ + "bitcoin 0.32.7", + "serde", + "serde_json", +] + [[package]] name = "cpufeatures" version = "0.2.17" @@ -1157,6 +1169,7 @@ dependencies = [ "bitcoin 0.32.7", "chrono", "console-subscriber", + "corepc-types", "dirs", "dns-lookup 2.0.4", "floresta-chain", @@ -1190,6 +1203,7 @@ version = "0.4.0" dependencies = [ "bitcoin 0.32.7", "clap", + "corepc-types", "jsonrpc", "rand", "rcgen", diff --git a/crates/floresta-node/Cargo.toml b/crates/floresta-node/Cargo.toml index 7273f226e..d32079fa0 100644 --- a/crates/floresta-node/Cargo.toml +++ b/crates/floresta-node/Cargo.toml @@ -32,6 +32,7 @@ tracing-subscriber = { version = "0.3.20", features = ["chrono", "ansi", "env-fi console-subscriber = { version = "0.4", optional = true } tracing = "0.1.41" tracing-appender = "0.2.3" +corepc-types = "0.10.1" [target.'cfg(target_env = "gnu")'.dependencies] libc = "0.2.169" diff --git a/crates/floresta-node/src/json_rpc/blockchain.rs b/crates/floresta-node/src/json_rpc/blockchain.rs index ffc49463b..d93357efa 100644 --- a/crates/floresta-node/src/json_rpc/blockchain.rs +++ b/crates/floresta-node/src/json_rpc/blockchain.rs @@ -10,9 +10,9 @@ use bitcoin::OutPoint; use bitcoin::Script; use bitcoin::ScriptBuf; use bitcoin::Txid; +use corepc_types::v29::GetTxOut; +use corepc_types::ScriptPubkey; use miniscript::descriptor::checksum; -use serde::Deserialize; -use serde::Serialize; use serde_json::json; use serde_json::Value; use tracing::debug; @@ -25,47 +25,6 @@ use super::server::RpcChain; use super::server::RpcImpl; use crate::json_rpc::res::RescanConfidence; -#[derive(Debug, Serialize, Deserialize)] -/// Struct helper for RpcGetTxOut -pub struct ScriptPubkeyDescription { - /// Disassembly of the output script - asm: String, - - /// Inferred descriptor for the output - desc: String, - - /// The raw output script bytes, hex-encoded - hex: String, - - /// The type, eg pubkeyhash - #[serde(rename = "type")] - type_field: String, - - /// The Bitcoin address (only if a well-defined address exists) - #[serde(skip_serializing_if = "Option::is_none")] - address: Option, -} - -#[derive(Debug, Serialize, Deserialize)] -/// Struct helper for serialize gettxout rpc -pub struct GetTxOut { - /// The hash of the block at the tip of the chain - bestblock: BlockHash, - - /// The number of confirmations - confirmations: u32, - - /// The transaction value in BTC - value: f64, - - #[serde(rename = "scriptPubKey")] - /// Script Public Key struct - script_pubkey: ScriptPubkeyDescription, - - /// Coinbase or not - coinbase: bool, -} - impl RpcImpl { async fn get_block_inner(&self, hash: BlockHash) -> Result { let is_genesis = self.chain.get_block_hash(0).unwrap().eq(&hash); @@ -518,22 +477,27 @@ impl RpcImpl { let network = self.chain.get_params().network; let address = Address::from_script(script, network).ok(); - let desc = Self::get_script_type_descriptor(script, &address); - let checksum_desc = checksum::desc_checksum(&desc) - .map(|checksum| format!("{desc}#{checksum}")) - .map_err(|_| JsonRpcError::InvalidDescriptor)?; + let base_descriptor = Self::get_script_type_descriptor(script, &address); + let descriptor: Option = match checksum::desc_checksum(&base_descriptor) { + Ok(checksum) => Some(format!("{base_descriptor}#{checksum}")), + Err(_) => None, + }; let asm = Self::to_core_asm_string(&txout.script_pubkey)?; - let script_pubkey = ScriptPubkeyDescription { + let script_pubkey = ScriptPubkey { asm, hex: txout.script_pubkey.to_hex_string(), - desc: checksum_desc, + descriptor, address: address.as_ref().map(ToString::to_string), - type_field: Self::get_script_type_label(script).to_string(), + type_: Self::get_script_type_label(script).to_string(), + // Deprecated in Bitcoin Core v22, require flags in Bitcoin Core. + // Set to None as not required for consensus. + addresses: None, + required_signatures: None, }; Some(GetTxOut { - bestblock: bestblock_hash, + best_block: bestblock_hash.to_string(), confirmations: bestblock_height - height + 1, value: txout.value.to_btc(), script_pubkey, diff --git a/tests/floresta-cli/gettxout.py b/tests/floresta-cli/gettxout.py index a785f1ccd..fbba6e801 100644 --- a/tests/floresta-cli/gettxout.py +++ b/tests/floresta-cli/gettxout.py @@ -121,7 +121,7 @@ def run_test(self): tx, vout=0, include_mempool=False ) - for key in ("bestblock", "coinbase", "value"): + for key in ("bestblock", "coinbase", "value", "confirmations"): self.assertEqual(txout_floresta[key], txout_bitcoind[key]) for key in ("address", "desc", "hex", "type", "asm"): From 717cf00004d93b55085990964d4080ec6cdae5ac Mon Sep 17 00:00:00 2001 From: moisesPomilio <93723302+moisesPompilio@users.noreply.github.com> Date: Wed, 29 Oct 2025 22:51:01 -0300 Subject: [PATCH 2/2] feat(rpc): add corepc-types dependency and integrate GetTxOut struct --- crates/floresta-rpc/Cargo.toml | 1 + crates/floresta-rpc/src/rpc.rs | 13 +++++++++---- crates/floresta-rpc/src/rpc_types.rs | 4 ++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/crates/floresta-rpc/Cargo.toml b/crates/floresta-rpc/Cargo.toml index a99d90836..96fd35c00 100644 --- a/crates/floresta-rpc/Cargo.toml +++ b/crates/floresta-rpc/Cargo.toml @@ -21,6 +21,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" jsonrpc = { version = "0.18.0", features = ["minreq_http"], optional = true } clap = { version = "4.0.29", features = ["derive"], optional = true } +corepc-types = "0.10.1" [features] default = ["with-jsonrpc"] diff --git a/crates/floresta-rpc/src/rpc.rs b/crates/floresta-rpc/src/rpc.rs index 59f8b4151..3a7f9452e 100644 --- a/crates/floresta-rpc/src/rpc.rs +++ b/crates/floresta-rpc/src/rpc.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use bitcoin::block::Header as BlockHeader; use bitcoin::BlockHash; use bitcoin::Txid; +use corepc_types::v29::GetTxOut; use serde_json::Number; use serde_json::Value; @@ -98,7 +99,7 @@ pub trait FlorestaRPC { /// This method returns a cached transaction output. If the output is not in the cache, /// or is spent, an empty object is returned. If you want to find a utxo that's not in /// the cache, you can use the findtxout method. - fn get_tx_out(&self, tx_id: Txid, outpoint: u32) -> Result; + fn get_tx_out(&self, tx_id: Txid, outpoint: u32) -> Result; /// Stops the florestad process /// /// This can be used to gracefully stop the florestad process. @@ -252,14 +253,18 @@ impl FlorestaRPC for T { self.call("getblockcount", &[]) } - fn get_tx_out(&self, tx_id: Txid, outpoint: u32) -> Result { - self.call( + fn get_tx_out(&self, tx_id: Txid, outpoint: u32) -> Result { + let result: serde_json::Value = self.call( "gettxout", &[ Value::String(tx_id.to_string()), Value::Number(Number::from(outpoint)), ], - ) + )?; + if result.is_null() { + return Err(Error::TxOutNotFound); + } + serde_json::from_value(result).map_err(Error::Serde) } fn get_txout_proof(&self, txids: Vec, blockhash: Option) -> Option { diff --git a/crates/floresta-rpc/src/rpc_types.rs b/crates/floresta-rpc/src/rpc_types.rs index c1cbfe8f8..a270c64bf 100644 --- a/crates/floresta-rpc/src/rpc_types.rs +++ b/crates/floresta-rpc/src/rpc_types.rs @@ -318,6 +318,9 @@ pub enum Error { /// The user requested a rescan based on invalid values. InvalidRescanVal, + + /// The requested transaction output was not found + TxOutNotFound, } impl From for Error { @@ -343,6 +346,7 @@ impl Display for Error { Error::EmptyResponse => write!(f, "got an empty response from server"), Error::InvalidVerbosity => write!(f, "invalid verbosity level"), Error::InvalidRescanVal => write!(f, "Invalid rescan values"), + Error::TxOutNotFound => write!(f, "Transaction output was not found"), } } }