diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 416c0fca..a317d610 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -59,7 +59,7 @@ jobs: needs: [rustfmt] strategy: matrix: - crate: [rosetta-server-astar, rosetta-server-ethereum, rosetta-server-polkadot, rosetta-client] + crate: [rosetta-server-astar, rosetta-server-ethereum, rosetta-server-polkadot, rosetta-client, rosetta-testing-arbitrum] name: ${{ matrix.crate }} runs-on: self-hosted steps: @@ -94,6 +94,16 @@ jobs: - name: Pull nodes run: ./scripts/pull_nodes.sh + + - name: Checkout nitro-testnode + if: ${{ matrix.crate == 'rosetta-testing-arbitrum' }} + run: git clone -b release --depth=1 --no-tags --recurse-submodules https://github.com/ManojJiSharma/nitro-testnode.git + + - name: Start arbitrum nitro-testnode + if: ${{ matrix.crate == 'rosetta-testing-arbitrum' }} + run: | + cd nitro-testnode + ./test-node.bash --detach - name: test (${{ matrix.crate }}) run: cargo test --locked -p ${{ matrix.crate }} @@ -119,18 +129,11 @@ jobs: components: clippy target: x86_64-unknown-linux-musl override: true - - - name: Checkout code - run: git clone -b release --recurse-submodules https://github.com/ManojJiSharma/nitro-testnode.git - - - name: Run the arbitrum nitro-testnode - run: | - cd nitro-testnode - ./test-node.bash --detach - name: clippy run: | cargo clippy --locked --workspace --examples --tests --all-features \ + --exclude rosetta-testing-arbitrum \ --exclude rosetta-server-astar \ --exclude rosetta-server-ethereum \ --exclude rosetta-server-polkadot \ @@ -149,10 +152,11 @@ jobs: - name: cargo test run: | cargo test --locked --workspace --all-features \ + --exclude rosetta-testing-arbitrum \ --exclude rosetta-server-astar \ --exclude rosetta-server-ethereum \ --exclude rosetta-server-polkadot \ --exclude rosetta-client - name: Cleanup Docker - run: ./scripts/reset_docker.sh \ No newline at end of file + run: ./scripts/reset_docker.sh diff --git a/Cargo.lock b/Cargo.lock index a452b7ed..342b9d60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5346,17 +5346,16 @@ dependencies = [ name = "rosetta-testing-arbitrum" version = "0.1.0" dependencies = [ - "alloy-sol-types 0.5.4", + "alloy-sol-types 0.6.0", "anyhow", "ethers", "ethers-solc", + "hex-literal", "rosetta-client", "rosetta-config-ethereum", "rosetta-core", "rosetta-docker", "rosetta-server-ethereum", - "sequential-test", - "serde_json", "sha3", "tokio", "tracing", @@ -6008,21 +6007,6 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" -[[package]] -name = "sequential-macro" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5facc5f409a55d25bf271c853402a00e1187097d326757043f5dd711944d07" - -[[package]] -name = "sequential-test" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d9c0d773bc7e7733264f460e5dfa00b2510421ddd6284db0749eef8dfb79e9" -dependencies = [ - "sequential-macro", -] - [[package]] name = "serde" version = "1.0.195" diff --git a/chains/arbitrum/testing/rosetta-testing-arbitrum/Cargo.toml b/chains/arbitrum/testing/rosetta-testing-arbitrum/Cargo.toml index f2139ce0..f94cf5c3 100644 --- a/chains/arbitrum/testing/rosetta-testing-arbitrum/Cargo.toml +++ b/chains/arbitrum/testing/rosetta-testing-arbitrum/Cargo.toml @@ -6,21 +6,18 @@ license = "MIT" repository = "https://github.com/analog-labs/chain-connectors" description = "Arbitrum unit test." -[dependencies] +[dev-dependencies] +alloy-sol-types = { version = "0.6" } anyhow = "1.0" ethers = { version = "2.0", default-features = true, features = ["abigen", "rustls"] } +ethers-solc = "2.0" +hex-literal = "0.4" +rosetta-client.workspace = true rosetta-config-ethereum.workspace = true rosetta-core.workspace = true rosetta-docker = { workspace = true, features = ["tests"] } rosetta-server-ethereum.workspace = true -sequential-test = "0.2.4" -serde_json.workspace = true +sha3 = "0.10" tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } tracing = "0.1.40" - -[dev-dependencies] -alloy-sol-types = { version = "0.5" } -ethers-solc = "2.0" -rosetta-client.workspace = true -sha3 = "0.10" url = "2.4" diff --git a/chains/arbitrum/testing/rosetta-testing-arbitrum/src/lib.rs b/chains/arbitrum/testing/rosetta-testing-arbitrum/src/lib.rs index 360961d9..8cd32a47 100644 --- a/chains/arbitrum/testing/rosetta-testing-arbitrum/src/lib.rs +++ b/chains/arbitrum/testing/rosetta-testing-arbitrum/src/lib.rs @@ -20,7 +20,6 @@ //! - `rosetta_client`: Client library for Rosetta API interactions. //! - `rosetta_config_ethereum`: Configuration for Ethereum Rosetta server. //! - `rosetta_server_arbitrum`: Custom client implementation for interacting with Arbitrum. -//! - `sequential_test`: Macro for ensuring sequential execution of asynchronous tests. //! - `sha3`: SHA-3 (Keccak) implementation for hashing. //! - `tokio`: Asynchronous runtime for running async functions. //! @@ -43,18 +42,25 @@ mod tests { use ethers::{ providers::Middleware, signers::{LocalWallet, Signer}, - types::{transaction::eip2718::TypedTransaction, TransactionRequest, H160, H256, U256}, - utils::hex, + types::{ + transaction::eip2718::TypedTransaction, BlockId, BlockNumber, TransactionRequest, H160, + H256, U256, U64, + }, }; use ethers_solc::{artifacts::Source, CompilerInput, EvmVersion, Solc}; + use hex_literal::hex; use rosetta_client::Wallet; use rosetta_config_ethereum::{AtBlock, CallResult}; use rosetta_core::{types::PartialBlockIdentifier, BlockchainClient}; use rosetta_server_ethereum::MaybeWsEthereumClient; - use sequential_test::sequential; use sha3::Digest; - use std::{collections::BTreeMap, future::Future, path::Path, str::FromStr}; - use tokio::sync::oneshot::{error::TryRecvError, Receiver}; + use std::{ + collections::BTreeMap, + future::Future, + path::Path, + sync::atomic::{AtomicU64, Ordering}, + time::Duration, + }; sol! { interface TestContract { @@ -65,38 +71,135 @@ mod tests { } } - async fn run_test(_future: Fut, mut stop_rx: Receiver<()>) { + macro_rules! create_account { + ($name: literal, $value: expr) => {{ + use ethers::core::k256::ecdsa::SigningKey; + let private_key: [u8; 32] = + sha3::Keccak256::digest(concat!(module_path!(), "::", $name)).into(); + let address = ::ethers::utils::secret_key_to_address( + &SigningKey::from_bytes(private_key.as_ref().into()).unwrap(), + ); + sync_send_funds(address, { $value }).await.unwrap(); + private_key + }}; + } + + /// Arbitrum faucet account private key. + const FAUCET_ACCOUNT_PRIVATE_KEY: [u8; 32] = + hex!("8aab161e2a1e57367b60bd870861e3042c2513f8a856f9fee014e7b96e0a2a36"); + + /// Account used exclusively to continuously sending tx to mine new blocks. + const BLOCK_MANEGER_PRIVATE_KEY: [u8; 32] = + hex!("b6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659"); + // const BLOCK_MANEGER_ADDRESS: H160 = H160(hex!("3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E")); + + /// Arbitrum rpc url + const ARBITRUM_RPC_URL: &str = "http://localhost:8547"; + + /// Send funds to the provided account + async fn sync_send_funds + Send>(dest: H160, amount: I) -> Result<()> { + // Guarantee the faucet nonce is incremented is sequentially + static NONCE: std::sync::OnceLock = + std::sync::OnceLock::new(); + + let amount = amount.into(); + // Connect to the provider + let wallet = LocalWallet::from_bytes(&FAUCET_ACCOUNT_PRIVATE_KEY)?; + let provider = + ethers::providers::Provider::::try_from(ARBITRUM_RPC_URL) + .context("Failed to create HTTP provider")? + .interval(Duration::from_secs(1)); + + // retrieve the current nonce + let nonce = provider + .get_transaction_count(wallet.address(), Some(BlockId::Number(BlockNumber::Latest))) + .await? + .as_u64(); + let nonce = NONCE.get_or_init(|| AtomicU64::new(nonce)); + let nonce = nonce.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + + // Retrieve chain id + let chain_id = provider.get_chainid().await?.as_u64(); + + // Create a transaction request + let transaction_request = TransactionRequest { + from: None, + to: Some(ethers::types::NameOrAddress::Address(dest)), + value: Some(amount), + gas: Some(U256::from(210_000)), + gas_price: Some(U256::from(500_000_000)), + nonce: Some(U256::from(nonce)), + data: None, + chain_id: Some(chain_id.into()), + }; + + // Sign and send the transaction + let tx: TypedTransaction = transaction_request.into(); + let signature = wallet.sign_transaction(&tx).await?; + let tx = tx.rlp_signed(&signature); + let receipt = provider + .send_raw_transaction(tx) + .await? + .confirmations(1) + .await? + .context("failed to retrieve tx receipt")?; + + // Verify if the tx reverted + if !matches!(receipt.status, Some(U64([1]))) { + anyhow::bail!("Transaction reverted: {:?}", receipt.transaction_hash); + } + Ok(()) + } + + /// Run the test in another thread and while sending txs to force arbitrum to mine new blocks + /// Panics if the test panics + async fn run_test + Send + 'static>(future: Fut) { + static TEST_ID_MANAGER: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(1); + static CURRENT_TEST: std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new(0); + static NONCE: std::sync::OnceLock = + std::sync::OnceLock::new(); + + // Create a unique id for this test context + let test_id = TEST_ID_MANAGER.fetch_add(1, Ordering::SeqCst); + + let wallet = LocalWallet::from_bytes(&BLOCK_MANEGER_PRIVATE_KEY).unwrap(); + let provider = + ethers::providers::Provider::::try_from(ARBITRUM_RPC_URL) + .expect("Failed to create HTTP provider") + .interval(Duration::from_secs(1)); + let address = H160(hex!("8Db77D3B019a52788bD3804724f5653d7C9Cf0b6")); + + let nonce = provider + .get_transaction_count(wallet.address(), None) + .await + .expect("failed to retrieve account nonce") + .as_u64(); + + let chain_id = provider.get_chainid().await.unwrap().as_u64(); + + let nonce = NONCE.get_or_init(|| AtomicU64::new(nonce)); + + // Run the test in another thread + let handler = tokio::spawn(future); + loop { - if matches!(stop_rx.try_recv(), Ok(()) | Err(TryRecvError::Closed)) { + let current_test = CURRENT_TEST.load(std::sync::atomic::Ordering::SeqCst); + if current_test == 0 { + let result = + CURRENT_TEST.compare_exchange(0, test_id, Ordering::Acquire, Ordering::Relaxed); + if result.is_ok() { + break; + } + } else if current_test == test_id { break; } - let hex_string = "0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659"; - let hex_string = &hex_string[2..]; - let mut private_key_result = [0; 32]; - let bytes = hex::decode(hex_string).expect("Failed to decode hex string"); - private_key_result.copy_from_slice(&bytes); - let result = MaybeWsEthereumClient::new( - "arbitrum", - "dev", - "ws://127.0.0.1:8548", - Some(private_key_result), - ) - .await; - assert!(result.is_ok(), "Error creating ArbitrumClient"); - let wallet = LocalWallet::from_bytes(&private_key_result).unwrap(); - let provider = ethers::providers::Provider::::try_from( - "http://localhost:8547", - ) - .expect("Failed to create HTTP provider"); - let address = H160::from_str("0x8Db77D3B019a52788bD3804724f5653d7C9Cf0b6").unwrap(); - let nonce = provider - .get_transaction_count( - H160::from_str("0x3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E").unwrap(), - None, - ) - .await - .unwrap(); - let chain_id = provider.get_chainid().await.unwrap().as_u64(); + tokio::time::sleep(std::time::Duration::from_millis(4000)).await; + } + + // Force arbitrum to mine a new block by sending a transaction until the test finishes + while !handler.is_finished() { + let next_nonce = nonce.fetch_add(1, std::sync::atomic::Ordering::SeqCst); + // Create a transaction request let transaction_request = TransactionRequest { from: None, @@ -104,151 +207,125 @@ mod tests { value: Some(U256::from(1)), gas: Some(U256::from(210_000)), gas_price: Some(U256::from(500_000_000)), - nonce: Some(nonce), + nonce: Some(U256::from(next_nonce)), data: None, chain_id: Some(chain_id.into()), }; + + // Sign and send the transaction let tx: TypedTransaction = transaction_request.into(); - let signature = wallet.sign_transaction(&tx).await.unwrap(); - let tx = tx.rlp_signed(&signature); - let _ = provider - .send_raw_transaction(tx) - .await - .unwrap() - .confirmations(1) - .await - .unwrap() - .context("failed to retrieve tx receipt") - .unwrap() - .transaction_hash - .0 - .to_vec(); - tokio::time::sleep(std::time::Duration::from_secs(1)).await; + let signature = match wallet.sign_transaction(&tx).await { + Ok(signature) => signature, + Err(err) => { + CURRENT_TEST.store(0, std::sync::atomic::Ordering::SeqCst); + panic!("{err}"); + }, + }; + let tx: ethers::types::Bytes = tx.rlp_signed(&signature); + let pending_tx = match provider.send_raw_transaction(tx).await { + Ok(tx) => tx, + Err(err) => { + CURRENT_TEST.store(0, std::sync::atomic::Ordering::SeqCst); + panic!("{err}"); + }, + }; + + // Wait 500ms for the tx to be mined + match pending_tx.confirmations(1).await { + Ok(Some(_)) => { + tokio::time::sleep(std::time::Duration::from_millis(500)).await; + }, + Ok(None) => { + CURRENT_TEST.store(0, std::sync::atomic::Ordering::SeqCst); + panic!("no tx receipt"); + }, + Err(err) => { + CURRENT_TEST.store(0, std::sync::atomic::Ordering::SeqCst); + panic!("{err}"); + }, + }; + } + if CURRENT_TEST.load(Ordering::SeqCst) == test_id { + CURRENT_TEST.store(0, Ordering::SeqCst); + } + + // Now is safe to panic + if let Err(err) = handler.await { + // Resume the panic on the main task + std::panic::resume_unwind(err.into_panic()); } } #[tokio::test] - #[sequential] + // #[sequential] async fn network_status() { - let hex_string = "0x8aab161e2a1e57367b60bd870861e3042c2513f8a856f9fee014e7b96e0a2a36"; - // Remove the "0x" prefix - let hex_string = &hex_string[2..]; - let mut result = [0; 32]; - // Parse the hexadecimal string into a Vec - let bytes = hex::decode(hex_string).expect("Failed to decode hex string"); - result.copy_from_slice(&bytes); - - match MaybeWsEthereumClient::new("arbitrum", "dev", "ws://127.0.0.1:8548", Some(result)) + run_test(async { + let private_key = create_account!("network_status", 20 * u128::pow(10, 18)); + let client = MaybeWsEthereumClient::new( + "arbitrum", + "dev", + "ws://127.0.0.1:8548", + Some(private_key), + ) .await - { - Ok(client) => { - // The client was successfully created, continue with the rest of the function - // ... - println!("Client created successfully"); - // Check if the genesis is consistent - let expected_genesis = client.genesis_block().clone(); - tracing::info!("expected_genesis=> {expected_genesis:?}"); - let actual_genesis = client - .block(&PartialBlockIdentifier { index: Some(0), hash: None }) - .await - .unwrap() - .block_identifier; - - tracing::info!("actual_genesis=> {actual_genesis:?}"); - assert_eq!(expected_genesis, actual_genesis); - // Check if the current block is consistent - let expected_current = client.current_block().await.unwrap(); - tracing::info!("expected_current=> {expected_current:?}"); - let actual_current = client - .block(&PartialBlockIdentifier { - index: None, - hash: Some(expected_current.hash.clone()), - }) - .await; - match actual_current { - Ok(block) => { - tracing::info!("actual_current=> {:?}", block.block_identifier); - assert_eq!(expected_current, block.block_identifier); - }, - Err(error) => { - tracing::error!("{error:?}"); - }, - } + .expect("Error creating client"); + // Check if the genesis is consistent + let expected_genesis = client.genesis_block().clone(); + let actual_genesis = client + .block(&PartialBlockIdentifier { index: Some(0), hash: None }) + .await + .unwrap() + .block_identifier; - // Check if the finalized block is consistent - let expected_finalized = client.finalized_block().await.unwrap(); - tracing::info!("expected_finalized=> {expected_finalized:?}"); - let actual_finalized = client - .block(&PartialBlockIdentifier { - index: None, - hash: Some(expected_finalized.hash.clone()), - }) - .await; - - match actual_finalized { - Ok(block) => { - tracing::info!("actual_finalized=> {:?}", block.block_identifier); - assert_eq!(expected_finalized, block.block_identifier); - }, - Err(error) => { - tracing::error!("ad{error:?}"); - }, - } + assert_eq!(expected_genesis, actual_genesis); + // Check if the current block is consistent + let expected_current = client.current_block().await.unwrap(); + let actual_current = client + .block(&PartialBlockIdentifier { index: None, hash: Some(expected_current.hash) }) + .await + .unwrap(); + assert_eq!(expected_current, actual_current.block_identifier); - tracing::info!("Arbitrum network is up and running"); - }, - Err(err) => { - // An error occurred while creating the client, handle the error here - eprintln!("Error creating client: {err:?}"); - }, - } + // Check if the finalized block is consistent + let expected_finalized = client.finalized_block().await.unwrap(); + let actual_finalized = client + .block(&PartialBlockIdentifier { index: None, hash: Some(expected_finalized.hash) }) + .await + .unwrap(); + assert_eq!(expected_finalized, actual_finalized.block_identifier); + }) + .await; } #[tokio::test] - #[sequential] + // #[sequential] async fn test_account() { - let (stop_tx, mut stop_rx) = tokio::sync::oneshot::channel::<()>(); - let handler = tokio::spawn(async move { - run_test(async {}, stop_rx).await; - }); - let hex_string = "0x8aab161e2a1e57367b60bd870861e3042c2513f8a856f9fee014e7b96e0a2a36"; - // Remove the "0x" prefix - let hex_string = &hex_string[2..]; - let mut private_key_result = [0; 32]; - // Parse the hexadecimal string into a Vec - let bytes = hex::decode(hex_string).expect("Failed to decode hex string"); - private_key_result.copy_from_slice(&bytes); - let result = MaybeWsEthereumClient::new( - "arbitrum", - "dev", - "ws://127.0.0.1:8548", - Some(private_key_result), - ) - .await; - assert!(result.is_ok(), "Error creating ArbitrumClient"); - let client = result.unwrap(); - let value = 100 * u128::pow(10, client.config().currency_decimals); - let wallet = Wallet::from_config( - client.config().clone(), - "ws://127.0.0.1:8548", - None, - Some(private_key_result), - ) + run_test(async { + let private_key = create_account!("test_account", 20 * u128::pow(10, 18)); + let client = MaybeWsEthereumClient::new( + "arbitrum", + "dev", + "ws://127.0.0.1:8548", + Some(private_key), + ) + .await + .expect("Error creating ArbitrumClient"); + let wallet = Wallet::from_config( + client.config().clone(), + "ws://127.0.0.1:8548", + None, + Some(private_key), + ) + .await + .unwrap(); + let value = 10 * u128::pow(10, client.config().currency_decimals); + let _ = wallet.faucet(value).await; + let amount = wallet.balance().await.unwrap(); + assert_eq!((amount.value), (value).to_string()); + assert_eq!(amount.currency, client.config().currency()); + assert!(amount.metadata.is_none()); + }) .await; - match wallet { - Ok(w) => { - let _ = w.faucet(value).await; - let amount = w.balance().await.unwrap(); - assert_eq!((amount.value), (value).to_string()); - assert_eq!(amount.currency, client.config().currency()); - assert!(amount.metadata.is_none()); - }, - Err(e) => { - println!("Error : {e:?}"); - }, - } - stop_tx.send(()).expect("Failed to send stop signal"); - handler.await.expect("Failed to join the background task"); } fn compile_snippet(source: &str) -> Result> { @@ -276,132 +353,105 @@ mod tests { Ok(bytecode) } - #[allow(clippy::needless_raw_string_hashes)] #[tokio::test] - #[sequential] + // #[sequential] async fn test_smart_contract() { - let (stop_tx, mut stop_rx) = tokio::sync::oneshot::channel::<()>(); - let handler = tokio::spawn(async move { - run_test(async {}, stop_rx).await; - }); - let hex_string = "0x8aab161e2a1e57367b60bd870861e3042c2513f8a856f9fee014e7b96e0a2a36"; - // Remove the "0x" prefix - let hex_string = &hex_string[2..]; - let mut private_key_result = [0; 32]; - // Parse the hexadecimal string into a Vec - let bytes = hex::decode(hex_string).expect("Failed to decode hex string"); - private_key_result.copy_from_slice(&bytes); - let result = MaybeWsEthereumClient::new( - "arbitrum", - "dev", - "ws://127.0.0.1:8548", - Some(private_key_result), - ) + run_test(async { + let private_key = create_account!("test_smart_contract", 20 * u128::pow(10, 18)); + let client = MaybeWsEthereumClient::new( + "arbitrum", + "dev", + "ws://127.0.0.1:8548", + Some(private_key), + ) + .await + .expect("Error creating ArbitrumClient"); + let faucet = 10 * u128::pow(10, client.config().currency_decimals); + let wallet = Wallet::from_config( + client.config().clone(), + "ws://127.0.0.1:8548", + None, + Some(private_key), + ) + .await + .unwrap(); + wallet.faucet(faucet).await.unwrap(); + + let bytes = compile_snippet( + r" + event AnEvent(); + function emitEvent() public { + emit AnEvent(); + } + ", + ) + .unwrap(); + let tx_hash = wallet.eth_deploy_contract(bytes).await.unwrap(); + let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap(); + let contract_address = receipt.contract_address.unwrap(); + let tx_hash = { + let call = TestContract::emitEventCall {}; + wallet.eth_send_call(contract_address.0, call.abi_encode(), 0).await.unwrap() + }; + let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap(); + assert_eq!(receipt.logs.len(), 1); + let topic = receipt.logs[0].topics[0]; + let expected = H256(sha3::Keccak256::digest("AnEvent()").into()); + assert_eq!(topic, expected); + }) .await; - assert!(result.is_ok(), "Error creating ArbitrumClient"); - - let client = result.unwrap(); - - let faucet = 100 * u128::pow(10, client.config().currency_decimals); - let wallet = Wallet::from_config( - client.config().clone(), - "ws://127.0.0.1:8548", - None, - Some(private_key_result), - ) - .await - .unwrap(); - wallet.faucet(faucet).await.unwrap(); - - let bytes = compile_snippet( - r" - event AnEvent(); - function emitEvent() public { - emit AnEvent(); - } - ", - ) - .unwrap(); - let tx_hash = wallet.eth_deploy_contract(bytes).await.unwrap(); - let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap(); - let contract_address = receipt.contract_address.unwrap(); - let tx_hash = { - let call = TestContract::emitEventCall {}; - wallet.eth_send_call(contract_address.0, call.abi_encode(), 0).await.unwrap() - }; - let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap(); - assert_eq!(receipt.logs.len(), 1); - let topic = receipt.logs[0].topics[0]; - let expected = H256(sha3::Keccak256::digest("AnEvent()").into()); - assert_eq!(topic, expected); - stop_tx.send(()).expect("Failed to send stop signal"); - handler.await.expect("Failed to join the background task"); } - #[allow(clippy::needless_raw_string_hashes)] #[tokio::test] - #[sequential] + // #[sequential] async fn test_smart_contract_view() { - let (stop_tx, mut stop_rx) = tokio::sync::oneshot::channel::<()>(); - let handler = tokio::spawn(async move { - run_test(async {}, stop_rx).await; - }); - let hex_string = "0x8aab161e2a1e57367b60bd870861e3042c2513f8a856f9fee014e7b96e0a2a36"; - // Remove the "0x" prefix - let hex_string = &hex_string[2..]; - let mut private_key_result = [0; 32]; - // Parse the hexadecimal string into a Vec - let bytes = hex::decode(hex_string).expect("Failed to decode hex string"); - private_key_result.copy_from_slice(&bytes); - let result = MaybeWsEthereumClient::new( - "arbitrum", - "dev", - "ws://127.0.0.1:8548", - Some(private_key_result), - ) - .await; - assert!(result.is_ok(), "Error creating ArbitrumClient"); - let client = result.unwrap(); - let faucet = 100 * u128::pow(10, client.config().currency_decimals); - let wallet = Wallet::from_config( - client.config().clone(), - "ws://127.0.0.1:8548", - None, - Some(private_key_result), - ) - .await - .unwrap(); - wallet.faucet(faucet).await.unwrap(); - let bytes = compile_snippet( - r" - function identity(bool a) public view returns (bool) { - return a; - } - ", - ) - .unwrap(); - let tx_hash = wallet.eth_deploy_contract(bytes).await.unwrap(); - let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap(); - let contract_address = receipt.contract_address.unwrap(); - - let response = { - let call = TestContract::identityCall { a: true }; - wallet - .eth_view_call(contract_address.0, call.abi_encode(), AtBlock::Latest) - .await - .unwrap() - }; - assert_eq!( - response, - CallResult::Success( - [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1 - ] - .to_vec() + run_test(async move { + let private_key = create_account!("test_smart_contract_view", 20 * u128::pow(10, 18)); + let client = MaybeWsEthereumClient::new( + "arbitrum", + "dev", + "ws://127.0.0.1:8548", + Some(private_key), + ) + .await + .expect("Error creating ArbitrumClient"); + let faucet = 10 * u128::pow(10, client.config().currency_decimals); + let wallet = Wallet::from_config( + client.config().clone(), + "ws://127.0.0.1:8548", + None, + Some(private_key), + ) + .await + .unwrap(); + wallet.faucet(faucet).await.unwrap(); + let bytes = compile_snippet( + r" + function identity(bool a) public view returns (bool) { + return a; + } + ", ) - ); - stop_tx.send(()).expect("Failed to send stop signal"); - handler.await.expect("Failed to join the background task"); + .unwrap(); + let tx_hash = wallet.eth_deploy_contract(bytes).await.unwrap(); + let receipt = wallet.eth_transaction_receipt(tx_hash).await.unwrap().unwrap(); + let contract_address = receipt.contract_address.unwrap(); + + let response = { + let call = TestContract::identityCall { a: true }; + wallet + .eth_view_call(contract_address.0, call.abi_encode(), AtBlock::Latest) + .await + .unwrap() + }; + assert_eq!( + response, + CallResult::Success( + hex!("0000000000000000000000000000000000000000000000000000000000000001") + .to_vec() + ) + ); + }) + .await; } } diff --git a/rosetta-client/src/wallet.rs b/rosetta-client/src/wallet.rs index b3262436..fdaa87c5 100644 --- a/rosetta-client/src/wallet.rs +++ b/rosetta-client/src/wallet.rs @@ -112,17 +112,13 @@ impl Wallet { /// Returns the balance of the wallet. #[allow(clippy::missing_errors_doc)] pub async fn balance(&self) -> Result { - println!("will current_block"); let block = self.client.current_block().await?; - println!("got block: {block:?}"); let address = Address::new(self.client.config().address_format, self.account.address.clone()); let balance = match &self.client { GenericClient::Astar(client) => match block { GenericBlockIdentifier::Ethereum(block) => { - let block_identifier = PartialBlockIdentifier::from(block); - println!("will get balance: {block_identifier:?}"); - client.balance(&address, &block_identifier).await? + client.balance(&address, &PartialBlockIdentifier::from(block)).await? }, GenericBlockIdentifier::Polkadot(_) => { anyhow::bail!("[this is bug] client returned an invalid block identifier") @@ -130,8 +126,7 @@ impl Wallet { }, GenericClient::Ethereum(client) => match block { GenericBlockIdentifier::Ethereum(block) => { - let block_identifier = PartialBlockIdentifier::from(block); - client.balance(&address, &block_identifier).await? + client.balance(&address, &PartialBlockIdentifier::from(block)).await? }, GenericBlockIdentifier::Polkadot(_) => { anyhow::bail!("[this is bug] client returned an invalid block identifier") @@ -139,8 +134,7 @@ impl Wallet { }, GenericClient::Polkadot(client) => match block { GenericBlockIdentifier::Polkadot(block) => { - let block_identifier = PartialBlockIdentifier::from(block); - client.balance(&address, &block_identifier).await? + client.balance(&address, &PartialBlockIdentifier::from(block)).await? }, GenericBlockIdentifier::Ethereum(_) => { anyhow::bail!("[this is bug] client returned an invalid block identifier") diff --git a/scripts/reset_docker.sh b/scripts/reset_docker.sh index af9c542a..0fffe041 100755 --- a/scripts/reset_docker.sh +++ b/scripts/reset_docker.sh @@ -24,7 +24,7 @@ fi # Remove all containers dockerContainers=() -while IFS='' read -r line; do dockerContainers+=("${line}"); done < <(docker ps -a -q --filter status=paused) +while IFS='' read -r line; do dockerContainers+=("${line}"); done < <(docker ps -a -q) if [[ "${#dockerContainers[@]}" -gt 0 ]]; then docker rm "${dockerContainers[@]}" fi