From 0f9605add2ae244f8f8e966eb73e7ca429370c65 Mon Sep 17 00:00:00 2001 From: lesa-telos Date: Thu, 21 Nov 2024 16:47:23 +0100 Subject: [PATCH] Integration tests (#71) * Add test for eip1559 and eip2930 transaction types. * Add double approve test. * Improve approve test. --------- Co-authored-by: lesa-telos --- crates/telos/node/tests/live_test_runner.rs | 137 ++++++++++++++++++-- 1 file changed, 129 insertions(+), 8 deletions(-) diff --git a/crates/telos/node/tests/live_test_runner.rs b/crates/telos/node/tests/live_test_runner.rs index 7c0012991087..4ba71a7f2c3a 100644 --- a/crates/telos/node/tests/live_test_runner.rs +++ b/crates/telos/node/tests/live_test_runner.rs @@ -1,16 +1,21 @@ -use alloy_network::{ReceiptResponse, TransactionBuilder}; -use alloy_primitives::U256; +use std::fmt::Debug; +use std::str::FromStr; +use alloy_contract::private::Transport; +use alloy_network::{Ethereum, ReceiptResponse, TransactionBuilder}; +use alloy_primitives::{keccak256, Address, B256, U256}; use alloy_provider::network::EthereumWallet; use alloy_provider::{Provider, ProviderBuilder}; -use alloy_rpc_types::TransactionRequest; +use alloy_rpc_types::{TransactionRequest}; use alloy_signer_local::PrivateKeySigner; -use alloy_sol_types::private::primitives::TxKind::Create; +use alloy_sol_types::private::primitives::TxKind::{Create}; use alloy_sol_types::{sol, SolEvent}; -use reqwest::Url; -use reth::primitives::BlockId; use reth::rpc::types::{BlockTransactionsKind, TransactionInput}; -use std::str::FromStr; +use reqwest::{Url}; use tracing::info; +use reth::primitives::BlockId; +use reth::primitives::BlockNumberOrTag::Latest; +use reth::primitives::revm_primitives::bytes::Bytes; +use reth::revm::primitives::{AccessList, AccessListItem}; #[tokio::test] pub async fn run_local() { @@ -92,7 +97,7 @@ pub async fn test_blocknum_onchain(url: &str, private_key: &str) { ..Default::default() }; - let deploy_result = provider.send_transaction(legacy_tx_request).await.unwrap(); + let deploy_result = provider.send_transaction(legacy_tx_request.clone()).await.unwrap(); let deploy_tx_hash = deploy_result.tx_hash(); info!("Deployed contract with tx hash: {deploy_tx_hash}"); @@ -125,10 +130,126 @@ pub async fn test_blocknum_onchain(url: &str, private_key: &str) { assert_eq!(U256::from(rpc_block_num), block_num_event.number); info!("Block numbers match inside transaction event"); + // test eip1559 transaction which is not supported + test_1559_tx(provider.clone(), address).await; + // test eip2930 transaction which is not supported + test_2930_tx(provider.clone(), address).await; + // test double approve erc20 call + test_double_approve_erc20(provider.clone(), address).await; // The below needs to be done using LegacyTransaction style call... with the current code it's including base_fee_per_gas and being rejected by reth // let block_num_latest = block_num_checker.getBlockNum().call().await.unwrap(); // assert!(block_num_latest._0 > U256::from(rpc_block_num), "Latest block number via call to getBlockNum is not greater than the block number in the previous log event"); // // let block_num_five_back = block_num_checker.getBlockNum().call().block(BlockId::number(rpc_block_num - 5)).await.unwrap(); // assert!(block_num_five_back._0 == U256::from(rpc_block_num - 5), "Block number 5 blocks back via historical eth_call is not correct"); + +} + +// test_1559_tx tests sending eip1559 transaction that has max_priority_fee_per_gas and max_fee_per_gas set +pub async fn test_1559_tx(provider: impl Provider + Send + Sync, sender_address: Address) +where + T: Transport + Clone + Debug, +{ + let nonce = provider.get_transaction_count(sender_address).await.unwrap(); + let chain_id = provider.get_chain_id().await.unwrap(); + let to_address: Address = Address::from_str("0x23CB6AE34A13a0977F4d7101eBc24B87Bb23F0d4").unwrap(); + + let tx = TransactionRequest::default() + .with_to(to_address) + .with_nonce(nonce) + .with_chain_id(chain_id) + .with_value(U256::from(100)) + .with_gas_limit(21_000) + .with_max_priority_fee_per_gas(1_000_000_000) + .with_max_fee_per_gas(20_000_000_000); + + let tx_result = provider.send_transaction(tx).await; + assert!(tx_result.is_err()); +} + +// test_2930_tx tests sending eip2930 transaction which has access_list provided +pub async fn test_2930_tx(provider: impl Provider + Send + Sync, sender_address: Address) +where + T: Transport + Clone + Debug, + +{ + let nonce = provider.get_transaction_count(sender_address).await.unwrap(); + let chain_id = provider.get_chain_id().await.unwrap(); + let gas_price = provider.get_gas_price().await.unwrap(); + + let to_address: Address = Address::from_str("0x23CB6AE34A13a0977F4d7101eBc24B87Bb23F0d4").unwrap(); + let tx = TransactionRequest::default() + .to(to_address) + .nonce(nonce) + .value(U256::from(1e17)) + .with_chain_id(chain_id) + .with_gas_price(gas_price) + .with_gas_limit(20_000_000) + .max_priority_fee_per_gas(1e11 as u128) + .with_access_list(AccessList::from(vec![AccessListItem { address: to_address, storage_keys: vec![B256::ZERO] }])) + .max_fee_per_gas(2e9 as u128); + let tx_result = provider.send_transaction(tx).await; + assert!(tx_result.is_err()); } + + +// test_double_approve_erc20 sends 2 transactions for approve on the ERC20 token and asserts that only once it is success +pub async fn test_double_approve_erc20( + provider: impl Provider + Send + Sync, + sender_address: Address, +) where + T: Transport + Clone + Debug, +{ + let nonce = provider.get_transaction_count(sender_address).await.unwrap(); + let chain_id = provider.get_chain_id().await.unwrap(); + let gas_price = provider.get_gas_price().await.unwrap(); + + let erc20_contract_address: Address = + "0x49f54c5e2301eb9256438123e80762470c2c7ec2".parse().unwrap(); + let spender: Address = "0x23CB6AE34A13a0977F4d7101eBc24B87Bb23F0d4".parse().unwrap(); + let function_signature = "approve(address,uint256)"; + let amount: U256 = U256::from(0); + let selector = &keccak256(function_signature.as_bytes())[..4]; + let amount_bytes: [u8; 32] = amount.to_be_bytes(); + let mut encoded_data = Vec::new(); + encoded_data.extend_from_slice(selector); + encoded_data.extend_from_slice(spender.as_ref()); + encoded_data.extend_from_slice(&amount_bytes); + let input_data = Bytes::from(encoded_data); + + // Build approve transaction + let mut tx = TransactionRequest::default() + .to(erc20_contract_address) + .with_input(input_data) + .nonce(nonce) + .value(U256::from(10)) + .with_chain_id(chain_id) + .with_gas_price(gas_price) + .with_gas_limit(20_000_000); + + // call approve + let tx_result = provider.send_transaction(tx.clone()).await; + assert!(tx_result.is_ok()); + let receipt1 = tx_result.unwrap().get_receipt().await; + assert!(receipt1.is_ok()); + + let nonce = provider.get_transaction_count(sender_address).await.unwrap(); + tx.nonce = Some(nonce); + + // repeat approve + let tx_result = provider.send_transaction(tx.clone()).await; + assert!(tx_result.is_ok()); + + let receipt2 = tx_result.unwrap().get_receipt().await; + assert!(receipt2.is_ok()); + + let block_number = receipt2.unwrap().block_number.unwrap(); + + // make sure the block is included + while let Some(block) = provider.get_block_by_number(Latest, false).await.unwrap() { + if block.header.number == block_number { + break; + } + } +} +