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(l1): check l2 integration test in the CI #1141

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9ff01b5
Initial version of the L2 SDK
ilitteri Oct 29, 2024
642d604
Add value to gas estimation request
ilitteri Oct 29, 2024
edee580
Add integration test: deposit + transfer + withdraw
ilitteri Oct 29, 2024
ac37cee
Increase deltas
ilitteri Oct 29, 2024
7f81e0a
Add docker image and compose for testing L2
ilitteri Oct 29, 2024
6e263c5
Modify L1 dev docker compose to connect to the same network as the L2…
ilitteri Oct 29, 2024
6c376d5
Add targets to setup and run tests in the CI
ilitteri Oct 29, 2024
12569e1
Merge branch 'main' into l2_integration_test
ManuelBilbao Nov 6, 2024
0e96db7
Use include in docker-compose to avoid manual networks
ManuelBilbao Nov 7, 2024
6ab63a7
Improve docker cache
ManuelBilbao Nov 7, 2024
cc44926
Take contracts path from env var
ManuelBilbao Nov 7, 2024
224c7d8
Merge branch 'main' into l2_integration_test
ManuelBilbao Nov 7, 2024
dc91435
Merge branch 'main' into l2_integration_test
ManuelBilbao Nov 8, 2024
f384c2e
Implement serialize and deserialize for PrivilegedL2Transaction
ManuelBilbao Nov 8, 2024
09b2498
Change getBlockByHash result type
ManuelBilbao Nov 8, 2024
ff60b23
Fix serialization
ManuelBilbao Nov 8, 2024
d0d91b6
Fix Privileged tx type serialization
ManuelBilbao Nov 11, 2024
5463e13
Fix getBlockByHash response
ManuelBilbao Nov 11, 2024
59db1e3
Fix withdrawals merkle root generation
ManuelBilbao Nov 11, 2024
943493f
Add contracts path env var to Makefile
ManuelBilbao Nov 11, 2024
6d4badb
Fix deployer tests
ManuelBilbao Nov 11, 2024
2e94a18
Fix CLI
ManuelBilbao Nov 11, 2024
f9fb154
Improve makefile
ManuelBilbao Nov 11, 2024
738fb24
Add max retries while wating balance update
ManuelBilbao Nov 11, 2024
53ad667
Exclude integration test from make test
ManuelBilbao Nov 11, 2024
cd458b7
Merge branch 'main' into l2_integration_test
ManuelBilbao Nov 11, 2024
6220fb4
Comment cache step on prover CI
ManuelBilbao Nov 11, 2024
d3f2300
Merge branch 'main' into l2-integration-test-check
rodrigo-o Nov 12, 2024
803c692
re-enabled l2 integration test
rodrigo-o Nov 12, 2024
502ad73
fix an issue with the platform setup for the deployer (due to solc no…
rodrigo-o Nov 12, 2024
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
4 changes: 2 additions & 2 deletions .github/workflows/l2_prover_ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ jobs:
run: |
curl -L https://risczero.com/install | bash
~/.risc0/bin/rzup install
- name: Caching
uses: Swatinem/rust-cache@v2
# - name: Caching
# uses: Swatinem/rust-cache@v2
- name: Build prover and zkVM
run: |
cd crates/l2/prover
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ members = [
"crates/l2/",
"crates/l2/prover",
"crates/l2/contracts",
"crates/l2/sdk",
]
resolver = "2"

Expand Down
1 change: 1 addition & 0 deletions cmd/ethereum_rust_l2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ethereum_rust-core.workspace = true
ethereum_rust-blockchain.workspace = true
ethereum_rust-prover.workspace = true
ethereum_rust-rlp.workspace = true
ethereum_rust-rpc.workspace = true

[[bin]]
name = "l2"
Expand Down
19 changes: 12 additions & 7 deletions cmd/ethereum_rust_l2/src/commands/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use ethereum_rust_l2::utils::{
eth_client::{eth_sender::Overrides, EthClient},
merkle_tree::merkle_proof,
};
use ethereum_rust_rpc::types::block::BlockBodyWrapper;
use ethereum_types::{Address, H256, U256};
use eyre::OptionExt;
use hex::FromHexError;
Expand Down Expand Up @@ -212,19 +213,23 @@ async fn get_withdraw_merkle_proof(
.await?
.ok_or_eyre("Transaction receipt not found")?;

let transactions = client
let block = client
.get_block_by_hash(tx_receipt.block_info.block_hash)
.await?
.transactions;
.await?;

let transactions = match block.body {
BlockBodyWrapper::Full(body) => body.transactions,
BlockBodyWrapper::OnlyHashes(_) => unreachable!(),
};

let (index, tx_withdrawal_hash) = transactions
.iter()
.filter(|tx| match tx {
.filter(|tx| match &tx.tx {
Transaction::PrivilegedL2Transaction(tx) => tx.tx_type == PrivilegedTxType::Withdrawal,
_ => false,
})
.find_position(|tx| tx.compute_hash() == tx_hash)
.map(|(i, tx)| match tx {
.find_position(|tx| tx.hash == tx_hash)
.map(|(i, tx)| match &tx.tx {
Transaction::PrivilegedL2Transaction(tx) => {
(i as u64, tx.get_withdrawal_hash().unwrap())
}
Expand All @@ -235,7 +240,7 @@ async fn get_withdraw_merkle_proof(
let path = merkle_proof(
transactions
.iter()
.filter_map(|tx| match tx {
.filter_map(|tx| match &tx.tx {
Transaction::PrivilegedL2Transaction(tx) => tx.get_withdrawal_hash(),
_ => None,
})
Expand Down
3 changes: 1 addition & 2 deletions crates/blockchain/dev/docker-compose-dev.yaml
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@

version: '3.2'
services:
ethereum_rust:
restart: always
container_name: ethereum_rust_l1
image: "ethereum_rust_dev"
build:
context: ../../../
Expand Down
147 changes: 141 additions & 6 deletions crates/common/types/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ pub struct EIP4844Transaction {
pub signature_s: U256,
}

#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
#[derive(Clone, Debug, PartialEq, Eq, Default)]
pub struct PrivilegedL2Transaction {
pub chain_id: u64,
pub nonce: u64,
Expand Down Expand Up @@ -1196,17 +1196,60 @@ mod serde_impl {
}
}

impl Serialize for PrivilegedL2Transaction {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut struct_serializer = serializer.serialize_struct("Eip1559Transaction", 14)?;
struct_serializer.serialize_field("type", &TxType::Privileged)?;
struct_serializer.serialize_field("nonce", &format!("{:#x}", self.nonce))?;
struct_serializer.serialize_field("to", &self.to)?;
struct_serializer.serialize_field("gas", &format!("{:#x}", self.gas_limit))?;
struct_serializer.serialize_field("value", &self.value)?;
struct_serializer.serialize_field("input", &format!("0x{:x}", self.data))?;
struct_serializer.serialize_field(
"maxPriorityFeePerGas",
&format!("{:#x}", self.max_priority_fee_per_gas),
)?;
struct_serializer
.serialize_field("maxFeePerGas", &format!("{:#x}", self.max_fee_per_gas))?;
struct_serializer
.serialize_field("gasPrice", &format!("{:#x}", self.max_fee_per_gas))?;
struct_serializer.serialize_field(
"accessList",
&self
.access_list
.iter()
.map(AccessListEntry::from)
.collect::<Vec<_>>(),
)?;
struct_serializer.serialize_field("chainId", &format!("{:#x}", self.chain_id))?;
struct_serializer
.serialize_field("yParity", &format!("{:#x}", self.signature_y_parity as u8))?;
struct_serializer
.serialize_field("v", &format!("{:#x}", self.signature_y_parity as u8))?; // added to match Hive tests
struct_serializer.serialize_field("r", &self.signature_r)?;
struct_serializer.serialize_field("s", &self.signature_s)?;
struct_serializer.serialize_field("tx_type", &self.tx_type)?;
struct_serializer.end()
}
}

impl<'de> Deserialize<'de> for Transaction {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
let tx_type =
serde_json::from_value::<TxType>(map.remove("type").ok_or_else(|| {
serde::de::Error::custom("Couldn't Deserialize the 'type' field".to_string())
})?)
.map_err(serde::de::Error::custom)?;
serde_json::from_value::<TxType>(map.remove("type").unwrap_or(Value::default()))
.unwrap_or_else(|_| {
if map.contains_key("tx_type") {
return TxType::Privileged;
}
TxType::EIP1559
});

let iter = map.into_iter();
match tx_type {
Expand Down Expand Up @@ -1242,7 +1285,9 @@ mod serde_impl {
serde::de::value::MapDeserializer::new(iter),
)
.map(Transaction::PrivilegedL2Transaction)
.map_err(|e| serde::de::Error::custom(format!("Couldn't Deserialize Legacy {e}"))),
.map_err(|e| {
serde::de::Error::custom(format!("Couldn't Deserialize Privileged {e}"))
}),
}
}
}
Expand Down Expand Up @@ -1601,6 +1646,96 @@ mod serde_impl {
}
}

impl<'de> Deserialize<'de> for PrivilegedL2Transaction {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut map = <HashMap<String, serde_json::Value>>::deserialize(deserializer)?;
let nonce = serde_json::from_value::<U256>(
map.remove("nonce")
.ok_or_else(|| serde::de::Error::missing_field("nonce"))?,
)
.map_err(serde::de::Error::custom)?
.as_u64();
let to = serde_json::from_value(
map.remove("to")
.ok_or_else(|| serde::de::Error::missing_field("to"))?,
)
.map_err(serde::de::Error::custom)?;
let value = serde_json::from_value(
map.remove("value")
.ok_or_else(|| serde::de::Error::missing_field("value"))?,
)
.map_err(serde::de::Error::custom)?;
let data = deserialize_input_field(&mut map).map_err(serde::de::Error::custom)?;
let r = serde_json::from_value(
map.remove("r")
.ok_or_else(|| serde::de::Error::missing_field("r"))?,
)
.map_err(serde::de::Error::custom)?;
let s = serde_json::from_value(
map.remove("s")
.ok_or_else(|| serde::de::Error::missing_field("s"))?,
)
.map_err(serde::de::Error::custom)?;

Ok(PrivilegedL2Transaction {
chain_id: serde_json::from_value::<U256>(
map.remove("chainId")
.ok_or_else(|| serde::de::Error::missing_field("chainId"))?,
)
.map_err(serde::de::Error::custom)?
.as_u64(),
nonce,
max_priority_fee_per_gas: serde_json::from_value::<U256>(
map.remove("maxPriorityFeePerGas")
.ok_or_else(|| serde::de::Error::missing_field("maxPriorityFeePerGas"))?,
)
.map_err(serde::de::Error::custom)?
.as_u64(),
max_fee_per_gas: serde_json::from_value::<U256>(
map.remove("maxFeePerGas")
.ok_or_else(|| serde::de::Error::missing_field("maxFeePerGas"))?,
)
.map_err(serde::de::Error::custom)?
.as_u64(),
gas_limit: serde_json::from_value::<U256>(
map.remove("gas")
.ok_or_else(|| serde::de::Error::missing_field("gas"))?,
)
.map_err(serde::de::Error::custom)?
.as_u64(),
to,
value,
data,
access_list: serde_json::from_value(
map.remove("accessList")
.ok_or_else(|| serde::de::Error::missing_field("accessList"))?,
)
.map_err(serde::de::Error::custom)?,
signature_y_parity: u8::from_str_radix(
serde_json::from_value::<String>(
map.remove("yParity")
.ok_or_else(|| serde::de::Error::missing_field("yParity"))?,
)
.map_err(serde::de::Error::custom)?
.trim_start_matches("0x"),
16,
)
.map_err(serde::de::Error::custom)?
!= 0,
signature_r: r,
signature_s: s,
tx_type: serde_json::from_value(
map.remove("tx_type")
.ok_or_else(|| serde::de::Error::missing_field("tx_type"))?,
)
.map_err(serde::de::Error::custom)?,
})
}
}

/// Unsigned Transaction struct generic to all types which may not contain all required transaction fields
/// Used to perform gas estimations and access list creation
#[derive(Deserialize, Debug, PartialEq, Clone, Default)]
Expand Down
4 changes: 4 additions & 0 deletions crates/l2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ c-kzg = "^1.0.3"
# risc0
risc0-zkvm = { version = "1.1.2" }

[dev-dependencies]
ethereum_rust-sdk = { path = "./sdk" }
rand = "0.8.5"


[lib]
path = "./l2.rs"
32 changes: 32 additions & 0 deletions crates/l2/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM rust:1.80 AS chef

RUN apt-get update && apt-get install -y \
build-essential \
libclang-dev \
libc6 \
libssl-dev \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN cargo install cargo-chef

WORKDIR /ethereum_rust

FROM chef AS planner
COPY . .
# Determine the crates that need to be built from dependencies
RUN cargo chef prepare --recipe-path recipe.json

FROM chef AS builder
COPY --from=planner /ethereum_rust/recipe.json recipe.json
# Build dependencies only, these remained cached
RUN cargo chef cook --release --recipe-path recipe.json

COPY . .
RUN cargo build --release --features l2

FROM ubuntu:24.04
WORKDIR /usr/local/bin

COPY --from=builder ethereum_rust/target/release/ethereum_rust .
EXPOSE 1729
ENTRYPOINT [ "./ethereum_rust" ]
14 changes: 12 additions & 2 deletions crates/l2/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.DEFAULT_GOAL := help

.PHONY: help init down clean init-local-l1 down-local-l1 clean-local-l1 init-l2 down-l2 deploy-l1 deploy-block-executor deploy-inbox setup-prover
.PHONY: help init down clean init-local-l1 down-local-l1 clean-local-l1 init-l2 down-l2 deploy-l1 deploy-block-executor deploy-inbox setup-prover test

L2_GENESIS_FILE_PATH=../../test_data/genesis-l2.json

Expand All @@ -23,6 +23,7 @@ cli: ## 🛠️ Installs the L2 Lambda Ethereum Rust CLI
ETHEREUM_RUST_PATH=$(shell pwd)/../..
ETHEREUM_RUST_BIN_PATH=$(ETHEREUM_RUST_PATH)/target/release/ethereum_rust
ETHEREUM_RUST_DEV_DOCKER_COMPOSE_PATH=$(ETHEREUM_RUST_PATH)/crates/blockchain/dev/docker-compose-dev.yaml
ETHEREUM_RUST_L2_DOCKER_COMPOSE_PATH=./docker-compose-l2.yaml

ETHEREUM_RUST_L2_CONTRACTS_PATH=./contracts
L1_RPC_URL=http://localhost:8545
Expand All @@ -35,6 +36,7 @@ init-local-l1: ## 🚀 Initializes an L1 Lambda Ethereum Rust Client

down-local-l1: ## 🛑 Shuts down the L1 Lambda Ethereum Rust Client
docker compose -f ${ETHEREUM_RUST_DEV_DOCKER_COMPOSE_PATH} down
docker compose -f docker-compose-l2.yaml down

restart-local-l1: down-local-l1 init-local-l1 ## 🔄 Restarts the L1 Lambda Ethereum Rust Client

Expand All @@ -47,7 +49,7 @@ clean-contract-deps: ## 🧹 Cleans the dependencies for the L1 contracts.
restart-contract-deps: clean-contract-deps ## 🔄 Restarts the dependencies for the L1 contracts.

deploy-l1: ## 📜 Deploys the L1 contracts
cargo run --release --bin ethereum_rust_l2_l1_deployer --manifest-path ${ETHEREUM_RUST_L2_CONTRACTS_PATH}/Cargo.toml
DEPLOYER_CONTRACTS_PATH=contracts cargo run --release --bin ethereum_rust_l2_l1_deployer --manifest-path ${ETHEREUM_RUST_L2_CONTRACTS_PATH}/Cargo.toml

# L2

Expand All @@ -64,3 +66,11 @@ init-l2-prover: ## 🚀 Initializes the Prover

init-l2-prover-gpu: ## 🚀 Initializes the Prover with GPU support
cargo run --release --features "build_zkvm,cuda" --manifest-path ../../Cargo.toml --bin ethereum_rust_prover

# CI Testing

test:
docker compose -f ${ETHEREUM_RUST_L2_DOCKER_COMPOSE_PATH} down
docker compose -f ${ETHEREUM_RUST_L2_DOCKER_COMPOSE_PATH} up -d
cargo test --release testito -- --nocapture
docker compose -f ${ETHEREUM_RUST_L2_DOCKER_COMPOSE_PATH} down
1 change: 1 addition & 0 deletions crates/l2/contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ bytes = { version = "1.6.0", features = ["serde"] }
libsecp256k1 = "0.7.1"
keccak-hash = "0.10.0"
hex = "0.4.3"
tracing.workspace = true

ethereum_rust-l2 = { path = "../../l2" }
ethereum_rust-core = { path = "../../common" }
Expand Down
Loading
Loading