mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(rpc): enable eth_call eth_estimateGas (#1799)
This commit is contained in:
@ -82,21 +82,23 @@ where
|
||||
EthApiClient::sign_typed_data(client, address, jsonrpsee::core::JsonValue::Null)
|
||||
.await
|
||||
.unwrap_err();
|
||||
EthApiClient::create_access_list(client, call_request.clone(), None).await.unwrap();
|
||||
EthApiClient::transaction_by_hash(client, tx_hash).await.unwrap();
|
||||
EthApiClient::transaction_by_block_hash_and_index(client, hash, index).await.unwrap();
|
||||
EthApiClient::transaction_by_block_number_and_index(client, block_number, index).await.unwrap();
|
||||
EthApiClient::create_access_list(client, call_request.clone(), Some(block_number.into()))
|
||||
.await
|
||||
.unwrap();
|
||||
EthApiClient::estimate_gas(client, call_request.clone(), Some(block_number.into()))
|
||||
.await
|
||||
.unwrap();
|
||||
EthApiClient::call(client, call_request.clone(), Some(block_number.into()), None)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
// Unimplemented
|
||||
assert!(is_unimplemented(EthApiClient::syncing(client).await.err().unwrap()));
|
||||
assert!(is_unimplemented(EthApiClient::author(client).await.err().unwrap()));
|
||||
assert!(is_unimplemented(EthApiClient::transaction_receipt(client, hash).await.err().unwrap()));
|
||||
assert!(is_unimplemented(
|
||||
EthApiClient::call(client, call_request.clone(), None, None).await.err().unwrap()
|
||||
));
|
||||
assert!(is_unimplemented(
|
||||
EthApiClient::estimate_gas(client, call_request.clone(), None).await.err().unwrap()
|
||||
));
|
||||
assert!(is_unimplemented(EthApiClient::gas_price(client).await.err().unwrap()));
|
||||
assert!(is_unimplemented(EthApiClient::max_priority_fee_per_gas(client).await.err().unwrap()));
|
||||
assert!(is_unimplemented(EthApiClient::is_mining(client).await.err().unwrap()));
|
||||
|
||||
@ -39,7 +39,7 @@ where
|
||||
Network: Send + Sync + 'static,
|
||||
{
|
||||
/// Executes the call request at the given [BlockId]
|
||||
pub(crate) async fn call_at(
|
||||
pub(crate) async fn execute_call_at(
|
||||
&self,
|
||||
request: CallRequest,
|
||||
at: BlockId,
|
||||
@ -165,14 +165,8 @@ where
|
||||
ExecutionResult::Success { .. } => {
|
||||
// succeeded
|
||||
}
|
||||
ExecutionResult::Halt { reason, .. } => {
|
||||
return match reason {
|
||||
Halt::OutOfGas(err) => {
|
||||
Err(InvalidTransactionError::out_of_gas(err, gas_limit).into())
|
||||
}
|
||||
Halt::NonceOverflow => Err(InvalidTransactionError::NonceMaxValue.into()),
|
||||
err => Err(InvalidTransactionError::EvmHalt(err).into()),
|
||||
}
|
||||
ExecutionResult::Halt { reason, gas_used } => {
|
||||
return Err(InvalidTransactionError::halt(reason, gas_used).into())
|
||||
}
|
||||
ExecutionResult::Revert { output, .. } => {
|
||||
// if price or limit was included in the request then we can execute the request
|
||||
|
||||
@ -5,7 +5,7 @@ use super::EthApiSpec;
|
||||
use crate::{
|
||||
eth::{
|
||||
api::{EthApi, EthTransactions},
|
||||
error::EthApiError,
|
||||
error::{ensure_success, EthApiError},
|
||||
},
|
||||
result::{internal_rpc_err, ToRpcResult},
|
||||
};
|
||||
@ -179,11 +179,19 @@ where
|
||||
/// Handler for: `eth_call`
|
||||
async fn call(
|
||||
&self,
|
||||
_request: CallRequest,
|
||||
_block_number: Option<BlockId>,
|
||||
_state_overrides: Option<StateOverride>,
|
||||
request: CallRequest,
|
||||
block_number: Option<BlockId>,
|
||||
state_overrides: Option<StateOverride>,
|
||||
) -> Result<Bytes> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
let (res, _env) = self
|
||||
.execute_call_at(
|
||||
request,
|
||||
block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Pending)),
|
||||
state_overrides,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(ensure_success(res.result)?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_createAccessList`
|
||||
@ -192,7 +200,7 @@ where
|
||||
mut request: CallRequest,
|
||||
block_number: Option<BlockId>,
|
||||
) -> Result<AccessListWithGasUsed> {
|
||||
let block_id = block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest));
|
||||
let block_id = block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Pending));
|
||||
let access_list = self.create_access_list_at(request.clone(), block_number).await?;
|
||||
request.access_list = Some(access_list.clone());
|
||||
let gas_used = self.estimate_gas_at(request, block_id).await?;
|
||||
@ -202,10 +210,15 @@ where
|
||||
/// Handler for: `eth_estimateGas`
|
||||
async fn estimate_gas(
|
||||
&self,
|
||||
_request: CallRequest,
|
||||
_block_number: Option<BlockId>,
|
||||
request: CallRequest,
|
||||
block_number: Option<BlockId>,
|
||||
) -> Result<U256> {
|
||||
Err(internal_rpc_err("unimplemented"))
|
||||
Ok(EthApi::estimate_gas_at(
|
||||
self,
|
||||
request,
|
||||
block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Pending)),
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
|
||||
/// Handler for: `eth_gasPrice`
|
||||
|
||||
@ -2,10 +2,10 @@
|
||||
|
||||
use crate::result::{internal_rpc_err, rpc_err};
|
||||
use jsonrpsee::{core::Error as RpcError, types::error::INVALID_PARAMS_CODE};
|
||||
use reth_primitives::{constants::SELECTOR_LEN, Address, U128, U256};
|
||||
use reth_primitives::{constants::SELECTOR_LEN, Address, Bytes, U128, U256};
|
||||
use reth_rpc_types::{error::EthRpcErrorCode, BlockError};
|
||||
use reth_transaction_pool::error::{InvalidPoolTransactionError, PoolError};
|
||||
use revm::primitives::{EVMError, Halt, OutOfGasError};
|
||||
use revm::primitives::{EVMError, ExecutionResult, Halt, OutOfGasError, Output};
|
||||
|
||||
/// Result alias
|
||||
pub type EthResult<T> = Result<T, EthApiError>;
|
||||
@ -191,8 +191,20 @@ impl InvalidTransactionError {
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the halt error
|
||||
///
|
||||
/// Takes the configured gas limit of the transaction which is attached to the error
|
||||
pub(crate) fn halt(reason: Halt, gas_limit: u64) -> Self {
|
||||
match reason {
|
||||
Halt::OutOfGas(err) => InvalidTransactionError::out_of_gas(err, gas_limit),
|
||||
Halt::NonceOverflow => InvalidTransactionError::NonceMaxValue,
|
||||
err => InvalidTransactionError::EvmHalt(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts the out of gas error
|
||||
pub(crate) fn out_of_gas(reason: OutOfGasError, gas_limit: U256) -> Self {
|
||||
pub(crate) fn out_of_gas(reason: OutOfGasError, gas_limit: u64) -> Self {
|
||||
let gas_limit = U256::from(gas_limit);
|
||||
match reason {
|
||||
OutOfGasError::BasicOutOfGas => InvalidTransactionError::BasicOutOfGas(gas_limit),
|
||||
OutOfGasError::Memory => InvalidTransactionError::MemoryOutOfGas(gas_limit),
|
||||
@ -352,6 +364,26 @@ pub enum SignError {
|
||||
TypedData,
|
||||
}
|
||||
|
||||
/// Converts the evm [ExecutionResult] into a result where `Ok` variant is the output bytes if it is
|
||||
/// [ExecutionResult::Success].
|
||||
pub(crate) fn ensure_success(result: ExecutionResult) -> EthResult<Bytes> {
|
||||
match result {
|
||||
ExecutionResult::Success { output, .. } => {
|
||||
let data = match output {
|
||||
Output::Call(data) => data,
|
||||
Output::Create(data, _) => data,
|
||||
};
|
||||
Ok(data.into())
|
||||
}
|
||||
ExecutionResult::Revert { output, .. } => {
|
||||
Err(InvalidTransactionError::Revert(RevertError::new(output)).into())
|
||||
}
|
||||
ExecutionResult::Halt { reason, gas_used } => {
|
||||
Err(InvalidTransactionError::halt(reason, gas_used).into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the revert reason from the `revm::TransactOut` data, if it's an abi encoded String.
|
||||
///
|
||||
/// **Note:** it's assumed the `out` buffer starts with the call's signature
|
||||
|
||||
Reference in New Issue
Block a user