//! Compatibility functions for rpc `Block` type. use crate::transaction::from_recovered_with_block_context; use alloy_rlp::Encodable; use alloy_rpc_types::Transaction; use reth_primitives::{ Block as PrimitiveBlock, BlockWithSenders, Header as PrimitiveHeader, Withdrawals, B256, U256, }; use reth_rpc_types::{Block, BlockError, BlockTransactions, BlockTransactionsKind, Header}; /// Converts the given primitive block into a [`Block`] response with the given /// [`BlockTransactionsKind`] /// /// If a `block_hash` is provided, then this is used, otherwise the block hash is computed. pub fn from_block( block: BlockWithSenders, total_difficulty: U256, kind: BlockTransactionsKind, block_hash: Option, ) -> Result { 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), } } /// Create a new [`Block`] response from a [primitive block](reth_primitives::Block), using the /// total difficulty to populate its field in the rpc response. /// /// This will populate the `transactions` field with only the hashes of the transactions in the /// block: [`BlockTransactions::Hashes`] pub fn from_block_with_tx_hashes( block: BlockWithSenders, total_difficulty: U256, block_hash: Option, ) -> 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), ) } /// Create a new [`Block`] response from a [primitive block](reth_primitives::Block), using the /// total difficulty to populate its field in the rpc response. /// /// This will populate the `transactions` field with the _full_ /// [`Transaction`] objects: [`BlockTransactions::Full`] pub fn from_block_full( mut block: BlockWithSenders, total_difficulty: U256, block_hash: Option, ) -> Result { 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; // NOTE: we can safely remove the body here because not needed to finalize the `Block` in // `from_block_with_transactions`, however we need to compute the length before 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::>(); Ok(from_block_with_transactions( block_length, block_hash, block.block, total_difficulty, BlockTransactions::Full(transactions), )) } /// Converts from a [`reth_primitives::SealedHeader`] to a [`reth_rpc_types::Header`] /// /// # Note /// /// This does not set the `totalDifficulty` field. 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(), } } /// Build an RPC block response representing /// an Uncle from its header. 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(), } }