db: make it possible to mark coins back as unspent
This commit is contained in:
parent
c30bc8cd18
commit
f78e831c39
@ -109,6 +109,9 @@ pub trait DatabaseConnection {
|
||||
/// Mark a set of coins as being spent by a specified txid of a pending transaction.
|
||||
fn spend_coins(&mut self, outpoints: &[(bitcoin::OutPoint, bitcoin::Txid)]);
|
||||
|
||||
/// Mark a set of coins as not being spent anymore.
|
||||
fn unspend_coins(&mut self, outpoints: &[bitcoin::OutPoint]);
|
||||
|
||||
/// Mark a set of coins as spent by a specified txid at a specified block time.
|
||||
fn confirm_spend(&mut self, outpoints: &[(bitcoin::OutPoint, bitcoin::Txid, i32, u32)]);
|
||||
|
||||
@ -232,6 +235,10 @@ impl DatabaseConnection for SqliteConn {
|
||||
self.spend_coins(outpoints)
|
||||
}
|
||||
|
||||
fn unspend_coins(&mut self, outpoints: &[bitcoin::OutPoint]) {
|
||||
self.unspend_coins(outpoints)
|
||||
}
|
||||
|
||||
fn confirm_spend<'a>(&mut self, outpoints: &[(bitcoin::OutPoint, bitcoin::Txid, i32, u32)]) {
|
||||
self.confirm_spend(outpoints)
|
||||
}
|
||||
|
||||
@ -509,6 +509,27 @@ impl SqliteConn {
|
||||
.expect("Database must be available")
|
||||
}
|
||||
|
||||
/// Mark a set of coins as not being spent.
|
||||
pub fn unspend_coins<'a>(
|
||||
&mut self,
|
||||
outpoints: impl IntoIterator<Item = &'a bitcoin::OutPoint>,
|
||||
) {
|
||||
db_exec(&mut self.conn, |db_tx| {
|
||||
for outpoint in outpoints {
|
||||
db_tx.execute(
|
||||
"UPDATE coins SET spend_txid = NULL, spend_block_height = NULL, spend_block_time = NULL WHERE txid = ?1 AND vout = ?2",
|
||||
rusqlite::params![
|
||||
outpoint.txid[..].to_vec(),
|
||||
outpoint.vout,
|
||||
],
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.expect("Database must be available")
|
||||
}
|
||||
|
||||
/// Mark the Spend transaction of a given set of coins as being confirmed at a given
|
||||
/// block.
|
||||
pub fn confirm_spend<'a>(
|
||||
@ -1350,18 +1371,27 @@ CREATE TABLE spend_transactions (
|
||||
coin_a.outpoint,
|
||||
bitcoin::Txid::from_slice(&[0; 32][..]).unwrap(),
|
||||
)]);
|
||||
let coins_map: HashMap<bitcoin::OutPoint, DbCoin> = conn
|
||||
.coins(&[], &[])
|
||||
let coin = conn
|
||||
.coins(&[], &[coin_a.outpoint])
|
||||
.into_iter()
|
||||
.map(|c| (c.outpoint, c))
|
||||
.collect();
|
||||
assert!(coins_map
|
||||
.get(&coin_a.outpoint)
|
||||
.unwrap()
|
||||
.spend_txid
|
||||
.is_some());
|
||||
.next()
|
||||
.unwrap();
|
||||
assert!(coin.spend_txid.is_some());
|
||||
|
||||
// We will see it as 'spending'
|
||||
// We can unspend it, if the spend transaction gets double spent.
|
||||
conn.unspend_coins(&[coin_a.outpoint]);
|
||||
let coin = conn
|
||||
.coins(&[], &[coin_a.outpoint])
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
assert!(coin.spend_txid.is_none());
|
||||
|
||||
// Spend it back. We will see it as 'spending'
|
||||
conn.spend_coins(&[(
|
||||
coin_a.outpoint,
|
||||
bitcoin::Txid::from_slice(&[0; 32][..]).unwrap(),
|
||||
)]);
|
||||
let outpoints: HashSet<bitcoin::OutPoint> = conn
|
||||
.list_spending_coins()
|
||||
.into_iter()
|
||||
@ -1406,6 +1436,16 @@ CREATE TABLE spend_transactions (
|
||||
assert_eq!(coin.spend_block.as_ref().unwrap().time, time);
|
||||
assert_eq!(coin.spend_block.unwrap().height, height);
|
||||
|
||||
// If we unspend it all spend info will be wiped.
|
||||
conn.unspend_coins(&[coin_a.outpoint]);
|
||||
let coin = conn
|
||||
.coins(&[], &[coin_a.outpoint])
|
||||
.into_iter()
|
||||
.next()
|
||||
.unwrap();
|
||||
assert!(coin.spend_txid.is_none());
|
||||
assert!(coin.spend_block.is_none());
|
||||
|
||||
// Add an immature coin. As all coins it's first registered as unconfirmed (even though
|
||||
// it's not).
|
||||
let coin_imma = Coin {
|
||||
|
||||
@ -278,6 +278,16 @@ impl DatabaseConnection for DummyDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
fn unspend_coins<'a>(&mut self, outpoints: &[bitcoin::OutPoint]) {
|
||||
for op in outpoints {
|
||||
let mut db = self.db.write().unwrap();
|
||||
let spent = &mut db.coins.get_mut(op).unwrap();
|
||||
assert!(spent.spend_txid.is_some());
|
||||
spent.spend_txid = None;
|
||||
spent.spend_block = None;
|
||||
}
|
||||
}
|
||||
|
||||
fn confirm_spend<'a>(&mut self, outpoints: &[(bitcoin::OutPoint, bitcoin::Txid, i32, u32)]) {
|
||||
for (op, spend_txid, height, time) in outpoints {
|
||||
let mut db = self.db.write().unwrap();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user