From 34a7bf5afe2d78db47b149f4958f0a0365b017d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=97=E5=AE=87?= Date: Thu, 20 Apr 2023 18:07:26 +0800 Subject: [PATCH] [bdk_chain_redesign] Rm unnecessary code and premature optimisation * Remove `chain_oracle::CacheBackend` for now as it is not used. * `SparseChain` does not need to implement `ChainOracle`. * Remove filter predicate for `list..` methods of `TxGraph` and `IndexedTxGraph` as this is premature optimisation. * `Append` can be implemented for all `BTreeMap`s and `BTreeSet`s, instead of only `local_chain::ChangeSet`. --- crates/chain/src/chain_oracle.rs | 56 ----------------- crates/chain/src/indexed_tx_graph.rs | 83 ++++++++++--------------- crates/chain/src/local_chain.rs | 8 +-- crates/chain/src/sparse_chain.rs | 23 +------ crates/chain/src/tx_data_traits.rs | 17 ++++- crates/chain/src/tx_graph.rs | 92 ++++++++-------------------- 6 files changed, 76 insertions(+), 203 deletions(-) diff --git a/crates/chain/src/chain_oracle.rs b/crates/chain/src/chain_oracle.rs index 7e975ad2..2b4ad36f 100644 --- a/crates/chain/src/chain_oracle.rs +++ b/crates/chain/src/chain_oracle.rs @@ -1,9 +1,3 @@ -use crate::collections::HashSet; -use core::marker::PhantomData; - -use alloc::{collections::VecDeque, vec::Vec}; -use bitcoin::BlockHash; - use crate::BlockId; /// Represents a service that tracks the blockchain. @@ -25,53 +19,3 @@ pub trait ChainOracle { static_block: BlockId, ) -> Result, Self::Error>; } - -/// A cache structure increases the performance of getting chain data. -/// -/// A simple FIFO cache replacement policy is used. Something more efficient and advanced can be -/// implemented later. -#[derive(Debug, Default)] -pub struct CacheBackend { - cache: HashSet<(BlockHash, BlockHash)>, - fifo: VecDeque<(BlockHash, BlockHash)>, - marker: PhantomData, -} - -impl CacheBackend { - /// Get the number of elements in the cache. - pub fn cache_size(&self) -> usize { - self.cache.len() - } - - /// Prunes the cache to reach the `max_size` target. - /// - /// Returns pruned elements. - pub fn prune(&mut self, max_size: usize) -> Vec<(BlockHash, BlockHash)> { - let prune_count = self.cache.len().saturating_sub(max_size); - (0..prune_count) - .filter_map(|_| self.fifo.pop_front()) - .filter(|k| self.cache.remove(k)) - .collect() - } - - pub fn contains(&self, static_block: BlockId, block: BlockId) -> bool { - if static_block.height < block.height - || static_block.height == block.height && static_block.hash != block.hash - { - return false; - } - - self.cache.contains(&(static_block.hash, block.hash)) - } - - pub fn insert(&mut self, static_block: BlockId, block: BlockId) -> bool { - let cache_key = (static_block.hash, block.hash); - - if self.cache.insert(cache_key) { - self.fifo.push_back(cache_key); - true - } else { - false - } - } -} diff --git a/crates/chain/src/indexed_tx_graph.rs b/crates/chain/src/indexed_tx_graph.rs index fd5aa6d9..5ce53111 100644 --- a/crates/chain/src/indexed_tx_graph.rs +++ b/crates/chain/src/indexed_tx_graph.rs @@ -120,15 +120,12 @@ where /// /// `anchors` can be provided to anchor the transactions to blocks. `seen_at` is a unix /// timestamp of when the transactions are last seen. - pub fn insert_relevant_txs<'t, T>( + pub fn insert_relevant_txs<'t, T: Iterator>( &mut self, txs: T, anchors: impl IntoIterator + Clone, seen_at: Option, - ) -> IndexedAdditions - where - T: Iterator, - { + ) -> IndexedAdditions { txs.filter_map(|tx| match self.index.is_tx_relevant(tx) { true => Some(self.insert_tx(tx, anchors.clone(), seen_at)), false => None, @@ -141,14 +138,11 @@ where } impl IndexedTxGraph { - pub fn try_list_owned_txs<'a, C>( + pub fn try_list_owned_txs<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - ) -> impl Iterator, C::Error>> - where - C: ChainOracle + 'a, - { + ) -> impl Iterator, C::Error>> { self.graph .full_txs() .filter(|node| tx_alters_owned_utxo_set(&self.graph, &self.index, node.txid, node.tx)) @@ -165,55 +159,55 @@ impl IndexedTxGraph { }) } - pub fn list_owned_txs<'a, C>( + pub fn list_owned_txs<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - ) -> impl Iterator> - where - C: ChainOracle + 'a, - { + ) -> impl Iterator> { self.try_list_owned_txs(chain, chain_tip) .map(|r| r.expect("chain oracle is infallible")) } - pub fn try_list_owned_txouts<'a, C>( + pub fn try_list_owned_txouts<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - ) -> impl Iterator>, C::Error>> + 'a - where - C: ChainOracle + 'a, - { + ) -> impl Iterator>, C::Error>> + 'a { self.graph() - .try_list_chain_txouts(chain, chain_tip, |_, txout| { - self.index.is_spk_owned(&txout.script_pubkey) + .try_list_chain_txouts(chain, chain_tip) + .filter(|r| { + if let Ok(full_txout) = r { + if !self.index.is_spk_owned(&full_txout.txout.script_pubkey) { + return false; + } + } + true }) } - pub fn list_owned_txouts<'a, C>( + pub fn list_owned_txouts<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - ) -> impl Iterator>> + 'a - where - C: ChainOracle + 'a, - { + ) -> impl Iterator>> + 'a { self.try_list_owned_txouts(chain, chain_tip) .map(|r| r.expect("oracle is infallible")) } - pub fn try_list_owned_unspents<'a, C>( + pub fn try_list_owned_unspents<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - ) -> impl Iterator>, C::Error>> + 'a - where - C: ChainOracle + 'a, - { + ) -> impl Iterator>, C::Error>> + 'a { self.graph() - .try_list_chain_unspents(chain, chain_tip, |_, txout| { - self.index.is_spk_owned(&txout.script_pubkey) + .try_list_chain_unspents(chain, chain_tip) + .filter(|r| { + if let Ok(full_txout) = r { + if !self.index.is_spk_owned(&full_txout.txout.script_pubkey) { + return false; + } + } + true }) } @@ -278,35 +272,26 @@ impl IndexedTxGraph { }) } - pub fn balance( - &self, - chain: &C, - static_block: BlockId, - tip: u32, - should_trust: F, - ) -> Balance + pub fn balance(&self, chain: &C, chain_tip: BlockId, tip: u32, should_trust: F) -> Balance where C: ChainOracle, F: FnMut(&Script) -> bool, { - self.try_balance(chain, static_block, tip, should_trust) + self.try_balance(chain, chain_tip, tip, should_trust) .expect("error is infallible") } pub fn try_balance_at( &self, chain: &C, - static_block: BlockId, + chain_tip: BlockId, height: u32, ) -> Result where C: ChainOracle, { let mut sum = 0; - for txo_res in self - .graph() - .try_list_chain_txouts(chain, static_block, |_, _| true) - { + for txo_res in self.try_list_owned_unspents(chain, chain_tip) { let txo = txo_res?; if txo.is_observed_as_confirmed_and_spendable(height) { sum += txo.txout.value; @@ -315,11 +300,11 @@ impl IndexedTxGraph { Ok(sum) } - pub fn balance_at(&self, chain: &C, static_block: BlockId, height: u32) -> u64 + pub fn balance_at(&self, chain: &C, chain_tip: BlockId, height: u32) -> u64 where C: ChainOracle, { - self.try_balance_at(chain, static_block, height) + self.try_balance_at(chain, chain_tip, height) .expect("error is infallible") } } diff --git a/crates/chain/src/local_chain.rs b/crates/chain/src/local_chain.rs index 88c688fe..30dfe80b 100644 --- a/crates/chain/src/local_chain.rs +++ b/crates/chain/src/local_chain.rs @@ -3,7 +3,7 @@ use core::convert::Infallible; use alloc::collections::{BTreeMap, BTreeSet}; use bitcoin::BlockHash; -use crate::{Append, BlockId, ChainOracle}; +use crate::{BlockId, ChainOracle}; /// This is a local implementation of [`ChainOracle`]. /// @@ -180,12 +180,6 @@ impl LocalChain { /// [`determine_changeset`]: LocalChain::determine_changeset pub type ChangeSet = BTreeMap>; -impl Append for ChangeSet { - fn append(&mut self, mut other: Self) { - BTreeMap::append(self, &mut other) - } -} - /// Represents an update failure of [`LocalChain`] due to the update not connecting to the original /// chain. /// diff --git a/crates/chain/src/sparse_chain.rs b/crates/chain/src/sparse_chain.rs index fbcdcaa5..55121695 100644 --- a/crates/chain/src/sparse_chain.rs +++ b/crates/chain/src/sparse_chain.rs @@ -307,12 +307,11 @@ //! ); //! ``` use core::{ - convert::Infallible, fmt::Debug, ops::{Bound, RangeBounds}, }; -use crate::{collections::*, tx_graph::TxGraph, BlockId, ChainOracle, FullTxOut, TxHeight}; +use crate::{collections::*, tx_graph::TxGraph, BlockId, FullTxOut, TxHeight}; use bitcoin::{hashes::Hash, BlockHash, OutPoint, Txid}; /// This is a non-monotone structure that tracks relevant [`Txid`]s that are ordered by chain @@ -457,26 +456,6 @@ impl core::fmt::Display for UpdateError

