From 4bc0e36f20c0c9aad09542a1b64bf76dcfe2def6 Mon Sep 17 00:00:00 2001 From: raphjaph Date: Fri, 30 Sep 2022 22:02:32 +0200 Subject: [PATCH 1/7] rebase --- Cargo.lock | 1 + src/subcommand.rs | 4 +++ src/subcommand/wallet.rs | 24 +++++++++++++ src/subcommand/wallet/identify.rs | 30 ++++++++++++++++ test-bitcoincore-rpc/Cargo.toml | 1 + test-bitcoincore-rpc/src/lib.rs | 57 +++++++++++++++++++++++++++++++ tests/lib.rs | 1 + tests/wallet.rs | 15 ++++++++ 8 files changed, 133 insertions(+) create mode 100644 src/subcommand/wallet.rs create mode 100644 src/subcommand/wallet/identify.rs create mode 100644 tests/wallet.rs diff --git a/Cargo.lock b/Cargo.lock index 4b9befde68..54c9ecb550 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2949,6 +2949,7 @@ name = "test-bitcoincore-rpc" version = "0.0.0" dependencies = [ "bitcoin", + "bitcoincore-rpc", "hex", "jsonrpc-core", "jsonrpc-core-client", diff --git a/src/subcommand.rs b/src/subcommand.rs index b1c3f9f3c7..9865bae3f9 100644 --- a/src/subcommand.rs +++ b/src/subcommand.rs @@ -10,6 +10,7 @@ mod range; mod server; mod supply; mod traits; +mod wallet; #[derive(Debug, Parser)] pub(crate) enum Subcommand { @@ -23,6 +24,8 @@ pub(crate) enum Subcommand { Server(server::Server), Supply, Traits(traits::Traits), + #[clap(subcommand)] + Wallet(wallet::Wallet), } impl Subcommand { @@ -43,6 +46,7 @@ impl Subcommand { } Self::Supply => supply::run(), Self::Traits(traits) => traits.run(), + Self::Wallet(wallet) => wallet.run(options), } } } diff --git a/src/subcommand/wallet.rs b/src/subcommand/wallet.rs new file mode 100644 index 0000000000..10ab5d2f66 --- /dev/null +++ b/src/subcommand/wallet.rs @@ -0,0 +1,24 @@ +use { + super::*, + bitcoincore_rpc::{Auth, Client, RpcApi}, +}; + +mod identify; + +#[derive(Debug, Parser)] +pub(crate) enum Wallet { + Identify, + List, +} + +impl Wallet { + pub(crate) fn run(self, options: Options) -> Result<()> { + match self { + Self::Identify => identify::run(options), + Self::List => Ok(()), + } + } +} + +#[cfg(test)] +mod tests {} diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs new file mode 100644 index 0000000000..5bf953ccd6 --- /dev/null +++ b/src/subcommand/wallet/identify.rs @@ -0,0 +1,30 @@ +use super::*; + +pub(crate) fn run(options: Options) -> Result { + let index = Index::open(&options)?; + index.index()?; + + let client = Client::new(&options.rpc_url(), Auth::CookieFile(options.cookie_file()?)) + .context("Failed to connect to RPC URL")?; + + let utxos = client.list_unspent(None, None, None, None, None).unwrap(); + for utxo in utxos { + let output = OutPoint::new(utxo.txid, utxo.vout); + match index.list(output).unwrap() { + Some(List::Unspent(ordinal_ranges)) => { + for (offset, ordinal_range) in ordinal_ranges.iter().enumerate() { + let ordinal = Ordinal(ordinal_range.0); + let rarity = ordinal.rarity(); + match rarity { + Rarity::Common => (), + _ => println!("{ordinal}\t{output}\t{offset}\t{rarity}"), + } + } + } + Some(_) => (), + None => (), + } + } + + Ok(()) +} diff --git a/test-bitcoincore-rpc/Cargo.toml b/test-bitcoincore-rpc/Cargo.toml index 798d8ff119..8d8d96250f 100644 --- a/test-bitcoincore-rpc/Cargo.toml +++ b/test-bitcoincore-rpc/Cargo.toml @@ -9,6 +9,7 @@ repository = "https://github.com/casey/ord" [dependencies] bitcoin = { version = "0.29.1", features = ["serde"] } +bitcoincore-rpc = "0.16.0" hex = "0.4.3" jsonrpc-core = "18.0.0" jsonrpc-core-client = "18.0.0" diff --git a/test-bitcoincore-rpc/src/lib.rs b/test-bitcoincore-rpc/src/lib.rs index c3121c0ad2..9e1fa7ce8f 100644 --- a/test-bitcoincore-rpc/src/lib.rs +++ b/test-bitcoincore-rpc/src/lib.rs @@ -3,7 +3,9 @@ use { blockdata::constants::COIN_VALUE, blockdata::script, consensus::encode::serialize, hash_types::BlockHash, hashes::Hash, Block, BlockHeader, Network, OutPoint, PackedLockTime, Script, Sequence, Transaction, TxIn, TxMerkleNode, TxOut, Txid, Witness, + util::amount::Amount, }, + bitcoincore_rpc::json::ListUnspentResultEntry, jsonrpc_core::IoHandler, jsonrpc_http_server::{CloseHandle, ServerBuilder}, std::collections::BTreeMap, @@ -204,6 +206,16 @@ pub trait Api { verbose: bool, blockhash: Option, ) -> Result; + + #[rpc(name = "listunspent")] + fn list_unspent( + &self, + minconf: Option, + maxconf: Option, + address: Option, + include_unsage: Option, + query_options: Option, + ) -> Result, jsonrpc_core::Error>; } impl Api for Server { @@ -255,6 +267,51 @@ impl Api for Server { )), } } + + fn list_unspent( + &self, + minconf: Option, + maxconf: Option, + address: Option, + include_unsafe: Option, + query_options: Option, + ) -> Result, jsonrpc_core::Error> { + assert_eq!(minconf, None, ""); + assert_eq!(maxconf, None, ""); + assert_eq!(address, None, ""); + assert_eq!(include_unsafe, None, ""); + assert_eq!(query_options, None, ""); + let all_outpoints = self + .state + .lock() + .unwrap() + .transactions + .iter() + .map(|(txid, tx)| (0..tx.output.len()).map(|vout| bitcoin::OutPoint::new(*txid, vout as u32))) + .flatten() + .collect::>(); + + Ok( + all_outpoints + .iter() + .map(|outpoint| ListUnspentResultEntry { + txid: outpoint.txid, + vout: outpoint.vout, + address: None, + label: None, + redeem_script: None, + witness_script: None, + script_pub_key: Script::new(), + amount: Amount::default(), + confirmations: 0, + spendable: true, + solvable: true, + descriptor: None, + safe: true, + }) + .collect(), + ) + } } pub struct Handle { diff --git a/tests/lib.rs b/tests/lib.rs index a0a7fca2ec..a439f72b51 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -28,3 +28,4 @@ mod server; mod supply; mod traits; mod version; +mod wallet; diff --git a/tests/wallet.rs b/tests/wallet.rs new file mode 100644 index 0000000000..ecf9ebe411 --- /dev/null +++ b/tests/wallet.rs @@ -0,0 +1,15 @@ +use { + super::*, + bitcoin::{OutPoint, blockdata::constants::COIN_VALUE}, +}; + +#[test] +fn show_second_uncommon_ordinal() { + let rpc_server = test_bitcoincore_rpc::spawn(); + let second_coinbase = rpc_server.mine_blocks(1)[0].txdata[0].txid(); + + CommandBuilder::new("wallet identify") + .rpc_server(&rpc_server) + .expected_stdout(format!("{}\t{}\t0\tuncommon\n", 50 * COIN_VALUE, OutPoint::new(second_coinbase, 0))) + .run(); +} From 80771b579d67c522777e805a6ce78a0a154e168c Mon Sep 17 00:00:00 2001 From: raphjaph Date: Fri, 30 Sep 2022 22:07:04 +0200 Subject: [PATCH 2/7] clippy+fmt --- test-bitcoincore-rpc/src/lib.rs | 11 ++++++----- tests/wallet.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/test-bitcoincore-rpc/src/lib.rs b/test-bitcoincore-rpc/src/lib.rs index 9e1fa7ce8f..4e7bd10296 100644 --- a/test-bitcoincore-rpc/src/lib.rs +++ b/test-bitcoincore-rpc/src/lib.rs @@ -1,9 +1,9 @@ use { bitcoin::{ blockdata::constants::COIN_VALUE, blockdata::script, consensus::encode::serialize, - hash_types::BlockHash, hashes::Hash, Block, BlockHeader, Network, OutPoint, PackedLockTime, - Script, Sequence, Transaction, TxIn, TxMerkleNode, TxOut, Txid, Witness, - util::amount::Amount, + hash_types::BlockHash, hashes::Hash, util::amount::Amount, Block, BlockHeader, Network, + OutPoint, PackedLockTime, Script, Sequence, Transaction, TxIn, TxMerkleNode, TxOut, Txid, + Witness, }, bitcoincore_rpc::json::ListUnspentResultEntry, jsonrpc_core::IoHandler, @@ -287,8 +287,9 @@ impl Api for Server { .unwrap() .transactions .iter() - .map(|(txid, tx)| (0..tx.output.len()).map(|vout| bitcoin::OutPoint::new(*txid, vout as u32))) - .flatten() + .flat_map(|(txid, tx)| { + (0..tx.output.len()).map(|vout| bitcoin::OutPoint::new(*txid, vout as u32)) + }) .collect::>(); Ok( diff --git a/tests/wallet.rs b/tests/wallet.rs index ecf9ebe411..e16c06f05b 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -1,6 +1,6 @@ use { super::*, - bitcoin::{OutPoint, blockdata::constants::COIN_VALUE}, + bitcoin::{blockdata::constants::COIN_VALUE, OutPoint}, }; #[test] @@ -10,6 +10,10 @@ fn show_second_uncommon_ordinal() { CommandBuilder::new("wallet identify") .rpc_server(&rpc_server) - .expected_stdout(format!("{}\t{}\t0\tuncommon\n", 50 * COIN_VALUE, OutPoint::new(second_coinbase, 0))) + .expected_stdout(format!( + "{}\t{}\t0\tuncommon\n", + 50 * COIN_VALUE, + OutPoint::new(second_coinbase, 0) + )) .run(); } From 1f43cae232a45175c866026da76a460f7871bf38 Mon Sep 17 00:00:00 2001 From: raphjaph Date: Fri, 30 Sep 2022 22:15:44 +0200 Subject: [PATCH 3/7] remove list command --- src/subcommand/wallet.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/subcommand/wallet.rs b/src/subcommand/wallet.rs index 10ab5d2f66..be208c4313 100644 --- a/src/subcommand/wallet.rs +++ b/src/subcommand/wallet.rs @@ -8,14 +8,12 @@ mod identify; #[derive(Debug, Parser)] pub(crate) enum Wallet { Identify, - List, } impl Wallet { pub(crate) fn run(self, options: Options) -> Result<()> { match self { Self::Identify => identify::run(options), - Self::List => Ok(()), } } } From 18e41890422c73756cfd1005c01ded7dd875d6da Mon Sep 17 00:00:00 2001 From: raphjaph Date: Fri, 30 Sep 2022 23:40:08 +0200 Subject: [PATCH 4/7] added some error messages --- src/subcommand/wallet.rs | 5 +--- src/subcommand/wallet/identify.rs | 38 +++++++++++++++++++++---------- test-bitcoincore-rpc/src/lib.rs | 12 +++++----- tests/wallet.rs | 2 +- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/subcommand/wallet.rs b/src/subcommand/wallet.rs index be208c4313..e575fb304c 100644 --- a/src/subcommand/wallet.rs +++ b/src/subcommand/wallet.rs @@ -1,7 +1,4 @@ -use { - super::*, - bitcoincore_rpc::{Auth, Client, RpcApi}, -}; +use super::*; mod identify; diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index 5bf953ccd6..5bade4615e 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -1,28 +1,42 @@ -use super::*; +use { + super::*, + bitcoincore_rpc::{Auth, Client, RpcApi}, +}; pub(crate) fn run(options: Options) -> Result { let index = Index::open(&options)?; index.index()?; - let client = Client::new(&options.rpc_url(), Auth::CookieFile(options.cookie_file()?)) - .context("Failed to connect to RPC URL")?; + let cookie_file = options.cookie_file()?; + let rpc_url = options.rpc_url(); + log::info!( + "Connecting to Bitcoin Core RPC server at {rpc_url} using credentials from `{}`", + cookie_file.display() + ); + + let client = Client::new(&rpc_url, Auth::CookieFile(cookie_file)) + .context("Failed to connect to Bitcoin Core RPC at {rpc_url}")?; + + let utxos = client.list_unspent(None, None, None, None, None)?; - let utxos = client.list_unspent(None, None, None, None, None).unwrap(); for utxo in utxos { let output = OutPoint::new(utxo.txid, utxo.vout); - match index.list(output).unwrap() { + match index.list(output)? { Some(List::Unspent(ordinal_ranges)) => { - for (offset, ordinal_range) in ordinal_ranges.iter().enumerate() { - let ordinal = Ordinal(ordinal_range.0); + let mut offset = 0; + for range in &ordinal_ranges { + let ordinal = Ordinal(range.0); let rarity = ordinal.rarity(); - match rarity { - Rarity::Common => (), - _ => println!("{ordinal}\t{output}\t{offset}\t{rarity}"), + if rarity > Rarity::Common { + println!("{ordinal}\t{output}\t{offset}\t{rarity}"); } + offset += range.1 - range.0 } } - Some(_) => (), - None => (), + Some(List::Spent(_)) => { + bail!("Output {output} in wallet but is spent according to index") + } + None => bail!("Ordinals index has not seen {output}"), } } diff --git a/test-bitcoincore-rpc/src/lib.rs b/test-bitcoincore-rpc/src/lib.rs index 4e7bd10296..a0e872be01 100644 --- a/test-bitcoincore-rpc/src/lib.rs +++ b/test-bitcoincore-rpc/src/lib.rs @@ -213,7 +213,7 @@ pub trait Api { minconf: Option, maxconf: Option, address: Option, - include_unsage: Option, + include_unsafe: Option, query_options: Option, ) -> Result, jsonrpc_core::Error>; } @@ -276,11 +276,11 @@ impl Api for Server { include_unsafe: Option, query_options: Option, ) -> Result, jsonrpc_core::Error> { - assert_eq!(minconf, None, ""); - assert_eq!(maxconf, None, ""); - assert_eq!(address, None, ""); - assert_eq!(include_unsafe, None, ""); - assert_eq!(query_options, None, ""); + assert_eq!(minconf, None, "minconf param not supported"); + assert_eq!(maxconf, None, "maxconf param not supported"); + assert_eq!(address, None, "address param not supported"); + assert_eq!(include_unsafe, None, "include_unsafe param not supported"); + assert_eq!(query_options, None, "query_options param not supported"); let all_outpoints = self .state .lock() diff --git a/tests/wallet.rs b/tests/wallet.rs index e16c06f05b..a519c01d56 100644 --- a/tests/wallet.rs +++ b/tests/wallet.rs @@ -4,7 +4,7 @@ use { }; #[test] -fn show_second_uncommon_ordinal() { +fn identify() { let rpc_server = test_bitcoincore_rpc::spawn(); let second_coinbase = rpc_server.mine_blocks(1)[0].txdata[0].txid(); From 3520f665f5d4ac46f288ad80b826f2b6f60c2c1d Mon Sep 17 00:00:00 2001 From: raphjaph Date: Sat, 1 Oct 2022 01:50:22 +0200 Subject: [PATCH 5/7] added unit tests --- src/subcommand/wallet/identify.rs | 94 +++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index 5bade4615e..9fcf5014af 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -13,25 +13,17 @@ pub(crate) fn run(options: Options) -> Result { "Connecting to Bitcoin Core RPC server at {rpc_url} using credentials from `{}`", cookie_file.display() ); - let client = Client::new(&rpc_url, Auth::CookieFile(cookie_file)) .context("Failed to connect to Bitcoin Core RPC at {rpc_url}")?; - let utxos = client.list_unspent(None, None, None, None, None)?; + let unspent = client.list_unspent(None, None, None, None, None)?; - for utxo in utxos { + let mut utxos = Vec::new(); + for utxo in unspent { let output = OutPoint::new(utxo.txid, utxo.vout); match index.list(output)? { Some(List::Unspent(ordinal_ranges)) => { - let mut offset = 0; - for range in &ordinal_ranges { - let ordinal = Ordinal(range.0); - let rarity = ordinal.rarity(); - if rarity > Rarity::Common { - println!("{ordinal}\t{output}\t{offset}\t{rarity}"); - } - offset += range.1 - range.0 - } + utxos.push((output, ordinal_ranges)); } Some(List::Spent(_)) => { bail!("Output {output} in wallet but is spent according to index") @@ -40,5 +32,83 @@ pub(crate) fn run(options: Options) -> Result { } } + for (ordinal, output, offset, rarity) in identify(utxos) { + println!("{ordinal}\t{output}\t{offset}\t{rarity}"); + } + Ok(()) } + +fn identify(utxos: Vec<(OutPoint, Vec<(u64, u64)>)>) -> Vec<(Ordinal, OutPoint, u64, Rarity)> { + utxos + .into_iter() + .flat_map(|(outpoint, ordinal_ranges)| { + let mut offset = 0; + ordinal_ranges.into_iter().filter_map(move |(start, end)| { + let ordinal = Ordinal(start); + let rarity = ordinal.rarity(); + let start_offset = offset; + offset += end - start; + if rarity > Rarity::Common { + Some((ordinal, outpoint, start_offset, rarity)) + } else { + None + } + }) + }) + .collect() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn identify_no_rare_ordinals() { + let utxos = vec![( + OutPoint::null(), + vec![(51 * COIN_VALUE, 100 * COIN_VALUE), (1234, 5678)], + )]; + assert_eq!(identify(utxos), vec![]) + } + + #[test] + fn identify_one_rare_ordinal() { + let utxos = vec![( + OutPoint::null(), + vec![(10, 80), (50 * COIN_VALUE, 100 * COIN_VALUE)], + )]; + assert_eq!( + identify(utxos), + vec![( + Ordinal(50 * COIN_VALUE), + OutPoint::null(), + 70, + Rarity::Uncommon + )] + ) + } + + #[test] + fn identify_two_rare_ordinals() { + let utxos = vec![( + OutPoint::null(), + vec![(0, 100), (1050000000000000, 1150000000000000)], + )]; + assert_eq!( + identify(utxos), + vec![( + Ordinal(0), + OutPoint::null(), + 0, + Rarity::Mythic + ), ( + Ordinal(1050000000000000), + OutPoint::null(), + 100, + Rarity::Epic + )] + ) + } + +} From 19627603569315e9bb292b41608f602b34e62f74 Mon Sep 17 00:00:00 2001 From: raphjaph Date: Sat, 1 Oct 2022 02:02:35 +0200 Subject: [PATCH 6/7] clippy+fmt --- src/subcommand/wallet/identify.rs | 23 ++++++++++------------- test-bitcoincore-rpc/src/lib.rs | 6 +++--- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index 9fcf5014af..22f99af028 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -25,7 +25,7 @@ pub(crate) fn run(options: Options) -> Result { Some(List::Unspent(ordinal_ranges)) => { utxos.push((output, ordinal_ranges)); } - Some(List::Spent(_)) => { + Some(List::Spent) => { bail!("Output {output} in wallet but is spent according to index") } None => bail!("Ordinals index has not seen {output}"), @@ -97,18 +97,15 @@ mod tests { )]; assert_eq!( identify(utxos), - vec![( - Ordinal(0), - OutPoint::null(), - 0, - Rarity::Mythic - ), ( - Ordinal(1050000000000000), - OutPoint::null(), - 100, - Rarity::Epic - )] + vec![ + (Ordinal(0), OutPoint::null(), 0, Rarity::Mythic), + ( + Ordinal(1050000000000000), + OutPoint::null(), + 100, + Rarity::Epic + ) + ] ) } - } diff --git a/test-bitcoincore-rpc/src/lib.rs b/test-bitcoincore-rpc/src/lib.rs index ae0caf6650..22a747a3e3 100644 --- a/test-bitcoincore-rpc/src/lib.rs +++ b/test-bitcoincore-rpc/src/lib.rs @@ -1,10 +1,10 @@ use { bitcoin::{ blockdata::constants::COIN_VALUE, blockdata::script, consensus::encode::serialize, - hash_types::BlockHash, hashes::Hash, Block, BlockHeader, Network, OutPoint, PackedLockTime, - Script, Sequence, Transaction, TxIn, TxMerkleNode, TxOut, Txid, Witness, Wtxid, Amount, + hash_types::BlockHash, hashes::Hash, Amount, Block, BlockHeader, Network, OutPoint, + PackedLockTime, Script, Sequence, Transaction, TxIn, TxMerkleNode, TxOut, Txid, Witness, Wtxid, }, - bitcoincore_rpc_json::{ListUnspentResultEntry, GetRawTransactionResult}, + bitcoincore_rpc_json::{GetRawTransactionResult, ListUnspentResultEntry}, jsonrpc_core::{IoHandler, Value}, jsonrpc_http_server::{CloseHandle, ServerBuilder}, std::collections::BTreeMap, From 81d5d736058f18a60119f42ede03b9f23b566d61 Mon Sep 17 00:00:00 2001 From: raphjaph Date: Sat, 1 Oct 2022 12:22:23 +0200 Subject: [PATCH 7/7] added one more test --- src/subcommand/wallet/identify.rs | 30 ++++++++++++++++++++ test-bitcoincore-rpc/src/lib.rs | 47 ++++++++++++++----------------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/src/subcommand/wallet/identify.rs b/src/subcommand/wallet/identify.rs index 22f99af028..a6ece41616 100644 --- a/src/subcommand/wallet/identify.rs +++ b/src/subcommand/wallet/identify.rs @@ -108,4 +108,34 @@ mod tests { ] ) } + + #[test] + fn identify_rare_ordinals_in_different_outpoints() { + let utxos = vec![ + (OutPoint::null(), vec![(50 * COIN_VALUE, 55 * COIN_VALUE)]), + ( + OutPoint::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:5") + .unwrap(), + vec![(100 * COIN_VALUE, 111 * COIN_VALUE)], + ), + ]; + assert_eq!( + identify(utxos), + vec![ + ( + Ordinal(50 * COIN_VALUE), + OutPoint::null(), + 0, + Rarity::Uncommon + ), + ( + Ordinal(100 * COIN_VALUE), + OutPoint::from_str("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b:5") + .unwrap(), + 0, + Rarity::Uncommon + ) + ] + ) + } } diff --git a/test-bitcoincore-rpc/src/lib.rs b/test-bitcoincore-rpc/src/lib.rs index 22a747a3e3..16002667bc 100644 --- a/test-bitcoincore-rpc/src/lib.rs +++ b/test-bitcoincore-rpc/src/lib.rs @@ -306,34 +306,29 @@ impl Api for Server { assert_eq!(address, None, "address param not supported"); assert_eq!(include_unsafe, None, "include_unsafe param not supported"); assert_eq!(query_options, None, "query_options param not supported"); - let all_outpoints = self - .state - .lock() - .unwrap() - .transactions - .iter() - .flat_map(|(txid, tx)| { - (0..tx.output.len()).map(|vout| bitcoin::OutPoint::new(*txid, vout as u32)) - }) - .collect::>(); - Ok( - all_outpoints + self + .state + .lock() + .unwrap() + .transactions .iter() - .map(|outpoint| ListUnspentResultEntry { - txid: outpoint.txid, - vout: outpoint.vout, - address: None, - label: None, - redeem_script: None, - witness_script: None, - script_pub_key: Script::new(), - amount: Amount::default(), - confirmations: 0, - spendable: true, - solvable: true, - descriptor: None, - safe: true, + .flat_map(|(txid, tx)| { + (0..tx.output.len()).map(|vout| ListUnspentResultEntry { + txid: *txid, + vout: vout as u32, + address: None, + label: None, + redeem_script: None, + witness_script: None, + script_pub_key: Script::new(), + amount: Amount::default(), + confirmations: 0, + spendable: true, + solvable: true, + descriptor: None, + safe: true, + }) }) .collect(), )