From 1f5fb90bc83dd48d38e2f376790125d68ba92f3e Mon Sep 17 00:00:00 2001 From: greged93 <82421016+greged93@users.noreply.github.com> Date: Wed, 21 Aug 2024 00:41:01 -0700 Subject: [PATCH] fix: getAccount (#10402) --- crates/rpc/rpc-builder/tests/it/http.rs | 1 + crates/rpc/rpc-eth-api/src/core.rs | 4 +- crates/rpc/rpc-eth-api/src/helpers/state.rs | 11 ++-- crates/rpc/rpc/src/eth/helpers/state.rs | 73 +++++++++++++++------ 4 files changed, 62 insertions(+), 27 deletions(-) diff --git a/crates/rpc/rpc-builder/tests/it/http.rs b/crates/rpc/rpc-builder/tests/it/http.rs index fa4ade38ef..9a858d5a47 100644 --- a/crates/rpc/rpc-builder/tests/it/http.rs +++ b/crates/rpc/rpc-builder/tests/it/http.rs @@ -175,6 +175,7 @@ where EthApiClient::protocol_version(client).await.unwrap(); EthApiClient::chain_id(client).await.unwrap(); EthApiClient::accounts(client).await.unwrap(); + EthApiClient::get_account(client, address, block_number.into()).await.unwrap(); EthApiClient::block_number(client).await.unwrap(); EthApiClient::get_code(client, address, None).await.unwrap(); EthApiClient::send_raw_transaction(client, tx).await.unwrap(); diff --git a/crates/rpc/rpc-eth-api/src/core.rs b/crates/rpc/rpc-eth-api/src/core.rs index 30c51a9f7e..1a1e914850 100644 --- a/crates/rpc/rpc-eth-api/src/core.rs +++ b/crates/rpc/rpc-eth-api/src/core.rs @@ -262,7 +262,7 @@ pub trait EthApi { &self, address: Address, block: BlockId, - ) -> RpcResult; + ) -> RpcResult>; /// Introduced in EIP-1559, returns suggestion for the priority for dynamic fee transactions. #[method(name = "maxPriorityFeePerGas")] @@ -652,7 +652,7 @@ where &self, address: Address, block: BlockId, - ) -> RpcResult { + ) -> RpcResult> { trace!(target: "rpc::eth", "Serving eth_getAccount"); Ok(EthState::get_account(self, address, block).await?) } diff --git a/crates/rpc/rpc-eth-api/src/helpers/state.rs b/crates/rpc/rpc-eth-api/src/helpers/state.rs index 2d2c159751..1407a661b1 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/state.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/state.rs @@ -134,14 +134,13 @@ pub trait EthState: LoadState + SpawnBlocking { &self, address: Address, block_id: BlockId, - ) -> impl Future> + Send { + ) -> impl Future, Self::Error>> + Send { self.spawn_blocking_io(move |this| { let state = this.state_at_block_id(block_id)?; - let account = state - .basic_account(address) - .map_err(Self::Error::from_eth_err)? - .unwrap_or_default(); + let account = state.basic_account(address).map_err(Self::Error::from_eth_err)?; + let Some(account) = account else { return Ok(None) }; + let balance = account.balance; let nonce = account.nonce; let code_hash = account.bytecode_hash.unwrap_or(KECCAK_EMPTY); @@ -152,7 +151,7 @@ pub trait EthState: LoadState + SpawnBlocking { .hashed_storage_root(address, Default::default()) .map_err(Self::Error::from_eth_err)?; - Ok(Account { balance, nonce, code_hash, storage_root }) + Ok(Some(Account { balance, nonce, code_hash, storage_root })) }) } } diff --git a/crates/rpc/rpc/src/eth/helpers/state.rs b/crates/rpc/rpc/src/eth/helpers/state.rs index 7974fc1143..6b1a24aff0 100644 --- a/crates/rpc/rpc/src/eth/helpers/state.rs +++ b/crates/rpc/rpc/src/eth/helpers/state.rs @@ -44,7 +44,7 @@ mod tests { use super::*; use reth_evm_ethereum::EthEvmConfig; use reth_primitives::{ - constants::ETHEREUM_BLOCK_GAS_LIMIT, Address, StorageKey, StorageValue, U256, + constants::ETHEREUM_BLOCK_GAS_LIMIT, Address, StorageKey, StorageValue, KECCAK_EMPTY, U256, }; use reth_provider::test_utils::{ExtendedAccount, MockEthProvider, NoopProvider}; use reth_rpc_eth_api::helpers::EthState; @@ -53,19 +53,17 @@ mod tests { }; use reth_rpc_server_types::constants::{DEFAULT_ETH_PROOF_WINDOW, DEFAULT_PROOF_PERMITS}; use reth_tasks::pool::BlockingTaskPool; - use reth_transaction_pool::test_utils::testing_pool; + use reth_transaction_pool::test_utils::{testing_pool, TestPool}; use std::collections::HashMap; - #[tokio::test] - async fn test_storage() { - // === Noop === + fn noop_eth_api() -> EthApi { let pool = testing_pool(); let evm_config = EthEvmConfig::default(); let cache = EthStateCache::spawn(NoopProvider::default(), Default::default(), evm_config); - let eth_api = EthApi::new( + EthApi::new( NoopProvider::default(), - pool.clone(), + pool, (), cache.clone(), GasPriceOracle::new(NoopProvider::default(), Default::default(), cache.clone()), @@ -76,21 +74,20 @@ mod tests { evm_config, None, DEFAULT_PROOF_PERMITS, - ); - let address = Address::random(); - let storage = eth_api.storage_at(address, U256::ZERO.into(), None).await.unwrap(); - assert_eq!(storage, U256::ZERO.to_be_bytes()); + ) + } + + fn mock_eth_api( + accounts: HashMap, + ) -> EthApi { + let pool = testing_pool(); + let evm_config = EthEvmConfig::default(); - // === Mock === let mock_provider = MockEthProvider::default(); - let storage_value = StorageValue::from(1337); - let storage_key = StorageKey::random(); - let storage = HashMap::from([(storage_key, storage_value)]); - let account = ExtendedAccount::new(0, U256::ZERO).extend_storage(storage); - mock_provider.add_account(address, account); + mock_provider.extend_accounts(accounts); let cache = EthStateCache::spawn(mock_provider.clone(), Default::default(), evm_config); - let eth_api = EthApi::new( + EthApi::new( mock_provider.clone(), pool, (), @@ -103,10 +100,48 @@ mod tests { evm_config, None, DEFAULT_PROOF_PERMITS, - ); + ) + } + + #[tokio::test] + async fn test_storage() { + // === Noop === + let eth_api = noop_eth_api(); + let address = Address::random(); + let storage = eth_api.storage_at(address, U256::ZERO.into(), None).await.unwrap(); + assert_eq!(storage, U256::ZERO.to_be_bytes()); + + // === Mock === + let storage_value = StorageValue::from(1337); + let storage_key = StorageKey::random(); + let storage = HashMap::from([(storage_key, storage_value)]); + + let accounts = + HashMap::from([(address, ExtendedAccount::new(0, U256::ZERO).extend_storage(storage))]); + let eth_api = mock_eth_api(accounts); let storage_key: U256 = storage_key.into(); let storage = eth_api.storage_at(address, storage_key.into(), None).await.unwrap(); assert_eq!(storage, storage_value.to_be_bytes()); } + + #[tokio::test] + async fn test_get_account_missing() { + let eth_api = noop_eth_api(); + let address = Address::random(); + let account = eth_api.get_account(address, Default::default()).await.unwrap(); + assert!(account.is_none()); + } + + #[tokio::test] + async fn test_get_account_empty() { + let address = Address::random(); + let accounts = HashMap::from([(address, ExtendedAccount::new(0, U256::ZERO))]); + let eth_api = mock_eth_api(accounts); + + let account = eth_api.get_account(address, Default::default()).await.unwrap(); + let expected_account = + reth_rpc_types::Account { code_hash: KECCAK_EMPTY, ..Default::default() }; + assert_eq!(Some(expected_account), account); + } }