Skip to content
This repository was archived by the owner on Jan 31, 2025. It is now read-only.

Commit 5e8700f

Browse files
authored
Merge pull request #73 from ethereum-optimism/0xkitsune/alloy
chore(op-test-vectors): Update `ExecutionFixture` to use `op-alloy-consensus` types
2 parents 35b36f9 + 3e2d5fa commit 5e8700f

File tree

6 files changed

+144
-144
lines changed

6 files changed

+144
-144
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/opt8n/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ shellwords.workspace = true
2626
# Alloy
2727
alloy-eips.workspace = true
2828
alloy-rpc-types.workspace = true
29+
alloy-primitives.workspace = true
2930

3031
# Foundry
3132
foundry-common.workspace = true
@@ -38,6 +39,7 @@ revm.workspace = true
3839
# OP Types
3940
op-test-vectors.workspace = true
4041
op-alloy-rpc-types.workspace = true
42+
op-alloy-consensus.workspace = true
4143
thiserror.workspace = true
4244
reqwest.workspace = true
43-
hyper = "1.4.1"
45+
hyper = "1.4.1"

bin/opt8n/src/opt8n.rs

Lines changed: 116 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,27 @@
22
33
use alloy_eips::eip2718::Encodable2718;
44
use alloy_eips::BlockId;
5-
use alloy_rpc_types::trace::geth::{PreStateConfig, PreStateFrame};
5+
use alloy_rpc_types::{
6+
trace::geth::{PreStateConfig, PreStateFrame},
7+
TransactionReceipt,
8+
};
69
use anvil::{cmd::NodeArgs, eth::EthApi, NodeConfig, NodeHandle};
7-
use anvil_core::eth::block::Block;
8-
use anvil_core::eth::transaction::PendingTransaction;
10+
use anvil_core::eth::transaction::{PendingTransaction, TypedTransaction};
11+
use anvil_core::eth::{block::Block, transaction::TypedReceipt};
912
use cast::traces::{GethTraceBuilder, TracingInspectorConfig};
1013
use clap::Parser;
14+
use op_alloy_consensus::{
15+
OpDepositReceipt, OpDepositReceiptWithBloom, OpReceiptEnvelope, OpTypedTransaction, TxDeposit,
16+
};
17+
use op_alloy_rpc_types::OpTransactionReceipt;
1118
use std::{
1219
error::Error,
1320
fs::{self, File},
1421
path::PathBuf,
1522
};
1623

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

144151
// Append block transactions and receipts to the execution fixture
145-
let mut receipts: Vec<ExecutionReceipt> = Vec::with_capacity(block.transactions.len());
152+
let mut receipts: Vec<OpTransactionReceipt> = Vec::with_capacity(block.transactions.len());
146153
for tx in block.transactions.iter() {
147154
if let Some(receipt) = self
148155
.eth_api
149156
.backend
150157
.transaction_receipt(tx.transaction.hash())
151158
.await?
152159
{
153-
receipts.push(receipt.try_into()?);
160+
let op_receipt = tx_receipt_to_op_tx_receipt(receipt);
161+
receipts.push(op_receipt);
154162
}
155-
self.execution_fixture
156-
.transactions
157-
.push(tx.transaction.clone());
163+
164+
let op_tx = typed_tx_to_op_typed_tx(&tx.transaction);
165+
self.execution_fixture.transactions.push(op_tx);
158166
}
159167

160168
let block_header = &block.header;
@@ -166,7 +174,17 @@ impl Opt8n {
166174
receipts,
167175
};
168176

169-
self.execution_fixture.env = block.into();
177+
let execution_environment = ExecutionEnvironment {
178+
current_coinbase: block_header.beneficiary,
179+
current_difficulty: block_header.difficulty,
180+
current_gas_limit: U256::from(block.header.gas_limit),
181+
previous_hash: block_header.parent_hash,
182+
current_number: U256::from(block.header.number),
183+
current_timestamp: U256::from(block_header.timestamp),
184+
block_hashes: None,
185+
};
186+
187+
self.execution_fixture.env = execution_environment;
170188
self.execution_fixture.result = execution_result;
171189

