mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
fix(op): fixes impl of eth api for OP (#9377)
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -7981,16 +7981,22 @@ name = "reth-optimism-rpc"
|
|||||||
version = "1.0.1"
|
version = "1.0.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"alloy-primitives",
|
"alloy-primitives",
|
||||||
|
"jsonrpsee",
|
||||||
"parking_lot 0.12.3",
|
"parking_lot 0.12.3",
|
||||||
"reth-chainspec",
|
"reth-chainspec",
|
||||||
"reth-errors",
|
"reth-errors",
|
||||||
"reth-evm",
|
"reth-evm",
|
||||||
|
"reth-evm-optimism",
|
||||||
|
"reth-primitives",
|
||||||
"reth-provider",
|
"reth-provider",
|
||||||
"reth-rpc-eth-api",
|
"reth-rpc-eth-api",
|
||||||
"reth-rpc-eth-types",
|
"reth-rpc-eth-types",
|
||||||
|
"reth-rpc-server-types",
|
||||||
"reth-rpc-types",
|
"reth-rpc-types",
|
||||||
"reth-tasks",
|
"reth-tasks",
|
||||||
"reth-transaction-pool",
|
"reth-transaction-pool",
|
||||||
|
"revm",
|
||||||
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@ -6,25 +6,47 @@ rust-version.workspace = true
|
|||||||
license.workspace = true
|
license.workspace = true
|
||||||
homepage.workspace = true
|
homepage.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
description = "Ethereum RPC implementation for optimism."
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# reth
|
# reth
|
||||||
|
reth-chainspec.workspace = true
|
||||||
reth-errors.workspace = true
|
reth-errors.workspace = true
|
||||||
|
reth-evm-optimism.workspace = true
|
||||||
reth-evm.workspace = true
|
reth-evm.workspace = true
|
||||||
|
reth-primitives.workspace = true
|
||||||
|
reth-provider.workspace = true
|
||||||
reth-rpc-eth-api.workspace = true
|
reth-rpc-eth-api.workspace = true
|
||||||
reth-rpc-eth-types.workspace = true
|
reth-rpc-eth-types.workspace = true
|
||||||
|
reth-rpc-server-types.workspace = true
|
||||||
reth-rpc-types.workspace = true
|
reth-rpc-types.workspace = true
|
||||||
reth-chainspec.workspace = true
|
|
||||||
reth-provider.workspace = true
|
|
||||||
reth-tasks = { workspace = true, features = ["rayon"] }
|
reth-tasks = { workspace = true, features = ["rayon"] }
|
||||||
reth-transaction-pool.workspace = true
|
reth-transaction-pool.workspace = true
|
||||||
|
|
||||||
# ethereum
|
# ethereum
|
||||||
alloy-primitives.workspace = true
|
alloy-primitives.workspace = true
|
||||||
|
revm.workspace = true
|
||||||
|
|
||||||
# async
|
# async
|
||||||
parking_lot.workspace = true
|
parking_lot.workspace = true
|
||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
|
|
||||||
|
# rpc
|
||||||
|
jsonrpsee.workspace = true
|
||||||
|
|
||||||
|
# misc
|
||||||
|
thiserror.workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
optimism = [
|
||||||
|
"reth-chainspec/optimism",
|
||||||
|
"reth-evm-optimism/optimism",
|
||||||
|
"reth-primitives/optimism",
|
||||||
|
"reth-provider/optimism",
|
||||||
|
"reth-rpc-eth-api/optimism",
|
||||||
|
"reth-rpc-eth-types/optimism",
|
||||||
|
"revm/optimism"
|
||||||
|
]
|
||||||
31
crates/optimism/rpc/src/error.rs
Normal file
31
crates/optimism/rpc/src/error.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//! RPC errors specific to OP.
|
||||||
|
|
||||||
|
use jsonrpsee::types::ErrorObject;
|
||||||
|
use reth_rpc_eth_types::EthApiError;
|
||||||
|
use reth_rpc_server_types::result::internal_rpc_err;
|
||||||
|
use reth_rpc_types::ToRpcError;
|
||||||
|
|
||||||
|
/// Optimism specific errors, that extend [`EthApiError`].
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum OpEthApiError {
|
||||||
|
/// Thrown when calculating L1 gas fee.
|
||||||
|
#[error("failed to calculate l1 gas fee")]
|
||||||
|
L1BlockFeeError,
|
||||||
|
/// Thrown when calculating L1 gas used
|
||||||
|
#[error("failed to calculate l1 gas used")]
|
||||||
|
L1BlockGasError,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToRpcError for OpEthApiError {
|
||||||
|
fn to_rpc_error(&self) -> ErrorObject<'static> {
|
||||||
|
match self {
|
||||||
|
Self::L1BlockFeeError | Self::L1BlockGasError => internal_rpc_err(self.to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<OpEthApiError> for EthApiError {
|
||||||
|
fn from(err: OpEthApiError) -> Self {
|
||||||
|
Self::other(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
75
crates/optimism/rpc/src/eth/block.rs
Normal file
75
crates/optimism/rpc/src/eth/block.rs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
//! Loads and formats OP block RPC response.
|
||||||
|
|
||||||
|
use reth_primitives::TransactionMeta;
|
||||||
|
use reth_provider::{BlockReaderIdExt, HeaderProvider};
|
||||||
|
use reth_rpc_eth_api::helpers::{EthApiSpec, EthBlocks, LoadBlock, LoadReceipt, LoadTransaction};
|
||||||
|
use reth_rpc_eth_types::{EthResult, EthStateCache, ReceiptBuilder};
|
||||||
|
use reth_rpc_types::{AnyTransactionReceipt, BlockId};
|
||||||
|
|
||||||
|
use crate::{op_receipt_fields, OpEthApi};
|
||||||
|
|
||||||
|
impl<Eth> EthBlocks for OpEthApi<Eth>
|
||||||
|
where
|
||||||
|
Eth: EthBlocks + EthApiSpec + LoadTransaction,
|
||||||
|
{
|
||||||
|
fn provider(&self) -> impl HeaderProvider {
|
||||||
|
EthBlocks::provider(&self.inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn block_receipts(
|
||||||
|
&self,
|
||||||
|
block_id: BlockId,
|
||||||
|
) -> EthResult<Option<Vec<AnyTransactionReceipt>>>
|
||||||
|
where
|
||||||
|
Self: LoadReceipt,
|
||||||
|
{
|
||||||
|
if let Some((block, receipts)) = self.load_block_and_receipts(block_id).await? {
|
||||||
|
let block_number = block.number;
|
||||||
|
let base_fee = block.base_fee_per_gas;
|
||||||
|
let block_hash = block.hash();
|
||||||
|
let excess_blob_gas = block.excess_blob_gas;
|
||||||
|
let timestamp = block.timestamp;
|
||||||
|
let block = block.unseal();
|
||||||
|
|
||||||
|
let l1_block_info = reth_evm_optimism::extract_l1_info(&block).ok();
|
||||||
|
|
||||||
|
let receipts = block
|
||||||
|
.body
|
||||||
|
.into_iter()
|
||||||
|
.zip(receipts.iter())
|
||||||
|
.enumerate()
|
||||||
|
.map(|(idx, (ref tx, receipt))| {
|
||||||
|
let meta = TransactionMeta {
|
||||||
|
tx_hash: tx.hash,
|
||||||
|
index: idx as u64,
|
||||||
|
block_hash,
|
||||||
|
block_number,
|
||||||
|
base_fee,
|
||||||
|
excess_blob_gas,
|
||||||
|
timestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
let optimism_tx_meta =
|
||||||
|
self.build_op_tx_meta(tx, l1_block_info.clone(), timestamp)?;
|
||||||
|
|
||||||
|
ReceiptBuilder::new(tx, meta, receipt, &receipts).map(|builder| {
|
||||||
|
op_receipt_fields(builder, tx, receipt, optimism_tx_meta).build()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<EthResult<Vec<_>>>();
|
||||||
|
return receipts.map(Some)
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Eth: LoadBlock> LoadBlock for OpEthApi<Eth> {
|
||||||
|
fn provider(&self) -> impl BlockReaderIdExt {
|
||||||
|
LoadBlock::provider(&self.inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cache(&self) -> &EthStateCache {
|
||||||
|
self.inner.cache()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,26 +1,26 @@
|
|||||||
//! OP-Reth `eth_` endpoint implementation.
|
//! OP-Reth `eth_` endpoint implementation.
|
||||||
|
|
||||||
|
pub mod receipt;
|
||||||
|
pub mod transaction;
|
||||||
|
|
||||||
|
mod block;
|
||||||
|
mod pending_block;
|
||||||
|
|
||||||
|
use std::{future::Future, sync::Arc};
|
||||||
|
|
||||||
use alloy_primitives::{Address, U64};
|
use alloy_primitives::{Address, U64};
|
||||||
use reth_chainspec::ChainInfo;
|
use reth_chainspec::{ChainInfo, ChainSpec};
|
||||||
use reth_errors::RethResult;
|
use reth_errors::RethResult;
|
||||||
use reth_evm::ConfigureEvm;
|
use reth_evm::ConfigureEvm;
|
||||||
use reth_provider::{
|
use reth_provider::{BlockReaderIdExt, ChainSpecProvider, HeaderProvider, StateProviderFactory};
|
||||||
BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, HeaderProvider, StateProviderFactory,
|
use reth_rpc_eth_api::helpers::{
|
||||||
|
Call, EthApiSpec, EthCall, EthFees, EthState, LoadFee, LoadState, SpawnBlocking, Trace,
|
||||||
};
|
};
|
||||||
use reth_rpc_eth_api::{
|
use reth_rpc_eth_types::EthStateCache;
|
||||||
helpers::{
|
|
||||||
Call, EthApiSpec, EthBlocks, EthCall, EthFees, EthSigner, EthState, EthTransactions,
|
|
||||||
LoadBlock, LoadFee, LoadPendingBlock, LoadReceipt, LoadState, LoadTransaction,
|
|
||||||
SpawnBlocking, Trace,
|
|
||||||
},
|
|
||||||
RawTransactionForwarder,
|
|
||||||
};
|
|
||||||
use reth_rpc_eth_types::{EthStateCache, PendingBlock};
|
|
||||||
use reth_rpc_types::SyncStatus;
|
use reth_rpc_types::SyncStatus;
|
||||||
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner};
|
use reth_tasks::{pool::BlockingTaskPool, TaskSpawner};
|
||||||
use reth_transaction_pool::TransactionPool;
|
use reth_transaction_pool::TransactionPool;
|
||||||
use std::future::Future;
|
use tokio::sync::{AcquireError, OwnedSemaphorePermit};
|
||||||
use tokio::sync::{AcquireError, Mutex, OwnedSemaphorePermit};
|
|
||||||
|
|
||||||
/// OP-Reth `Eth` API implementation.
|
/// OP-Reth `Eth` API implementation.
|
||||||
///
|
///
|
||||||
@ -68,35 +68,9 @@ impl<Eth: EthApiSpec> EthApiSpec for OpEthApi<Eth> {
|
|||||||
fn sync_status(&self) -> RethResult<SyncStatus> {
|
fn sync_status(&self) -> RethResult<SyncStatus> {
|
||||||
self.inner.sync_status()
|
self.inner.sync_status()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<Eth: LoadBlock> LoadBlock for OpEthApi<Eth> {
|
fn chain_spec(&self) -> Arc<ChainSpec> {
|
||||||
fn provider(&self) -> impl BlockReaderIdExt {
|
self.inner.chain_spec()
|
||||||
LoadBlock::provider(&self.inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cache(&self) -> &reth_rpc_eth_types::EthStateCache {
|
|
||||||
self.inner.cache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Eth: LoadPendingBlock> LoadPendingBlock for OpEthApi<Eth> {
|
|
||||||
fn provider(
|
|
||||||
&self,
|
|
||||||
) -> impl BlockReaderIdExt + EvmEnvProvider + ChainSpecProvider + StateProviderFactory {
|
|
||||||
self.inner.provider()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pool(&self) -> impl TransactionPool {
|
|
||||||
self.inner.pool()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pending_block(&self) -> &Mutex<Option<PendingBlock>> {
|
|
||||||
self.inner.pending_block()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn evm_config(&self) -> &impl ConfigureEvm {
|
|
||||||
self.inner.evm_config()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,12 +97,6 @@ impl<Eth: SpawnBlocking> SpawnBlocking for OpEthApi<Eth> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Eth: LoadReceipt> LoadReceipt for OpEthApi<Eth> {
|
|
||||||
fn cache(&self) -> &EthStateCache {
|
|
||||||
self.inner.cache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Eth: LoadFee> LoadFee for OpEthApi<Eth> {
|
impl<Eth: LoadFee> LoadFee for OpEthApi<Eth> {
|
||||||
fn provider(&self) -> impl reth_provider::BlockIdReader + HeaderProvider + ChainSpecProvider {
|
fn provider(&self) -> impl reth_provider::BlockIdReader + HeaderProvider + ChainSpecProvider {
|
||||||
LoadFee::provider(&self.inner)
|
LoadFee::provider(&self.inner)
|
||||||
@ -171,42 +139,6 @@ impl<Eth: LoadState> LoadState for OpEthApi<Eth> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Eth: LoadTransaction> LoadTransaction for OpEthApi<Eth> {
|
|
||||||
type Pool = Eth::Pool;
|
|
||||||
|
|
||||||
fn provider(&self) -> impl reth_provider::TransactionsProvider {
|
|
||||||
LoadTransaction::provider(&self.inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cache(&self) -> &EthStateCache {
|
|
||||||
LoadTransaction::cache(&self.inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn pool(&self) -> &Self::Pool {
|
|
||||||
LoadTransaction::pool(&self.inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Eth: EthTransactions> EthTransactions for OpEthApi<Eth> {
|
|
||||||
fn provider(&self) -> impl BlockReaderIdExt {
|
|
||||||
EthTransactions::provider(&self.inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn raw_tx_forwarder(&self) -> Option<std::sync::Arc<dyn RawTransactionForwarder>> {
|
|
||||||
self.inner.raw_tx_forwarder()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner>>> {
|
|
||||||
self.inner.signers()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Eth: EthBlocks> EthBlocks for OpEthApi<Eth> {
|
|
||||||
fn provider(&self) -> impl HeaderProvider {
|
|
||||||
EthBlocks::provider(&self.inner)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<Eth: EthState> EthState for OpEthApi<Eth> {
|
impl<Eth: EthState> EthState for OpEthApi<Eth> {
|
||||||
fn max_proof_window(&self) -> u64 {
|
fn max_proof_window(&self) -> u64 {
|
||||||
self.inner.max_proof_window()
|
self.inner.max_proof_window()
|
||||||
|
|||||||
72
crates/optimism/rpc/src/eth/pending_block.rs
Normal file
72
crates/optimism/rpc/src/eth/pending_block.rs
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
//! Loads OP pending block for a RPC response.
|
||||||
|
|
||||||
|
use reth_primitives::{
|
||||||
|
revm_primitives::{BlockEnv, ExecutionResult},
|
||||||
|
BlockNumber, Receipt, TransactionSignedEcRecovered, B256,
|
||||||
|
};
|
||||||
|
use reth_provider::{ChainSpecProvider, ExecutionOutcome};
|
||||||
|
use reth_rpc_eth_api::helpers::LoadPendingBlock;
|
||||||
|
use reth_rpc_eth_types::PendingBlock;
|
||||||
|
|
||||||
|
use crate::OpEthApi;
|
||||||
|
|
||||||
|
impl<Eth> LoadPendingBlock for OpEthApi<Eth>
|
||||||
|
where
|
||||||
|
Eth: LoadPendingBlock,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn provider(
|
||||||
|
&self,
|
||||||
|
) -> impl reth_provider::BlockReaderIdExt
|
||||||
|
+ reth_provider::EvmEnvProvider
|
||||||
|
+ reth_provider::ChainSpecProvider
|
||||||
|
+ reth_provider::StateProviderFactory {
|
||||||
|
self.inner.provider()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn pool(&self) -> impl reth_transaction_pool::TransactionPool {
|
||||||
|
self.inner.pool()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn pending_block(&self) -> &tokio::sync::Mutex<Option<PendingBlock>> {
|
||||||
|
self.inner.pending_block()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn evm_config(&self) -> &impl reth_evm::ConfigureEvm {
|
||||||
|
self.inner.evm_config()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assemble_receipt(
|
||||||
|
&self,
|
||||||
|
tx: &TransactionSignedEcRecovered,
|
||||||
|
result: ExecutionResult,
|
||||||
|
cumulative_gas_used: u64,
|
||||||
|
) -> Receipt {
|
||||||
|
Receipt {
|
||||||
|
tx_type: tx.tx_type(),
|
||||||
|
success: result.is_success(),
|
||||||
|
cumulative_gas_used,
|
||||||
|
logs: result.into_logs().into_iter().map(Into::into).collect(),
|
||||||
|
deposit_nonce: None,
|
||||||
|
deposit_receipt_version: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receipts_root(
|
||||||
|
&self,
|
||||||
|
_block_env: &BlockEnv,
|
||||||
|
execution_outcome: &ExecutionOutcome,
|
||||||
|
block_number: BlockNumber,
|
||||||
|
) -> B256 {
|
||||||
|
execution_outcome
|
||||||
|
.optimism_receipts_root_slow(
|
||||||
|
block_number,
|
||||||
|
self.provider().chain_spec().as_ref(),
|
||||||
|
_block_env.timestamp.to::<u64>(),
|
||||||
|
)
|
||||||
|
.expect("Block is present")
|
||||||
|
}
|
||||||
|
}
|
||||||
64
crates/optimism/rpc/src/eth/receipt.rs
Normal file
64
crates/optimism/rpc/src/eth/receipt.rs
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//! Loads and formats OP receipt RPC response.
|
||||||
|
|
||||||
|
use reth_primitives::{Receipt, TransactionMeta, TransactionSigned};
|
||||||
|
use reth_rpc_eth_api::helpers::{EthApiSpec, LoadReceipt, LoadTransaction};
|
||||||
|
use reth_rpc_eth_types::{EthApiError, EthResult, EthStateCache, ReceiptBuilder};
|
||||||
|
use reth_rpc_types::{AnyTransactionReceipt, OptimismTransactionReceiptFields};
|
||||||
|
|
||||||
|
use crate::{OpEthApi, OptimismTxMeta};
|
||||||
|
|
||||||
|
impl<Eth> LoadReceipt for OpEthApi<Eth>
|
||||||
|
where
|
||||||
|
Eth: LoadReceipt + EthApiSpec + LoadTransaction,
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn cache(&self) -> &EthStateCache {
|
||||||
|
LoadReceipt::cache(&self.inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn build_transaction_receipt(
|
||||||
|
&self,
|
||||||
|
tx: TransactionSigned,
|
||||||
|
meta: TransactionMeta,
|
||||||
|
receipt: Receipt,
|
||||||
|
) -> EthResult<AnyTransactionReceipt> {
|
||||||
|
let (block, receipts) = LoadReceipt::cache(self)
|
||||||
|
.get_block_and_receipts(meta.block_hash)
|
||||||
|
.await?
|
||||||
|
.ok_or(EthApiError::UnknownBlockNumber)?;
|
||||||
|
|
||||||
|
let block = block.unseal();
|
||||||
|
let l1_block_info = reth_evm_optimism::extract_l1_info(&block).ok();
|
||||||
|
let optimism_tx_meta = self.build_op_tx_meta(&tx, l1_block_info, block.timestamp)?;
|
||||||
|
|
||||||
|
let resp_builder = ReceiptBuilder::new(&tx, meta, &receipt, &receipts)?;
|
||||||
|
let resp_builder = op_receipt_fields(resp_builder, &tx, &receipt, optimism_tx_meta);
|
||||||
|
|
||||||
|
Ok(resp_builder.build())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Applies OP specific fields to a receipt.
|
||||||
|
pub fn op_receipt_fields(
|
||||||
|
resp_builder: ReceiptBuilder,
|
||||||
|
tx: &TransactionSigned,
|
||||||
|
receipt: &Receipt,
|
||||||
|
optimism_tx_meta: OptimismTxMeta,
|
||||||
|
) -> ReceiptBuilder {
|
||||||
|
let mut op_fields = OptimismTransactionReceiptFields::default();
|
||||||
|
|
||||||
|
if tx.is_deposit() {
|
||||||
|
op_fields.deposit_nonce = receipt.deposit_nonce.map(reth_primitives::U64::from);
|
||||||
|
op_fields.deposit_receipt_version =
|
||||||
|
receipt.deposit_receipt_version.map(reth_primitives::U64::from);
|
||||||
|
} else if let Some(l1_block_info) = optimism_tx_meta.l1_block_info {
|
||||||
|
op_fields.l1_fee = optimism_tx_meta.l1_fee;
|
||||||
|
op_fields.l1_gas_used = optimism_tx_meta.l1_data_gas.map(|dg| {
|
||||||
|
dg + l1_block_info.l1_fee_overhead.unwrap_or_default().saturating_to::<u128>()
|
||||||
|
});
|
||||||
|
op_fields.l1_fee_scalar = Some(f64::from(l1_block_info.l1_base_fee_scalar) / 1_000_000.0);
|
||||||
|
op_fields.l1_gas_price = Some(l1_block_info.l1_base_fee.saturating_to());
|
||||||
|
}
|
||||||
|
|
||||||
|
resp_builder.add_other_fields(op_fields.into())
|
||||||
|
}
|
||||||
107
crates/optimism/rpc/src/eth/transaction.rs
Normal file
107
crates/optimism/rpc/src/eth/transaction.rs
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
//! Loads and formats OP transaction RPC response.
|
||||||
|
|
||||||
|
use reth_evm_optimism::RethL1BlockInfo;
|
||||||
|
use reth_primitives::TransactionSigned;
|
||||||
|
use reth_provider::BlockReaderIdExt;
|
||||||
|
use reth_rpc_eth_api::{
|
||||||
|
helpers::{EthApiSpec, EthSigner, EthTransactions, LoadTransaction},
|
||||||
|
RawTransactionForwarder,
|
||||||
|
};
|
||||||
|
use reth_rpc_eth_types::{EthResult, EthStateCache};
|
||||||
|
use revm::L1BlockInfo;
|
||||||
|
|
||||||
|
use crate::{OpEthApi, OpEthApiError};
|
||||||
|
|
||||||
|
impl<Eth: EthTransactions> EthTransactions for OpEthApi<Eth> {
|
||||||
|
fn provider(&self) -> impl BlockReaderIdExt {
|
||||||
|
EthTransactions::provider(&self.inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn raw_tx_forwarder(&self) -> Option<std::sync::Arc<dyn RawTransactionForwarder>> {
|
||||||
|
self.inner.raw_tx_forwarder()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signers(&self) -> &parking_lot::RwLock<Vec<Box<dyn EthSigner>>> {
|
||||||
|
self.inner.signers()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Eth: LoadTransaction> LoadTransaction for OpEthApi<Eth> {
|
||||||
|
type Pool = Eth::Pool;
|
||||||
|
|
||||||
|
fn provider(&self) -> impl reth_provider::TransactionsProvider {
|
||||||
|
LoadTransaction::provider(&self.inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cache(&self) -> &EthStateCache {
|
||||||
|
LoadTransaction::cache(&self.inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pool(&self) -> &Self::Pool {
|
||||||
|
LoadTransaction::pool(&self.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// L1 fee and data gas for a transaction, along with the L1 block info.
|
||||||
|
#[derive(Debug, Default, Clone)]
|
||||||
|
pub struct OptimismTxMeta {
|
||||||
|
/// The L1 block info.
|
||||||
|
pub l1_block_info: Option<L1BlockInfo>,
|
||||||
|
/// The L1 fee for the block.
|
||||||
|
pub l1_fee: Option<u128>,
|
||||||
|
/// The L1 data gas for the block.
|
||||||
|
pub l1_data_gas: Option<u128>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OptimismTxMeta {
|
||||||
|
/// Creates a new [`OptimismTxMeta`].
|
||||||
|
pub const fn new(
|
||||||
|
l1_block_info: Option<L1BlockInfo>,
|
||||||
|
l1_fee: Option<u128>,
|
||||||
|
l1_data_gas: Option<u128>,
|
||||||
|
) -> Self {
|
||||||
|
Self { l1_block_info, l1_fee, l1_data_gas }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Eth> OpEthApi<Eth>
|
||||||
|
where
|
||||||
|
Eth: EthApiSpec + LoadTransaction,
|
||||||
|
{
|
||||||
|
/// Builds [`OptimismTxMeta`] object using the provided [`TransactionSigned`], L1 block
|
||||||
|
/// info and block timestamp. The [`L1BlockInfo`] is used to calculate the l1 fee and l1 data
|
||||||
|
/// gas for the transaction. If the [`L1BlockInfo`] is not provided, the meta info will be
|
||||||
|
/// empty.
|
||||||
|
pub fn build_op_tx_meta(
|
||||||
|
&self,
|
||||||
|
tx: &TransactionSigned,
|
||||||
|
l1_block_info: Option<L1BlockInfo>,
|
||||||
|
block_timestamp: u64,
|
||||||
|
) -> EthResult<OptimismTxMeta> {
|
||||||
|
let Some(l1_block_info) = l1_block_info else { return Ok(OptimismTxMeta::default()) };
|
||||||
|
|
||||||
|
let (l1_fee, l1_data_gas) = if !tx.is_deposit() {
|
||||||
|
let envelope_buf = tx.envelope_encoded();
|
||||||
|
|
||||||
|
let inner_l1_fee = l1_block_info
|
||||||
|
.l1_tx_data_fee(
|
||||||
|
&self.inner.chain_spec(),
|
||||||
|
block_timestamp,
|
||||||
|
&envelope_buf,
|
||||||
|
tx.is_deposit(),
|
||||||
|
)
|
||||||
|
.map_err(|_| OpEthApiError::L1BlockFeeError)?;
|
||||||
|
let inner_l1_data_gas = l1_block_info
|
||||||
|
.l1_data_gas(&self.inner.chain_spec(), block_timestamp, &envelope_buf)
|
||||||
|
.map_err(|_| OpEthApiError::L1BlockGasError)?;
|
||||||
|
(
|
||||||
|
Some(inner_l1_fee.saturating_to::<u128>()),
|
||||||
|
Some(inner_l1_data_gas.saturating_to::<u128>()),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(OptimismTxMeta::new(Some(l1_block_info), l1_fee, l1_data_gas))
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,7 +5,13 @@
|
|||||||
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
||||||
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||||
)]
|
)]
|
||||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
#![cfg_attr(all(not(test), feature = "optimism"), warn(unused_crate_dependencies))]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
|
// The `optimism` feature must be enabled to use this crate.
|
||||||
|
#![cfg(feature = "optimism")]
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
pub mod eth;
|
pub mod eth;
|
||||||
|
|
||||||
|
pub use error::OpEthApiError;
|
||||||
|
pub use eth::{receipt::op_receipt_fields, transaction::OptimismTxMeta, OpEthApi};
|
||||||
|
|||||||
@ -210,7 +210,7 @@ pub struct PeerStats {
|
|||||||
/// https://github.com/ethereum-optimism/optimism/blob/8dd17a7b114a7c25505cd2e15ce4e3d0f7e3f7c1/op-node/node/api.go#L114
|
/// https://github.com/ethereum-optimism/optimism/blob/8dd17a7b114a7c25505cd2e15ce4e3d0f7e3f7c1/op-node/node/api.go#L114
|
||||||
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "optimism"))]
|
#[cfg_attr(not(feature = "client"), rpc(server, namespace = "optimism"))]
|
||||||
#[cfg_attr(feature = "client", rpc(server, client, namespace = "optimism"))]
|
#[cfg_attr(feature = "client", rpc(server, client, namespace = "optimism"))]
|
||||||
pub trait OptimismApi {
|
pub trait OpEthApi {
|
||||||
/// Get the output root at a specific block.
|
/// Get the output root at a specific block.
|
||||||
#[method(name = "outputAtBlock")]
|
#[method(name = "outputAtBlock")]
|
||||||
async fn optimism_output_at_block(
|
async fn optimism_output_at_block(
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
//! Loads chain metadata.
|
//! Loads chain metadata.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use reth_chainspec::ChainInfo;
|
use reth_chainspec::{ChainInfo, ChainSpec};
|
||||||
use reth_errors::RethResult;
|
use reth_errors::RethResult;
|
||||||
use reth_primitives::{Address, U64};
|
use reth_primitives::{Address, U64};
|
||||||
use reth_rpc_types::SyncStatus;
|
use reth_rpc_types::SyncStatus;
|
||||||
@ -28,4 +30,7 @@ pub trait EthApiSpec: Send + Sync {
|
|||||||
|
|
||||||
/// Returns the [`SyncStatus`] of the network
|
/// Returns the [`SyncStatus`] of the network
|
||||||
fn sync_status(&self) -> RethResult<SyncStatus>;
|
fn sync_status(&self) -> RethResult<SyncStatus>;
|
||||||
|
|
||||||
|
/// Returns the configured [`ChainSpec`].
|
||||||
|
fn chain_spec(&self) -> Arc<ChainSpec>;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use reth_chainspec::ChainInfo;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use reth_chainspec::{ChainInfo, ChainSpec};
|
||||||
use reth_errors::{RethError, RethResult};
|
use reth_errors::{RethError, RethResult};
|
||||||
use reth_evm::ConfigureEvm;
|
use reth_evm::ConfigureEvm;
|
||||||
use reth_network_api::NetworkInfo;
|
use reth_network_api::NetworkInfo;
|
||||||
@ -62,4 +64,8 @@ where
|
|||||||
};
|
};
|
||||||
Ok(status)
|
Ok(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn chain_spec(&self) -> Arc<ChainSpec> {
|
||||||
|
self.inner.provider().chain_spec()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user