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

Commit b3c391a

Browse files
committed
checkpoint
1 parent 5e8700f commit b3c391a

File tree

20 files changed

+1923
-4423
lines changed

20 files changed

+1923
-4423
lines changed

Cargo.lock

Lines changed: 957 additions & 3588 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,25 @@ hashbrown = "0.14.5"
3030
# Alloy Dependencies
3131
op-alloy-rpc-types = "0.1.4"
3232
op-alloy-consensus = "0.1.4"
33+
op-alloy-network = "0.1.5"
34+
alloy-rlp = { version = "0.3.8" }
3335
alloy-primitives = { version = "0.7" }
3436
alloy-consensus = { version = "0.2" }
3537
alloy-eips = { version = "0.2" }
3638
alloy-rpc-types = { version = "0.2" }
3739

38-
# Foundry Dependencies
39-
foundry-common = { git = "https://github.com/foundry-rs/foundry", default-features = true, rev = "c600237f3e54604274bfdcba627f347493fd21d2" }
40-
foundry-compilers = { git = "https://github.com/foundry-rs/foundry", default-features = true, rev = "c600237f3e54604274bfdcba627f347493fd21d2" }
41-
anvil = { git = "https://github.com/foundry-rs/foundry", default-features = true, rev = "c600237f3e54604274bfdcba627f347493fd21d2" }
42-
anvil-core = { git = "https://github.com/foundry-rs/foundry", default-features = true, rev = "c600237f3e54604274bfdcba627f347493fd21d2" }
43-
cast = { git = "https://github.com/foundry-rs/foundry", rev = "c600237f3e54604274bfdcba627f347493fd21d2" }
44-
forge-script = { git = "https://github.com/foundry-rs/foundry", rev = "c600237f3e54604274bfdcba627f347493fd21d2" }
45-
revm = { version = "12.1", features = ["alloydb", "optimism"] }
40+
# revm + reth
41+
revm = { version = "13.0", features = ["optimism", "serde"] }
42+
reth-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.5" }
43+
reth-evm = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.5" }
44+
reth-evm-optimism = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.5", features = ["optimism"] }
45+
reth-chainspec = { git = "https://github.com/paradigmxyz/reth", tag = "v1.0.5", features = ["optimism"] }
4646

4747
# Kona + OP Types
4848
superchain-registry = "0.2.6"
49-
kona-primitives = { git = "https://github.com/ethereum-optimism/kona", version = "0.0.2", features = ["online"] }
50-
kona-derive = { git = "https://github.com/ethereum-optimism/kona", version = "0.0.3", features = ["online"] }
49+
kona-primitives = { git = "https://github.com/ethereum-optimism/kona", version = "0.0.1", features = ["online"] }
50+
kona-derive = { git = "https://github.com/ethereum-optimism/kona", version = "0.0.2", features = ["online"] }
51+
kona-mpt = { git = "https://github.com/ethereum-optimism/kona", version = "0.0.2" }
5152

5253
# Internal
5354
op-test-vectors = { path = "crates/op-test-vectors" }

bin/opt8n/Cargo.toml

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,44 @@ publish = false
1010

1111
[dependencies]
1212
# Core
13+
hashbrown.workspace = true
1314
serde.workspace = true
14-
serde_json.workspace = true
1515
tracing.workspace = true
16+
serde_json.workspace = true
1617
tokio.workspace = true
18+
reqwest.workspace = true
1719
futures.workspace = true
1820
color-eyre.workspace = true
19-
axum = "0.7.5"
20-
http-body-util = "0.1.2"
21+
tracing-subscriber.workspace = true
2122

2223
# CLI
2324
clap.workspace = true
24-
shellwords.workspace = true
25+
inquire = { version = "0.7.5", features = ["editor"] }
26+
axum = "0.7"
27+
ctrlc = "3.4"
2528

2629
# Alloy
27-
alloy-eips.workspace = true
28-
alloy-rpc-types.workspace = true
2930
alloy-primitives.workspace = true
31+
alloy-rlp.workspace = true
32+
alloy-consensus.workspace = true
33+
alloy-eips.workspace = true
34+
alloy-transport = "0.2"
35+
alloy-provider = "0.2"
36+
alloy-transport-http = "0.2"
37+
op-alloy-consensus.workspace = true
38+
op-alloy-network.workspace = true
3039

31-
# Foundry
32-
foundry-common.workspace = true
33-
anvil.workspace = true
34-
anvil-core.workspace = true
35-
cast.workspace = true
36-
forge-script.workspace = true
37-
revm.workspace = true
38-
39-
# OP Types
40+
# OP Types + Kona
4041
op-test-vectors.workspace = true
41-
op-alloy-rpc-types.workspace = true
42-
op-alloy-consensus.workspace = true
43-
thiserror.workspace = true
44-
reqwest.workspace = true
45-
hyper = "1.4.1"
42+
kona-primitives.workspace = true
43+
kona-mpt.workspace = true
44+
superchain-registry.workspace = true
45+
46+
# reth
47+
reth-primitives = { workspace = true, features = ["optimism"] }
48+
reth-evm.workspace = true
49+
reth-evm-optimism.workspace = true
50+
reth-chainspec.workspace = true
51+
52+
# revm
53+
revm = { workspace = true, features = ["optimism", "alloydb"] }

