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

feat: Derivation Test Fixtures #34

Merged
merged 5 commits into from
Jul 25, 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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ op-alloy-consensus = "0.1.2"
alloy = { version = "0.1.4", features = [
"rpc",
"rpc-types-trace",
"consensus",
"providers"
] }
anvil = { git = "https://github.com/foundry-rs/foundry", default-features = true, rev = "7c4482fc9541f11b57575e2d8bf7bd190b61bda6" }
Expand Down
103 changes: 101 additions & 2 deletions crates/op-test-vectors/src/derivation.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,107 @@
//! Module containing the derivation test fixture.

use alloy::consensus::Blob;
use alloy::primitives::{Bytes, B256};
use serde::{Deserialize, Serialize};

/// The derivation fixture is the top-level object that contains
/// everything needed to run a derivation test.
#[derive(Serialize, Deserialize, Debug, Default)]
pub struct DerivationFixture {}
#[derive(Serialize, Deserialize, Debug, Default, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct DerivationFixture {
/// A list of L1 Blocks to derive from.
pub l1_blocks: Vec<FixtureBlock>,
/// A list of L2 Output Roots to assert against.
pub l2_output_roots: Vec<B256>,
}

/// A fixture block is a minimal block with associated data including blobs
/// to derive from.
#[derive(Serialize, Deserialize, Debug, Default, Eq, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct FixtureBlock {
/// The block number.
pub number: u64,
/// The block hash.
pub hash: B256,
/// The block timestamp.
pub timestamp: u64,
/// Block Transactions.
/// EIP-2718 encoded raw transactions
pub transactions: Vec<Bytes>,
/// Blobs for this block.
pub blobs: Vec<Box<Blob>>,
}

