From b5a6aa8f50fa0cb64d48055c740aa2ff194e0f96 Mon Sep 17 00:00:00 2001 From: corey Date: Wed, 8 Jul 2026 17:21:18 +0800 Subject: [PATCH] feat: adapt run-morph-node to centralized single-sequencer (integrate #92 + #100) Version matrix: - go-ethereum -> morph-v2.2.4 (0eda191) - morph -> main f96a4775 (single-sequencer network config); its node/go.mod pins github.com/morph-l2/tendermint v0.3.8 (a5de063), so tendermint enters as a build-time dep, not a submodule/service here - docker images: geth 2.2.3 -> 2.2.4, node 0.5.7 -> 0.5.8 (provisional; must point to a morph-main build with --derivation.verify-mode before merge) Single self-verifying node (PR #100): - remove the separate validator docker-compose service; merge its env into the single node and expose DERIVATION_VERIFY_MODE (--derivation.verify-mode: local default / layer1 = former validator behavior) - run-binary.sh drops its node|validator mode arg - keep run-validator* Makefile commands as wrappers that run the SAME node with verify-mode=layer1 (no separate container) Legacy cleanup: - remove ZK legacy: .env_zk, .env_hoodi_zk, entrypoint-geth-zk.sh, all run-zk-* / *-zk-snapshot targets, and the ZK README snapshot tables - .env_hoodi: restore NODE_EXTRA_FLAGS=--hoodi (else node -> network=dev and fails "L1 Sequencer contract address is required") - align env snapshots/heights to README newest MPT (mainnet 20260701-1, hoodi 20260630-1) WIP: node:0.5.8 tag provisional; make build not yet run in this environment. Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 54 +++++++++---------- go-ethereum | 2 +- morph | 2 +- morph-node/.env | 24 +++++++-- morph-node/.env_hoodi | 30 ++++++++--- morph-node/.env_hoodi_zk | 6 --- morph-node/.env_zk | 6 --- morph-node/Makefile | 89 +++++++++----------------------- morph-node/docker-compose.yml | 49 ++++++------------ morph-node/entrypoint-geth-zk.sh | 37 ------------- morph-node/entrypoint-node.sh | 13 ++++- morph-node/run-binary.sh | 23 ++++----- 12 files changed, 131 insertions(+), 204 deletions(-) delete mode 100644 morph-node/.env_hoodi_zk delete mode 100644 morph-node/.env_zk delete mode 100644 morph-node/entrypoint-geth-zk.sh diff --git a/README.md b/README.md index 41c74e3..ece5d05 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ ## Features -- **Dockerized Deployment**: Simplifies the process of setting up Morph validator nodes using Docker containers. +- **Dockerized Deployment**: Simplifies the process of setting up Morph nodes using Docker containers. - **Network Support**: Provides configurations for both Mainnet and Hoodi testnet environments. - **Snapshot Synchronization**: Supports synchronizing node data from snapshots to expedite the setup process. @@ -47,16 +47,6 @@ Before setting up a Morph node, ensure you have the following installed: make download-and-decompress-hoodi-snapshot ``` -- For ZK node (legacy), download the ZK-specific snapshot: - - ```bash - make download-and-decompress-mainnet-zk-snapshot - ``` - or - ```bash - make download-and-decompress-hoodi-zk-snapshot - ``` - - After downloading the snapshot, you need to manually place the decompressed data files in the appropriate node data directories. Alternatively, use the `quickstart-*` targets (e.g. `make quickstart-mainnet-node`) which handle snapshot download and placement automatically. - `make download-and-decompress-*` now extracts snapshots under network directories (`../mainnet` or `../hoodi`). - For example, if the snapshot folder is named `snapshot-20260415-1`, move the directory to the `MORPH_HOME` directories: @@ -92,13 +82,32 @@ Before setting up a Morph node, ensure you have the following installed: make run-hoodi-node ``` -- Both commands default to MPT mode. For ZK legacy nodes, use `make run-zk-node` or `make run-hoodi-zk-node`. - - This command will set up and run the node based on the configurations specified in your .env file. +### Running as a validator (batch verification mode) + +There is no separate validator service anymore — every node self-verifies L1 batches. The +mode is controlled by `DERIVATION_VERIFY_MODE` (`--derivation.verify-mode`) in the env file: + +- `local` (default): rebuild the blob from local L2 blocks and compare versioned hashes + against L1. No beacon fetch on the happy path. +- `layer1`: pull the L1 beacon blob, decode it, and derive via the engine — equivalent to + the former validator node. Requires a working `L1_BEACON_CHAIN_RPC`. + +Convenience targets run the same node in `layer1` mode: + +```bash +make run-validator # mainnet, Docker +make run-hoodi-validator # hoodi, Docker +make run-validator-binary # mainnet, binary +``` + +> `L1_SEQUENCER_CONTRACT` and `CONSENSUS_SWITCH_HEIGHT` are hardcoded per-network defaults +> in the binary and must not be set as operator config. + ## Snapshot Information -The table below provides the node snapshot data and corresponding download URLs. When starting the validator, ensure `DERIVATION_START_HEIGHT`, `L1_MSG_START_HEIGHT`, and `L2_BASE_HEIGHT` match the selected snapshot: use `.env`/`.env_hoodi` for MPT, and `.env_zk`/`.env_hoodi_zk` for ZK legacy. +The table below provides the node snapshot data and corresponding download URLs. Ensure `DERIVATION_START_HEIGHT`, `L1_MSG_START_HEIGHT`, and `L2_BASE_HEIGHT` in `.env`/`.env_hoodi` match the selected snapshot. **For mainnet** (reth is currently in an internal testing phase and is not yet recommended for production use): @@ -127,23 +136,6 @@ The table below provides the node snapshot data and corresponding download URLs. | [snapshot-archive-reth-20260601-1](https://snapshot.morphl2.io/hoodi/snapshot-archive-reth-20260601-1.tar.gz) | 2930601 | 2916614 | 5828361 | | [snapshot-archive-20260531-1](https://snapshot.morphl2.io/hoodi/snapshot-archive-20260531-1.tar.gz) | 2927766 | 2916614 | 5817801 | -**For mainnet ZK node(legacy)**: - -| Snapshot Name | Derivation Start Height | L1 Msg Start Height | L2 Base Height | -|:--------------|:------------------------|:--------------------|:---------------| -| [snapshot-20260316-1](https://snapshot.morphl2.io/mainnet/snapshot-20260316-1.tar.gz) | 24668486 | 24667943 | 21474974 | -| [snapshot-20260304-1](https://snapshot.morphl2.io/mainnet/snapshot-20260304-1.tar.gz) | 24582164 | 24582123 | 21195806 | -| [snapshot-20260210-1](https://snapshot.morphl2.io/mainnet/snapshot-20260210-1.tar.gz) | 24424695 | 24424698 | 20674922 | - -**For hoodi testnet ZK node(legacy)**: - -| Snapshot Name | Derivation Start Height | L1 Msg Start Height | L2 Base Height | -|:--------------|:------------------------|:--------------------|:---------------| -| [snapshot-20260316-1](https://snapshot.morphl2.io/hoodi/snapshot-20260316-1.tar.gz) | 2427831 | 2408746 | 4001145 | -| [snapshot-20260304-1](https://snapshot.morphl2.io/hoodi/snapshot-20260304-1.tar.gz) | 2349111 | 2346416 | 3713448 | -| [snapshot-20260210-1](https://snapshot.morphl2.io/hoodi/snapshot-20260210-1.tar.gz) | 2205636 | 2201288 | 3187147 | - - ## Documentation For detailed information on Morph and its ecosystem, refer to the official documentation: diff --git a/go-ethereum b/go-ethereum index 1d46057..0eda191 160000 --- a/go-ethereum +++ b/go-ethereum @@ -1 +1 @@ -Subproject commit 1d4605778e32dd6dc205e74a97b925149bbe6c88 +Subproject commit 0eda19148ddd2c6d8cf252a242def9f940445a24 diff --git a/morph b/morph index a20bbfa..f96a477 160000 --- a/morph +++ b/morph @@ -1 +1 @@ -Subproject commit a20bbfa25014a20ba229ca0c9621001d6b334b44 +Subproject commit f96a47759a613b0c181e9db205482eee9e6080a4 diff --git a/morph-node/.env b/morph-node/.env index 32f359a..de059b6 100644 --- a/morph-node/.env +++ b/morph-node/.env @@ -2,17 +2,31 @@ MORPH_HOME=../mainnet MORPH_FLAG=morph JWT_SECRET_FILE=${MORPH_HOME}/jwt-secret.txt GETH_ENTRYPOINT_FILE=./entrypoint-geth.sh -MAINNET_SNAPSHOT_NAME=snapshot-20260415-1 +MAINNET_SNAPSHOT_NAME=snapshot-20260701-1 -## Environment variables for validator node +## Environment variables for the node L1_CHAIN_ID=1 L1_ETH_RPC=https://eth.drpc.org +# Beacon RPC is only used when DERIVATION_VERIFY_MODE=layer1 (former validator behavior). L1_BEACON_CHAIN_RPC=https://rpc.ankr.com/eth L1MESSAGEQUEUE_CONTRACT=0x3931ade842f5bb8763164bdd81e5361dce6cc1ef ROLLUP_CONTRACT=0x759894ced0e6af42c26668076ffa84d02e3cef60 -DERIVATION_START_HEIGHT=24883902 -L1_MSG_START_HEIGHT=24883052 -L2_BASE_HEIGHT=22181317 +# Heights match MAINNET_SNAPSHOT_NAME above (see the README snapshot table). +DERIVATION_START_HEIGHT=25440822 +L1_MSG_START_HEIGHT=25439950 +L2_BASE_HEIGHT=24216219 ## Extra flags for node NODE_EXTRA_FLAGS=--mainnet + +## Batch verification mode (--derivation.verify-mode). +## local (default): rebuild the blob from local L2 blocks and compare versioned +## hashes against L1 (no beacon fetch on the happy path). +## layer1: pull the L1 beacon blob, decode it, and derive via the engine — +## equivalent to the former validator node (needs L1_BEACON_CHAIN_RPC). +## Leave empty for the binary default (local). `make run-validator` sets layer1. +DERIVATION_VERIFY_MODE= + +## NOTE: do NOT set L1_SEQUENCER_CONTRACT or CONSENSUS_SWITCH_HEIGHT here. These +## are hardcoded per-network defaults in the binary, not operator config; setting +## them (especially CONSENSUS_SWITCH_HEIGHT=-1) overrides the built-in activation. diff --git a/morph-node/.env_hoodi b/morph-node/.env_hoodi index 480741a..33975dd 100644 --- a/morph-node/.env_hoodi +++ b/morph-node/.env_hoodi @@ -2,15 +2,33 @@ MORPH_HOME=../hoodi MORPH_FLAG=morph-hoodi JWT_SECRET_FILE=${MORPH_HOME}/jwt-secret.txt GETH_ENTRYPOINT_FILE=./entrypoint-geth.sh -## todo snapshot -HOODI_SNAPSHOT_NAME=mpt-snapshot-20260402-1 +HOODI_SNAPSHOT_NAME=snapshot-20260630-1 -## Environment variables for validator node +## Environment variables for the node L1_CHAIN_ID=560048 L1_ETH_RPC=${your_layer1_execution_client_rpc_url} +# Beacon RPC is only used when DERIVATION_VERIFY_MODE=layer1 (former validator behavior). L1_BEACON_CHAIN_RPC=${your_layer1_beacon_client_rpc_url} L1MESSAGEQUEUE_CONTRACT=0xd7f39d837f4790b215ba67e0ab63665912648dbe ROLLUP_CONTRACT=0x57e0e6dde89dc52c01fe785774271504b1e04664 -DERIVATION_START_HEIGHT=2534958 -L1_MSG_START_HEIGHT=2528506 -L2_BASE_HEIGHT=4391571 +# Heights match HOODI_SNAPSHOT_NAME above (see the README snapshot table). +DERIVATION_START_HEIGHT=3122685 +L1_MSG_START_HEIGHT=3106743 +L2_BASE_HEIGHT=6543334 + +## Extra flags for morphnode. --hoodi selects the Hoodi network so the node picks +## up the built-in Hoodi L1 sequencer contract address; without it the node +## defaults to network=dev and fails with "L1 Sequencer contract address is required". +NODE_EXTRA_FLAGS=--hoodi + +## Batch verification mode (--derivation.verify-mode). +## local (default): rebuild the blob from local L2 blocks and compare versioned +## hashes against L1 (no beacon fetch on the happy path). +## layer1: pull the L1 beacon blob, decode it, and derive via the engine — +## equivalent to the former validator node (needs L1_BEACON_CHAIN_RPC). +## Leave empty for the binary default (local). `make run-hoodi-validator` sets layer1. +DERIVATION_VERIFY_MODE= + +## NOTE: do NOT set L1_SEQUENCER_CONTRACT or CONSENSUS_SWITCH_HEIGHT here. These +## are hardcoded per-network defaults in the binary, not operator config; setting +## them (especially CONSENSUS_SWITCH_HEIGHT=-1) overrides the built-in activation. diff --git a/morph-node/.env_hoodi_zk b/morph-node/.env_hoodi_zk deleted file mode 100644 index 78404af..0000000 --- a/morph-node/.env_hoodi_zk +++ /dev/null @@ -1,6 +0,0 @@ -# ZK (legacy) override - load after .env_hoodi to switch back to ZK mode -GETH_ENTRYPOINT_FILE=./entrypoint-geth-zk.sh -HOODI_ZK_SNAPSHOT_NAME=snapshot-20260316-1 -DERIVATION_START_HEIGHT=2427831 -L1_MSG_START_HEIGHT=2408746 -L2_BASE_HEIGHT=4001145 diff --git a/morph-node/.env_zk b/morph-node/.env_zk deleted file mode 100644 index 273a3ad..0000000 --- a/morph-node/.env_zk +++ /dev/null @@ -1,6 +0,0 @@ -# ZK (legacy) override - load after .env to switch back to ZK mode -GETH_ENTRYPOINT_FILE=./entrypoint-geth-zk.sh -MAINNET_ZK_SNAPSHOT_NAME=snapshot-20260316-1 -DERIVATION_START_HEIGHT=24668486 -L1_MSG_START_HEIGHT=24667943 -L2_BASE_HEIGHT=21474974 diff --git a/morph-node/Makefile b/morph-node/Makefile index 55d5333..af98c9b 100644 --- a/morph-node/Makefile +++ b/morph-node/Makefile @@ -7,10 +7,6 @@ include .env_hoodi JWT_SECRET_FILE_HOODI := $(JWT_SECRET_FILE) -# Load ZK-specific snapshot variables used by *-zk-snapshot targets -include .env_zk -include .env_hoodi_zk - generate-jwt: @[ -f $(JWT_SECRET_FILE_MAINNET) ] || (echo "Generating $(JWT_SECRET_FILE_MAINNET)..." && openssl rand -hex 32 > $(JWT_SECRET_FILE_MAINNET) && echo "$(JWT_SECRET_FILE_MAINNET) created.") @@ -19,55 +15,35 @@ generate-jwt-hoodi: ## node management run-node: generate-jwt - @echo "You are about to run a Mainnet MPT node." - @echo "To run a ZK (legacy) node instead, use: make run-zk-node" + @echo "You are about to run a Mainnet node." @{ [ -t 0 ] || { echo "Error: interactive confirmation required (run in a TTY)."; exit 1; }; printf "Continue? [Y/n] "; read confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi; } docker-compose --env-file .env up node & run-hoodi-node: generate-jwt-hoodi - @echo "You are about to run a Hoodi MPT node." - @echo "To run a ZK (legacy) node instead, use: make run-hoodi-zk-node" + @echo "You are about to run a Hoodi node." @{ [ -t 0 ] || { echo "Error: interactive confirmation required (run in a TTY)."; exit 1; }; printf "Continue? [Y/n] "; read confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi; } docker-compose --env-file .env_hoodi up node & - -run-zk-node: generate-jwt - docker-compose --env-file .env --env-file .env_zk up node & - -run-hoodi-zk-node: generate-jwt-hoodi - docker-compose --env-file .env_hoodi --env-file .env_hoodi_zk up node & - stop-node: docker stop morph-node morph-geth rm-node: docker rm morph-node morph-geth -## validator management +## validator mode = the SAME single node run with layer1 batch verification +## (--derivation.verify-mode=layer1: pull the L1 beacon blob and derive via the +## engine). It is NOT a separate service/container, so stop/rm with the node +## targets above. Requires a working L1_BEACON_CHAIN_RPC in the env file. +## The shell-exported DERIVATION_VERIFY_MODE overrides the empty value in .env. run-validator: generate-jwt - @echo "You are about to run a Mainnet MPT validator." - @echo "To run a ZK (legacy) validator instead, use: make run-zk-validator" + @echo "You are about to run a Mainnet node in validator mode (--derivation.verify-mode=layer1)." @{ [ -t 0 ] || { echo "Error: interactive confirmation required (run in a TTY)."; exit 1; }; printf "Continue? [Y/n] "; read confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi; } - docker-compose --env-file .env up validator & + DERIVATION_VERIFY_MODE=layer1 docker-compose --env-file .env up node & run-hoodi-validator: generate-jwt-hoodi - @echo "You are about to run a Hoodi MPT validator." - @echo "To run a ZK (legacy) validator instead, use: make run-hoodi-zk-validator" + @echo "You are about to run a Hoodi node in validator mode (--derivation.verify-mode=layer1)." @{ [ -t 0 ] || { echo "Error: interactive confirmation required (run in a TTY)."; exit 1; }; printf "Continue? [Y/n] "; read confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi; } - docker-compose --env-file .env_hoodi up validator & - - -run-zk-validator: generate-jwt - docker-compose --env-file .env --env-file .env_zk up validator & - -run-hoodi-zk-validator: generate-jwt-hoodi - docker-compose --env-file .env_hoodi --env-file .env_hoodi_zk up validator & - -stop-validator: - docker stop validator_node morph-geth - -rm-validator: - docker rm validator_node morph-geth + DERIVATION_VERIFY_MODE=layer1 docker-compose --env-file .env_hoodi up node & ## build from source (requires Go) submodule-init: @@ -112,38 +88,27 @@ build: build-geth build-morphnode ## binary mode run-node-binary: generate-jwt - @echo "You are about to run a Mainnet MPT node (binary mode)." - @echo "To run a ZK (legacy) node instead, use: make run-zk-node-binary" + @echo "You are about to run a Mainnet node (binary mode)." @{ [ -t 0 ] || { echo "Error: interactive confirmation required (run in a TTY)."; exit 1; }; printf "Continue? [Y/n] "; read confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi; } - sh ./run-binary.sh node .env + sh ./run-binary.sh .env run-hoodi-node-binary: generate-jwt-hoodi - @echo "You are about to run a Hoodi MPT node (binary mode)." - @echo "To run a ZK (legacy) node instead, use: make run-hoodi-zk-node-binary" + @echo "You are about to run a Hoodi node (binary mode)." @{ [ -t 0 ] || { echo "Error: interactive confirmation required (run in a TTY)."; exit 1; }; printf "Continue? [Y/n] "; read confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi; } - sh ./run-binary.sh node .env_hoodi + sh ./run-binary.sh .env_hoodi +## validator mode (binary) = single node with --derivation.verify-mode=layer1. +## MORPH_NODE_DERIVATION_VERIFY_MODE is not set by the env files, so it survives +## sourcing and the entrypoint honors it first. Requires L1_BEACON_CHAIN_RPC. run-validator-binary: generate-jwt - @echo "You are about to run a Mainnet MPT validator (binary mode)." + @echo "You are about to run a Mainnet node in validator mode (--derivation.verify-mode=layer1, binary)." @{ [ -t 0 ] || { echo "Error: interactive confirmation required (run in a TTY)."; exit 1; }; printf "Continue? [Y/n] "; read confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi; } - sh ./run-binary.sh validator .env + MORPH_NODE_DERIVATION_VERIFY_MODE=layer1 sh ./run-binary.sh .env run-hoodi-validator-binary: generate-jwt-hoodi - @echo "You are about to run a Hoodi MPT validator (binary mode)." + @echo "You are about to run a Hoodi node in validator mode (--derivation.verify-mode=layer1, binary)." @{ [ -t 0 ] || { echo "Error: interactive confirmation required (run in a TTY)."; exit 1; }; printf "Continue? [Y/n] "; read confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi; } - sh ./run-binary.sh validator .env_hoodi - -run-zk-node-binary: generate-jwt - sh ./run-binary.sh node .env .env_zk - -run-hoodi-zk-node-binary: generate-jwt-hoodi - sh ./run-binary.sh node .env_hoodi .env_hoodi_zk - -run-zk-validator-binary: generate-jwt - sh ./run-binary.sh validator .env .env_zk - -run-hoodi-zk-validator-binary: generate-jwt-hoodi - sh ./run-binary.sh validator .env_hoodi .env_hoodi_zk + MORPH_NODE_DERIVATION_VERIFY_MODE=layer1 sh ./run-binary.sh .env_hoodi stop-binary: @if [ -f .geth.pid ]; then kill $$(cat .geth.pid) 2>/dev/null; rm -f .geth.pid; echo "geth stopped."; fi @@ -204,7 +169,7 @@ quickstart-hoodi-node: generate-jwt-hoodi quickstart-hoodi-node-binary: generate-jwt-hoodi build @echo "=== Quickstart: Hoodi Node (Binary) ===" $(call setup-snapshot-data,$(HOODI_SNAPSHOT_NAME),https://snapshot.morphl2.io/hoodi,../hoodi) - sh ./run-binary.sh node .env_hoodi + sh ./run-binary.sh .env_hoodi quickstart-mainnet-node: generate-jwt @echo "=== Quickstart: Mainnet Node (Docker) ===" @@ -214,7 +179,7 @@ quickstart-mainnet-node: generate-jwt quickstart-mainnet-node-binary: generate-jwt build @echo "=== Quickstart: Mainnet Node (Binary) ===" $(call setup-snapshot-data,$(MAINNET_SNAPSHOT_NAME),https://snapshot.morphl2.io/mainnet,../mainnet) - sh ./run-binary.sh node .env + sh ./run-binary.sh .env # Common function for download and decompress @@ -261,11 +226,5 @@ download-and-decompress-mainnet-mpt-snapshot: download-and-decompress-mainnet-sn download-and-decompress-hoodi-mpt-snapshot: download-and-decompress-hoodi-snapshot -download-and-decompress-mainnet-zk-snapshot: - $(call download-and-decompress,$(MAINNET_ZK_SNAPSHOT_NAME),https://snapshot.morphl2.io/mainnet,../mainnet) - -download-and-decompress-hoodi-zk-snapshot: - $(call download-and-decompress,$(HOODI_ZK_SNAPSHOT_NAME),https://snapshot.morphl2.io/hoodi,../hoodi) - diff --git a/morph-node/docker-compose.yml b/morph-node/docker-compose.yml index 0c390d5..3ec789d 100644 --- a/morph-node/docker-compose.yml +++ b/morph-node/docker-compose.yml @@ -1,7 +1,7 @@ services: geth: container_name: morph-geth - image: ghcr.io/morph-l2/go-ethereum:2.2.3 + image: ghcr.io/morph-l2/go-ethereum:2.2.4 restart: unless-stopped ports: - "8545:8545" @@ -19,12 +19,19 @@ services: - "/bin/sh" - "/entrypoint.sh" + # Single self-verifying node. There is no separate validator service anymore: + # every node verifies batches via --derivation.verify-mode. Set + # DERIVATION_VERIFY_MODE=layer1 (in .env/.env_hoodi) for the former validator + # behavior (pull L1 beacon blob + derive); default "local" needs no beacon. node: container_name: morph-node depends_on: geth: condition: service_started - image: ghcr.io/morph-l2/node:0.5.7 + # Provisional: bumped 0.5.7 -> 0.5.8. This must be a build of morph main + # (single-sequencer + --derivation.verify-mode); 0.5.7 and earlier predate + # verify-mode. Confirm/replace with the real published tag before merge. + image: ghcr.io/morph-l2/node:0.5.8 restart: unless-stopped ports: - "26656" @@ -36,41 +43,19 @@ services: - MORPH_NODE_L2_ENGINE_RPC=http://morph-geth:8551 - MORPH_NODE_L2_ENGINE_AUTH=/jwt-secret.txt - MORPH_NODE_L1_ETH_RPC=${L1_ETH_RPC} + # Beacon RPC is only used on the layer1 verify path; harmless when unset for local. + - MORPH_NODE_L1_ETH_BEACON_RPC=${L1_BEACON_CHAIN_RPC} - MORPH_NODE_L1_CHAIN_ID=${L1_CHAIN_ID} - MORPH_NODE_ROLLUP_ADDRESS=${ROLLUP_CONTRACT} - - MORPH_NODE_SYNC_START_HEIGHT=${L1_MSG_START_HEIGHT} - - NODE_EXTRA_FLAGS=${NODE_EXTRA_FLAGS:-} - volumes: - - "${MORPH_HOME}/node-data:/db" - - "${JWT_SECRET_FILE}:/jwt-secret.txt" - - "./entrypoint-node.sh:/entrypoint-node.sh" - entrypoint: - - "/bin/sh" - - "/entrypoint-node.sh" - - validator: - container_name: validator_node - restart: unless-stopped - depends_on: - geth: - condition: service_started - image: ghcr.io/morph-l2/node:0.5.7 - ports: - - "26660" - environment: - - MORPH_NODE_L2_ETH_RPC=http://morph-geth:8545 - - MORPH_NODE_L2_ENGINE_RPC=http://morph-geth:8551 - - MORPH_NODE_L2_ENGINE_AUTH=/jwt-secret.txt - # TODO: replace these with public network RPC URLs in .env_hoodi before running Hoodi validator - - MORPH_NODE_L1_ETH_RPC=${L1_ETH_RPC} - - MORPH_NODE_L1_ETH_BEACON_RPC=${L1_BEACON_CHAIN_RPC} - MORPH_NODE_SYNC_DEPOSIT_CONTRACT_ADDRESS=${L1MESSAGEQUEUE_CONTRACT} - - MORPH_NODE_ROLLUP_ADDRESS=${ROLLUP_CONTRACT} + - MORPH_NODE_SYNC_START_HEIGHT=${L1_MSG_START_HEIGHT} - MORPH_NODE_DERIVATION_START_HEIGHT=${DERIVATION_START_HEIGHT} - MORPH_NODE_DERIVATION_BASE_HEIGHT=${L2_BASE_HEIGHT} - - MORPH_NODE_SYNC_START_HEIGHT=${L1_MSG_START_HEIGHT} - - MORPH_NODE_L1_CHAIN_ID=${L1_CHAIN_ID} - - NODE_EXTRA_FLAGS=--validator ${NODE_EXTRA_FLAGS:-} + # Batch verification mode: "local" (default, rebuild blob from L2 + compare + # vs L1) or "layer1" (pull L1 beacon blob + derive, former validator behavior). + # Empty => binary default (local). + - MORPH_NODE_DERIVATION_VERIFY_MODE=${DERIVATION_VERIFY_MODE:-} + - NODE_EXTRA_FLAGS=${NODE_EXTRA_FLAGS:-} volumes: - "${MORPH_HOME}/node-data:/db" - "${JWT_SECRET_FILE}:/jwt-secret.txt" diff --git a/morph-node/entrypoint-geth-zk.sh b/morph-node/entrypoint-geth-zk.sh deleted file mode 100644 index f8e462e..0000000 --- a/morph-node/entrypoint-geth-zk.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -GETH_BIN=${GETH_BINARY:-geth} -GETH_DATADIR=${GETH_DATADIR:-./db} -JWT_PATH=${JWT_SECRET_PATH:-/jwt-secret.txt} - -if [ ! -f "${JWT_PATH}" ]; then - echo "Error: jwt-secret.txt not found at ${JWT_PATH}." - echo "Please create it before starting the service." - exit 1 -fi - -MORPH_FLAG=${MORPH_FLAG:-"morph"} - -exec "${GETH_BIN}" \ - "--${MORPH_FLAG}" \ - "--datadir=${GETH_DATADIR}" \ - --verbosity=3 \ - --http \ - "--http.corsdomain=*" \ - "--http.vhosts=*" \ - --http.addr=0.0.0.0 \ - --http.port=8545 \ - --http.api=web3,debug,eth,txpool,net,morph,engine,admin \ - --ws \ - --ws.addr=0.0.0.0 \ - --ws.port=8546 \ - "--ws.origins=*" \ - --ws.api=web3,debug,eth,txpool,net,morph,engine,admin \ - --authrpc.addr=0.0.0.0 \ - --authrpc.port=8551 \ - "--authrpc.vhosts=*" \ - "--authrpc.jwtsecret=${JWT_PATH}" \ - --gcmode=archive \ - "--log.filename=${GETH_DATADIR}/geth.log" \ - --metrics \ - --metrics.addr=0.0.0.0 diff --git a/morph-node/entrypoint-node.sh b/morph-node/entrypoint-node.sh index 0796a02..6703b61 100755 --- a/morph-node/entrypoint-node.sh +++ b/morph-node/entrypoint-node.sh @@ -13,7 +13,7 @@ export MORPH_NODE_L2_ENGINE_AUTH=${MORPH_NODE_L2_ENGINE_AUTH:-${JWT_PATH}} export MORPH_NODE_L1_ETH_RPC=${MORPH_NODE_L1_ETH_RPC:-${L1_ETH_RPC:-}} export MORPH_NODE_ROLLUP_ADDRESS=${MORPH_NODE_ROLLUP_ADDRESS:-${ROLLUP_CONTRACT:-}} -# Validator-specific mappings +# Map remaining .env variables to MORPH_NODE_* for binary mode (Docker sets these directly) export MORPH_NODE_L1_ETH_BEACON_RPC=${MORPH_NODE_L1_ETH_BEACON_RPC:-${L1_BEACON_CHAIN_RPC:-}} export MORPH_NODE_SYNC_DEPOSIT_CONTRACT_ADDRESS=${MORPH_NODE_SYNC_DEPOSIT_CONTRACT_ADDRESS:-${L1MESSAGEQUEUE_CONTRACT:-}} DERIVATION_START_HEIGHT_VALUE=${MORPH_NODE_DERIVATION_START_HEIGHT:-${DERIVATION_START_HEIGHT:-}} @@ -29,6 +29,17 @@ fi export MORPH_NODE_SYNC_START_HEIGHT=${MORPH_NODE_SYNC_START_HEIGHT:-${L1_MSG_START_HEIGHT:-}} export MORPH_NODE_L1_CHAIN_ID=${MORPH_NODE_L1_CHAIN_ID:-${L1_CHAIN_ID:-}} +# Batch verification mode (--derivation.verify-mode). "local" (default) rebuilds +# the blob from local L2 and compares versioned hashes vs L1; "layer1" pulls the +# L1 beacon blob and derives via the engine (former validator behavior). +# Export only when set; empty/unset falls back to the binary default (local). +DERIVATION_VERIFY_MODE_VALUE=${MORPH_NODE_DERIVATION_VERIFY_MODE:-${DERIVATION_VERIFY_MODE:-}} +if [ -n "${DERIVATION_VERIFY_MODE_VALUE}" ]; then + export MORPH_NODE_DERIVATION_VERIFY_MODE="${DERIVATION_VERIFY_MODE_VALUE}" +else + unset MORPH_NODE_DERIVATION_VERIFY_MODE +fi + COMMAND="${NODE_BIN} \ --home ${NODE_HOME} \ --log.filename ${NODE_HOME}/node.log \ diff --git a/morph-node/run-binary.sh b/morph-node/run-binary.sh index a766733..a2095da 100755 --- a/morph-node/run-binary.sh +++ b/morph-node/run-binary.sh @@ -1,13 +1,15 @@ #!/bin/sh -# Usage: run-binary.sh [override-env-file] -# mode: node | validator +# Usage: run-binary.sh [override-env-file] # env-file: .env | .env_hoodi -# override-env-file: optional, e.g. .env_zk for ZK legacy mode +# override-env-file: optional extra env file layered on top +# +# There is no node/validator mode arg anymore: every node self-verifies. For the +# former validator behavior, set MORPH_NODE_DERIVATION_VERIFY_MODE=layer1 in the +# environment (see `make run-validator-binary`). -MODE=${1:-node} -ENV_FILE=${2:-.env} -OVERRIDE_ENV_FILE=${3:-} +ENV_FILE=${1:-.env} +OVERRIDE_ENV_FILE=${2:-} # Source environment set -a @@ -50,7 +52,7 @@ trap cleanup INT TERM # Validate entrypoint file case "${GETH_ENTRYPOINT_FILE}" in - ./entrypoint-geth.sh|./entrypoint-geth-zk.sh) ;; + ./entrypoint-geth.sh) ;; *) echo "Error: invalid GETH_ENTRYPOINT_FILE: ${GETH_ENTRYPOINT_FILE}" exit 1 @@ -88,13 +90,8 @@ if ! nc -z localhost 8551 2>/dev/null; then exit 1 fi -# Set validator mode -if [ "${MODE}" = "validator" ]; then - NODE_EXTRA_FLAGS="--validator ${NODE_EXTRA_FLAGS:-}" -fi - # Start morphnode -echo "Starting morphnode (${MODE} mode)..." +echo "Starting morphnode..." NODE_BINARY=${NODE_BINARY} \ NODE_HOME=${MORPH_HOME}/node-data \ JWT_SECRET_PATH=${JWT_SECRET_FILE} \