From ed156543c95db2e6e1fd4712ec7dcb0dfc025c41 Mon Sep 17 00:00:00 2001 From: Antoine Poinsot Date: Thu, 2 Feb 2023 16:35:18 +0100 Subject: [PATCH] database: permit to remove coins from DB --- src/database/mod.rs | 7 +++++++ src/database/sqlite/mod.rs | 22 ++++++++++++++++++++++ src/testutils.rs | 6 ++++++ 3 files changed, 35 insertions(+) diff --git a/src/database/mod.rs b/src/database/mod.rs index 6662a365..04953c36 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -89,6 +89,9 @@ pub trait DatabaseConnection { /// Store new UTxOs. Coins must not already be in database. fn new_unspent_coins(&mut self, coins: &[Coin]); + /// Remove some UTxOs from the database. + fn remove_coins(&mut self, coins: &[bitcoin::OutPoint]); + /// Mark a set of coins as being confirmed at a specified height and block time. fn confirm_coins(&mut self, outpoints: &[(bitcoin::OutPoint, i32, u32)]); @@ -196,6 +199,10 @@ impl DatabaseConnection for SqliteConn { self.new_unspent_coins(coins) } + fn remove_coins(&mut self, outpoints: &[bitcoin::OutPoint]) { + self.remove_coins(outpoints) + } + fn confirm_coins<'a>(&mut self, outpoints: &[(bitcoin::OutPoint, i32, u32)]) { self.confirm_coins(outpoints) } diff --git a/src/database/sqlite/mod.rs b/src/database/sqlite/mod.rs index d12064b8..17663a13 100644 --- a/src/database/sqlite/mod.rs +++ b/src/database/sqlite/mod.rs @@ -363,6 +363,21 @@ impl SqliteConn { .expect("Database must be available") } + /// Remove a set of coins from the database. + pub fn remove_coins(&mut self, outpoints: &[bitcoin::OutPoint]) { + db_exec(&mut self.conn, |db_tx| { + for outpoint in outpoints { + db_tx.execute( + "DELETE FROM coins WHERE txid = ?1 AND vout = ?2", + rusqlite::params![outpoint.txid.to_vec(), outpoint.vout,], + )?; + } + + Ok(()) + }) + .expect("Database must be available") + } + /// Mark a set of coins as confirmed. pub fn confirm_coins<'a>( &mut self, @@ -705,6 +720,13 @@ mod tests { conn.new_unspent_coins(&[coin_a]); assert_eq!(conn.coins(CoinType::All)[0].outpoint, coin_a.outpoint); + // We can also remove it. Say the unconfirmed tx that created it got replaced. + conn.remove_coins(&[coin_a.outpoint]); + assert!(conn.coins(CoinType::All).is_empty()); + + // Add it back for the rest of the test. + conn.new_unspent_coins(&[coin_a]); + // We can query it by its outpoint let coins = conn.db_coins(&[coin_a.outpoint]); assert_eq!(coins.len(), 1); diff --git a/src/testutils.rs b/src/testutils.rs index b07cdda7..cf063e15 100644 --- a/src/testutils.rs +++ b/src/testutils.rs @@ -220,6 +220,12 @@ impl DatabaseConnection for DummyDatabase { } } + fn remove_coins(&mut self, outpoints: &[bitcoin::OutPoint]) { + for op in outpoints { + self.db.write().unwrap().coins.remove(op); + } + } + fn confirm_coins<'a>(&mut self, outpoints: &[(bitcoin::OutPoint, i32, u32)]) { for (op, height, time) in outpoints { let mut db = self.db.write().unwrap();