{ #[cfg(feature = "std")] impl std::error::Error for UpdateError

{} -impl

ChainOracle for SparseChain

{ - type Error = Infallible; - - fn is_block_in_chain( - &self, - block: BlockId, - static_block: BlockId, - ) -> Result, Self::Error> { - Ok( - match ( - self.checkpoint_at(block.height), - self.checkpoint_at(static_block.height), - ) { - (Some(b), Some(static_b)) => Some(b == block && static_b == static_block), - _ => None, - }, - ) - } -} - impl

SparseChain

{ /// Creates a new chain from a list of block hashes and heights. The caller must guarantee they /// are in the same chain. diff --git a/crates/chain/src/tx_data_traits.rs b/crates/chain/src/tx_data_traits.rs index 9d41c549..bd7e66ac 100644 --- a/crates/chain/src/tx_data_traits.rs +++ b/crates/chain/src/tx_data_traits.rs @@ -1,6 +1,7 @@ -use bitcoin::{Block, BlockHash, OutPoint, Transaction, TxOut}; - +use crate::collections::BTreeMap; +use crate::collections::BTreeSet; use crate::BlockId; +use bitcoin::{Block, BlockHash, OutPoint, Transaction, TxOut}; /// Trait to do something with every txout contained in a structure. /// @@ -77,3 +78,15 @@ pub trait Append { impl Append for () { fn append(&mut self, _other: Self) {} } + +impl Append for BTreeMap { + fn append(&mut self, mut other: Self) { + BTreeMap::append(self, &mut other) + } +} + +impl Append for BTreeSet { + fn append(&mut self, mut other: Self) { + BTreeSet::append(self, &mut other) + } +} diff --git a/crates/chain/src/tx_graph.rs b/crates/chain/src/tx_graph.rs index a1ddbf87..07e4680e 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -627,15 +627,12 @@ impl TxGraph { /// [`ChainOracle`] is infallible, [`get_chain_position`] can be used instead. /// /// [`get_chain_position`]: Self::get_chain_position - pub fn try_get_chain_position( + pub fn try_get_chain_position( &self, chain: &C, chain_tip: BlockId, txid: Txid, - ) -> Result>, C::Error> - where - C: ChainOracle, - { + ) -> Result>, C::Error> { let (tx_node, anchors, &last_seen) = match self.txs.get(&txid) { Some((tx, anchors, last_seen)) if !(anchors.is_empty() && *last_seen == 0) => { (tx, anchors, last_seen) @@ -682,15 +679,12 @@ impl TxGraph { /// This is the infallible version of [`try_get_chain_position`]. /// /// [`try_get_chain_position`]: Self::try_get_chain_position - pub fn get_chain_position( + pub fn get_chain_position>( &self, chain: &C, chain_tip: BlockId, txid: Txid, - ) -> Option> - where - C: ChainOracle, - { + ) -> Option> { self.try_get_chain_position(chain, chain_tip, txid) .expect("error is infallible") } @@ -707,15 +701,12 @@ impl TxGraph { /// If the [`ChainOracle`] is infallible, [`get_chain_spend`] can be used instead. /// /// [`get_chain_spend`]: Self::get_chain_spend - pub fn try_get_chain_spend( + pub fn try_get_chain_spend( &self, chain: &C, chain_tip: BlockId, outpoint: OutPoint, - ) -> Result, Txid)>, C::Error> - where - C: ChainOracle, - { + ) -> Result, Txid)>, C::Error> { if self .try_get_chain_position(chain, chain_tip, outpoint.txid)? .is_none() @@ -738,15 +729,12 @@ impl TxGraph { /// This is the infallible version of [`try_get_chain_spend`] /// /// [`try_get_chain_spend`]: Self::try_get_chain_spend - pub fn get_chain_spend( + pub fn get_chain_spend>( &self, chain: &C, static_block: BlockId, outpoint: OutPoint, - ) -> Option<(ObservedAs<&A>, Txid)> - where - C: ChainOracle, - { + ) -> Option<(ObservedAs<&A>, Txid)> { self.try_get_chain_spend(chain, static_block, outpoint) .expect("error is infallible") } @@ -764,14 +752,11 @@ impl TxGraph { /// If the [`ChainOracle`] is infallible, [`list_chain_txs`] can be used instead. /// /// [`list_chain_txs`]: Self::list_chain_txs - pub fn try_list_chain_txs<'a, C>( + pub fn try_list_chain_txs<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - ) -> impl Iterator, C::Error>> - where - C: ChainOracle + 'a, - { + ) -> impl Iterator, C::Error>> { self.full_txs().filter_map(move |tx| { self.try_get_chain_position(chain, chain_tip, tx.txid) .map(|v| { @@ -789,14 +774,11 @@ impl TxGraph { /// This is the infallible version of [`try_list_chain_txs`]. /// /// [`try_list_chain_txs`]: Self::try_list_chain_txs - pub fn list_chain_txs<'a, C>( + pub fn list_chain_txs<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - ) -> impl Iterator> - where - C: ChainOracle + 'a, - { + ) -> impl Iterator> { self.try_list_chain_txs(chain, chain_tip) .map(|r| r.expect("oracle is infallible")) } @@ -814,16 +796,11 @@ impl TxGraph { /// If the [`ChainOracle`] is infallible, [`list_chain_txouts`] can be used instead. /// /// [`list_chain_txouts`]: Self::list_chain_txouts - pub fn try_list_chain_txouts<'a, C, P>( + pub fn try_list_chain_txouts<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - mut filter_predicate: P, - ) -> impl Iterator>, C::Error>> + 'a - where - C: ChainOracle + 'a, - P: FnMut(OutPoint, &TxOut) -> bool + 'a, - { + ) -> impl Iterator>, C::Error>> + 'a { self.try_list_chain_txs(chain, chain_tip) .flat_map(move |tx_res| match tx_res { Ok(canonical_tx) => canonical_tx @@ -831,13 +808,9 @@ impl TxGraph { .output .iter() .enumerate() - .filter_map(|(vout, txout)| { + .map(|(vout, txout)| { let outpoint = OutPoint::new(canonical_tx.node.txid, vout as _); - if filter_predicate(outpoint, txout) { - Some(Ok((outpoint, txout.clone(), canonical_tx.clone()))) - } else { - None - } + Ok((outpoint, txout.clone(), canonical_tx.clone())) }) .collect::>(), Err(err) => vec![Err(err)], @@ -871,17 +844,12 @@ impl TxGraph { /// This is the infallible version of [`try_list_chain_txouts`]. /// /// [`try_list_chain_txouts`]: Self::try_list_chain_txouts - pub fn list_chain_txouts<'a, C, P>( + pub fn list_chain_txouts<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - filter_predicate: P, - ) -> impl Iterator>> + 'a - where - C: ChainOracle + 'a, - P: FnMut(OutPoint, &TxOut) -> bool + 'a, - { - self.try_list_chain_txouts(chain, chain_tip, filter_predicate) + ) -> impl Iterator>> + 'a { + self.try_list_chain_txouts(chain, chain_tip) .map(|r| r.expect("error in infallible")) } @@ -895,17 +863,12 @@ impl TxGraph { /// infallible, [`list_chain_unspents`] can be used instead. /// /// [`list_chain_unspents`]: Self::list_chain_unspents - pub fn try_list_chain_unspents<'a, C, P>( + pub fn try_list_chain_unspents<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, chain_tip: BlockId, - filter_txout: P, - ) -> impl Iterator>, C::Error>> + 'a - where - C: ChainOracle + 'a, - P: FnMut(OutPoint, &TxOut) -> bool + 'a, - { - self.try_list_chain_txouts(chain, chain_tip, filter_txout) + ) -> impl Iterator>, C::Error>> + 'a { + self.try_list_chain_txouts(chain, chain_tip) .filter(|r| !matches!(r, Ok(txo) if txo.spent_by.is_none())) } @@ -914,17 +877,12 @@ impl TxGraph { /// This is the infallible version of [`try_list_chain_unspents`]. /// /// [`try_list_chain_unspents`]: Self::try_list_chain_unspents - pub fn list_chain_unspents<'a, C, P>( + pub fn list_chain_unspents<'a, C: ChainOracle + 'a>( &'a self, chain: &'a C, static_block: BlockId, - filter_txout: P, - ) -> impl Iterator>> + 'a - where - C: ChainOracle + 'a, - P: FnMut(OutPoint, &TxOut) -> bool + 'a, - { - self.try_list_chain_unspents(chain, static_block, filter_txout) + ) -> impl Iterator>> + 'a { + self.try_list_chain_unspents(chain, static_block) .map(|r| r.expect("error is infallible")) } }