Skip to content

Commit 7e894f4

Browse files
committed
feat(bitcoind_rpc)!: Use getrawmempool without verbose
This is the more performant method. The downside is that mempool txids are not returned to the seen-in-mempool timestamps so the caller either needs to provide this, or we need to rely on std to get the current timestamp. * `Emitter::mempool` method now requires the `std` feature. A non-std version of this is added: `Emitter::mempool_at` which takes in a `sync_time` parameter. Additional changes: * `NO_EXPECTED_MEMPOOL_TXIDS` is renamed to `NO_EXPECTED_MEMPOOL_TXS`. * Updated documentation. * Fix imports so that `bdk_bitcoind_rpc` compiles without `std`.
1 parent 05464ec commit 7e894f4

File tree

2 files changed

+41
-36
lines changed

2 files changed

+41
-36
lines changed

crates/bitcoind_rpc/src/lib.rs

Lines changed: 33 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,16 @@
99
//! separate method, [`Emitter::mempool`] can be used to emit the whole mempool.
1010
#![warn(missing_docs)]
1111

12+
#[allow(unused_imports)]
13+
#[macro_use]
14+
extern crate alloc;
15+
16+
use alloc::sync::Arc;
17+
use bdk_core::collections::{HashMap, HashSet};
1218
use bdk_core::{BlockId, CheckPoint};
1319
use bitcoin::{Block, BlockHash, Transaction, Txid};
1420
use bitcoincore_rpc::{bitcoincore_rpc_json, RpcApi};
15-
use std::{
16-
collections::{HashMap, HashSet},
17-
ops::Deref,
18-
sync::Arc,
19-
};
21+
use core::ops::Deref;
2022

2123
pub mod bip158;
2224

@@ -53,11 +55,11 @@ pub struct Emitter<C> {
5355
mempool_snapshot: HashMap<Txid, Arc<Transaction>>,
5456
}
5557

56-
/// Indicates that there are no initially expected mempool transactions.
58+
/// Indicates that there are no initially-expected mempool transactions.
5759
///
58-
/// Pass this to the `expected_mempool_txids` field of [`Emitter::new`] when the wallet is known
60+
/// Use this as the `expected_mempool_txs` field of [`Emitter::new`] when the wallet is known
5961
/// to start empty (i.e. with no unconfirmed transactions).
60-
pub const NO_EXPECTED_MEMPOOL_TXIDS: core::iter::Empty<Arc<Transaction>> = core::iter::empty();
62+
pub const NO_EXPECTED_MEMPOOL_TXS: core::iter::Empty<Arc<Transaction>> = core::iter::empty();
6163

