Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: move to PevmChain::get_tx_env #331

Merged
merged 3 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

use std::fmt::Debug;

use alloy_primitives::{B256, U256};
use alloy_rpc_types::{BlockTransactions, Header, Transaction};
use alloy_primitives::B256;
use alloy_rpc_types::{BlockTransactions, Header};
use revm::{
primitives::{BlockEnv, SpecId, TxEnv},
Handler,
Expand All @@ -22,20 +22,23 @@ pub enum RewardPolicy {

/// Custom behaviours for different chains & networks
pub trait PevmChain: Debug {
/// The transaction type
type Transaction: Debug + Clone + PartialEq;

/// The error type for [Self::get_block_spec].
type BlockSpecError: Debug + Clone + PartialEq;

/// The error type for [Self::get_gas_price].
type GasPriceError: Debug + Clone + PartialEq;
/// The error type for [Self::get_tx_env].
type TransactionParsingError: Debug + Clone + PartialEq;

/// Get chain id.
fn id(&self) -> u64;

/// Get block's [SpecId]
fn get_block_spec(&self, header: &Header) -> Result<SpecId, Self::BlockSpecError>;

/// Get tx gas price.
fn get_gas_price(&self, tx: &Transaction) -> Result<U256, Self::GasPriceError>;
/// Get [TxEnv]
fn get_tx_env(&self, tx: Self::Transaction) -> Result<TxEnv, Self::TransactionParsingError>;

/// Build [MvMemory]
fn build_mv_memory(
Expand All @@ -61,7 +64,7 @@ pub trait PevmChain: Debug {
fn calculate_receipt_root(
&self,
spec_id: SpecId,
txs: &BlockTransactions<Transaction>,
txs: &BlockTransactions<Self::Transaction>,
tx_results: &[PevmTxExecutionResult],
) -> B256;
}
Expand Down
72 changes: 51 additions & 21 deletions src/chain/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use alloy_chains::NamedChain;
use alloy_consensus::{ReceiptEnvelope, TxType};
use alloy_primitives::{B256, U256};
use alloy_provider::network::eip2718::Encodable2718;
use alloy_rpc_types::{BlockTransactions, Header, Transaction};
use alloy_rpc_types::{BlockTransactions, Header};
use revm::{
primitives::{BlockEnv, SpecId, TxEnv},
Handler,
Expand Down Expand Up @@ -44,9 +44,11 @@ pub enum EthereumBlockSpecError {
MissingTotalDifficulty,
}

/// Error type for [PevmEthereum::get_gas_price].
/// Represents errors that can occur when parsing transactions
#[derive(Debug, Clone, PartialEq)]
pub enum EthereumGasPriceError {
pub enum EthereumTransactionParsingError {
/// [tx.gas] is overflowed.
OverflowedGasLimit,
/// [tx.type] is invalid.
InvalidType(u8),
/// [tx.gas_price] is none.
Expand All @@ -55,9 +57,30 @@ pub enum EthereumGasPriceError {
MissingMaxFeePerGas,
}

fn get_ethereum_gas_price(
tx: &alloy_rpc_types::Transaction,
) -> Result<U256, EthereumTransactionParsingError> {
let tx_type_raw: u8 = tx.transaction_type.unwrap_or_default();
let Ok(tx_type) = TxType::try_from(tx_type_raw) else {
return Err(EthereumTransactionParsingError::InvalidType(tx_type_raw));
};

match tx_type {
TxType::Legacy | TxType::Eip2930 => tx
.gas_price
.map(U256::from)
.ok_or(EthereumTransactionParsingError::MissingGasPrice),
TxType::Eip1559 | TxType::Eip4844 | TxType::Eip7702 => tx
.max_fee_per_gas
.map(U256::from)
.ok_or(EthereumTransactionParsingError::MissingMaxFeePerGas),
}
}

impl PevmChain for PevmEthereum {
type Transaction = alloy_rpc_types::Transaction;
type BlockSpecError = EthereumBlockSpecError;
type GasPriceError = EthereumGasPriceError;
type TransactionParsingError = EthereumTransactionParsingError;

fn id(&self) -> u64 {
self.id
Expand Down Expand Up @@ -102,22 +125,29 @@ impl PevmChain for PevmEthereum {
})
}

fn get_gas_price(&self, tx: &Transaction) -> Result<U256, Self::GasPriceError> {
let tx_type_raw: u8 = tx.transaction_type.unwrap_or_default();
let Ok(tx_type) = TxType::try_from(tx_type_raw) else {
return Err(EthereumGasPriceError::InvalidType(tx_type_raw));
};

match tx_type {
TxType::Legacy | TxType::Eip2930 => tx
.gas_price
.map(U256::from)
.ok_or(EthereumGasPriceError::MissingGasPrice),
TxType::Eip1559 | TxType::Eip4844 | TxType::Eip7702 => tx
.max_fee_per_gas
.map(U256::from)
.ok_or(EthereumGasPriceError::MissingMaxFeePerGas),
}
/// Get the REVM tx envs of an Alloy block.
// https://github.com/paradigmxyz/reth/blob/280aaaedc4699c14a5b6e88f25d929fe22642fa3/crates/primitives/src/revm/env.rs#L234-L339
// https://github.com/paradigmxyz/reth/blob/280aaaedc4699c14a5b6e88f25d929fe22642fa3/crates/primitives/src/alloy_compat.rs#L112-L233
// TODO: Properly test this.
fn get_tx_env(&self, tx: Self::Transaction) -> Result<TxEnv, EthereumTransactionParsingError> {
Ok(TxEnv {
caller: tx.from,
gas_limit: tx
.gas
.try_into()
.map_err(|_| EthereumTransactionParsingError::OverflowedGasLimit)?,
gas_price: get_ethereum_gas_price(&tx)?,
gas_priority_fee: tx.max_priority_fee_per_gas.map(U256::from),
transact_to: tx.to.into(),
value: tx.value,
data: tx.input,
nonce: Some(tx.nonce),
chain_id: tx.chain_id,
access_list: tx.access_list.unwrap_or_default().into(),
blob_hashes: tx.blob_versioned_hashes.unwrap_or_default(),
max_fee_per_blob_gas: tx.max_fee_per_blob_gas.map(U256::from),
authorization_list: None, // TODO: Support in the upcoming hardfork
})
}

fn build_mv_memory(
Expand Down Expand Up @@ -156,7 +186,7 @@ impl PevmChain for PevmEthereum {
fn calculate_receipt_root(
&self,
_spec_id: SpecId,
txs: &BlockTransactions<Transaction>,
txs: &BlockTransactions<Self::Transaction>,
tx_results: &[PevmTxExecutionResult],
) -> B256 {
// 1. Create an iterator of ReceiptEnvelope
Expand Down
48 changes: 2 additions & 46 deletions src/compat.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// TODO: Support custom chains like OP & RISE
// Ideally REVM & Alloy would provide all these.

use alloy_rpc_types::{Header, Transaction};
use revm::primitives::{BlobExcessGasAndPrice, BlockEnv, TransactTo, TxEnv, U256};

use crate::chain::PevmChain;
use alloy_rpc_types::Header;
use revm::primitives::{BlobExcessGasAndPrice, BlockEnv, U256};

/// Get the REVM block env of an Alloy block.
// https://github.com/paradigmxyz/reth/blob/280aaaedc4699c14a5b6e88f25d929fe22642fa3/crates/primitives/src/revm/env.rs#L23-L48
Expand All @@ -24,45 +22,3 @@ pub(crate) fn get_block_env(header: &Header) -> BlockEnv {
.map(|excess_blob_gas| BlobExcessGasAndPrice::new(excess_blob_gas as u64)),
}
}

/// Represents errors that can occur when parsing transactions
#[derive(Debug, Clone, PartialEq)]
pub enum TransactionParsingError<C: PevmChain> {
OverflowedGasLimit,
GasPriceError(C::GasPriceError),
MissingMaxFeePerGas,
InvalidType(u8),
}

/// Get the REVM tx envs of an Alloy block.
// https://github.com/paradigmxyz/reth/blob/280aaaedc4699c14a5b6e88f25d929fe22642fa3/crates/primitives/src/revm/env.rs#L234-L339
// https://github.com/paradigmxyz/reth/blob/280aaaedc4699c14a5b6e88f25d929fe22642fa3/crates/primitives/src/alloy_compat.rs#L112-L233
// TODO: Properly test this.
pub(crate) fn get_tx_env<C: PevmChain>(
chain: &C,
tx: Transaction,
) -> Result<TxEnv, TransactionParsingError<C>> {
Ok(TxEnv {
caller: tx.from,
gas_limit: tx
.gas
.try_into()
.map_err(|_| TransactionParsingError::OverflowedGasLimit)?,
gas_price: chain
.get_gas_price(&tx)
.map_err(TransactionParsingError::GasPriceError)?,
gas_priority_fee: tx.max_priority_fee_per_gas.map(U256::from),
transact_to: match tx.to {
Some(address) => TransactTo::Call(address),
None => TransactTo::Create,
},
value: tx.value,
data: tx.input,
nonce: Some(tx.nonce),
chain_id: tx.chain_id,
access_list: tx.access_list.unwrap_or_default().0,
blob_hashes: tx.blob_versioned_hashes.unwrap_or_default(),
max_fee_per_blob_gas: tx.max_fee_per_blob_gas.map(U256::from),
authorization_list: None, // TODO: Support in the upcoming hardfork
})
}
10 changes: 5 additions & 5 deletions src/pevm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use revm::{

use crate::{
chain::PevmChain,
compat::{get_block_env, get_tx_env, TransactionParsingError},
compat::get_block_env,
mv_memory::MvMemory,
scheduler::Scheduler,
storage::StorageWrapper,
Expand All @@ -36,7 +36,7 @@ pub enum PevmError<C: PevmChain> {
/// Transactions lack information for execution.
MissingTransactionData,
/// Invalid input transaction.
InvalidTransaction(TransactionParsingError<C>),
InvalidTransaction(C::TransactionParsingError),
/// Storage error.
// TODO: More concrete types than just an arbitrary string.
StorageError(String),
Expand Down Expand Up @@ -98,7 +98,7 @@ impl Pevm {
&mut self,
storage: &S,
chain: &C,
block: Block,
block: Block<C::Transaction>,
concurrency_level: NonZeroUsize,
force_sequential: bool,
) -> PevmResult<C> {
Expand All @@ -109,8 +109,8 @@ impl Pevm {
let tx_envs = match block.transactions {
BlockTransactions::Full(txs) => txs
.into_iter()
.map(|tx| get_tx_env(chain, tx))
.collect::<Result<Vec<TxEnv>, TransactionParsingError<_>>>()
.map(|tx| chain.get_tx_env(tx))
.collect::<Result<Vec<TxEnv>, _>>()
.map_err(PevmError::InvalidTransaction)?,
_ => return Err(PevmError::MissingTransactionData),
};
Expand Down
2 changes: 1 addition & 1 deletion tests/common/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub fn test_execute_revm<S: Storage + Send + Sync>(storage: S, txs: Vec<TxEnv>)
pub fn test_execute_alloy<S: Storage + Send + Sync, C: PevmChain + Send + Sync + PartialEq>(
storage: &S,
chain: &C,
block: Block,
block: Block<C::Transaction>,
must_match_block_header: bool,
) {
let concurrency_level = thread::available_parallelism().unwrap_or(NonZeroUsize::MIN);
Expand Down