Skip to content

Commit

Permalink
Add a mempool_spenders method to the Bitcoin interface
Browse files Browse the repository at this point in the history
  • Loading branch information
darosior committed Dec 6, 2023
1 parent f52e65d commit 575025d
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/bitcoin/d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,29 @@ impl BitcoinD {
}
}

/// 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", &params!(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", &[]);
Expand Down
14 changes: 14 additions & 0 deletions src/bitcoin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ pub trait BitcoinInterface: Send {
/// Get mempool entry of the given transaction.
/// Returns `None` if it is not in the mempool.
fn mempool_entry(&self, txid: &bitcoin::Txid) -> Option<MempoolEntry>;

/// 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 {
Expand Down Expand Up @@ -364,6 +367,13 @@ impl BitcoinInterface for d::BitcoinD {
fn mempool_entry(&self, txid: &bitcoin::Txid) -> Option<MempoolEntry> {
self.mempool_entry(txid)
}

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?
Expand Down Expand Up @@ -454,6 +464,10 @@ impl BitcoinInterface for sync::Arc<sync::Mutex<dyn BitcoinInterface + 'static>>
fn mempool_entry(&self, txid: &bitcoin::Txid) -> Option<MempoolEntry> {
self.lock().unwrap().mempool_entry(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
Expand Down
4 changes: 4 additions & 0 deletions src/testutils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ impl BitcoinInterface for DummyBitcoind {
}
})
}

fn mempool_spenders(&self, _: &[bitcoin::OutPoint]) -> Vec<MempoolEntry> {
Vec::new()
}
}

struct DummyDbState {
Expand Down

0 comments on commit 575025d

Please sign in to comment.