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
132 changes: 96 additions & 36 deletions crates/rpc/rpc/src/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ 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, SealedBlock, SealedHeader, B256, U256,
};
use reth_provider::{BlockReader, ChainSpecProvider, EvmEnvProvider, StateProviderFactory};
use reth_revm::database::StateProviderDatabase;
use reth_rpc_api::TraceApiServer;
Expand Down Expand Up @@ -262,11 +266,11 @@ where
}

// fetch all blocks in that range
let blocks = self.provider().block_range(start..=end)?;
let blocks = self.provider().sealed_block_with_senders_range(start..=end)?;
mattsse marked this conversation as resolved.
Show resolved Hide resolved

// 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 +312,27 @@ 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<_>>();

let mut is_paris_activated = None;
for block in &blocks {
// check if the Paris hardfork is activated or not, no need to recheck if it's
// activation status is already known
if is_paris_activated.is_none() {
is_paris_activated =
self.provider().chain_spec().is_paris_active_at_block(block.number);
}
jsvisa marked this conversation as resolved.
Show resolved Hide resolved

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

Ok(all_traces)
}
Expand Down Expand Up @@ -362,36 +382,12 @@ 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, is_paris_activated)?
{
traces.extend(self.extract_reward_traces(&block, base_block_reward));
}
}

Expand Down Expand Up @@ -485,6 +481,70 @@ 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,
block: &SealedBlock,
jsvisa marked this conversation as resolved.
Show resolved Hide resolved
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(), block.header.number))
}
None => {
if let Some(header_td) = self.provider().header_td(&block.header.hash())? {
base_block_reward(
chain_spec.as_ref(),
block.header.number,
block.header.difficulty,
header_td,
)
} else {
None
}
}
})
}

/// Extracts the reward traces for the given block.
fn extract_reward_traces(
&self,
block: &SealedBlock,
jsvisa marked this conversation as resolved.
Show resolved Hide resolved
base_block_reward: u128,
) -> Vec<LocalizedTransactionTrace> {
let mut traces = Vec::new();

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),
},
));
}
traces
}
}

#[async_trait]
Expand Down
Loading