Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions crates/chain/src/indexer/keychain_txout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1129,7 +1129,9 @@ pub trait SyncRequestBuilderExt<K> {
fn unused_spks_from_indexer(self, indexer: &KeychainTxOutIndex<K>) -> Self;
}

impl<K: Clone + Ord + core::fmt::Debug> SyncRequestBuilderExt<K> for SyncRequestBuilder<(K, u32)> {
impl<K: Clone + Ord + core::fmt::Debug, D> SyncRequestBuilderExt<K>
for SyncRequestBuilder<(K, u32), D>
{
fn revealed_spks_from_indexer<R>(self, indexer: &KeychainTxOutIndex<K>, spk_range: R) -> Self
where
R: core::ops::RangeBounds<K>,
Expand All @@ -1148,7 +1150,9 @@ pub trait FullScanRequestBuilderExt<K> {
fn spks_from_indexer(self, indexer: &KeychainTxOutIndex<K>) -> Self;
}

impl<K: Clone + Ord + core::fmt::Debug> FullScanRequestBuilderExt<K> for FullScanRequestBuilder<K> {
impl<K: Clone + Ord + core::fmt::Debug, D> FullScanRequestBuilderExt<K>
for FullScanRequestBuilder<K, D>
{
fn spks_from_indexer(mut self, indexer: &KeychainTxOutIndex<K>) -> Self {
for (keychain, spks) in indexer.all_unbounded_spk_iters() {
let last_revealed = indexer.last_revealed_index(keychain.clone());
Expand Down
7 changes: 5 additions & 2 deletions crates/chain/src/local_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ impl<D> PartialEq for LocalChain<D> {
}
}

// Methods for `LocalChain<BlockHash>`
impl LocalChain<BlockHash> {
// Methods for any `D`
impl<D> LocalChain<D> {
/// Check if a block is in the chain.
///
/// # Arguments
Expand Down Expand Up @@ -167,7 +167,10 @@ impl LocalChain<BlockHash> {
let canonical_txs = self.canonicalize(tx_graph.canonical_task(tip, params));
self.canonicalize(canonical_txs.view_task(tx_graph))
}
}

// Methods for `LocalChain<BlockHash>`
impl LocalChain<BlockHash> {
/// Update the chain with a given [`Header`] at `height` which you claim is connected to a
/// existing block in the chain.
///
Expand Down
6 changes: 3 additions & 3 deletions crates/chain/tests/test_canonical_view_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

mod common;

use bdk_chain::{CanonicalReason, ChainPosition};
use bdk_chain::{local_chain::LocalChain, CanonicalReason, ChainPosition};
use bdk_testenv::{block_id, hash, local_chain};
use bitcoin::Txid;
use bitcoin::{BlockHash, Txid};
use common::*;
use std::collections::HashSet;

Expand All @@ -13,7 +13,7 @@ fn test_assumed_canonical_scenarios() {
// scenario: "txC spends txB; txB spends txA; txB is anchored; txC is assumed canonical"

// create a local chain
let local_chain = local_chain![
let local_chain: LocalChain<BlockHash> = local_chain![
(0, hash!("genesis")),
(1, hash!("block1")),
(2, hash!("block2")),
Expand Down
35 changes: 35 additions & 0 deletions crates/chain/tests/test_keychain_txout_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,3 +761,38 @@ fn overlapping_descriptor_does_not_panic_in_release() {
let _ = index.insert_descriptor(1, single);
assert!(index.reveal_next_spk(1).is_none());
}

/// The request builder extensions work for any checkpoint data, not only `BlockHash`.
#[test]
fn request_builder_ext_works_with_any_checkpoint_data() {
use bdk_chain::{
bitcoin::{block::Header, constants::genesis_block, Network},
indexer::keychain_txout::{FullScanRequestBuilderExt, SyncRequestBuilderExt},
spk_client::{FullScanRequest, SyncRequest},
CheckPoint,
};

let mut indexer = init_txout_index(
parse_descriptor(DESCRIPTORS[0]),
parse_descriptor(DESCRIPTORS[1]),
0,
false,
);
let _ = indexer.reveal_to_target(TestKeychain::External, 2);
let tip = CheckPoint::<Header>::new(0, genesis_block(Network::Regtest).header);

let sync_request = SyncRequest::builder_at(0)
.chain_tip(tip.clone())
.revealed_spks_from_indexer(&indexer, ..)
.build();
assert_eq!(sync_request.spks().len(), 3);

let full_scan_request = FullScanRequest::builder_at(0)
.chain_tip(tip)
.spks_from_indexer(&indexer)
.build();
assert_eq!(
full_scan_request.last_revealed(&TestKeychain::External),
Some(2)
);
}
22 changes: 22 additions & 0 deletions crates/chain/tests/test_local_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,28 @@ fn header(prev_blockhash: BlockHash) -> Header {
}
}

/// A `LocalChain<Header>` answers chain queries and canonicalizes a `TxGraph`.
#[test]
fn local_chain_header_is_block_in_chain() {
let genesis = header(hash!("_"));
let block_1 = header(genesis.block_hash());
let (mut chain, _) = LocalChain::from_genesis(genesis);
chain.insert_block(1, block_1).expect("must connect");

let tip = chain.chain_tip();
assert_eq!(tip, BlockId::from((1, block_1.block_hash())));
let genesis_id = BlockId::from((0, genesis.block_hash()));
assert_eq!(chain.is_block_in_chain(genesis_id, tip), Some(true));
assert_eq!(
chain.is_block_in_chain(BlockId::from((0, hash!("other"))), tip),
Some(false)
);

let graph = bdk_chain::TxGraph::<BlockId>::default();
let view = chain.canonical_view(&graph, tip, Default::default());
assert_eq!(view.txs().count(), 0);
}

#[test]
fn local_chain_insert_header() {
// Create consecutive headers of height `n`, where the genesis header is height 0.
Expand Down
2 changes: 1 addition & 1 deletion crates/chain/tests/test_tx_graph_conflicts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1078,7 +1078,7 @@ fn test_tx_conflict_handling() {
/// height is only an upper bound until its own anchor is known.
#[test]
fn transitively_confirmed_tx_reports_descendant_anchor_height() {
let chain = local_chain![
let chain: LocalChain<BlockHash> = local_chain![
(0, hash!("genesis")),
(1, hash!("parent_block")),
(5, hash!("child_block"))
Expand Down
Loading