Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
54 changes: 23 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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):

Expand Down Expand Up @@ -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:

Expand Down
2 changes: 1 addition & 1 deletion go-ethereum
Submodule go-ethereum updated 187 files
2 changes: 1 addition & 1 deletion morph
Submodule morph updated 311 files
24 changes: 19 additions & 5 deletions morph-node/.env
Original file line number Diff line number Diff line change
Expand Up @@ -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.
30 changes: 24 additions & 6 deletions morph-node/.env_hoodi
Original file line number Diff line number Diff line change
Expand Up @@ -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.
6 changes: 0 additions & 6 deletions morph-node/.env_hoodi_zk

This file was deleted.

6 changes: 0 additions & 6 deletions morph-node/.env_zk

This file was deleted.

89 changes: 24 additions & 65 deletions morph-node/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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.")

Expand All @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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) ==="
Expand All @@ -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
Expand Down Expand Up @@ -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)



Loading