diff --git a/src/common/mod.rs b/src/common/mod.rs index a4789eee..4c0c76d2 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -92,10 +92,10 @@ impl From<&ExecutionPayload> for BlockInfo { /// Converts an [ExecutionPayload] to [BlockInfo] fn from(value: &ExecutionPayload) -> Self { Self { - number: value.block_number.as_u64(), - hash: B256::from_slice(value.block_hash.as_bytes()), - parent_hash: B256::from_slice(value.parent_hash.as_bytes()), - timestamp: value.timestamp.as_u64(), + number: value.block_number.try_into().unwrap_or_default(), + hash: value.block_hash, + parent_hash: value.parent_hash, + timestamp: value.timestamp.try_into().unwrap_or_default(), } } } diff --git a/src/derive/stages/attributes.rs b/src/derive/stages/attributes.rs index bc99287f..e41fac5b 100644 --- a/src/derive/stages/attributes.rs +++ b/src/derive/stages/attributes.rs @@ -1,7 +1,7 @@ use std::sync::{Arc, RwLock}; use ethers::abi::{decode, encode, ParamType, Token}; -use ethers::types::{Address, Log, H256, U256, U64}; +use ethers::types::{Address, Log, H256, U256}; use ethers::utils::{keccak256, rlp::Encodable, rlp::RlpStream}; use eyre::Result; @@ -89,7 +89,6 @@ impl Attributes { None }; - let timestamp = U64([input.timestamp]); let l1_inclusion_block = Some(input.l1_inclusion_block); let seq_number = Some(self.sequence_number); let prev_randao = l1_info.block_info.mix_hash; @@ -98,12 +97,12 @@ impl Attributes { let suggested_fee_recipient = SystemAccounts::default().fee_vault; PayloadAttributes { - timestamp, - prev_randao: H256::from_slice(prev_randao.as_slice()), - suggested_fee_recipient: Address::from_slice(suggested_fee_recipient.as_slice()), + timestamp: alloy_primitives::U64::from(input.timestamp), + prev_randao, + suggested_fee_recipient, transactions, no_tx_pool: true, - gas_limit: U64([l1_info.system_config.gas_limit.try_into().unwrap()]), + gas_limit: alloy_primitives::U64::from(l1_info.system_config.gas_limit), withdrawals, epoch, l1_inclusion_block, diff --git a/src/driver/engine_driver.rs b/src/driver/engine_driver.rs index 50c02303..10f33e9f 100644 --- a/src/driver/engine_driver.rs +++ b/src/driver/engine_driver.rs @@ -1,6 +1,5 @@ use std::sync::Arc; -use alloy_primitives::B256; use ethers::providers::{Http, Middleware, Provider}; use ethers::types::Transaction; use ethers::{ @@ -38,7 +37,8 @@ pub struct EngineDriver { impl EngineDriver { /// Initiates validation & production of a new L2 block from the given [PayloadAttributes] and updates the forkchoice pub async fn handle_attributes(&mut self, attributes: PayloadAttributes) -> Result<()> { - let block: Option> = self.block_at(attributes.timestamp.as_u64()).await; + let timestamp: u64 = attributes.timestamp.try_into()?; + let block: Option> = self.block_at(timestamp).await; if let Some(block) = block { if should_skip(&block, &attributes)? { @@ -100,10 +100,10 @@ impl EngineDriver { let payload = self.build_payload(attributes).await?; let new_head = BlockInfo { - number: payload.block_number.as_u64(), - hash: B256::from_slice(payload.block_hash.as_bytes()), - parent_hash: B256::from_slice(payload.parent_hash.as_bytes()), - timestamp: payload.timestamp.as_u64(), + number: payload.block_number.try_into().unwrap_or_default(), + hash: payload.block_hash, + parent_hash: payload.parent_hash, + timestamp: payload.timestamp.try_into().unwrap_or_default(), }; self.push_payload(payload).await?; @@ -199,9 +199,9 @@ impl EngineDriver { /// - `finalized_block` = `finalized_head` fn create_forkchoice_state(&self) -> ForkchoiceState { ForkchoiceState { - head_block_hash: H256::from_slice(self.unsafe_head.hash.as_slice()), - safe_block_hash: H256::from_slice(self.safe_head.hash.as_slice()), - finalized_block_hash: H256::from_slice(self.finalized_head.hash.as_slice()), + head_block_hash: self.unsafe_head.hash, + safe_block_hash: self.safe_head.hash, + finalized_block_hash: self.finalized_head.hash, } } @@ -243,10 +243,10 @@ fn should_skip(block: &Block, attributes: &PayloadAttributes) -> Re tracing::debug!("block hashes: {:?}", block_hashes); let is_same = attributes_hashes == block_hashes - && attributes.timestamp.as_u64() == block.timestamp.as_u64() - && attributes.prev_randao == block.mix_hash.unwrap() - && attributes.suggested_fee_recipient == block.author.unwrap() - && attributes.gas_limit.as_u64() == block.gas_limit.as_u64(); + && attributes.timestamp == alloy_primitives::U64::from(block.timestamp.as_u64()) + && attributes.prev_randao == alloy_primitives::B256::from_slice(block.mix_hash.unwrap().as_bytes()) + && attributes.suggested_fee_recipient == alloy_primitives::Address::from_slice(block.author.unwrap().as_bytes()) + && attributes.gas_limit == alloy_primitives::U64::from(block.gas_limit.as_u64()); Ok(is_same) } diff --git a/src/driver/mod.rs b/src/driver/mod.rs index 522fa720..187aa384 100644 --- a/src/driver/mod.rs +++ b/src/driver/mod.rs @@ -230,14 +230,17 @@ impl Driver { } self.future_unsafe_blocks.retain(|payload| { - let unsafe_block_num = payload.block_number.as_u64(); + let unsafe_block_num: u64 = match payload.block_number.try_into() { + Ok(num) => num, + Err(_) => return false, + }; let synced_block_num = self.engine_driver.unsafe_head.number; unsafe_block_num > synced_block_num && unsafe_block_num - synced_block_num < 1024 }); let next_unsafe_payload = self.future_unsafe_blocks.iter().find(|p| { - alloy_primitives::B256::from_slice(p.parent_hash.as_bytes()) + p.parent_hash == self.engine_driver.unsafe_head.hash }); diff --git a/src/engine/fork.rs b/src/engine/fork.rs index c078a5b4..db5a6280 100644 --- a/src/engine/fork.rs +++ b/src/engine/fork.rs @@ -1,5 +1,4 @@ use alloy_primitives::B256; -use ethers::types::H256; use serde::{Deserialize, Serialize}; use super::{PayloadId, PayloadStatus}; @@ -23,23 +22,22 @@ pub struct ForkChoiceUpdate { #[serde(rename_all = "camelCase")] pub struct ForkchoiceState { /// 32 byte block hash of the head of the canonical chain - pub head_block_hash: H256, + pub head_block_hash: B256, /// 32 byte "safe" block hash of the canonical chain under certain synchrony and honesty assumptions /// This value MUST be either equal to or an ancestor of headBlockHash - pub safe_block_hash: H256, + pub safe_block_hash: B256, /// 32 byte block hash of the most recent finalized block - pub finalized_block_hash: H256, + pub finalized_block_hash: B256, } impl ForkchoiceState { /// Creates a new fork choice state with the given head block hash. /// The safe and finalized block hashes are set to the head block hash. pub fn from_single_head(head_block_hash: B256) -> Self { - let hash = H256::from_slice(head_block_hash.as_slice()); Self { - head_block_hash: hash, - safe_block_hash: hash, - finalized_block_hash: hash, + head_block_hash, + safe_block_hash: head_block_hash, + finalized_block_hash: head_block_hash, } } } diff --git a/src/engine/payload.rs b/src/engine/payload.rs index 533e453b..738c6c6e 100644 --- a/src/engine/payload.rs +++ b/src/engine/payload.rs @@ -1,8 +1,8 @@ use alloy_consensus::TxEnvelope; use alloy_eips::eip2718::Encodable2718; -use alloy_rpc_types::Block as AlloyBlock; +use alloy_rpc_types::Block; use alloy_rpc_types::BlockTransactions; -use ethers::types::{Block, Bytes, Transaction, H160, H256, U64}; +use alloy_primitives::{Bytes, Address, B256, U64}; use eyre::Result; use serde::{Deserialize, Serialize}; @@ -16,17 +16,17 @@ use crate::{ #[serde(rename_all = "camelCase")] pub struct ExecutionPayload { /// A 32 byte hash of the parent payload - pub parent_hash: H256, - /// A 20 byte hash (aka Address) for the feeRecipient field of the new payload - pub fee_recipient: H160, + pub parent_hash: B256, + /// The fee recipient of the new payload + pub fee_recipient: Address, /// A 32 byte state root hash - pub state_root: H256, + pub state_root: B256, /// A 32 byte receipt root hash - pub receipts_root: H256, + pub receipts_root: B256, /// A 32 byte logs bloom filter pub logs_bloom: Bytes, /// A 32 byte beacon chain randomness value - pub prev_randao: H256, + pub prev_randao: B256, /// A 64 bit number for the current block index pub block_number: U64, /// A 64 bit value for the gas limit @@ -40,7 +40,7 @@ pub struct ExecutionPayload { /// 256 bits for the base fee per gas pub base_fee_per_gas: U64, /// The 32 byte block hash - pub block_hash: H256, + pub block_hash: B256, /// An array of transaction objects where each object is a byte list pub transactions: Vec, /// An array of beaconchain withdrawals. Always empty as this exists only for L1 compatibility @@ -54,11 +54,11 @@ pub struct ExecutionPayload { pub excess_blob_gas: Option, } -impl TryFrom for ExecutionPayload { +impl TryFrom for ExecutionPayload { type Error = eyre::Report; /// Converts a [Block] to an [ExecutionPayload] - fn try_from(value: AlloyBlock) -> Result { + fn try_from(value: Block) -> Result { let txs = if let BlockTransactions::Full(txs) = value.transactions { txs } else { @@ -75,62 +75,24 @@ impl TryFrom for ExecutionPayload { .to_vec(); Ok(ExecutionPayload { - parent_hash: H256::from_slice(value.header.parent_hash.as_slice()), - fee_recipient: H160::from_slice(SystemAccounts::default().fee_vault.as_slice()), - state_root: H256::from_slice(value.header.state_root.as_slice()), - receipts_root: H256::from_slice(value.header.receipts_root.as_slice()), + parent_hash: value.header.parent_hash, + fee_recipient: SystemAccounts::default().fee_vault, + state_root: value.header.state_root, + receipts_root: value.header.receipts_root, logs_bloom: value.header.logs_bloom.0.to_vec().into(), - prev_randao: H256::from_slice(value.header.mix_hash.unwrap().as_slice()), - block_number: value.header.number.unwrap().into(), - gas_limit: (value.header.gas_limit as u64).into(), - gas_used: (value.header.gas_used as u64).into(), - timestamp: value.header.timestamp.into(), + prev_randao: value.header.mix_hash.ok_or_else(|| eyre::eyre!("Missing mix hash"))?, + block_number: value.header.number.ok_or_else(|| eyre::eyre!("Missing block number"))?.try_into()?, + gas_limit: (value.header.gas_limit as u64).try_into()?, + gas_used: (value.header.gas_used as u64).try_into()?, + timestamp: value.header.timestamp.try_into()?, extra_data: Bytes::from(value.header.extra_data.0), base_fee_per_gas: (value.header.base_fee_per_gas.unwrap_or_else(|| 0u64.into()) as u64) - .into(), - block_hash: H256::from_slice(value.header.hash.unwrap().as_slice()), + .try_into()?, + block_hash: value.header.hash.ok_or_else(|| eyre::eyre!("Missing block hash"))?, transactions: encoded_txs, withdrawals: Some(Vec::new()), - blob_gas_used: value.header.blob_gas_used.map(|v| (v as u64).into()), - excess_blob_gas: value.header.excess_blob_gas.map(|v| (v as u64).into()), - }) - } -} - -impl TryFrom> for ExecutionPayload { - type Error = eyre::Report; - - /// Converts a [Block] to an [ExecutionPayload] - fn try_from(value: Block) -> Result { - let encoded_txs = (*value - .transactions - .into_iter() - .map(|tx| RawTransaction(tx.rlp().to_vec())) - .collect::>()) - .to_vec(); - - Ok(ExecutionPayload { - parent_hash: value.parent_hash, - fee_recipient: H160::from_slice(SystemAccounts::default().fee_vault.as_slice()), - state_root: value.state_root, - receipts_root: value.receipts_root, - logs_bloom: value.logs_bloom.unwrap().as_bytes().to_vec().into(), - prev_randao: value.mix_hash.unwrap(), - block_number: value.number.unwrap(), - gas_limit: value.gas_limit.as_u64().into(), - gas_used: value.gas_used.as_u64().into(), - timestamp: value.timestamp.as_u64().into(), - extra_data: value.extra_data.clone(), - base_fee_per_gas: value - .base_fee_per_gas - .unwrap_or_else(|| 0u64.into()) - .as_u64() - .into(), - block_hash: value.hash.unwrap(), - transactions: encoded_txs, - withdrawals: Some(Vec::new()), - blob_gas_used: value.blob_gas_used.map(|v| v.as_u64().into()), - excess_blob_gas: value.excess_blob_gas.map(|v| v.as_u64().into()), + blob_gas_used: value.header.blob_gas_used.map(|v| (v as u64).try_into()).transpose()?, + excess_blob_gas: value.header.excess_blob_gas.map(|v| (v as u64).try_into()).transpose()?, }) } } @@ -145,9 +107,9 @@ pub struct PayloadAttributes { /// 64 bit value for the timestamp field of the new payload. pub timestamp: U64, /// 32 byte value for the prevRandao field of the new payload. - pub prev_randao: H256, + pub prev_randao: B256, /// 20 bytes suggested value for the feeRecipient field of the new payload. - pub suggested_fee_recipient: H160, + pub suggested_fee_recipient: Address, /// Array of transactions to be included in the new payload. pub transactions: Option>, /// Boolean value indicating whether or not the payload should be built without including transactions from the txpool. @@ -187,7 +149,7 @@ pub struct PayloadStatus { /// The status of the payload. pub status: Status, /// 32 Bytes - the hash of the most recent valid block in the branch defined by payload and its ancestors - pub latest_valid_hash: Option, + pub latest_valid_hash: Option, /// A message providing additional details on the validation error if the payload is classified as INVALID or INVALID_BLOCK_HASH. #[serde(default)] pub validation_error: Option, @@ -213,37 +175,30 @@ pub enum Status { #[cfg(test)] mod tests { - - use ethers::{ - providers::{Http, Middleware, Provider}, - types::H256, - }; use eyre::Result; - + use alloy_provider::{Provider, ProviderBuilder}; + use alloy_primitives::{b256, uint}; use crate::engine::ExecutionPayload; #[tokio::test] async fn test_from_block_hash_to_execution_paylaod() -> Result<()> { - if std::env::var("L2_TEST_RPC_URL").is_ok() { - let checkpoint_hash: H256 = - "0xc2794a16acacd9f7670379ffd12b6968ff98e2a602f57d7d1f880220aa5a4973".parse()?; + let Ok(l2_rpc_url) = std::env::var("L2_TEST_RPC_URL") else { + return Ok(()); + }; + let checkpoint_hash = b256!("c2794a16acacd9f7670379ffd12b6968ff98e2a602f57d7d1f880220aa5a4973"); + let url = reqwest::Url::parse(&l2_rpc_url)?; + let l2_provider = ProviderBuilder::new().on_http(url); - let l2_rpc = std::env::var("L2_TEST_RPC_URL")?; - let checkpoint_sync_url = Provider::::try_from(l2_rpc)?; - let checkpoint_block = checkpoint_sync_url - .get_block_with_txs(checkpoint_hash) - .await? - .unwrap(); + let checkpoint_block = l2_provider + .get_block(checkpoint_hash.into(), true) + .await? + .unwrap(); - let payload = ExecutionPayload::try_from(checkpoint_block)?; + let payload = ExecutionPayload::try_from(checkpoint_block)?; - assert_eq!( - payload.block_hash, - "0xc2794a16acacd9f7670379ffd12b6968ff98e2a602f57d7d1f880220aa5a4973".parse()? - ); - assert_eq!(payload.block_number, 8453214u64.into()); - assert_eq!(payload.base_fee_per_gas, 50u64.into()); - } + assert_eq!(payload.block_hash, checkpoint_hash); + assert_eq!(payload.block_number, uint!(8453214U64)); + assert_eq!(payload.base_fee_per_gas, uint!(50U64)); Ok(()) } diff --git a/src/network/handlers/block_handler.rs b/src/network/handlers/block_handler.rs index 54868c9d..79d248c0 100644 --- a/src/network/handlers/block_handler.rs +++ b/src/network/handlers/block_handler.rs @@ -102,8 +102,9 @@ impl BlockHandler { .unwrap() .as_secs(); - let is_future = envelope.payload.timestamp.as_u64() > current_timestamp + 5; - let is_past = envelope.payload.timestamp.as_u64() < current_timestamp - 60; + let timestamp: u64 = envelope.payload.timestamp.try_into().unwrap_or_default(); + let is_future = timestamp > current_timestamp + 5; + let is_past = timestamp < current_timestamp - 60; let time_valid = !(is_future || is_past); let msg = envelope.hash.signature_message(self.chain_id);