diff --git a/src/rust/crates/ain-evm-state/src/evm.rs b/src/rust/crates/ain-evm-state/src/evm.rs index 473fdb7ff65..d39aeb22c1c 100644 --- a/src/rust/crates/ain-evm-state/src/evm.rs +++ b/src/rust/crates/ain-evm-state/src/evm.rs @@ -9,7 +9,7 @@ use evm::{ ExitReason, }; use hex::FromHex; -use primitive_types::{H160, U256}; +use primitive_types::{H160, H256, U256}; use std::collections::BTreeMap; use std::error::Error; use std::fs::File; @@ -155,9 +155,7 @@ impl EVMHandler { for signed_tx in self.tx_queues.drain_all(context) { let tx_response = executor.exec(&signed_tx); - println!("tx_response : {:#?}", tx_response); if tx_response.exit_reason.is_succeed() { - // responses.push() tx_hashes.push(signed_tx.transaction); } else { failed_tx_hashes.push(signed_tx.transaction) @@ -194,6 +192,37 @@ impl EVMHandler { } } +impl EVMHandler { + pub fn get_account(&self, account: H160) -> MemoryAccount { + self.state + .read() + .unwrap() + .get(&account) + .unwrap_or(&MemoryAccount { + nonce: Default::default(), + balance: Default::default(), + storage: Default::default(), + code: Default::default(), + }) + .to_owned() + } + + pub fn get_code(&self, account: H160) -> Vec { + self.get_account(account).code + } + + pub fn get_storage(&self, account: H160) -> BTreeMap { + self.get_account(account).storage + } + + pub fn get_balance(&self, account: H160) -> U256 { + self.get_account(account).balance + } + pub fn get_nonce(&self, account: H160) -> U256 { + self.get_account(account).nonce + } +} + // TBD refine what vicinity we need. gas_price and origin only ? fn get_vicinity(origin: Option, gas_price: Option) -> MemoryVicinity { MemoryVicinity { diff --git a/src/rust/crates/ain-evm-state/src/traits.rs b/src/rust/crates/ain-evm-state/src/traits.rs index c1de444f021..7d463e6d5e1 100644 --- a/src/rust/crates/ain-evm-state/src/traits.rs +++ b/src/rust/crates/ain-evm-state/src/traits.rs @@ -8,14 +8,12 @@ pub trait PersistentState { use std::fmt; use std::io; -// Define a custom error type #[derive(Debug)] pub enum PersistentStateError { IoError(io::Error), BincodeError(bincode::Error), } -// Implement std::fmt::Display for PersistentStateError impl fmt::Display for PersistentStateError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -25,10 +23,8 @@ impl fmt::Display for PersistentStateError { } } -// Implement std::error::Error for PersistentStateError impl std::error::Error for PersistentStateError {} -// Implement the From trait for the required error types impl From for PersistentStateError { fn from(error: io::Error) -> Self { PersistentStateError::IoError(error) @@ -76,7 +72,6 @@ mod tests { let state = BTreeMap::new(); let path = "empty_test.bin"; - // Save to an empty file state.save_to_disk(path).unwrap(); let new_state = EVMState::load_from_disk(path).unwrap(); @@ -89,7 +84,6 @@ mod tests { let invalid_data = b"invalid_data"; let path = "invalid_file_format.bin"; - // Write invalid data to a file let mut file = File::create(path).unwrap(); file.write_all(invalid_data).unwrap(); diff --git a/src/rust/crates/ain-evm-state/tests/block.rs b/src/rust/crates/ain-evm-state/tests/block.rs index f8ebe61dae9..b7455d38063 100644 --- a/src/rust/crates/ain-evm-state/tests/block.rs +++ b/src/rust/crates/ain-evm-state/tests/block.rs @@ -1,5 +1,7 @@ +use std::str::FromStr; + use ain_evm::transaction::SignedTx; -use primitive_types::U256; +use primitive_types::{H160, H256, U256}; use ain_evm_state::handler::Handlers; @@ -16,7 +18,6 @@ fn test_finalize_block_and_do_not_update_state() { ); let tx1: SignedTx = "f86b02830186a0830186a094a8f7c4c78c36e54c3950ad58dad24ca5e0191b2989056bc75e2d631000008025a0b0842b0c78dd7fc33584ec9a81ab5104fe70169878de188ba6c11fe7605e298aa0735dc483f625f17d68d1e1fae779b7160612628e6dde9eecf087892fe60bba4e".try_into().unwrap(); - println!("tx1 : {:#?}", tx1); handler.evm.tx_queues.add_signed_tx(context, tx1); let old_state = handler.evm.state.read().unwrap(); @@ -108,3 +109,55 @@ fn test_finalize_block_and_update_state() { U256::from_str_radix("0", 10).unwrap() ); } + +#[test] +fn test_deploy_and_call_smart_contract() { + let smart_contract_address: H160 = "69762793de93f55ab919c5efdaafb63d413dcbb5".parse().unwrap(); + + let handler = Handlers::new(); + let context = handler.evm.get_context(); + handler.evm.add_balance( + context, + "0x4a1080c5533cb89edc4b65013f08f78868e382de" + .parse() + .unwrap(), + U256::from_str_radix("100000000000000000000", 10).unwrap(), + ); + + // Create simple storage smart contract + let create_smart_contract_tx: SignedTx = "f9044e808504a817c800832dc6c08080b903fb608060405234801561001057600080fd5b506103db806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063131a06801461003b5780632e64cec114610050575b600080fd5b61004e61004936600461015d565b61006e565b005b6100586100b5565b604051610065919061020e565b60405180910390f35b600061007a82826102e5565b507ffe3101cc3119e1fe29a9c3464a3ff7e98501e65122abab6937026311367dc516816040516100aa919061020e565b60405180910390a150565b6060600080546100c49061025c565b80601f01602080910402602001604051908101604052809291908181526020018280546100f09061025c565b801561013d5780601f106101125761010080835404028352916020019161013d565b820191906000526020600020905b81548152906001019060200180831161012057829003601f168201915b5050505050905090565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561016f57600080fd5b813567ffffffffffffffff8082111561018757600080fd5b818401915084601f83011261019b57600080fd5b8135818111156101ad576101ad610147565b604051601f8201601f19908116603f011681019083821181831017156101d5576101d5610147565b816040528281528760208487010111156101ee57600080fd5b826020860160208301376000928101602001929092525095945050505050565b600060208083528351808285015260005b8181101561023b5785810183015185820160400152820161021f565b506000604082860101526040601f19601f8301168501019250505092915050565b600181811c9082168061027057607f821691505b60208210810361029057634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156102e057600081815260208120601f850160051c810160208610156102bd5750805b601f850160051c820191505b818110156102dc578281556001016102c9565b5050505b505050565b815167ffffffffffffffff8111156102ff576102ff610147565b6103138161030d845461025c565b84610296565b602080601f83116001811461034857600084156103305750858301515b600019600386901b1c1916600185901b1785556102dc565b600085815260208120601f198616915b8281101561037757888601518255948401946001909101908401610358565b50858210156103955787850151600019600388901b60f8161c191681555b5050505050600190811b0190555056fea2646970667358221220f5c9bb4feb3fa563cfe06a38d411044d98edf92f98726288036607edd71587b564736f6c634300081100332aa06aa3b6274fbd96df7215c2b791c766e21a65d97467ddbd90c0d869ba51d04387a05512f44e35c5ab3c1716373877503d03a5f9ebdf5b7645e8fb30b308a6f046f8".try_into().unwrap(); + handler + .evm + .tx_queues + .add_signed_tx(context, create_smart_contract_tx); + + handler.evm.finalize_block(context, true).unwrap(); + + // Fund caller address + handler.evm.add_balance( + context, + "0xb069baef499f992ff243300f78cf9ca1406a122e" + .parse() + .unwrap(), + U256::from_str_radix("100000000000000000000000000", 10).unwrap(), + ); + let call_smart_contract_tx: SignedTx = "f8ca018504a817c8008302c1789469762793de93f55ab919c5efdaafb63d413dcbb580b864131a06800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000d48656c6c6f2c20576f726c64210000000000000000000000000000000000000029a041fc9c0581885d77263dcba0603d8c6c164a9acfe803ad11188069eafa22169ca0018c1ba512639bd8ce32e76bcc2ea0759073a3f908014e47544d6c6674388b37".try_into().unwrap(); + + // Each block requires a new context + let context = handler.evm.get_context(); + handler + .evm + .tx_queues + .add_signed_tx(context, call_smart_contract_tx); + + handler.evm.finalize_block(context, true).unwrap(); + + let smart_contract_storage = handler.evm.get_storage(smart_contract_address); + assert_eq!( + smart_contract_storage.get(&H256::zero()), + Some( + &H256::from_str("0x48656c6c6f2c20576f726c64210000000000000000000000000000000000001a") + .unwrap() + ) + ) +}