L2 integration tests with a SP1 GPU prover
This validates a release’s SP1 GPU proving path end to end: bring up an L1 + L2 testnet from the release binaries with the SP1 GPU prover, then run the integration test against it. Run it on a host with an NVIDIA GPU (l2-gpu). It is one of the checks in the release testing checklist.
Note
The standard integration tests run the prover in
execmode (no real proofs). This variant swaps in the SP1 GPU backend so the release’s proving path is actually exercised. GPU/driver setup (CUDA,nvidia-container-toolkit, thedockergroup) is covered in Prover § GPU mode and Run an ethrex L2 SP1 prover; the SP1 wrap step runs in amoongateDocker container, sodocker run --gpus allmust work.
Host prerequisites: solc 0.8.31 exactly (the FeeToken pragmas are pinned), foundry (cast/forge) on PATH, and the Rust toolchain from rust-toolchain.toml.
-
Download the release artifacts (note: asset names use
x86_64, with an underscore):export TAG=vX.Y.Z-rc.W mkdir -p ~/ethrex_$TAG && cd ~/ethrex_$TAG BASE=https://github.com/lambdaclass/ethrex/releases/download/$TAG curl -sSL -o ethrex "$BASE/ethrex-linux-x86_64" & curl -sSL -o ethrex-l2 "$BASE/ethrex-l2-linux-x86_64-gpu" & curl -sSL -o ethrex-contracts.tar.gz "$BASE/ethrex-contracts.tar.gz" & curl -sSL -o ethrex-guests.tar.gz "$BASE/ethrex-guests.tar.gz" & wait chmod +x ethrex ethrex-l2 mkdir -p contracts && tar xzf ethrex-contracts.tar.gz -C contractsGenesis files and rich-account keys aren’t published as assets — get them from a source checkout at the same tag (the test in step 7 reuses this checkout):
git clone --depth 1 --branch $TAG https://github.com/lambdaclass/ethrex.git ~/ethrex_${TAG}_src cp ~/ethrex_${TAG}_src/fixtures/genesis/l1.json l1.json cp ~/ethrex_${TAG}_src/fixtures/genesis/l2.json l2.json cp ~/ethrex_${TAG}_src/fixtures/keys/private_keys_l1.txt private_keys_l1.txt -
Start L1 (dev mode auto-mines):
nohup ./ethrex --network l1.json \ --http.addr 0.0.0.0 --http.port 8545 \ --authrpc.addr 0.0.0.0 --authrpc.port 8551 \ --dev --datadir dev_ethrex_l1 > l1.log 2>&1 & -
Deploy the L1 contracts with SP1 enabled (
solc/forgemust be onPATH):COMPILE_CONTRACTS=true ./ethrex-l2 l2 deploy \ --eth-rpc-url http://localhost:8545 \ --private-key 0x385c546456b6a603a1cfcaa9ec9494ba4832da08dd6bcf4de9a71e4a01b74924 \ --sp1 true \ --on-chain-proposer-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ --bridge-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ --bridge-owner-pk 0x941e103320615d394a55708be13e45994c7d93b932b064dbcb2b511fe3254e2e \ --deposit-rich \ --private-keys-file-path private_keys_l1.txt \ --genesis-l1-path l1.json --genesis-l2-path l2.json \ --sp1-vk-path contracts/ethrex-riscv32im-succinct-zkvm-vk-bn254 \ --inclusion-max-wait 86400 \ --env-file-path ~/ethrex_${TAG}_src/cmd/.env > deploy.log 2>&1 grep -E "(Timelock|OnChainProposer|CommonBridge|SP1Verifier) deployed" deploy.logWarning
--sp1-vk-pathmust point at the verification key insidecontracts/(contracts/ethrex-riscv32im-succinct-zkvm-vk-bn254), not the similarly namedguests/sp1/...file fromethrex-guests.tar.gz. The wrong file registers a VK the binary’s embedded ELF never produces, andlastVerifiedBatchstays stuck at0whilelastCommittedBatchclimbs.--inclusion-max-wait 86400avoids a privileged-transaction deadlock when the test bursts ~300 transactions.--env-file-pathwrites the deployed addresses to the source checkout’scmd/.env(where the test in step 7 reads them) instead of the default baked-in path, which would otherwise be unwriteable and abort the deploy. The same addresses are also printed todeploy.logfor the sequencer command in step 4. -
Start the L2 sequencer (substitute the addresses from
deploy.log):nohup ./ethrex-l2 l2 --no-monitor \ --watcher.block-delay 0 --network l2.json \ --http.addr 0.0.0.0 --http.port 1729 --metrics --metrics.port 3702 \ --datadir dev_ethrex_l2 \ --l1.bridge-address <BRIDGE_FROM_DEPLOY> \ --l1.on-chain-proposer-address <PROPOSER_FROM_DEPLOY> \ --l1.timelock-address <TIMELOCK_FROM_DEPLOY> \ --eth.rpc-url http://localhost:8545 \ --osaka-activation-time 1761677592 \ --block-producer.coinbase-address 0x0007a881CD95B1484fca47615B64803dad620C8d \ --block-producer.base-fee-vault-address 0x000c0d6b7c4516a5b274c51ea331a9410fe69127 \ --block-producer.operator-fee-vault-address 0xd5d2a85751b6F158e5b9B8cD509206A865672362 \ --block-producer.operator-fee-per-gas 1000000000 \ --committer.l1-private-key 0x385c546456b6a603a1cfcaa9ec9494ba4832da08dd6bcf4de9a71e4a01b74924 \ --proof-coordinator.l1-private-key 0x39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d \ --proof-coordinator.addr 127.0.0.1 \ --log.color never > l2.log 2>&1 &--no-monitoris mandatory when running headless — otherwise the binary starts the monitor TUI and emits no logs. -
Start the SP1 GPU prover (first run pulls the
moongatecontainer and loads ~15 GB into VRAM):nohup ./ethrex-l2 l2 prover --backend sp1 \ --proof-coordinators tcp://127.0.0.1:3900 --log.level info > prover.log 2>&1 & -
Sanity check (after ~3 min both should be non-zero and climbing):
PROP=<PROPOSER_FROM_DEPLOY> cast call $PROP 'lastCommittedBatch()(uint256)' --rpc-url http://localhost:8545 cast call $PROP 'lastVerifiedBatch()(uint256)' --rpc-url http://localhost:8545If
lastVerifiedBatchstays at0whilelastCommittedBatchclimbs, you picked the wrong--sp1-vk-path(see the warning above). -
Run the integration test against the running testnet, from the source checkout cloned in step 1.
The test reads the deployed contract addresses from
cmd/.envin the checkout (ETHREX_WATCHER_BRIDGE_ADDRESSandETHREX_COMMITTER_ON_CHAIN_PROPOSER_ADDRESS) — already written there by the deploy’s--env-file-pathin step 3, so no manual setup is needed:cd ~/ethrex_${TAG}_src INTEGRATION_TEST_L1_RPC=http://localhost:8545 \ INTEGRATION_TEST_L2_RPC=http://localhost:1729 \ ETHREX_DEPLOYER_PRIVATE_KEYS_FILE_PATH=~/ethrex_$TAG/private_keys_l1.txt \ INTEGRATION_TEST_PRIVATE_KEYS_FILE_PATH=~/ethrex_$TAG/private_keys_l1.txt \ INTEGRATION_TEST_BRIDGE_OWNER_PRIVATE_KEY=0x941e103320615d394a55708be13e45994c7d93b932b064dbcb2b511fe3254e2e \ cargo test -p ethrex-test l2::integration_tests --release --features l2 -- --nocapture --test-threads=1Pass criterion:
test result: ok. 1 passed; 0 failed, plus the finalTotal L2 ETH == Bridge locked ETH on L1reconciliation line. Expect a multi-hour run on the GPU backend (proving dominates the wall-clock). See integration tests § “taking too long” if it appears to stall. -
Clean up — the L1, sequencer, and prover were started with
nohupand keep running; stop them (and the prover’s GPU container) when you’re done:pkill -f 'ethrex-l2 l2 prover' # prover first pkill -f 'ethrex-l2 l2 --no-monitor' # sequencer pkill -f 'ethrex --network l1.json' # L1 docker rm -f "$(docker ps -q --filter ancestor=public.ecr.aws/succinct-labs/moongate)" 2>/dev/null || true