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

Signed-off-by: jsvisa <delweng@gmail.com>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
Delweng
2024-06-19 07:13:20 +08:00
committed by GitHub
parent da0004e361
commit 7bfc604a10
2 changed files with 97 additions and 40 deletions

View File

@ -851,8 +851,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)

View File

@ -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;
@ -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() {
@ -308,11 +310,26 @@ 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<_>>();
// add reward traces for all blocks
for block in &blocks {
if let Some(base_block_reward) = self.calculate_base_block_reward(&block.header)? {
all_traces.extend(self.extract_reward_traces(
&block.header,
&block.ommers,
base_block_reward,
));
} else {
// no block reward, means we're past the Paris hardfork and don't expect any rewards
// because the blocks in ascending order
break
}
}
Ok(all_traces)
}
@ -362,36 +379,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),
},
));
}
}
if let Some(base_block_reward) = self.calculate_base_block_reward(&block.header)? {
traces.extend(self.extract_reward_traces(
&block.header,
&block.ommers,
base_block_reward,
));
}
}
@ -481,10 +474,74 @@ where
Ok(Some(BlockOpcodeGas {
block_hash: block.hash(),
block_number: block.number,
block_number: block.header.number,
transactions,
}))
}
/// Calculates the base block reward for the given block:
///
/// - 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) -> EthResult<Option<u128>> {
let chain_spec = self.provider().chain_spec();
let is_paris_activated = chain_spec.is_paris_active_at_block(header.number);
Ok(match is_paris_activated {
Some(true) => None,
Some(false) => Some(base_block_reward_pre_merge(&chain_spec, header.number)),
None => {
// if Paris hardfork is unknown, we need to fetch the total difficulty at the
// block's height and check if it is pre-merge to calculate the base block reward
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:
/// - block reward
/// - uncle rewards
fn extract_reward_traces(
&self,
header: &Header,
ommers: &[Header],
base_block_reward: u128,
) -> Vec<LocalizedTransactionTrace> {
let mut traces = Vec::with_capacity(ommers.len() + 1);
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]
@ -628,9 +685,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,