[database] Wrap BlockTime in another struct to allow adding more

fields in the future
This commit is contained in:
Alekos Filini 2021-11-04 15:38:38 +00:00
parent 2c77329333
commit 5830226216
No known key found for this signature in database
GPG Key ID: 431401E4A4530061
6 changed files with 103 additions and 88 deletions

View File

@ -144,8 +144,8 @@ impl BatchOperations for AnyDatabase {
fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> { fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> {
impl_inner_method!(AnyDatabase, self, set_last_index, keychain, value) impl_inner_method!(AnyDatabase, self, set_last_index, keychain, value)
} }
fn set_last_sync_time(&mut self, last_sync_time: BlockTime) -> Result<(), Error> { fn set_sync_time(&mut self, sync_time: SyncTime) -> Result<(), Error> {
impl_inner_method!(AnyDatabase, self, set_last_sync_time, last_sync_time) impl_inner_method!(AnyDatabase, self, set_sync_time, sync_time)
} }
fn del_script_pubkey_from_path( fn del_script_pubkey_from_path(
@ -183,8 +183,8 @@ impl BatchOperations for AnyDatabase {
fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> { fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
impl_inner_method!(AnyDatabase, self, del_last_index, keychain) impl_inner_method!(AnyDatabase, self, del_last_index, keychain)
} }
fn del_last_sync_time(&mut self) -> Result<Option<BlockTime>, Error> { fn del_sync_time(&mut self) -> Result<Option<SyncTime>, Error> {
impl_inner_method!(AnyDatabase, self, del_last_sync_time) impl_inner_method!(AnyDatabase, self, del_sync_time)
} }
} }
@ -247,8 +247,8 @@ impl Database for AnyDatabase {
fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error> { fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
impl_inner_method!(AnyDatabase, self, get_last_index, keychain) impl_inner_method!(AnyDatabase, self, get_last_index, keychain)
} }
fn get_last_sync_time(&self) -> Result<Option<BlockTime>, Error> { fn get_sync_time(&self) -> Result<Option<SyncTime>, Error> {
impl_inner_method!(AnyDatabase, self, get_last_sync_time) impl_inner_method!(AnyDatabase, self, get_sync_time)
} }
fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> { fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> {
@ -281,8 +281,8 @@ impl BatchOperations for AnyBatch {
fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> { fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error> {
impl_inner_method!(AnyBatch, self, set_last_index, keychain, value) impl_inner_method!(AnyBatch, self, set_last_index, keychain, value)
} }
fn set_last_sync_time(&mut self, last_sync_time: BlockTime) -> Result<(), Error> { fn set_sync_time(&mut self, sync_time: SyncTime) -> Result<(), Error> {
impl_inner_method!(AnyBatch, self, set_last_sync_time, last_sync_time) impl_inner_method!(AnyBatch, self, set_sync_time, sync_time)
} }
fn del_script_pubkey_from_path( fn del_script_pubkey_from_path(
@ -314,8 +314,8 @@ impl BatchOperations for AnyBatch {
fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> { fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error> {
impl_inner_method!(AnyBatch, self, del_last_index, keychain) impl_inner_method!(AnyBatch, self, del_last_index, keychain)
} }
fn del_last_sync_time(&mut self) -> Result<Option<BlockTime>, Error> { fn del_sync_time(&mut self) -> Result<Option<SyncTime>, Error> {
impl_inner_method!(AnyBatch, self, del_last_sync_time) impl_inner_method!(AnyBatch, self, del_sync_time)
} }
} }

View File

@ -18,7 +18,7 @@ use bitcoin::hash_types::Txid;
use bitcoin::{OutPoint, Script, Transaction}; use bitcoin::{OutPoint, Script, Transaction};
use crate::database::memory::MapKey; use crate::database::memory::MapKey;
use crate::database::{BatchDatabase, BatchOperations, Database}; use crate::database::{BatchDatabase, BatchOperations, Database, SyncTime};
use crate::error::Error; use crate::error::Error;
use crate::types::*; use crate::types::*;
@ -82,9 +82,9 @@ macro_rules! impl_batch_operations {
Ok(()) Ok(())
} }
fn set_last_sync_time(&mut self, ct: BlockTime) -> Result<(), Error> { fn set_sync_time(&mut self, data: SyncTime) -> Result<(), Error> {
let key = MapKey::LastSyncTime.as_map_key(); let key = MapKey::SyncTime.as_map_key();
self.insert(key, serde_json::to_vec(&ct)?)$($after_insert)*; self.insert(key, serde_json::to_vec(&data)?)$($after_insert)*;
Ok(()) Ok(())
} }
@ -176,8 +176,8 @@ macro_rules! impl_batch_operations {
} }
} }
fn del_last_sync_time(&mut self) -> Result<Option<BlockTime>, Error> { fn del_sync_time(&mut self) -> Result<Option<SyncTime>, Error> {
let key = MapKey::LastSyncTime.as_map_key(); let key = MapKey::SyncTime.as_map_key();
let res = self.remove(key); let res = self.remove(key);
let res = $process_delete!(res); let res = $process_delete!(res);
@ -357,8 +357,8 @@ impl Database for Tree {
.transpose() .transpose()
} }
fn get_last_sync_time(&self) -> Result<Option<BlockTime>, Error> { fn get_sync_time(&self) -> Result<Option<SyncTime>, Error> {
let key = MapKey::LastSyncTime.as_map_key(); let key = MapKey::SyncTime.as_map_key();
Ok(self Ok(self
.get(key)? .get(key)?
.map(|b| serde_json::from_slice(&b)) .map(|b| serde_json::from_slice(&b))
@ -495,7 +495,7 @@ mod test {
} }
#[test] #[test]
fn test_last_sync_time() { fn test_sync_time() {
crate::database::test::test_last_sync_time(get_tree()); crate::database::test::test_sync_time(get_tree());
} }
} }

View File

@ -22,7 +22,7 @@ use bitcoin::consensus::encode::{deserialize, serialize};
use bitcoin::hash_types::Txid; use bitcoin::hash_types::Txid;
use bitcoin::{OutPoint, Script, Transaction}; use bitcoin::{OutPoint, Script, Transaction};
use crate::database::{BatchDatabase, BatchOperations, ConfigurableDatabase, Database}; use crate::database::{BatchDatabase, BatchOperations, ConfigurableDatabase, Database, SyncTime};
use crate::error::Error; use crate::error::Error;
use crate::types::*; use crate::types::*;
@ -42,7 +42,7 @@ pub(crate) enum MapKey<'a> {
RawTx(Option<&'a Txid>), RawTx(Option<&'a Txid>),
Transaction(Option<&'a Txid>), Transaction(Option<&'a Txid>),
LastIndex(KeychainKind), LastIndex(KeychainKind),
LastSyncTime, SyncTime,
DescriptorChecksum(KeychainKind), DescriptorChecksum(KeychainKind),
} }
@ -61,7 +61,7 @@ impl MapKey<'_> {
MapKey::RawTx(_) => b"r".to_vec(), MapKey::RawTx(_) => b"r".to_vec(),
MapKey::Transaction(_) => b"t".to_vec(), MapKey::Transaction(_) => b"t".to_vec(),
MapKey::LastIndex(st) => [b"c", st.as_ref()].concat(), MapKey::LastIndex(st) => [b"c", st.as_ref()].concat(),
MapKey::LastSyncTime => b"l".to_vec(), MapKey::SyncTime => b"l".to_vec(),
MapKey::DescriptorChecksum(st) => [b"d", st.as_ref()].concat(), MapKey::DescriptorChecksum(st) => [b"d", st.as_ref()].concat(),
} }
} }
@ -183,9 +183,9 @@ impl BatchOperations for MemoryDatabase {
Ok(()) Ok(())
} }
fn set_last_sync_time(&mut self, ct: BlockTime) -> Result<(), Error> { fn set_sync_time(&mut self, data: SyncTime) -> Result<(), Error> {
let key = MapKey::LastSyncTime.as_map_key(); let key = MapKey::SyncTime.as_map_key();
self.map.insert(key, Box::new(ct)); self.map.insert(key, Box::new(data));
Ok(()) Ok(())
} }
@ -279,8 +279,8 @@ impl BatchOperations for MemoryDatabase {
Some(b) => Ok(Some(*b.downcast_ref().unwrap())), Some(b) => Ok(Some(*b.downcast_ref().unwrap())),
} }
} }
fn del_last_sync_time(&mut self) -> Result<Option<BlockTime>, Error> { fn del_sync_time(&mut self) -> Result<Option<SyncTime>, Error> {
let key = MapKey::LastSyncTime.as_map_key(); let key = MapKey::SyncTime.as_map_key();
let res = self.map.remove(&key); let res = self.map.remove(&key);
self.deleted_keys.push(key); self.deleted_keys.push(key);
@ -423,8 +423,8 @@ impl Database for MemoryDatabase {
Ok(self.map.get(&key).map(|b| *b.downcast_ref().unwrap())) Ok(self.map.get(&key).map(|b| *b.downcast_ref().unwrap()))
} }
fn get_last_sync_time(&self) -> Result<Option<BlockTime>, Error> { fn get_sync_time(&self) -> Result<Option<SyncTime>, Error> {
let key = MapKey::LastSyncTime.as_map_key(); let key = MapKey::SyncTime.as_map_key();
Ok(self Ok(self
.map .map
.get(&key) .get(&key)
@ -503,9 +503,7 @@ macro_rules! populate_test_db {
}; };
let txid = tx.txid(); let txid = tx.txid();
let confirmation_time = tx_meta let confirmation_time = tx_meta.min_confirmations.map(|conf| $crate::BlockTime {
.min_confirmations
.map(|conf| $crate::BlockTime {
height: current_height.unwrap().checked_sub(conf as u32).unwrap(), height: current_height.unwrap().checked_sub(conf as u32).unwrap(),
timestamp: 0, timestamp: 0,
}); });
@ -616,7 +614,7 @@ mod test {
} }
#[test] #[test]
fn test_last_sync_time() { fn test_sync_time() {
crate::database::test::test_last_sync_time(get_tree()); crate::database::test::test_sync_time(get_tree());
} }
} }

View File

@ -24,6 +24,8 @@
//! //!
//! [`Wallet`]: crate::wallet::Wallet //! [`Wallet`]: crate::wallet::Wallet
use serde::{Deserialize, Serialize};
use bitcoin::hash_types::Txid; use bitcoin::hash_types::Txid;
use bitcoin::{OutPoint, Script, Transaction, TxOut}; use bitcoin::{OutPoint, Script, Transaction, TxOut};
@ -44,6 +46,15 @@ pub use sqlite::SqliteDatabase;
pub mod memory; pub mod memory;
pub use memory::MemoryDatabase; pub use memory::MemoryDatabase;
/// Blockchain state at the time of syncing
///
/// Contains only the block time and height at the moment
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct SyncTime {
/// Block timestamp and height at the time of sync
pub block_time: BlockTime,
}
/// Trait for operations that can be batched /// Trait for operations that can be batched
/// ///
/// This trait defines the list of operations that must be implemented on the [`Database`] type and /// This trait defines the list of operations that must be implemented on the [`Database`] type and
@ -64,8 +75,8 @@ pub trait BatchOperations {
fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error>; fn set_tx(&mut self, transaction: &TransactionDetails) -> Result<(), Error>;
/// Store the last derivation index for a given keychain. /// Store the last derivation index for a given keychain.
fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error>; fn set_last_index(&mut self, keychain: KeychainKind, value: u32) -> Result<(), Error>;
/// Store the sync time in terms of block height and timestamp /// Store the sync time
fn set_last_sync_time(&mut self, last_sync_time: BlockTime) -> Result<(), Error>; fn set_sync_time(&mut self, sync_time: SyncTime) -> Result<(), Error>;
/// Delete a script_pubkey given the keychain and its child number. /// Delete a script_pubkey given the keychain and its child number.
fn del_script_pubkey_from_path( fn del_script_pubkey_from_path(
@ -91,10 +102,10 @@ pub trait BatchOperations {
) -> Result<Option<TransactionDetails>, Error>; ) -> Result<Option<TransactionDetails>, Error>;
/// Delete the last derivation index for a keychain. /// Delete the last derivation index for a keychain.
fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error>; fn del_last_index(&mut self, keychain: KeychainKind) -> Result<Option<u32>, Error>;
/// Reset the last sync time to `None` /// Reset the sync time to `None`
/// ///
/// Returns the removed value /// Returns the removed value
fn del_last_sync_time(&mut self) -> Result<Option<BlockTime>, Error>; fn del_sync_time(&mut self) -> Result<Option<SyncTime>, Error>;
} }
/// Trait for reading data from a database /// Trait for reading data from a database
@ -140,8 +151,8 @@ pub trait Database: BatchOperations {
fn get_tx(&self, txid: &Txid, include_raw: bool) -> Result<Option<TransactionDetails>, Error>; fn get_tx(&self, txid: &Txid, include_raw: bool) -> Result<Option<TransactionDetails>, Error>;
/// Return the last defivation index for a keychain. /// Return the last defivation index for a keychain.
fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error>; fn get_last_index(&self, keychain: KeychainKind) -> Result<Option<u32>, Error>;
/// Return the last sync time, if present /// Return the sync time, if present
fn get_last_sync_time(&self) -> Result<Option<BlockTime>, Error>; fn get_sync_time(&self) -> Result<Option<SyncTime>, Error>;
/// Increment the last derivation index for a keychain and return it /// Increment the last derivation index for a keychain and return it
/// ///
@ -385,22 +396,24 @@ pub mod test {
); );
} }
pub fn test_last_sync_time<D: Database>(mut tree: D) { pub fn test_sync_time<D: Database>(mut tree: D) {
assert!(tree.get_last_sync_time().unwrap().is_none()); assert!(tree.get_sync_time().unwrap().is_none());
tree.set_last_sync_time(BlockTime { tree.set_sync_time(SyncTime {
block_time: BlockTime {
height: 100, height: 100,
timestamp: 1000, timestamp: 1000,
},
}) })
.unwrap(); .unwrap();
let extracted = tree.get_last_sync_time().unwrap(); let extracted = tree.get_sync_time().unwrap();
assert!(extracted.is_some()); assert!(extracted.is_some());
assert_eq!(extracted.as_ref().unwrap().height, 100); assert_eq!(extracted.as_ref().unwrap().block_time.height, 100);
assert_eq!(extracted.as_ref().unwrap().timestamp, 1000); assert_eq!(extracted.as_ref().unwrap().block_time.timestamp, 1000);
tree.del_last_sync_time().unwrap(); tree.del_sync_time().unwrap();
assert!(tree.get_last_sync_time().unwrap().is_none()); assert!(tree.get_sync_time().unwrap().is_none());
} }
// TODO: more tests... // TODO: more tests...