bin/opt8n/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# `opt8n`
2+
3+
A CLI-tool for creating execution test fixtures.

bin/opt8n/src/cli/deposits.rs

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
//! Deposit capture tool for `opt8n`.
2+
3+
use super::Cli;
4+
use alloy_consensus::{Eip658Value, Receipt};
5+
use alloy_primitives::{b256, keccak256, Address, Bytes, Log, B256};
6+
use alloy_provider::{network::Ethereum, Provider, ReqwestProvider, RootProvider};
7+
use color_eyre::eyre::{eyre, Result};
8+
use kona_primitives::{decode_deposit, DEPOSIT_EVENT_ABI_HASH};
9+
use reqwest::Url;
10+
use tokio::sync::broadcast::Sender;
11+
use tracing::info;
12+
13+
/// keccak256("t8n")
14+
const T8N_L1_SOURCE_HASH: B256 =
15+
b256!("60b82a553424b66356596123f87f40cc9a453c02816a147e9418b49a373fa41a");
16+
17+
/// The deposit capture proxy for `opt8n`.
18+
#[derive(Debug)]
19+
pub struct DepositCapture<'a> {
20+
/// The CLI configuration for `opt8n`
21+
pub(crate) cli: &'a Cli,
22+
/// The interrupt receiver for the deposit configurator.
23+
pub(crate) interrupt: Sender<()>,
24+
/// The RLP-encoded transactions to apply to the genesis state to create the deposit.
25+
pub(crate) transactions: Vec<Bytes>,
26+
}
27+
28+
impl<'a> DepositCapture<'a> {
29+
/// Create a new deposit configurator.
30+
pub(crate) fn new(cli: &'a Cli, interrupt: Sender<()>) -> Self {
31+
Self {
32+
cli,
33+
interrupt,
34+
transactions: Vec::new(),
35+
}
36+
}
37+
38+
/// Opens a proxy to the L1 chain and captures the deposit transactions.
39+
pub(crate) async fn capture_deposits(&mut self) -> Result<()> {
40+
info!(
41+
target: "opt8n", "Capturing deposit transactions sent to the L1 chain's `OptimismPortal`..."
42+
);
43+
44+
// Capture the deposit transactions sent to the L1 node.
45+
let transactions =
46+
crate::proxy::capture_transactions(3000, self.cli.l1_port, self.interrupt.subscribe())
47+
.await?;
48+
49+
// Fetch all receipts for the deposit transactions from the L1.
50+
let l1_rpc_url = format!("http://localhost:{}", self.cli.l1_port);
51+
let l1_provider: RootProvider<_, Ethereum> =
52+
ReqwestProvider::new_http(Url::parse(&l1_rpc_url)?);
53+
let mut receipts = Vec::new();
54+
for tx in transactions {
55+
let tx_hash = keccak256(tx.as_ref());
56+
57+
// Fetch RPC receipt.
58+
let rpc_receipt = l1_provider
59+
.get_transaction_receipt(tx_hash)
60+
.await?
61+
.ok_or(eyre!(
62+
"Transaction receipt not found for transaction hash: {:?}",
63+
tx_hash
64+
))?;
65+
let receipt_rpc_logs = rpc_receipt.inner.as_receipt().ok_or(eyre!(
66+
"Receipt not found for transaction hash: {:?}",
67+
tx_hash
68+
))?;
69+
70+
// Convert to consensus receipt.
71+
let receipt: Receipt<Log> = Receipt {
72+
status: receipt_rpc_logs.status,
73+
cumulative_gas_used: receipt_rpc_logs.cumulative_gas_used,
74+
logs: receipt_rpc_logs
75+
.logs
76+
.iter()
77+
.map(|l| Log {
78+
address: l.address(),
79+
data: l.data().clone(),
80+
})
81+
.collect(),
82+
};
83+
84+
receipts.push(receipt);
85+
}
86+
87+
// Derive the deposit transactions from the OptimismPortal `depositTransaction` receipts.
88+
let deposits = Self::derive_deposits(
89+
T8N_L1_SOURCE_HASH,
90+
receipts,
91+
self.cli.optimism_portal_address,
92+
)?;
93+
94+
self.transactions = deposits;
95+
Ok(())
96+
}
97+
98+
/// Derive the deposit transactions from the OptimismPortal `depositTransaction` receipts.
99+
fn derive_deposits(
100+
block_hash: B256,
101+
receipts: Vec<Receipt>,
102+
deposit_contract: Address,
103+
) -> Result<Vec<Bytes>> {
104+
let mut global_index = 0;
105+
let mut res = Vec::new();
106+
for r in receipts.iter() {
107+
if Eip658Value::Eip658(false) == r.status {
108+
continue;
109+
}
110+
for l in r.logs.iter() {
111+
let curr_index = global_index;
112+
global_index += 1;
113+
if !l
114+
.data
115+
.topics()
116+
.first()
117+
.map_or(false, |i| *i == DEPOSIT_EVENT_ABI_HASH)
118+
{
119+
continue;
120+
}
121+
if l.address != deposit_contract {
122+
continue;
123+
}
124+
let decoded = decode_deposit(block_hash, curr_index, l).map_err(|e| eyre!(e))?;
125+
res.push(decoded.0);
126+
}
127+
}
128+
Ok(res)
129+
}
130+
}

