Skip to content

refactor!: Implement generics for CheckPoint, LocalChain, and spk_client types #1582

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
10 changes: 3 additions & 7 deletions crates/bitcoind_rpc/examples/filter_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bdk_chain::bitcoin::{constants::genesis_block, secp256k1::Secp256k1, Network
use bdk_chain::indexer::keychain_txout::KeychainTxOutIndex;
use bdk_chain::local_chain::LocalChain;
use bdk_chain::miniscript::Descriptor;
use bdk_chain::{BlockId, ConfirmationBlockTime, IndexedTxGraph, SpkIterator};
use bdk_chain::{ConfirmationBlockTime, IndexedTxGraph, SpkIterator};
use bdk_testenv::anyhow;
use bitcoin::Address;

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

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

// Assume a minimum birthday height
let block = BlockId {
height: START_HEIGHT,
hash: START_HASH.parse()?,
};
let _ = chain.insert_block(block)?;
let _ = chain.insert_block(START_HEIGHT, START_HASH.parse()?)?;

// Configure RPC client
let url = std::env::var("RPC_URL").context("must set RPC_URL")?;
Expand Down
10 changes: 5 additions & 5 deletions crates/bitcoind_rpc/src/bip158.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub struct FilterIter<'c, C> {
// SPK inventory
spks: Vec<ScriptBuf>,
// local cp
cp: Option<CheckPoint>,
cp: Option<CheckPoint<BlockHash>>,
// blocks map
blocks: BTreeMap<Height, BlockHash>,
// best height counter
Expand All @@ -53,7 +53,7 @@ impl<'c, C: RpcApi> FilterIter<'c, C> {
}

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

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

// note: to connect with the local chain we must guarantee that `self.blocks.first()`
// is also the point of agreement with `self.cp`.
Some(
CheckPoint::from_block_ids(self.blocks.iter().map(BlockId::from))
CheckPoint::from_blocks(self.blocks.iter().map(|(&height, &hash)| (height, hash)))
.expect("blocks must be in order"),
)
}
Expand Down
19 changes: 8 additions & 11 deletions crates/bitcoind_rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct Emitter<C> {

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

/// The block result returned from rpc of the last-emitted block. As this result contains the
/// next block's block hash (which we use to fetch the next block), we set this to `None`
Expand Down Expand Up @@ -80,7 +80,7 @@ where
/// known that the wallet is empty, [`NO_EXPECTED_MEMPOOL_TXIDS`] can be used.
pub fn new(
client: C,
last_cp: CheckPoint,
last_cp: CheckPoint<BlockHash>,
start_height: u32,
expected_mempool_txids: impl IntoIterator<Item = impl Into<Txid>>,
) -> Self {
Expand Down Expand Up @@ -269,7 +269,7 @@ pub struct BlockEvent<B> {
///
/// This is important as BDK structures require block-to-apply to be connected with another
/// block in the original chain.
pub checkpoint: CheckPoint,
pub checkpoint: CheckPoint<BlockHash>,
}

impl<B> BlockEvent<B> {
Expand Down Expand Up @@ -303,7 +303,7 @@ enum PollResponse {
NoMoreBlocks,
/// Fetched block is not in the best chain.
BlockNotInBestChain,
AgreementFound(bitcoincore_rpc_json::GetBlockResult, CheckPoint),
AgreementFound(bitcoincore_rpc_json::GetBlockResult, CheckPoint<BlockHash>),
/// Force the genesis checkpoint down the receiver's throat.
AgreementPointNotFound(BlockHash),
}
Expand Down Expand Up @@ -365,7 +365,7 @@ where
fn poll<C, V, F>(
emitter: &mut Emitter<C>,
get_item: F,
) -> Result<Option<(CheckPoint, V)>, bitcoincore_rpc::Error>
) -> Result<Option<(CheckPoint<BlockHash>, V)>, bitcoincore_rpc::Error>
where
C: Deref,
C::Target: RpcApi,
Expand All @@ -381,7 +381,7 @@ where
let new_cp = emitter
.last_cp
.clone()
.push(BlockId { height, hash })
.push(height, hash)
.expect("must push");
emitter.last_cp = new_cp.clone();
emitter.last_block = Some(res);
Expand Down Expand Up @@ -412,10 +412,7 @@ where
continue;
}
PollResponse::AgreementPointNotFound(genesis_hash) => {
emitter.last_cp = CheckPoint::new(BlockId {
height: 0,
hash: genesis_hash,
});
emitter.last_cp = CheckPoint::new(0, genesis_hash);
emitter.last_block = None;
continue;
}
Expand Down Expand Up @@ -454,7 +451,7 @@ mod test {
#[test]
fn test_expected_mempool_txids_accumulate_and_remove() -> anyhow::Result<()> {
let env = TestEnv::new()?;
let chain = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?).0;
let chain = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?).0;
let chain_tip = chain.tip();
let mut emitter = Emitter::new(
env.rpc_client(),
Expand Down
42 changes: 12 additions & 30 deletions crates/bitcoind_rpc/tests/test_emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use bitcoincore_rpc::RpcApi;
pub fn test_sync_local_chain() -> anyhow::Result<()> {
let env = TestEnv::new()?;
let network_tip = env.rpc_client().get_block_count()?;
let (mut local_chain, _) = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?);
let (mut local_chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?);
let mut emitter = Emitter::new(
env.rpc_client(),
local_chain.tip(),
Expand Down Expand Up @@ -155,7 +155,7 @@ fn test_into_tx_graph() -> anyhow::Result<()> {

env.mine_blocks(101, None)?;

let (mut chain, _) = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?);
let (mut chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?);
let mut indexed_tx_graph = IndexedTxGraph::<BlockId, _>::new({
let mut index = SpkTxOutIndex::<usize>::default();
index.insert_spk(0, addr_0.script_pubkey());
Expand Down Expand Up @@ -255,10 +255,7 @@ fn ensure_block_emitted_after_reorg_is_at_reorg_height() -> anyhow::Result<()> {
let env = TestEnv::new()?;
let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(BlockId {
height: 0,
hash: env.rpc_client().get_block_hash(0)?,
}),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
EMITTER_START_HEIGHT as _,
NO_EXPECTED_MEMPOOL_TXIDS,
);
Expand Down Expand Up @@ -289,7 +286,7 @@ fn process_block(
block: Block,
block_height: u32,
) -> anyhow::Result<()> {
recv_chain.apply_update(CheckPoint::from_header(&block.header, block_height))?;
recv_chain.apply_header(&block.header, block_height)?;
let _ = recv_graph.apply_block(block, block_height);
Ok(())
}
Expand Down Expand Up @@ -337,10 +334,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
let env = TestEnv::new()?;
let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(BlockId {
height: 0,
hash: env.rpc_client().get_block_hash(0)?,
}),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
0,
NO_EXPECTED_MEMPOOL_TXIDS,
);
Expand All @@ -354,7 +348,7 @@ fn tx_can_become_unconfirmed_after_reorg() -> anyhow::Result<()> {
let addr_to_track = Address::from_script(&spk_to_track, bitcoin::Network::Regtest)?;

// setup receiver
let (mut recv_chain, _) = LocalChain::from_genesis_hash(env.rpc_client().get_block_hash(0)?);
let (mut recv_chain, _) = LocalChain::from_genesis(env.rpc_client().get_block_hash(0)?);
let mut recv_graph = IndexedTxGraph::<BlockId, _>::new({
let mut recv_index = SpkTxOutIndex::default();
recv_index.insert_spk((), spk_to_track.clone());
Expand Down Expand Up @@ -429,10 +423,7 @@ fn mempool_avoids_re_emission() -> anyhow::Result<()> {
let env = TestEnv::new()?;
let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(BlockId {
height: 0,
hash: env.rpc_client().get_block_hash(0)?,
}),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
0,
NO_EXPECTED_MEMPOOL_TXIDS,
);
Expand Down Expand Up @@ -496,10 +487,7 @@ fn mempool_re_emits_if_tx_introduction_height_not_reached() -> anyhow::Result<()
let env = TestEnv::new()?;
let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(BlockId {
height: 0,
hash: env.rpc_client().get_block_hash(0)?,
}),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
0,
NO_EXPECTED_MEMPOOL_TXIDS,
);
Expand Down Expand Up @@ -588,10 +576,7 @@ fn mempool_during_reorg() -> anyhow::Result<()> {
let env = TestEnv::new()?;
let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(BlockId {
height: 0,
hash: env.rpc_client().get_block_hash(0)?,
}),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
0,
NO_EXPECTED_MEMPOOL_TXIDS,
);
Expand Down Expand Up @@ -716,10 +701,7 @@ fn no_agreement_point() -> anyhow::Result<()> {
// start height is 99
let mut emitter = Emitter::new(
env.rpc_client(),
CheckPoint::new(BlockId {
height: 0,
hash: env.rpc_client().get_block_hash(0)?,
}),
CheckPoint::new(0, env.rpc_client().get_block_hash(0)?),
(PREMINE_COUNT - 2) as u32,
NO_EXPECTED_MEMPOOL_TXIDS,
);
Expand Down Expand Up @@ -791,7 +773,7 @@ fn test_expect_tx_evicted() -> anyhow::Result<()> {
.0;
let spk = desc.at_derivation_index(0)?.script_pubkey();

let mut chain = LocalChain::from_genesis_hash(genesis_block(Network::Regtest).block_hash()).0;
let mut chain = LocalChain::from_genesis(genesis_block(Network::Regtest).block_hash()).0;
let chain_tip = chain.tip().block_id();

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

let changeset = graph.batch_insert_unconfirmed(emitter.mempool()?.new_txs);
Expand Down
7 changes: 6 additions & 1 deletion crates/bitcoind_rpc/tests/test_filter_iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,12 @@ fn get_tip_and_chain_update() -> anyhow::Result<()> {
]
.into_iter()
.for_each(|test| {
let cp = CheckPoint::from_block_ids(test.chain).unwrap();
let cp = CheckPoint::from_blocks(
test.chain
.iter()
.map(|block_id| (block_id.height, block_id.hash)),
)
.unwrap();
let mut iter = FilterIter::new_with_checkpoint(env.rpc_client(), cp);
assert_eq!(iter.get_tip().unwrap(), Some(new_tip));
let update_cp = iter.chain_update().unwrap();
Expand Down
8 changes: 6 additions & 2 deletions crates/chain/benches/canonicalization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,12 @@ fn add_ancestor_tx(graph: &mut KeychainTxGraph, block_id: BlockId, locktime: u32

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

let (desc, _) =
Expand Down
7 changes: 6 additions & 1 deletion crates/chain/benches/indexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,12 @@ fn setup<F: Fn(&mut KeychainTxGraph, &LocalChain)>(f: F) -> (KeychainTxGraph, Lo
.unwrap()
.0;

let cp = CheckPoint::from_block_ids([genesis_block_id(), tip_block_id()]).unwrap();
let cp = CheckPoint::from_blocks(
[genesis_block_id(), tip_block_id()]
.into_iter()
.map(|block_id| (block_id.height, block_id.hash)),
)
.unwrap();
let chain = LocalChain::from_tip(cp).unwrap();

let mut index = KeychainTxOutIndex::new(LOOKAHEAD, USE_SPK_CACHE);
Expand Down
Loading
Loading