From 5c0d204f809476538ea94e3dab69912e68e7ada9 Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Fri, 29 Nov 2024 10:51:08 +1100 Subject: [PATCH] feat: add `anvil_{get,set}Automine`/`anvil_setIntervalMining` (#446) * add `anvil_{get,set}Automine`/`anvil_setIntervalMining` * add an e2e test --- e2e-tests-rust/Cargo.toml | 4 +- e2e-tests-rust/src/lib.rs | 31 ++++++++++ e2e-tests-rust/tests/lib.rs | 112 +++++++++++++++++++++++++++--------- src/main.rs | 21 ++++--- src/namespaces/anvil.rs | 26 ++++++++- src/node/anvil.rs | 27 +++++++++ src/node/in_memory.rs | 9 ++- src/node/in_memory_ext.rs | 43 +++++++++++++- src/node/mod.rs | 2 +- src/node/sealer.rs | 87 +++++++++++++++++++++++----- 10 files changed, 307 insertions(+), 55 deletions(-) diff --git a/e2e-tests-rust/Cargo.toml b/e2e-tests-rust/Cargo.toml index 2d19e21c..0200265e 100644 --- a/e2e-tests-rust/Cargo.toml +++ b/e2e-tests-rust/Cargo.toml @@ -10,12 +10,12 @@ categories = ["cryptography"] publish = false [dependencies] +alloy-zksync = { git = "https://github.com/itegulov/alloy-zksync.git", rev = "e0e54a5ac9e24c1c32c7a8783bbf3e34dde2e218" } +alloy = { version = "0.6", features = ["full", "rlp", "serde", "sol-types"] } anyhow = "1.0" fs2 = "0.4.3" tokio = { version = "1", features = ["time", "rt", "process"] } [dev-dependencies] -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/src/lib.rs b/e2e-tests-rust/src/lib.rs index b5614dd8..7ee02df6 100644 --- a/e2e-tests-rust/src/lib.rs +++ b/e2e-tests-rust/src/lib.rs @@ -1 +1,32 @@ +use alloy::providers::{Provider, ProviderCall}; +use alloy::rpc::client::NoParams; +use alloy::transports::Transport; +use alloy_zksync::network::Zksync; + pub mod utils; + +pub trait EraTestNodeApiProvider: Provider +where + T: Transport + Clone, +{ + fn get_auto_mine(&self) -> ProviderCall { + self.client().request_noparams("anvil_getAutomine").into() + } + + fn set_auto_mine(&self, enable: bool) -> ProviderCall { + self.client().request("anvil_setAutomine", (enable,)).into() + } + + fn set_interval_mining(&self, seconds: u64) -> ProviderCall { + self.client() + .request("anvil_setIntervalMining", (seconds,)) + .into() + } +} + +impl EraTestNodeApiProvider for P +where + T: Transport + Clone, + P: Provider, +{ +} diff --git a/e2e-tests-rust/tests/lib.rs b/e2e-tests-rust/tests/lib.rs index f0934a68..1563e06b 100644 --- a/e2e-tests-rust/tests/lib.rs +++ b/e2e-tests-rust/tests/lib.rs @@ -7,6 +7,7 @@ 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 era_test_node_e2e_tests::EraTestNodeApiProvider; use std::time::Duration; async fn init( @@ -32,45 +33,28 @@ async fn init( 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 provider = init(|node| node.block_time(1)).await?; - - let tx = TransactionRequest::default() - .with_to(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")) - .with_value(U256::from(100)); - let receipt = provider.send_transaction(tx).await?.get_receipt().await?; - assert!(receipt.status()); - - Ok(()) -} - -#[tokio::test] -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 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"); +const RICH_WALLET0: Address = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); +const RICH_WALLET1: Address = address!("70997970C51812dc3A010C7d01b50e0d17dc79C8"); +async fn test_finalize_two_txs_in_the_same_block( + provider: impl Provider, Zksync> + WalletProvider + Clone + 'static, + target: Address, +) -> anyhow::Result<()> { async fn submit_tx( provider: impl Provider, Zksync> + WalletProvider + Clone, rich_wallet: Address, + target: Address, ) -> Result { let tx = TransactionRequest::default() .with_from(rich_wallet) - .with_to(TARGET) + .with_to(target) .with_value(U256::from(100)); provider.send_transaction(tx).await?.register().await } // Submit two txs at the same time - let handle0 = tokio::spawn(submit_tx(provider.clone(), RICH_WALLET0)); - let handle1 = tokio::spawn(submit_tx(provider.clone(), RICH_WALLET1)); + let handle0 = tokio::spawn(submit_tx(provider.clone(), RICH_WALLET0, target)); + let handle1 = tokio::spawn(submit_tx(provider.clone(), RICH_WALLET1, target)); // Wait until both are finalized let (pending_tx0, pending_tx1) = tokio::join!(handle0, handle1); @@ -103,6 +87,37 @@ async fn interval_sealing_multiple_txs() -> anyhow::Result<()> { Ok(()) } +#[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 provider = init(|node| node.block_time(1)).await?; + + let tx = TransactionRequest::default() + .with_to(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")) + .with_value(U256::from(100)); + let receipt = provider.send_transaction(tx).await?.get_receipt().await?; + assert!(receipt.status()); + + Ok(()) +} + +#[tokio::test] +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 provider = init(|node| node.block_time(3)).await?; + + test_finalize_two_txs_in_the_same_block( + provider, + address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), + ) + .await?; + + 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 @@ -118,3 +133,46 @@ async fn no_sealing_timeout() -> anyhow::Result<()> { Ok(()) } + +#[tokio::test] +async fn dynamic_sealing_mode() -> anyhow::Result<()> { + // Test that we can successfully switch between different sealing modes + let provider = init(|node| node.no_mine()).await?; + assert_eq!(provider.get_auto_mine().await?, false); + + // Enable immediate block sealing + provider.set_auto_mine(true).await?; + assert_eq!(provider.get_auto_mine().await?, true); + + // Check that we can finalize transactions now + let tx = TransactionRequest::default() + .with_to(address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045")) + .with_value(U256::from(100)); + let receipt = provider.send_transaction(tx).await?.get_receipt().await?; + assert!(receipt.status()); + + // Enable interval block sealing + provider.set_interval_mining(3).await?; + assert_eq!(provider.get_auto_mine().await?, false); + + // Check that we can finalize two txs in the same block now + test_finalize_two_txs_in_the_same_block( + provider.clone(), + address!("d8dA6BF26964aF9D7eEd9e03E53415D37aA96045"), + ) + .await?; + + // Disable block sealing entirely + provider.set_auto_mine(false).await?; + assert_eq!(provider.get_auto_mine().await?, false); + + // Check that transactions do not get finalized now + 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/main.rs b/src/main.rs index bc9654f1..60594c79 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,7 +51,9 @@ use crate::namespaces::{ EthTestNodeNamespaceT, EvmNamespaceT, HardhatNamespaceT, NetNamespaceT, Web3NamespaceT, ZksNamespaceT, }; -use crate::node::{BlockProducer, BlockSealer, ImpersonationManager, TimestampManager, TxPool}; +use crate::node::{ + BlockProducer, BlockSealer, BlockSealerMode, ImpersonationManager, TimestampManager, TxPool, +}; use crate::system_contracts::SystemContracts; #[allow(clippy::too_many_arguments)] @@ -260,6 +262,15 @@ async fn main() -> anyhow::Result<()> { let time = TimestampManager::default(); let impersonation = ImpersonationManager::default(); let pool = TxPool::new(impersonation.clone()); + let sealing_mode = if config.no_mining { + BlockSealerMode::noop() + } else if let Some(block_time) = config.block_time { + BlockSealerMode::fixed_time(config.max_transactions, block_time) + } else { + BlockSealerMode::immediate(config.max_transactions) + }; + let block_sealer = BlockSealer::new(sealing_mode); + let node: InMemoryNode = InMemoryNode::new( fork_details, Some(observability), @@ -267,6 +278,7 @@ async fn main() -> anyhow::Result<()> { time.clone(), impersonation, pool.clone(), + block_sealer.clone(), ); if let Some(ref bytecodes_dir) = config.override_bytecodes_dir { @@ -307,13 +319,6 @@ async fn main() -> anyhow::Result<()> { })) .await; - 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) - }; let system_contracts = SystemContracts::from_options(&config.system_contracts_options, config.use_evm_emulator); let block_producer_handle = tokio::task::spawn(BlockProducer::new( diff --git a/src/namespaces/anvil.rs b/src/namespaces/anvil.rs index b77e320a..b55f1c7c 100644 --- a/src/namespaces/anvil.rs +++ b/src/namespaces/anvil.rs @@ -6,13 +6,37 @@ use crate::utils::Numeric; #[rpc] pub trait AnvilNamespaceT { + /// Gets node's auto mining status. + /// + /// # Returns + /// `true` if auto mining is enabled, `false` otherwise + #[rpc(name = "anvil_getAutomine")] + fn get_auto_mine(&self) -> RpcResult; + + /// Enables or disables, based on the single boolean argument, the automatic mining of new + /// blocks with each new transaction submitted to the network. + /// + /// # Arguments + /// + /// * `enable` - if `true` automatic mining will be enabled, disabled otherwise + #[rpc(name = "anvil_setAutomine")] + fn set_auto_mine(&self, enable: bool) -> RpcResult<()>; + + /// Sets the mining behavior to interval with the given interval (seconds). + /// + /// # Arguments + /// + /// * `seconds` - Frequency of automatic block production (in seconds) + #[rpc(name = "anvil_setIntervalMining")] + fn set_interval_mining(&self, seconds: u64) -> RpcResult<()>; + /// Sets the block timestamp interval. All future blocks' timestamps will /// have the provided amount of seconds in-between of them. Does not affect /// the block production interval. /// /// # Arguments /// - /// * `seconds` - The minimum gas price to be set + /// * `seconds` - The interval between two consecutive blocks (in seconds) #[rpc(name = "anvil_setBlockTimestampInterval")] fn set_block_timestamp_interval(&self, seconds: u64) -> RpcResult<()>; diff --git a/src/node/anvil.rs b/src/node/anvil.rs index 96ef63a2..ad18e12f 100644 --- a/src/node/anvil.rs +++ b/src/node/anvil.rs @@ -12,6 +12,33 @@ use crate::{ impl AnvilNamespaceT for InMemoryNode { + fn get_auto_mine(&self) -> RpcResult { + self.get_immediate_sealing() + .map_err(|err| { + tracing::error!("failed getting immediate sealing: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } + + fn set_auto_mine(&self, enable: bool) -> RpcResult<()> { + self.set_immediate_sealing(enable) + .map_err(|err| { + tracing::error!("failed setting immediate sealing: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } + + fn set_interval_mining(&self, seconds: u64) -> RpcResult<()> { + self.set_interval_sealing(seconds) + .map_err(|err| { + tracing::error!("failed setting interval sealing: {:?}", err); + into_jsrpc_error(Web3Error::InternalError(err)) + }) + .into_boxed_future() + } + fn set_block_timestamp_interval(&self, seconds: u64) -> RpcResult<()> { self.time.set_block_timestamp_interval(seconds); Ok(()).into_boxed_future() diff --git a/src/node/in_memory.rs b/src/node/in_memory.rs index 8537cc16..0a071c2d 100644 --- a/src/node/in_memory.rs +++ b/src/node/in_memory.rs @@ -48,7 +48,7 @@ use zksync_web3_decl::error::Web3Error; use crate::node::impersonate::{ImpersonationManager, ImpersonationState}; use crate::node::time::{AdvanceTime, ReadTime, TimestampManager}; -use crate::node::TxPool; +use crate::node::{BlockSealer, TxPool}; use crate::{ bootloader_debug::{BootloaderDebug, BootloaderDebugTracer}, config::{ @@ -971,6 +971,7 @@ pub struct InMemoryNode { /// An optional handle to the observability stack pub(crate) observability: Option, pub(crate) pool: TxPool, + pub(crate) sealer: BlockSealer, } fn contract_address_from_tx_result(execution_result: &VmExecutionResultAndLogs) -> Option { @@ -992,6 +993,7 @@ impl Default for InMemoryNode { TimestampManager::default(), impersonation.clone(), TxPool::new(impersonation), + BlockSealer::default(), ) } } @@ -1004,6 +1006,7 @@ impl InMemoryNode { time: TimestampManager, impersonation: ImpersonationManager, pool: TxPool, + sealer: BlockSealer, ) -> Self { let system_contracts_options = config.system_contracts_options; let inner = InMemoryNodeInner::new(fork, config, &time, impersonation.clone()); @@ -1015,6 +1018,7 @@ impl InMemoryNode { impersonation, observability, pool, + sealer, } } @@ -1029,6 +1033,7 @@ impl InMemoryNode { TimestampManager::default(), impersonation.clone(), TxPool::new(impersonation), + BlockSealer::default(), ) } @@ -2070,6 +2075,7 @@ mod tests { TimestampManager::default(), impersonation.clone(), TxPool::new(impersonation), + BlockSealer::default(), ); let tx = testing::TransactionBuilder::new().build(); @@ -2094,6 +2100,7 @@ mod tests { TimestampManager::default(), impersonation.clone(), TxPool::new(impersonation), + BlockSealer::default(), ); let private_key = K256PrivateKey::from_bytes(H256::repeat_byte(0xef)).unwrap(); diff --git a/src/node/in_memory_ext.rs b/src/node/in_memory_ext.rs index 1fb476a1..55b6c505 100644 --- a/src/node/in_memory_ext.rs +++ b/src/node/in_memory_ext.rs @@ -1,3 +1,4 @@ +use crate::node::sealer::BlockSealerMode; use crate::utils::Numeric; use crate::{ fork::{ForkDetails, ForkSource}, @@ -7,6 +8,7 @@ use crate::{ }; use anyhow::{anyhow, Context}; use std::convert::TryInto; +use std::time::Duration; use zksync_types::{ get_code_key, get_nonce_key, utils::{nonces_to_full_nonce, storage_key_for_eth_balance}, @@ -360,6 +362,44 @@ impl InMemoryNo observability.disable_logging() } } + + pub fn get_immediate_sealing(&self) -> Result { + Ok(self.sealer.is_immediate()) + } + + pub fn set_immediate_sealing(&self, enable: bool) -> Result<()> { + if enable { + self.sealer.set_mode(BlockSealerMode::immediate( + self.inner + .read() + .map_err(|err| anyhow!("failed acquiring lock: {:?}", err))? + .config + .max_transactions, + )) + } else { + self.sealer.set_mode(BlockSealerMode::Noop) + } + Ok(()) + } + + pub fn set_interval_sealing(&self, seconds: u64) -> Result<()> { + let sealing_mode = if seconds == 0 { + BlockSealerMode::noop() + } else { + let block_time = Duration::from_secs(seconds); + + BlockSealerMode::fixed_time( + self.inner + .read() + .map_err(|err| anyhow!("failed acquiring lock: {:?}", err))? + .config + .max_transactions, + block_time, + ) + }; + self.sealer.set_mode(sealing_mode); + Ok(()) + } } #[cfg(test)] @@ -368,7 +408,7 @@ mod tests { use crate::fork::ForkStorage; use crate::namespaces::EthNamespaceT; use crate::node::time::{ReadTime, TimestampManager}; - use crate::node::{ImpersonationManager, InMemoryNodeInner, Snapshot, TxPool}; + use crate::node::{BlockSealer, ImpersonationManager, InMemoryNodeInner, Snapshot, TxPool}; use crate::{http_fork_source::HttpForkSource, node::InMemoryNode}; use std::str::FromStr; use std::sync::{Arc, RwLock}; @@ -507,6 +547,7 @@ mod tests { impersonation, observability: None, pool, + sealer: BlockSealer::default(), }; let address = Address::from_str("0x36615Cf349d7F6344891B1e7CA7C72883F5dc049").unwrap(); diff --git a/src/node/mod.rs b/src/node/mod.rs index 71b1e63f..5b004900 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -22,6 +22,6 @@ mod zks; pub use self::{ block_producer::BlockProducer, impersonate::ImpersonationManager, pool::TxPool, - sealer::BlockSealer, time::TimestampManager, + sealer::BlockSealer, sealer::BlockSealerMode, time::TimestampManager, }; pub use in_memory::*; diff --git a/src/node/sealer.rs b/src/node/sealer.rs index 4ec58160..0d536087 100644 --- a/src/node/sealer.rs +++ b/src/node/sealer.rs @@ -1,11 +1,59 @@ use crate::node::pool::{TxBatch, TxPool}; +use futures::task::AtomicWaker; +use std::sync::{Arc, RwLock}; use std::task::{Context, Poll}; use std::time::Duration; use tokio::time::{Interval, MissedTickBehavior}; +#[derive(Clone, Debug)] +pub struct BlockSealer { + /// The mode this sealer currently operates in + mode: Arc>, + /// Used for task wake up when the sealing mode was forcefully changed + waker: Arc, +} + +impl Default for BlockSealer { + fn default() -> Self { + BlockSealer::new(BlockSealerMode::immediate(1000)) + } +} + +impl BlockSealer { + pub fn new(mode: BlockSealerMode) -> Self { + Self { + mode: Arc::new(RwLock::new(mode)), + waker: Arc::new(AtomicWaker::new()), + } + } + + pub fn is_immediate(&self) -> bool { + matches!( + *self.mode.read().expect("BlockSealer lock is poisoned"), + BlockSealerMode::Immediate(_) + ) + } + + pub fn set_mode(&self, mode: BlockSealerMode) { + *self.mode.write().expect("BlockSealer lock is poisoned") = mode; + // Notify last used waker that the mode might have changed + self.waker.wake(); + } + + pub fn poll(&mut self, pool: &TxPool, cx: &mut Context<'_>) -> Poll { + self.waker.register(cx.waker()); + let mut mode = self.mode.write().expect("BlockSealer lock is poisoned"); + match &mut *mode { + BlockSealerMode::Noop => Poll::Pending, + BlockSealerMode::Immediate(immediate) => immediate.poll(pool), + BlockSealerMode::FixedTime(fixed) => fixed.poll(pool, cx), + } + } +} + /// Represents different modes of block sealing available on the node #[derive(Debug)] -pub enum BlockSealer { +pub enum BlockSealerMode { /// Never seals blocks. Noop, /// Seals a block as soon as there is at least one transaction. @@ -14,7 +62,7 @@ pub enum BlockSealer { FixedTime(FixedTimeBlockSealer), } -impl BlockSealer { +impl BlockSealerMode { pub fn noop() -> Self { Self::Noop } @@ -29,9 +77,9 @@ 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), + BlockSealerMode::Noop => Poll::Pending, + BlockSealerMode::Immediate(immediate) => immediate.poll(pool), + BlockSealerMode::FixedTime(fixed) => fixed.poll(pool, cx), } } } @@ -89,6 +137,7 @@ impl FixedTimeBlockSealer { #[cfg(test)] mod tests { use crate::node::pool::TxBatch; + use crate::node::sealer::BlockSealerMode; use crate::node::{BlockSealer, ImpersonationManager, TxPool}; use std::ptr; use std::task::{Context, Poll, RawWaker, RawWakerVTable, Waker}; @@ -112,7 +161,7 @@ mod tests { #[test] fn immediate_empty() { let pool = TxPool::new(ImpersonationManager::default()); - let mut block_sealer = BlockSealer::immediate(1000); + let mut block_sealer = BlockSealer::new(BlockSealerMode::immediate(1000)); let waker = &WAKER_NOOP; let mut cx = Context::from_waker(waker); @@ -122,7 +171,7 @@ mod tests { #[test] fn immediate_one_tx() { let pool = TxPool::new(ImpersonationManager::default()); - let mut block_sealer = BlockSealer::immediate(1000); + let mut block_sealer = BlockSealer::new(BlockSealerMode::immediate(1000)); let waker = &WAKER_NOOP; let mut cx = Context::from_waker(waker); @@ -141,7 +190,7 @@ mod tests { #[test] fn immediate_several_txs() { let pool = TxPool::new(ImpersonationManager::default()); - let mut block_sealer = BlockSealer::immediate(1000); + let mut block_sealer = BlockSealer::new(BlockSealerMode::immediate(1000)); let waker = &WAKER_NOOP; let mut cx = Context::from_waker(waker); @@ -160,7 +209,7 @@ mod tests { #[test] fn immediate_respect_max_txs() { let pool = TxPool::new(ImpersonationManager::default()); - let mut block_sealer = BlockSealer::immediate(3); + let mut block_sealer = BlockSealer::new(BlockSealerMode::immediate(3)); let waker = &WAKER_NOOP; let mut cx = Context::from_waker(waker); @@ -180,7 +229,7 @@ mod tests { #[test] fn immediate_gradual_txs() { let pool = TxPool::new(ImpersonationManager::default()); - let mut block_sealer = BlockSealer::immediate(1000); + let mut block_sealer = BlockSealer::new(BlockSealerMode::immediate(1000)); let waker = &WAKER_NOOP; let mut cx = Context::from_waker(waker); @@ -217,7 +266,10 @@ mod tests { #[tokio::test] async fn fixed_time_very_long() { let pool = TxPool::new(ImpersonationManager::default()); - let mut block_sealer = BlockSealer::fixed_time(1000, Duration::from_secs(10000)); + let mut block_sealer = BlockSealer::new(BlockSealerMode::fixed_time( + 1000, + Duration::from_secs(10000), + )); let waker = &WAKER_NOOP; let mut cx = Context::from_waker(waker); @@ -227,7 +279,10 @@ mod tests { #[tokio::test] async fn fixed_time_seal_empty() { let pool = TxPool::new(ImpersonationManager::default()); - let mut block_sealer = BlockSealer::fixed_time(1000, Duration::from_millis(100)); + let mut block_sealer = BlockSealer::new(BlockSealerMode::fixed_time( + 1000, + Duration::from_millis(100), + )); let waker = &WAKER_NOOP; let mut cx = Context::from_waker(waker); @@ -261,7 +316,10 @@ mod tests { #[tokio::test] async fn fixed_time_seal_with_txs() { let pool = TxPool::new(ImpersonationManager::default()); - let mut block_sealer = BlockSealer::fixed_time(1000, Duration::from_millis(100)); + let mut block_sealer = BlockSealer::new(BlockSealerMode::fixed_time( + 1000, + Duration::from_millis(100), + )); let waker = &WAKER_NOOP; let mut cx = Context::from_waker(waker); @@ -282,7 +340,8 @@ mod tests { #[tokio::test] async fn fixed_time_respect_max_txs() { let pool = TxPool::new(ImpersonationManager::default()); - let mut block_sealer = BlockSealer::fixed_time(3, Duration::from_millis(100)); + let mut block_sealer = + BlockSealer::new(BlockSealerMode::fixed_time(3, Duration::from_millis(100))); let waker = &WAKER_NOOP; let mut cx = Context::from_waker(waker);