6264
impl<C> Emitter<C>
6365
where
@@ -74,7 +76,7 @@ where
7476
///
7577
/// `expected_mempool_txs` is the initial set of unconfirmed transactions provided by the
7678
/// wallet. This allows the [`Emitter`] to inform the wallet about relevant mempool evictions.
77-
/// If it is known that the wallet is empty, [`NO_EXPECTED_MEMPOOL_TXIDS`] can be used.
79+
/// If it is known that the wallet is empty, [`NO_EXPECTED_MEMPOOL_TXS`] can be used.
7880
pub fn new(
7981
client: C,
8082
last_cp: CheckPoint,
@@ -99,21 +101,26 @@ where
99101
/// Emit mempool transactions and any evicted [`Txid`]s.
100102
///
101103
/// This method returns a [`MempoolEvent`] containing the full transactions (with their
102-
/// first-seen unix timestamps) that were emitted, and [`MempoolEvent::evicted_txids`] which are
104+
/// first-seen unix timestamps) that were emitted, and [`MempoolEvent::evicted`] which are
103105
/// any [`Txid`]s which were previously seen in the mempool and are now missing. Evicted txids
104106
/// are only reported once the emitter’s checkpoint matches the RPC’s best block in both height
105107
/// and hash. Until `next_block()` advances the checkpoint to tip, `mempool()` will always
106-
/// return an empty `evicted_txids` set.
108+
/// return an empty `evicted` set.
109+
#[cfg(feature = "std")]
110+
pub fn mempool(&mut self) -> Result<MempoolEvent, bitcoincore_rpc::Error> {
111+
let sync_time = std::time::UNIX_EPOCH
112+
.elapsed()
113+
.expect("must get current time")
114+
.as_secs();
115+
self.mempool_at(sync_time)
116+
}
117+
118+
/// Emit mempool transactions and any evicted [`Txid`]s at the given `sync_time`.
107119
///
108-
/// This method emits each transaction only once, unless we cannot guarantee the transaction's
109-
/// ancestors are already emitted.
120+
/// `sync_time` is in unix seconds.
110121
///
111-
/// To understand why, consider a receiver which filters transactions based on whether it
112-
/// alters the UTXO set of tracked script pubkeys. If an emitted mempool transaction spends a
113-
/// tracked UTXO which is confirmed at height `h`, but the receiver has only seen up to block
114-
/// of height `h-1`, we want to re-emit this transaction until the receiver has seen the block
115-
/// at height `h`.
116-
pub fn mempool(&mut self) -> Result<MempoolEvent, bitcoincore_rpc::Error> {
122+
/// This is the no-std version of [`mempool`](Self::mempool).
123+
pub fn mempool_at(&mut self, sync_time: u64) -> Result<MempoolEvent, bitcoincore_rpc::Error> {
117124
let client = &*self.client;
118125

119126
let mut rpc_tip_height;
@@ -125,8 +132,8 @@ where
125132
loop {
126133
rpc_tip_height = client.get_block_count()?;
127134
rpc_tip_hash = client.get_block_hash(rpc_tip_height)?;
128-
rpc_mempool = client.get_raw_mempool_verbose()?;
129-
rpc_mempool_txids = rpc_mempool.keys().copied().collect::<HashSet<Txid>>();
135+
rpc_mempool = client.get_raw_mempool()?;
136+
rpc_mempool_txids = rpc_mempool.iter().copied().collect::<HashSet<Txid>>();
130137
let is_still_at_tip = rpc_tip_hash == client.get_block_hash(rpc_tip_height)?
131138
&& rpc_tip_height == client.get_block_count()?;
132139
if is_still_at_tip {
@@ -135,13 +142,11 @@ where
135142
}
136143

137144
let mut mempool_event = MempoolEvent::default();
138-
let update_time = &mut 0_u64;
139145

140146
mempool_event.update = rpc_mempool
141147
.into_iter()
142148
.filter_map({
143-
|(txid, tx_entry)| -> Option<Result<_, bitcoincore_rpc::Error>> {
144-
*update_time = u64::max(*update_time, tx_entry.time);
149+
|txid| -> Option<Result<_, bitcoincore_rpc::Error>> {
145150
let tx = match self.mempool_snapshot.get(&txid) {
146151
Some(tx) => tx.clone(),
147152
None => match client.get_raw_transaction(&txid, None) {
@@ -154,7 +159,7 @@ where
154159
Err(err) => return Some(Err(err)),
155160
},
156161
};
157-
Some(Ok((tx, tx_entry.time)))
162+
Some(Ok((tx, sync_time)))
158163
}
159164
})
160165
.collect::<Result<Vec<_>, _>>()?;
@@ -171,7 +176,7 @@ where
171176
.mempool_snapshot
172177
.keys()
173178
.filter(|&txid| !rpc_mempool_txids.contains(txid))
174-
.map(|&txid| (txid, *update_time))
179+
.map(|&txid| (txid, sync_time))
175180
.collect();
176181
self.mempool_snapshot = mempool_event
177182
.update
@@ -396,7 +401,7 @@ impl BitcoindRpcErrorExt for bitcoincore_rpc::Error {
396401

397402
#[cfg(test)]
398403
mod test {
399-
use crate::{bitcoincore_rpc::RpcApi, Emitter, NO_EXPECTED_MEMPOOL_TXIDS};
404+
use crate::{bitcoincore_rpc::RpcApi, Emitter, NO_EXPECTED_MEMPOOL_TXS};
400405
use bdk_chain::local_chain::LocalChain;
401406
use bdk_testenv::{anyhow, TestEnv};
402407
use bitcoin::{hashes::Hash, Address, Amount, ScriptBuf, Txid, WScriptHash};
@@ -411,7 +416,7 @@ mod test {
411416
env.rpc_client(),
412417
chain_tip.clone(),
413418
1,
414-
NO_EXPECTED_MEMPOOL_TXIDS,
419+
NO_EXPECTED_MEMPOOL_TXS,
415420
);
416421

417422
env.mine_blocks(100, None)?;

crates/bitcoind_rpc/tests/test_emitter.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{collections::BTreeSet, ops::Deref};
22

3-
use bdk_bitcoind_rpc::{Emitter, NO_EXPECTED_MEMPOOL_TXIDS};
3+
use bdk_bitcoind_rpc::{Emitter, NO_EXPECTED_MEMPOOL_TXS};
44
use bdk_chain::{
55
bitcoin::{Address, Amount, Txid},
66
local_chain::{CheckPoint, LocalChain},
@@ -26,7 +26,7 @@ pub fn test_sync_local_chain() -> anyhow::Result<()> {
2626
env.rpc_client(),
2727
local_chain.tip(),
2828
0,
29-
NO_EXPECTED_MEMPOOL_TXIDS,
29+
NO_EXPECTED_MEMPOOL_TXS,
3030
);
3131

3232
// Mine some blocks and return the actual block hashes.
@@ -161,7 +161,7 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
161161
index
162162
});
163163

164-
let emitter = &mut Emitter::new(env.rpc_client(), chain.tip(), 0, NO_EXPECTED_MEMPOOL_TXIDS);
164+
let emitter = &mut Emitter::new(env.rpc_client(), chain.tip(), 0, NO_EXPECTED_MEMPOOL_TXS);
165165

166166
while let Some(emission) = emitter.next_block()? {
167167
let height = emission.block_height();
@@ -257,7 +257,7 @@ fn ensure_block_emitted_after_reorg_is_at_reorg_height() -> anyhow::Result<()> {
257257
hash: env.rpc_client().get_block_hash(0)?,
258258
}),
259259
EMITTER_START_HEIGHT as _,
260-
NO_EXPECTED_MEMPOOL_TXIDS,
260+
NO_EXPECTED_MEMPOOL_TXS,
261261
);
262262

263263
env.mine_blocks(CHAIN_TIP_HEIGHT, None)?;
@@ -339,7 +339,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
339339
hash: env.rpc_client().get_block_hash(0)?,
340340
}),
341341
0,
342-
NO_EXPECTED_MEMPOOL_TXIDS,
342+
NO_EXPECTED_MEMPOOL_TXS,
343343
);
344344

345345
// setup addresses
@@ -430,7 +430,7 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> {
430430
hash: env.rpc_client().get_block_hash(0)?,
431431
}),
432432
0,
433-
NO_EXPECTED_MEMPOOL_TXIDS,
433+
NO_EXPECTED_MEMPOOL_TXS,
434434
);
435435

436436
// mine blocks and sync up emitter
@@ -503,7 +503,7 @@ fn no_agreement_point() -> anyhow::Result<()> {
503503
hash: env.rpc_client().get_block_hash(0)?,
504504
}),
505505
(PREMINE_COUNT - 2) as u32,
506-
NO_EXPECTED_MEMPOOL_TXIDS,
506+
NO_EXPECTED_MEMPOOL_TXS,
507507
);
508508

509509
// mine 101 blocks
@@ -675,7 +675,7 @@ fn detect_new_mempool_txs() -> anyhow::Result<()> {
675675
hash: env.rpc_client().get_block_hash(0)?,
676676
}),
677677
0,
678-
NO_EXPECTED_MEMPOOL_TXIDS,
678+
NO_EXPECTED_MEMPOOL_TXS,
679679
);
680680

681681
while emitter.next_block()?.is_some() {}

0 commit comments

Comments
 (0)