• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

bitcoindevkit / bdk / 10758395900

08 Sep 2024 08:25AM UTC coverage: 81.674% (-0.03%) from 81.704%
10758395900

Pull #1594

github

web-flow
Merge 26c528280 into 257c5f7f5
Pull Request #1594: Replace trait `AnchorFromBlockPosition` with new struct

18 of 27 new or added lines in 2 files covered. (66.67%)

25 existing lines in 2 files now uncovered.

11084 of 13571 relevant lines covered (81.67%)

14361.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

63.64
/crates/chain/src/tx_data_traits.rs
1
use crate::collections::{BTreeMap, BTreeSet};
2
use crate::{BlockId, ConfirmationBlockTime};
3
use alloc::vec::Vec;
4

5
/// Trait that "anchors" blockchain data to a specific block of height and hash.
6
///
7
/// If transaction A is anchored in block B, and block B is in the best chain, we can
8
/// assume that transaction A is also confirmed in the best chain. This does not necessarily mean
9
/// that transaction A is confirmed in block B. It could also mean transaction A is confirmed in a
10
/// parent block of B.
11
///
12
/// Every [`Anchor`] implementation must contain a [`BlockId`] parameter, and must implement
13
/// [`Ord`]. When implementing [`Ord`], the anchors' [`BlockId`]s should take precedence
14
/// over other elements inside the [`Anchor`]s for comparison purposes, i.e., you should first
15
/// compare the anchors' [`BlockId`]s and then care about the rest.
16
///
17
/// The example shows different types of anchors:
18
/// ```
19
/// # use bdk_chain::local_chain::LocalChain;
20
/// # use bdk_chain::tx_graph::TxGraph;
21
/// # use bdk_chain::BlockId;
22
/// # use bdk_chain::ConfirmationBlockTime;
23
/// # use bdk_chain::example_utils::*;
24
/// # use bitcoin::hashes::Hash;
25
/// // Initialize the local chain with two blocks.
26
/// let chain = LocalChain::from_blocks(
27
///     [
28
///         (1, Hash::hash("first".as_bytes())),
29
///         (2, Hash::hash("second".as_bytes())),
30
///     ]
31
///     .into_iter()
32
///     .collect(),
33
/// );
34
///
35
/// // Transaction to be inserted into `TxGraph`s with different anchor types.
36
/// let tx = tx_from_hex(RAW_TX_1);
37
///
38
/// // Insert `tx` into a `TxGraph` that uses `BlockId` as the anchor type.
39
/// // When a transaction is anchored with `BlockId`, the anchor block and the confirmation block of
40
/// // the transaction is the same block.
41
/// let mut graph_a = TxGraph::<BlockId>::default();
42
/// let _ = graph_a.insert_tx(tx.clone());
43
/// graph_a.insert_anchor(
44
///     tx.compute_txid(),
45
///     BlockId {
46
///         height: 1,
47
///         hash: Hash::hash("first".as_bytes()),
48
///     },
49
/// );
50
///
51
/// // Insert `tx` into a `TxGraph` that uses `ConfirmationBlockTime` as the anchor type.
52
/// // This anchor records the anchor block and the confirmation time of the transaction. When a
53
/// // transaction is anchored with `ConfirmationBlockTime`, the anchor block and confirmation block
54
/// // of the transaction is the same block.
55
/// let mut graph_c = TxGraph::<ConfirmationBlockTime>::default();
56
/// let _ = graph_c.insert_tx(tx.clone());
57
/// graph_c.insert_anchor(
58
///     tx.compute_txid(),
59
///     ConfirmationBlockTime {
60
///         block_id: BlockId {
61
///             height: 2,
62
///             hash: Hash::hash("third".as_bytes()),
63
///         },
64
///         confirmation_time: 123,
65
///     },
66
/// );
67
/// ```
68
pub trait Anchor: core::fmt::Debug + Clone + Eq + PartialOrd + Ord + core::hash::Hash {
69
    /// Returns the [`BlockId`] that the associated blockchain data is "anchored" in.
70
    fn anchor_block(&self) -> BlockId;
71

72
    /// Get the upper bound of the chain data's confirmation height.
73
    ///
74
    /// The default definition gives a pessimistic answer. This can be overridden by the `Anchor`
75
    /// implementation for a more accurate value.
76
    fn confirmation_height_upper_bound(&self) -> u32 {
73✔
77
        self.anchor_block().height
73✔
78
    }
73✔
79
}
80

81
impl<'a, A: Anchor> Anchor for &'a A {
82
    fn anchor_block(&self) -> BlockId {
2✔
83
        <A as Anchor>::anchor_block(self)
2✔
84
    }
2✔
85
}
86

87
impl Anchor for BlockId {
88
    fn anchor_block(&self) -> Self {
15,603✔
89
        *self
15,603✔
90
    }
15,603✔
91
}
92

93
impl Anchor for ConfirmationBlockTime {
94
    fn anchor_block(&self) -> BlockId {
31,437✔
95
        self.block_id
31,437✔
96
    }
31,437✔
97

98
    fn confirmation_height_upper_bound(&self) -> u32 {
1,260✔
99
        self.block_id.height
1,260✔
100
    }
1,260✔
101
}
102

