Skip to content

Commit e062d58

Browse files
committed
fix(core): calling CheckPoint::insert with existing block must succeed
Previously, we were panicking when the caller tried to insert a block at height 0. However, this should succeed if the block hash does not change.
1 parent 8760653 commit e062d58

File tree

2 files changed

+51
-2
lines changed

2 files changed

+51
-2
lines changed

crates/core/src/checkpoint.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -173,15 +173,14 @@ impl CheckPoint {
173173
/// passed in. Of course, if the `block_id` was already present then this just returns `self`.
174174
#[must_use]
175175
pub fn insert(self, block_id: BlockId) -> Self {
176-
assert_ne!(block_id.height, 0, "cannot insert the genesis block");
177-
178176
let mut cp = self.clone();
179177
let mut tail = vec![];
180178
let base = loop {
181179
if cp.height() == block_id.height {
182180
if cp.hash() == block_id.hash {
183181
return self;
184182
}
183+
assert_ne!(cp.height(), 0, "cannot replace genesis block");
185184
// if we have a conflict we just return the inserted block because the tail is by
186185
// implication invalid.
187186
tail = vec![];

crates/core/tests/test_checkpoint.rs

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use bdk_core::CheckPoint;
2+
3+
#[allow(unused_macros)]
4+
macro_rules! h {
5+
($index:literal) => {{
6+
bitcoin::hashes::Hash::hash($index.as_bytes())
7+
}};
8+
}
9+
10+
#[allow(unused_macros)]
11+
macro_rules! block_id {
12+
($height:expr, $hash:literal) => {{
13+
bdk_chain::BlockId {
14+
height: $height,
15+
hash: bitcoin::hashes::Hash::hash($hash.as_bytes()),
16+
}
17+
}};
18+
}
19+
20+
/// Inserting a block that already exists in the checkpoint chain must always succeed.
21+
#[test]
22+
fn checkpoint_insert_existing() {
23+
let blocks = &[
24+
block_id!(0, "genesis"),
25+
block_id!(1, "A"),
26+
block_id!(2, "B"),
27+
block_id!(3, "C"),
28+
];
29+
30+
// Index `i` allows us to test with chains of different length.
31+
// Index `j` allows us to test inserting different block heights.
32+
for i in 0..blocks.len() {
33+
let cp_chain = CheckPoint::from_block_ids(blocks[..=i].iter().copied())
34+
.expect("must construct valid chain");
35+
36+
for j in 0..i {
37+
let block_to_insert = cp_chain
38+
.get(j as u32)
39+
.expect("cp of height must exist")
40+
.block_id();
41+
let new_cp_chain = cp_chain.clone().insert(block_to_insert);
42+
43+
assert_eq!(
44+
new_cp_chain, cp_chain,
45+
"must not divert from original chain"
46+
);
47+
assert!(new_cp_chain.eq_ptr(&cp_chain), "pointers must still match");
48+
}
49+
}
50+
}

0 commit comments

Comments
 (0)