From 54c702e73c0449c30ff5b008ff993835b47d9e4c Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 12 Jan 2024 16:19:05 +1000 Subject: [PATCH] fix(miner): Avoid some duplicate block errors (#8150) * Update to the latest equihash solver code * Wait for a new template after mining a block * Remove an unused import * Another solver update --- Cargo.lock | 2 +- zebrad/src/components/miner.rs | 54 ++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ad6821a9..63d018c0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "equihash" version = "0.2.0" -source = "git+https://github.com/ZcashFoundation/librustzcash.git?branch=equihash-solver-tromp#251098313920466958fcd05b25e151d4edd3a1b1" +source = "git+https://github.com/ZcashFoundation/librustzcash.git?branch=equihash-solver-tromp#aff6fac6cb9c7390565313733f0ba7d679166504" dependencies = [ "blake2b_simd", "byteorder", diff --git a/zebrad/src/components/miner.rs b/zebrad/src/components/miner.rs index b337c7669..0774d9853 100644 --- a/zebrad/src/components/miner.rs +++ b/zebrad/src/components/miner.rs @@ -30,7 +30,6 @@ use zebra_rpc::{ config::mining::Config, methods::{ get_block_template_rpcs::{ - constants::GET_BLOCK_TEMPLATE_MEMPOOL_LONG_POLL_INTERVAL, get_block_template::{ self, proposal::TimeSource, proposal_block_from_template, GetBlockTemplateCapability::*, GetBlockTemplateRequestMode::*, @@ -45,6 +44,15 @@ use zebra_state::WatchReceiver; /// The amount of time we wait between block template retries. pub const BLOCK_TEMPLATE_WAIT_TIME: Duration = Duration::from_secs(20); +/// A rate-limit for block template refreshes. +pub const BLOCK_TEMPLATE_REFRESH_LIMIT: Duration = Duration::from_secs(2); + +/// How long we wait after mining a block, before expecting a new template. +/// +/// This should be slightly longer than `BLOCK_TEMPLATE_REFRESH_LIMIT` to allow for template +/// generation. +pub const BLOCK_MINING_WAIT_TIME: Duration = Duration::from_secs(3); + /// Initialize the miner based on its config, and spawn a task for it. /// /// This method is CPU and memory-intensive. It uses 144 MB of RAM and one CPU core per configured @@ -295,10 +303,7 @@ where // If the blockchain is changing rapidly, limit how often we'll update the template. // But if we're shutting down, do that immediately. if !template_sender.is_closed() && !is_shutting_down() { - sleep(Duration::from_secs( - GET_BLOCK_TEMPLATE_MEMPOOL_LONG_POLL_INTERVAL, - )) - .await; + sleep(BLOCK_TEMPLATE_REFRESH_LIMIT).await; } } @@ -426,7 +431,7 @@ where // If the blockchain is changing rapidly, limit how often we'll update the template. // But if we're shutting down, do that immediately. if template_receiver.has_changed().is_ok() && !is_shutting_down() { - sleep(Duration::from_secs(1)).await; + sleep(BLOCK_TEMPLATE_REFRESH_LIMIT).await; } continue; @@ -437,19 +442,23 @@ where // TODO: if there is a new template (`cancel_fn().is_err()`), and // GetBlockTemplate.submit_old is false, return immediately, and skip submitting the // blocks. + let mut any_success = false; for block in blocks { let data = block .zcash_serialize_to_vec() .expect("serializing to Vec never fails"); match rpc.submit_block(HexData(data), None).await { - Ok(success) => info!( - ?height, - hash = ?block.hash(), - ?solver_id, - ?success, - "successfully mined a new block", - ), + Ok(success) => { + info!( + ?height, + hash = ?block.hash(), + ?solver_id, + ?success, + "successfully mined a new block", + ); + any_success = true; + } Err(error) => info!( ?height, hash = ?block.hash(), @@ -459,6 +468,25 @@ where ), } } + + // Start re-mining quickly after a failed solution. + // If there's a new template, we'll use it, otherwise the existing one is ok. + if !any_success { + // If the blockchain is changing rapidly, limit how often we'll update the template. + // But if we're shutting down, do that immediately. + if template_receiver.has_changed().is_ok() && !is_shutting_down() { + sleep(BLOCK_TEMPLATE_REFRESH_LIMIT).await; + } + continue; + } + + // Wait for the new block to verify, and the RPC task to pick up a new template. + // But don't wait too long, we could have mined on a fork. + tokio::select! { + shutdown_result = template_receiver.changed() => shutdown_result?, + _ = sleep(BLOCK_MINING_WAIT_TIME) => {} + + } } Ok(())