]> Untitled Git - bdk/commitdiff
[bdk_chain_redesign] Simplify `LocalChain`
author志宇 <hello@evanlinjin.me>
Mon, 10 Apr 2023 07:04:20 +0000 (15:04 +0800)
committer志宇 <hello@evanlinjin.me>
Mon, 10 Apr 2023 07:04:20 +0000 (15:04 +0800)
Remove the requirement that evicted blocks should have in-best-chain
counterparts in the update.

crates/chain/src/local_chain.rs

index 20b54a2f2f8df4847ca76b866acbd805a74e27db..58cf923b47f67a712771b3e944bfea12d77efb8e 100644 (file)
@@ -1,12 +1,9 @@
 use core::{convert::Infallible, ops::Deref};
 
-use alloc::{
-    collections::{BTreeMap, BTreeSet},
-    vec::Vec,
-};
+use alloc::collections::{BTreeMap, BTreeSet};
 use bitcoin::BlockHash;
 
-use crate::{BlockId, ChainOracle};
+use crate::{Append, BlockId, ChainOracle};
 
 #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
 pub struct LocalChain {
@@ -56,6 +53,12 @@ impl From<LocalChain> for BTreeMap<u32, BlockHash> {
     }
 }
 
+impl From<BTreeMap<u32, BlockHash>> for LocalChain {
+    fn from(value: BTreeMap<u32, BlockHash>) -> Self {
+        Self { blocks: value }
+    }
+}
+
 impl LocalChain {
     pub fn tip(&self) -> Option<BlockId> {
         self.blocks
@@ -66,10 +69,7 @@ impl LocalChain {
 
     /// This is like the sparsechain's logic, expect we must guarantee that all invalidated heights
     /// are to be re-filled.
-    pub fn determine_changeset<U>(&self, update: &U) -> Result<ChangeSet, UpdateError>
-    where
-        U: AsRef<BTreeMap<u32, BlockHash>>,
-    {
+    pub fn determine_changeset(&self, update: &Self) -> Result<ChangeSet, UpdateNotConnectedError> {
         let update = update.as_ref();
         let update_tip = match update.keys().last().cloned() {
             Some(tip) => tip,
@@ -96,24 +96,9 @@ impl LocalChain {
         // the first block of height to invalidate (if any) should be represented in the update
         if let Some(first_invalid_height) = invalidate_from_height {
             if !update.contains_key(&first_invalid_height) {
-                return Err(UpdateError::NotConnected(first_invalid_height));
-            }
-        }
-
-        let invalidated_heights = invalidate_from_height
-            .into_iter()
-            .flat_map(|from_height| self.blocks.range(from_height..).map(|(h, _)| h));
-
-        // invalidated heights must all exist in the update
-        let mut missing_heights = Vec::<u32>::new();
-        for invalidated_height in invalidated_heights {
-            if !update.contains_key(invalidated_height) {
-                missing_heights.push(*invalidated_height);
+                return Err(UpdateNotConnectedError(first_invalid_height));
             }
         }
-        if !missing_heights.is_empty() {
-            return Err(UpdateError::MissingHeightsInUpdate(missing_heights));
-        }
 
         let mut changeset = BTreeMap::<u32, BlockHash>::new();
         for (height, new_hash) in update {
@@ -136,7 +121,7 @@ impl LocalChain {
     ///
     /// [`determine_changeset`]: Self::determine_changeset
     /// [`apply_changeset`]: Self::apply_changeset
-    pub fn apply_update(&mut self, update: Self) -> Result<ChangeSet, UpdateError> {
+    pub fn apply_update(&mut self, update: Self) -> Result<ChangeSet, UpdateNotConnectedError> {
         let changeset = self.determine_changeset(&update)?;
         self.apply_changeset(changeset.clone());
         Ok(changeset)
@@ -160,7 +145,7 @@ impl LocalChain {
     derive(serde::Deserialize, serde::Serialize),
     serde(crate = "serde_crate")
 )]
-pub struct ChangeSet(pub BTreeMap<u32, BlockHash>);
+pub struct ChangeSet(pub(crate) BTreeMap<u32, BlockHash>);
 
 impl Deref for ChangeSet {
     type Target = BTreeMap<u32, BlockHash>;
@@ -170,32 +155,30 @@ impl Deref for ChangeSet {
     }
 }
 
-/// Represents an update failure of [`LocalChain`].
-#[derive(Clone, Debug, PartialEq)]
-pub enum UpdateError {
-    /// The update cannot be applied to the chain because the chain suffix it represents did not
-    /// connect to the existing chain. This error case contains the checkpoint height to include so
-    /// that the chains can connect.
-    NotConnected(u32),
-    /// If the update results in displacements of original blocks, the update should include all new
-    /// block hashes that have displaced the original block hashes. This error case contains the
-    /// heights of all missing block hashes in the update.
-    MissingHeightsInUpdate(Vec<u32>),
+impl Append for ChangeSet {
+    fn append(&mut self, mut other: Self) {
+        BTreeMap::append(&mut self.0, &mut other.0)
+    }
 }
 
-impl core::fmt::Display for UpdateError {
+/// Represents an update failure of [`LocalChain`] due to the update not connecting to the original
+/// chain.
+///
+/// The update cannot be applied to the chain because the chain suffix it represents did not
+/// connect to the existing chain. This error case contains the checkpoint height to include so
+/// that the chains can connect.
+#[derive(Clone, Debug, PartialEq)]
+pub struct UpdateNotConnectedError(u32);
+
+impl core::fmt::Display for UpdateNotConnectedError {
     fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
-        match self {
-            UpdateError::NotConnected(heights) => write!(
-                f,
-                "the update cannot connect with the chain, try include blockhash at height {}",
-                heights
-            ),
-            UpdateError::MissingHeightsInUpdate(missing_heights) => write!(
-                f,
-                "block hashes of these heights must be included in the update to succeed: {:?}",
-                missing_heights
-            ),
-        }
+        write!(
+            f,
+            "the update cannot connect with the chain, try include block at height {}",
+            self.0
+        )
     }
 }
+
+#[cfg(feature = "std")]
+impl std::error::Error for UpdateNotConnectedError {}