Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport: fix fetching of coins txids before migration #1523

Merged
merged 1 commit into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions lianad/src/database/sqlite/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down Expand Up @@ -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();
Expand Down
9 changes: 2 additions & 7 deletions lianad/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{
};

use std::{
collections, error, fmt, fs, io, path,
error, fmt, fs, io, path,
sync::{self, mpsc},
thread,
};
Expand Down Expand Up @@ -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))
Expand Down
Loading