2023-04-20 18:07:26 +08:00
|
|
|
use crate::collections::BTreeMap;
|
|
|
|
use crate::collections::BTreeSet;
|
2023-03-24 09:23:36 +08:00
|
|
|
use crate::BlockId;
|
2023-05-10 14:48:26 +08:00
|
|
|
use alloc::vec::Vec;
|
2023-03-24 09:23:36 +08:00
|
|
|
|
2023-04-07 09:23:00 +08:00
|
|
|
/// Trait that "anchors" blockchain data to a specific block of height and hash.
|
2023-03-24 09:23:36 +08:00
|
|
|
///
|
2023-07-22 22:41:33 +08:00
|
|
|
/// [`Anchor`] implementations must be [`Ord`] by the anchor block's [`BlockId`] first.
|
|
|
|
///
|
2023-04-07 09:23:00 +08:00
|
|
|
/// I.e. If transaction A is anchored in block B, then if block B is in the best chain, we can
|
|
|
|
/// assume that transaction A is also confirmed in the best chain. This does not necessarily mean
|
|
|
|
/// that transaction A is confirmed in block B. It could also mean transaction A is confirmed in a
|
|
|
|
/// parent block of B.
|
2023-08-16 11:30:33 +03:00
|
|
|
///
|
|
|
|
/// ```
|
|
|
|
/// # use bdk_chain::local_chain::LocalChain;
|
|
|
|
/// # use bdk_chain::tx_graph::TxGraph;
|
|
|
|
/// # use bdk_chain::BlockId;
|
|
|
|
/// # use bdk_chain::ConfirmationHeightAnchor;
|
|
|
|
/// # use bdk_chain::example_utils::*;
|
|
|
|
/// # use bitcoin::hashes::Hash;
|
|
|
|
///
|
|
|
|
/// // Initialize the local chain with two blocks.
|
|
|
|
/// let chain = LocalChain::from_blocks(
|
|
|
|
/// [
|
|
|
|
/// (1, Hash::hash("first".as_bytes())),
|
|
|
|
/// (2, Hash::hash("second".as_bytes())),
|
|
|
|
/// ]
|
|
|
|
/// .into_iter()
|
|
|
|
/// .collect(),
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// // Transaction to be inserted into `TxGraph`s with different anchor types.
|
|
|
|
/// let tx = tx_from_hex(RAW_TX_1);
|
|
|
|
///
|
|
|
|
/// // Insert `tx` into a `TxGraph` that uses `BlockId` as the anchor type.
|
|
|
|
/// // When a transaction is anchored with `BlockId`, the anchor block and the confirmation block of
|
|
|
|
/// // the transaction is the same block.
|
|
|
|
/// let mut graph_a = TxGraph::<BlockId>::default();
|
|
|
|
/// let _ = graph_a.insert_tx(tx.clone());
|
|
|
|
/// graph_a.insert_anchor(
|
|
|
|
/// tx.txid(),
|
|
|
|
/// BlockId {
|
|
|
|
/// height: 1,
|
|
|
|
/// hash: Hash::hash("first".as_bytes()),
|
|
|
|
/// },
|
|
|
|
/// );
|
|
|
|
///
|
|
|
|
/// // Insert `tx` into a `TxGraph` that uses `ConfirmationHeightAnchor` as the anchor type.
|
|
|
|
/// // When a transaction is anchored with `ConfirmationHeightAnchor`, the anchor block and
|
|
|
|
/// // confirmation block can be different. However, the confirmation block cannot be higher than
|
|
|
|
/// // the anchor block and both blocks must be in the same chain for the anchor to be valid.
|
|
|
|
/// let mut graph_b = TxGraph::<ConfirmationHeightAnchor>::default();
|
|
|
|
/// let _ = graph_b.insert_tx(tx.clone());
|
|
|
|
/// graph_b.insert_anchor(
|
|
|
|
/// tx.txid(),
|
|
|
|
/// ConfirmationHeightAnchor {
|
|
|
|
/// anchor_block: BlockId {
|
|
|
|
/// height: 2,
|
|
|
|
/// hash: Hash::hash("second".as_bytes()),
|
|
|
|
/// },
|
|
|
|
/// confirmation_height: 1,
|
|
|
|
/// },
|
|
|
|
/// );
|
|
|
|
/// ```
|
2023-04-21 13:29:44 +08:00
|
|
|
pub trait Anchor: core::fmt::Debug + Clone + Eq + PartialOrd + Ord + core::hash::Hash {
|
2023-03-24 09:23:36 +08:00
|
|
|
/// Returns the [`BlockId`] that the associated blockchain data is "anchored" in.
|
|
|
|
fn anchor_block(&self) -> BlockId;
|
|
|
|
|
2023-04-21 13:29:44 +08:00
|
|
|
/// Get the upper bound of the chain data's confirmation height.
|
|
|
|
///
|
|
|
|
/// The default definition gives a pessimistic answer. This can be overridden by the `Anchor`
|
|
|
|
/// implementation for a more accurate value.
|
|
|
|
fn confirmation_height_upper_bound(&self) -> u32 {
|
|
|
|
self.anchor_block().height
|
2023-03-24 15:47:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-04 16:54:28 +08:00
|
|
|
impl<'a, A: Anchor> Anchor for &'a A {
|
2023-03-24 09:23:36 +08:00
|
|
|
fn anchor_block(&self) -> BlockId {
|
2023-04-21 13:29:44 +08:00
|
|
|
<A as Anchor>::anchor_block(self)
|
2023-03-24 09:23:36 +08:00
|
|
|
}
|
|
|
|
}
|
2023-03-24 15:47:39 +08:00
|
|
|
|
2023-10-04 16:54:28 +08:00
|
|
|
/// An [`Anchor`] that can be constructed from a given block, block height and transaction position
|
|
|
|
/// within the block.
|
|
|
|
pub trait AnchorFromBlockPosition: Anchor {
|
|
|
|
/// Construct the anchor from a given `block`, block height and `tx_pos` within the block.
|
|
|
|
fn from_block_position(block: &bitcoin::Block, block_id: BlockId, tx_pos: usize) -> Self;
|
|
|
|
}
|
|
|
|
|
2023-04-05 17:29:20 +08:00
|
|
|
/// Trait that makes an object appendable.
|
|
|
|
pub trait Append {
|
|
|
|
/// Append another object of the same type onto `self`.
|
|
|
|
fn append(&mut self, other: Self);
|
2023-05-09 09:59:42 +08:00
|
|
|
|
|
|
|
/// Returns whether the structure is considered empty.
|
|
|
|
fn is_empty(&self) -> bool;
|
2023-04-05 17:29:20 +08:00
|
|
|
}
|
|
|
|
|
2023-04-20 18:07:26 +08:00
|
|
|
impl<K: Ord, V> Append for BTreeMap<K, V> {
|
|
|
|
fn append(&mut self, mut other: Self) {
|
|
|
|
BTreeMap::append(self, &mut other)
|
|
|
|
}
|
2023-05-09 09:59:42 +08:00
|
|
|
|
|
|
|
fn is_empty(&self) -> bool {
|
|
|
|
BTreeMap::is_empty(self)
|
|
|
|
}
|
2023-04-20 18:07:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Ord> Append for BTreeSet<T> {
|
|
|
|
fn append(&mut self, mut other: Self) {
|
|
|
|
BTreeSet::append(self, &mut other)
|
|
|
|
}
|
2023-05-09 09:59:42 +08:00
|
|
|
|
|
|
|
fn is_empty(&self) -> bool {
|
|
|
|
BTreeSet::is_empty(self)
|
|
|
|
}
|
2023-04-20 18:07:26 +08:00
|
|
|
}
|
2023-05-10 14:48:26 +08:00
|
|
|
|
|
|
|
impl<T> Append for Vec<T> {
|
|
|
|
fn append(&mut self, mut other: Self) {
|
|
|
|
Vec::append(self, &mut other)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_empty(&self) -> bool {
|
|
|
|
Vec::is_empty(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-05 07:53:50 +08:00
|
|
|
macro_rules! impl_append_for_tuple {
|
|
|
|
($($a:ident $b:tt)*) => {
|
|
|
|
impl<$($a),*> Append for ($($a,)*) where $($a: Append),* {
|
2023-05-10 14:48:26 +08:00
|
|
|
|
2023-09-05 07:53:50 +08:00
|
|
|
fn append(&mut self, _other: Self) {
|
|
|
|
$(Append::append(&mut self.$b, _other.$b) );*
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_empty(&self) -> bool {
|
|
|
|
$(Append::is_empty(&self.$b) && )* true
|
|
|
|
}
|
|
|
|
}
|
2023-05-10 14:48:26 +08:00
|
|
|
}
|
|
|
|
}
|
2023-09-05 07:53:50 +08:00
|
|
|
|
|
|
|
impl_append_for_tuple!();
|
|
|
|
impl_append_for_tuple!(T0 0);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1 T2 2);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1 T2 2 T3 3);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9);
|
|
|
|
impl_append_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10);
|