ci(l1): build the reorg-test ethrex binary with release-fast #20275
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: L2 (without proving) | |
| on: | |
| push: | |
| branches: ["main"] | |
| merge_group: | |
| pull_request: | |
| branches: ["**"] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| actions: write | |
| packages: write | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| env: | |
| DOCKER_ETHREX_WORKDIR: /usr/local/bin | |
| # Work around frequent libgit2/submodule fetch flakiness in CI. | |
| CARGO_NET_GIT_FETCH_WITH_CLI: "true" | |
| CARGO_NET_RETRY: "10" | |
| jobs: | |
| detect-changes: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| run_tests: ${{ steps.finish.outputs.run_tests }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: dorny/paths-filter@v4 | |
| id: filter | |
| with: | |
| filters: | | |
| run_tests: | |
| - "crates/l2/**" | |
| - "test/tests/l2/**" | |
| - "fixtures/keys/**" | |
| - "fixtures/genesis/l1.json" | |
| - "fixtures/genesis/l2.json" | |
| - "fixtures/cache/**" | |
| - "fixtures/blobs/**" | |
| - "fixtures/blockchain/**" | |
| - "fixtures/contracts/**" | |
| - "crates/blockchain/dev/**" | |
| - "crates/vm/levm/**" | |
| - "crates/common/types/block_execution_witness.rs" | |
| - "crates/networking/rpc/debug/execution_witness.rs" | |
| - ".github/workflows/pr-main_l2.yaml" | |
| - "cmd/ethrex/l2/**" | |
| non_docs: | |
| - "!docs/**" | |
| code_changed: | |
| - "**/*.rs" | |
| - "**/*.toml" | |
| - "**/*.lock" | |
| - name: finish | |
| id: finish | |
| run: | | |
| if [[ "${{ steps.filter.outputs.non_docs_count }}" == 0 ]]; then | |
| echo "run_tests=false" >> "$GITHUB_OUTPUT" | |
| elif [[ "${GITHUB_EVENT_NAME}" == "merge_group" ]]; then | |
| # In merge queue, only run lint if code files changed | |
| echo "run_tests=${{ steps.filter.outputs.code_changed }}" >> "$GITHUB_OUTPUT" | |
| elif [[ "${GITHUB_EVENT_NAME}" != "pull_request" ]]; then | |
| echo "run_tests=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "run_tests=${{ steps.filter.outputs.run_tests }}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Print result | |
| run: echo "run_tests=${{ steps.finish.outputs.run_tests }}" | |
| lint: | |
| # "Lint L2" is a required check, don't change the name | |
| name: Lint L2 | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' }} | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v6 | |
| - name: Free Disk Space | |
| uses: ./.github/actions/free-disk | |
| - name: Setup Rust Environment | |
| uses: ./.github/actions/setup-rust | |
| with: | |
| components: rustfmt, clippy | |
| - name: Install RISC0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| uses: ./.github/actions/install-risc0 | |
| - name: Create placeholder SP1 ELF | |
| run: | | |
| mkdir -p crates/guest-program/bin/sp1/out | |
| touch crates/guest-program/bin/sp1/out/riscv32im-succinct-zkvm-elf | |
| - name: Run cargo check | |
| run: cargo check --workspace --features l2,l2-sql | |
| - name: Run cargo clippy | |
| run: | | |
| cargo clippy --workspace --features l2,l2-sql -- -D warnings | |
| make lint | |
| - name: Run cargo fmt | |
| run: | | |
| cargo fmt --all -- --check | |
| validate-blobs: | |
| # Fast validation to catch stale blobs early | |
| # This prevents waiting for state-diff-test to fail | |
| # If this fails, regenerate blobs following: | |
| # - docs/workflows/regenerate-blobs.md (agent workflow) | |
| # - docs/developers/l2/state-reconstruction-blobs.md (step-by-step guide) | |
| name: Validate Blob Fixtures | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' && github.event_name != 'merge_group' }} | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust Environment | |
| uses: ./.github/actions/setup-rust | |
| - name: Validate blobs match genesis | |
| run: | | |
| cd crates/l2 | |
| make validate-blobs | |
| build-docker: | |
| name: Build docker image | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' && github.event_name != 'merge_group' }} | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v6 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Build L1 docker image | |
| uses: ./.github/actions/build-docker | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| dockerhub_username: ${{ vars.DOCKERHUB_USERNAME }} | |
| dockerhub_password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| tags: ethrex:main | |
| variant: l1 | |
| cache_write: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork != true }} | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: ethrex_image | |
| path: /tmp/ethrex_image.tar | |
| # We build the docker image for the l2 usage. It needs to add | |
| # The build args for l2. | |
| build-docker-l2: | |
| name: Build docker image L2 | |
| runs-on: ubuntu-latest | |
| needs: detect-changes | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' && github.event_name != 'merge_group' }} | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v6 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Build L2 docker image | |
| uses: ./.github/actions/build-docker | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| dockerhub_username: ${{ vars.DOCKERHUB_USERNAME }} | |
| dockerhub_password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| tags: ethrex:main-l2 | |
| artifact_path: ethrex_image_l2.tar | |
| build_args: BUILD_FLAGS=--features l2,l2-sql | |
| variant: l2 | |
| cache_write: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork != true }} | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: ethrex_image_l2 | |
| path: /tmp/ethrex_image_l2.tar | |
| uniswap-swap: | |
| name: Uniswap Swap Token Flow | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes] | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' && github.event_name != 'merge_group' }} | |
| timeout-minutes: 60 | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v6 | |
| - name: Free Disk Space | |
| uses: ./.github/actions/free-disk | |
| - name: Setup Rust Environment | |
| uses: ./.github/actions/setup-rust | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: "20" | |
| - name: Install Yarn | |
| run: npm install -g yarn | |
| - name: Install solc | |
| uses: ./.github/actions/install-solc | |
| - name: Install rex | |
| run: | | |
| curl -L https://github.com/lambdaclass/rex/releases/download/v8.0.0/rex-linux-x86_64 -o /tmp/rex | |
| chmod +x /tmp/rex | |
| sudo mv /tmp/rex /usr/local/bin/rex | |
| - name: Build ethrex with L2 features and contracts | |
| env: | |
| COMPILE_CONTRACTS: "true" | |
| run: | | |
| cargo build --release --features "l2,l2-sql" --bin ethrex | |
| - name: Run L2 dev node and Uniswap Swap Token Script | |
| env: | |
| COMPILE_CONTRACTS: "true" | |
| run: | | |
| set -euo pipefail | |
| echo "Starting ethrex L2 dev node (logging to /tmp/ethrex.log)..." | |
| ./target/release/ethrex \ | |
| l2 --dev \ | |
| --osaka-activation-time 1761677592 \ | |
| --no-monitor \ | |
| --log.level debug > /tmp/ethrex.log 2>&1 & | |
| ETHREX_PID=$! | |
| trap 'kill "$ETHREX_PID" 2>/dev/null || true' EXIT | |
| if ! kill -0 "$ETHREX_PID" 2>/dev/null; then | |
| echo "ethrex l2 --dev process exited unexpectedly" | |
| exit 1 | |
| fi | |
| echo "Waiting until rich account 0x0000bd19F707CA481886244bDd20Bd6B8a81bd3e has funds on the L2..." | |
| MAX_BALANCE_TRIES=300 | |
| BALANCE_SLEEP_SECS=2 | |
| balance_wei=0 | |
| balance_output="" | |
| for ((i = 1; i <= MAX_BALANCE_TRIES; i++)); do | |
| if ! balance_output=$(rex balance 0x0000bd19F707CA481886244bDd20Bd6B8a81bd3e http://localhost:1729 2>/dev/null); then | |
| sleep "${BALANCE_SLEEP_SECS}" | |
| continue | |
| fi | |
| balance_wei=$(echo "${balance_output}" | grep -Eo '[0-9]+' | tail -n1 || echo "0") | |
| if [[ "${balance_wei}" =~ ^[0-9]+$ ]] && (( balance_wei > 0 )); then | |
| echo "Detected L2 balance for rich account: ${balance_wei} wei" | |
| break | |
| fi | |
| sleep "${BALANCE_SLEEP_SECS}" | |
| done | |
| if [[ ! "${balance_wei}" =~ ^[0-9]+$ ]] || (( balance_wei == 0 )); then | |
| echo "Timed out waiting for non-zero L2 balance for rich account." | |
| echo "Last rex balance output:" | |
| echo "${balance_output:-'<none>'}" | |
| exit 1 | |
| fi | |
| echo "Cloning ethrex-l2-contracts-kit..." | |
| git clone https://github.com/lambdaclass/ethrex-l2-contracts-kit.git \ | |
| /tmp/ethrex-l2-contracts-kit | |
| cd /tmp/ethrex-l2-contracts-kit | |
| echo "Running Uniswap swap_token script..." | |
| chmod +x examples/uniswap/swap_token | |
| examples/uniswap/swap_token | |
| - name: Dump ethrex logs on failure | |
| if: ${{ failure() }} | |
| run: | | |
| echo "===== ethrex logs (/tmp/ethrex.log) =====" | |
| if [ -f /tmp/ethrex.log ]; then | |
| grep -E "INFO|WARN|ERROR" /tmp/ethrex.log | |
| else | |
| echo "Log file /tmp/ethrex.log not found" | |
| fi | |
| integration-test: | |
| name: Integration Test - ${{ matrix.name }} | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, build-docker, build-docker-l2] | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' && github.event_name != 'merge_group' }} | |
| strategy: | |
| matrix: | |
| include: | |
| - name: "Validium" | |
| validium: true | |
| web3signer: false | |
| based: false | |
| compose_targets: [docker-compose.yaml] | |
| - name: "Vanilla" | |
| validium: false | |
| web3signer: false | |
| based: false | |
| compose_targets: [docker-compose.yaml] | |
| - name: "Vanilla with Web3signer" | |
| validium: false | |
| web3signer: true | |
| based: false | |
| compose_targets: | |
| [docker-compose.yaml, docker-compose-l2-web3signer.yaml] | |
| - name: "Based" | |
| validium: false | |
| web3signer: false | |
| based: true | |
| compose_targets: [docker-compose.yaml] | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust Environment | |
| uses: ./.github/actions/setup-rust | |
| - name: Install solc | |
| uses: ./.github/actions/install-solc | |
| - name: Build prover | |
| run: | | |
| cd crates/l2 | |
| make build-prover-exec | |
| mkdir -p ../guest-program/bin/sp1/out && touch ../guest-program/bin/sp1/out/riscv32im-succinct-zkvm-vk-bn254 && touch ../guest-program/bin/sp1/out/riscv32im-succinct-zkvm-vk-u32 | |
| - name: Build test | |
| run: | | |
| cargo test -p ethrex-test l2:: --no-run --release | |
| - name: Start Web3Signer | |
| if: matrix.web3signer | |
| run: | | |
| cd crates/l2 | |
| docker compose -f ${{ join(matrix.compose_targets, ' -f ') }} up --detach web3signer | |
| - name: Download ethrex image artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: ethrex_image | |
| path: /tmp | |
| - name: Load ethrex image | |
| run: | | |
| docker load --input /tmp/ethrex_image.tar | |
| - name: Download ethrex L2 image artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: ethrex_image_l2 | |
| path: /tmp | |
| - name: Load ethrex L2 image | |
| run: | | |
| docker load --input /tmp/ethrex_image_l2.tar | |
| - name: Start L1 | |
| run: | | |
| cd crates/l2 | |
| ETHREX_LOG_LEVEL=debug docker compose up --detach ethrex_l1 | |
| - name: Install rex | |
| run: | | |
| curl -L https://github.com/lambdaclass/rex/releases/download/v8.0.0/rex-linux-x86_64 -o /tmp/rex | |
| chmod +x /tmp/rex | |
| sudo mv /tmp/rex /usr/local/bin/rex | |
| - name: Deploy contracts | |
| run: | | |
| # | |
| # If this job fails due to connection refused to ethrex_l1 consider increasing the failure retries | |
| # in the contract_deployer service in crates/l2/docker-compose.yaml | |
| # | |
| touch cmd/.env | |
| cd crates/l2 | |
| if [ "${{ matrix.based }}" = true ]; then | |
| export ETHREX_DEPLOYER_DEPLOY_BASED_CONTRACTS=true | |
| export COMPILE_CONTRACTS=true | |
| fi | |
| DOCKER_ETHREX_WORKDIR=/usr/local/bin \ | |
| ETHREX_DEPLOYER_DEPLOY_RICH=true \ | |
| ETHREX_L2_VALIDIUM=${{ matrix.validium }} \ | |
| docker compose up contract_deployer | |
| DEPLOYER_EXIT_CODE=$(docker inspect -f '{{.State.ExitCode}}' contract_deployer) | |
| if [ "$DEPLOYER_EXIT_CODE" != "0" ]; then | |
| echo "If this job fails due to connection refused to ethrex_l1 consider increasing the failure retries in the contract_deployer service in crates/l2/docker-compose.yaml" | |
| docker logs contract_deployer | |
| exit 1 | |
| fi | |
| - name: Copy env to host | |
| run: | | |
| docker cp contract_deployer:/env/.env cmd/.env | |
| cat cmd/.env | |
| - name: Register sequencer | |
| if: matrix.based | |
| run: | | |
| cd cmd | |
| SEQUENCER_REGISTRY=$(grep ETHREX_DEPLOYER_SEQUENCER_REGISTRY .env | cut -d= -f2) | |
| export SEQUENCER_REGISTRY | |
| if [ -z "$SEQUENCER_REGISTRY" ]; then | |
| echo "Failed to get SEQUENCER_REGISTRY from .env file" | |
| exit 1 | |
| fi | |
| rex send "$SEQUENCER_REGISTRY" "register(address)" 0x3d1e15a1a55578f7c920884a9943b3b35d0d885b --value 1000000000000000000 -k 0x385c546456b6a603a1cfcaa9ec9494ba4832da08dd6bcf4de9a71e4a01b74924 | |
| rex call "$SEQUENCER_REGISTRY" "leaderSequencer()" | |
| - name: Start Sequencer | |
| run: | | |
| if [ "${{ matrix.based }}" = true ]; then | |
| cd cmd | |
| ETHREX_STATE_UPDATER_SEQUENCER_REGISTRY=$(grep ETHREX_DEPLOYER_SEQUENCER_REGISTRY .env | cut -d= -f2) | |
| export ETHREX_STATE_UPDATER_SEQUENCER_REGISTRY | |
| export ETHREX_BASED=true | |
| cd .. | |
| else | |
| export ETHREX_BLOCK_PRODUCER_BASE_FEE_VAULT_ADDRESS=0x000c0d6b7c4516a5b274c51ea331a9410fe69127 | |
| export ETHREX_BLOCK_PRODUCER_OPERATOR_FEE_VAULT_ADDRESS=0xd5d2a85751b6F158e5b9B8cD509206A865672362 | |
| export ETHREX_BLOCK_PRODUCER_OPERATOR_FEE_PER_GAS=1000000000 | |
| export ETHREX_BLOCK_PRODUCER_L1_FEE_VAULT_ADDRESS=0x45681AE1768a8936FB87aB11453B4755e322ceec | |
| fi | |
| cd crates/l2 | |
| DOCKER_ETHREX_WORKDIR=/usr/local/bin \ | |
| ETHREX_L2_VALIDIUM=${{ matrix.validium }} \ | |
| ETHREX_WATCHER_BLOCK_DELAY=0 \ | |
| ETHREX_COMMITTER_COMMIT_TIME=15000 \ | |
| ETHREX_WATCHER_WATCH_INTERVAL=1000 \ | |
| ETHREX_LOG_LEVEL=debug \ | |
| docker compose -f ${{ join(matrix.compose_targets, ' -f ') }} up --detach --no-deps ethrex_l2 | |
| - name: Wait for L2 deposits to be processed | |
| run: | | |
| # Wait until test account deposits are processed on L2 | |
| # Get the first test account private key (last line, since tests use pop()) | |
| FIRST_TEST_PK=$(tail -n1 fixtures/keys/private_keys_tests.txt) | |
| RICH_ADDRESS=$(rex address --from-private-key "$FIRST_TEST_PK") | |
| echo "Waiting for test account $RICH_ADDRESS deposits to be processed on L2..." | |
| MAX_TRIES=300 | |
| SLEEP_SECS=2 | |
| for i in $(seq 1 $MAX_TRIES); do | |
| echo "Checking L2 balance... (attempt $i)" | |
| if balance_output=$(rex balance "$RICH_ADDRESS" http://localhost:1729 2>/dev/null); then | |
| balance_wei=$(echo "${balance_output}" | grep -Eo '[0-9]+' | tail -n1 || echo "0") | |
| if [[ "${balance_wei}" =~ ^[0-9]+$ ]] && (( balance_wei > 0 )); then | |
| echo "Rich account has balance on L2: ${balance_wei} wei" | |
| exit 0 | |
| fi | |
| fi | |
| sleep "${SLEEP_SECS}" | |
| done | |
| echo "Timed out waiting for L2 deposits to be processed" | |
| exit 1 | |
| - name: Run test | |
| run: | | |
| sudo chmod -R a+rw crates/l2 | |
| cd crates/l2 | |
| RUST_LOG=info,ethrex_l2_prover=debug make init-prover-exec & | |
| docker logs --follow ethrex_l2 | grep -E "INFO|WARN|ERROR" & | |
| docker logs --follow ethrex_l1 | grep -E "INFO|WARN|ERROR" & | |
| PROPOSER_COINBASE_ADDRESS=0x0007a881CD95B1484fca47615B64803dad620C8d cargo test -p ethrex-test l2_integration_test --release --features l2 -- --nocapture --test-threads=1 | |
| killall ethrex -s SIGINT | |
| integration-test-tdx: | |
| name: Integration Test - TDX | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, build-docker, build-docker-l2] | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' && github.event_name != 'merge_group' }} | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v6 | |
| - name: Free Disk Space | |
| uses: ./.github/actions/free-disk | |
| - name: Setup Rust Environment | |
| uses: ./.github/actions/setup-rust | |
| - name: Install solc | |
| uses: ./.github/actions/install-solc | |
| - name: Download ethrex image artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: ethrex_image | |
| path: /tmp | |
| - name: Load ethrex image | |
| run: | | |
| docker load --input /tmp/ethrex_image.tar | |
| - name: Download ethrex L2 image artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: ethrex_image_l2 | |
| path: /tmp | |
| - name: Load ethrex L2 image | |
| run: | | |
| docker load --input /tmp/ethrex_image_l2.tar | |
| - name: Set up Nix | |
| uses: cachix/install-nix-action@v31 | |
| with: | |
| # crates.io 403s any User-Agent containing "curl/", which is what Nix's | |
| # fetchurl sends by default, breaking crate downloads during the image | |
| # build. In multi-user (daemon) mode the FOD builds run under the | |
| # nix-daemon and don't see the caller's environment, so override the | |
| # User-Agent via impure-env (honored because the runner is a trusted | |
| # user). Use curl's glued short option `-A<value>`: a single space-free | |
| # token that survives impure-env's space-separated parsing and | |
| # fetchurl's unquoted word-split (curl rejects the --user-agent=value form). | |
| extra_nix_config: | | |
| extra-experimental-features = configurable-impure-env | |
| impure-env = NIX_CURL_FLAGS=-Aethrex-ci+https://github.com/lambdaclass/ethrex | |
| - name: Set up QEMU | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y qemu-system-x86 qemu-utils | |
| - name: Install rex | |
| # NOTE: TDX deployment uses automata-on-chain-pccs which has rex commands | |
| # with old CLI syntax (positional args). Updating to rex v8.0.0 requires | |
| # updating that repo first: https://github.com/lambdaclass/automata-on-chain-pccs | |
| run: | | |
| cd /tmp | |
| git clone https://github.com/lambdaclass/rex | |
| cd rex | |
| git checkout 18466ec1c3dbcbbf22a68fc1f850d660cb2fbf1f | |
| cargo build --release | |
| cp target/release/rex /usr/local/bin | |
| - name: Build prover | |
| run: | | |
| sudo sysctl kernel.unprivileged_userns_apparmor_policy=0 | |
| sudo sysctl kernel.apparmor_restrict_unprivileged_userns=0 | |
| cd crates/l2/tee/quote-gen | |
| make image.raw || { echo "if fails run in the root of the project: make update-cargo-lock"; exit 1; } | |
| - name: Start L1 & Deploy contracts | |
| run: | | |
| touch cmd/.env | |
| cd crates/l2 | |
| make init-l1-docker; | |
| ETHREX_DEPLOYER_DEPLOY_RICH=true \ | |
| ETHREX_L2_TDX=true \ | |
| ETHREX_TDX_DEV_MODE=true \ | |
| make deploy-l1 | |
| - name: Start Sequencer | |
| run: | | |
| cd crates/l2 | |
| ETHREX_WATCHER_BLOCK_DELAY=0 \ | |
| ETHREX_WATCHER_WATCH_INTERVAL=1000 \ | |
| DOCKER_ETHREX_WORKDIR=/usr/local/bin \ | |
| ETHREX_COMMITTER_COMMIT_TIME=15000 \ | |
| ETHREX_BLOCK_PRODUCER_BASE_FEE_VAULT_ADDRESS=0x000c0d6b7c4516a5b274c51ea331a9410fe69127 \ | |
| ETHREX_BLOCK_PRODUCER_OPERATOR_FEE_VAULT_ADDRESS=0xd5d2a85751b6F158e5b9B8cD509206A865672362 \ | |
| ETHREX_BLOCK_PRODUCER_OPERATOR_FEE_PER_GAS=1000000000 \ | |
| ETHREX_BLOCK_PRODUCER_L1_FEE_VAULT_ADDRESS=0x45681AE1768a8936FB87aB11453B4755e322ceec \ | |
| ETHREX_PROOF_COORDINATOR_ADDRESS=0.0.0.0 \ | |
| ETHREX_LOG_LEVEL=debug \ | |
| docker compose -f docker-compose.yaml -f docker-compose-l2-tdx.yaml up --detach --no-deps ethrex_l2 | |
| - name: Wait for L2 deposits to be processed | |
| run: | | |
| # Wait until test account deposits are processed on L2 | |
| # Get the first test account private key (last line, since tests use pop()) | |
| FIRST_TEST_PK=$(tail -n1 fixtures/keys/private_keys_tests.txt) | |
| RICH_ADDRESS=$(rex address --from-private-key "$FIRST_TEST_PK") | |
| echo "Waiting for test account $RICH_ADDRESS deposits to be processed on L2..." | |
| MAX_TRIES=300 | |
| SLEEP_SECS=2 | |
| for i in $(seq 1 $MAX_TRIES); do | |
| echo "Checking L2 balance... (attempt $i)" | |
| if balance_output=$(rex balance "$RICH_ADDRESS" http://localhost:1729 2>/dev/null); then | |
| balance_wei=$(echo "${balance_output}" | grep -Eo '[0-9]+' | tail -n1 || echo "0") | |
| if [[ "${balance_wei}" =~ ^[0-9]+$ ]] && (( balance_wei > 0 )); then | |
| echo "Rich account has balance on L2: ${balance_wei} wei" | |
| exit 0 | |
| fi | |
| fi | |
| sleep "${SLEEP_SECS}" | |
| done | |
| echo "Timed out waiting for L2 deposits to be processed" | |
| exit 1 | |
| - name: Run test | |
| run: | | |
| cd crates/l2/tee/quote-gen/ | |
| qemu-system-x86_64 \ | |
| -daemonize \ | |
| -serial file:tdx_prover.log \ | |
| -name guest=ethrex_tdx_prover \ | |
| -machine q35,kernel_irqchip=split,hpet=off -smp 2 -m 2G \ | |
| -accel kvm -cpu host -nographic -nodefaults \ | |
| -bios OVMF.fd \ | |
| -no-user-config \ | |
| -netdev user,id=net0,net=192.168.76.0/24 -device e1000,netdev=net0 \ | |
| -device ide-hd,bus=ide.0,drive=main,bootindex=0 -drive "if=none,media=disk,id=main,file.filename=./image.raw,discard=unmap,detect-zeroes=unmap" | |
| tail -f tdx_prover.log & | |
| cd ../../ | |
| docker logs --follow ethrex_l2 | grep -E "INFO|WARN|ERROR" & | |
| PROPOSER_COINBASE_ADDRESS=0x0007a881CD95B1484fca47615B64803dad620C8d cargo test -p ethrex-test l2_integration_test --release --features l2 -- --nocapture --test-threads=1 | |
| pkill -9 -f ethrex_tdx_prover | |
| state-diff-test: | |
| # If this test fails due to stale blobs, regenerate them following: | |
| # - docs/workflows/regenerate-blobs.md (agent workflow) | |
| # - docs/developers/l2/state-reconstruction-blobs.md (step-by-step guide) | |
| name: State Reconstruction Tests | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, build-docker, build-docker-l2, validate-blobs] | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' && github.event_name != 'merge_group' }} | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust Environment | |
| uses: ./.github/actions/setup-rust | |
| - name: Download ethrex image artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: ethrex_image | |
| path: /tmp | |
| - name: Load ethrex image | |
| run: | | |
| docker load --input /tmp/ethrex_image.tar | |
| - name: Download ethrex L2 image artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: ethrex_image_l2 | |
| path: /tmp | |
| - name: Load ethrex L2 image | |
| run: | | |
| docker load --input /tmp/ethrex_image_l2.tar | |
| - name: Install solc | |
| uses: ./.github/actions/install-solc | |
| - name: Start L1 & Deploy contracts | |
| run: | | |
| # | |
| # If this job fails due to connection refused to ethrex_l1 consider increasing the failure retries | |
| # in the contract_deployer service in crates/l2/docker-compose.yaml | |
| # | |
| touch cmd/.env | |
| cd crates/l2 | |
| DOCKER_ETHREX_WORKDIR=/usr/local/bin \ | |
| ETHREX_DEPLOYER_DEPLOY_RICH=true \ | |
| COMPILE_CONTRACTS=true \ | |
| docker compose up contract_deployer | |
| DEPLOYER_EXIT_CODE=$(docker inspect -f '{{.State.ExitCode}}' contract_deployer) | |
| if [ "$DEPLOYER_EXIT_CODE" != "0" ]; then | |
| echo "If this job fails due to connection refused to ethrex_l1 consider increasing the failure retries in the contract_deployer service in crates/l2/docker-compose.yaml" | |
| docker logs contract_deployer | |
| exit 1 | |
| fi | |
| - name: Run tests | |
| run: | | |
| cd crates/l2 | |
| make state-diff-test | |
| integration-test-shared-bridge: | |
| name: Integration Test Shared Bridge - ${{ matrix.name }} | |
| runs-on: ubuntu-latest | |
| needs: [detect-changes, build-docker, build-docker-l2] | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' && github.event_name != 'merge_group' }} | |
| strategy: | |
| matrix: | |
| include: | |
| - name: "Normal" | |
| forced_inclusion: false | |
| - name: "Forced Inclusion" | |
| forced_inclusion: true | |
| steps: | |
| - name: Checkout sources | |
| uses: actions/checkout@v6 | |
| - name: Setup Rust Environment | |
| uses: ./.github/actions/setup-rust | |
| - name: Install solc | |
| uses: ./.github/actions/install-solc | |
| - name: Install rex | |
| run: | | |
| curl -L https://github.com/lambdaclass/rex/releases/download/v8.0.0/rex-linux-x86_64 -o /tmp/rex | |
| chmod +x /tmp/rex | |
| sudo mv /tmp/rex /usr/local/bin/rex | |
| - name: Build prover | |
| run: | | |
| cd crates/l2 | |
| make build-prover-exec | |
| mkdir -p ../guest-program/bin/sp1/out && touch ../guest-program/bin/sp1/out/riscv32im-succinct-zkvm-vk-bn254 && touch ../guest-program/bin/sp1/out/riscv32im-succinct-zkvm-vk-u32 | |
| - name: Build test | |
| run: | | |
| cargo test -p ethrex-test l2:: --no-run --release | |
| - name: Download ethrex image artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: ethrex_image | |
| path: /tmp | |
| - name: Load ethrex image | |
| run: | | |
| docker load --input /tmp/ethrex_image.tar | |
| - name: Download ethrex L2 image artifact | |
| uses: actions/download-artifact@v6 | |
| with: | |
| name: ethrex_image_l2 | |
| path: /tmp | |
| - name: Load ethrex L2 image | |
| run: | | |
| docker load --input /tmp/ethrex_image_l2.tar | |
| - name: Start L1 | |
| run: | | |
| cd crates/l2 | |
| ETHREX_LOG_LEVEL=debug docker compose up --detach ethrex_l1 | |
| - name: Deploy contracts L2A | |
| run: | | |
| # | |
| # If this job fails due to connection refused to ethrex_l1 consider increasing the failure retries | |
| # in the contract_deployer service in crates/l2/docker-compose.yaml | |
| # | |
| touch cmd/.env | |
| cd crates/l2 | |
| if [ "${{ matrix.forced_inclusion }}" = true ]; then | |
| # We set the inclusion max wait to 0 to force expired messages | |
| export ETHREX_ON_CHAIN_PROPOSER_INCLUSION_MAX_WAIT=0 | |
| fi | |
| DOCKER_ETHREX_WORKDIR=/usr/local/bin \ | |
| ETHREX_DEPLOYER_DEPLOY_RICH=true \ | |
| ETHREX_SHARED_BRIDGE_DEPLOY_ROUTER=true \ | |
| docker compose up contract_deployer | |
| DEPLOYER_EXIT_CODE=$(docker inspect -f '{{.State.ExitCode}}' contract_deployer) | |
| if [ "$DEPLOYER_EXIT_CODE" != "0" ]; then | |
| echo "If this job fails due to connection refused to ethrex_l1 consider increasing the failure retries in the contract_deployer service in crates/l2/docker-compose.yaml" | |
| docker logs contract_deployer | |
| exit 1 | |
| fi | |
| - name: Copy env to host | |
| run: | | |
| docker cp contract_deployer:/env/.env cmd/.env_l2a | |
| cat cmd/.env_l2a | |
| - name: Deploy contracts L2B | |
| run: | | |
| jq '.config.chainId = 1730' fixtures/genesis/l2.json > fixtures/genesis/l2b.json | |
| # | |
| # If this job fails due to connection refused to ethrex_l1 consider increasing the failure retries | |
| # in the contract_deployer service in crates/l2/docker-compose.yaml | |
| # | |
| touch cmd/.env | |
| cd crates/l2 | |
| export $(grep -v '^#' ../../cmd/.env_l2a | xargs) | |
| DOCKER_ETHREX_WORKDIR=/usr/local/bin \ | |
| ETHREX_DEPLOYER_DEPLOY_RICH=true \ | |
| ETHREX_SHARED_BRIDGE_ROUTER_ADDRESS=$ETHREX_SHARED_BRIDGE_ROUTER_ADDRESS \ | |
| docker compose -f docker-compose.yaml -f docker-compose-l2-shared-bridge.overrides.yaml up contract_deployer | |
| DEPLOYER_EXIT_CODE=$(docker inspect -f '{{.State.ExitCode}}' contract_deployer) | |
| if [ "$DEPLOYER_EXIT_CODE" != "0" ]; then | |
| echo "If this job fails due to connection refused to ethrex_l1 consider increasing the failure retries in the contract_deployer service in crates/l2/docker-compose.yaml" | |
| docker logs contract_deployer | |
| exit 1 | |
| fi | |
| - name: Copy env to host | |
| run: | | |
| docker cp contract_deployer:/env/.env cmd/.env_l2b | |
| cat cmd/.env_l2b | |
| - name: Start Sequencer L2A | |
| run: | | |
| cp cmd/.env_l2a cmd/.env | |
| export ETHREX_BLOCK_PRODUCER_BASE_FEE_VAULT_ADDRESS=0x000c0d6b7c4516a5b274c51ea331a9410fe69127 | |
| export ETHREX_BLOCK_PRODUCER_OPERATOR_FEE_VAULT_ADDRESS=0xd5d2a85751b6F158e5b9B8cD509206A865672362 | |
| export ETHREX_BLOCK_PRODUCER_OPERATOR_FEE_PER_GAS=1000000000 | |
| export ETHREX_BLOCK_PRODUCER_L1_FEE_VAULT_ADDRESS=0x45681AE1768a8936FB87aB11453B4755e322ceec | |
| if [ "${{ matrix.forced_inclusion }}" = false ]; then | |
| # In forced_inclusion, we ommit these variables to avoid including messages from L2B into L2A | |
| export ETHREX_WATCHER_L2_RPCS=http://ethrex_l2_b:1730 | |
| export ETHREX_WATCHER_L2_CHAIN_IDS=1730 | |
| fi | |
| cd crates/l2 | |
| export $(xargs < ../../cmd/.env_l2a) | |
| DOCKER_ETHREX_WORKDIR=/usr/local/bin \ | |
| ETHREX_WATCHER_BLOCK_DELAY=0 \ | |
| ETHREX_COMMITTER_COMMIT_TIME=15000 \ | |
| ETHREX_WATCHER_WATCH_INTERVAL=1000 \ | |
| ETHREX_LOG_LEVEL=debug \ | |
| ETHREX_WATCHER_ROUTER_ADDRESS=$ETHREX_SHARED_BRIDGE_ROUTER_ADDRESS \ | |
| docker compose -f docker-compose.yaml up --detach --no-deps ethrex_l2 | |
| - name: Start Sequencer L2B | |
| run: | | |
| cp cmd/.env_l2b cmd/.env | |
| export ETHREX_BLOCK_PRODUCER_BASE_FEE_VAULT_ADDRESS=0x000c0d6b7c4516a5b274c51ea331a9410fe69127 | |
| export ETHREX_BLOCK_PRODUCER_OPERATOR_FEE_VAULT_ADDRESS=0xd5d2a85751b6F158e5b9B8cD509206A865672362 | |
| export ETHREX_BLOCK_PRODUCER_OPERATOR_FEE_PER_GAS=1000000000 | |
| export ETHREX_BLOCK_PRODUCER_L1_FEE_VAULT_ADDRESS=0x45681AE1768a8936FB87aB11453B4755e322ceec | |
| cd crates/l2 | |
| export $(xargs < ../../cmd/.env_l2b) | |
| DOCKER_ETHREX_WORKDIR=/usr/local/bin \ | |
| ETHREX_WATCHER_BLOCK_DELAY=0 \ | |
| ETHREX_COMMITTER_COMMIT_TIME=15000 \ | |
| ETHREX_WATCHER_WATCH_INTERVAL=1000 \ | |
| ETHREX_WATCHER_L2_RPCS=http://ethrex_l2:1729 \ | |
| ETHREX_WATCHER_L2_CHAIN_IDS=65536999 \ | |
| ETHREX_LOG_LEVEL=debug \ | |
| ETHREX_WATCHER_ROUTER_ADDRESS=$ETHREX_SHARED_BRIDGE_ROUTER_ADDRESS \ | |
| docker compose -f docker-compose.yaml -f docker-compose-l2-shared-bridge.overrides.yaml up --detach --no-deps ethrex_l2_b | |
| - name: Wait for L2A deposits to be processed | |
| run: | | |
| # Wait until shared_bridge test account deposits are processed on L2A | |
| # This address is hardcoded in test/tests/l2/shared_bridge.rs (SENDER_ADDRESS) | |
| SENDER_ADDRESS="0x000130bade00212be1aa2f4acfe965934635c9cd" | |
| echo "Waiting for shared_bridge test account $SENDER_ADDRESS deposits to be processed on L2A..." | |
| MAX_TRIES=300 | |
| SLEEP_SECS=2 | |
| for i in $(seq 1 $MAX_TRIES); do | |
| echo "Checking L2A balance... (attempt $i)" | |
| if balance_output=$(rex balance "$SENDER_ADDRESS" http://localhost:1729 2>/dev/null); then | |
| balance_wei=$(echo "${balance_output}" | grep -Eo '[0-9]+' | tail -n1 || echo "0") | |
| if [[ "${balance_wei}" =~ ^[0-9]+$ ]] && (( balance_wei > 0 )); then | |
| echo "Shared bridge test account has balance on L2A: ${balance_wei} wei" | |
| exit 0 | |
| fi | |
| fi | |
| sleep "${SLEEP_SECS}" | |
| done | |
| echo "Timed out waiting for L2A deposits to be processed" | |
| exit 1 | |
| - name: Wait for L2B deposits to be processed | |
| run: | | |
| # Wait until shared_bridge test account deposits are processed on L2B | |
| # This address is hardcoded in test/tests/l2/shared_bridge.rs (SENDER_ADDRESS) | |
| SENDER_ADDRESS="0x000130bade00212be1aa2f4acfe965934635c9cd" | |
| echo "Waiting for shared_bridge test account $SENDER_ADDRESS deposits to be processed on L2B..." | |
| MAX_TRIES=300 | |
| SLEEP_SECS=2 | |
| for i in $(seq 1 $MAX_TRIES); do | |
| echo "Checking L2B balance... (attempt $i)" | |
| if balance_output=$(rex balance "$SENDER_ADDRESS" http://localhost:1730 2>/dev/null); then | |
| balance_wei=$(echo "${balance_output}" | grep -Eo '[0-9]+' | tail -n1 || echo "0") | |
| if [[ "${balance_wei}" =~ ^[0-9]+$ ]] && (( balance_wei > 0 )); then | |
| echo "Shared bridge test account has balance on L2B: ${balance_wei} wei" | |
| exit 0 | |
| fi | |
| fi | |
| sleep "${SLEEP_SECS}" | |
| done | |
| echo "Timed out waiting for L2B deposits to be processed" | |
| exit 1 | |
| - name: Run Shared Bridge Tests | |
| if: matrix.forced_inclusion == false | |
| run: | | |
| sudo chmod -R a+rw crates/l2 | |
| cd crates/l2 | |
| cargo run --release --features "l2,l2-sql" --manifest-path ../../Cargo.toml -- \ | |
| l2 prover \ | |
| --proof-coordinators tcp://127.0.0.1:3900 tcp://127.0.0.1:3901 \ | |
| --backend exec & | |
| docker logs --follow ethrex_l2 | grep -E "INFO|WARN|ERROR" & | |
| docker logs --follow ethrex_l2_b | grep -E "INFO|WARN|ERROR" & | |
| docker logs --follow ethrex_l1 | grep -E "INFO|WARN|ERROR" & | |
| cp ../../cmd/.env_l2a ../../cmd/.env | |
| export $(xargs < ../../cmd/.env_l2a) | |
| cargo test -p ethrex-test test_shared_bridge --release --features l2 -- --nocapture --test-threads=1 | |
| PROPOSER_COINBASE_ADDRESS=0x0007a881CD95B1484fca47615B64803dad620C8d INTEGRATION_TEST_SKIP_TEST_TOTAL_ETH=true cargo test -p ethrex-test l2_integration_test --release --features l2 -- --nocapture --test-threads=1 | |
| cp ../../cmd/.env_l2b ../../cmd/.env | |
| export $(xargs < ../../cmd/.env_l2b) | |
| PROPOSER_COINBASE_ADDRESS=0x0007a881CD95B1484fca47615B64803dad620C8d INTEGRATION_TEST_SKIP_TEST_TOTAL_ETH=true INTEGRATION_TEST_L2_RPC=http://localhost:1730 cargo test -p ethrex-test l2_integration_test --release --features l2 -- --nocapture --test-threads=1 | |
| cp ../../cmd/.env_l2a ../../cmd/.env | |
| export $(xargs < ../../cmd/.env_l2a) | |
| cargo test -p ethrex-test test_shared_bridge --release --features l2 -- --nocapture --test-threads=1 | |
| killall ethrex -s SIGINT | |
| - name: Run Forced Inclusion Test | |
| if: matrix.forced_inclusion | |
| run: | | |
| sudo chmod -R a+rw crates/l2 | |
| cd crates/l2 | |
| cargo run --release --features "l2,l2-sql" --manifest-path ../../Cargo.toml -- \ | |
| l2 prover \ | |
| --proof-coordinators tcp://127.0.0.1:3900 tcp://127.0.0.1:3901 \ | |
| --backend exec & | |
| docker logs --follow ethrex_l2 | grep -E "INFO|WARN|ERROR" & | |
| docker logs --follow ethrex_l2_b | grep -E "INFO|WARN|ERROR" & | |
| docker logs --follow ethrex_l1 | grep -E "INFO|WARN|ERROR" & | |
| cp ../../cmd/.env_l2a ../../cmd/.env | |
| cargo test -p ethrex-test forced_inclusion --release --features l2 -- --nocapture --test-threads=1 | |
| killall ethrex -s SIGINT | |
| # The purpose of this job is to add it as a required check in GitHub so that we don't have to add every individual job as a required check | |
| all-tests: | |
| # "Integration Test L2" is a required check, don't change the name | |
| name: Integration Test L2 | |
| runs-on: ubuntu-latest | |
| needs: | |
| [ | |
| detect-changes, | |
| integration-test, | |
| state-diff-test, | |
| integration-test-tdx, | |
| uniswap-swap, | |
| integration-test-shared-bridge, | |
| ] | |
| # Make sure this job runs even if the previous jobs failed or were skipped | |
| if: ${{ needs.detect-changes.outputs.run_tests == 'true' && always() && needs.integration-test.result != 'skipped' && needs.state-diff-test.result != 'skipped' && needs.integration-test-tdx.result != 'skipped' && needs.uniswap-swap.result != 'skipped' && needs.integration-test-shared-bridge.result != 'skipped' }} | |
| steps: | |
| - name: Check if any job failed | |
| run: | | |
| if [ "${{ needs.integration-test.result }}" != "success" ]; then | |
| echo "Job Integration Tests failed" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.state-diff-test.result }}" != "success" ]; then | |
| echo "Job State Reconstruction Tests failed" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.uniswap-swap.result }}" != "success" ]; then | |
| echo "Job Uniswap Swap Token Flow failed" | |
| exit 1 | |
| fi | |
| if [ "${{ needs.integration-test-shared-bridge.result }}" != "success" ]; then | |
| echo "Job Integration test shared bridge failed" | |
| exit 1 | |
| fi |