use crate::transaction::from_recovered_with_block_context;
use alloy_rlp::Encodable;
use reth_primitives::{
Block as PrimitiveBlock, BlockWithSenders, Header as PrimitiveHeader, Withdrawals, B256, U256,
};
use reth_rpc_types::{Block, BlockError, BlockTransactions, BlockTransactionsKind, Header};
pub fn from_block(
block: BlockWithSenders,
total_difficulty: U256,
kind: BlockTransactionsKind,
block_hash: Option<B256>,
) -> Result<Block, BlockError> {
match kind {
BlockTransactionsKind::Hashes => {
Ok(from_block_with_tx_hashes(block, total_difficulty, block_hash))
}
BlockTransactionsKind::Full => from_block_full(block, total_difficulty, block_hash),
}
}
pub fn from_block_with_tx_hashes(
block: BlockWithSenders,
total_difficulty: U256,
block_hash: Option<B256>,
) -> Block {
let block_hash = block_hash.unwrap_or_else(|| block.header.hash_slow());
let transactions = block.body.iter().map(|tx| tx.hash()).collect();
from_block_with_transactions(
block.length(),
block_hash,
block.block,
total_difficulty,
BlockTransactions::Hashes(transactions),
)
}
pub fn from_block_full(
mut block: BlockWithSenders,
total_difficulty: U256,
block_hash: Option<B256>,
) -> Result<Block, BlockError> {
let block_hash = block_hash.unwrap_or_else(|| block.block.header.hash_slow());
let block_number = block.block.number;
let base_fee_per_gas = block.block.base_fee_per_gas;
let block_length = block.block.length();
let body = std::mem::take(&mut block.block.body);
let transactions_with_senders = body.into_iter().zip(block.senders);
let transactions = transactions_with_senders
.enumerate()
.map(|(idx, (tx, sender))| {
let signed_tx_ec_recovered = tx.with_signer(sender);
from_recovered_with_block_context(
signed_tx_ec_recovered,
block_hash,
block_number,
base_fee_per_gas,
idx,
)
})
.collect::<Vec<_>>();
Ok(from_block_with_transactions(
block_length,
block_hash,
block.block,
total_difficulty,
BlockTransactions::Full(transactions),
))
}
pub fn from_primitive_with_hash(primitive_header: reth_primitives::SealedHeader) -> Header {
let (header, hash) = primitive_header.split();
let PrimitiveHeader {
parent_hash,
ommers_hash,
beneficiary,
state_root,
transactions_root,
receipts_root,
logs_bloom,
difficulty,
number,
gas_limit,
gas_used,
timestamp,
mix_hash,
nonce,
base_fee_per_gas,
extra_data,
withdrawals_root,
blob_gas_used,
excess_blob_gas,
parent_beacon_block_root,
requests_root,
} = header;
Header {
hash: Some(hash),
parent_hash,
uncles_hash: ommers_hash,
miner: beneficiary,
state_root,
transactions_root,
receipts_root,
withdrawals_root,
number: Some(number),
gas_used: gas_used as u128,
gas_limit: gas_limit as u128,
extra_data,
logs_bloom,
timestamp,
difficulty,
mix_hash: Some(mix_hash),
nonce: Some(nonce.to_be_bytes().into()),
base_fee_per_gas: base_fee_per_gas.map(u128::from),
blob_gas_used: blob_gas_used.map(u128::from),
excess_blob_gas: excess_blob_gas.map(u128::from),
parent_beacon_block_root,
total_difficulty: None,
requests_root,
}
}
#[inline]
fn from_block_with_transactions(
block_length: usize,
block_hash: B256,
block: PrimitiveBlock,
total_difficulty: U256,
transactions: BlockTransactions,
) -> Block {
let uncles = block.ommers.into_iter().map(|h| h.hash_slow()).collect();
let mut header = from_primitive_with_hash(block.header.seal(block_hash));
header.total_difficulty = Some(total_difficulty);
let withdrawals = header
.withdrawals_root
.is_some()
.then(|| block.withdrawals.map(Withdrawals::into_inner))
.flatten();
Block {
header,
uncles,
transactions,
size: Some(U256::from(block_length)),
withdrawals,
other: Default::default(),
}
}
pub fn uncle_block_from_header(header: PrimitiveHeader) -> Block {
let hash = header.hash_slow();
let rpc_header = from_primitive_with_hash(header.clone().seal(hash));
let uncle_block = PrimitiveBlock { header, ..Default::default() };
let size = Some(U256::from(uncle_block.length()));
Block {
uncles: vec![],
header: rpc_header,
transactions: BlockTransactions::Uncle,
withdrawals: Some(vec![]),
size,
other: Default::default(),
}
}