//! Test submitblock RPC method on Regtest.
//!
//! This test will get block templates via the `getblocktemplate` RPC method and submit them as new blocks
//! via the `submitblock` RPC method on Regtest.
use std::{net::SocketAddr, sync::Arc, time::Duration};
use color_eyre::eyre::{eyre, Context, Result};
use tower::BoxError;
use tracing::*;
use zebra_chain::{
block::{Block, Height},
parameters::{testnet::REGTEST_NU5_ACTIVATION_HEIGHT, Network, NetworkUpgrade},
primitives::byte_array::increment_big_endian,
serialization::{ZcashDeserializeInto, ZcashSerialize},
};
use zebra_node_services::rpc_client::RpcRequestClient;
use zebra_rpc::{
constants::MISSING_BLOCK_ERROR_CODE,
methods::{
get_block_template_rpcs::{
get_block_template::{
proposal::TimeSource, proposal_block_from_template, GetBlockTemplate,
},
types::submit_block,
},
hex_data::HexData,
},
server::OPENED_RPC_ENDPOINT_MSG,
};
use zebra_test::args;
use crate::common::{
config::{os_assigned_rpc_port_config, read_listen_addr_from_logs, testdir},
launch::ZebradTestDirExt,
};
/// Number of blocks that should be submitted before the test is considered successful.
const NUM_BLOCKS_TO_SUBMIT: usize = 200;
pub(crate) async fn submit_blocks_test() -> Result<()> {
let _init_guard = zebra_test::init();
info!("starting regtest submit_blocks test");
let network = Network::new_regtest(None, None);
let mut config = os_assigned_rpc_port_config(false, &network)?;
config.mempool.debug_enable_at_height = Some(0);
let mut zebrad = testdir()?
.with_config(&mut config)?
.spawn_child(args!["start"])?;
let rpc_address = read_listen_addr_from_logs(&mut zebrad, OPENED_RPC_ENDPOINT_MSG)?;
info!("waiting for zebrad to start");
tokio::time::sleep(Duration::from_secs(30)).await;
info!("attempting to submit blocks");
submit_blocks(network, rpc_address).await?;
zebrad.kill(false)?;
let output = zebrad.wait_with_output()?;
let output = output.assert_failure()?;
// [Note on port conflict](#Note on port conflict)
output
.assert_was_killed()
.wrap_err("Possible port conflict. Are there other acceptance tests running?")
}
/// Get block templates and submit blocks
async fn submit_blocks(network: Network, rpc_address: SocketAddr) -> Result<()> {
let client = RpcRequestClient::new(rpc_address);
for _ in 1..=NUM_BLOCKS_TO_SUBMIT {
let (mut block, height) = client
.block_from_template(Height(REGTEST_NU5_ACTIVATION_HEIGHT))
.await?;
while !network.disable_pow()
&& zebra_consensus::difficulty_is_valid(&block.header, &network, &height, &block.hash())
.is_err()
{
increment_big_endian(Arc::make_mut(&mut block.header).nonce.as_mut());
}
if height.0 % 40 == 0 {
info!(?block, ?height, "submitting block");
}
client.submit_block(block).await?;
}
Ok(())
}
pub trait MiningRpcMethods {
async fn block_from_template(&self, nu5_activation_height: Height) -> Result<(Block, Height)>;
async fn submit_block(&self, block: Block) -> Result<()>;
async fn submit_block_from_template(&self) -> Result<(Block, Height)>;
async fn get_block(&self, height: i32) -> Result