From ed396307d8b715b8c1377e35aa9cf34992d83851 Mon Sep 17 00:00:00 2001 From: edouardparis Date: Tue, 7 Jan 2025 16:10:14 +0100 Subject: [PATCH] fix fetching of coins txids before migration --- lianad/src/database/sqlite/mod.rs | 139 ++++++++++++++++++++++++++++++ lianad/src/lib.rs | 9 +- 2 files changed, 141 insertions(+), 7 deletions(-) diff --git a/lianad/src/database/sqlite/mod.rs b/lianad/src/database/sqlite/mod.rs index 1eed24f26..93e49255d 100644 --- a/lianad/src/database/sqlite/mod.rs +++ b/lianad/src/database/sqlite/mod.rs @@ -726,6 +726,28 @@ impl SqliteConn { .expect("Db must not fail") } + pub fn db_list_all_txids(&mut self) -> Vec { + db_query( + &mut self.conn, + " + SELECT txid AS id + FROM coins + UNION + SELECT spend_txid AS id + FROM coins + WHERE spend_txid IS NOT NULL + ", + rusqlite::params![], + |row| { + let txid: Vec = row.get(0)?; + let txid: bitcoin::Txid = + encode::deserialize(&txid).expect("We only store valid txids"); + Ok(txid) + }, + ) + .expect("Db must not fail") + } + /// Store transactions in database, ignoring any that already exist. pub fn new_txs(&mut self, txs: &[bitcoin::Transaction]) { db_exec(&mut self.conn, |db_tx| { @@ -2371,6 +2393,123 @@ CREATE TABLE labels ( fs::remove_dir_all(tmp_dir).unwrap(); } + #[test] + fn sqlite_list_all_txids() { + let (tmp_dir, _, _, db) = dummy_db(); + + { + let mut conn = db.connection().unwrap(); + + let txs: Vec<_> = (0..7) + .map(|i| bitcoin::Transaction { + version: bitcoin::transaction::Version::TWO, + lock_time: bitcoin::absolute::LockTime::from_height(i).unwrap(), + input: vec![bitcoin::TxIn::default()], // a single input + output: vec![bitcoin::TxOut::minimal_non_dust(ScriptBuf::default())], // a single output, + }) + .collect(); + conn.new_txs(&txs); + + let coins = [ + Coin { + outpoint: bitcoin::OutPoint::new(txs.first().unwrap().txid(), 1), + is_immature: false, + block_info: None, + amount: bitcoin::Amount::from_sat(98765), + derivation_index: bip32::ChildNumber::from_normal_idx(10).unwrap(), + is_change: false, + spend_txid: None, + spend_block: None, + is_from_self: false, + }, + Coin { + outpoint: bitcoin::OutPoint::new(txs.get(1).unwrap().txid(), 2), + is_immature: false, + block_info: Some(BlockInfo { + height: 101_095, + time: 1_121_000, + }), + amount: bitcoin::Amount::from_sat(98765), + derivation_index: bip32::ChildNumber::from_normal_idx(100).unwrap(), + is_change: false, + spend_txid: None, + spend_block: None, + is_from_self: false, + }, + Coin { + outpoint: bitcoin::OutPoint::new(txs.get(2).unwrap().txid(), 3), + is_immature: false, + block_info: Some(BlockInfo { + height: 101_099, + time: 1_122_000, + }), + amount: bitcoin::Amount::from_sat(98765), + derivation_index: bip32::ChildNumber::from_normal_idx(1000).unwrap(), + is_change: false, + spend_txid: Some(txs.get(3).unwrap().txid()), + spend_block: Some(BlockInfo { + height: 101_199, + time: 1_123_000, + }), + is_from_self: false, + }, + Coin { + outpoint: bitcoin::OutPoint::new(txs.get(4).unwrap().txid(), 4), + is_immature: true, + block_info: Some(BlockInfo { + height: 101_100, + time: 1_124_000, + }), + amount: bitcoin::Amount::from_sat(98765), + derivation_index: bip32::ChildNumber::from_normal_idx(10000).unwrap(), + is_change: false, + spend_txid: None, + spend_block: None, + is_from_self: false, + }, + Coin { + outpoint: bitcoin::OutPoint::new(txs.get(5).unwrap().txid(), 5), + is_immature: false, + block_info: Some(BlockInfo { + height: 101_102, + time: 1_125_000, + }), + amount: bitcoin::Amount::from_sat(98765), + derivation_index: bip32::ChildNumber::from_normal_idx(100000).unwrap(), + is_change: false, + spend_txid: Some(txs.get(6).unwrap().txid()), + spend_block: Some(BlockInfo { + height: 101_105, + time: 1_126_000, + }), + is_from_self: false, + }, + ]; + conn.new_unspent_coins(&coins); + conn.confirm_coins( + &coins + .iter() + .filter_map(|c| c.block_info.map(|b| (c.outpoint, b.height, b.time))) + .collect::>(), + ); + conn.confirm_spend( + &coins + .iter() + .filter_map(|c| { + c.spend_block + .as_ref() + .map(|b| (c.outpoint, c.spend_txid.unwrap(), b.height, b.time)) + }) + .collect::>(), + ); + + let db_txids = conn.db_list_all_txids(); + assert_eq!(db_txids.len(), txs.len()); + } + + fs::remove_dir_all(tmp_dir).unwrap(); + } + #[test] fn sqlite_list_saved_txids() { let (tmp_dir, _, _, db) = dummy_db(); diff --git a/lianad/src/lib.rs b/lianad/src/lib.rs index 3c540d7fc..4fc32e947 100644 --- a/lianad/src/lib.rs +++ b/lianad/src/lib.rs @@ -26,7 +26,7 @@ use crate::{ }; use std::{ - collections, error, fmt, fs, io, path, + error, fmt, fs, io, path, sync::{self, mpsc}, thread, }; @@ -217,12 +217,7 @@ fn setup_sqlite( let bit = bitcoind.as_ref().ok_or(StartupError::DbMigrateBitcoinTxs( "a connection to a Bitcoin backend is required", ))?; - let coins = conn.db_coins(&[]); - let coins_txids = coins - .iter() - .map(|c| c.outpoint.txid) - .chain(coins.iter().filter_map(|c| c.spend_txid)) - .collect::>(); + let coins_txids = conn.db_list_all_txids(); coins_txids .into_iter() .map(|txid| bit.get_transaction(&txid).map(|res| res.tx))