103
/// Minimal set of parameters that are needed to construct a generic [`Anchor`].
104
/// Typically used as an additional constraint on anchor:
105
/// `A: Anchor + From<BlockPosition<'b>>`.
106
pub struct BlockPosition<'b> {
107
    block: &'b bitcoin::Block,
108
    block_id: BlockId,
109
}
110

111
impl<'b> BlockPosition<'b> {
112
    /// Creates new [`BlockPosition`].
113
    pub fn new(block: &'b bitcoin::Block, block_id: BlockId) -> Self {
4,053✔
114
        Self { block, block_id }
4,053✔
115
    }
4,053✔
116

117
    /// Returns block associated with this [`BlockPosition`].
NEW
118
    pub fn block(&self) -> &bitcoin::Block {
×
NEW
119
        self.block
×
NEW
UNCOV
120
    }
×
121

122
    /// Returns block ID associated with this [`BlockPosition`].
NEW
123
    pub fn block_id(&self) -> BlockId {
×
NEW
124
        self.block_id
×
NEW
125
    }
×
126
}
127

128
impl<'b> From<BlockPosition<'b>> for BlockId {
129
    fn from(value: BlockPosition) -> Self {
4,053✔
130
        value.block_id
4,053✔
131
    }
4,053✔
132
}
133

134
impl<'b> From<BlockPosition<'b>> for ConfirmationBlockTime {
NEW
UNCOV
135
    fn from(value: BlockPosition) -> Self {
×
UNCOV
136
        Self {
×
NEW
UNCOV
137
            block_id: value.block_id,
×
NEW
UNCOV
138
            confirmation_time: value.block.header.time as _,
×
UNCOV
139
        }
×
UNCOV
140
    }
×
141
}
142

143
/// Trait that makes an object mergeable.
144
pub trait Merge: Default {
145
    /// Merge another object of the same type onto `self`.
146
    fn merge(&mut self, other: Self);
147

148
    /// Returns whether the structure is considered empty.
149
    fn is_empty(&self) -> bool;
150

151
    /// Take the value, replacing it with the default value.
152
    fn take(&mut self) -> Option<Self> {
80✔
153
        if self.is_empty() {
80✔
UNCOV
154
            None
×
155
        } else {
156
            Some(core::mem::take(self))
80✔
157
        }
158
    }
80✔
159
}
160

161
impl<K: Ord, V> Merge for BTreeMap<K, V> {
162
    fn merge(&mut self, other: Self) {
46,620✔
163
        // We use `extend` instead of `BTreeMap::append` due to performance issues with `append`.
46,620✔
164
        // Refer to https://github.com/rust-lang/rust/issues/34666#issuecomment-675658420
46,620✔
165
        BTreeMap::extend(self, other)
46,620✔
166
    }
46,620✔
167

UNCOV
168
    fn is_empty(&self) -> bool {
×
UNCOV
169
        BTreeMap::is_empty(self)
×
UNCOV
170
    }
×
171
}
172

173
impl<T: Ord> Merge for BTreeSet<T> {
174
    fn merge(&mut self, other: Self) {
450✔
175
        // We use `extend` instead of `BTreeMap::append` due to performance issues with `append`.
450✔
176
        // Refer to https://github.com/rust-lang/rust/issues/34666#issuecomment-675658420
450✔
177
        BTreeSet::extend(self, other)
450✔
178
    }
450✔
179

180
    fn is_empty(&self) -> bool {
437✔
181
        BTreeSet::is_empty(self)
437✔
182
    }
437✔
183
}
184

185
impl<T> Merge for Vec<T> {
UNCOV
186
    fn merge(&mut self, mut other: Self) {
×
UNCOV
187
        Vec::append(self, &mut other)
×
UNCOV
188
    }
×
189

UNCOV
190
    fn is_empty(&self) -> bool {
×
UNCOV
191
        Vec::is_empty(self)
×
192
    }
×
193
}
194

195
macro_rules! impl_merge_for_tuple {
196
    ($($a:ident $b:tt)*) => {
197
        impl<$($a),*> Merge for ($($a,)*) where $($a: Merge),* {
198

199
            fn merge(&mut self, _other: Self) {
6,762✔
200
                $(Merge::merge(&mut self.$b, _other.$b) );*
6,762✔
201
            }
6,762✔
202

UNCOV
203
            fn is_empty(&self) -> bool {
×
UNCOV
204
                $(Merge::is_empty(&self.$b) && )* true
×
205
            }
2,142✔
206
        }
207
    }
208
}
209

210
impl_merge_for_tuple!();
211
impl_merge_for_tuple!(T0 0);
212
impl_merge_for_tuple!(T0 0 T1 1);
213
impl_merge_for_tuple!(T0 0 T1 1 T2 2);
214
impl_merge_for_tuple!(T0 0 T1 1 T2 2 T3 3);
215
impl_merge_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4);
216
impl_merge_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5);
217
impl_merge_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6);
218
impl_merge_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7);
219
impl_merge_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8);
220
impl_merge_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9);
221
impl_merge_for_tuple!(T0 0 T1 1 T2 2 T3 3 T4 4 T5 5 T6 6 T7 7 T8 8 T9 9 T10 10);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc