diff --git a/crates/rpc/rpc-builder/tests/it/http.rs b/crates/rpc/rpc-builder/tests/it/http.rs index 3fa79f051d..6d04dfe6c2 100644 --- a/crates/rpc/rpc-builder/tests/it/http.rs +++ b/crates/rpc/rpc-builder/tests/it/http.rs @@ -61,12 +61,14 @@ where // Implemented EthApiClient::protocol_version(client).await.unwrap(); EthApiClient::chain_id(client).await.unwrap(); - EthApiClient::chain_id(client).await.unwrap(); EthApiClient::accounts(client).await.unwrap(); EthApiClient::block_number(client).await.unwrap(); EthApiClient::get_code(client, address, None).await.unwrap(); EthApiClient::send_raw_transaction(client, tx).await.unwrap(); EthApiClient::fee_history(client, 0.into(), block_number.into(), None).await.unwrap(); + EthApiClient::balance(client, address, None).await.unwrap(); + EthApiClient::transaction_count(client, address, None).await.unwrap(); + EthApiClient::storage_at(client, address, U256::default(), None).await.unwrap(); // Unimplemented assert!(is_unimplemented(EthApiClient::syncing(client).await.err().unwrap())); @@ -109,13 +111,6 @@ where .unwrap() )); assert!(is_unimplemented(EthApiClient::transaction_receipt(client, hash).await.err().unwrap())); - assert!(is_unimplemented(EthApiClient::balance(client, address, None).await.err().unwrap())); - assert!(is_unimplemented( - EthApiClient::storage_at(client, address, U256::default(), None).await.err().unwrap() - )); - assert!(is_unimplemented( - EthApiClient::transaction_count(client, address, None).await.err().unwrap() - )); assert!(is_unimplemented( EthApiClient::call(client, call_request.clone(), None).await.err().unwrap() )); diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index 12f0c77c46..2ad83a976a 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -130,25 +130,25 @@ where Err(internal_rpc_err("unimplemented")) } - async fn balance(&self, _address: Address, _block_number: Option) -> Result { - Err(internal_rpc_err("unimplemented")) + async fn balance(&self, address: Address, block_number: Option) -> Result { + Ok(EthApi::balance(self, address, block_number)?) } async fn storage_at( &self, - _address: Address, - _index: U256, - _block_number: Option, + address: Address, + index: U256, + block_number: Option, ) -> Result { - Err(internal_rpc_err("unimplemented")) + Ok(EthApi::storage_at(self, address, index, block_number)?) } async fn transaction_count( &self, - _address: Address, - _block_number: Option, + address: Address, + block_number: Option, ) -> Result { - Err(internal_rpc_err("unimplemented")) + Ok(EthApi::get_transaction_count(self, address, block_number)?) } async fn get_code(&self, address: Address, block_number: Option) -> Result { diff --git a/crates/rpc/rpc/src/eth/api/state.rs b/crates/rpc/rpc/src/eth/api/state.rs index 7d38deb887..39d14ef1e5 100644 --- a/crates/rpc/rpc/src/eth/api/state.rs +++ b/crates/rpc/rpc/src/eth/api/state.rs @@ -4,7 +4,6 @@ use crate::{ eth::error::{EthApiError, EthResult}, EthApi, }; -use reth_interfaces::Result; use reth_primitives::{rpc::BlockId, Address, Bytes, H256, U256}; use reth_provider::{BlockProvider, StateProvider, StateProviderFactory}; @@ -19,12 +18,34 @@ where Ok(code) } - async fn storage_at( + pub(crate) fn balance(&self, address: Address, block_id: Option) -> EthResult { + let state = + self.state_at_block_id_or_latest(block_id)?.ok_or(EthApiError::UnknownBlockNumber)?; + let balance = state.account_balance(address)?.unwrap_or_default(); + Ok(balance) + } + + pub(crate) fn get_transaction_count( &self, - _address: Address, - _index: U256, - _block_number: Option, - ) -> Result { - todo!() + address: Address, + block_id: Option, + ) -> EthResult { + let state = + self.state_at_block_id_or_latest(block_id)?.ok_or(EthApiError::UnknownBlockNumber)?; + let nonce = U256::from(state.account_nonce(address)?.unwrap_or_default()); + Ok(nonce) + } + + pub(crate) fn storage_at( + &self, + address: Address, + index: U256, + block_id: Option, + ) -> EthResult { + let state = + self.state_at_block_id_or_latest(block_id)?.ok_or(EthApiError::UnknownBlockNumber)?; + let storage_key = H256(index.to_be_bytes()); + let value = state.storage(address, storage_key)?.unwrap_or_default(); + Ok(H256(value.to_be_bytes())) } } diff --git a/crates/storage/provider/src/traits/state.rs b/crates/storage/provider/src/traits/state.rs index 4fb2faec12..dd050c6332 100644 --- a/crates/storage/provider/src/traits/state.rs +++ b/crates/storage/provider/src/traits/state.rs @@ -3,7 +3,7 @@ use crate::BlockHashProvider; use auto_impl::auto_impl; use reth_interfaces::Result; use reth_primitives::{ - Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, H256, KECCAK_EMPTY, + Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, H256, KECCAK_EMPTY, U256, }; /// An abstraction for a type that provides state data. @@ -37,6 +37,30 @@ pub trait StateProvider: BlockHashProvider + AccountProvider + Send + Sync { // Return `None` if no code hash is set Ok(None) } + + /// Get account balance by its address. + /// + /// Returns `None` if the account doesn't exist + fn account_balance(&self, addr: Address) -> Result> { + // Get basic account information + // Returns None if acc doesn't exist + match self.basic_account(addr)? { + Some(acc) => Ok(Some(acc.balance)), + None => Ok(None), + } + } + + /// Get account nonce by its address. + /// + /// Returns `None` if the account doesn't exist + fn account_nonce(&self, addr: Address) -> Result> { + // Get basic account information + // Returns None if acc doesn't exist + match self.basic_account(addr)? { + Some(acc) => Ok(Some(acc.nonce)), + None => Ok(None), + } + } } /// Light wrapper that returns `StateProvider` implementations that correspond to the given