From cef614132f5e3329ed4bfccf694ffb1185da070b Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Thu, 28 Nov 2024 19:56:40 +1100 Subject: [PATCH] add `--no-mine` mode --- e2e-tests-rust/Cargo.lock | 2 +- e2e-tests-rust/Cargo.toml | 2 +- e2e-tests-rust/tests/lib.rs | 55 ++++++++++++++++++++++++++----------- src/config/cli.rs | 7 ++++- src/config/mod.rs | 11 ++++++++ src/main.rs | 4 ++- src/node/sealer.rs | 9 +++++- 7 files changed, 69 insertions(+), 21 deletions(-) diff --git a/e2e-tests-rust/Cargo.lock b/e2e-tests-rust/Cargo.lock index 5b745825..0b33af4d 100644 --- a/e2e-tests-rust/Cargo.lock +++ b/e2e-tests-rust/Cargo.lock @@ -627,7 +627,7 @@ dependencies = [ [[package]] name = "alloy-zksync" version = "0.6.0" -source = "git+https://github.com/itegulov/alloy-zksync.git?rev=b433d2d64e0f7d939891064b00d8a7991a427682#b433d2d64e0f7d939891064b00d8a7991a427682" +source = "git+https://github.com/itegulov/alloy-zksync.git?rev=e0e54a5ac9e24c1c32c7a8783bbf3e34dde2e218#e0e54a5ac9e24c1c32c7a8783bbf3e34dde2e218" dependencies = [ "alloy", "async-trait", diff --git a/e2e-tests-rust/Cargo.toml b/e2e-tests-rust/Cargo.toml index 7c075db8..2d19e21c 100644 --- a/e2e-tests-rust/Cargo.toml +++ b/e2e-tests-rust/Cargo.toml @@ -15,7 +15,7 @@ fs2 = "0.4.3" tokio = { version = "1", features = ["time", "rt", "process"] } [dev-dependencies] -alloy-zksync = { git = "https://github.com/itegulov/alloy-zksync.git", rev = "b433d2d64e0f7d939891064b00d8a7991a427682" } +alloy-zksync = { git = "https://github.com/itegulov/alloy-zksync.git", rev = "e0e54a5ac9e24c1c32c7a8783bbf3e34dde2e218" } alloy = { version = "0.6", features = ["full", "rlp", "serde", "sol-types"] } [workspace] # ignore higher-level workspace diff --git a/e2e-tests-rust/tests/lib.rs b/e2e-tests-rust/tests/lib.rs index 81f1d2f2..f0934a68 100644 --- a/e2e-tests-rust/tests/lib.rs +++ b/e2e-tests-rust/tests/lib.rs @@ -4,31 +4,39 @@ use alloy::providers::{PendingTransaction, PendingTransactionError, Provider, Wa use alloy::transports::http::{reqwest, Http}; use alloy_zksync::network::transaction_request::TransactionRequest; use alloy_zksync::network::Zksync; +use alloy_zksync::node_bindings::EraTestNode; use alloy_zksync::provider::{zksync_provider, ProviderBuilderExt}; use era_test_node_e2e_tests::utils::LockedPort; +use std::time::Duration; -fn init( - block_time: u64, - port: u16, -) -> impl Provider, Zksync> + WalletProvider + Clone { - zksync_provider() +async fn init( + f: impl FnOnce(EraTestNode) -> EraTestNode, +) -> anyhow::Result, Zksync> + WalletProvider + Clone> { + let locked_port = LockedPort::acquire_unused().await?; + let provider = zksync_provider() .with_recommended_fillers() .on_era_test_node_with_wallet_and_config(|node| { - node.path( - std::env::var("ERA_TEST_NODE_BINARY_PATH") - .unwrap_or("../target/release/era_test_node".to_string()), - ) - .port(port) - .block_time(block_time) - }) + f(node + .path( + std::env::var("ERA_TEST_NODE_BINARY_PATH") + .unwrap_or("../target/release/era_test_node".to_string()), + ) + .port(locked_port.port)) + }); + + // Wait for era-test-node to get up and be able to respond + provider.get_accounts().await?; + // Explicitly unlock the port to showcase why we waited above + drop(locked_port); + + Ok(provider) } #[tokio::test] async fn interval_sealing_finalization() -> anyhow::Result<()> { // Test that we can submit a transaction and wait for it to finalize when era-test-node is // operating in interval sealing mode. - let locked_port = LockedPort::acquire_unused().await?; - let provider = init(1, locked_port.port); + let provider = init(|node| node.block_time(1)).await?; let tx = TransactionRequest::default() .with_to(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")) @@ -44,8 +52,7 @@ async fn interval_sealing_multiple_txs() -> anyhow::Result<()> { // Test that we can submit two transactions and wait for them to finalize in the same block when // era-test-node is operating in interval sealing mode. 3 seconds should be long enough for // the entire flow to execute before the first block is produced. - let locked_port = LockedPort::acquire_unused().await?; - let provider = init(3, locked_port.port); + let provider = init(|node| node.block_time(3)).await?; const RICH_WALLET0: Address = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); const RICH_WALLET1: Address = address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"); const TARGET: Address = address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"); @@ -95,3 +102,19 @@ async fn interval_sealing_multiple_txs() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test] +async fn no_sealing_timeout() -> anyhow::Result<()> { + // Test that we can submit a transaction and timeout while waiting for it to finalize when + // era-test-node is operating in no sealing mode. + let provider = init(|node| node.no_mine()).await?; + + let tx = TransactionRequest::default() + .with_to(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")) + .with_value(U256::from(100)); + let pending_tx = provider.send_transaction(tx).await?.register().await?; + let finalization_result = tokio::time::timeout(Duration::from_secs(3), pending_tx).await; + assert!(finalization_result.is_err()); + + Ok(()) +} diff --git a/src/config/cli.rs b/src/config/cli.rs index 082665eb..5853404d 100644 --- a/src/config/cli.rs +++ b/src/config/cli.rs @@ -216,6 +216,10 @@ pub struct Cli { /// If unset, node seals a new block as soon as there is at least one transaction. #[arg(short, long, value_name = "SECONDS", value_parser = duration_from_secs_f64, help_heading = "Block Sealing")] pub block_time: Option, + + /// Disable auto and interval mining, and mine on demand instead. + #[arg(long, visible_alias = "no-mine", conflicts_with = "block_time")] + pub no_mining: bool, } #[derive(Debug, Subcommand, Clone)] @@ -357,7 +361,8 @@ impl Cli { } else { None }) - .with_block_time(self.block_time); + .with_block_time(self.block_time) + .with_no_mining(self.no_mining); if self.emulate_evm && self.dev_system_contracts != Some(SystemContractsOptions::Local) { return Err(eyre::eyre!( diff --git a/src/config/mod.rs b/src/config/mod.rs index e8fdc443..c11c60ea 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -120,6 +120,8 @@ pub struct TestNodeConfig { pub block_time: Option, /// Maximum number of transactions per block pub max_transactions: usize, + /// Disable automatic sealing mode and use `BlockSealer::Noop` instead + pub no_mining: bool, } impl Default for TestNodeConfig { @@ -172,6 +174,8 @@ impl Default for TestNodeConfig { // Block sealing configuration default block_time: None, + no_mining: false, + max_transactions: 1000, } } @@ -796,6 +800,13 @@ impl TestNodeConfig { self.block_time = block_time; self } + + /// If set to `true` auto sealing will be disabled + #[must_use] + pub fn with_no_mining(mut self, no_mining: bool) -> Self { + self.no_mining = no_mining; + self + } } /// Account Generator diff --git a/src/main.rs b/src/main.rs index 4d68fc66..bc9654f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -307,7 +307,9 @@ async fn main() -> anyhow::Result<()> { })) .await; - let block_sealer = if let Some(block_time) = config.block_time { + let block_sealer = if config.no_mining { + BlockSealer::noop() + } else if let Some(block_time) = config.block_time { BlockSealer::fixed_time(config.max_transactions, block_time) } else { BlockSealer::immediate(config.max_transactions) diff --git a/src/node/sealer.rs b/src/node/sealer.rs index 215f3ddd..4ec58160 100644 --- a/src/node/sealer.rs +++ b/src/node/sealer.rs @@ -3,9 +3,11 @@ use std::task::{Context, Poll}; use std::time::Duration; use tokio::time::{Interval, MissedTickBehavior}; -/// Mode of operations for the `BlockSealer` +/// Represents different modes of block sealing available on the node #[derive(Debug)] pub enum BlockSealer { + /// Never seals blocks. + Noop, /// Seals a block as soon as there is at least one transaction. Immediate(ImmediateBlockSealer), /// Seals a new block every `interval` tick @@ -13,6 +15,10 @@ pub enum BlockSealer { } impl BlockSealer { + pub fn noop() -> Self { + Self::Noop + } + pub fn immediate(max_transactions: usize) -> Self { Self::Immediate(ImmediateBlockSealer { max_transactions }) } @@ -23,6 +29,7 @@ impl BlockSealer { pub fn poll(&mut self, pool: &TxPool, cx: &mut Context<'_>) -> Poll { match self { + BlockSealer::Noop => Poll::Pending, BlockSealer::Immediate(immediate) => immediate.poll(pool), BlockSealer::FixedTime(fixed) => fixed.poll(pool, cx), }