View File

@ -13,7 +13,7 @@ use bitcoin::consensus::encode::{deserialize, serialize};
use bitcoin::hash_types::Txid; use bitcoin::hash_types::Txid;
use bitcoin::{OutPoint, Script, Transaction, TxOut}; use bitcoin::{OutPoint, Script, Transaction, TxOut};
use crate::database::{BatchDatabase, BatchOperations, Database}; use crate::database::{BatchDatabase, BatchOperations, Database, SyncTime};
use crate::error::Error; use crate::error::Error;
use crate::types::*; use crate::types::*;
@ -35,7 +35,7 @@ static MIGRATIONS: &[&str] = &[
"CREATE UNIQUE INDEX idx_indices_keychain ON last_derivation_indices(keychain);", "CREATE UNIQUE INDEX idx_indices_keychain ON last_derivation_indices(keychain);",
"CREATE TABLE checksums (keychain TEXT, checksum BLOB);", "CREATE TABLE checksums (keychain TEXT, checksum BLOB);",
"CREATE INDEX idx_checksums_keychain ON checksums(keychain);", "CREATE INDEX idx_checksums_keychain ON checksums(keychain);",
"CREATE TABLE last_sync_time (id INTEGER PRIMARY KEY, height INTEGER, timestamp INTEGER);" "CREATE TABLE sync_time (id INTEGER PRIMARY KEY, height INTEGER, timestamp INTEGER);"
]; ];
/// Sqlite database stored on filesystem /// Sqlite database stored on filesystem
@ -206,14 +206,14 @@ impl SqliteDatabase {
Ok(()) Ok(())
} }
fn update_last_sync_time(&self, ct: BlockTime) -> Result<i64, Error> { fn update_sync_time(&self, data: SyncTime) -> Result<i64, Error> {
let mut statement = self.connection.prepare_cached( let mut statement = self.connection.prepare_cached(
"INSERT INTO last_sync_time (id, height, timestamp) VALUES (0, :height, :timestamp) ON CONFLICT(id) DO UPDATE SET height=:height, timestamp=:timestamp WHERE id = 0", "INSERT INTO sync_time (id, height, timestamp) VALUES (0, :height, :timestamp) ON CONFLICT(id) DO UPDATE SET height=:height, timestamp=:timestamp WHERE id = 0",
)?; )?;
statement.execute(named_params! { statement.execute(named_params! {
":height": ct.height, ":height": data.block_time.height,
":timestamp": ct.timestamp, ":timestamp": data.block_time.timestamp,
})?; })?;
Ok(self.connection.last_insert_rowid()) Ok(self.connection.last_insert_rowid())
@ -501,18 +501,22 @@ impl SqliteDatabase {
} }
} }
fn select_last_sync_time(&self) -> Result<Option<BlockTime>, Error> { fn select_sync_time(&self) -> Result<Option<SyncTime>, Error> {
let mut statement = self let mut statement = self
.connection .connection
.prepare_cached("SELECT height, timestamp FROM last_sync_time WHERE id = 0")?; .prepare_cached("SELECT height, timestamp FROM sync_time WHERE id = 0")?;
let mut rows = statement.query_map([], |row| { let mut rows = statement.query([])?;
Ok(BlockTime {
if let Some(row) = rows.next()? {
Ok(Some(SyncTime {
block_time: BlockTime {
height: row.get(0)?, height: row.get(0)?,
timestamp: row.get(1)?, timestamp: row.get(1)?,
}) },
})?; }))
} else {
Ok(rows.next().transpose()?) Ok(None)
}
} }
fn select_checksum_by_keychain(&self, keychain: String) -> Result<Option<Vec<u8>>, Error> { fn select_checksum_by_keychain(&self, keychain: String) -> Result<Option<Vec<u8>>, Error> {
@ -592,10 +596,10 @@ impl SqliteDatabase {
Ok(()) Ok(())
} }
fn delete_last_sync_time(&self) -> Result<(), Error> { fn delete_sync_time(&self) -> Result<(), Error> {
let mut statement = self let mut statement = self
.connection .connection
.prepare_cached("DELETE FROM last_sync_time WHERE id = 0")?; .prepare_cached("DELETE FROM sync_time WHERE id = 0")?;
statement.execute([])?; statement.execute([])?;
Ok(()) Ok(())
} }
@ -658,8 +662,8 @@ impl BatchOperations for SqliteDatabase {
Ok(()) Ok(())
} }
fn set_last_sync_time(&mut self, ct: BlockTime) -> Result<(), Error> { fn set_sync_time(&mut self, ct: SyncTime) -> Result<(), Error> {
self.update_last_sync_time(ct)?; self.update_sync_time(ct)?;
Ok(()) Ok(())
} }
@ -749,10 +753,10 @@ impl BatchOperations for SqliteDatabase {
} }
} }
fn del_last_sync_time(&mut self) -> Result<Option<BlockTime>, Error> { fn del_sync_time(&mut self) -> Result<Option<SyncTime>, Error> {
match self.select_last_sync_time()? { match self.select_sync_time()? {
Some(value) => { Some(value) => {
self.delete_last_sync_time()?; self.delete_sync_time()?;
Ok(Some(value)) Ok(Some(value))
} }
@ -870,8 +874,8 @@ impl Database for SqliteDatabase {
Ok(value) Ok(value)
} }
fn get_last_sync_time(&self) -> Result<Option<BlockTime>, Error> { fn get_sync_time(&self) -> Result<Option<SyncTime>, Error> {
self.select_last_sync_time() self.select_sync_time()
} }
fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> { fn increment_last_index(&mut self, keychain: KeychainKind) -> Result<u32, Error> {
@ -1023,7 +1027,7 @@ pub mod test {
} }
#[test] #[test]
fn test_last_sync_time() { fn test_sync_time() {
crate::database::test::test_last_sync_time(get_database()); crate::database::test::test_sync_time(get_database());
} }
} }

View File

@ -57,7 +57,7 @@ use utils::{check_nlocktime, check_nsequence_rbf, After, Older, SecpCtx, DUST_LI
use crate::blockchain::{Blockchain, Progress}; use crate::blockchain::{Blockchain, Progress};
use crate::database::memory::MemoryDatabase; use crate::database::memory::MemoryDatabase;
use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils}; use crate::database::{BatchDatabase, BatchOperations, DatabaseUtils, SyncTime};
use crate::descriptor::derived::AsDerived; use crate::descriptor::derived::AsDerived;
use crate::descriptor::policy::BuildSatisfaction; use crate::descriptor::policy::BuildSatisfaction;
use crate::descriptor::{ use crate::descriptor::{
@ -1554,14 +1554,14 @@ where
} }
} }
let last_sync_time = BlockTime { let sync_time = SyncTime {
block_time: BlockTime {
height: maybe_await!(self.client.get_height())?, height: maybe_await!(self.client.get_height())?,
timestamp: time::get_timestamp(), timestamp: time::get_timestamp(),
},
}; };
debug!("Saving `last_sync_time` = {:?}", last_sync_time); debug!("Saving `sync_time` = {:?}", sync_time);
self.database self.database.borrow_mut().set_sync_time(sync_time)?;
.borrow_mut()
.set_last_sync_time(last_sync_time)?;
Ok(()) Ok(())
} }