From 7daee2418fd3403f77598d6da4e0cd574ed4a7c4 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:00:42 +0000 Subject: [PATCH 01/12] override ethgetproof --- Cargo.lock | 9 ++++ Cargo.toml | 5 ++ bin/odyssey/src/main.rs | 11 +++- crates/node/Cargo.toml | 10 ++++ crates/node/src/lib.rs | 1 + crates/node/src/rpc.rs | 111 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 crates/node/src/rpc.rs diff --git a/Cargo.lock b/Cargo.lock index 1faabf3..27e5d8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4586,9 +4586,13 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", + "alloy-rpc-types", + "alloy-rpc-types-eth", "eyre", + "jsonrpsee", "reth-chainspec", "reth-cli", + "reth-errors", "reth-evm", "reth-network", "reth-network-types", @@ -4601,7 +4605,12 @@ dependencies = [ "reth-payload-builder", "reth-primitives", "reth-revm", + "reth-rpc-eth-api", + "reth-rpc-eth-types", + "reth-rpc-types-compat", + "reth-storage-api", "reth-transaction-pool", + "reth-trie-common", "reth-trie-db", "revm-precompile", "revm-primitives", diff --git a/Cargo.toml b/Cargo.toml index bec8d4a..fca7e52 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -149,6 +149,7 @@ alloy-eips = "0.6.4" alloy-network = "0.6.4" alloy-primitives = "0.8.11" alloy-rpc-types = "0.6.4" +alloy-rpc-types-eth = "0.6.4" alloy-signer-local = { version = "0.6.4", features = ["mnemonic"] } # tokio @@ -158,6 +159,7 @@ tokio = { version = "1.21", default-features = false } reth-chainspec = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-cli = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-cli-util = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } +reth-errors = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-evm = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-node-api = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } @@ -185,9 +187,12 @@ reth-provider = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aa "optimism", ] } reth-revm = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } +reth-rpc-types-compat = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } +reth-rpc-eth-types = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-storage-api = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-tracing = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } +reth-trie-common = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-trie-db = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-network = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-network-types = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } diff --git a/bin/odyssey/src/main.rs b/bin/odyssey/src/main.rs index 6030d53..0f9755f 100644 --- a/bin/odyssey/src/main.rs +++ b/bin/odyssey/src/main.rs @@ -28,7 +28,11 @@ use alloy_primitives::Address; use alloy_signer_local::PrivateKeySigner; use clap::Parser; use eyre::Context; -use odyssey_node::{chainspec::OdysseyChainSpecParser, node::OdysseyNode}; +use odyssey_node::{ + chainspec::OdysseyChainSpecParser, + node::OdysseyNode, + rpc::{EthApiExt, EthApiOverrideServer}, +}; use odyssey_wallet::{OdysseyWallet, OdysseyWalletApiServer}; use odyssey_walltime::{OdysseyWallTime, OdysseyWallTimeRpcApiServer}; use reth_node_builder::{engine_tree_config::TreeConfig, EngineNodeLauncher}; @@ -56,6 +60,11 @@ fn main() { .with_components(OdysseyNode::components(&rollup_args)) .with_add_ons(OpAddOns::new(rollup_args.sequencer_http)) .extend_rpc_modules(move |ctx| { + // override eth namespace + ctx.modules.replace_configured( + EthApiExt::new(ctx.registry.eth_api().clone()).into_rpc(), + )?; + // register odyssey wallet namespace if let Ok(sk) = std::env::var("EXP1_SK") { let signer: PrivateKeySigner = diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index 8aaf1c9..325fe35 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -14,6 +14,7 @@ revm-precompile.workspace = true revm-primitives.workspace = true reth-cli.workspace = true +reth-errors.workspace = true reth-node-api.workspace = true reth-node-builder.workspace = true reth-optimism-node.workspace = true @@ -25,7 +26,12 @@ reth-payload-builder.workspace = true reth-primitives.workspace = true reth-evm.workspace = true reth-revm.workspace = true +reth-rpc-eth-api.workspace = true +reth-rpc-eth-types.workspace = true +reth-rpc-types-compat.workspace = true +reth-storage-api.workspace = true reth-transaction-pool.workspace = true +reth-trie-common.workspace = true reth-trie-db.workspace = true reth-network.workspace = true reth-network-types.workspace = true @@ -33,10 +39,14 @@ reth-network-types.workspace = true alloy-consensus.workspace = true alloy-eips.workspace = true alloy-primitives.workspace = true +alloy-rpc-types.workspace = true +alloy-rpc-types-eth.workspace = true + serde_json.workspace = true tracing.workspace = true eyre.workspace = true +jsonrpsee.workspace = true [lints] workspace = true diff --git a/crates/node/src/lib.rs b/crates/node/src/lib.rs index c0e4ee6..6966b27 100644 --- a/crates/node/src/lib.rs +++ b/crates/node/src/lib.rs @@ -18,3 +18,4 @@ pub mod chainspec; pub mod evm; pub mod node; +pub mod rpc; diff --git a/crates/node/src/rpc.rs b/crates/node/src/rpc.rs new file mode 100644 index 0000000..bfda067 --- /dev/null +++ b/crates/node/src/rpc.rs @@ -0,0 +1,111 @@ +//! Odyssey rpc logic. +//! +//! `eth_` namespace overrides: +//! +//! - `eth_getProof` will _ONLY_ return the storage proofs _WITHOUT_ an account proof _IF_ targeting +//! the withdrawal contract. Otherwise, it fallbacks to default behaviour. + +use alloy_eips::BlockId; +use alloy_primitives::Address; +use alloy_rpc_types::serde_helpers::JsonStorageKey; +use alloy_rpc_types_eth::EIP1186AccountProofResponse; +use jsonrpsee::{ + core::{async_trait, RpcResult}, + proc_macros::rpc, +}; +use reth_errors::RethError; +use reth_rpc_eth_api::{ + helpers::{EthState, FullEthApi}, + FromEthApiError, +}; +use reth_rpc_eth_types::EthApiError; +use reth_rpc_types_compat::proof::from_primitive_account_proof; +use reth_storage_api::BlockIdReader; +use reth_trie_common::AccountProof; +use tracing::trace; + +const WITHDRAWAL_CONTRACT: alloy_primitives::Address = + alloy_primitives::address!("4200000000000000000000000000000000000011"); + +/// Odyssey `eth_` RPC namespace overrides. +#[cfg_attr(not(test), rpc(server, namespace = "eth"))] +#[cfg_attr(test, rpc(server, client, namespace = "eth"))] +pub trait EthApiOverride { + /// Returns the account and storage values of the specified account including the Merkle-proof. + /// This call can be used to verify that the data you are pulling from is not tampered with. + #[method(name = "getProof")] + async fn get_proof( + &self, + address: Address, + keys: Vec, + block_number: Option, + ) -> RpcResult; +} + +/// Implementation of the `eth_` namespace override +#[derive(Debug)] +pub struct EthApiExt { + eth_api: Eth, +} + +impl EthApiExt { + /// Create a new `EthApiExt` module. + pub const fn new(eth_api: E) -> Self { + Self { eth_api } + } +} + +#[async_trait] +impl EthApiOverrideServer for EthApiExt +where + Eth: FullEthApi + Send + Sync + 'static, +{ + async fn get_proof( + &self, + address: Address, + keys: Vec, + block_number: Option, + ) -> RpcResult { + trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof"); + + // If we are targeting the withdrawal contract, then we only need to provide the storage + // proofs for withdrawal. + if address == WITHDRAWAL_CONTRACT { + let _permit = self + .eth_api + .acquire_owned() + .await + .map_err(RethError::other) + .map_err(EthApiError::Internal)?; + + return self + .eth_api + .spawn_blocking_io(move |this| { + let state = this.state_at_block_id(block_number.unwrap_or_default())?; + let storage_root = state + .storage_root(WITHDRAWAL_CONTRACT, Default::default()) + .map_err(EthApiError::from_eth_err)?; + let storage_proofs = keys + .iter() + .map(|key| { + state.storage_proof( + WITHDRAWAL_CONTRACT, + key.as_b256(), + Default::default(), + ) + }) + .collect::, _>>() + .map_err(EthApiError::from_eth_err)?; + let proof = AccountProof { storage_root, storage_proofs, ..Default::default() }; + Ok(from_primitive_account_proof(proof, keys)) + }) + .await + .map_err(Into::into); + } + + EthState::get_proof(&self.eth_api, address, keys, block_number) + .map_err(Into::into)? + .await + .map_err(Into::into) + } +} From 06796ff008d2f758f8bfaf0043bae4c2eff07062 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:12:52 +0000 Subject: [PATCH 02/12] rm unused import --- Cargo.lock | 1 - crates/node/Cargo.toml | 1 - crates/node/src/rpc.rs | 1 - 3 files changed, 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27e5d8c..978d85e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4608,7 +4608,6 @@ dependencies = [ "reth-rpc-eth-api", "reth-rpc-eth-types", "reth-rpc-types-compat", - "reth-storage-api", "reth-transaction-pool", "reth-trie-common", "reth-trie-db", diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index 325fe35..05b7e36 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -29,7 +29,6 @@ reth-revm.workspace = true reth-rpc-eth-api.workspace = true reth-rpc-eth-types.workspace = true reth-rpc-types-compat.workspace = true -reth-storage-api.workspace = true reth-transaction-pool.workspace = true reth-trie-common.workspace = true reth-trie-db.workspace = true diff --git a/crates/node/src/rpc.rs b/crates/node/src/rpc.rs index bfda067..dc20785 100644 --- a/crates/node/src/rpc.rs +++ b/crates/node/src/rpc.rs @@ -20,7 +20,6 @@ use reth_rpc_eth_api::{ }; use reth_rpc_eth_types::EthApiError; use reth_rpc_types_compat::proof::from_primitive_account_proof; -use reth_storage_api::BlockIdReader; use reth_trie_common::AccountProof; use tracing::trace; From e4fc303c9ab4abec14cdcf91c1453429d8ba14de Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 13:19:19 +0000 Subject: [PATCH 03/12] add address to response --- crates/node/src/rpc.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/node/src/rpc.rs b/crates/node/src/rpc.rs index dc20785..5f82a81 100644 --- a/crates/node/src/rpc.rs +++ b/crates/node/src/rpc.rs @@ -95,7 +95,12 @@ where }) .collect::, _>>() .map_err(EthApiError::from_eth_err)?; - let proof = AccountProof { storage_root, storage_proofs, ..Default::default() }; + let proof = AccountProof { + address, + storage_root, + storage_proofs, + ..Default::default() + }; Ok(from_primitive_account_proof(proof, keys)) }) .await From e3dffc726de814ead1b7e8d4c7c15252fc8b5d3d Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:43:29 +0000 Subject: [PATCH 04/12] add docs on WITHDRAWAL_CONTRACT --- crates/node/src/rpc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/node/src/rpc.rs b/crates/node/src/rpc.rs index 5f82a81..334927c 100644 --- a/crates/node/src/rpc.rs +++ b/crates/node/src/rpc.rs @@ -23,6 +23,7 @@ use reth_rpc_types_compat::proof::from_primitive_account_proof; use reth_trie_common::AccountProof; use tracing::trace; +/// Withdrawal contract address. const WITHDRAWAL_CONTRACT: alloy_primitives::Address = alloy_primitives::address!("4200000000000000000000000000000000000011"); From 288e8bf737b32bb29ef73cd27e4232b78395353a Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:53:25 +0000 Subject: [PATCH 05/12] add e2e test_withdrawal_proof_with_fallback --- Cargo.lock | 1 + crates/e2e-tests/Cargo.toml | 1 + crates/e2e-tests/src/tests.rs | 45 +++++++++++++++++++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 978d85e..bd56043 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4575,6 +4575,7 @@ dependencies = [ "alloy-rpc-types", "alloy-signer-local", "ci_info", + "serde", "tokio", "url", ] diff --git a/crates/e2e-tests/Cargo.toml b/crates/e2e-tests/Cargo.toml index eefd8c6..02eb2f2 100644 --- a/crates/e2e-tests/Cargo.toml +++ b/crates/e2e-tests/Cargo.toml @@ -18,6 +18,7 @@ alloy-signer-local.workspace = true tokio.workspace = true url = "2.5.0" ci_info = "0.14.14" +serde.workspace = true [lints] workspace = true diff --git a/crates/e2e-tests/src/tests.rs b/crates/e2e-tests/src/tests.rs index b96820c..463a6fa 100644 --- a/crates/e2e-tests/src/tests.rs +++ b/crates/e2e-tests/src/tests.rs @@ -2,14 +2,15 @@ use std::{collections::BTreeMap, sync::LazyLock}; use alloy::{ eips::eip7702::Authorization, - primitives::{b256, Address, B256, U256}, + primitives::{address, b256, Address, B256, U256}, providers::{PendingTransactionBuilder, Provider, ProviderBuilder}, signers::SignerSync, }; use alloy_network::{TransactionBuilder, TransactionBuilder7702}; -use alloy_rpc_types::TransactionRequest; +use alloy_rpc_types::{BlockNumberOrTag, TransactionRequest}; use alloy_signer_local::PrivateKeySigner; use url::Url; +use alloy_rpc_types::EIP1186AccountProofResponse; static REPLICA_RPC: LazyLock = LazyLock::new(|| { std::env::var("REPLICA_RPC") @@ -127,3 +128,43 @@ async fn test_new_wallet_api() -> Result<(), Box> { Ok(()) } + + +#[tokio::test] +async fn test_withdrawal_proof_with_fallback() -> Result<(), Box> { + if !ci_info::is_ci() { + return Ok(()); + } + + #[derive(Debug, Clone, serde::Serialize)] + struct ProofParams { + address: Address, + keys: Vec, + block: BlockNumberOrTag + } + + let provider = ProviderBuilder::new().on_http(REPLICA_RPC.clone()); + let signer = PrivateKeySigner::from_bytes(&b256!( + "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + ))?; + + // Withdrawal contract will return an empty account proof, since it only handles storage proofs + let withdrawal_contract_response: EIP1186AccountProofResponse = provider.client().request("eth_getProof", ProofParams { + address: address!("4200000000000000000000000000000000000011"), + keys: vec![B256::ZERO], + block: BlockNumberOrTag::Latest + }).await?; + assert!(withdrawal_contract_response.account_proof.is_empty()); + assert!(!withdrawal_contract_response.storage_proof.is_empty()); + + // If not targeting the withdrawal contract, it defaults back to the standard getProof implementation + let eoa_response: EIP1186AccountProofResponse = provider.client().request("eth_getProof", ProofParams { + address: signer.address(), + keys: vec![], + block: BlockNumberOrTag::Latest + }).await?; + assert!(!eoa_response.account_proof.is_empty()); + + + Ok(()) +} From 00725aa7420ef28b7c41ef5301739c6d1ed65d03 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:59:37 +0000 Subject: [PATCH 06/12] doc & fmt --- crates/e2e-tests/src/tests.rs | 44 +++++++++++++++++++++-------------- crates/node/src/rpc.rs | 4 +++- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/crates/e2e-tests/src/tests.rs b/crates/e2e-tests/src/tests.rs index 463a6fa..a9be9ac 100644 --- a/crates/e2e-tests/src/tests.rs +++ b/crates/e2e-tests/src/tests.rs @@ -7,10 +7,9 @@ use alloy::{ signers::SignerSync, }; use alloy_network::{TransactionBuilder, TransactionBuilder7702}; -use alloy_rpc_types::{BlockNumberOrTag, TransactionRequest}; +use alloy_rpc_types::{BlockNumberOrTag, EIP1186AccountProofResponse, TransactionRequest}; use alloy_signer_local::PrivateKeySigner; use url::Url; -use alloy_rpc_types::EIP1186AccountProofResponse; static REPLICA_RPC: LazyLock = LazyLock::new(|| { std::env::var("REPLICA_RPC") @@ -129,7 +128,6 @@ async fn test_new_wallet_api() -> Result<(), Box> { Ok(()) } - #[tokio::test] async fn test_withdrawal_proof_with_fallback() -> Result<(), Box> { if !ci_info::is_ci() { @@ -140,31 +138,43 @@ async fn test_withdrawal_proof_with_fallback() -> Result<(), Box, - block: BlockNumberOrTag + block: BlockNumberOrTag, } - + let provider = ProviderBuilder::new().on_http(REPLICA_RPC.clone()); let signer = PrivateKeySigner::from_bytes(&b256!( "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" ))?; // Withdrawal contract will return an empty account proof, since it only handles storage proofs - let withdrawal_contract_response: EIP1186AccountProofResponse = provider.client().request("eth_getProof", ProofParams { - address: address!("4200000000000000000000000000000000000011"), - keys: vec![B256::ZERO], - block: BlockNumberOrTag::Latest - }).await?; + let withdrawal_contract_response: EIP1186AccountProofResponse = provider + .client() + .request( + "eth_getProof", + ProofParams { + address: address!("4200000000000000000000000000000000000011"), + keys: vec![B256::ZERO], + block: BlockNumberOrTag::Latest, + }, + ) + .await?; assert!(withdrawal_contract_response.account_proof.is_empty()); assert!(!withdrawal_contract_response.storage_proof.is_empty()); - // If not targeting the withdrawal contract, it defaults back to the standard getProof implementation - let eoa_response: EIP1186AccountProofResponse = provider.client().request("eth_getProof", ProofParams { - address: signer.address(), - keys: vec![], - block: BlockNumberOrTag::Latest - }).await?; + // If not targeting the withdrawal contract, it defaults back to the standard getProof + // implementation + let eoa_response: EIP1186AccountProofResponse = provider + .client() + .request( + "eth_getProof", + ProofParams { + address: signer.address(), + keys: vec![], + block: BlockNumberOrTag::Latest, + }, + ) + .await?; assert!(!eoa_response.account_proof.is_empty()); - Ok(()) } diff --git a/crates/node/src/rpc.rs b/crates/node/src/rpc.rs index 334927c..26b7c00 100644 --- a/crates/node/src/rpc.rs +++ b/crates/node/src/rpc.rs @@ -23,7 +23,9 @@ use reth_rpc_types_compat::proof::from_primitive_account_proof; use reth_trie_common::AccountProof; use tracing::trace; -/// Withdrawal contract address. +/// Withdrawal predeployed contract address. +/// +/// [The L2ToL1MessagePasser](https://specs.optimism.io/protocol/withdrawals.html#the-l2tol1messagepasser-contract) const WITHDRAWAL_CONTRACT: alloy_primitives::Address = alloy_primitives::address!("4200000000000000000000000000000000000011"); From df725e18f1d579ee352fef778a18873ac9fa4004 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:11:49 +0000 Subject: [PATCH 07/12] fix withdrawal contract address --- Cargo.lock | 9 +++++++++ Cargo.toml | 2 ++ crates/constants/Cargo.toml | 16 ++++++++++++++++ crates/constants/src/lib.rs | 6 ++++++ crates/e2e-tests/Cargo.toml | 2 ++ crates/e2e-tests/src/tests.rs | 2 +- crates/node/Cargo.toml | 2 ++ crates/node/src/rpc.rs | 7 +------ 8 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 crates/constants/Cargo.toml create mode 100644 crates/constants/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index bd56043..22674f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4566,6 +4566,13 @@ dependencies = [ "tracing", ] +[[package]] +name = "odyssey-constants" +version = "0.0.0" +dependencies = [ + "alloy-primitives", +] + [[package]] name = "odyssey-e2e-tests" version = "0.0.0" @@ -4575,6 +4582,7 @@ dependencies = [ "alloy-rpc-types", "alloy-signer-local", "ci_info", + "odyssey-constants", "serde", "tokio", "url", @@ -4591,6 +4599,7 @@ dependencies = [ "alloy-rpc-types-eth", "eyre", "jsonrpsee", + "odyssey-constants", "reth-chainspec", "reth-cli", "reth-errors", diff --git a/Cargo.toml b/Cargo.toml index fca7e52..a10892f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ "bin/odyssey/", + "crates/constants", "crates/node", "crates/e2e-tests", "crates/wallet", @@ -134,6 +135,7 @@ strip = false [workspace.dependencies] # odyssey +odyssey-constants = { path = "crates/constants" } odyssey-node = { path = "crates/node" } odyssey-wallet = { path = "crates/wallet" } odyssey-walltime = { path = "crates/walltime" } diff --git a/crates/constants/Cargo.toml b/crates/constants/Cargo.toml new file mode 100644 index 0000000..308eba0 --- /dev/null +++ b/crates/constants/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "odyssey-constants" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true +repository.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +alloy-primitives.workspace = true + +[lints] +workspace = true diff --git a/crates/constants/src/lib.rs b/crates/constants/src/lib.rs new file mode 100644 index 0000000..f10a6de --- /dev/null +++ b/crates/constants/src/lib.rs @@ -0,0 +1,6 @@ +use alloy_primitives::{Address, address}; + +/// Withdrawal predeployed contract address. +/// +/// [The L2ToL1MessagePasser](https://specs.optimism.io/protocol/withdrawals.html#the-l2tol1messagepasser-contract) +pub const WITHDRAWAL_CONTRACT: Address = address!("4200000000000000000000000000000000000016"); diff --git a/crates/e2e-tests/Cargo.toml b/crates/e2e-tests/Cargo.toml index 02eb2f2..6b986d0 100644 --- a/crates/e2e-tests/Cargo.toml +++ b/crates/e2e-tests/Cargo.toml @@ -10,6 +10,8 @@ keywords.workspace = true categories.workspace = true [dev-dependencies] +odyssey-constants.workspace = true + alloy.workspace = true alloy-network.workspace = true alloy-rpc-types.workspace = true diff --git a/crates/e2e-tests/src/tests.rs b/crates/e2e-tests/src/tests.rs index a9be9ac..6f3cc62 100644 --- a/crates/e2e-tests/src/tests.rs +++ b/crates/e2e-tests/src/tests.rs @@ -152,7 +152,7 @@ async fn test_withdrawal_proof_with_fallback() -> Result<(), Box Date: Tue, 26 Nov 2024 15:12:46 +0000 Subject: [PATCH 08/12] fmt --- crates/constants/src/lib.rs | 2 +- crates/node/src/rpc.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/constants/src/lib.rs b/crates/constants/src/lib.rs index f10a6de..812572f 100644 --- a/crates/constants/src/lib.rs +++ b/crates/constants/src/lib.rs @@ -1,4 +1,4 @@ -use alloy_primitives::{Address, address}; +use alloy_primitives::{address, Address}; /// Withdrawal predeployed contract address. /// diff --git a/crates/node/src/rpc.rs b/crates/node/src/rpc.rs index 3f94b7f..50cd1de 100644 --- a/crates/node/src/rpc.rs +++ b/crates/node/src/rpc.rs @@ -13,6 +13,7 @@ use jsonrpsee::{ core::{async_trait, RpcResult}, proc_macros::rpc, }; +use odyssey_constants::WITHDRAWAL_CONTRACT; use reth_errors::RethError; use reth_rpc_eth_api::{ helpers::{EthState, FullEthApi}, @@ -22,7 +23,6 @@ use reth_rpc_eth_types::EthApiError; use reth_rpc_types_compat::proof::from_primitive_account_proof; use reth_trie_common::AccountProof; use tracing::trace; -use odyssey_constants::WITHDRAWAL_CONTRACT; /// Odyssey `eth_` RPC namespace overrides. #[cfg_attr(not(test), rpc(server, namespace = "eth"))] From 90dcba360ab8314df0daeb85b840216825638711 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:17:35 +0000 Subject: [PATCH 09/12] rename to odyssey-common --- Cargo.lock | 6 +++--- Cargo.toml | 4 ++-- crates/{constants => common}/Cargo.toml | 2 +- crates/{constants/src/lib.rs => common/src/constants.rs} | 2 ++ crates/common/src/lib.rs | 7 +++++++ crates/e2e-tests/Cargo.toml | 2 +- crates/e2e-tests/src/tests.rs | 2 +- crates/node/Cargo.toml | 2 +- crates/node/src/rpc.rs | 2 +- 9 files changed, 19 insertions(+), 10 deletions(-) rename crates/{constants => common}/Cargo.toml (91%) rename crates/{constants/src/lib.rs => common/src/constants.rs} (92%) create mode 100644 crates/common/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 22674f2..d37fcee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4567,7 +4567,7 @@ dependencies = [ ] [[package]] -name = "odyssey-constants" +name = "odyssey-common" version = "0.0.0" dependencies = [ "alloy-primitives", @@ -4582,7 +4582,7 @@ dependencies = [ "alloy-rpc-types", "alloy-signer-local", "ci_info", - "odyssey-constants", + "odyssey-common", "serde", "tokio", "url", @@ -4599,7 +4599,7 @@ dependencies = [ "alloy-rpc-types-eth", "eyre", "jsonrpsee", - "odyssey-constants", + "odyssey-common", "reth-chainspec", "reth-cli", "reth-errors", diff --git a/Cargo.toml b/Cargo.toml index a10892f..8d74019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ "bin/odyssey/", - "crates/constants", + "crates/common", "crates/node", "crates/e2e-tests", "crates/wallet", @@ -135,7 +135,7 @@ strip = false [workspace.dependencies] # odyssey -odyssey-constants = { path = "crates/constants" } +odyssey-common = { path = "crates/common" } odyssey-node = { path = "crates/node" } odyssey-wallet = { path = "crates/wallet" } odyssey-walltime = { path = "crates/walltime" } diff --git a/crates/constants/Cargo.toml b/crates/common/Cargo.toml similarity index 91% rename from crates/constants/Cargo.toml rename to crates/common/Cargo.toml index 308eba0..a15a44e 100644 --- a/crates/constants/Cargo.toml +++ b/crates/common/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "odyssey-constants" +name = "odyssey-common" version.workspace = true edition.workspace = true rust-version.workspace = true diff --git a/crates/constants/src/lib.rs b/crates/common/src/constants.rs similarity index 92% rename from crates/constants/src/lib.rs rename to crates/common/src/constants.rs index 812572f..1b175e2 100644 --- a/crates/constants/src/lib.rs +++ b/crates/common/src/constants.rs @@ -1,3 +1,5 @@ +//! Odyssey constants. + use alloy_primitives::{address, Address}; /// Withdrawal predeployed contract address. diff --git a/crates/common/src/lib.rs b/crates/common/src/lib.rs new file mode 100644 index 0000000..5018fe5 --- /dev/null +++ b/crates/common/src/lib.rs @@ -0,0 +1,7 @@ +//! Odyssey common types and constants + +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![warn(unused_crate_dependencies)] + +mod constants; +pub use constants::WITHDRAWAL_CONTRACT; diff --git a/crates/e2e-tests/Cargo.toml b/crates/e2e-tests/Cargo.toml index 6b986d0..f55374a 100644 --- a/crates/e2e-tests/Cargo.toml +++ b/crates/e2e-tests/Cargo.toml @@ -10,7 +10,7 @@ keywords.workspace = true categories.workspace = true [dev-dependencies] -odyssey-constants.workspace = true +odyssey-common.workspace = true alloy.workspace = true alloy-network.workspace = true diff --git a/crates/e2e-tests/src/tests.rs b/crates/e2e-tests/src/tests.rs index 6f3cc62..0861c19 100644 --- a/crates/e2e-tests/src/tests.rs +++ b/crates/e2e-tests/src/tests.rs @@ -152,7 +152,7 @@ async fn test_withdrawal_proof_with_fallback() -> Result<(), Box Date: Tue, 26 Nov 2024 15:19:45 +0000 Subject: [PATCH 10/12] clippy --- crates/e2e-tests/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/e2e-tests/src/tests.rs b/crates/e2e-tests/src/tests.rs index 0861c19..a739ab8 100644 --- a/crates/e2e-tests/src/tests.rs +++ b/crates/e2e-tests/src/tests.rs @@ -2,7 +2,7 @@ use std::{collections::BTreeMap, sync::LazyLock}; use alloy::{ eips::eip7702::Authorization, - primitives::{address, b256, Address, B256, U256}, + primitives::{b256, Address, B256, U256}, providers::{PendingTransactionBuilder, Provider, ProviderBuilder}, signers::SignerSync, }; From 0dafa423f31704e3a578484b9f03b3d2e46f657c Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:41:15 +0000 Subject: [PATCH 11/12] verify proofs --- Cargo.lock | 3 +- Cargo.toml | 1 + crates/e2e-tests/Cargo.toml | 4 ++- crates/e2e-tests/src/tests.rs | 59 ++++++++++++++++++++--------------- 4 files changed, 40 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d37fcee..f475a04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4583,7 +4583,8 @@ dependencies = [ "alloy-signer-local", "ci_info", "odyssey-common", - "serde", + "reth-primitives-traits", + "reth-trie-common", "tokio", "url", ] diff --git a/Cargo.toml b/Cargo.toml index 8d74019..dab5fde 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -185,6 +185,7 @@ reth-payload-builder = { git = "https://github.com/paradigmxyz/reth.git", rev = reth-primitives = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac", features = [ "optimism", ] } +reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac" } reth-provider = { git = "https://github.com/paradigmxyz/reth.git", rev = "f211aac", features = [ "optimism", ] } diff --git a/crates/e2e-tests/Cargo.toml b/crates/e2e-tests/Cargo.toml index f55374a..c840a2b 100644 --- a/crates/e2e-tests/Cargo.toml +++ b/crates/e2e-tests/Cargo.toml @@ -12,6 +12,9 @@ categories.workspace = true [dev-dependencies] odyssey-common.workspace = true +reth-primitives-traits.workspace = true +reth-trie-common.workspace = true + alloy.workspace = true alloy-network.workspace = true alloy-rpc-types.workspace = true @@ -20,7 +23,6 @@ alloy-signer-local.workspace = true tokio.workspace = true url = "2.5.0" ci_info = "0.14.14" -serde.workspace = true [lints] workspace = true diff --git a/crates/e2e-tests/src/tests.rs b/crates/e2e-tests/src/tests.rs index a739ab8..2e529aa 100644 --- a/crates/e2e-tests/src/tests.rs +++ b/crates/e2e-tests/src/tests.rs @@ -7,8 +7,10 @@ use alloy::{ signers::SignerSync, }; use alloy_network::{TransactionBuilder, TransactionBuilder7702}; -use alloy_rpc_types::{BlockNumberOrTag, EIP1186AccountProofResponse, TransactionRequest}; +use alloy_rpc_types::{Block, BlockNumberOrTag, EIP1186AccountProofResponse, TransactionRequest}; use alloy_signer_local::PrivateKeySigner; +use reth_primitives_traits::Account; +use reth_trie_common::{AccountProof, StorageProof}; use url::Url; static REPLICA_RPC: LazyLock = LazyLock::new(|| { @@ -134,47 +136,54 @@ async fn test_withdrawal_proof_with_fallback() -> Result<(), Box, - block: BlockNumberOrTag, - } - let provider = ProviderBuilder::new().on_http(REPLICA_RPC.clone()); - let signer = PrivateKeySigner::from_bytes(&b256!( - "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" - ))?; + let block: Block = provider + .client() + .request("eth_getBlockByNumber", (BlockNumberOrTag::Latest, false)) + .await?; + let block_number = BlockNumberOrTag::Number(block.header.number); // Withdrawal contract will return an empty account proof, since it only handles storage proofs let withdrawal_contract_response: EIP1186AccountProofResponse = provider .client() .request( "eth_getProof", - ProofParams { - address: odyssey_common::WITHDRAWAL_CONTRACT, - keys: vec![B256::ZERO], - block: BlockNumberOrTag::Latest, - }, + (odyssey_common::WITHDRAWAL_CONTRACT, vec![B256::ZERO], block_number), ) .await?; + assert!(withdrawal_contract_response.account_proof.is_empty()); assert!(!withdrawal_contract_response.storage_proof.is_empty()); + let storage_root = withdrawal_contract_response.storage_hash; + for proof in withdrawal_contract_response.storage_proof { + StorageProof::new(proof.key.as_b256()).with_proof(proof.proof).verify(storage_root)? + } + // If not targeting the withdrawal contract, it defaults back to the standard getProof // implementation + let signer = PrivateKeySigner::from_bytes(&b256!( + "59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" + ))?; + let eoa_response: EIP1186AccountProofResponse = provider .client() - .request( - "eth_getProof", - ProofParams { - address: signer.address(), - keys: vec![], - block: BlockNumberOrTag::Latest, - }, - ) - .await?; + .request("eth_getProof", (signer.address(), [0; 0], block_number)) + .await + .unwrap(); + assert!(!eoa_response.account_proof.is_empty()); + AccountProof { + address: signer.address(), + info: Some(Account { + nonce: eoa_response.nonce, + balance: eoa_response.balance, + bytecode_hash: None, + }), + proof: eoa_response.account_proof, + ..Default::default() + } + .verify(block.header.state_root)?; Ok(()) } From 62af756df14af6a13d0a9df80d5176ecb83f1bb3 Mon Sep 17 00:00:00 2001 From: joshieDo <93316087+joshieDo@users.noreply.github.com> Date: Tue, 26 Nov 2024 17:10:32 +0000 Subject: [PATCH 12/12] specify code_hash --- crates/e2e-tests/src/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/e2e-tests/src/tests.rs b/crates/e2e-tests/src/tests.rs index 2e529aa..bbcff25 100644 --- a/crates/e2e-tests/src/tests.rs +++ b/crates/e2e-tests/src/tests.rs @@ -178,7 +178,7 @@ async fn test_withdrawal_proof_with_fallback() -> Result<(), Box