172190
// Ensure pre and post states are different
@@ -183,6 +201,94 @@ impl Opt8n {
183201
}
184202
}
185203

204+
// TODO: Consider adding `From` implementation for
205+
// `TypedTransaction` -> `OpTypedTransaction` in `op-alloy-consensus`
206+
fn typed_tx_to_op_typed_tx(tx: &TypedTransaction) -> OpTypedTransaction {
207+
let op_tx = match tx {
208+
TypedTransaction::Legacy(signed_tx) => OpTypedTransaction::Legacy(signed_tx.tx().clone()),
209+
TypedTransaction::EIP2930(signed_tx) => OpTypedTransaction::Eip2930(signed_tx.tx().clone()),
210+
211+
TypedTransaction::EIP1559(signed_tx) => OpTypedTransaction::Eip1559(signed_tx.tx().clone()),
212+
TypedTransaction::EIP4844(signed_tx) => OpTypedTransaction::Eip4844(signed_tx.tx().clone()),
213+
TypedTransaction::Deposit(deposit_tx) => {
214+
let op_deposit_tx = TxDeposit {
215+
source_hash: deposit_tx.source_hash,
216+
from: deposit_tx.from,
217+
to: deposit_tx.kind,
218+
mint: Some(
219+
deposit_tx
220+
.mint
221+
.try_into()
222+
.expect("Mint is greater than u128"),
223+
),
224+
value: deposit_tx.value,
225+
gas_limit: deposit_tx.gas_limit,
226+
is_system_transaction: deposit_tx.is_system_tx,
227+
input: deposit_tx.input.clone(),
228+
};
229+
230+
OpTypedTransaction::Deposit(op_deposit_tx)
231+
}
232+
TypedTransaction::EIP7702(_) => {
233+
unimplemented!("EIP7702 not implemented")
234+
}
235+
};
236+
237+
op_tx
238+
}
239+
240+
// TODO: Consider adding `From` implementation for
241+
// `TransactionReceipt` -> `OpTransactionReceipt` in `op-alloy-consensus`
242+
fn tx_receipt_to_op_tx_receipt(
243+
receipt: TransactionReceipt<TypedReceipt<alloy_rpc_types::Log>>,
244+
) -> OpTransactionReceipt {
245+
let receipt_envelope = receipt.inner;
246+
let op_receipt_envelope = match receipt_envelope {
247+
TypedReceipt::Legacy(receipt_with_bloom) => OpReceiptEnvelope::Legacy(receipt_with_bloom),
248+
TypedReceipt::EIP2930(receipt_with_bloom) => OpReceiptEnvelope::Eip2930(receipt_with_bloom),
249+
TypedReceipt::EIP1559(receipt_with_bloom) => OpReceiptEnvelope::Eip1559(receipt_with_bloom),
250+
TypedReceipt::EIP4844(receipt_with_bloom) => OpReceiptEnvelope::Eip4844(receipt_with_bloom),
251+
TypedReceipt::EIP7702(_) => {
252+
unimplemented!("EIP7702 not implemented")
253+
}
254+
TypedReceipt::Deposit(deposit_receipt) => {
255+
let op_deposit_receipt = OpDepositReceipt {
256+
inner: deposit_receipt.inner.receipt,
257+
deposit_nonce: deposit_receipt.deposit_nonce,
258+
deposit_receipt_version: deposit_receipt.deposit_receipt_version,
259+
};
260+
261+
let op_deposit_receipt_with_bloom = OpDepositReceiptWithBloom {
262+
receipt: op_deposit_receipt,
263+
logs_bloom: deposit_receipt.inner.logs_bloom,
264+
};
265+
266+
OpReceiptEnvelope::Deposit(op_deposit_receipt_with_bloom)
267+
}
268+
};
269+
270+
271+
272+
OpTransactionReceipt {
273+
inner: TransactionReceipt {
274+
inner: op_receipt_envelope,
275+
transaction_hash: receipt.transaction_hash,
276+
transaction_index: receipt.transaction_index,
277+
block_hash: receipt.block_hash,
278+
block_number: receipt.block_number,
279+
gas_used: receipt.gas_used,
280+
effective_gas_price: receipt.effective_gas_price,
281+
blob_gas_used: receipt.blob_gas_used,
282+
blob_gas_price: receipt.blob_gas_price,
283+
from: receipt.from,
284+
to: receipt.to,
285+
contract_address: receipt.contract_address,
286+
state_root: receipt.state_root,
287+
authorization_list: receipt.authorization_list,
288+
},
289+
}
290+
}
291+
186292
/// Creates a new EVM instance from a given block, chain, database, and spec id.
187293
pub fn evm<'a, DB>(block: &Block, chain_id: u64, db: DB, spec_id: SpecId) -> Evm<'a, (), Box<DB>>
188294
where

