From d2e7b48e2c76a34f065705053f6e6955d6878d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=97=E5=AE=87?= Date: Thu, 4 May 2023 16:53:35 +0800 Subject: [PATCH] [persist_redesign] Add `is_empty` method to `Append` trait `Store::append_changeset` logic now checks whether the changeset is empty, and if so, it skips persisting. --- crates/chain/src/indexed_tx_graph.rs | 4 ++++ crates/chain/src/keychain.rs | 14 ++++++++------ crates/chain/src/remote_chain.rs | 4 ++++ crates/chain/src/tracker.rs | 16 ++-------------- crates/chain/src/tx_data_traits.rs | 15 +++++++++++++++ crates/chain/src/tx_graph.rs | 13 ++++++++----- crates/chain/tests/test_keychain_txout_index.rs | 1 + crates/file_store/src/keychain_store.rs | 2 +- crates/file_store/src/store.rs | 12 +++++++++--- 9 files changed, 52 insertions(+), 29 deletions(-) diff --git a/crates/chain/src/indexed_tx_graph.rs b/crates/chain/src/indexed_tx_graph.rs index c550d86f07..7ab0ffa8a4 100644 --- a/crates/chain/src/indexed_tx_graph.rs +++ b/crates/chain/src/indexed_tx_graph.rs @@ -301,6 +301,10 @@ impl Append for IndexedAdditions { self.graph_additions.append(other.graph_additions); self.index_additions.append(other.index_additions); } + + fn is_empty(&self) -> bool { + self.graph_additions.is_empty() && self.index_additions.is_empty() + } } /// Represents a structure that can index transaction data. diff --git a/crates/chain/src/keychain.rs b/crates/chain/src/keychain.rs index 81503049bd..3807e04cb9 100644 --- a/crates/chain/src/keychain.rs +++ b/crates/chain/src/keychain.rs @@ -59,11 +59,6 @@ pub use txout_index::*; pub struct DerivationAdditions(pub BTreeMap); impl DerivationAdditions { - /// Returns whether the additions are empty. - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } - /// Get the inner map of the keychain to its new derivation index. pub fn as_inner(&self) -> &BTreeMap { &self.0 @@ -84,6 +79,10 @@ impl Append for DerivationAdditions { self.0.append(&mut other.0); } + + fn is_empty(&self) -> bool { + self.0.is_empty() + } } impl Default for DerivationAdditions { @@ -159,7 +158,10 @@ impl Default for KeychainChangeSet { impl KeychainChangeSet { /// Returns whether the [`KeychainChangeSet`] is empty (no changes recorded). - pub fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool + where + K: Ord, + { self.chain_graph.is_empty() && self.derivation_indices.is_empty() } diff --git a/crates/chain/src/remote_chain.rs b/crates/chain/src/remote_chain.rs index df4952313c..795dc125f6 100644 --- a/crates/chain/src/remote_chain.rs +++ b/crates/chain/src/remote_chain.rs @@ -86,4 +86,8 @@ impl Append for ChangeSet { *self = other; } } + + fn is_empty(&self) -> bool { + self.is_none() + } } diff --git a/crates/chain/src/tracker.rs b/crates/chain/src/tracker.rs index 15883a7e45..a607c75448 100644 --- a/crates/chain/src/tracker.rs +++ b/crates/chain/src/tracker.rs @@ -341,20 +341,8 @@ impl Append for ChangeSet { Append::append(&mut self.indexed_additions, other.indexed_additions); Append::append(&mut self.chain_changeset, other.chain_changeset) } -} - -impl LocalChangeSet { - pub fn is_empty(&self) -> bool { - self.indexed_additions.index_additions.is_empty() - && self.indexed_additions.graph_additions.is_empty() - && self.chain_changeset.is_empty() - } -} -impl RemoteChangeSet { - pub fn is_empty(&self) -> bool { - self.indexed_additions.index_additions.is_empty() - && self.indexed_additions.graph_additions.is_empty() - && self.chain_changeset.is_none() + fn is_empty(&self) -> bool { + self.indexed_additions.is_empty() && self.chain_changeset.is_empty() } } diff --git a/crates/chain/src/tx_data_traits.rs b/crates/chain/src/tx_data_traits.rs index 8ec695add3..7d5d0a8080 100644 --- a/crates/chain/src/tx_data_traits.rs +++ b/crates/chain/src/tx_data_traits.rs @@ -64,20 +64,35 @@ impl Anchor for &'static A { pub trait Append { /// Append another object of the same type onto `self`. fn append(&mut self, other: Self); + + /// Determines whether the structure is empty. + fn is_empty(&self) -> bool; } impl Append for () { fn append(&mut self, _other: Self) {} + + fn is_empty(&self) -> bool { + true + } } impl Append for BTreeMap { fn append(&mut self, mut other: Self) { BTreeMap::append(self, &mut other) } + + fn is_empty(&self) -> bool { + BTreeMap::is_empty(self) + } } impl Append for BTreeSet { fn append(&mut self, mut other: Self) { BTreeSet::append(self, &mut other) } + + fn is_empty(&self) -> bool { + BTreeSet::is_empty(self) + } } diff --git a/crates/chain/src/tx_graph.rs b/crates/chain/src/tx_graph.rs index b1152c334f..32fe6874c4 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -38,6 +38,7 @@ //! # use bdk_chain::BlockId; //! # use bdk_chain::tx_graph::TxGraph; //! # use bdk_chain::example_utils::*; +//! # use bdk_chain::Append; //! # use bitcoin::Transaction; //! # let tx_a = tx_from_hex(RAW_TX_1); //! # let tx_b = tx_from_hex(RAW_TX_2); @@ -906,11 +907,6 @@ impl Default for Additions { } impl Additions { - /// Returns true if the [`Additions`] is empty (no transactions or txouts). - pub fn is_empty(&self) -> bool { - self.tx.is_empty() && self.txout.is_empty() - } - /// Iterates over all outpoints contained within [`Additions`]. pub fn txouts(&self) -> impl Iterator { self.tx @@ -940,6 +936,13 @@ impl Append for Additions { .collect::>(), ); } + + fn is_empty(&self) -> bool { + self.tx.is_empty() + && self.txout.is_empty() + && self.anchors.is_empty() + && self.last_seen.is_empty() + } } impl AsRef> for TxGraph { diff --git a/crates/chain/tests/test_keychain_txout_index.rs b/crates/chain/tests/test_keychain_txout_index.rs index 5f586584cb..a92e74486d 100644 --- a/crates/chain/tests/test_keychain_txout_index.rs +++ b/crates/chain/tests/test_keychain_txout_index.rs @@ -5,6 +5,7 @@ mod common; use bdk_chain::{ collections::BTreeMap, keychain::{DerivationAdditions, KeychainTxOutIndex}, + Append, }; use bitcoin::{secp256k1::Secp256k1, OutPoint, Script, Transaction, TxOut}; diff --git a/crates/file_store/src/keychain_store.rs b/crates/file_store/src/keychain_store.rs index d60b12737e..af0a1d61fb 100644 --- a/crates/file_store/src/keychain_store.rs +++ b/crates/file_store/src/keychain_store.rs @@ -4,7 +4,7 @@ //! [`KeychainChangeSet`]s which can be used to restore a [`KeychainTracker`]. use bdk_chain::{ keychain::{KeychainChangeSet, KeychainTracker}, - sparse_chain, + sparse_chain, Append, }; use bincode::Options; use std::{ diff --git a/crates/file_store/src/store.rs b/crates/file_store/src/store.rs index dbcc6b022b..6550bd2710 100644 --- a/crates/file_store/src/store.rs +++ b/crates/file_store/src/store.rs @@ -172,10 +172,12 @@ where /// /// The truncation is to avoid the possibility of having a valid but inconsistent changeset /// directly after the appended changeset. - /// - /// **WARNING**: This method does not detect whether the changeset is empty or not, and will - /// append an empty changeset to the file (not catastrophic, just a waste of space). pub fn append_changeset(&mut self, changeset: &C) -> Result<(), io::Error> { + // no need to write anything if changeset is empty + if changeset.is_empty() { + return Ok(()); + } + bincode_options() .serialize_into(&mut self.db_file, changeset) .map_err(|e| match *e { @@ -243,6 +245,10 @@ mod test { fn append(&mut self, mut other: Self) { self.changes.append(&mut other.changes) } + + fn is_empty(&self) -> bool { + self.changes.is_empty() + } } #[derive(Debug)]