From 9c68853c08f55366ad9199c7ac8543fb4830358b Mon Sep 17 00:00:00 2001 From: Daniyar Itegulov Date: Fri, 29 Nov 2024 00:10:33 +1100 Subject: [PATCH] add an e2e test --- e2e-tests-rust/Cargo.toml | 4 +- e2e-tests-rust/src/lib.rs | 31 ++++++++++ e2e-tests-rust/tests/lib.rs | 112 +++++++++++++++++++++++++++--------- 3 files changed, 118 insertions(+), 29 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(()) +}