Skip to content

Commit 4b52510

Browse files
committed
refactor!: make CheckPoint, LocalChain, and SpkClient take a generic
1 parent 8d9df97 commit 4b52510

24 files changed

+562
-493
lines changed

crates/bitcoind_rpc/examples/filter_iter.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use bdk_chain::bitcoin::{constants::genesis_block, secp256k1::Secp256k1, Network
77
use bdk_chain::indexer::keychain_txout::KeychainTxOutIndex;
88
use bdk_chain::local_chain::LocalChain;
99
use bdk_chain::miniscript::Descriptor;
10-
use bdk_chain::{BlockId, ConfirmationBlockTime, IndexedTxGraph, SpkIterator};
10+
use bdk_chain::{ConfirmationBlockTime, IndexedTxGraph, SpkIterator};
1111
use bdk_testenv::anyhow;
1212
use bitcoin::Address;
1313

@@ -30,7 +30,7 @@ fn main() -> anyhow::Result<()> {
3030
let secp = Secp256k1::new();
3131
let (descriptor, _) = Descriptor::parse_descriptor(&secp, EXTERNAL)?;
3232
let (change_descriptor, _) = Descriptor::parse_descriptor(&secp, INTERNAL)?;
33-
let (mut chain, _) = LocalChain::from_genesis_hash(genesis_block(NETWORK).block_hash());
33+
let (mut chain, _) = LocalChain::from_genesis(genesis_block(NETWORK).block_hash());
3434

3535
let mut graph = IndexedTxGraph::<ConfirmationBlockTime, KeychainTxOutIndex<&str>>::new({
3636
let mut index = KeychainTxOutIndex::default();
@@ -40,11 +40,7 @@ fn main() -> anyhow::Result<()> {
4040
});
4141

4242
// Assume a minimum birthday height
43-
let block = BlockId {
44-
height: START_HEIGHT,
45-
hash: START_HASH.parse()?,
46-
};
47-
let _ = chain.insert_block(block)?;
43+
let _ = chain.insert_block(START_HEIGHT, START_HASH.parse()?)?;
4844

4945
// Configure RPC client
5046
let url = std::env::var("RPC_URL").context("must set RPC_URL")?;

crates/bitcoind_rpc/src/bip158.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub struct FilterIter<'c, C> {
3030
// SPK inventory
3131
spks: Vec<ScriptBuf>,
3232
// local cp
33-
cp: Option<CheckPoint>,
33+
cp: Option<CheckPoint<BlockHash>>,
3434
// blocks map
3535
blocks: BTreeMap<Height, BlockHash>,
3636
// best height counter
@@ -53,7 +53,7 @@ impl<'c, C: RpcApi> FilterIter<'c, C> {
5353
}
5454

5555
/// Construct [`FilterIter`] from a given `client` and [`CheckPoint`].
56-
pub fn new_with_checkpoint(client: &'c C, cp: CheckPoint) -> Self {
56+
pub fn new_with_checkpoint(client: &'c C, cp: CheckPoint<BlockHash>) -> Self {
5757
let mut filter_iter = Self::new_with_height(client, cp.height());
5858
filter_iter.cp = Some(cp);
5959
filter_iter
@@ -199,7 +199,7 @@ impl<C: RpcApi> Iterator for FilterIter<'_, C> {
199199

200200
impl<C: RpcApi> FilterIter<'_, C> {
201201
/// Returns the point of agreement between `self` and the given `cp`.
202-
fn find_base_with(&mut self, mut cp: CheckPoint) -> Result<BlockId, Error> {
202+
fn find_base_with(&mut self, mut cp: CheckPoint<BlockHash>) -> Result<BlockId, Error> {
203203
loop {
204204
let height = cp.height();
205205
let fetched_hash = match self.blocks.get(&height) {
@@ -222,15 +222,15 @@ impl<C: RpcApi> FilterIter<'_, C> {
222222
///
223223
/// Returns `None` if this [`FilterIter`] was not constructed using a [`CheckPoint`], or
224224
/// if no blocks have been fetched for example by using [`get_tip`](Self::get_tip).
225-
pub fn chain_update(&mut self) -> Option<CheckPoint> {
225+
pub fn chain_update(&mut self) -> Option<CheckPoint<BlockHash>> {
226226
if self.cp.is_none() || self.blocks.is_empty() {
227227
return None;
228228
}
229229

230230
// note: to connect with the local chain we must guarantee that `self.blocks.first()`
231231
// is also the point of agreement with `self.cp`.
232232
Some(
233-
CheckPoint::from_block_ids(self.blocks.iter().map(BlockId::from))
233+
CheckPoint::from_blocks(self.blocks.iter().map(|(&height, &hash)| (height, hash)))
234234
.expect("blocks must be in order"),
235235
)
236236
}

crates/bitcoind_rpc/src/lib.rs

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub struct Emitter<C> {
3636

3737
/// The checkpoint of the last-emitted block that is in the best chain. If it is later found
3838
/// that the block is no longer in the best chain, it will be popped off from here.
39-
last_cp: CheckPoint,
39+
last_cp: CheckPoint<BlockHash>,
4040

4141
/// The block result returned from rpc of the last-emitted block. As this result contains the
4242
/// next block's block hash (which we use to fetch the next block), we set this to `None`
@@ -80,7 +80,7 @@ where
8080
/// If it is known that the wallet is empty, [`NO_EXPECTED_MEMPOOL_TXS`] can be used.
8181
pub fn new(
8282
client: C,
83-
last_cp: CheckPoint,
83+
last_cp: CheckPoint<BlockHash>,
8484
start_height: u32,
8585
expected_mempool_txs: impl IntoIterator<Item = impl Into<Arc<Transaction>>>,
8686
) -> Self {
@@ -235,7 +235,7 @@ pub struct BlockEvent<B> {
235235
///
236236
/// This is important as BDK structures require block-to-apply to be connected with another
237237
/// block in the original chain.
238-
pub checkpoint: CheckPoint,
238+
pub checkpoint: CheckPoint<BlockHash>,
239239
}
240240

241241
impl<B> BlockEvent<B> {
@@ -269,7 +269,7 @@ enum PollResponse {
269269
NoMoreBlocks,
270270
/// Fetched block is not in the best chain.
271271
BlockNotInBestChain,
272-
AgreementFound(bitcoincore_rpc_json::GetBlockResult, CheckPoint),
272+
AgreementFound(bitcoincore_rpc_json::GetBlockResult, CheckPoint<BlockHash>),
273273
/// Force the genesis checkpoint down the receiver's throat.
274274
AgreementPointNotFound(BlockHash),
275275
}
@@ -331,7 +331,7 @@ where
331331
fn poll<C, V, F>(
332332
emitter: &mut Emitter<C>,
333333
get_item: F,
334-
) -> Result<Option<(CheckPoint, V)>, bitcoincore_rpc::Error>
334+
) -> Result<Option<(CheckPoint<BlockHash>, V)>, bitcoincore_rpc::Error>
335335
where
336336
C: Deref,
337337
C::Target: RpcApi,
@@ -347,7 +347,7 @@ where
347347
let new_cp = emitter
348348
.last_cp
349349
.clone()
350-
.push(BlockId { height, hash })
350+
.push(height, hash)
351351
.expect("must push");
352352
emitter.last_cp = new_cp.clone();
353353
emitter.last_block = Some(res);
@@ -368,10 +368,7 @@ where
368368
continue;
369369
}
370370
PollResponse::AgreementPointNotFound(genesis_hash) => {
371-
emitter.last_cp = CheckPoint::new(BlockId {
372-
height: 0,
373-
hash: genesis_hash,
374-
});
371+
emitter.last_cp = CheckPoint::new(0, genesis_hash);
375372
emitter.last_block = None;
376373
continue;
377374
}
@@ -411,7 +408,7 @@ mod test {
411408
#[test]
412409
fn test_expected_mempool_txids_accumulate_and_remove() -> anyhow::Result<()> {
413410
let env = TestEnv::new()?;
414-
let chain = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?).0;
411+
let chain = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?).0;
415412
let chain_tip = chain.tip();
416413
let mut emitter = Emitter::new(
417414
env.rpc_client(),

crates/bitcoind_rpc/tests/test_emitter.rs

Lines changed: 11 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ use bitcoincore_rpc::RpcApi;
2121
pub fn test_sync_local_chain() -> anyhow::Result<()> {
2222
let env = TestEnv::new()?;
2323
let network_tip = env.rpc_client().get_block_count()?;
24-
let (mut local_chain, _) = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?);
24+
let (mut local_chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?);
2525
let mut emitter = Emitter::new(
2626
env.rpc_client(),
2727
local_chain.tip(),
@@ -152,7 +152,7 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
152152

153153
env.mine_blocks(101, None)?;
154154

155-
let (mut chain, _) = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?);
155+
let (mut chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?);
156156
let mut indexed_tx_graph = IndexedTxGraph::<BlockId, _>::new({
157157
let mut index = SpkTxOutIndex::<usize>::default();
158158
index.insert_spk(0, addr_0.script_pubkey());
@@ -252,10 +252,7 @@ fn ensure_block_emitted_after_reorg_is_at_reorg_height() -> anyhow::Result<()> {
252252
let env = TestEnv::new()?;
253253
let mut emitter = Emitter::new(
254254
env.rpc_client(),
255-
CheckPoint::new(BlockId {
256-
height: 0,
257-
hash: env.rpc_client().get_block_hash(0)?,
258-
}),
255+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
259256
EMITTER_START_HEIGHT as _,
260257
NO_EXPECTED_MEMPOOL_TXS,
261258
);
@@ -286,7 +283,7 @@ fn process_block(
286283
block: Block,
287284
block_height: u32,
288285
) -> anyhow::Result<()> {
289-
recv_chain.apply_update(CheckPoint::from_header(&block.header, block_height))?;
286+
recv_chain.apply_header(&block.header, block_height)?;
290287
let _ = recv_graph.apply_block(block, block_height);
291288
Ok(())
292289
}
@@ -334,10 +331,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
334331
let env = TestEnv::new()?;
335332
let mut emitter = Emitter::new(
336333
env.rpc_client(),
337-
CheckPoint::new(BlockId {
338-
height: 0,
339-
hash: env.rpc_client().get_block_hash(0)?,
340-
}),
334+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
341335
0,
342336
NO_EXPECTED_MEMPOOL_TXS,
343337
);
@@ -351,7 +345,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
351345
let addr_to_track = Address::from_script(&spk_to_track, Network::Regtest)?;
352346

353347
// setup receiver
354-
let (mut recv_chain, _) = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?);
348+
let (mut recv_chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?);
355349
let mut recv_graph = IndexedTxGraph::<BlockId, _>::new({
356350
let mut recv_index = SpkTxOutIndex::default();
357351
recv_index.insert_spk((), spk_to_track.clone());
@@ -425,10 +419,7 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> {
425419
let env = TestEnv::new()?;
426420
let mut emitter = Emitter::new(
427421
env.rpc_client(),
428-
CheckPoint::new(BlockId {
429-
height: 0,
430-
hash: env.rpc_client().get_block_hash(0)?,
431-
}),
422+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
432423
0,
433424
NO_EXPECTED_MEMPOOL_TXS,
434425
);
@@ -498,10 +489,7 @@ fn no_agreement_point() -> anyhow::Result<()> {
498489
// start height is 99
499490
let mut emitter = Emitter::new(
500491
env.rpc_client(),
501-
CheckPoint::new(BlockId {
502-
height: 0,
503-
hash: env.rpc_client().get_block_hash(0)?,
504-
}),
492+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
505493
(PREMINE_COUNT - 2) as u32,
506494
NO_EXPECTED_MEMPOOL_TXS,
507495
);
@@ -573,7 +561,7 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> {
573561
.0;
574562
let spk = desc.at_derivation_index(0)?.script_pubkey();
575563

576-
let mut chain = LocalChain::from_genesis_hash(genesis_block(Network::Regtest).block_hash()).0;
564+
let mut chain = LocalChain::from_genesis(genesis_block(Network::Regtest).block_hash()).0;
577565
let chain_tip = chain.tip().block_id();
578566

579567
let mut index = SpkTxOutIndex::default();
@@ -594,7 +582,7 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> {
594582
let mut emitter = Emitter::new(env.rpc_client(), chain.tip(), 1, core::iter::once(tx_1));
595583
while let Some(emission) = emitter.next_block()? {
596584
let height = emission.block_height();
597-
chain.apply_update(CheckPoint::from_header(&emission.block.header, height))?;
585+
chain.apply_header(&emission.block.header, height)?;
598586
}
599587

600588
let changeset = graph.batch_insert_unconfirmed(emitter.mempool()?.update);
@@ -670,10 +658,7 @@ fn detect_new_mempool_txs() -> anyhow::Result<()> {
670658

671659
let mut emitter = Emitter::new(
672660
env.rpc_client(),
673-
CheckPoint::new(BlockId {
674-
height: 0,
675-
hash: env.rpc_client().get_block_hash(0)?,
676-
}),
661+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
677662
0,
678663
NO_EXPECTED_MEMPOOL_TXS,
679664
);

crates/bitcoind_rpc/tests/test_filter_iter.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,12 @@ fn get_tip_and_chain_update() -> anyhow::Result<()> {
9797
]
9898
.into_iter()
9999
.for_each(|test| {
100-
let cp = CheckPoint::from_block_ids(test.chain).unwrap();
100+
let cp = CheckPoint::from_blocks(
101+
test.chain
102+
.iter()
103+
.map(|block_id| (block_id.height, block_id.hash)),
104+
)
105+
.unwrap();
101106
let mut iter = FilterIter::new_with_checkpoint(env.rpc_client(), cp);
102107
assert_eq!(iter.get_tip().unwrap(), Some(new_tip));
103108
let update_cp = iter.chain_update().unwrap();

crates/chain/benches/canonicalization.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,12 @@ fn add_ancestor_tx(graph: &mut KeychainTxGraph, block_id: BlockId, locktime: u32
7676

7777
fn setup<F: Fn(&mut KeychainTxGraph, &LocalChain)>(f: F) -> (KeychainTxGraph, LocalChain) {
7878
const DESC: &str = "tr([ab28dc00/86h/1h/0h]tpubDCdDtzAMZZrkwKBxwNcGCqe4FRydeD9rfMisoi7qLdraG79YohRfPW4YgdKQhpgASdvh612xXNY5xYzoqnyCgPbkpK4LSVcH5Xv4cK7johH/0/*)";
79-
let cp = CheckPoint::from_block_ids([genesis_block_id(), tip_block_id()])
80-
.expect("blocks must be chronological");
79+
let cp = CheckPoint::from_blocks(
80+
[genesis_block_id(), tip_block_id()]
81+
.into_iter()
82+
.map(|block_id| (block_id.height, block_id.hash)),
83+
)
84+
.expect("blocks must be chronological");
8185
let chain = LocalChain::from_tip(cp).unwrap();
8286

8387
let (desc, _) =

crates/chain/benches/indexer.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ fn setup<F: Fn(&mut KeychainTxGraph, &LocalChain)>(f: F) -> (KeychainTxGraph, Lo
5050
.unwrap()
5151
.0;
5252

53-
let cp = CheckPoint::from_block_ids([genesis_block_id(), tip_block_id()]).unwrap();
53+
let cp = CheckPoint::from_blocks(
54+
[genesis_block_id(), tip_block_id()]
55+
.into_iter()
56+
.map(|block_id| (block_id.height, block_id.hash)),
57+
)
58+
.unwrap();
5459
let chain = LocalChain::from_tip(cp).unwrap();
5560

5661
let mut index = KeychainTxOutIndex::new(LOOKAHEAD, USE_SPK_CACHE);

0 commit comments

Comments
 (0)