bitcoin: add mempool_spenders to Bitcoin interface
`is_in_mempool` has been updated to use `mempool_entry`.
This commit is contained in:
parent
68b2503b12
commit
714fd5e142
@ -1120,20 +1120,49 @@ impl BitcoinD {
|
||||
|
||||
/// Whether this transaction is in the mempool.
|
||||
pub fn is_in_mempool(&self, txid: &bitcoin::Txid) -> bool {
|
||||
self.mempool_entry(txid).is_some()
|
||||
}
|
||||
|
||||
/// Get mempool entry of the given transaction.
|
||||
/// Returns `None` if it is not in the mempool.
|
||||
pub fn mempool_entry(&self, txid: &bitcoin::Txid) -> Option<MempoolEntry> {
|
||||
match self
|
||||
.make_fallible_node_request("getmempoolentry", ¶ms!(Json::String(txid.to_string())))
|
||||
{
|
||||
Ok(_) => true,
|
||||
Ok(json) => Some(MempoolEntry::from(json)),
|
||||
Err(BitcoindError::Server(jsonrpc::Error::Rpc(jsonrpc::error::RpcError {
|
||||
code: -5,
|
||||
..
|
||||
}))) => false,
|
||||
}))) => None,
|
||||
Err(e) => {
|
||||
panic!("Unexpected error returned by bitcoind {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the list of txids spending those outpoints in mempool.
|
||||
pub fn mempool_txs_spending_prevouts(
|
||||
&self,
|
||||
outpoints: &[bitcoin::OutPoint],
|
||||
) -> Vec<bitcoin::Txid> {
|
||||
let prevouts: Json = outpoints
|
||||
.iter()
|
||||
.map(|op| serde_json::json!({"txid": op.txid.to_string(), "vout": op.vout}))
|
||||
.collect();
|
||||
self.make_node_request("gettxspendingprevout", ¶ms!(prevouts))
|
||||
.as_array()
|
||||
.expect("Always returns an array")
|
||||
.iter()
|
||||
.filter_map(|e| {
|
||||
e.get("spendingtxid").map(|e| {
|
||||
e.as_str()
|
||||
.and_then(|s| bitcoin::Txid::from_str(s).ok())
|
||||
.expect("Must be a valid txid if present")
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Stop bitcoind.
|
||||
pub fn stop(&self) {
|
||||
self.make_node_request("stop", &[]);
|
||||
@ -1394,3 +1423,48 @@ impl<'a> CachedTxGetter<'a> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MempoolEntry {
|
||||
pub vsize: u64,
|
||||
pub fees: MempoolEntryFees,
|
||||
}
|
||||
|
||||
impl From<Json> for MempoolEntry {
|
||||
fn from(json: Json) -> MempoolEntry {
|
||||
let vsize = json
|
||||
.get("vsize")
|
||||
.and_then(Json::as_u64)
|
||||
.expect("Must be present in bitcoind response");
|
||||
let fees = json
|
||||
.get("fees")
|
||||
.as_ref()
|
||||
.expect("Must be present in bitcoind response")
|
||||
.into();
|
||||
|
||||
MempoolEntry { vsize, fees }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MempoolEntryFees {
|
||||
pub base: bitcoin::Amount,
|
||||
pub descendant: bitcoin::Amount,
|
||||
}
|
||||
|
||||
impl From<&&Json> for MempoolEntryFees {
|
||||
fn from(json: &&Json) -> MempoolEntryFees {
|
||||
let json = json.as_object().expect("fees must be an object");
|
||||
let base = json
|
||||
.get("base")
|
||||
.and_then(Json::as_f64)
|
||||
.and_then(|a| bitcoin::Amount::from_btc(a).ok())
|
||||
.expect("Must be present and a valid amount");
|
||||
let descendant = json
|
||||
.get("descendant")
|
||||
.and_then(Json::as_f64)
|
||||
.and_then(|a| bitcoin::Amount::from_btc(a).ok())
|
||||
.expect("Must be present and a valid amount");
|
||||
MempoolEntryFees { base, descendant }
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,7 +9,7 @@ use crate::{
|
||||
bitcoin::d::{BitcoindError, CachedTxGetter, LSBlockEntry},
|
||||
descriptors,
|
||||
};
|
||||
pub use d::SyncProgress;
|
||||
pub use d::{MempoolEntry, MempoolEntryFees, SyncProgress};
|
||||
|
||||
use std::{fmt, sync};
|
||||
|
||||
@ -113,6 +113,9 @@ pub trait BitcoinInterface: Send {
|
||||
&self,
|
||||
txid: &bitcoin::Txid,
|
||||
) -> Option<(bitcoin::Transaction, Option<Block>)>;
|
||||
|
||||
/// Get the details of unconfirmed transactions spending these outpoints, if any.
|
||||
fn mempool_spenders(&self, outpoints: &[bitcoin::OutPoint]) -> Vec<MempoolEntry>;
|
||||
}
|
||||
|
||||
impl BitcoinInterface for d::BitcoinD {
|
||||
@ -356,6 +359,13 @@ impl BitcoinInterface for d::BitcoinD {
|
||||
) -> Option<(bitcoin::Transaction, Option<Block>)> {
|
||||
self.get_transaction(txid).map(|res| (res.tx, res.block))
|
||||
}
|
||||
|
||||
fn mempool_spenders(&self, outpoints: &[bitcoin::OutPoint]) -> Vec<MempoolEntry> {
|
||||
self.mempool_txs_spending_prevouts(outpoints)
|
||||
.into_iter()
|
||||
.filter_map(|txid| self.mempool_entry(&txid))
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: do we need to repeat the entire trait implemenation? Isn't there a nicer way?
|
||||
@ -442,6 +452,10 @@ impl BitcoinInterface for sync::Arc<sync::Mutex<dyn BitcoinInterface + 'static>>
|
||||
) -> Option<(bitcoin::Transaction, Option<Block>)> {
|
||||
self.lock().unwrap().wallet_transaction(txid)
|
||||
}
|
||||
|
||||
fn mempool_spenders(&self, outpoints: &[bitcoin::OutPoint]) -> Vec<MempoolEntry> {
|
||||
self.lock().unwrap().mempool_spenders(outpoints)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: We could avoid this type (and all the conversions entailing allocations) if bitcoind
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
bitcoin::{BitcoinInterface, Block, BlockChainTip, SyncProgress, UTxO},
|
||||
bitcoin::{BitcoinInterface, Block, BlockChainTip, MempoolEntry, SyncProgress, UTxO},
|
||||
config::{BitcoinConfig, Config},
|
||||
database::{BlockInfo, Coin, CoinStatus, DatabaseConnection, DatabaseInterface, LabelItem},
|
||||
descriptors, DaemonHandle,
|
||||
@ -119,6 +119,10 @@ impl BitcoinInterface for DummyBitcoind {
|
||||
) -> Option<(bitcoin::Transaction, Option<Block>)> {
|
||||
self.txs.get(txid).cloned()
|
||||
}
|
||||
|
||||
fn mempool_spenders(&self, _: &[bitcoin::OutPoint]) -> Vec<MempoolEntry> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
|
||||
struct DummyDbState {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user