From 14fdd3002bab331539daa862ceb4f2c0e78eebad Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 1 Feb 2023 09:02:22 +1000 Subject: [PATCH] change(ci): Run block proposal tests in CI (#5963) * Revert "Temporarily fix the code for a disabled test" This reverts commit d915624417cc946e53aac76449e0b5b719e03d2a. * Check every valid time source in the proposal tests * Activate block proposal tests in CI * Repeats block proposal test a few times at an interval to sample different mempool contents * Increase the number of templates tested to 10 Co-authored-by: Arya --------- Co-authored-by: arya2 --- .../types/get_block_template/proposal.rs | 13 ++++- .../bin/block-template-to-proposal/main.rs | 2 +- .../get_block_template.rs | 56 ++++++++++--------- 3 files changed, 40 insertions(+), 31 deletions(-) diff --git a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template/proposal.rs b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template/proposal.rs index 9f4e1a1c..bbbca523 100644 --- a/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template/proposal.rs +++ b/zebra-rpc/src/methods/get_block_template_rpcs/types/get_block_template/proposal.rs @@ -131,6 +131,13 @@ impl TimeSource { Raw(_) | RawNow => false, } } + + /// Returns an iterator of time sources that are valid according to the consensus rules. + pub fn valid_sources() -> impl IntoIterator { + use TimeSource::*; + + [CurTime, MinTime, MaxTime, ClampedNow].into_iter() + } } impl FromStr for TimeSource { @@ -160,7 +167,7 @@ impl FromStr for TimeSource { /// /// If `time_source` is not supplied, uses the current time from the template. pub fn proposal_block_from_template( - template: GetBlockTemplate, + template: &GetBlockTemplate, time_source: impl Into>, ) -> Result { let GetBlockTemplate { @@ -177,7 +184,7 @@ pub fn proposal_block_from_template( ref coinbase_txn, transactions: ref tx_templates, .. - } = template; + } = *template; if Height(height) > Height::MAX { Err(SerializationError::Parse( @@ -188,7 +195,7 @@ pub fn proposal_block_from_template( let time = time_source .into() .unwrap_or_default() - .time_from_template(&template); + .time_from_template(template); let mut transactions = vec![coinbase_txn.data.as_ref().zcash_deserialize_into()?]; diff --git a/zebra-utils/src/bin/block-template-to-proposal/main.rs b/zebra-utils/src/bin/block-template-to-proposal/main.rs index 8cc22cb0..cb62a399 100644 --- a/zebra-utils/src/bin/block-template-to-proposal/main.rs +++ b/zebra-utils/src/bin/block-template-to-proposal/main.rs @@ -96,7 +96,7 @@ fn main() -> Result<()> { let template: GetBlockTemplate = serde_json::from_value(template)?; // generate proposal according to arguments - let proposal = proposal_block_from_template(template, time_source)?; + let proposal = proposal_block_from_template(&template, time_source)?; eprintln!("{proposal:#?}"); let proposal = proposal diff --git a/zebrad/tests/common/get_block_template_rpcs/get_block_template.rs b/zebrad/tests/common/get_block_template_rpcs/get_block_template.rs index 1c0133b4..3c44dba0 100644 --- a/zebrad/tests/common/get_block_template_rpcs/get_block_template.rs +++ b/zebrad/tests/common/get_block_template_rpcs/get_block_template.rs @@ -27,6 +27,10 @@ use crate::common::{ /// We've seen it take anywhere from 1-45 seconds for the mempool to have some transactions in it. pub const EXPECTED_MEMPOOL_TRANSACTION_TIME: Duration = Duration::from_secs(45); +/// Number of times we want to try submitting a block template as a block proposal at an interval +/// that allows testing the varying mempool contents. +const NUM_SUCCESSFUL_BLOCK_PROPOSALS_REQUIRED: usize = 10; + /// Launch Zebra, wait for it to sync, and check the getblocktemplate RPC returns without errors. pub(crate) async fn run() -> Result<()> { let _init_guard = zebra_test::init(); @@ -86,25 +90,24 @@ pub(crate) async fn run() -> Result<()> { assert!(is_response_success); - tracing::info!( - "waiting {EXPECTED_MEMPOOL_TRANSACTION_TIME:?} for the mempool \ - to download and verify some transactions...", - ); + for _ in 0..NUM_SUCCESSFUL_BLOCK_PROPOSALS_REQUIRED { + tracing::info!( + "waiting {EXPECTED_MEMPOOL_TRANSACTION_TIME:?} for the mempool \ + to download and verify some transactions...", + ); - tokio::time::sleep(EXPECTED_MEMPOOL_TRANSACTION_TIME).await; + tokio::time::sleep(EXPECTED_MEMPOOL_TRANSACTION_TIME).await; - /* TODO: activate this test after #5925 and #5953 have merged, - and we've checked for any other bugs using #5944. - tracing::info!( - "calling getblocktemplate RPC method at {rpc_address}, \ - with a mempool that likely has transactions and attempting \ - to validate response result as a block proposal", - ); + tracing::info!( + "calling getblocktemplate RPC method at {rpc_address}, \ + with a mempool that likely has transactions and attempting \ + to validate response result as a block proposal", + ); - try_validate_block_template(&client) - .await - .expect("block proposal validation failed"); - */ + try_validate_block_template(&client) + .await + .expect("block proposal validation failed"); + } zebrad.kill(false)?; @@ -130,7 +133,6 @@ pub(crate) async fn run() -> Result<()> { /// If an RPC call returns a failure /// If the response result cannot be deserialized to `GetBlockTemplate` in 'template' mode /// or `ProposalResponse` in 'proposal' mode. -#[allow(dead_code)] async fn try_validate_block_template(client: &RPCRequestClient) -> Result<()> { let response_json_result = client .json_result_from_call("getblocktemplate", "[]".to_string()) @@ -142,16 +144,16 @@ async fn try_validate_block_template(client: &RPCRequestClient) -> Result<()> { "got getblocktemplate response, hopefully with transactions" ); - // Propose a new block with an empty solution and nonce field - tracing::info!("calling getblocktemplate with a block proposal...",); + for time_source in TimeSource::valid_sources() { + // Propose a new block with an empty solution and nonce field + tracing::info!( + "calling getblocktemplate with a block proposal and time source {time_source:?}...", + ); - // TODO: update this to use all valid time sources in the next PR - #[allow(clippy::single_element_loop)] - for proposal_block in [proposal_block_from_template( - response_json_result, - TimeSource::CurTime, - )?] { - let raw_proposal_block = hex::encode(proposal_block.zcash_serialize_to_vec()?); + let raw_proposal_block = hex::encode( + proposal_block_from_template(&response_json_result, time_source)? + .zcash_serialize_to_vec()?, + ); let json_result = client .json_result_from_call( @@ -163,7 +165,7 @@ async fn try_validate_block_template(client: &RPCRequestClient) -> Result<()> { tracing::info!( ?json_result, - ?proposal_block.header.time, + ?time_source, "got getblocktemplate proposal response" );