crates/op-test-vectors/Cargo.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ serde.workspace = true
1515
color-eyre.workspace = true
1616
hashbrown.workspace = true
1717

18-
# Foundry
19-
anvil-core.workspace = true
20-
2118
# Alloy
2219
alloy-rpc-types.workspace = true
2320
alloy-primitives.workspace = true

crates/op-test-vectors/src/execution.rs

Lines changed: 5 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
33
use alloy_primitives::{Address, Bloom, B256, U256};
44
use alloy_rpc_types::trace::geth::AccountState;
5-
use alloy_rpc_types::{Log, TransactionReceipt};
6-
use anvil_core::eth::block::Block;
7-
use anvil_core::eth::transaction::{TypedReceipt, TypedTransaction};
8-
use color_eyre::eyre;
5+
6+
use op_alloy_consensus::OpTypedTransaction;
7+
use op_alloy_rpc_types::OpTransactionReceipt;
98
use serde::{Deserialize, Serialize};
109
use std::collections::HashMap;
1110

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

54-
impl From<Block> for ExecutionEnvironment {
55-
fn from(block: Block) -> Self {
56-
Self {
57-
current_coinbase: block.header.beneficiary,
58-
current_difficulty: block.header.difficulty,
59-
current_gas_limit: U256::from(block.header.gas_limit),
60-
previous_hash: block.header.parent_hash,
61-
current_number: U256::from(block.header.number),
62-
current_timestamp: U256::from(block.header.timestamp),
63-
block_hashes: None,
64-
}
65-
}
66-
}
67-
6853
/// The execution result is the expected result after running the transactions
6954
/// in the execution environment over the pre-state.
7055
#[derive(Serialize, Deserialize, Debug, Default)]
@@ -79,53 +64,7 @@ pub struct ExecutionResult {
7964
/// The logs bloom.
8065
pub logs_bloom: Bloom,
8166
/// A list of execution receipts for each executed transaction.
82-
pub receipts: Vec<ExecutionReceipt>,
83-
}
84-
85-
/// An execution receipt is the result of running a transaction in the execution environment.
86-
#[derive(Serialize, Deserialize, Debug)]
87-
#[serde(rename_all = "camelCase")]
88-
pub struct ExecutionReceipt {
89-
/// The state root.
90-
pub root: B256,
91-
/// The hash of the transaction.
92-
pub transaction_hash: B256,
93-
/// The contract address that the transaction created.
94-
#[serde(skip_serializing_if = "Option::is_none")]
95-
pub contract_address: Option<Address>,
96-
/// The gas used by the transaction.
97-
pub gas_used: U256,
98-
/// The block hash.
99-
pub block_hash: B256,
100-
/// The transaction index.
101-
pub transaction_index: U256,
102-
/// The inner log receipt.
103-
#[serde(flatten)]
104-
pub inner: TypedReceipt<Log>,
105-
}
106-
107-
impl TryFrom<TransactionReceipt<TypedReceipt<Log>>> for ExecutionReceipt {
108-
type Error = eyre::Error;
109-
110-
fn try_from(receipt: TransactionReceipt<TypedReceipt<Log>>) -> eyre::Result<Self> {
111-
Ok(Self {
112-
transaction_hash: receipt.transaction_hash,
113-
root: receipt
114-
.state_root
115-
.ok_or_else(|| eyre::eyre!("missing state root"))?,
116-
contract_address: receipt.contract_address,
117-
gas_used: U256::from(receipt.gas_used),
118-
block_hash: receipt
119-
.block_hash
120-
.ok_or_else(|| eyre::eyre!("missing block hash"))?,
121-
transaction_index: U256::from(
122-
receipt
123-
.transaction_index
124-
.ok_or_else(|| eyre::eyre!("missing transaction index"))?,
125-
),
126-
inner: receipt.inner,
127-
})
128-
}
67+
pub receipts: Vec<OpTransactionReceipt>,
12968
}
13069

