poller: sync wallet before checking updates
This includes changes from darosior's comment in https://github.com/wizardsardine/liana/pull/1222#issuecomment-2324894986.
This commit is contained in:
parent
89e004d4fd
commit
69259c1236
@ -4,7 +4,7 @@ use crate::{
|
||||
descriptors,
|
||||
};
|
||||
|
||||
use std::{collections::HashSet, sync, time};
|
||||
use std::{collections::HashSet, sync, thread, time};
|
||||
|
||||
use miniscript::bitcoin::{self, secp256k1};
|
||||
|
||||
@ -239,20 +239,44 @@ fn new_tip(bit: &impl BitcoinInterface, current_tip: &BlockChainTip) -> TipUpdat
|
||||
|
||||
fn updates(
|
||||
db_conn: &mut Box<dyn DatabaseConnection>,
|
||||
bit: &impl BitcoinInterface,
|
||||
bit: &mut impl BitcoinInterface,
|
||||
descs: &[descriptors::SinglePathLianaDesc],
|
||||
secp: &secp256k1::Secp256k1<secp256k1::VerifyOnly>,
|
||||
) {
|
||||
// Check if there was a new block before updating ourselves.
|
||||
// Check if there was a new block before we update our state.
|
||||
//
|
||||
// Some backends (such as Electrum) need to perform an explicit sync to provide updated data
|
||||
// about the Bitcoin network. For those the common ancestor is immediately returned in case
|
||||
// there was a reorg. For other backends (such as bitcoind) this function always return
|
||||
// `Ok(None)`. We leverage this to query the next tip and poll for reorgs only in this case.
|
||||
// FIXME: harmonize the Bitcoin backend interface, this intricacy is due to the introduction of
|
||||
// an Electrum backend with the bitcoind-specific backend interface.
|
||||
let current_tip = db_conn.chain_tip().expect("Always set at first startup");
|
||||
let latest_tip = match new_tip(bit, ¤t_tip) {
|
||||
TipUpdate::Same => current_tip,
|
||||
TipUpdate::Progress(new_tip) => new_tip,
|
||||
TipUpdate::Reorged(new_tip) => {
|
||||
let (receive_index, change_index) = (db_conn.receive_index(), db_conn.change_index());
|
||||
let latest_tip = match bit.sync_wallet(receive_index, change_index) {
|
||||
Ok(None) => {
|
||||
match new_tip(bit, ¤t_tip) {
|
||||
TipUpdate::Same => current_tip,
|
||||
TipUpdate::Progress(new_tip) => new_tip,
|
||||
TipUpdate::Reorged(new_tip) => {
|
||||
// The block chain was reorganized. Rollback our state down to the common ancestor
|
||||
// between our former chain and the new one, then restart fresh.
|
||||
db_conn.rollback_tip(&new_tip);
|
||||
log::info!("Tip was rolled back to '{}'.", new_tip);
|
||||
return updates(db_conn, bit, descs, secp);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Some(reorg_common_ancestor)) => {
|
||||
// The block chain was reorganized. Rollback our state down to the common ancestor
|
||||
// between our former chain and the new one, then restart fresh.
|
||||
db_conn.rollback_tip(&new_tip);
|
||||
log::info!("Tip was rolled back to '{}'.", new_tip);
|
||||
db_conn.rollback_tip(&reorg_common_ancestor);
|
||||
log::info!("Tip was rolled back to '{}'.", &reorg_common_ancestor);
|
||||
return updates(db_conn, bit, descs, secp);
|
||||
}
|
||||
Err(e) => {
|
||||
log::error!("Error syncing wallet: '{}'.", e);
|
||||
thread::sleep(time::Duration::from_secs(2));
|
||||
return updates(db_conn, bit, descs, secp);
|
||||
}
|
||||
};
|
||||
@ -289,7 +313,7 @@ fn updates(
|
||||
// Check if there is any rescan of the backend ongoing or one that just finished.
|
||||
fn rescan_check(
|
||||
db_conn: &mut Box<dyn DatabaseConnection>,
|
||||
bit: &impl BitcoinInterface,
|
||||
bit: &mut impl BitcoinInterface,
|
||||
descs: &[descriptors::SinglePathLianaDesc],
|
||||
secp: &secp256k1::Secp256k1<secp256k1::VerifyOnly>,
|
||||
) {
|
||||
@ -356,7 +380,7 @@ pub fn sync_poll_interval() -> time::Duration {
|
||||
|
||||
/// Update our state from the Bitcoin backend.
|
||||
pub fn poll(
|
||||
bit: &sync::Arc<sync::Mutex<dyn BitcoinInterface>>,
|
||||
bit: &mut sync::Arc<sync::Mutex<dyn BitcoinInterface>>,
|
||||
db: &sync::Arc<sync::Mutex<dyn DatabaseInterface>>,
|
||||
secp: &secp256k1::Secp256k1<secp256k1::VerifyOnly>,
|
||||
descs: &[descriptors::SinglePathLianaDesc],
|
||||
|
||||
@ -56,7 +56,7 @@ impl Poller {
|
||||
/// Typically this would run for the whole duration of the program in a thread, and the main
|
||||
/// thread would set the `shutdown` atomic to `true` when shutting down.
|
||||
pub fn poll_forever(
|
||||
&self,
|
||||
&mut self,
|
||||
poll_interval: time::Duration,
|
||||
receiver: mpsc::Receiver<PollerMessage>,
|
||||
) {
|
||||
@ -91,7 +91,7 @@ impl Poller {
|
||||
// We've been asked to poll, don't wait any further and signal completion to
|
||||
// the caller.
|
||||
last_poll = Some(time::Instant::now());
|
||||
looper::poll(&self.bit, &self.db, &self.secp, &self.descs);
|
||||
looper::poll(&mut self.bit, &self.db, &self.secp, &self.descs);
|
||||
if let Err(e) = sender.send(()) {
|
||||
log::error!("Error sending immediate poll completion signal: {}.", e);
|
||||
}
|
||||
@ -122,7 +122,7 @@ impl Poller {
|
||||
}
|
||||
}
|
||||
|
||||
looper::poll(&self.bit, &self.db, &self.secp, &self.descs);
|
||||
looper::poll(&mut self.bit, &self.db, &self.secp, &self.descs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,7 +426,7 @@ impl DaemonHandle {
|
||||
|
||||
// Start the poller thread. Keep the thread handle to be able to check if it crashed. Store
|
||||
// an atomic to be able to stop it.
|
||||
let bitcoin_poller =
|
||||
let mut bitcoin_poller =
|
||||
poller::Poller::new(bit.clone(), db.clone(), config.main_descriptor.clone());
|
||||
let (poller_sender, poller_receiver) = mpsc::sync_channel(0);
|
||||
let poller_handle = thread::Builder::new()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user