Skip to content
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

Introduce redesigned bdk_chain structures #926

Merged
Merged
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
5ae5fe3
[bdk_chain_redesign] Introduce `BlockAnchor` trait
evanlinjin Mar 24, 2023
61a8606
[bdk_chain_redesign] Introduce `ChainOracle` and `TxIndex` traits
evanlinjin Mar 24, 2023
43b648f
[bdk_chain_redesign] Add `..in_chain` methods
evanlinjin Mar 26, 2023
784cd34
[bdk_chain_redesign] List chain data methods can be try/non-try
evanlinjin Mar 27, 2023
6cbb18d
[bdk_chain_redesign] MOVE: `IndexedTxGraph` into submodule
evanlinjin Mar 27, 2023
d0a2aa8
[bdk_chain_redesign] Add `apply_additions` to `IndexedTxGraph`
evanlinjin Mar 27, 2023
db7883d
[bdk_chain_redesign] Add balance methods to `IndexedTxGraph`
evanlinjin Mar 27, 2023
313965d
[bdk_chain_redesign] `mut_index` should be `index_mut`
evanlinjin Mar 27, 2023
e902c10
[bdk_chain_redesign] Fix `apply_additions` logic for `IndexedTxGraph`.
evanlinjin Mar 27, 2023
236c50f
[bdk_chain_redesign] `IndexedTxGraph` keeps track of the last synced …
evanlinjin Mar 27, 2023
3440a05
[bdk_chain_redesign] Add docs
evanlinjin Mar 28, 2023
34d0277
[bdk_chain_redesign] Rm anchor type param for structs that don't use it
evanlinjin Mar 28, 2023
468701a
[bdk_chain_redesign] Initial work on `LocalChain`.
evanlinjin Mar 29, 2023
8c90617
[bdk_chain_redesign] Make default anchor for `TxGraph` as `()`
evanlinjin Mar 30, 2023
a1172de
[bdk_chain_redesign] Revert some API changes
evanlinjin Mar 30, 2023
a63ffe9
[bdk_chain_redesign] Simplify `TxIndex`
evanlinjin Mar 31, 2023
7810059
[bdk_chain_redesign] `TxGraph` tweaks
evanlinjin Mar 31, 2023
c09cd2a
[bdk_chain_redesign] Added methods to `LocalChain`
evanlinjin Mar 31, 2023
a7eaebb
[bdk_chain_redesign] Add serde support for `IndexedAdditions`
evanlinjin Mar 31, 2023
6e59dce
[bdk_chain_redesign] `chain_oracle::Cache`
evanlinjin Apr 5, 2023
89cfa4d
[bdk_chain_redesign] Better names, comments and generic bounds
evanlinjin Apr 5, 2023
da4cef0
[bdk_chain_redesign] Introduce `Append` trait for additions
evanlinjin Apr 5, 2023
ddd5e95
[bdk_chain_redesign] Modify signature of `TxIndex`
evanlinjin Apr 5, 2023
24cd8c5
[bdk_chain_redesign] More tweaks and renamings
evanlinjin Apr 5, 2023
bff80ec
[bdk_chain_redesign] Improve `BlockAnchor` docs
evanlinjin Apr 7, 2023
611d2e3
[bdk_chain_redesign] Consistent `ChainOracle`
evanlinjin Apr 10, 2023
ee1060f
[bdk_chain_redesign] Simplify `LocalChain`
evanlinjin Apr 10, 2023
a7fbe0a
[bdk_chain_redesign] Documentation improvements
evanlinjin Apr 10, 2023
7d92337
[bdk_chain_redesign] Remove `IndexedTxGraph::last_height`
evanlinjin Apr 10, 2023
10ab77c
[bdk_chain_redesign] MOVE `TxIndex` into `indexed_chain_graph.rs`
evanlinjin Apr 12, 2023
001efdd
Include tests for new updates of TxGraph
rajarshimaitra Apr 8, 2023
81436fc
[bdk_chain_redesign] Fix `Anchor` definition + docs
evanlinjin Apr 17, 2023
8e36a2e
[bdk_chain_redesign] Remove incomplete logic
evanlinjin Apr 19, 2023
7175a82
[bdk_chain_redesign] Add tests for `TxGraph::relevant_heights`
evanlinjin Apr 19, 2023
1003fe2
[bdk_chain_redesign] Test `LocalChain`
evanlinjin Apr 20, 2023
6c49570
[bdk_chain_redesign] Rm `HashSet` from `TxGraph::relevant_heights`
evanlinjin Apr 20, 2023
34a7bf5
[bdk_chain_redesign] Rm unnecessary code and premature optimisation
evanlinjin Apr 20, 2023
03c1283
[bdk_chain_redesign] Revert changes to `SparseChain`
evanlinjin Apr 21, 2023
f3e7b67
[bdk_chain_redesign] Various tweaks and fixes
evanlinjin Apr 21, 2023
165b874
[bdk_chain_redesign] Add test for `insert_relevant_txs`
evanlinjin Apr 21, 2023
ac336aa
[bdk_chain_redesign] Make `insert_relevant_txs` topologically-agnostic
evanlinjin Apr 22, 2023
ecc74ce
[bdk_chain_redesign] Docs for `is_mature` and `is_confirmed_and_spend…
evanlinjin Apr 22, 2023
1b15264
[bdk_chain_redesign] Change `insert_relevant_txs` method
evanlinjin Apr 22, 2023
f101dde
[bdk_chain_redesign] Fix `tx_graph::Additions::append` logic
evanlinjin Apr 25, 2023
e536307
[bdk_chain_redesign] Fix `tx_graph::Additions::append` logic
evanlinjin Apr 28, 2023
911af34
[bdk_chain_redesign] Fix calculation bugs.
rajarshimaitra Apr 27, 2023
8cd0328
[bdk_chain_redesign] Implement `OwnedIndexer` for indexers
rajarshimaitra Apr 27, 2023
b799a57
[bdk_chain_redesign] Add tests for `IndexedTxGraph` with `LocalChain`
rajarshimaitra Apr 27, 2023
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
100 changes: 93 additions & 7 deletions crates/chain/src/chain_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,29 @@ use bitcoin::{hashes::Hash, BlockHash, OutPoint, TxOut, Txid};

use crate::{
sparse_chain::{self, ChainPosition},
COINBASE_MATURITY,
Anchor, COINBASE_MATURITY,
};

/// Represents an observation of some chain data.
///
/// The generic `A` should be a [`Anchor`] implementation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, core::hash::Hash)]
pub enum ObservedAs<A> {
/// The chain data is seen as confirmed, and in anchored by `A`.
Confirmed(A),
/// The chain data is seen in mempool at this given timestamp.
Unconfirmed(u64),
}

impl<A: Clone> ObservedAs<&A> {
pub fn cloned(self) -> ObservedAs<A> {
match self {
ObservedAs::Confirmed(a) => ObservedAs::Confirmed(a.clone()),
ObservedAs::Unconfirmed(last_seen) => ObservedAs::Unconfirmed(last_seen),
}
}
}

/// Represents the height at which a transaction is confirmed.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(
Expand Down Expand Up @@ -118,7 +138,7 @@ impl ConfirmationTime {
}

/// A reference to a block in the canonical chain.
#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord)]
#[derive(Debug, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
Expand All @@ -140,6 +160,12 @@ impl Default for BlockId {
}
}

impl Anchor for BlockId {
fn anchor_block(&self) -> BlockId {
*self
}
}

impl From<(u32, BlockHash)> for BlockId {
fn from((height, hash): (u32, BlockHash)) -> Self {
Self { height, hash }
Expand All @@ -162,21 +188,21 @@ impl From<(&u32, &BlockHash)> for BlockId {
}

/// A `TxOut` with as much data as we can retrieve about it
#[derive(Debug, Clone, PartialEq)]
pub struct FullTxOut<I> {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FullTxOut<P> {
/// The location of the `TxOut`.
pub outpoint: OutPoint,
/// The `TxOut`.
pub txout: TxOut,
/// The position of the transaction in `outpoint` in the overall chain.
pub chain_position: I,
pub chain_position: P,
/// The txid and chain position of the transaction (if any) that has spent this output.
pub spent_by: Option<(I, Txid)>,
pub spent_by: Option<(P, Txid)>,
/// Whether this output is on a coinbase transaction.
pub is_on_coinbase: bool,
}

impl<I: ChainPosition> FullTxOut<I> {
impl<P: ChainPosition> FullTxOut<P> {
/// Whether the utxo is/was/will be spendable at `height`.
///
/// It is spendable if it is not an immature coinbase output and no spending tx has been
Expand Down Expand Up @@ -215,4 +241,64 @@ impl<I: ChainPosition> FullTxOut<I> {
}
}

impl<A: Anchor> FullTxOut<ObservedAs<A>> {
/// Whether the `txout` is considered mature.
///
/// This is the alternative version of [`is_mature`] which depends on `chain_position` being a
/// [`ObservedAs<A>`] where `A` implements [`Anchor`].
///
/// [`is_mature`]: Self::is_mature
pub fn is_mature(&self, tip: u32) -> bool {
if !self.is_on_coinbase {
return true;
}

let tx_height = match &self.chain_position {
ObservedAs::Confirmed(anchor) => anchor.confirmation_height_upper_bound(),
ObservedAs::Unconfirmed(_) => {
debug_assert!(false, "coinbase tx can never be unconfirmed");
return false;
}
};

let age = tip.saturating_sub(tx_height);
if age + 1 < COINBASE_MATURITY {
return false;
}

true
}

/// Whether the utxo is/was/will be spendable with chain `tip`.
///
/// This method does not take into account the locktime.
///
/// This is the alternative version of [`is_spendable_at`] which depends on `chain_position`
/// being a [`ObservedAs<A>`] where `A` implements [`Anchor`].
///
/// [`is_spendable_at`]: Self::is_spendable_at
pub fn is_confirmed_and_spendable(&self, tip: u32) -> bool {
if !self.is_mature(tip) {
return false;
}

let confirmation_height = match &self.chain_position {
ObservedAs::Confirmed(anchor) => anchor.confirmation_height_upper_bound(),
ObservedAs::Unconfirmed(_) => return false,
};
if confirmation_height > tip {
return false;
}

// if the spending tx is confirmed within tip height, the txout is no longer spendable
if let Some((ObservedAs::Confirmed(spending_anchor), _)) = &self.spent_by {
if spending_anchor.anchor_block().height <= tip {
return false;
}
}

true
}
}

// TODO: make test
21 changes: 21 additions & 0 deletions crates/chain/src/chain_oracle.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use crate::BlockId;

/// Represents a service that tracks the blockchain.
///
/// The main method is [`is_block_in_chain`] which determines whether a given block of [`BlockId`]
/// is an ancestor of another "static block".
///
/// [`is_block_in_chain`]: Self::is_block_in_chain
pub trait ChainOracle {
/// Error type.
type Error: core::fmt::Debug;

/// Determines whether `block` of [`BlockId`] exists as an ancestor of `static_block`.
///
/// If `None` is returned, it means the implementation cannot determine whether `block` exists.
fn is_block_in_chain(
&self,
block: BlockId,
static_block: BlockId,
) -> Result<Option<bool>, Self::Error>;
}
Loading