use super::*;
static MINER: Lazy<RwLock<Miner>> = Lazy::new(|| RwLock::new(Miner { no_mine_count: 0 }));
#[derive(Clone, Debug)]
pub(crate) struct Miner {
no_mine_count: u32,
}
pub(crate) fn _bitcoin_cli() -> [String; 9] {
let compose_file = ["tests", "docker-compose.yml"].join(&MAIN_SEPARATOR.to_string());
[
s!("-f"),
compose_file,
s!("exec"),
s!("-T"),
s!("-u"),
s!("blits"),
s!("bitcoind"),
s!("bitcoin-cli"),
s!("-regtest"),
]
}
impl Miner {
fn mine(&self) -> bool {
if self.no_mine_count > 0 {
return false;
}
let status = Command::new("docker")
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.arg("compose")
.args(_bitcoin_cli())
.arg("-rpcwallet=miner")
.arg("-generate")
.arg("1")
.status()
.expect("failed to mine");
assert!(status.success());
wait_electrs_sync();
true
}
fn stop_mining(&mut self) {
self.no_mine_count += 1;
}
fn resume_mining(&mut self) {
if self.no_mine_count > 0 {
self.no_mine_count -= 1;
}
}
}
pub(crate) fn mine(resume: bool) {
let t_0 = OffsetDateTime::now_utc();
if resume {
resume_mining();
}
let mut last_result = false;
while !last_result {
let miner = MINER.read();
last_result = miner.as_ref().expect("MINER has been initialized").mine();
drop(miner);
if (OffsetDateTime::now_utc() - t_0).as_seconds_f32() > 120.0 {
println!("forcibly breaking mining wait");
resume_mining();
}
if !last_result {
std::thread::sleep(std::time::Duration::from_millis(500));
}
}
}
pub(crate) fn stop_mining() {
MINER
.write()
.expect("MINER has been initialized")
.stop_mining()
}
pub(crate) fn resume_mining() {
MINER
.write()
.expect("MINER has been initialized")
.resume_mining()
}
pub(crate) fn wait_electrs_sync() {
let t_0 = OffsetDateTime::now_utc();
let output = Command::new("docker")
.stdin(Stdio::null())
.stderr(Stdio::null())
.arg("compose")
.args(_bitcoin_cli())
.arg("getblockcount")
.output()
.expect("failed to call getblockcount");
assert!(output.status.success());
let blockcount_str =
std::str::from_utf8(&output.stdout).expect("could not parse blockcount output");
let blockcount = blockcount_str
.trim()
.parse::<u32>()
.expect("could not parte blockcount");
loop {
std::thread::sleep(std::time::Duration::from_millis(100));
let mut all_synced = true;
for electrum_url in [ELECTRUM_URL, ELECTRUM_2_URL] {
let electrum =
electrum_client::Client::new(electrum_url).expect("cannot get electrum client");
if electrum.block_header(blockcount as usize).is_err() {
all_synced = false;
}
}
if all_synced {
break;
};
if (OffsetDateTime::now_utc() - t_0).as_seconds_f32() > 10.0 {
panic!("electrs not syncing with bitcoind");
}
}
}