fix fetching of coins txids before migration

This commit is contained in:
edouardparis 2025-01-07 16:10:14 +01:00
parent 451ba88445
commit c5b1f73660
2 changed files with 141 additions and 7 deletions

View File

@ -726,6 +726,28 @@ impl SqliteConn {
.expect("Db must not fail")
}
pub fn db_list_all_txids(&mut self) -> Vec<bitcoin::Txid> {
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<u8> = 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::<Vec<_>>(),
);
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::<Vec<_>>(),
);
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();

View File

@ -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::<collections::HashSet<_>>();
let coins_txids = conn.db_list_all_txids();
coins_txids
.into_iter()
.map(|txid| bit.get_transaction(&txid).map(|res| res.tx))