Skip to content

Commit 4907581

Browse files
committed
fix(chain)!: In apply_changeset_to_checkpoint propagate the error from extend
Now that `extend` detects conflicts (via `push`) we need to handle the error and propagate it up to `apply_update` in case `merge_chains` fails. Added `ApplyChangeSetError` struct internally but don't expose it. Change `LocalChain::from_blocks` to propagate the error from `CheckPoint::from_blocks`.
1 parent 2a80bc5 commit 4907581

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

crates/chain/src/local_chain.rs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,22 @@ pub use bdk_core::{CheckPoint, CheckPointIter};
1111
use bitcoin::block::Header;
1212
use bitcoin::BlockHash;
1313

14+
/// Error for `apply_changeset_to_checkpoint`.
15+
#[derive(Debug)]
16+
struct ApplyChangeSetError<D> {
17+
error: Option<CheckPoint<D>>,
18+
}
19+
1420
/// Apply `changeset` to the checkpoint.
21+
///
22+
/// # Errors
23+
///
24+
/// - If constructing the new chain from the provided `changeset` fails, then a
25+
/// [`ApplyChangeSetError`] is returned.
1526
fn apply_changeset_to_checkpoint<D>(
1627
mut init_cp: CheckPoint<D>,
1728
changeset: &ChangeSet<D>,
18-
) -> Result<CheckPoint<D>, MissingGenesisError>
29+
) -> Result<CheckPoint<D>, ApplyChangeSetError<D>>
1930
where
2031
D: ToBlockHash + fmt::Debug + Copy,
2132
{
@@ -48,8 +59,11 @@ where
4859
let new_tip = match base {
4960
Some(base) => base
5061
.extend(extension)
51-
.expect("extension is strictly greater than base"),
52-
None => LocalChain::from_blocks(extension)?.tip(),
62+
.map_err(Option::Some)
63+
.map_err(|error| ApplyChangeSetError { error })?,
64+
None => LocalChain::from_blocks(extension)
65+
.map_err(|error| ApplyChangeSetError { error })?
66+
.tip(),
5367
};
5468
init_cp = new_tip;
5569
}
@@ -251,13 +265,16 @@ where
251265
///
252266
/// The [`BTreeMap`] enforces the height order. However, the caller must ensure the blocks are
253267
/// all of the same chain.
254-
pub fn from_blocks(blocks: BTreeMap<u32, D>) -> Result<Self, MissingGenesisError> {
268+
///
269+
/// Returns `Err(None)` if `blocks` doesn't contain a value at height `0` a.k.a
270+
/// "genesis" block.
271+
pub fn from_blocks(blocks: BTreeMap<u32, D>) -> Result<Self, Option<CheckPoint<D>>> {
255272
if !blocks.contains_key(&0) {
256-
return Err(MissingGenesisError);
273+
return Err(None);
257274
}
258275

259276
Ok(Self {
260-
tip: CheckPoint::from_blocks(blocks).expect("blocks must be in order"),
277+
tip: CheckPoint::from_blocks(blocks)?,
261278
})
262279
}
263280

@@ -312,7 +329,8 @@ where
312329
/// Apply the given `changeset`.
313330
pub fn apply_changeset(&mut self, changeset: &ChangeSet<D>) -> Result<(), MissingGenesisError> {
314331
let old_tip = self.tip.clone();
315-
let new_tip = apply_changeset_to_checkpoint(old_tip, changeset)?;
332+
let new_tip =
333+
apply_changeset_to_checkpoint(old_tip, changeset).map_err(|_| MissingGenesisError)?;
316334
self.tip = new_tip;
317335
debug_assert!(self._check_changeset_is_applied(changeset));
318336
Ok(())
@@ -702,9 +720,9 @@ where
702720
}
703721

704722
// Apply changeset to tip.
705-
let new_tip = apply_changeset_to_checkpoint(self.tip(), &changeset).map_err(|_| {
723+
let new_tip = apply_changeset_to_checkpoint(self.tip(), &changeset).map_err(|e| {
706724
CannotConnectError {
707-
try_include_height: 0,
725+
try_include_height: e.error.as_ref().map_or(0, CheckPoint::height),
708726
}
709727
})?;
710728

0 commit comments

Comments
 (0)