bin/opt8n/src/cli/l1_info.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
//! L1 info transaction configuration tool for `opt8n`.
2+
3+
use color_eyre::{eyre::Result, owo_colors::OwoColorize};
4+
use inquire::{Editor, Select};
5+
use kona_primitives::{L1BlockInfoBedrock, L1BlockInfoEcotone, L1BlockInfoTx};
6+
use std::{ffi::OsStr, fmt::Display};
7+
8+
/// The L1 info transaction configurator for `opt8n`.
9+
#[derive(Debug)]
10+
pub struct L1InfoConfigurator {
11+
/// The L1 info transaction data.
12+
pub(crate) tx: L1BlockInfoTx,
13+
}
14+
15+
impl Default for L1InfoConfigurator {
16+
fn default() -> Self {
17+
Self {
18+
tx: L1BlockInfoTx::Ecotone(L1BlockInfoEcotone::default()),
19+
}
20+
}
21+
}
22+
23+
impl L1InfoConfigurator {
24+
/// Show the configuration menu for the prestate.
25+
pub(crate) fn show_configuration_menu(&mut self) -> Result<()> {
26+
let select = Select::new(
27+
"What would you like to configure?",
28+
[L1InfoConfigOption::TxKind, L1InfoConfigOption::Tx].to_vec(),
29+
)
30+
.prompt()?;
31+
32+
match select {
33+
L1InfoConfigOption::TxKind => self.configure_tx_kind(),
34+
L1InfoConfigOption::Tx => self.configure_tx(),
35+
}
36+
}
37+
38+
/// Opens a prompt to configure the chain state.
39+
pub(crate) fn configure_tx_kind(&mut self) -> Result<()> {
40+
let select = Select::new(
41+
"Which version of the L1 info transaction are you sending?",
42+
[L1InfoTxKind::Bedrock, L1InfoTxKind::Ecotone].to_vec(),
43+
)
44+
.prompt()?;
45+
46+
// Update the tx kind.
47+
match select {
48+
L1InfoTxKind::Bedrock => {
49+
self.tx = L1BlockInfoTx::Bedrock(L1BlockInfoBedrock::default())
50+
}
51+
L1InfoTxKind::Ecotone => {
52+
self.tx = L1BlockInfoTx::Ecotone(L1BlockInfoEcotone::default())
53+
}
54+
}
55+
56+
// Return to the L1 info tx configuration menu.
57+
self.show_configuration_menu()
58+
}
59+
60+
/// Opens a prompt to configure the L1 info transaction data.
61+
pub(crate) fn configure_tx(&mut self) -> Result<()> {
62+
// Serialize the tx data to a JSON string.
63+
let serialized_tx_data = serde_json::to_string_pretty(&self.tx)?;
64+
65+
// Prompt the user to edit the block environment.
66+
let editor_command = option_env!("EDITOR").unwrap_or("vim");
67+
let editor = Editor::new("Edit the L1 info transaction data")
68+
.with_file_extension(".json")
69+
.with_editor_command(OsStr::new(editor_command))
70+
.with_predefined_text(serialized_tx_data.as_str())
71+
.prompt()?;
72+
73+
// Deserialize the block environment from the editor.
74+
let deserialized_tx_data = serde_json::from_str(&editor);
75+
if let Ok(tx_data) = deserialized_tx_data {
76+
self.tx = tx_data;
77+
} else {
78+
eprintln!("Failed to deserialize L1 info transaction data. Using previous value.");
79+
}
80+
81+
Ok(())
82+
}
83+
}
84+
85+
/// The L1 info transaction configuration options.
86+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
87+
enum L1InfoConfigOption {
88+
TxKind,
89+
Tx,
90+
}
91+
92+
impl Display for L1InfoConfigOption {
93+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94+
match self {
95+
L1InfoConfigOption::TxKind => write!(
96+
f,
97+
"L1 info transaction kind ({} | {})",
98+
"BEDROCK".green(),
99+
"ECOTONE".green()
100+
),
101+
L1InfoConfigOption::Tx => write!(f, "Modify L1 info transaction"),
102+
}
103+
}
104+
}
105+
106+
/// The L1 info transaction kinds.
107+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
108+
enum L1InfoTxKind {
109+
Bedrock,
110+
Ecotone,
111+
}
112+
113+
impl Display for L1InfoTxKind {
114+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
115+
match self {
116+
L1InfoTxKind::Bedrock => write!(f, "Bedrock"),
117+
L1InfoTxKind::Ecotone => write!(f, "Ecotone"),
118+
}
119+
}
120+
}

0 commit comments

Comments
 (0)