Skip to content

Commit

Permalink
chore(drive): alloy type port
Browse files Browse the repository at this point in the history
  • Loading branch information
refcell committed Apr 30, 2024
1 parent ca41e5a commit 7fb3c4b
Show file tree
Hide file tree
Showing 10 changed files with 577 additions and 593 deletions.
31 changes: 11 additions & 20 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
use std::fmt::Debug;

use alloy_primitives::B256;
use ethers::{
types::{Block, Transaction},
utils::rlp::{Decodable, DecoderError, Rlp},
};
use alloy_rpc_types::Block;
use eyre::Result;
use figment::value::{Dict, Tag, Value};
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
Expand All @@ -29,7 +26,7 @@ pub struct BlockInfo {
}

/// A raw transaction
#[derive(Clone, PartialEq, Eq)]
#[derive(Clone, alloy_rlp::RlpDecodable, alloy_rlp::RlpEncodable, PartialEq, Eq)]
pub struct RawTransaction(pub Vec<u8>);

/// L1 epoch block
Expand Down Expand Up @@ -57,23 +54,25 @@ impl From<BlockInfo> for Value {
}
}

impl TryFrom<Block<Transaction>> for BlockInfo {
impl TryFrom<Block> for BlockInfo {
type Error = eyre::Report;

/// Converts a [Block] to [BlockInfo]
fn try_from(block: Block<Transaction>) -> Result<Self> {
fn try_from(block: Block) -> Result<Self> {
let number = block
.header
.number
.ok_or(eyre::eyre!("block not included"))?
.as_u64();
.try_into()?;

let hash = block.hash.ok_or(eyre::eyre!("block not included"))?;
let hash = block.header.hash.ok_or(eyre::eyre!("block not included"))?;
let timestamp = block.header.timestamp.try_into()?;

Ok(BlockInfo {
number,
hash: B256::from_slice(hash.as_bytes()),
parent_hash: B256::from_slice(block.parent_hash.as_bytes()),
timestamp: block.timestamp.as_u64(),
hash,
parent_hash: block.header.parent_hash,
timestamp,
})
}
}
Expand Down Expand Up @@ -111,14 +110,6 @@ impl From<&AttributesDepositedCall> for Epoch {
}
}

impl Decodable for RawTransaction {
/// Decodes RLP encoded bytes into [RawTransaction] bytes
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
let tx_bytes: Vec<u8> = rlp.as_val()?;
Ok(Self(tx_bytes))
}
}

impl Debug for RawTransaction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "0x{}", hex::encode(&self.0))
Expand Down
6 changes: 3 additions & 3 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{fmt, iter, path::PathBuf, process::exit, str::FromStr};