#[cfg(test)]
mod tests {
use super::*;
use alloy::primitives::{b256, bytes};

fn ref_blocks() -> Vec<FixtureBlock> {
vec![
FixtureBlock {
number: 1,
hash: b256!("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
timestamp: 102,
transactions: vec![
bytes!("02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"),
bytes!("02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"),
bytes!("02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"),
],
blobs: vec![],
},
FixtureBlock {
number: 2,
hash: b256!("cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"),
timestamp: 104,
transactions: vec![
bytes!("02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"),
bytes!("02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"),
],
blobs: vec![],
},
FixtureBlock {
number: 2,
hash: b256!("dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"),
timestamp: 106,
transactions: vec![
bytes!("02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"),
],
blobs: vec![],
},
]
}

fn ref_l2_output_roots() -> Vec<B256> {
vec![
b256!("eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"),
b256!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
]
}

#[test]
fn test_derivation_fixture() {
let fixture_str = include_str!("./testdata/derivation_fixture.json");
let fixture: DerivationFixture = serde_json::from_str(fixture_str).unwrap();
let expected = DerivationFixture {
l1_blocks: ref_blocks(),
l2_output_roots: ref_l2_output_roots(),
};
assert_eq!(fixture, expected);
}

#[test]
fn test_fixture_block() {
let fixture_str = include_str!("./testdata/fixture_block.json");
let fixture: FixtureBlock = serde_json::from_str(fixture_str).unwrap();
assert_eq!(fixture.number, 1);
assert_eq!(
fixture.hash,
b256!("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
);
assert_eq!(fixture.timestamp, 102);
assert_eq!(fixture.transactions.len(), 1);
assert_eq!(fixture.blobs.len(), 0);
}
}
62 changes: 43 additions & 19 deletions crates/op-test-vectors/src/execution.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
//! Module containing the execution test fixture.

use std::collections::HashMap;
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 serde::{Deserialize, Serialize};
use color_eyre::eyre;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// The execution fixture is the top-level object that contains
/// everything needed to run an execution test.
#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct ExecutionFixture {
/// The execution environment sets up the current block context.
pub env: ExecutionEnvironment,
Expand All @@ -33,7 +34,7 @@ pub struct ExecutionFixture {
#[derive(Serialize, Deserialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct ExecutionEnvironment {
/// The current block coinbase.
/// The current block coinbase.
pub current_coinbase: Address,
/// The current block difficulty.
pub current_difficulty: U256,
Expand Down Expand Up @@ -111,11 +112,19 @@ impl TryFrom<TransactionReceipt<TypedReceipt<Log>>> for ExecutionReceipt {
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"))?,
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"))?),
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,
})
}
Expand All @@ -129,41 +138,54 @@ mod tests {
#[test]
fn test_serialize_execution_environment() {
let expected_env = include_str!("./testdata/environment.json");
let env = serde_json::from_str::<ExecutionEnvironment>(expected_env).expect("failed to parse environment");
let env = serde_json::from_str::<ExecutionEnvironment>(expected_env)
.expect("failed to parse environment");
let serialized_env = serde_json::to_string(&env).expect("failed to serialize environment");
let serialized_value = serde_json::from_str::<Value>(&serialized_env).expect("failed to parse serialized environment");
let expected_value = serde_json::from_str::<Value>(expected_env).expect("failed to parse expected environment");
let serialized_value = serde_json::from_str::<Value>(&serialized_env)
.expect("failed to parse serialized environment");
let expected_value = serde_json::from_str::<Value>(expected_env)
.expect("failed to parse expected environment");
assert_eq!(serialized_value, expected_value);
}

#[test]
fn test_serialize_execution_result() {
let expected_result = include_str!("./testdata/result.json");
let execution_result = serde_json::from_str::<ExecutionResult>(expected_result).expect("failed to parse result");
let serialized_result = serde_json::to_string(&execution_result).expect("failed to serialize result");
let serialized_value = serde_json::from_str::<Value>(&serialized_result).expect("failed to parse serialized result");
let expected_value = serde_json::from_str::<Value>(expected_result).expect("failed to parse expected result");
let execution_result = serde_json::from_str::<ExecutionResult>(expected_result)
.expect("failed to parse result");
let serialized_result =
serde_json::to_string(&execution_result).expect("failed to serialize result");
let serialized_value = serde_json::from_str::<Value>(&serialized_result)
.expect("failed to parse serialized result");
let expected_value = serde_json::from_str::<Value>(expected_result)
.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");
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.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");
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());
Expand All @@ -172,7 +194,8 @@ mod tests {
#[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");
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());
Expand All @@ -181,7 +204,8 @@ mod tests {
#[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");
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());
Expand Down
7 changes: 6 additions & 1 deletion crates/op-test-vectors/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
#![doc = include_str!("../README.md")]
#![warn(missing_debug_implementations, missing_docs, unreachable_pub, rustdoc::all)]
#![warn(
missing_debug_implementations,
missing_docs,
unreachable_pub,
rustdoc::all
)]
#![deny(unused_must_use, rust_2018_idioms)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]

Expand Down
38 changes: 38 additions & 0 deletions crates/op-test-vectors/src/testdata/derivation_fixture.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"l2OutputRoots": [
"0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
],
"l1Blocks": [
{
"number": 1,
"hash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"timestamp": 102,
"transactions": [
"0x02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5",
"0x02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5",
"0x02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"
],
"blobs": []
},
{
"number": 2,
"hash": "0xcccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
"timestamp": 104,
"transactions": [
"0x02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5",
"0x02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"
],
"blobs": []
},
{
"number": 2,
"hash": "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
"timestamp": 106,
"transactions": [
"0x02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"
],
"blobs": []
}
]
}
9 changes: 9 additions & 0 deletions crates/op-test-vectors/src/testdata/fixture_block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"number": 1,
"hash": "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"timestamp": 102,
"transactions": [
"0x02f870018307c100808476d0a39c82565f94388c818ca8b9251b393131c08a736a67ccb1929787b60572b2eb6c9080c001a033bee682348fa78ffc1027bc9981e7dc60eca03af909c4eb05720e781fdae179a01ccf85367c246082fa09ef748d3b07c90752c2b59034a6b881cf99aca586eaf5"
],
"blobs": []
}
27 changes: 27 additions & 0 deletions crates/op-test-vectors/src/testdata/fixture_block_with_blob.json

Large diffs are not rendered by default.