From 0bee46e75bc99112abc15de59984e6059ff874e5 Mon Sep 17 00:00:00 2001 From: LLFourn Date: Fri, 19 Jan 2024 10:34:37 +1100 Subject: [PATCH 1/2] fix(store): Remove lifetime Remove gratuitous use of lifetimes in the main persistence struct --- crates/file_store/src/store.rs | 20 ++++++++++---------- example-crates/example_cli/src/lib.rs | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/crates/file_store/src/store.rs b/crates/file_store/src/store.rs index ebab2fd0..b66275df 100644 --- a/crates/file_store/src/store.rs +++ b/crates/file_store/src/store.rs @@ -15,13 +15,13 @@ use crate::{bincode_options, EntryIter, FileError, IterError}; /// /// The changesets are the results of altering a tracker implementation (`T`). #[derive(Debug)] -pub struct Store<'a, C> { - magic: &'a [u8], +pub struct Store { + magic_len: usize, db_file: File, marker: PhantomData, } -impl<'a, C> PersistBackend for Store<'a, C> +impl PersistBackend for Store where C: Append + serde::Serialize + serde::de::DeserializeOwned, { @@ -38,7 +38,7 @@ where } } -impl<'a, C> Store<'a, C> +impl Store where C: Append + serde::Serialize + serde::de::DeserializeOwned, { @@ -48,7 +48,7 @@ where /// the `Store` in the future with [`open`]. /// /// [`open`]: Store::open - pub fn create_new