use alloy_primitives::{Address, B256, U256};
use alloy_primitives::{Address, B256, U64, U256};
use figment::{
providers::{Format, Serialized, Toml},
Figment,
Expand Down Expand Up @@ -293,13 +293,13 @@ impl ChainConfig {
}

/// Returns true if the block is the first block subject to the Ecotone hardfork
pub fn is_ecotone_activation_block(&self, l2_block_timestamp: u64) -> bool {
pub fn is_ecotone_activation_block(&self, l2_block_timestamp: U64) -> bool {
l2_block_timestamp == self.ecotone_time

Check failure on line 297 in src/config/mod.rs

View workflow job for this annotation

GitHub Actions / clippy

mismatched types

Check failure on line 297 in src/config/mod.rs

View workflow job for this annotation

GitHub Actions / check

mismatched types

Check failure on line 297 in src/config/mod.rs

View workflow job for this annotation

GitHub Actions / test

mismatched types

Check failure on line 297 in src/config/mod.rs

View workflow job for this annotation

GitHub Actions / build

mismatched types
}

/// Returns true if Ecotone hardfork is active but the block is not the
/// first block subject to the hardfork. Ecotone activation at genesis does not count.
pub fn is_ecotone_but_not_first_block(&self, l2_block_timestamp: u64) -> bool {
pub fn is_ecotone_but_not_first_block(&self, l2_block_timestamp: U64) -> bool {
let is_ecotone = l2_block_timestamp >= self.ecotone_time;

Check failure on line 303 in src/config/mod.rs

View workflow job for this annotation

GitHub Actions / check

mismatched types

Check failure on line 303 in src/config/mod.rs

View workflow job for this annotation

GitHub Actions / test

mismatched types

Check failure on line 303 in src/config/mod.rs

View workflow job for this annotation

GitHub Actions / build

mismatched types

is_ecotone && !self.is_ecotone_activation_block(l2_block_timestamp)
Expand Down
3 changes: 2 additions & 1 deletion src/derive/stages/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ethers::utils::{keccak256, rlp::Encodable, rlp::RlpStream};

use eyre::Result;

use alloy_primitives::U64;
use crate::common::{Epoch, RawTransaction};
use crate::config::{Config, SystemAccounts};
use crate::derive::state::State;
Expand Down Expand Up @@ -136,7 +137,7 @@ impl Attributes {
if self
.config
.chain
.is_ecotone_activation_block(input.timestamp)
.is_ecotone_activation_block(U64::from(input.timestamp))
{
tracing::info!("found Ecotone activation block; Upgrade transactions added");
let mut ecotone_upgrade_txs = get_ecotone_upgrade_transactions();
Expand Down
14 changes: 10 additions & 4 deletions src/derive/stages/batches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::io::Read;
use std::sync::{Arc, RwLock};
use alloy_rlp::Decodable;

use ethers::utils::rlp::Rlp;
use eyre::Result;
Expand Down Expand Up @@ -204,13 +205,17 @@ where
}

// check that block builds on existing chain
if alloy_primitives::B256::from_slice(batch.parent_hash.as_bytes()) != head.hash {
if batch.parent_hash != head.hash {
tracing::warn!("invalid parent hash");
return BatchStatus::Drop;
}

// check the inclusion delay
if batch.epoch_num + self.config.chain.seq_window_size < batch.l1_inclusion_block {
if batch.l1_inclusion_block.is_none() {
tracing::warn!("missing inclusion block");
return BatchStatus::Drop;
}
if batch.epoch_num + self.config.chain.seq_window_size < batch.l1_inclusion_block.unwrap_or(0) {
tracing::warn!("inclusion window elapsed");
return BatchStatus::Drop;
}
Expand All @@ -226,7 +231,7 @@ where
};

if let Some(batch_origin) = batch_origin {
if alloy_primitives::B256::from_slice(batch.epoch_hash.as_bytes()) != batch_origin.hash
if batch.epoch_hash != batch_origin.hash
{
tracing::warn!("invalid epoch hash");
return BatchStatus::Drop;
Expand Down Expand Up @@ -434,7 +439,8 @@ fn decode_batches(channel: &Channel, chain_id: u64) -> Result<Vec<Batch>> {
let rlp = Rlp::new(batch_content);
let size = rlp.payload_info()?.total();

let batch = SingleBatch::decode(&rlp, channel.l1_inclusion_block)?;
let mut batch = SingleBatch::decode(&mut batch_content)?;
batch.l1_inclusion_block = Some(channel.l1_inclusion_block);
batches.push(Batch::Single(batch));

offset += size + batch_info.header_len + 1;
Expand Down
35 changes: 8 additions & 27 deletions src/derive/stages/single_batch.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,29 @@
use ethers::{
types::H256,
utils::rlp::{DecoderError, Rlp},
};
use alloy_primitives::B256;
use alloy_rlp::{RlpDecodable, RlpEncodable};

use crate::common::RawTransaction;

use super::block_input::BlockInput;

/// Represents a single batch: a single encoded L2 block
#[derive(Debug, Clone)]
#[derive(Debug, RlpEncodable, RlpDecodable, Clone)]
#[rlp(trailing)]
pub struct SingleBatch {
/// Block hash of the previous L2 block
pub parent_hash: H256,
pub parent_hash: B256,
/// The batch epoch number. Same as the first L1 block number in the epoch.
pub epoch_num: u64,
/// The block hash of the first L1 block in the epoch
pub epoch_hash: H256,
pub epoch_hash: B256,
/// The L2 block timestamp of this batch
pub timestamp: u64,
/// The L2 block transactions in this batch
pub transactions: Vec<RawTransaction>,
/// The L1 block number this batch was fully derived from.
pub l1_inclusion_block: u64,
pub l1_inclusion_block: Option<u64>,
}

impl SingleBatch {
/// Decodes RLP bytes into a [SingleBatch]
pub fn decode(rlp: &Rlp, l1_inclusion_block: u64) -> Result<Self, DecoderError> {
let parent_hash = rlp.val_at(0)?;
let epoch_num = rlp.val_at(1)?;
let epoch_hash = rlp.val_at(2)?;
let timestamp = rlp.val_at(3)?;
let transactions = rlp.list_at(4)?;

Ok(SingleBatch {
parent_hash,
epoch_num,
epoch_hash,
timestamp,
transactions,
l1_inclusion_block,
})
}

/// If any transactions are empty or deposited transaction types.
pub fn has_invalid_transactions(&self) -> bool {
self.transactions
Expand All @@ -56,7 +37,7 @@ impl SingleBatch {
timestamp: self.timestamp,
epoch: self.epoch_num,
transactions: self.transactions.clone(),
l1_inclusion_block: self.l1_inclusion_block,
l1_inclusion_block: self.l1_inclusion_block.unwrap_or(0),
}
}
}
45 changes: 23 additions & 22 deletions src/driver/engine_driver.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
//! A module to handle block production & validation

use std::sync::Arc;

use ethers::providers::{Http, Middleware, Provider};
use ethers::types::Transaction;
use ethers::{
types::{Block, H256},
utils::keccak256,
};
use alloy_primitives::keccak256;
use alloy_rpc_types::{BlockTransactions, Block};
use alloy_provider::{Provider, ReqwestProvider};
use eyre::Result;

use crate::{
Expand All @@ -19,7 +18,7 @@ pub struct EngineDriver<E: Engine> {
/// The L2 execution engine
engine: Arc<E>,
/// Provider for the local L2 execution RPC
provider: Provider<Http>,
provider: ReqwestProvider,
/// Blocktime of the L2 chain
blocktime: u64,
/// Most recent block found on the p2p network
Expand All @@ -38,7 +37,7 @@ impl<E: Engine> EngineDriver<E> {
/// 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 timestamp: u64 = attributes.timestamp.try_into()?;
let block: Option<Block<Transaction>> = self.block_at(timestamp).await;
let block: Option<Block> = self.block_at(timestamp).await;

if let Some(block) = block {
if should_skip(&block, &attributes)? {
Expand Down Expand Up @@ -117,7 +116,7 @@ impl<E: Engine> EngineDriver<E> {
async fn skip_attributes(
&mut self,
attributes: PayloadAttributes,
block: Block<Transaction>,
block: Block,
) -> Result<()> {
let new_epoch = *attributes.epoch.as_ref().unwrap();
let new_head = BlockInfo::try_from(block)?;
Expand Down Expand Up @@ -206,22 +205,22 @@ impl<E: Engine> EngineDriver<E> {
}

/// Fetches the L2 block for a given timestamp from the L2 Execution Client
async fn block_at(&self, timestamp: u64) -> Option<Block<Transaction>> {
async fn block_at(&self, timestamp: u64) -> Option<Block> {
let time_diff = timestamp as i64 - self.finalized_head.timestamp as i64;
let blocks = time_diff / self.blocktime as i64;
let block_num = self.finalized_head.number as i64 + blocks;
self.provider
.get_block_with_txs(block_num as u64)
.get_block((block_num as u64).into(), true)
.await
.ok()?
}
}

/// True if transactions in [PayloadAttributes] are not the same as those in a fetched L2 [Block]
fn should_skip(block: &Block<Transaction>, attributes: &PayloadAttributes) -> Result<bool> {
fn should_skip(block: &Block, attributes: &PayloadAttributes) -> Result<bool> {
tracing::debug!(
"comparing block at {} with attributes at {}",
block.timestamp,
block.header.timestamp,
attributes.timestamp
);

Expand All @@ -230,11 +229,14 @@ fn should_skip(block: &Block<Transaction>, attributes: &PayloadAttributes) -> Re
.as_ref()
.unwrap()
.iter()
.map(|tx| H256(keccak256(&tx.0)))
.map(|tx| keccak256(&tx.0))
.collect::<Vec<_>>();

let block_hashes = block
.transactions
let BlockTransactions::Full(txs) = &block.transactions else {
return Ok(true);
};

let block_hashes = txs
.iter()
.map(|tx| tx.hash())
.collect::<Vec<_>>();
Expand All @@ -243,12 +245,11 @@ fn should_skip(block: &Block<Transaction>, attributes: &PayloadAttributes) -> Re
tracing::debug!("block hashes: {:?}", block_hashes);

let is_same = attributes_hashes == block_hashes
&& 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.timestamp == block.header.timestamp
&& block.header.mix_hash.map_or(false, |m| m == attributes.prev_randao)
&& 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());
== block.header.miner
&& attributes.gas_limit == block.header.gas_limit;

Ok(is_same)
}
Expand All @@ -258,7 +259,7 @@ impl EngineDriver<EngineApi> {
pub fn new(
finalized_head: BlockInfo,
finalized_epoch: Epoch,
provider: Provider<Http>,
provider: ReqwestProvider,
config: &Arc<Config>,
) -> Result<Self> {
let engine = Arc::new(EngineApi::new(&config.l2_engine_url, &config.jwt_secret));
Expand Down
Loading

0 comments on commit 7fb3c4b

Please sign in to comment.