From c8e04c30cef6342d8df0e5512449d1c81a203c86 Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:09:48 +0100 Subject: [PATCH 1/2] chore: minimize reth dependencies used --- bolt-sidecar/src/builder/compat.rs | 44 +++++++++---------- .../src/builder/fallback/engine_hinter.rs | 14 +++--- .../src/builder/fallback/payload_builder.rs | 14 +++--- bolt-sidecar/src/builder/mod.rs | 9 +++- bolt-sidecar/src/builder/template.rs | 7 ++- bolt-sidecar/src/primitives/transaction.rs | 23 ++-------- 6 files changed, 47 insertions(+), 64 deletions(-) diff --git a/bolt-sidecar/src/builder/compat.rs b/bolt-sidecar/src/builder/compat.rs index 23404342..957d46a7 100644 --- a/bolt-sidecar/src/builder/compat.rs +++ b/bolt-sidecar/src/builder/compat.rs @@ -1,5 +1,5 @@ use alloy::{ - consensus::BlockHeader, + consensus::{transaction::PooledTransaction, BlockHeader}, eips::{eip2718::Encodable2718, eip4895::Withdrawal}, primitives::{Address, Bloom, B256, U256}, rpc::types::Withdrawals, @@ -19,14 +19,14 @@ use ethereum_consensus::{ ssz::prelude::{ssz_rs, ByteList, ByteVector, HashTreeRoot, List}, types::mainnet::ExecutionPayload as ConsensusExecutionPayload, }; -use reth_primitives::{SealedBlock, TransactionSigned}; -use reth_primitives_traits::BlockBody; + +use super::SealedAlloyBlock; /// Compatibility: convert a sealed header into an ethereum-consensus execution payload header. /// This requires recalculating the withdrals and transactions roots as SSZ instead of MPT roots. pub(crate) fn to_execution_payload_header( - sealed_block: &SealedBlock, - transactions: Vec, + sealed_block: &SealedAlloyBlock, + transactions: Vec, ) -> ConsensusExecutionPayloadHeader { // Transactions and withdrawals are treated as opaque byte arrays in consensus types let transactions_bytes = transactions.iter().map(|t| t.encoded_2718()).collect::>(); @@ -75,36 +75,30 @@ pub(crate) fn to_execution_payload_header( /// Compatibility: convert a sealed block into an Alloy execution payload pub(crate) fn to_alloy_execution_payload( - block: &SealedBlock, + block: &SealedAlloyBlock, block_hash: B256, ) -> ExecutionPayloadV3 { - let alloy_withdrawals = block + let alloy_withdrawals = + block.body().withdrawals.clone().map(|w| w.into_inner()).unwrap_or_default(); + + let transactions = block .body() - .withdrawals - .as_ref() - .map(|withdrawals| { - withdrawals - .iter() - .map(|w| Withdrawal { - index: w.index, - validator_index: w.validator_index, - address: w.address, - amount: w.amount, - }) - .collect::>() - }) - .unwrap_or_default(); + .transactions + .iter() + .map(|tx| tx.encoded_2718()) + .map(Into::into) + .collect::>(); ExecutionPayloadV3 { blob_gas_used: block.blob_gas_used().unwrap_or_default(), excess_blob_gas: block.excess_blob_gas.unwrap_or_default(), payload_inner: ExecutionPayloadV2 { payload_inner: ExecutionPayloadV1 { - base_fee_per_gas: U256::from(block.base_fee_per_gas.unwrap_or_default()), block_hash, + transactions, + base_fee_per_gas: U256::from(block.base_fee_per_gas.unwrap_or_default()), block_number: block.number, extra_data: block.extra_data.clone(), - transactions: block.body().encoded_2718_transactions(), fee_recipient: block.header().beneficiary, gas_limit: block.gas_limit, gas_used: block.gas_used, @@ -121,7 +115,9 @@ pub(crate) fn to_alloy_execution_payload( } /// Compatibility: convert a sealed block into an ethereum-consensus execution payload -pub(crate) fn to_consensus_execution_payload(value: &SealedBlock) -> ConsensusExecutionPayload { +pub(crate) fn to_consensus_execution_payload( + value: &SealedAlloyBlock, +) -> ConsensusExecutionPayload { let hash = value.hash(); let header = value.header(); let transactions = &value.body().transactions; diff --git a/bolt-sidecar/src/builder/fallback/engine_hinter.rs b/bolt-sidecar/src/builder/fallback/engine_hinter.rs index 03284298..f13aae78 100644 --- a/bolt-sidecar/src/builder/fallback/engine_hinter.rs +++ b/bolt-sidecar/src/builder/fallback/engine_hinter.rs @@ -1,18 +1,18 @@ use std::ops::Deref; use alloy::{ - consensus::{Header, EMPTY_OMMER_ROOT_HASH}, + consensus::{transaction::PooledTransaction, Header, EMPTY_OMMER_ROOT_HASH}, primitives::{Address, Bloom, Bytes, B256, B64, U256}, rpc::types::{Block, Withdrawal, Withdrawals}, }; use alloy_provider::ext::EngineApi; use alloy_rpc_types_engine::{ClientCode, ExecutionPayloadV3, JwtSecret, PayloadStatusEnum}; use reqwest::Url; -use reth_primitives::{BlockBody, SealedBlock, SealedHeader, TransactionSigned}; +use reth_primitives::{BlockBody, SealedBlock, SealedHeader}; use tracing::{debug, error}; use crate::{ - builder::{compat::to_alloy_execution_payload, BuilderError}, + builder::{compat::to_alloy_execution_payload, BuilderError, SealedAlloyBlock}, client::EngineClient, }; @@ -52,7 +52,7 @@ impl EngineHinter { pub async fn fetch_payload_from_hints( &self, mut ctx: EngineHinterContext, - ) -> Result { + ) -> Result { // The block body can be the same for all iterations, since it only contains // the transactions and withdrawals from the context. let body = ctx.build_block_body(); @@ -206,7 +206,7 @@ pub struct EngineHinterContext { pub parent_beacon_block_root: B256, pub blob_versioned_hashes: Vec, pub block_timestamp: u64, - pub transactions: Vec, + pub transactions: Vec, pub withdrawals: Vec, pub head_block: Block, pub hints: Hints, @@ -215,8 +215,8 @@ pub struct EngineHinterContext { impl EngineHinterContext { /// Build a block body using the transactions and withdrawals from the context. - pub fn build_block_body(&self) -> BlockBody { - BlockBody { + pub fn build_block_body(&self) -> BlockBody { + BlockBody:: { ommers: Vec::new(), transactions: self.transactions.clone(), withdrawals: Some(Withdrawals::new(self.withdrawals.clone())), diff --git a/bolt-sidecar/src/builder/fallback/payload_builder.rs b/bolt-sidecar/src/builder/fallback/payload_builder.rs index 775b7d37..df7f2307 100644 --- a/bolt-sidecar/src/builder/fallback/payload_builder.rs +++ b/bolt-sidecar/src/builder/fallback/payload_builder.rs @@ -1,9 +1,8 @@ use alloy::{ - consensus::{proofs, Transaction}, + consensus::{proofs, transaction::PooledTransaction, Transaction}, eips::{calc_excess_blob_gas, calc_next_block_base_fee, eip1559::BaseFeeParams}, primitives::{Address, Bytes}, }; -use reth_primitives::{SealedBlock, TransactionSigned}; use tracing::debug; use super::{ @@ -11,7 +10,7 @@ use super::{ DEFAULT_EXTRA_DATA, }; use crate::{ - builder::BuilderError, + builder::{BuilderError, SealedAlloyBlock}, client::{BeaconClient, ExecutionClient}, config::Opts, }; @@ -62,8 +61,8 @@ impl FallbackPayloadBuilder { pub async fn build_fallback_payload( &self, target_slot: u64, - transactions: &[TransactionSigned], - ) -> Result { + transactions: &[PooledTransaction], + ) -> Result { // Fetch the latest block to get the necessary parent values for the new block. // For the timestamp, we must use the one expected by the beacon chain instead, to // prevent edge cases where the proposer before us has missed their slot and therefore @@ -145,7 +144,7 @@ mod tests { use std::time::{SystemTime, UNIX_EPOCH}; use alloy::{ - consensus::{constants, proofs}, + consensus::{constants, proofs, transaction::PooledTransaction}, eips::eip2718::{Decodable2718, Encodable2718}, network::{EthereumWallet, TransactionBuilder}, primitives::{hex, Address}, @@ -153,7 +152,6 @@ mod tests { signers::{k256::ecdsa::SigningKey, local::PrivateKeySigner}, }; use beacon_api_client::mainnet::Client as BeaconClient; - use reth_primitives::TransactionSigned; use tracing::warn; use crate::{ @@ -192,7 +190,7 @@ mod tests { let tx = default_test_transaction(addy, Some(nonce)).with_chain_id(17000); let tx_signed = tx.build(&wallet).await?; let raw_encoded = tx_signed.encoded_2718(); - let tx_signed_reth = TransactionSigned::decode_2718(&mut raw_encoded.as_slice())?; + let tx_signed_reth = PooledTransaction::decode_2718(&mut raw_encoded.as_slice())?; let slot = genesis_time + (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() / cfg.chain.slot_time()) + diff --git a/bolt-sidecar/src/builder/mod.rs b/bolt-sidecar/src/builder/mod.rs index d5648e0c..bf0d55c0 100644 --- a/bolt-sidecar/src/builder/mod.rs +++ b/bolt-sidecar/src/builder/mod.rs @@ -1,10 +1,14 @@ -use alloy::primitives::U256; +use alloy::{ + consensus::{transaction::PooledTransaction, BlockBody, Header}, + primitives::U256, +}; use alloy_rpc_types_engine::{ClientCode, PayloadStatusEnum}; use ethereum_consensus::{ crypto::{KzgCommitment, PublicKey}, deneb::mainnet::ExecutionPayloadHeader, ssz::prelude::{List, MerkleizationError}, }; +use reth_primitives::SealedBlock; use crate::{ common::secrets::BlsSecretKeyWrapper, @@ -40,6 +44,9 @@ pub use payload_fetcher::{LocalPayloadFetcher, PayloadFetcher}; #[doc(hidden)] mod compat; +/// Type alias for the sealed block. +type SealedAlloyBlock = SealedBlock>; + #[derive(Debug, thiserror::Error)] #[non_exhaustive] #[allow(missing_docs)] diff --git a/bolt-sidecar/src/builder/template.rs b/bolt-sidecar/src/builder/template.rs index 36d227da..973fdcc8 100644 --- a/bolt-sidecar/src/builder/template.rs +++ b/bolt-sidecar/src/builder/template.rs @@ -1,12 +1,11 @@ use alloy::{ - consensus::Transaction, + consensus::{transaction::PooledTransaction, Transaction}, primitives::{Address, TxHash, U256}, }; use ethereum_consensus::{ crypto::{KzgCommitment, KzgProof}, deneb::mainnet::{Blob, BlobsBundle}, }; -use reth_primitives::TransactionSigned; use std::collections::HashMap; use tracing::warn; @@ -47,10 +46,10 @@ impl BlockTemplate { /// Converts the list of signed constraints into a list of signed transactions. Use this when /// building a local execution payload. #[inline] - pub fn as_signed_transactions(&self) -> Vec { + pub fn as_signed_transactions(&self) -> Vec { self.signed_constraints_list .iter() - .flat_map(|sc| sc.message.transactions.iter().map(|c| c.clone().into_signed())) + .flat_map(|sc| sc.message.transactions.iter().map(|c| c.clone().into_inner())) .collect() } diff --git a/bolt-sidecar/src/primitives/transaction.rs b/bolt-sidecar/src/primitives/transaction.rs index a32f6f62..ed8d5d32 100644 --- a/bolt-sidecar/src/primitives/transaction.rs +++ b/bolt-sidecar/src/primitives/transaction.rs @@ -1,15 +1,14 @@ +use std::{borrow::Cow, fmt}; + use alloy::{ consensus::{ - transaction::PooledTransaction, BlobTransactionSidecar, Signed, Transaction, TxType, - Typed2718, + transaction::PooledTransaction, BlobTransactionSidecar, Transaction, TxType, Typed2718, }, eips::eip2718::{Decodable2718, Encodable2718}, hex, primitives::{Address, U256}, }; -use reth_primitives::TransactionSigned; use serde::{de, ser::SerializeSeq}; -use std::{borrow::Cow, fmt}; /// Trait that exposes additional information on transaction types that don't already do it /// by themselves (e.g. [`PooledTransaction`]). @@ -139,22 +138,6 @@ impl FullTransaction { self.tx } - /// Returns the signed transaction. - pub fn into_signed(self) -> TransactionSigned { - match self.tx { - PooledTransaction::Legacy(tx) => tx.into(), - PooledTransaction::Eip1559(tx) => tx.into(), - PooledTransaction::Eip2930(tx) => tx.into(), - PooledTransaction::Eip4844(tx) => { - let sig = *tx.signature(); - let hash = *tx.hash(); - let inner_tx = tx.into_parts().0.into_parts().0; - Signed::new_unchecked(inner_tx, sig, hash).into() - } - PooledTransaction::Eip7702(tx) => tx.into(), - } - } - /// Returns the sender of the transaction, if recovered. pub fn sender(&self) -> Option<&Address> { self.sender.as_ref() From ab429cebe46eb48dbb4fc20c2c0576d27070aa1a Mon Sep 17 00:00:00 2001 From: nicolas <48695862+merklefruit@users.noreply.github.com> Date: Wed, 29 Jan 2025 14:44:05 +0100 Subject: [PATCH 2/2] feat: remove all reth types --- bolt-sidecar/src/builder/compat.rs | 28 +++++++++---------- .../src/builder/fallback/engine_hinter.rs | 21 ++++++-------- .../src/builder/fallback/payload_builder.rs | 8 +++--- bolt-sidecar/src/builder/mod.rs | 9 +----- 4 files changed, 27 insertions(+), 39 deletions(-) diff --git a/bolt-sidecar/src/builder/compat.rs b/bolt-sidecar/src/builder/compat.rs index 957d46a7..4cc09b42 100644 --- a/bolt-sidecar/src/builder/compat.rs +++ b/bolt-sidecar/src/builder/compat.rs @@ -1,5 +1,5 @@ use alloy::{ - consensus::{transaction::PooledTransaction, BlockHeader}, + consensus::{transaction::PooledTransaction, Block, BlockHeader}, eips::{eip2718::Encodable2718, eip4895::Withdrawal}, primitives::{Address, Bloom, B256, U256}, rpc::types::Withdrawals, @@ -20,12 +20,10 @@ use ethereum_consensus::{ types::mainnet::ExecutionPayload as ConsensusExecutionPayload, }; -use super::SealedAlloyBlock; - /// Compatibility: convert a sealed header into an ethereum-consensus execution payload header. /// This requires recalculating the withdrals and transactions roots as SSZ instead of MPT roots. pub(crate) fn to_execution_payload_header( - sealed_block: &SealedAlloyBlock, + sealed_block: &Block, transactions: Vec, ) -> ConsensusExecutionPayloadHeader { // Transactions and withdrawals are treated as opaque byte arrays in consensus types @@ -42,7 +40,7 @@ pub(crate) fn to_execution_payload_header( let mut withdrawals_ssz: List = List::default(); - if let Some(withdrawals) = sealed_block.body().withdrawals.as_ref() { + if let Some(withdrawals) = sealed_block.body.withdrawals.as_ref() { for w in withdrawals { withdrawals_ssz.push(to_consensus_withdrawal(w)); } @@ -50,7 +48,7 @@ pub(crate) fn to_execution_payload_header( let withdrawals_root = withdrawals_ssz.hash_tree_root().expect("valid withdrawals root"); - let header = sealed_block.header(); + let header = &sealed_block.header; ConsensusExecutionPayloadHeader { parent_hash: to_bytes32(header.parent_hash), @@ -75,14 +73,14 @@ pub(crate) fn to_execution_payload_header( /// Compatibility: convert a sealed block into an Alloy execution payload pub(crate) fn to_alloy_execution_payload( - block: &SealedAlloyBlock, + block: &Block, block_hash: B256, ) -> ExecutionPayloadV3 { let alloy_withdrawals = - block.body().withdrawals.clone().map(|w| w.into_inner()).unwrap_or_default(); + block.body.withdrawals.clone().map(|w| w.into_inner()).unwrap_or_default(); let transactions = block - .body() + .body .transactions .iter() .map(|tx| tx.encoded_2718()) @@ -99,7 +97,7 @@ pub(crate) fn to_alloy_execution_payload( base_fee_per_gas: U256::from(block.base_fee_per_gas.unwrap_or_default()), block_number: block.number, extra_data: block.extra_data.clone(), - fee_recipient: block.header().beneficiary, + fee_recipient: block.header.beneficiary, gas_limit: block.gas_limit, gas_used: block.gas_used, logs_bloom: block.logs_bloom, @@ -116,12 +114,12 @@ pub(crate) fn to_alloy_execution_payload( /// Compatibility: convert a sealed block into an ethereum-consensus execution payload pub(crate) fn to_consensus_execution_payload( - value: &SealedAlloyBlock, + value: &Block, ) -> ConsensusExecutionPayload { - let hash = value.hash(); - let header = value.header(); - let transactions = &value.body().transactions; - let withdrawals = &value.body().withdrawals; + let hash = value.hash_slow(); + let header = &value.header; + let transactions = &value.body.transactions; + let withdrawals = &value.body.withdrawals; let transactions = transactions .iter() .map(|t| spec::Transaction::try_from(t.encoded_2718().as_ref()).unwrap()) diff --git a/bolt-sidecar/src/builder/fallback/engine_hinter.rs b/bolt-sidecar/src/builder/fallback/engine_hinter.rs index f13aae78..4e0d61bb 100644 --- a/bolt-sidecar/src/builder/fallback/engine_hinter.rs +++ b/bolt-sidecar/src/builder/fallback/engine_hinter.rs @@ -1,18 +1,17 @@ use std::ops::Deref; use alloy::{ - consensus::{transaction::PooledTransaction, Header, EMPTY_OMMER_ROOT_HASH}, + consensus::{transaction::PooledTransaction, Block, BlockBody, Header, EMPTY_OMMER_ROOT_HASH}, primitives::{Address, Bloom, Bytes, B256, B64, U256}, - rpc::types::{Block, Withdrawal, Withdrawals}, + rpc::types::{Block as RpcBlock, Withdrawal, Withdrawals}, }; use alloy_provider::ext::EngineApi; use alloy_rpc_types_engine::{ClientCode, ExecutionPayloadV3, JwtSecret, PayloadStatusEnum}; use reqwest::Url; -use reth_primitives::{BlockBody, SealedBlock, SealedHeader}; use tracing::{debug, error}; use crate::{ - builder::{compat::to_alloy_execution_payload, BuilderError, SealedAlloyBlock}, + builder::{compat::to_alloy_execution_payload, BuilderError}, client::EngineClient, }; @@ -52,7 +51,7 @@ impl EngineHinter { pub async fn fetch_payload_from_hints( &self, mut ctx: EngineHinterContext, - ) -> Result { + ) -> Result, BuilderError> { // The block body can be the same for all iterations, since it only contains // the transactions and withdrawals from the context. let body = ctx.build_block_body(); @@ -66,20 +65,18 @@ impl EngineHinter { // Build a new block header using the hints from the context let header = ctx.build_block_header_with_hints(); - let sealed_hash = header.hash_slow(); - let sealed_header = SealedHeader::new(header, sealed_hash); - let sealed_block = SealedBlock::new(sealed_header, body.clone()); - let block_hash = ctx.hints.block_hash.unwrap_or(sealed_block.hash()); + let block = Block { header, body: body.clone() }; + let block_hash = ctx.hints.block_hash.unwrap_or(block.hash_slow()); // build the new execution payload from the block header - let exec_payload = to_alloy_execution_payload(&sealed_block, block_hash); + let exec_payload = to_alloy_execution_payload(&block, block_hash); // attempt to fetch the next hint from the engine API payload response let hint = self.next_hint(exec_payload, &ctx).await?; debug!(?hint, "Received hint from engine API"); if matches!(hint, EngineApiHint::ValidPayload) { - return Ok(sealed_block); + return Ok(block); } // Populate the new hint in the context and continue the loop @@ -208,7 +205,7 @@ pub struct EngineHinterContext { pub block_timestamp: u64, pub transactions: Vec, pub withdrawals: Vec, - pub head_block: Block, + pub head_block: RpcBlock, pub hints: Hints, pub el_client_code: ClientCode, } diff --git a/bolt-sidecar/src/builder/fallback/payload_builder.rs b/bolt-sidecar/src/builder/fallback/payload_builder.rs index df7f2307..9ebca4ab 100644 --- a/bolt-sidecar/src/builder/fallback/payload_builder.rs +++ b/bolt-sidecar/src/builder/fallback/payload_builder.rs @@ -1,5 +1,5 @@ use alloy::{ - consensus::{proofs, transaction::PooledTransaction, Transaction}, + consensus::{proofs, transaction::PooledTransaction, Block, Transaction}, eips::{calc_excess_blob_gas, calc_next_block_base_fee, eip1559::BaseFeeParams}, primitives::{Address, Bytes}, }; @@ -10,7 +10,7 @@ use super::{ DEFAULT_EXTRA_DATA, }; use crate::{ - builder::{BuilderError, SealedAlloyBlock}, + builder::BuilderError, client::{BeaconClient, ExecutionClient}, config::Opts, }; @@ -62,7 +62,7 @@ impl FallbackPayloadBuilder { &self, target_slot: u64, transactions: &[PooledTransaction], - ) -> Result { + ) -> Result, BuilderError> { // Fetch the latest block to get the necessary parent values for the new block. // For the timestamp, we must use the one expected by the beacon chain instead, to // prevent edge cases where the proposer before us has missed their slot and therefore @@ -198,7 +198,7 @@ mod tests { let block = builder.build_fallback_payload(slot, &[tx_signed_reth]).await?; - assert_eq!(block.body().transactions.len(), 1); + assert_eq!(block.body.transactions.len(), 1); Ok(()) } diff --git a/bolt-sidecar/src/builder/mod.rs b/bolt-sidecar/src/builder/mod.rs index bf0d55c0..d5648e0c 100644 --- a/bolt-sidecar/src/builder/mod.rs +++ b/bolt-sidecar/src/builder/mod.rs @@ -1,14 +1,10 @@ -use alloy::{ - consensus::{transaction::PooledTransaction, BlockBody, Header}, - primitives::U256, -}; +use alloy::primitives::U256; use alloy_rpc_types_engine::{ClientCode, PayloadStatusEnum}; use ethereum_consensus::{ crypto::{KzgCommitment, PublicKey}, deneb::mainnet::ExecutionPayloadHeader, ssz::prelude::{List, MerkleizationError}, }; -use reth_primitives::SealedBlock; use crate::{ common::secrets::BlsSecretKeyWrapper, @@ -44,9 +40,6 @@ pub use payload_fetcher::{LocalPayloadFetcher, PayloadFetcher}; #[doc(hidden)] mod compat; -/// Type alias for the sealed block. -type SealedAlloyBlock = SealedBlock>; - #[derive(Debug, thiserror::Error)] #[non_exhaustive] #[allow(missing_docs)]