From 4f32f5627c5db42f2921dbe58c4cfc446955e15e Mon Sep 17 00:00:00 2001 From: Bjerg Date: Sun, 2 Jul 2023 17:06:52 +0200 Subject: [PATCH] fix: add block rewards to `trace_block` (#3491) Co-authored-by: Georgios Konstantopoulos --- Cargo.lock | 1 + bin/reth/src/args/rpc_server_args.rs | 5 +- crates/rpc/rpc-builder/src/lib.rs | 44 +++++++++--- crates/rpc/rpc/Cargo.toml | 1 + crates/rpc/rpc/src/trace.rs | 67 +++++++++++++++++-- crates/storage/provider/src/lib.rs | 11 +-- .../provider/src/providers/database/mod.rs | 14 +++- crates/storage/provider/src/providers/mod.rs | 20 ++++-- .../storage/provider/src/test_utils/noop.rs | 18 +++-- crates/storage/provider/src/traits/mod.rs | 3 + .../storage/provider/src/traits/receipts.rs | 2 +- crates/storage/provider/src/traits/spec.rs | 8 +++ 12 files changed, 160 insertions(+), 34 deletions(-) create mode 100644 crates/storage/provider/src/traits/spec.rs diff --git a/Cargo.lock b/Cargo.lock index 04d8ee92c..3e33d1e1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5651,6 +5651,7 @@ dependencies = [ "jsonwebtoken", "pin-project", "rand 0.8.5", + "reth-consensus-common", "reth-interfaces", "reth-metrics", "reth-network-api", diff --git a/bin/reth/src/args/rpc_server_args.rs b/bin/reth/src/args/rpc_server_args.rs index bcf10cd03..9e7b890e0 100644 --- a/bin/reth/src/args/rpc_server_args.rs +++ b/bin/reth/src/args/rpc_server_args.rs @@ -8,7 +8,8 @@ use clap::{ use futures::TryFutureExt; use reth_network_api::{NetworkInfo, Peers}; use reth_provider::{ - BlockReaderIdExt, CanonStateSubscriptions, EvmEnvProvider, HeaderProvider, StateProviderFactory, + BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, EvmEnvProvider, HeaderProvider, + StateProviderFactory, }; use reth_rpc::{ eth::{ @@ -235,6 +236,7 @@ impl RpcServerArgs { + HeaderProvider + StateProviderFactory + EvmEnvProvider + + ChainSpecProvider + Clone + Unpin + 'static, @@ -295,6 +297,7 @@ impl RpcServerArgs { + HeaderProvider + StateProviderFactory + EvmEnvProvider + + ChainSpecProvider + Clone + Unpin + 'static, diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 38fbb76f4..9a1544023 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -31,13 +31,13 @@ //! //! ``` //! use reth_network_api::{NetworkInfo, Peers}; -//! use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, StateProviderFactory, EvmEnvProvider}; +//! use reth_provider::{BlockReaderIdExt, ChainSpecProvider, CanonStateSubscriptions, StateProviderFactory, EvmEnvProvider}; //! use reth_rpc_builder::{RethRpcModule, RpcModuleBuilder, RpcServerConfig, ServerBuilder, TransportRpcModuleConfig}; //! use reth_tasks::TokioTaskExecutor; //! use reth_transaction_pool::TransactionPool; //! pub async fn launch(provider: Provider, pool: Pool, network: Network, events: Events) //! where -//! Provider: BlockReaderIdExt + StateProviderFactory + EvmEnvProvider + Clone + Unpin + 'static, +//! Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + Clone + Unpin + 'static, //! Pool: TransactionPool + Clone + 'static, //! Network: NetworkInfo + Peers + Clone + 'static, //! Events: CanonStateSubscriptions + Clone + 'static, @@ -64,7 +64,7 @@ //! ``` //! use tokio::try_join; //! use reth_network_api::{NetworkInfo, Peers}; -//! use reth_provider::{BlockReaderIdExt, CanonStateSubscriptions, StateProviderFactory, EvmEnvProvider}; +//! use reth_provider::{BlockReaderIdExt, ChainSpecProvider, CanonStateSubscriptions, StateProviderFactory, EvmEnvProvider}; //! use reth_rpc::JwtSecret; //! use reth_rpc_builder::{RethRpcModule, RpcModuleBuilder, RpcServerConfig, TransportRpcModuleConfig}; //! use reth_tasks::TokioTaskExecutor; @@ -73,7 +73,7 @@ //! use reth_rpc_builder::auth::AuthServerConfig; //! pub async fn launch(provider: Provider, pool: Pool, network: Network, events: Events, engine_api: EngineApi) //! where -//! Provider: BlockReaderIdExt + StateProviderFactory + EvmEnvProvider + Clone + Unpin + 'static, +//! Provider: BlockReaderIdExt + ChainSpecProvider + StateProviderFactory + EvmEnvProvider + Clone + Unpin + 'static, //! Pool: TransactionPool + Clone + 'static, //! Network: NetworkInfo + Peers + Clone + 'static, //! Events: CanonStateSubscriptions + Clone + 'static, @@ -113,7 +113,8 @@ use jsonrpsee::{ use reth_ipc::server::IpcServer; use reth_network_api::{NetworkInfo, Peers}; use reth_provider::{ - BlockReader, BlockReaderIdExt, CanonStateSubscriptions, EvmEnvProvider, StateProviderFactory, + BlockReader, BlockReaderIdExt, CanonStateSubscriptions, ChainSpecProvider, EvmEnvProvider, + StateProviderFactory, }; use reth_rpc::{ eth::{ @@ -169,7 +170,13 @@ pub async fn launch( events: Events, ) -> Result where - Provider: BlockReaderIdExt + StateProviderFactory + EvmEnvProvider + Clone + Unpin + 'static, + Provider: BlockReaderIdExt + + StateProviderFactory + + EvmEnvProvider + + ChainSpecProvider + + Clone + + Unpin + + 'static, Pool: TransactionPool + Clone + 'static, Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, @@ -268,7 +275,13 @@ impl impl RpcModuleBuilder where - Provider: BlockReaderIdExt + StateProviderFactory + EvmEnvProvider + Clone + Unpin + 'static, + Provider: BlockReaderIdExt + + StateProviderFactory + + EvmEnvProvider + + ChainSpecProvider + + Clone + + Unpin + + 'static, Pool: TransactionPool + Clone + 'static, Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, @@ -485,8 +498,13 @@ impl RpcModuleSelection { config: RpcModuleConfig, ) -> RpcModule<()> where - Provider: - BlockReaderIdExt + StateProviderFactory + EvmEnvProvider + Clone + Unpin + 'static, + Provider: BlockReaderIdExt + + StateProviderFactory + + EvmEnvProvider + + ChainSpecProvider + + Clone + + Unpin + + 'static, Pool: TransactionPool + Clone + 'static, Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, @@ -692,7 +710,13 @@ where impl RethModuleRegistry where - Provider: BlockReaderIdExt + StateProviderFactory + EvmEnvProvider + Clone + Unpin + 'static, + Provider: BlockReaderIdExt + + StateProviderFactory + + EvmEnvProvider + + ChainSpecProvider + + Clone + + Unpin + + 'static, Pool: TransactionPool + Clone + 'static, Network: NetworkInfo + Peers + Clone + 'static, Tasks: TaskSpawner + Clone + 'static, diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index c12188792..c3003e496 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -23,6 +23,7 @@ reth-rpc-engine-api = { path = "../rpc-engine-api" } reth-revm = { path = "../../revm" } reth-tasks = { workspace = true } reth-metrics = { workspace = true } +reth-consensus-common = { path = "../../consensus/common" } # eth revm = { workspace = true, features = [ diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index bfa45863c..fa1372a50 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -11,8 +11,11 @@ use crate::{ }; use async_trait::async_trait; use jsonrpsee::core::RpcResult as Result; -use reth_primitives::{BlockId, BlockNumberOrTag, Bytes, H256}; -use reth_provider::{BlockReader, EvmEnvProvider, StateProviderBox, StateProviderFactory}; +use reth_consensus_common::calc::{base_block_reward, block_reward}; +use reth_primitives::{BlockId, BlockNumberOrTag, Bytes, SealedHeader, H256, U256}; +use reth_provider::{ + BlockReader, ChainSpecProvider, EvmEnvProvider, StateProviderBox, StateProviderFactory, +}; use reth_revm::{ database::{State, SubState}, env::tx_env_with_recovered, @@ -77,7 +80,7 @@ impl TraceApi { impl TraceApi where - Provider: BlockReader + StateProviderFactory + EvmEnvProvider + 'static, + Provider: BlockReader + StateProviderFactory + EvmEnvProvider + ChainSpecProvider + 'static, Eth: EthTransactions + 'static, { /// Executes the future on a new blocking task. @@ -396,7 +399,7 @@ where &self, block_id: BlockId, ) -> EthResult>> { - let traces = self + let mut traces: Option> = self .trace_block_with( block_id, TracingInspectorConfig::default_parity(), @@ -408,6 +411,43 @@ where ) .await? .map(|traces| traces.into_iter().flatten().collect()); + + // Add block reward traces + // TODO: We only really need the header and ommers here to determine the reward + if let (Some(block), Some(traces)) = + (self.inner.eth_api.block_by_id(block_id).await?, traces.as_mut()) + { + if let Some(header_td) = self.provider().header_td(&block.header.hash)? { + if let Some(base_block_reward) = base_block_reward( + self.provider().chain_spec().as_ref(), + block.header.number, + block.header.difficulty, + header_td, + ) { + traces.push(reward_trace( + &block.header, + RewardAction { + author: block.header.beneficiary, + reward_type: RewardType::Block, + value: U256::from(base_block_reward), + }, + )); + + if !block.ommers.is_empty() { + traces.push(reward_trace( + &block.header, + RewardAction { + author: block.header.beneficiary, + reward_type: RewardType::Uncle, + value: block_reward(base_block_reward, block.ommers.len()) - + U256::from(base_block_reward), + }, + )); + } + } + } + } + Ok(traces) } @@ -448,7 +488,7 @@ where #[async_trait] impl TraceApiServer for TraceApi where - Provider: BlockReader + StateProviderFactory + EvmEnvProvider + 'static, + Provider: BlockReader + StateProviderFactory + EvmEnvProvider + ChainSpecProvider + 'static, Eth: EthTransactions + 'static, { /// Executes the given call and returns a number of possible traces for it. @@ -581,3 +621,20 @@ fn tracing_config(trace_types: &HashSet) -> TracingInspectorConfig { .set_state_diffs(trace_types.contains(&TraceType::StateDiff)) .set_steps(trace_types.contains(&TraceType::VmTrace)) } + +/// Helper to construct a [`LocalizedTransactionTrace`] that describes a reward to the block +/// beneficiary. +fn reward_trace(header: &SealedHeader, reward: RewardAction) -> LocalizedTransactionTrace { + LocalizedTransactionTrace { + block_hash: Some(header.hash), + block_number: Some(header.number), + transaction_hash: None, + transaction_position: None, + trace: TransactionTrace { + trace_address: vec![], + subtraces: 0, + action: Action::Reward(reward), + result: None, + }, + } +} diff --git a/crates/storage/provider/src/lib.rs b/crates/storage/provider/src/lib.rs index 3d00040c0..a6a1f6bf2 100644 --- a/crates/storage/provider/src/lib.rs +++ b/crates/storage/provider/src/lib.rs @@ -24,11 +24,12 @@ pub use traits::{ AccountExtReader, AccountReader, BlockExecutionWriter, BlockExecutor, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockSource, BlockWriter, BlockchainTreePendingStateProvider, CanonChainTracker, CanonStateNotification, - CanonStateNotificationSender, CanonStateNotifications, CanonStateSubscriptions, EvmEnvProvider, - ExecutorFactory, HashingWriter, HeaderProvider, HistoryWriter, PostStateDataProvider, - ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StageCheckpointWriter, - StateProvider, StateProviderBox, StateProviderFactory, StateRootProvider, StorageReader, - TransactionsProvider, WithdrawalsProvider, + CanonStateNotificationSender, CanonStateNotifications, CanonStateSubscriptions, + ChainSpecProvider, EvmEnvProvider, ExecutorFactory, HashingWriter, HeaderProvider, + HistoryWriter, PostStateDataProvider, ReceiptProvider, ReceiptProviderIdExt, + StageCheckpointReader, StageCheckpointWriter, StateProvider, StateProviderBox, + StateProviderFactory, StateRootProvider, StorageReader, TransactionsProvider, + WithdrawalsProvider, }; /// Provider trait implementations. diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 5170f4b21..e1ec92d5c 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -1,8 +1,9 @@ use crate::{ providers::state::{historical::HistoricalStateProvider, latest::LatestStateProvider}, traits::{BlockSource, ReceiptProvider}, - BlockHashReader, BlockNumReader, BlockReader, EvmEnvProvider, HeaderProvider, ProviderError, - StageCheckpointReader, StateProviderBox, TransactionsProvider, WithdrawalsProvider, + BlockHashReader, BlockNumReader, BlockReader, ChainSpecProvider, EvmEnvProvider, + HeaderProvider, ProviderError, StageCheckpointReader, StateProviderBox, TransactionsProvider, + WithdrawalsProvider, }; use reth_db::{database::Database, init_db, models::StoredBlockBodyIndices, DatabaseEnv}; use reth_interfaces::Result; @@ -343,6 +344,15 @@ impl EvmEnvProvider for ProviderFactory { } } +impl ChainSpecProvider for ProviderFactory +where + DB: Send + Sync, +{ + fn chain_spec(&self) -> Arc { + self.chain_spec.clone() + } +} + #[cfg(test)] mod tests { use super::ProviderFactory; diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index df1c04b66..7dfeae75f 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -1,9 +1,10 @@ use crate::{ BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, BlockchainTreePendingStateProvider, CanonChainTracker, CanonStateNotifications, - CanonStateSubscriptions, EvmEnvProvider, HeaderProvider, PostStateDataProvider, ProviderError, - ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StateProviderBox, - StateProviderFactory, TransactionsProvider, WithdrawalsProvider, + CanonStateSubscriptions, ChainSpecProvider, EvmEnvProvider, HeaderProvider, + PostStateDataProvider, ProviderError, ReceiptProvider, ReceiptProviderIdExt, + StageCheckpointReader, StateProviderBox, StateProviderFactory, TransactionsProvider, + WithdrawalsProvider, }; use reth_db::{database::Database, models::StoredBlockBodyIndices}; use reth_interfaces::{ @@ -14,7 +15,7 @@ use reth_interfaces::{ use reth_primitives::{ stage::{StageCheckpoint, StageId}, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumber, - BlockNumberOrTag, BlockWithSenders, ChainInfo, Header, Receipt, SealedBlock, + BlockNumberOrTag, BlockWithSenders, ChainInfo, ChainSpec, Header, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, TransactionMeta, TransactionSigned, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, H256, U256, }; @@ -26,6 +27,7 @@ pub use state::{ use std::{ collections::{BTreeMap, HashSet}, ops::RangeBounds, + sync::Arc, time::Instant, }; use tracing::trace; @@ -431,6 +433,16 @@ where } } +impl ChainSpecProvider for BlockchainProvider +where + DB: Send + Sync, + Tree: Send + Sync, +{ + fn chain_spec(&self) -> Arc { + self.database.chain_spec() + } +} + impl StateProviderFactory for BlockchainProvider where DB: Database, diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 31ece7b38..b330697b8 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -1,26 +1,32 @@ use crate::{ traits::{BlockSource, ReceiptProvider}, AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, - EvmEnvProvider, HeaderProvider, PostState, ReceiptProviderIdExt, StageCheckpointReader, - StateProvider, StateProviderBox, StateProviderFactory, StateRootProvider, TransactionsProvider, - WithdrawalsProvider, + ChainSpecProvider, EvmEnvProvider, HeaderProvider, PostState, ReceiptProviderIdExt, + StageCheckpointReader, StateProvider, StateProviderBox, StateProviderFactory, + StateRootProvider, TransactionsProvider, WithdrawalsProvider, }; use reth_db::models::StoredBlockBodyIndices; use reth_interfaces::Result; use reth_primitives::{ stage::{StageCheckpoint, StageId}, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, Bytecode, Bytes, - ChainInfo, Header, Receipt, SealedBlock, SealedHeader, StorageKey, StorageValue, - TransactionMeta, TransactionSigned, TxHash, TxNumber, H256, KECCAK_EMPTY, U256, + ChainInfo, ChainSpec, Header, Receipt, SealedBlock, SealedHeader, StorageKey, StorageValue, + TransactionMeta, TransactionSigned, TxHash, TxNumber, H256, KECCAK_EMPTY, MAINNET, U256, }; use reth_revm_primitives::primitives::{BlockEnv, CfgEnv}; -use std::ops::RangeBounds; +use std::{ops::RangeBounds, sync::Arc}; /// Supports various api interfaces for testing purposes. #[derive(Debug, Clone, Default, Copy)] #[non_exhaustive] pub struct NoopProvider; +impl ChainSpecProvider for NoopProvider { + fn chain_spec(&self) -> Arc { + MAINNET.clone() + } +} + /// Noop implementation for testing purposes impl BlockHashReader for NoopProvider { fn block_hash(&self, _number: u64) -> Result> { diff --git a/crates/storage/provider/src/traits/mod.rs b/crates/storage/provider/src/traits/mod.rs index 503162758..0411c995f 100644 --- a/crates/storage/provider/src/traits/mod.rs +++ b/crates/storage/provider/src/traits/mod.rs @@ -48,6 +48,9 @@ pub use chain::{ CanonStateSubscriptions, }; +mod spec; +pub use spec::ChainSpecProvider; + mod stage_checkpoint; pub use stage_checkpoint::{StageCheckpointReader, StageCheckpointWriter}; diff --git a/crates/storage/provider/src/traits/receipts.rs b/crates/storage/provider/src/traits/receipts.rs index 3166b6208..7b3e4640f 100644 --- a/crates/storage/provider/src/traits/receipts.rs +++ b/crates/storage/provider/src/traits/receipts.rs @@ -3,7 +3,7 @@ use reth_primitives::{BlockHashOrNumber, BlockId, BlockNumberOrTag, Receipt, TxH use crate::BlockIdReader; -/// Client trait for fetching [Receipt] data . +/// Client trait for fetching [Receipt] data . #[auto_impl::auto_impl(&, Arc)] pub trait ReceiptProvider: Send + Sync { /// Get receipt by transaction number diff --git a/crates/storage/provider/src/traits/spec.rs b/crates/storage/provider/src/traits/spec.rs new file mode 100644 index 000000000..47d95fbd5 --- /dev/null +++ b/crates/storage/provider/src/traits/spec.rs @@ -0,0 +1,8 @@ +use reth_primitives::ChainSpec; +use std::sync::Arc; + +/// A trait for reading the current chainspec. +pub trait ChainSpecProvider: Send + Sync { + /// Get an [`Arc`] to the chainspec. + fn chain_spec(&self) -> Arc; +}