Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(rpc/trace): include block rewards in trace_filter rpc #8868

Merged
merged 15 commits into from
Jun 18, 2024
4 changes: 2 additions & 2 deletions crates/chainspec/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -853,8 +853,8 @@ impl ChainSpec {
self.fork(Hardfork::Homestead).active_at_block(block_number)
}

/// The Paris hardfork (merge) is activated via ttd. If we have knowledge of the block, this
/// function will return true if the block number is greater than or equal to the Paris
/// The Paris hardfork (merge) is activated via block number. If we have knowledge of the block,
/// this function will return true if the block number is greater than or equal to the Paris
/// (merge) block.
pub fn is_paris_active_at_block(&self, block_number: u64) -> Option<bool> {
self.paris_block_and_final_difficulty.map(|(paris_block, _)| block_number >= paris_block)
Expand Down
140 changes: 103 additions & 37 deletions crates/rpc/rpc/src/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ use crate::eth::{
};
use async_trait::async_trait;
use jsonrpsee::core::RpcResult as Result;
use reth_consensus_common::calc::{base_block_reward, block_reward, ommer_reward};
use reth_primitives::{revm::env::tx_env_with_recovered, BlockId, Bytes, SealedHeader, B256, U256};
use reth_consensus_common::calc::{
base_block_reward, base_block_reward_pre_merge, block_reward, ommer_reward,
};
use reth_primitives::{revm::env::tx_env_with_recovered, BlockId, Bytes, Header, B256, U256};
use reth_provider::{BlockReader, ChainSpecProvider, EvmEnvProvider, StateProviderFactory};
use reth_revm::database::StateProviderDatabase;
use reth_rpc_api::TraceApiServer;
Expand Down Expand Up @@ -266,7 +268,7 @@ where

// find relevant blocks to trace
let mut target_blocks = Vec::new();
for block in blocks {
for block in &blocks {
let mut transaction_indices = HashSet::new();
let mut highest_matching_index = 0;
for (tx_idx, tx) in block.body.iter().enumerate() {
Expand Down Expand Up @@ -308,11 +310,32 @@ where
}

let block_traces = futures::future::try_join_all(block_traces).await?;
let all_traces = block_traces
let mut all_traces = block_traces
.into_iter()
.flatten()
.flat_map(|traces| traces.into_iter().flatten().flat_map(|traces| traces.into_iter()))
.collect();
.collect::<Vec<_>>();

for block in &blocks {
let is_paris_activated =
self.provider().chain_spec().is_paris_active_at_block(block.number);

// if the Paris hardfork is activated on current block, no need to check the later
// blocks
if is_paris_activated.is_some_and(|activated| activated) {
break
}

if let Some(base_block_reward) =
self.calculate_base_block_reward(&block.header, is_paris_activated)?
{
all_traces.extend(self.extract_reward_traces(
&block.header,
&block.ommers,
base_block_reward,
));
}
}

Ok(all_traces)
}
Expand Down Expand Up @@ -362,36 +385,16 @@ where
maybe_traces.map(|traces| traces.into_iter().flatten().collect::<Vec<_>>());

if let (Some(block), Some(traces)) = (maybe_block, maybe_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,
) {
let block_reward = block_reward(base_block_reward, block.ommers.len());
traces.push(reward_trace(
&block.header,
RewardAction {
author: block.header.beneficiary,
reward_type: RewardType::Block,
value: U256::from(block_reward),
},
));

for uncle in &block.ommers {
let uncle_reward =
ommer_reward(base_block_reward, block.header.number, uncle.number);
traces.push(reward_trace(
&block.header,
RewardAction {
author: uncle.beneficiary,
reward_type: RewardType::Uncle,
value: U256::from(uncle_reward),
},
));
}
}
let is_paris_activated =
self.provider().chain_spec().is_paris_active_at_block(block.number);
if let Some(base_block_reward) =
self.calculate_base_block_reward(&block.header, is_paris_activated)?
{
traces.extend(self.extract_reward_traces(
&block.header,
&block.ommers,
base_block_reward,
));
}
}

Expand Down Expand Up @@ -485,6 +488,69 @@ where
transactions,
}))
}

/// Calculates the base block reward for the given block based on the Paris hardfork status:
///
/// - if Paris hardfork is activated, no block rewards are given
/// - if Paris hardfork is not activated, calculate block rewards with block number only
/// - if Paris hardfork is unknown, calculate block rewards with block number and ttd
fn calculate_base_block_reward(
&self,
header: &Header,
is_paris_activated: Option<bool>,
) -> EthResult<Option<u128>> {
let chain_spec = self.provider().chain_spec();

Ok(match is_paris_activated {
Some(true) => None,
Some(false) => Some(base_block_reward_pre_merge(chain_spec.as_ref(), header.number)),
None => {
if let Some(header_td) = self.provider().header_td_by_number(header.number)? {
base_block_reward(
chain_spec.as_ref(),
header.number,
header.difficulty,
header_td,
)
} else {
None
}
}
})
}

/// Extracts the reward traces for the given block.
fn extract_reward_traces(
&self,
header: &Header,
ommers: &[Header],
base_block_reward: u128,
) -> Vec<LocalizedTransactionTrace> {
let mut traces = Vec::new();

let block_reward = block_reward(base_block_reward, ommers.len());
traces.push(reward_trace(
header,
RewardAction {
author: header.beneficiary,
reward_type: RewardType::Block,
value: U256::from(block_reward),
},
));

for uncle in ommers {
let uncle_reward = ommer_reward(base_block_reward, header.number, uncle.number);
traces.push(reward_trace(
header,
RewardAction {
author: uncle.beneficiary,
reward_type: RewardType::Uncle,
value: U256::from(uncle_reward),
},
));
}
traces
}
}

#[async_trait]
Expand Down Expand Up @@ -628,9 +694,9 @@ struct TraceApiInner<Provider, Eth> {

/// Helper to construct a [`LocalizedTransactionTrace`] that describes a reward to the block
/// beneficiary.
fn reward_trace(header: &SealedHeader, reward: RewardAction) -> LocalizedTransactionTrace {
fn reward_trace(header: &Header, reward: RewardAction) -> LocalizedTransactionTrace {
LocalizedTransactionTrace {
block_hash: Some(header.hash()),
block_hash: Some(header.hash_slow()),
block_number: Some(header.number),
transaction_hash: None,
transaction_position: None,
Expand Down
Loading