Skip to content

Commit

Permalink
fix: getAccount (#10402)
Browse files Browse the repository at this point in the history
  • Loading branch information
greged93 authored Aug 21, 2024
1 parent a6689e6 commit 1f5fb90
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 27 deletions.
1 change: 1 addition & 0 deletions crates/rpc/rpc-builder/tests/it/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
4 changes: 2 additions & 2 deletions crates/rpc/rpc-eth-api/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ pub trait EthApi {
&self,
address: Address,
block: BlockId,
) -> RpcResult<reth_rpc_types::Account>;
) -> RpcResult<Option<reth_rpc_types::Account>>;

/// Introduced in EIP-1559, returns suggestion for the priority for dynamic fee transactions.
#[method(name = "maxPriorityFeePerGas")]
Expand Down Expand Up @@ -652,7 +652,7 @@ where
&self,
address: Address,
block: BlockId,
) -> RpcResult<reth_rpc_types::Account> {
) -> RpcResult<Option<reth_rpc_types::Account>> {
trace!(target: "rpc::eth", "Serving eth_getAccount");
Ok(EthState::get_account(self, address, block).await?)
}
Expand Down
11 changes: 5 additions & 6 deletions crates/rpc/rpc-eth-api/src/helpers/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,14 +134,13 @@ pub trait EthState: LoadState + SpawnBlocking {
&self,
address: Address,
block_id: BlockId,
) -> impl Future<Output = Result<Account, Self::Error>> + Send {
) -> impl Future<Output = Result<Option<Account>, 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);
Expand All @@ -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 }))
})
}
}
Expand Down
73 changes: 54 additions & 19 deletions crates/rpc/rpc/src/eth/helpers/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<NoopProvider, TestPool, (), EthEvmConfig> {
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()),
Expand All @@ -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<Address, ExtendedAccount>,
) -> EthApi<MockEthProvider, TestPool, (), EthEvmConfig> {
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,
(),
Expand All @@ -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);
}
}

0 comments on commit 1f5fb90

Please sign in to comment.