Skip to content

Commit

Permalink
fix: transaction trie needs tx rlp to support 4844 (#291)
Browse files Browse the repository at this point in the history
* fix: transaction trie needs tx rlp to support 4844

No ZK circuit code was changed.

To generate witness transaction MPT proofs, we reconstruct the
transactions trie of a block from the raw transactions returns by a
JSON-RPC call for a block. To construct the trie, we must compute the
RLP encoding of each raw transaction. Previously, we used `ethers_core`
to do this. However `ethers_core` has not been updated after EIP 4844
(Dencun) for the new Type 3 Blob Transaction.

At first I tried to use `reth`'s transaction RLP encoding logic. However
`reth` uses an internal type to represent transactions. Since we get
transactions from RPC calls, we need an adapter from the RPC type. This
latter type is provided in `alloy_rpc_types`, but in writing the
converter from RPC type to reth primitive type, I ran into issues that
many structs were defined in parallel in the two crates, and also there
was inconsistency in the use of `ruint` primitives. I decided it was
easier just to keep `ethers_core` types for now and add custom
implementations of RLP for the new transaction type.

Also added RLP support for OP stack deposit transactions.

Moved some of the trie code from `axiom-query` to `axiom-eth` to remove
redundancy.

References:
- https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md
- https://github.com/paradigmxyz/reth/blob/28f3a2e2d9525bf2f6373e755e2d6dc0c2f97821/crates/primitives/src/transaction/mod.rs#L128
- https://github.com/alloy-rs/alloy/blob/d5967abdbae58dd84acc4c1ee31345108d42d041/crates/rpc-types/src/eth/transaction/mod.rs

* feat: switch to `ethers` v2.0.14 so `OtherField` and "optimism" are
compatible

* chore: storageProof key is now U256 instead of H256

* chore: add rpc tests
  • Loading branch information
jonathanpwang committed Mar 18, 2024
1 parent 35151f0 commit 796d4db
Show file tree
Hide file tree
Showing 14 changed files with 307 additions and 150 deletions.
4 changes: 2 additions & 2 deletions axiom-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ anyhow = "1.0"
hex = "0.4.3"

# halo2, features turned on by axiom-eth
axiom-eth = { version = "=0.4.1", path = "../axiom-eth", default-features = false, features = ["providers", "aggregation", "evm"] }
axiom-eth = { version = "0.4.1", path = "../axiom-eth", default-features = false, features = ["providers", "aggregation", "evm"] }

# crypto
ethers-core = { version = "=2.0.10" }
ethers-core = { version = "=2.0.14" }

# keygen
clap = { version = "=4.4.7", features = ["derive"], optional = true }
Expand Down
6 changes: 3 additions & 3 deletions axiom-eth/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "axiom-eth"
version = "0.4.1"
version = "0.4.2"
authors = ["Intrinsic Technologies"]
license = "MIT"
edition = "2021"
Expand Down Expand Up @@ -35,7 +35,7 @@ zkevm-hashes = { git = "https://github.com/axiom-crypto/halo2-lib.git", tag = "v

# crypto
rlp = "=0.5.2"
ethers-core = { version = "=2.0.10" } # fix the version as it affects what fields are included in the `Block` struct
ethers-core = { version = "=2.0.14", features = ["optimism"] } # fix the version as it affects what fields are included in the `Block` struct
# mpt implementation
hasher = { version = "=0.1", features = ["hash-keccak"] }
cita_trie = "=5.0.0"
Expand All @@ -53,7 +53,7 @@ snark-verifier = { git = "https://github.com/axiom-crypto/snark-verifier.git", t
snark-verifier-sdk = { git = "https://github.com/axiom-crypto/snark-verifier.git", tag = "v0.1.7-git", default-features = false }

# generating circuit inputs from blockchain
ethers-providers = { version = "=2.0.10", optional = true }
ethers-providers = { version = "=2.0.14", optional = true, features = ["optimism"] }
tokio = { version = "1.28", default-features = false, features = ["rt", "rt-multi-thread", "macros"], optional = true }
futures = { version = "0.3", optional = true }

Expand Down
51 changes: 23 additions & 28 deletions axiom-eth/src/providers/block.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ethers_core::{
types::{Block, H256, U64},
types::{Block, H256},
utils::keccak256,
};
use ethers_providers::{JsonRpcClient, Middleware, Provider, ProviderError};
Expand Down Expand Up @@ -36,22 +36,10 @@ pub fn get_block_rlp<TX>(block: &Block<TX>) -> Vec<u8> {
let base_fee = block.base_fee_per_gas;
let withdrawals_root: Option<H256> = block.withdrawals_root;
// EIP-4844:
let other = &block.other;
let mut blob_gas_used = other.get("blobGasUsed"); // EIP-4844 spec
if blob_gas_used.is_none() {
blob_gas_used = other.get("dataGasUsed"); // EIP-4788 spec
}
let blob_gas_used: Option<U64> =
blob_gas_used.map(|v| serde_json::from_value(v.clone()).unwrap());
let mut excess_blob_gas = other.get("excessBlobGas"); // EIP-4844 spec
if excess_blob_gas.is_none() {
excess_blob_gas = other.get("excessDataGas"); // EIP-4788 spec
}
let excess_blob_gas: Option<U64> =
excess_blob_gas.map(|v| serde_json::from_value(v.clone()).unwrap());
let blob_gas_used = block.blob_gas_used;
let excess_blob_gas = block.excess_blob_gas;
// EIP-4788:
let parent_beacon_block_root: Option<H256> =
other.get("parentBeaconBlockRoot").map(|v| serde_json::from_value(v.clone()).unwrap());
let parent_beacon_block_root: Option<H256> = block.parent_beacon_block_root;

let mut rlp_len = 15;
for opt in [
Expand Down Expand Up @@ -116,25 +104,32 @@ mod tests {

use super::*;

#[test]
fn test_retry_provider() {
#[tokio::test]
async fn test_retry_provider() {
let provider = setup_provider(Chain::Mainnet);
let latest = provider.get_block_number().await.unwrap().as_u64();
for block_num in [5_000_050, 5_000_051, 17_034_973, 19_426_587, 19_426_589, latest] {
let block = provider.get_block(block_num).await.unwrap().unwrap();
get_block_rlp(&block);
}
}

let rt = Runtime::new().unwrap();
for block_num in [5000050, 5000051, 17034973] {
let block = rt.block_on(provider.get_block(block_num)).unwrap().unwrap();
#[tokio::test]
async fn test_retry_provider_base() {
let provider = setup_provider(Chain::Base);
let latest = provider.get_block_number().await.unwrap().as_u64();
for block_num in [0, 100, 100_000, 5_000_050, 7_000_000, 8_000_000, 11_864_572, latest] {
let block = provider.get_block(block_num).await.unwrap().unwrap();
get_block_rlp(&block);
}
}

#[test]
fn test_retry_provider_sepolia() {
#[tokio::test]
async fn test_retry_provider_sepolia() {
let provider = setup_provider(Chain::Sepolia);

let rt = Runtime::new().unwrap();
let latest = rt.block_on(provider.get_block_number()).unwrap();
for block_num in [0, 5000050, 5187023, 5187810, 5187814, latest.as_u64()] {
let block = rt.block_on(provider.get_block(block_num)).unwrap().unwrap();
let latest = provider.get_block_number().await.unwrap().as_u64();
for block_num in [0, 5000050, 5187023, 5187810, 5187814, latest] {
let block = provider.get_block(block_num).await.unwrap().unwrap();
get_block_rlp(&block);
}
}
Expand Down
13 changes: 12 additions & 1 deletion axiom-eth/src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,18 @@ pub mod transaction;

pub fn get_provider_uri(chain: Chain) -> String {
let key = var("ALCHEMY_KEY").expect("ALCHEMY_KEY environmental variable not set");
format!("https://eth-{chain}.g.alchemy.com/v2/{key}")
match chain {
Chain::Base | Chain::Optimism | Chain::Arbitrum => {
format!("https://{chain}-mainnet.g.alchemy.com/v2/{key}")
}
Chain::Mainnet | Chain::Sepolia => {
format!("https://eth-{chain}.g.alchemy.com/v2/{key}")
}
_ => {
// Catch-all, may not always work
format!("https://{chain}.g.alchemy.com/v2/{key}")
}
}
}

pub fn setup_provider(chain: Chain) -> Provider<RetryClient<Http>> {
Expand Down
3 changes: 2 additions & 1 deletion axiom-eth/src/providers/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use ethers_providers::{JsonRpcClient, Middleware, Provider};
use futures::future::join_all;
use rlp::{Encodable, Rlp, RlpStream};
use tokio::runtime::Runtime;
use zkevm_hashes::util::eth_types::ToBigEndian;

use crate::{
mpt::{MPTInput, KECCAK_RLP_EMPTY_STRING},
Expand Down Expand Up @@ -87,7 +88,7 @@ pub fn json_to_mpt_input(
.storage_proof
.into_iter()
.map(|storage_pf| {
let path = H256(keccak256(storage_pf.key));
let path = H256(keccak256(storage_pf.key.to_be_bytes()));
let (new_proof, mut value) = get_new_proof_and_value(&path, &storage_pf.proof);
let new_proof_bytes: Vec<Bytes> =
new_proof.clone().into_iter().map(Bytes::from_iter).collect();
Expand Down
Loading

0 comments on commit 796d4db

Please sign in to comment.