Skip to content

Commit

Permalink
Merge pull request #73 from ethereum-optimism/0xkitsune/alloy
Browse files Browse the repository at this point in the history
chore(op-test-vectors): Update `ExecutionFixture` to use `op-alloy-consensus` types
  • Loading branch information
clabby authored Aug 24, 2024
2 parents 35b36f9 + 3e2d5fa commit 5e8700f
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 144 deletions.
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion bin/opt8n/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ shellwords.workspace = true
# Alloy
alloy-eips.workspace = true
alloy-rpc-types.workspace = true
alloy-primitives.workspace = true

# Foundry
foundry-common.workspace = true
Expand All @@ -38,6 +39,7 @@ revm.workspace = true
# OP Types
op-test-vectors.workspace = true
op-alloy-rpc-types.workspace = true
op-alloy-consensus.workspace = true
thiserror.workspace = true
reqwest.workspace = true
hyper = "1.4.1"
hyper = "1.4.1"
126 changes: 116 additions & 10 deletions bin/opt8n/src/opt8n.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,27 @@
use alloy_eips::eip2718::Encodable2718;
use alloy_eips::BlockId;
use alloy_rpc_types::trace::geth::{PreStateConfig, PreStateFrame};
use alloy_rpc_types::{
trace::geth::{PreStateConfig, PreStateFrame},
TransactionReceipt,
};
use anvil::{cmd::NodeArgs, eth::EthApi, NodeConfig, NodeHandle};
use anvil_core::eth::block::Block;
use anvil_core::eth::transaction::PendingTransaction;
use anvil_core::eth::transaction::{PendingTransaction, TypedTransaction};
use anvil_core::eth::{block::Block, transaction::TypedReceipt};
use cast::traces::{GethTraceBuilder, TracingInspectorConfig};
use clap::Parser;
use op_alloy_consensus::{
OpDepositReceipt, OpDepositReceiptWithBloom, OpReceiptEnvelope, OpTypedTransaction, TxDeposit,
};
use op_alloy_rpc_types::OpTransactionReceipt;
use std::{
error::Error,
fs::{self, File},
path::PathBuf,
};