13170
#[cfg(test)]
@@ -159,53 +98,4 @@ mod tests {
15998
.expect("failed to parse expected result");
16099
assert_eq!(serialized_value, expected_value);
161100
}
162-
163-
#[test]
164-
fn test_exec_receipt_try_from_tx_receipt() {
165-
let tx_receipt_str = include_str!("./testdata/tx_receipt.json");
166-
let tx_receipt: TransactionReceipt<TypedReceipt<Log>> =
167-
serde_json::from_str(tx_receipt_str).expect("failed to parse tx receipt");
168-
let exec_receipt = ExecutionReceipt::try_from(tx_receipt.clone())
169-
.expect("failed to convert tx receipt to exec receipt");
170-
assert_eq!(exec_receipt.transaction_hash, tx_receipt.transaction_hash);
171-
assert_eq!(exec_receipt.root, tx_receipt.state_root.unwrap());
172-
assert_eq!(exec_receipt.contract_address, tx_receipt.contract_address);
173-
assert_eq!(exec_receipt.gas_used, U256::from(tx_receipt.gas_used));
174-
assert_eq!(exec_receipt.block_hash, tx_receipt.block_hash.unwrap());
175-
assert_eq!(
176-
exec_receipt.transaction_index,
177-
U256::from(tx_receipt.transaction_index.unwrap())
178-
);
179-
assert_eq!(exec_receipt.inner, tx_receipt.inner);
180-
}
181-
182-
#[test]
183-
fn test_exec_receipt_try_from_missing_root() {
184-
let tx_receipt_str = include_str!("./testdata/tx_receipt.json");
185-
let mut tx_receipt: TransactionReceipt<TypedReceipt<Log>> =
186-
serde_json::from_str(tx_receipt_str).expect("failed to parse tx receipt");
187-
tx_receipt.state_root = None;
188-
let exec_receipt = ExecutionReceipt::try_from(tx_receipt);
189-
assert!(exec_receipt.is_err());
190-
}
191-
192-
#[test]
193-
fn test_exec_receipt_try_from_missing_block_hash() {
194-
let tx_receipt_str = include_str!("./testdata/tx_receipt.json");
195-
let mut tx_receipt: TransactionReceipt<TypedReceipt<Log>> =
196-
serde_json::from_str(tx_receipt_str).expect("failed to parse tx receipt");
197-
tx_receipt.block_hash = None;
198-
let exec_receipt = ExecutionReceipt::try_from(tx_receipt);
199-
assert!(exec_receipt.is_err());
200-
}
201-
202-
#[test]
203-
fn test_exec_receipt_try_from_missing_tx_index() {
204-
let tx_receipt_str = include_str!("./testdata/tx_receipt.json");
205-
let mut tx_receipt: TransactionReceipt<TypedReceipt<Log>> =
206-
serde_json::from_str(tx_receipt_str).expect("failed to parse tx receipt");
207-
tx_receipt.transaction_index = None;
208-
let exec_receipt = ExecutionReceipt::try_from(tx_receipt);
209-
assert!(exec_receipt.is_err());
210-
}
211101
}

0 commit comments

Comments
 (0)