(magic: &'a [u8], file_path: P) -> Result + pub fn create_new

(magic: &[u8], file_path: P) -> Result where P: AsRef, { @@ -67,7 +67,7 @@ where .open(file_path)?; f.write_all(magic)?; Ok(Self { - magic, + magic_len: magic.len(), db_file: f, marker: Default::default(), }) @@ -83,7 +83,7 @@ where /// [`FileError::InvalidMagicBytes`] error variant will be returned. /// /// [`create_new`]: Store::create_new - pub fn open

(magic: &'a [u8], file_path: P) -> Result + pub fn open

(magic: &[u8], file_path: P) -> Result where P: AsRef, { @@ -99,7 +99,7 @@ where } Ok(Self { - magic, + magic_len: magic.len(), db_file: f, marker: Default::default(), }) @@ -111,7 +111,7 @@ where /// /// [`open`]: Store::open /// [`create_new`]: Store::create_new - pub fn open_or_create_new

(magic: &'a [u8], file_path: P) -> Result + pub fn open_or_create_new

(magic: &[u8], file_path: P) -> Result where P: AsRef, { @@ -132,7 +132,7 @@ where /// always iterate over all entries until `None` is returned if you want your next write to go /// at the end; otherwise, you will write over existing entries. pub fn iter_changesets(&mut self) -> EntryIter { - EntryIter::new(self.magic.len() as u64, &mut self.db_file) + EntryIter::new(self.magic_len as u64, &mut self.db_file) } /// Loads all the changesets that have been stored as one giant changeset. diff --git a/example-crates/example_cli/src/lib.rs b/example-crates/example_cli/src/lib.rs index 46231946..aa52b46d 100644 --- a/example-crates/example_cli/src/lib.rs +++ b/example-crates/example_cli/src/lib.rs @@ -29,7 +29,7 @@ pub type KeychainChangeSet = ( local_chain::ChangeSet, indexed_tx_graph::ChangeSet>, ); -pub type Database<'m, C> = Persist, C>; +pub type Database = Persist, C>; #[derive(Parser)] #[clap(author, version, about, long_about = None)] @@ -646,14 +646,14 @@ where } #[allow(clippy::type_complexity)] -pub fn init<'m, CS: clap::Subcommand, S: clap::Args, C>( - db_magic: &'m [u8], +pub fn init( + db_magic: &[u8], db_default_path: &str, ) -> anyhow::Result<( Args, KeyMap, KeychainTxOutIndex, - Mutex>, + Mutex>, C, )> where @@ -681,7 +681,7 @@ where index.add_keychain(Keychain::Internal, internal_descriptor); } - let mut db_backend = match Store::<'m, C>::open_or_create_new(db_magic, &args.db_path) { + let mut db_backend = match Store::::open_or_create_new(db_magic, &args.db_path) { Ok(db_backend) => db_backend, // we cannot return `err` directly as it has lifetime `'m` Err(err) => return Err(anyhow::anyhow!("failed to init db backend: {:?}", err)), From e6433fb2c1526cff37e3a17cc71986759ebac30f Mon Sep 17 00:00:00 2001 From: LLFourn Date: Fri, 19 Jan 2024 11:23:46 +1100 Subject: [PATCH 2/2] feat(persist): Add stage_and_commit to Persist In the example_cli we were not always committing (seemingly by mistake). This then caused all the examples to have to compensate by manually committing. --- crates/chain/src/persist.rs | 12 ++++++++++++ .../example_bitcoind_rpc_polling/src/main.rs | 4 +--- example-crates/example_cli/src/lib.rs | 14 ++++++-------- example-crates/example_electrum/src/main.rs | 5 +---- example-crates/example_esplora/src/main.rs | 5 +---- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/crates/chain/src/persist.rs b/crates/chain/src/persist.rs index 3c8c8b9e..c527e57d 100644 --- a/crates/chain/src/persist.rs +++ b/crates/chain/src/persist.rs @@ -55,6 +55,18 @@ where // if written successfully, take and return `self.stage` .map(|_| Some(core::mem::take(&mut self.stage))) } + + /// Stages a new changeset and commits it (along with any other previously staged changes) to + /// the persistence backend + /// + /// Convience method for calling [`stage`] and then [`commit`]. + /// + /// [`stage`]: Self::stage + /// [`commit`]: Self::commit + pub fn stage_and_commit(&mut self, changeset: C) -> Result, B::WriteError> { + self.stage(changeset); + self.commit() + } } /// A persistence backend for [`Persist`]. diff --git a/example-crates/example_bitcoind_rpc_polling/src/main.rs b/example-crates/example_bitcoind_rpc_polling/src/main.rs index 449242e4..553dc28b 100644 --- a/example-crates/example_bitcoind_rpc_polling/src/main.rs +++ b/example-crates/example_bitcoind_rpc_polling/src/main.rs @@ -147,7 +147,7 @@ fn main() -> anyhow::Result<()> { let rpc_cmd = match args.command { example_cli::Commands::ChainSpecific(rpc_cmd) => rpc_cmd, general_cmd => { - let res = example_cli::handle_commands( + return example_cli::handle_commands( &graph, &db, &chain, @@ -160,8 +160,6 @@ fn main() -> anyhow::Result<()> { }, general_cmd, ); - db.lock().unwrap().commit()?; - return res; } }; diff --git a/example-crates/example_cli/src/lib.rs b/example-crates/example_cli/src/lib.rs index aa52b46d..cfc499a0 100644 --- a/example-crates/example_cli/src/lib.rs +++ b/example-crates/example_cli/src/lib.rs @@ -457,11 +457,10 @@ where let ((spk_i, spk), index_changeset) = spk_chooser(index, &Keychain::External); let db = &mut *db.lock().unwrap(); - db.stage(C::from(( + db.stage_and_commit(C::from(( local_chain::ChangeSet::default(), indexed_tx_graph::ChangeSet::from(index_changeset), - ))); - db.commit()?; + )))?; let addr = Address::from_script(spk, network).context("failed to derive address")?; println!("[address @ {}] {}", spk_i, addr); @@ -601,11 +600,10 @@ where // If we're unable to persist this, then we don't want to broadcast. { let db = &mut *db.lock().unwrap(); - db.stage(C::from(( + db.stage_and_commit(C::from(( local_chain::ChangeSet::default(), indexed_tx_graph::ChangeSet::from(index_changeset), - ))); - db.commit()?; + )))?; } // We don't want other callers/threads to use this address while we're using it @@ -627,10 +625,10 @@ where // We know the tx is at least unconfirmed now. Note if persisting here fails, // it's not a big deal since we can always find it again form // blockchain. - db.lock().unwrap().stage(C::from(( + db.lock().unwrap().stage_and_commit(C::from(( local_chain::ChangeSet::default(), keychain_changeset, - ))); + )))?; Ok(()) } Err(e) => { diff --git a/example-crates/example_electrum/src/main.rs b/example-crates/example_electrum/src/main.rs index e7545f05..ccd17a70 100644 --- a/example-crates/example_electrum/src/main.rs +++ b/example-crates/example_electrum/src/main.rs @@ -122,7 +122,7 @@ fn main() -> anyhow::Result<()> { let electrum_cmd = match &args.command { example_cli::Commands::ChainSpecific(electrum_cmd) => electrum_cmd, general_cmd => { - let res = example_cli::handle_commands( + return example_cli::handle_commands( &graph, &db, &chain, @@ -135,9 +135,6 @@ fn main() -> anyhow::Result<()> { }, general_cmd.clone(), ); - - db.lock().unwrap().commit()?; - return res; } }; diff --git a/example-crates/example_esplora/src/main.rs b/example-crates/example_esplora/src/main.rs index 298532cb..b4dabea7 100644 --- a/example-crates/example_esplora/src/main.rs +++ b/example-crates/example_esplora/src/main.rs @@ -125,7 +125,7 @@ fn main() -> anyhow::Result<()> { example_cli::Commands::ChainSpecific(esplora_cmd) => esplora_cmd, // These are general commands handled by example_cli. Execute the cmd and return. general_cmd => { - let res = example_cli::handle_commands( + return example_cli::handle_commands( &graph, &db, &chain, @@ -140,9 +140,6 @@ fn main() -> anyhow::Result<()> { }, general_cmd.clone(), ); - - db.lock().unwrap().commit()?; - return res; } };