use color_eyre::eyre::{ensure, eyre, Result};
use op_test_vectors::execution::{ExecutionFixture, ExecutionReceipt, ExecutionResult};
use op_test_vectors::execution::{ExecutionEnvironment, ExecutionFixture, ExecutionResult};
use revm::{
db::{AlloyDB, CacheDB},
primitives::{BlobExcessGasAndPrice, BlockEnv, CfgEnv, Env, SpecId, U256},
Expand Down Expand Up @@ -142,19 +149,20 @@ impl Opt8n {
self.capture_pre_post_alloc(&block)?;

// Append block transactions and receipts to the execution fixture
let mut receipts: Vec<ExecutionReceipt> = Vec::with_capacity(block.transactions.len());
let mut receipts: Vec<OpTransactionReceipt> = Vec::with_capacity(block.transactions.len());
for tx in block.transactions.iter() {
if let Some(receipt) = self
.eth_api
.backend
.transaction_receipt(tx.transaction.hash())
.await?
{
receipts.push(receipt.try_into()?);
let op_receipt = tx_receipt_to_op_tx_receipt(receipt);
receipts.push(op_receipt);
}
self.execution_fixture
.transactions
.push(tx.transaction.clone());

let op_tx = typed_tx_to_op_typed_tx(&tx.transaction);
self.execution_fixture.transactions.push(op_tx);
}

let block_header = &block.header;
Expand All @@ -166,7 +174,17 @@ impl Opt8n {
receipts,
};

self.execution_fixture.env = block.into();
let execution_environment = ExecutionEnvironment {
current_coinbase: block_header.beneficiary,
current_difficulty: block_header.difficulty,
current_gas_limit: U256::from(block.header.gas_limit),
previous_hash: block_header.parent_hash,
current_number: U256::from(block.header.number),
current_timestamp: U256::from(block_header.timestamp),
block_hashes: None,
};

self.execution_fixture.env = execution_environment;
self.execution_fixture.result = execution_result;

// Ensure pre and post states are different
Expand All @@ -183,6 +201,94 @@ impl Opt8n {
}
}

// TODO: Consider adding `From` implementation for
// `TypedTransaction` -> `OpTypedTransaction` in `op-alloy-consensus`
fn typed_tx_to_op_typed_tx(tx: &TypedTransaction) -> OpTypedTransaction {
let op_tx = match tx {
TypedTransaction::Legacy(signed_tx) => OpTypedTransaction::Legacy(signed_tx.tx().clone()),
TypedTransaction::EIP2930(signed_tx) => OpTypedTransaction::Eip2930(signed_tx.tx().clone()),

TypedTransaction::EIP1559(signed_tx) => OpTypedTransaction::Eip1559(signed_tx.tx().clone()),
TypedTransaction::EIP4844(signed_tx) => OpTypedTransaction::Eip4844(signed_tx.tx().clone()),
TypedTransaction::Deposit(deposit_tx) => {
let op_deposit_tx = TxDeposit {
source_hash: deposit_tx.source_hash,
from: deposit_tx.from,
to: deposit_tx.kind,
mint: Some(
deposit_tx
.mint
.try_into()
.expect("Mint is greater than u128"),
),
value: deposit_tx.value,
gas_limit: deposit_tx.gas_limit,
is_system_transaction: deposit_tx.is_system_tx,
input: deposit_tx.input.clone(),
};

OpTypedTransaction::Deposit(op_deposit_tx)
}
TypedTransaction::EIP7702(_) => {
unimplemented!("EIP7702 not implemented")
}
};

op_tx
}

// TODO: Consider adding `From` implementation for
// `TransactionReceipt` -> `OpTransactionReceipt` in `op-alloy-consensus`
fn tx_receipt_to_op_tx_receipt(
receipt: TransactionReceipt<TypedReceipt<alloy_rpc_types::Log>>,
) -> OpTransactionReceipt {
let receipt_envelope = receipt.inner;
let op_receipt_envelope = match receipt_envelope {
TypedReceipt::Legacy(receipt_with_bloom) => OpReceiptEnvelope::Legacy(receipt_with_bloom),
TypedReceipt::EIP2930(receipt_with_bloom) => OpReceiptEnvelope::Eip2930(receipt_with_bloom),
TypedReceipt::EIP1559(receipt_with_bloom) => OpReceiptEnvelope::Eip1559(receipt_with_bloom),
TypedReceipt::EIP4844(receipt_with_bloom) => OpReceiptEnvelope::Eip4844(receipt_with_bloom),
TypedReceipt::EIP7702(_) => {
unimplemented!("EIP7702 not implemented")
}
TypedReceipt::Deposit(deposit_receipt) => {
let op_deposit_receipt = OpDepositReceipt {
inner: deposit_receipt.inner.receipt,
deposit_nonce: deposit_receipt.deposit_nonce,
deposit_receipt_version: deposit_receipt.deposit_receipt_version,
};

let op_deposit_receipt_with_bloom = OpDepositReceiptWithBloom {
receipt: op_deposit_receipt,
logs_bloom: deposit_receipt.inner.logs_bloom,
};

OpReceiptEnvelope::Deposit(op_deposit_receipt_with_bloom)
}
};



OpTransactionReceipt {
inner: TransactionReceipt {
inner: op_receipt_envelope,
transaction_hash: receipt.transaction_hash,
transaction_index: receipt.transaction_index,
block_hash: receipt.block_hash,
block_number: receipt.block_number,
gas_used: receipt.gas_used,
effective_gas_price: receipt.effective_gas_price,
blob_gas_used: receipt.blob_gas_used,
blob_gas_price: receipt.blob_gas_price,
from: receipt.from,
to: receipt.to,
contract_address: receipt.contract_address,
state_root: receipt.state_root,
authorization_list: receipt.authorization_list,
},
}
}

/// Creates a new EVM instance from a given block, chain, database, and spec id.
pub fn evm<'a, DB>(block: &Block, chain_id: u64, db: DB, spec_id: SpecId) -> Evm<'a, (), Box<DB>>
where
Expand Down
3 changes: 0 additions & 3 deletions crates/op-test-vectors/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ serde.workspace = true
color-eyre.workspace = true
hashbrown.workspace = true

# Foundry
anvil-core.workspace = true

# Alloy
alloy-rpc-types.workspace = true
alloy-primitives.workspace = true
Expand Down
120 changes: 5 additions & 115 deletions crates/op-test-vectors/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
use alloy_primitives::{Address, Bloom, B256, U256};
use alloy_rpc_types::trace::geth::AccountState;
use alloy_rpc_types::{Log, TransactionReceipt};
use anvil_core::eth::block::Block;
use anvil_core::eth::transaction::{TypedReceipt, TypedTransaction};
use color_eyre::eyre;

use op_alloy_consensus::OpTypedTransaction;
use op_alloy_rpc_types::OpTransactionReceipt;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

Expand All @@ -24,7 +23,7 @@ pub struct ExecutionFixture {
pub out_alloc: HashMap<Address, AccountState>,
/// Transactions to execute.
#[serde(rename = "txs")]
pub transactions: Vec<TypedTransaction>,
pub transactions: Vec<OpTypedTransaction>,
/// The expected result after executing transactions.
pub result: ExecutionResult,
}
Expand All @@ -51,20 +50,6 @@ pub struct ExecutionEnvironment {
pub block_hashes: Option<HashMap<U256, B256>>,
}

impl From<Block> for ExecutionEnvironment {
fn from(block: Block) -> Self {
Self {
current_coinbase: block.header.beneficiary,
current_difficulty: block.header.difficulty,
current_gas_limit: U256::from(block.header.gas_limit),
previous_hash: block.header.parent_hash,
current_number: U256::from(block.header.number),
current_timestamp: U256::from(block.header.timestamp),
block_hashes: None,
}
}
}

/// The execution result is the expected result after running the transactions
/// in the execution environment over the pre-state.
#[derive(Serialize, Deserialize, Debug, Default)]
Expand All @@ -79,53 +64,7 @@ pub struct ExecutionResult {
/// The logs bloom.
pub logs_bloom: Bloom,
/// A list of execution receipts for each executed transaction.
pub receipts: Vec<ExecutionReceipt>,
}

/// An execution receipt is the result of running a transaction in the execution environment.
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
pub struct ExecutionReceipt {
/// The state root.
pub root: B256,
/// The hash of the transaction.
pub transaction_hash: B256,
/// The contract address that the transaction created.
#[serde(skip_serializing_if = "Option::is_none")]
pub contract_address: Option<Address>,
/// The gas used by the transaction.
pub gas_used: U256,
/// The block hash.
pub block_hash: B256,
/// The transaction index.
pub transaction_index: U256,
/// The inner log receipt.
#[serde(flatten)]
pub inner: TypedReceipt<Log>,
}

impl TryFrom<TransactionReceipt<TypedReceipt<Log>>> for ExecutionReceipt {
type Error = eyre::Error;

fn try_from(receipt: TransactionReceipt<TypedReceipt<Log>>) -> eyre::Result<Self> {
Ok(Self {
transaction_hash: receipt.transaction_hash,
root: receipt
.state_root
.ok_or_else(|| eyre::eyre!("missing state root"))?,
contract_address: receipt.contract_address,
gas_used: U256::from(receipt.gas_used),
block_hash: receipt
.block_hash
.ok_or_else(|| eyre::eyre!("missing block hash"))?,
transaction_index: U256::from(
receipt
.transaction_index
.ok_or_else(|| eyre::eyre!("missing transaction index"))?,
),
inner: receipt.inner,
})
}
pub receipts: Vec<OpTransactionReceipt>,
}

#[cfg(test)]
Expand Down Expand Up @@ -159,53 +98,4 @@ mod tests {
.expect("failed to parse expected result");
assert_eq!(serialized_value, expected_value);
}

#[test]
fn test_exec_receipt_try_from_tx_receipt() {
let tx_receipt_str = include_str!("./testdata/tx_receipt.json");
let tx_receipt: TransactionReceipt<TypedReceipt<Log>> =
serde_json::from_str(tx_receipt_str).expect("failed to parse tx receipt");
let exec_receipt = ExecutionReceipt::try_from(tx_receipt.clone())
.expect("failed to convert tx receipt to exec receipt");
assert_eq!(exec_receipt.transaction_hash, tx_receipt.transaction_hash);
assert_eq!(exec_receipt.root, tx_receipt.state_root.unwrap());
assert_eq!(exec_receipt.contract_address, tx_receipt.contract_address);
assert_eq!(exec_receipt.gas_used, U256::from(tx_receipt.gas_used));
assert_eq!(exec_receipt.block_hash, tx_receipt.block_hash.unwrap());
assert_eq!(
exec_receipt.transaction_index,
U256::from(tx_receipt.transaction_index.unwrap())
);
assert_eq!(exec_receipt.inner, tx_receipt.inner);
}

#[test]
fn test_exec_receipt_try_from_missing_root() {
let tx_receipt_str = include_str!("./testdata/tx_receipt.json");
let mut tx_receipt: TransactionReceipt<TypedReceipt<Log>> =
serde_json::from_str(tx_receipt_str).expect("failed to parse tx receipt");
tx_receipt.state_root = None;
let exec_receipt = ExecutionReceipt::try_from(tx_receipt);
assert!(exec_receipt.is_err());
}

#[test]
fn test_exec_receipt_try_from_missing_block_hash() {
let tx_receipt_str = include_str!("./testdata/tx_receipt.json");
let mut tx_receipt: TransactionReceipt<TypedReceipt<Log>> =
serde_json::from_str(tx_receipt_str).expect("failed to parse tx receipt");
tx_receipt.block_hash = None;
let exec_receipt = ExecutionReceipt::try_from(tx_receipt);
assert!(exec_receipt.is_err());
}

#[test]
fn test_exec_receipt_try_from_missing_tx_index() {
let tx_receipt_str = include_str!("./testdata/tx_receipt.json");
let mut tx_receipt: TransactionReceipt<TypedReceipt<Log>> =
serde_json::from_str(tx_receipt_str).expect("failed to parse tx receipt");
tx_receipt.transaction_index = None;
let exec_receipt = ExecutionReceipt::try_from(tx_receipt);
assert!(exec_receipt.is_err());
}
}
Loading

0 comments on commit 5e8700f

Please sign in to comment.