Skip to content

Commit

Permalink
Refactor wait_bitcoind
Browse files Browse the repository at this point in the history
Reorganize some code into bitcoincore_ext, in preparation for progress
updates while syncing/scanning is taking place.
  • Loading branch information
shesek committed Nov 15, 2020
1 parent 3f218a1 commit 041f4bb
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 68 deletions.
71 changes: 6 additions & 65 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use std::sync::{mpsc, Arc, RwLock};
use std::{net, thread, time};
use std::{net, thread};

use bitcoincore_rpc::{self as rpc, Client as RpcClient, RpcApi};

use crate::util::{banner, debounce_sender};
use crate::util::{banner, debounce_sender, RpcApiExt};
use crate::{Config, Indexer, Query, Result, WalletWatcher};

#[cfg(feature = "electrum")]
Expand Down Expand Up @@ -222,8 +222,10 @@ fn load_wallet(rpc: &RpcClient, name: &str) -> Result<()> {

// wait for bitcoind to sync and finish rescanning
fn wait_bitcoind(rpc: &RpcClient) -> Result<()> {
let bcinfo = rpc.wait_blockchain_sync()?;
let walletinfo = rpc.wait_wallet_scan()?;

let netinfo = rpc.get_network_info()?;
let mut bcinfo = rpc.get_blockchain_info()?;
info!(
"bwt v{} connected to {} on {}, protocolversion={}, bestblock={}",
crate::BWT_VERSION,
Expand All @@ -232,70 +234,9 @@ fn wait_bitcoind(rpc: &RpcClient) -> Result<()> {
netinfo.protocol_version,
bcinfo.best_block_hash
);

trace!("{:?}", netinfo);
trace!("{:?}", bcinfo);

let dur = time::Duration::from_secs(15);
while (bcinfo.chain != "regtest" && bcinfo.initial_block_download)
|| bcinfo.blocks < bcinfo.headers
{
info!(
"waiting for bitcoind to sync [{}/{} blocks, progress={:.1}%, initialblockdownload={}]",
bcinfo.blocks,
bcinfo.headers,
bcinfo.verification_progress * 100.0,
bcinfo.initial_block_download
);
thread::sleep(dur);
bcinfo = rpc.get_blockchain_info()?;
}
loop {
match check_scanning(rpc)? {
ScanningResult::NotScanning => break,
ScanningResult::Unsupported => {
warn!("Your bitcoin node does not report the `scanning` status in `getwalletinfo`. It is recommended to upgrade to Bitcoin Core v0.19+ to enable this.");
warn!("This is needed for bwt to wait for scanning to finish before starting up. Starting bwt while the node is scanning may lead to unexpected results. Continuing anyway...");
break;
}
ScanningResult::Scanning(scanning) => {
info!(
"waiting for bitcoind to finish scanning [done {:.1}%, running for {:?}]",
scanning.progress * 100f64,
time::Duration::from_secs(scanning.duration)
);
}
};
thread::sleep(dur);
}
trace!("{:?}", walletinfo);

Ok(())
}

fn check_scanning(rpc: &RpcClient) -> Result<ScanningResult> {
let mut wallet_info: serde_json::Value = rpc.call("getwalletinfo", &[])?;

// the "rescanning" field is only supported as of Bitcoin Core v0.19
let rescanning = some_or_ret!(
wallet_info.get_mut("scanning"),
Ok(ScanningResult::Unsupported)
);

Ok(if rescanning.as_bool() == Some(false) {
ScanningResult::NotScanning
} else {
let details = serde_json::from_value(rescanning.take())?;
ScanningResult::Scanning(details)
})
}

enum ScanningResult {
Scanning(ScanningDetails),
NotScanning,
Unsupported,
}
#[derive(Deserialize)]
struct ScanningDetails {
duration: u64,
progress: f64,
}
2 changes: 1 addition & 1 deletion src/util/banner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use chrono::Duration;
use bitcoin::{blockdata::constants, Amount};
use bitcoincore_rpc::RpcApi;

use crate::util::bitcoincore_ext::RpcApiExt;
use crate::util::RpcApiExt;
use crate::{Query, Result};

const DIFFCHANGE_INTERVAL: u64 = constants::DIFFCHANGE_INTERVAL as u64;
Expand Down
51 changes: 49 additions & 2 deletions src/util/bitcoincore_ext.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use serde::{de, Serialize};
use std::fmt::{self, Formatter};
use std::{thread, time};

use bitcoincore_rpc::json::ImportMultiRescanSince;
use bitcoincore_rpc::json::{self, ImportMultiRescanSince, ScanningDetails};
use bitcoincore_rpc::{Client, Result as RpcResult, RpcApi};

const WAIT_INTERVAL: time::Duration = time::Duration::from_secs(10);

// Extensions for rust-bitcoincore-rpc

pub trait RpcApiExt: RpcApi {
// Only supports the fields we're interested in (so not currently upstremable)

fn get_block_stats(&self, blockhash: &bitcoin::BlockHash) -> RpcResult<GetBlockStatsResult> {
let fields = (
"height",
Expand All @@ -23,9 +25,54 @@ pub trait RpcApiExt: RpcApi {
self.call("getblockstats", &[json!(blockhash), json!(fields)])
}

// Only supports the fields we're interested in (so not currently upstremable)
fn get_mempool_info(&self) -> RpcResult<GetMempoolInfoResult> {
self.call("getmempoolinfo", &[])
}

fn wait_blockchain_sync(&self) -> RpcResult<json::GetBlockchainInfoResult> {
Ok(loop {
let info = self.get_blockchain_info()?;

if info.blocks == info.headers
&& (!info.initial_block_download || info.chain == "regtest")
{
break info;
}

info!(target: "bwt",
"waiting for bitcoind to sync [{}/{} blocks, progress={:.1}%]",
info.blocks, info.headers, info.verification_progress * 100.0
);

thread::sleep(WAIT_INTERVAL);
})
}

fn wait_wallet_scan(&self) -> RpcResult<json::GetWalletInfoResult> {
Ok(loop {
let info = self.get_wallet_info()?;
match info.scanning {
None => {
warn!("Your bitcoin node does not report the `scanning` status in `getwalletinfo`. It is recommended to upgrade to Bitcoin Core v0.19+ to enable this.");
warn!("This is needed for bwt to wait for scanning to finish before starting up. Starting bwt while the node is scanning may lead to unexpected results. Continuing anyway...");
break info;
}
Some(ScanningDetails::NotScanning(_)) => break info,
Some(ScanningDetails::Scanning { progress, duration }) => {
let duration = duration as u64;
let progress = progress as f64;
let eta = (duration as f64 / progress) as u64 - duration;

info!(target: "bwt",
"waiting for bitcoind to finish scanning [done {:.1}%, running for {}m, eta {}m]",
progress * 100.0, duration / 60, eta / 60
);
}
};
thread::sleep(WAIT_INTERVAL);
})
}
}

impl RpcApiExt for Client {}
Expand Down
2 changes: 2 additions & 0 deletions src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub mod bitcoincore_ext;
pub mod descriptor;
pub mod xpub;

pub use bitcoincore_ext::RpcApiExt;

lazy_static! {
pub static ref EC: Secp256k1<secp256k1::VerifyOnly> = Secp256k1::verification_only();
}
Expand Down

0 comments on commit 041f4bb

Please sign in to comment.