Skip to content

Commit bf2ee94

Browse files
committed
refactor!: make CheckPoint, LocalChain, and SpkClient take a generic
1 parent 5e49d3e commit bf2ee94

22 files changed

+546
-492
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
let mut graph = IndexedTxGraph::<ConfirmationBlockTime, KeychainTxOutIndex<&str>>::new({
3535
let mut index = KeychainTxOutIndex::default();
3636
index.insert_descriptor("external", descriptor.clone())?;
@@ -39,11 +39,7 @@ fn main() -> anyhow::Result<()> {
3939
});
4040

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

4844
// Configure RPC client
4945
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
@@ -28,7 +28,7 @@ pub struct Emitter<C> {
2828

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

3333
/// The block result returned from rpc of the last-emitted block. As this result contains the
3434
/// next block's block hash (which we use to fetch the next block), we set this to `None`
@@ -79,7 +79,7 @@ where
7979
/// known that the wallet is empty, [`NO_EXPECTED_MEMPOOL_TXIDS`] can be used.
8080
pub fn new(
8181
client: C,
82-
last_cp: CheckPoint,
82+
last_cp: CheckPoint<BlockHash>,
8383
start_height: u32,
8484
expected_mempool_txids: impl IntoIterator<Item = impl Into<Txid>>,
8585
) -> Self {
@@ -268,7 +268,7 @@ pub struct BlockEvent<B> {
268268
///
269269
/// This is important as BDK structures require block-to-apply to be connected with another
270270
/// block in the original chain.
271-
pub checkpoint: CheckPoint,
271+
pub checkpoint: CheckPoint<BlockHash>,
272272
}
273273

274274
impl<B> BlockEvent<B> {
@@ -302,7 +302,7 @@ enum PollResponse {
302302
NoMoreBlocks,
303303
/// Fetched block is not in the best chain.
304304
BlockNotInBestChain,
305-
AgreementFound(bitcoincore_rpc_json::GetBlockResult, CheckPoint),
305+
AgreementFound(bitcoincore_rpc_json::GetBlockResult, CheckPoint<BlockHash>),
306306
/// Force the genesis checkpoint down the receiver's throat.
307307
AgreementPointNotFound(BlockHash),
308308
}
@@ -364,7 +364,7 @@ where
364364
fn poll<C, V, F>(
365365
emitter: &mut Emitter<C>,
366366
get_item: F,
367-
) -> Result<Option<(CheckPoint, V)>, bitcoincore_rpc::Error>
367+
) -> Result<Option<(CheckPoint<BlockHash>, V)>, bitcoincore_rpc::Error>
368368
where
369369
C: Deref,
370370
C::Target: RpcApi,
@@ -380,7 +380,7 @@ where
380380
let new_cp = emitter
381381
.last_cp
382382
.clone()
383-
.push(BlockId { height, hash })
383+
.push(height, hash)
384384
.expect("must push");
385385
emitter.last_cp = new_cp.clone();
386386
emitter.last_block = Some(res);
@@ -411,10 +411,7 @@ where
411411
continue;
412412
}
413413
PollResponse::AgreementPointNotFound(genesis_hash) => {
414-
emitter.last_cp = CheckPoint::new(BlockId {
415-
height: 0,
416-
hash: genesis_hash,
417-
});
414+
emitter.last_cp = CheckPoint::new(0, genesis_hash);
418415
emitter.last_block = None;
419416
continue;
420417
}
@@ -453,7 +450,7 @@ mod test {
453450
#[test]
454451
fn test_expected_mempool_txids_accumulate_and_remove() -> anyhow::Result<()> {
455452
let env = TestEnv::new()?;
456-
let chain = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?).0;
453+
let chain = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?).0;
457454
let chain_tip = chain.tip();
458455
let mut emitter = Emitter::new(
459456
env.rpc_client(),

crates/bitcoind_rpc/tests/test_emitter.rs

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use bitcoincore_rpc::RpcApi;
2424
pub fn test_sync_local_chain() -> anyhow::Result<()> {
2525
let env = TestEnv::new()?;
2626
let network_tip = env.rpc_client().get_block_count()?;
27-
let (mut local_chain, _) = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?);
27+
let (mut local_chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?);
2828
let mut emitter = Emitter::new(
2929
env.rpc_client(),
3030
local_chain.tip(),
@@ -155,7 +155,7 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
155155

156156
env.mine_blocks(101, None)?;
157157

158-
let (mut chain, _) = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?);
158+
let (mut chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?);
159159
let mut indexed_tx_graph = IndexedTxGraph::<BlockId, _>::new({
160160
let mut index = SpkTxOutIndex::<usize>::default();
161161
index.insert_spk(0, addr_0.script_pubkey());
@@ -255,10 +255,7 @@ fn ensure_block_emitted_after_reorg_is_at_reorg_height() -> anyhow::Result<()> {
255255
let env = TestEnv::new()?;
256256
let mut emitter = Emitter::new(
257257
env.rpc_client(),
258-
CheckPoint::new(BlockId {
259-
height: 0,
260-
hash: env.rpc_client().get_block_hash(0)?,
261-
}),
258+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
262259
EMITTER_START_HEIGHT as _,
263260
NO_EXPECTED_MEMPOOL_TXIDS,
264261
);
@@ -289,7 +286,7 @@ fn process_block(
289286
block: Block,
290287
block_height: u32,
291288
) -> anyhow::Result<()> {
292-
recv_chain.apply_update(CheckPoint::from_header(&block.header, block_height))?;
289+
recv_chain.apply_header(&block.header, block_height)?;
293290
let _ = recv_graph.apply_block(block, block_height);
294291
Ok(())
295292
}
@@ -337,10 +334,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
337334
let env = TestEnv::new()?;
338335
let mut emitter = Emitter::new(
339336
env.rpc_client(),
340-
CheckPoint::new(BlockId {
341-
height: 0,
342-
hash: env.rpc_client().get_block_hash(0)?,
343-
}),
337+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
344338
0,
345339
NO_EXPECTED_MEMPOOL_TXIDS,
346340
);
@@ -354,7 +348,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
354348
let addr_to_track = Address::from_script(&spk_to_track, bitcoin::Network::Regtest)?;
355349

356350
// setup receiver
357-
let (mut recv_chain, _) = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?);
351+
let (mut recv_chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?);
358352
let mut recv_graph = IndexedTxGraph::<BlockId, _>::new({
359353
let mut recv_index = SpkTxOutIndex::default();
360354
recv_index.insert_spk((), spk_to_track.clone());
@@ -429,10 +423,7 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> {
429423
let env = TestEnv::new()?;
430424
let mut emitter = Emitter::new(
431425
env.rpc_client(),
432-
CheckPoint::new(BlockId {
433-
height: 0,
434-
hash: env.rpc_client().get_block_hash(0)?,
435-
}),
426+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
436427
0,
437428
NO_EXPECTED_MEMPOOL_TXIDS,
438429
);
@@ -496,10 +487,7 @@ fn mempool_re_emits_if_tx_introduction_height_not_reached() -> anyhow::Result<()
496487
let env = TestEnv::new()?;
497488
let mut emitter = Emitter::new(
498489
env.rpc_client(),
499-
CheckPoint::new(BlockId {
500-
height: 0,
501-
hash: env.rpc_client().get_block_hash(0)?,
502-
}),
490+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
503491
0,
504492
NO_EXPECTED_MEMPOOL_TXIDS,
505493
);
@@ -588,10 +576,7 @@ fn mempool_during_reorg() -> anyhow::Result<()> {
588576
let env = TestEnv::new()?;
589577
let mut emitter = Emitter::new(
590578
env.rpc_client(),
591-
CheckPoint::new(BlockId {
592-
height: 0,
593-
hash: env.rpc_client().get_block_hash(0)?,
594-
}),
579+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
595580
0,
596581
NO_EXPECTED_MEMPOOL_TXIDS,
597582
);
@@ -716,10 +701,7 @@ fn no_agreement_point() -> anyhow::Result<()> {
716701
// start height is 99
717702
let mut emitter = Emitter::new(
718703
env.rpc_client(),
719-
CheckPoint::new(BlockId {
720-
height: 0,
721-
hash: env.rpc_client().get_block_hash(0)?,
722-
}),
704+
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
723705
(PREMINE_COUNT - 2) as u32,
724706
NO_EXPECTED_MEMPOOL_TXIDS,
725707
);
@@ -791,7 +773,7 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> {
791773
.0;
792774
let spk = desc.at_derivation_index(0)?.script_pubkey();
793775

794-
let mut chain = LocalChain::from_genesis_hash(genesis_block(Network::Regtest).block_hash()).0;
776+
let mut chain = LocalChain::from_genesis(genesis_block(Network::Regtest).block_hash()).0;
795777
let chain_tip = chain.tip().block_id();
796778

797779
let mut index = SpkTxOutIndex::default();
@@ -808,7 +790,7 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> {
808790
let mut emitter = Emitter::new(env.rpc_client(), chain.tip(), 1, HashSet::from([txid_1]));
809791
while let Some(emission) = emitter.next_block()? {
810792
let height = emission.block_height();
811-
chain.apply_update(CheckPoint::from_header(&emission.block.header, height))?;
793+
chain.apply_header(&emission.block.header, height)?;
812794
}
813795

814796
let changeset = graph.batch_insert_unconfirmed(emitter.mempool()?.new_txs);

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, _) =

0 commit comments

Comments
 (0)