diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8cf7a27 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "go-ethereum"] + path = go-ethereum + url = https://github.com/morph-l2/go-ethereum.git +[submodule "morph"] + path = morph + url = https://github.com/morph-l2/morph.git diff --git a/README.md b/README.md index 7c5d0ac..12e28ad 100644 --- a/README.md +++ b/README.md @@ -47,14 +47,14 @@ Before setting up a Morph node, ensure you have the following installed: make download-and-decompress-hoodi-snapshot ``` -- For MPT node (mainnet or Hoodi testnet), download the MPT-specific snapshot: +- For ZK node (legacy), download the ZK-specific snapshot: ```bash - make download-and-decompress-mainnet-mpt-snapshot + make download-and-decompress-mainnet-zk-snapshot ``` or ```bash - make download-and-decompress-hoodi-mpt-snapshot + 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. @@ -86,21 +86,13 @@ Before setting up a Morph node, ensure you have the following installed: make run-node ``` - For testnet, run + For Hoodi testnet, run ```bash make run-hoodi-node ``` - For MPT node, run - - ```bash - make run-mainnet-mpt-node - ``` - or - ```bash - make run-hoodi-mpt-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. @@ -139,13 +131,6 @@ The table below provides the node snapshot data and corresponding download URLs. | [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 | -**For holesky testnet(legacy)**: - -| Snapshot Name |Derivation Start Height | L1 Msg Start Height | L2 Base Height | -|:--------------------|:------------------------|:--------------------|:--------------------| -|[snapshot-20250903-1](https://snapshot.morphl2.io/holesky/snapshot-20250903-1.tar.gz)|4445350|4445989|19741862| -|[snapshot-20250818-1](https://snapshot.morphl2.io/holesky/snapshot-20250818-1.tar.gz)|4360545|4359976|19432113| -|[snapshot-20250428-1](https://snapshot.morphl2.io/holesky/snapshot-20250428-1.tar.gz)|3748991|3748974|17193670| ## Documentation For detailed information on Morph and its ecosystem, refer to the official documentation: diff --git a/go-ethereum b/go-ethereum new file mode 160000 index 0000000..1d46057 --- /dev/null +++ b/go-ethereum @@ -0,0 +1 @@ +Subproject commit 1d4605778e32dd6dc205e74a97b925149bbe6c88 diff --git a/holesky/geth-data/static-nodes.json b/holesky/geth-data/static-nodes.json deleted file mode 100644 index 1d2fefe..0000000 --- a/holesky/geth-data/static-nodes.json +++ /dev/null @@ -1,5 +0,0 @@ -[ -"enode://8c400a01a9457ab99219bb7d87677ecdd4638ccf6a5f81c8bcf89abcd59cca91bd27b82071760e7f7d8ef043ca6817278495509197a3fc4ed2fd34fd67fb123b@52.69.21.155:30303", -"enode://8eba7278fcb84a7b836a684fd4b62526af775633297974bf2b48584ea2f831a65a7ae7d914198f66b94820348cdad37533fc7336688b139ca27d30a7713867ab@35.76.156.3:30303", -"enode://588b64f887745a2f53a92312926c9d5ae03c64412860889a9c605570d7b71522a0774d254311752ac2cd44c68c3282ea125874f66ef7e65548573420d6cd98e2@35.78.13.184:30303" -] \ No newline at end of file diff --git a/holesky/node-data/config/config.toml b/holesky/node-data/config/config.toml deleted file mode 100644 index 72a404e..0000000 --- a/holesky/node-data/config/config.toml +++ /dev/null @@ -1,413 +0,0 @@ -# This is a TOML config file. -# For more information, see https://github.com/toml-lang/toml - -# NOTE: Any path below can be absolute (e.g. "/var/myawesomeapp/data") or -# relative to the home directory (e.g. "data"). The home directory is -# "$HOME/.tendermint" by default, but could be changed via $TMHOME env variable -# or --home cmd flag. - -####################################################################### -### Main Base Config Options ### -####################################################################### - -# TCP or UNIX socket address of the ABCI application, -# or the name of an ABCI application compiled in with the Tendermint binary -proxy_app = "tcp://127.0.0.1:26658" - -# A custom human readable name for this node -moniker = "my-morph-node" - -# If this node is many blocks behind the tip of the chain, BlockSync -# allows them to catchup quickly by downloading blocks in parallel -# and verifying their commits -block_sync = true - -# Database backend: goleveldb | cleveldb | boltdb | rocksdb | badgerdb -# * goleveldb (github.com/syndtr/goleveldb - most popular implementation) -# - pure go -# - stable -# * cleveldb (uses levigo wrapper) -# - fast -# - requires gcc -# - use cleveldb build tag (go build -tags cleveldb) -# * boltdb (uses etcd's fork of bolt - github.com/etcd-io/bbolt) -# - EXPERIMENTAL -# - may be faster is some use-cases (random reads - indexer) -# - use boltdb build tag (go build -tags boltdb) -# * rocksdb (uses github.com/tecbot/gorocksdb) -# - EXPERIMENTAL -# - requires gcc -# - use rocksdb build tag (go build -tags rocksdb) -# * badgerdb (uses github.com/dgraph-io/badger) -# - EXPERIMENTAL -# - use badgerdb build tag (go build -tags badgerdb) -db_backend = "goleveldb" - -# Database directory -db_dir = "data" - -# Output level for logging, including package level options -log_level = "info" - -# Output format: 'plain' (colored text) or 'json' -log_format = "plain" - -##### additional base config options ##### - -# Path to the JSON file containing the initial validator set and other meta data -genesis_file = "config/genesis.json" - -# Path to the JSON file containing the private key to use as a validator in the consensus protocol -priv_validator_key_file = "config/priv_validator_key.json" - -# Path to the JSON file containing the last sign state of a validator -priv_validator_state_file = "data/priv_validator_state.json" - -# TCP or UNIX socket address for Tendermint to listen on for -# connections from an external PrivValidator process -priv_validator_laddr = "" - -# Path to the JSON file containing the private key to use for node authentication in the p2p protocol -node_key_file = "config/node_key.json" - -# Mechanism to connect to the ABCI application: socket | grpc -abci = "socket" - -# If true, query the ABCI app on connecting to a new peer -# so the app can decide if we should keep the connection or not -filter_peers = false - - -####################################################################### -### Advanced Configuration Options ### -####################################################################### - -####################################################### -### RPC Server Configuration Options ### -####################################################### -[rpc] - -# TCP or UNIX socket address for the RPC server to listen on -laddr = "tcp://0.0.0.0:26657" - -# A list of origins a cross-domain request can be executed from -# Default value '[]' disables cors support -# Use '["*"]' to allow any origin -cors_allowed_origins = [] - -# A list of methods the client is allowed to use with cross-domain requests -cors_allowed_methods = ["HEAD", "GET", "POST", ] - -# A list of non simple headers the client is allowed to use with cross-domain requests -cors_allowed_headers = ["Origin", "Accept", "Content-Type", "X-Requested-With", "X-Server-Time", ] - -# TCP or UNIX socket address for the gRPC server to listen on -# NOTE: This server only supports /broadcast_tx_commit -grpc_laddr = "" - -# Maximum number of simultaneous connections. -# Does not include RPC (HTTP&WebSocket) connections. See max_open_connections -# If you want to accept a larger number than the default, make sure -# you increase your OS limits. -# 0 - unlimited. -# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} -# 1024 - 40 - 10 - 50 = 924 = ~900 -grpc_max_open_connections = 900 - -# Activate unsafe RPC commands like /dial_seeds and /unsafe_flush_mempool -unsafe = false - -# Maximum number of simultaneous connections (including WebSocket). -# Does not include gRPC connections. See grpc_max_open_connections -# If you want to accept a larger number than the default, make sure -# you increase your OS limits. -# 0 - unlimited. -# Should be < {ulimit -Sn} - {MaxNumInboundPeers} - {MaxNumOutboundPeers} - {N of wal, db and other open files} -# 1024 - 40 - 10 - 50 = 924 = ~900 -max_open_connections = 900 - -# Maximum number of unique clientIDs that can /subscribe -# If you're using /broadcast_tx_commit, set to the estimated maximum number -# of broadcast_tx_commit calls per block. -max_subscription_clients = 100 - -# Maximum number of unique queries a given client can /subscribe to -# If you're using GRPC (or Local RPC client) and /broadcast_tx_commit, set to -# the estimated # maximum number of broadcast_tx_commit calls per block. -max_subscriptions_per_client = 5 - -# Experimental parameter to specify the maximum number of events a node will -# buffer, per subscription, before returning an error and closing the -# subscription. Must be set to at least 100, but higher values will accommodate -# higher event throughput rates (and will use more memory). -experimental_subscription_buffer_size = 200 - -# Experimental parameter to specify the maximum number of RPC responses that -# can be buffered per WebSocket client. If clients cannot read from the -# WebSocket endpoint fast enough, they will be disconnected, so increasing this -# parameter may reduce the chances of them being disconnected (but will cause -# the node to use more memory). -# -# Must be at least the same as "experimental_subscription_buffer_size", -# otherwise connections could be dropped unnecessarily. This value should -# ideally be somewhat higher than "experimental_subscription_buffer_size" to -# accommodate non-subscription-related RPC responses. -experimental_websocket_write_buffer_size = 200 - -# If a WebSocket client cannot read fast enough, at present we may -# silently drop events instead of generating an error or disconnecting the -# client. -# -# Enabling this experimental parameter will cause the WebSocket connection to -# be closed instead if it cannot read fast enough, allowing for greater -# predictability in subscription behavior. -experimental_close_on_slow_client = false - -# How long to wait for a tx to be committed during /broadcast_tx_commit. -# WARNING: Using a value larger than 10s will result in increasing the -# global HTTP write timeout, which applies to all connections and endpoints. -# See https://github.com/tendermint/tendermint/issues/3435 -timeout_broadcast_tx_commit = "10s" - -# Maximum size of request body, in bytes -max_body_bytes = 1000000 - -# Maximum size of request header, in bytes -max_header_bytes = 1048576 - -# The path to a file containing certificate that is used to create the HTTPS server. -# Might be either absolute path or path related to Tendermint's config directory. -# If the certificate is signed by a certificate authority, -# the certFile should be the concatenation of the server's certificate, any intermediates, -# and the CA's certificate. -# NOTE: both tls_cert_file and tls_key_file must be present for Tendermint to create HTTPS server. -# Otherwise, HTTP server is run. -tls_cert_file = "" - -# The path to a file containing matching private key that is used to create the HTTPS server. -# Might be either absolute path or path related to Tendermint's config directory. -# NOTE: both tls-cert-file and tls-key-file must be present for Tendermint to create HTTPS server. -# Otherwise, HTTP server is run. -tls_key_file = "" - -# pprof listen address (https://golang.org/pkg/net/http/pprof) -pprof_laddr = "" - -####################################################### -### P2P Configuration Options ### -####################################################### -[p2p] - -# Address to listen for incoming connections -laddr = "tcp://0.0.0.0:26656" - -# Address to advertise to peers for them to dial -# If empty, will use the same port as the laddr, -# and will introspect on the listener or use UPnP -# to figure out the address. ip and port are required -# example: 159.89.10.97:26656 -external_address = "" - -# Comma separated list of seed nodes to connect to -seeds = "" - -# Comma separated list of nodes to keep persistent connections to -persistent_peers = "7581c3fc378f1d6013e4f2eaa1e50fc3c25b9524@52.197.82.153:26656,0fb5ce425197a462a66de015ee5fbbf103835b8a@54.238.14.220:26656,d1a99acbf7139c9cf148357332986bbe7358793b@54.150.188.132:26656" - -# UPNP port forwarding -upnp = false - -# Path to address book -addr_book_file = "config/addrbook.json" - -# Set true for strict address routability rules -# Set false for private or local networks -addr_book_strict = false - -# Maximum number of inbound peers -max_num_inbound_peers = 40 - -# Maximum number of outbound peers to connect to, excluding persistent peers -max_num_outbound_peers = 10 - -# List of node IDs, to which a connection will be (re)established ignoring any existing limits -unconditional_peer_ids = "" - -# Maximum pause when redialing a persistent peer (if zero, exponential backoff is used) -persistent_peers_max_dial_period = "0s" - -# Time to wait before flushing messages out on the connection -flush_throttle_timeout = "100ms" - -# Maximum size of a message packet payload, in bytes -max_packet_msg_payload_size = 1024 - -# Rate at which packets can be sent, in bytes/second -send_rate = 5120000 - -# Rate at which packets can be received, in bytes/second -recv_rate = 5120000 - -# Set true to enable the peer-exchange reactor -pex = false - -# Seed mode, in which node constantly crawls the network and looks for -# peers. If another node asks it for addresses, it responds and disconnects. -# -# Does not work if the peer-exchange reactor is disabled. -seed_mode = false - -# Comma separated list of peer IDs to keep private (will not be gossiped to other peers) -private_peer_ids = "" - -# Toggle to disable guard against peers connecting from the same ip. -allow_duplicate_ip = true - -# Peer connection configuration. -handshake_timeout = "20s" -dial_timeout = "3s" - -####################################################### -### State Sync Configuration Options ### -####################################################### -[statesync] -# State sync rapidly bootstraps a new node by discovering, fetching, and restoring a state machine -# snapshot from peers instead of fetching and replaying historical blocks. Requires some peers in -# the network to take and serve state machine snapshots. State sync is not attempted if the node -# has any local state (LastBlockHeight > 0). The node will have a truncated block history, -# starting from the height of the snapshot. -enable = false - -# RPC servers (comma-separated) for light client verification of the synced state machine and -# retrieval of state data for node bootstrapping. Also needs a trusted height and corresponding -# header hash obtained from a trusted source, and a period during which validators can be trusted. -# -# For Cosmos SDK-based chains, trust_period should usually be about 2/3 of the unbonding time (~2 -# weeks) during which they can be financially punished (slashed) for misbehavior. -rpc_servers = "" -trust_height = 0 -trust_hash = "" -trust_period = "168h0m0s" - -# Time to spend discovering snapshots before initiating a restore. -discovery_time = "15s" - -# Temporary directory for state sync snapshot chunks, defaults to the OS tempdir (typically /tmp). -# Will create a new, randomly named directory within, and remove it when done. -temp_dir = "" - -# The timeout duration before re-requesting a chunk, possibly from a different -# peer (default: 1 minute). -chunk_request_timeout = "10s" - -# The number of concurrent chunk fetchers to run (default: 1). -chunk_fetchers = "4" - -####################################################### -### Block Sync Configuration Options ### -####################################################### -[blocksync] - -# Block Sync version to use: -# -# In v0.37, v1 and v2 of the block sync protocols were deprecated. -# Please use v0 instead. -# -# 1) "v0" - the default block sync implementation -version = "v0" - -####################################################### -### Consensus Configuration Options ### -####################################################### -[consensus] - -wal_file = "data/cs.wal/wal" - -# How long we wait for a proposal block before prevoting nil -timeout_propose = "3s" -# How much timeout_propose increases with each round -timeout_propose_delta = "500ms" -# How long we wait after receiving +2/3 prevotes for “anything” (ie. not a single block or nil) -timeout_prevote = "1s" -# How much the timeout_prevote increases with each round -timeout_prevote_delta = "500ms" -# How long we wait after receiving +2/3 precommits for “anything” (ie. not a single block or nil) -timeout_precommit = "1s" -# How much the timeout_precommit increases with each round -timeout_precommit_delta = "500ms" -# How long we wait after committing a block, before starting on the new -# height (this gives us a chance to receive some more precommits, even -# though we already have +2/3). -timeout_commit = "1s" - -# How many blocks to look back to check existence of the node's consensus votes before joining consensus -# When non-zero, the node will panic upon restart -# if the same consensus key was used to sign {double_sign_check_height} last blocks. -# So, validators should stop the state machine, wait for some blocks, and then restart the state machine to avoid panic. -double_sign_check_height = 0 - -# Make progress as soon as we have all the precommits (as if TimeoutCommit = 0) -skip_timeout_commit = false - -# EmptyBlocks mode and possible interval between empty blocks -create_empty_blocks = true -create_empty_blocks_interval = "4s" - -# Reactor sleep duration parameters -peer_gossip_sleep_duration = "100ms" -peer_query_maj23_sleep_duration = "2s" - -####################################################### -### Storage Configuration Options ### -####################################################### -[storage] - -# Set to true to discard ABCI responses from the state store, which can save a -# considerable amount of disk space. Set to false to ensure ABCI responses are -# persisted. ABCI responses are required for /block_results RPC queries, and to -# reindex events in the command-line tool. -discard_abci_responses = false - -####################################################### -### Transaction Indexer Configuration Options ### -####################################################### -[tx_index] - -# What indexer to use for transactions -# -# The application will set which txs to index. In some cases a node operator will be able -# to decide which txs to index based on configuration set in the application. -# -# Options: -# 1) "null" -# 2) "kv" (default) - the simplest possible indexer, backed by key-value storage (defaults to levelDB; see DBBackend). -# - When "kv" is chosen "tx.height" and "tx.hash" will always be indexed. -# 3) "psql" - the indexer services backed by PostgreSQL. -# When "kv" or "psql" is chosen "tx.height" and "tx.hash" will always be indexed. -indexer = "kv" - -# The PostgreSQL connection configuration, the connection format: -# postgresql://:@:/? -psql-conn = "" - -####################################################### -### Instrumentation Configuration Options ### -####################################################### -[instrumentation] - -# When true, Prometheus metrics are served under /metrics on -# PrometheusListenAddr. -# Check out the documentation for the list of available metrics. -prometheus = true - -# Address to listen for Prometheus collector(s) connections -prometheus_listen_addr = ":26660" - -# Maximum number of simultaneous connections. -# If you want to accept a larger number than the default, make sure -# you increase your OS limits. -# 0 - unlimited. -max_open_connections = 3 - -# Instrumentation namespace -namespace = "tendermint" \ No newline at end of file diff --git a/holesky/node-data/config/genesis.json b/holesky/node-data/config/genesis.json deleted file mode 100644 index aaa971d..0000000 --- a/holesky/node-data/config/genesis.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "genesis_time": "2024-04-30T02:00:00.000000Z", - "chain_id": "chain-morph-holesky", - "initial_height": "0", - "consensus_params": { - "batch": { - "blocks_interval": "600", - "max_bytes": "124928", - "timeout": "1200000000000", - "max_chunks": "15" - }, - "block": { - "max_bytes": "22020096", - "max_gas": "-1" - }, - "evidence": { - "max_age_num_blocks": "100000", - "max_age_duration": "172800000000000", - "max_bytes": "1048576" - }, - "validator": { - "pub_key_types": [ - "ed25519" - ] - }, - "version": { - "app": "0" - } - }, - "validators": [ - { - "address": "CBE693B3525FA9249B36D165D49686D022E3934D", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "pPOn+4gsMVk5j1IOPImjncmBgjX+oHeJmVqc57Srox0=" - }, - "power": "1", - "name": "node0" - }, - { - "address": "83C99FA24332B02BB6E804AC3E702B58CDEF6CF1", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "BTWCT3KZhhWsgmXBLJz8Y9MV2PPoSaoYV/QrEc/F1yw=" - }, - "power": "1", - "name": "node1" - }, - { - "address": "283442A86D42E96A0266CEF1555630979C57D2A5", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "OlAZfL/b5bvYX/E7DVXdwI7NXb3bwBKIC6E1hWLhkr0=" - }, - "power": "1", - "name": "node2" - }, - { - "address": "BE50743CD55375D8C4C0F0935BDA21B4EAA174C0", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "gUznV+lyd2jyXq1GGe+lUtn4+srYUjbAp3TQsh+uKOo=" - }, - "power": "1", - "name": "node3" - }, - { - "address": "CFF884A82BF8CBF630AAD1E6386D68B55E28091B", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "nSmS6UzFDNi7iB9es604KM+7Xiv5ItmI8xHfCXGmzJw=" - }, - "power": "1", - "name": "node4" - }, - { - "address": "9C02F53B7938B91715B0A0BC99397D6B083A93FC", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "YSN8paRbO5rr1s+qzcACB3Xq7svQxMYQIWWbbVgfYG8=" - }, - "power": "1", - "name": "node5" - }, - { - "address": "D4C1EB59EB71EC4081AA192CB3FC65FAF97A2107", - "pub_key": { - "type": "tendermint/PubKeyEd25519", - "value": "qOxnBz10r6N5HDadOIyNwutj6z9Rnzl1t+iU4LuhVfY=" - }, - "power": "1", - "name": "node6" - } - - ], - "app_hash": "" - } \ No newline at end of file diff --git a/holesky/node-data/data/.gitignore b/holesky/node-data/data/.gitignore deleted file mode 100644 index c96a04f..0000000 --- a/holesky/node-data/data/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/morph b/morph new file mode 160000 index 0000000..a20bbfa --- /dev/null +++ b/morph @@ -0,0 +1 @@ +Subproject commit a20bbfa25014a20ba229ca0c9621001d6b334b44 diff --git a/morph-node/.env b/morph-node/.env index 86a2793..c473ae8 100644 --- a/morph-node/.env +++ b/morph-node/.env @@ -3,6 +3,7 @@ MORPH_FLAG=morph JWT_SECRET_FILE=${MORPH_HOME}/jwt-secret.txt GETH_ENTRYPOINT_FILE=./entrypoint-geth.sh MAINNET_SNAPSHOT_NAME=snapshot-20250122-1 +MAINNET_MPT_SNAPSHOT_NAME=mpt-snapshot-20260317-1 ## Environment variables for validator node L1_CHAIN_ID=1 @@ -10,8 +11,9 @@ L1_ETH_RPC=https://eth.drpc.org L1_BEACON_CHAIN_RPC=https://rpc.ankr.com/eth L1MESSAGEQUEUE_CONTRACT=0x3931ade842f5bb8763164bdd81e5361dce6cc1ef ROLLUP_CONTRACT=0x759894ced0e6af42c26668076ffa84d02e3cef60 -DERIVATION_START_HEIGHT=20996776 -L1_MSG_START_HEIGHT=20996776 +DERIVATION_START_HEIGHT=24676384 +L1_MSG_START_HEIGHT=24674343 +L2_BASE_HEIGHT=21500591 ## Extra flags for node NODE_EXTRA_FLAGS=--mainnet diff --git a/morph-node/.env_holesky b/morph-node/.env_holesky deleted file mode 100644 index 51943fb..0000000 --- a/morph-node/.env_holesky +++ /dev/null @@ -1,14 +0,0 @@ -MORPH_HOME=../holesky -MORPH_FLAG=morph-holesky -JWT_SECRET_FILE=${MORPH_HOME}/jwt-secret.txt -GETH_ENTRYPOINT_FILE=./entrypoint-geth.sh -HOLESKY_SNAPSHOT_NAME=snapshot-20250109-1 - -## Environment variables for validator node -L1_CHAIN_ID=17000 -L1_ETH_RPC=${your_layer1_execution_client_rpc_url} -L1_BEACON_CHAIN_RPC=${your_layer1_beacon_client_rpc_url} -L1MESSAGEQUEUE_CONTRACT=0x778d1d9a4d8b6b9ade36d967a9ac19455ec3fd0b -ROLLUP_CONTRACT=0xd8c5c541d56f59d65cf775de928ccf4a47d4985c -DERIVATION_START_HEIGHT=3106901 -L1_MSG_START_HEIGHT=3106887 \ No newline at end of file diff --git a/morph-node/.env_hoodi b/morph-node/.env_hoodi index 72089dd..3329489 100644 --- a/morph-node/.env_hoodi +++ b/morph-node/.env_hoodi @@ -4,12 +4,14 @@ JWT_SECRET_FILE=${MORPH_HOME}/jwt-secret.txt GETH_ENTRYPOINT_FILE=./entrypoint-geth.sh ## todo snapshot HOODI_SNAPSHOT_NAME=snapshot-20250930-1 +HOODI_MPT_SNAPSHOT_NAME=mpt-snapshot-20260402-1 ## Environment variables for validator node L1_CHAIN_ID=560048 -L1_ETH_RPC=${your_layer1_execution_client_rpc_url} -L1_BEACON_CHAIN_RPC=${your_layer1_beacon_client_rpc_url} +L1_ETH_RPC=YOUR_LAYER1_EXECUTION_CLIENT_RPC_URL +L1_BEACON_CHAIN_RPC=YOUR_LAYER1_BEACON_CLIENT_RPC_URL L1MESSAGEQUEUE_CONTRACT=0xd7f39d837f4790b215ba67e0ab63665912648dbe ROLLUP_CONTRACT=0x57e0e6dde89dc52c01fe785774271504b1e04664 -DERIVATION_START_HEIGHT=1182317 -L1_MSG_START_HEIGHT=1182317 \ No newline at end of file +DERIVATION_START_HEIGHT=2534958 +L1_MSG_START_HEIGHT=2528506 +L2_BASE_HEIGHT=4391571 \ No newline at end of file diff --git a/morph-node/.env_hoodi_zk b/morph-node/.env_hoodi_zk new file mode 100644 index 0000000..dd08215 --- /dev/null +++ b/morph-node/.env_hoodi_zk @@ -0,0 +1,2 @@ +# ZK (legacy) override - load after .env_hoodi to switch back to ZK mode +GETH_ENTRYPOINT_FILE=./entrypoint-geth-zk.sh diff --git a/morph-node/.env_mpt b/morph-node/.env_mpt deleted file mode 100644 index f27eb61..0000000 --- a/morph-node/.env_mpt +++ /dev/null @@ -1,6 +0,0 @@ -# MPT specific overrides (loaded after base env to override values) -GETH_ENTRYPOINT_FILE=./entrypoint-geth-mpt.sh - -# MPT snapshot names -HOODI_MPT_SNAPSHOT_NAME=snapshot-20260312-1 -MAINNET_MPT_SNAPSHOT_NAME=snapshot-20260312-1 diff --git a/morph-node/.env_zk b/morph-node/.env_zk new file mode 100644 index 0000000..f42ad1d --- /dev/null +++ b/morph-node/.env_zk @@ -0,0 +1,2 @@ +# ZK (legacy) override - load after .env to switch back to ZK mode +GETH_ENTRYPOINT_FILE=./entrypoint-geth-zk.sh diff --git a/morph-node/Makefile b/morph-node/Makefile index 2aef9ad..f973e7f 100644 --- a/morph-node/Makefile +++ b/morph-node/Makefile @@ -1,43 +1,37 @@ include .env -# Store the value of JWT_SECRET_FILE from .env +# Capture mainnet JWT path before .env_hoodi overwrites MORPH_HOME (:= forces immediate expansion) JWT_SECRET_FILE_MAINNET := $(JWT_SECRET_FILE) -include .env_holesky - include .env_hoodi -# Store the value of JWT_SECRET_FILE from .env_holesky -JWT_SECRET_FILE_HOLESKY := $(JWT_SECRET_FILE) - JWT_SECRET_FILE_HOODI := $(JWT_SECRET_FILE) -include .env_mpt - 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.") -generate-jwt-holesky: - @[ -f $(JWT_SECRET_FILE_HOLESKY) ] || (echo "Generating $(JWT_SECRET_FILE_HOLESKY)..." && openssl rand -hex 32 > $(JWT_SECRET_FILE_HOLESKY) && echo "$(JWT_SECRET_FILE_HOLESKY) created.") - generate-jwt-hoodi: @[ -f $(JWT_SECRET_FILE_HOODI) ] || (echo "Generating $(JWT_SECRET_FILE_HOODI)..." && openssl rand -hex 32 > $(JWT_SECRET_FILE_HOODI) && echo "$(JWT_SECRET_FILE_HOODI) created.") ## 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" + @read -p "Continue? [Y/n] " confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi docker-compose --env-file .env up node & -run-holesky-node: generate-jwt-holesky - docker-compose --env-file .env_holesky 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" + @read -p "Continue? [Y/n] " confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi docker-compose --env-file .env_hoodi up node & -run-hoodi-mpt-node: generate-jwt-hoodi - docker-compose --env-file .env_hoodi --env-file .env_mpt up node & -run-mainnet-mpt-node: generate-jwt - docker-compose --env-file .env --env-file .env_mpt 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 @@ -47,25 +41,152 @@ rm-node: ## validator management 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" + @read -p "Continue? [Y/n] " confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi docker-compose --env-file .env up validator & -run-holesky-validator: generate-jwt-holesky - docker-compose --env-file .env_holesky up validator & - 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" + @read -p "Continue? [Y/n] " confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi docker-compose --env-file .env_hoodi up validator & -run-hoodi-mpt-validator: generate-jwt-hoodi - docker-compose --env-file .env_hoodi --env-file .env_mpt up validator & -run-mainnet-mpt-validator: generate-jwt - docker-compose --env-file .env --env-file .env_mpt 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 + docker stop validator_node morph-geth rm-validator: - docker rm validator-node morph-geth + docker rm validator_node morph-geth + +## build from source (requires Go) +submodule-init: + @echo "Initializing git submodules..." + cd .. && git submodule update --init --recursive + @echo "Submodules ready." + +# Update submodule versions and docker-compose.yml image tags in one shot. +# Usage: make set-versions GETH_VERSION=2.2.1 NODE_VERSION=0.5.3 +set-versions: + cd ../go-ethereum && git fetch --tags && git checkout morph-v$(GETH_VERSION) + cd ../morph && git fetch --tags && git checkout v$(NODE_VERSION) + sed -i 's|go-ethereum:[0-9.]*|go-ethereum:$(GETH_VERSION)|g' docker-compose.yml + sed -i 's|morph-l2/node:[0-9.]*|morph-l2/node:$(NODE_VERSION)|g' docker-compose.yml + cd .. && git add go-ethereum morph + @echo "Done. Commit with: git commit -m 'chore: bump geth=$(GETH_VERSION) node=$(NODE_VERSION)'" + +build-geth: submodule-init + @echo "Building geth from source..." + cd ../go-ethereum && make geth + cp ../go-ethereum/build/bin/geth ./bin/geth + @echo "geth binary copied to morph-node/bin/geth" + +build-morphnode: submodule-init + @echo "Building morphnode from source..." + cd ../morph/node && make morphnode + cp ../morph/node/build/bin/morphnode ./bin/morphnode + @echo "morphnode binary copied to morph-node/bin/morphnode" + +build: build-geth build-morphnode + @echo "All binaries built successfully." + +## 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" + @read -p "Continue? [Y/n] " confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi + sh ./run-binary.sh node .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" + @read -p "Continue? [Y/n] " confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi + sh ./run-binary.sh node .env_hoodi + +run-validator-binary: generate-jwt + @echo "You are about to run a Mainnet MPT validator (binary mode)." + @read -p "Continue? [Y/n] " confirm; if [ "$$confirm" = "n" ] || [ "$$confirm" = "N" ]; then exit 1; fi + sh ./run-binary.sh validator .env + +run-hoodi-validator-binary: generate-jwt-hoodi + @echo "You are about to run a Hoodi MPT validator (binary mode)." + @read -p "Continue? [Y/n] " 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 + +stop-binary: + @if [ -f .geth.pid ]; then kill $$(cat .geth.pid) 2>/dev/null; rm -f .geth.pid; echo "geth stopped."; fi + @if [ -f .node.pid ]; then kill $$(cat .node.pid) 2>/dev/null; rm -f .node.pid; echo "morphnode stopped."; fi + + +# Helper: download, extract, and move snapshot data into MORPH_HOME +# $(1) = snapshot name, $(2) = download URL base, $(3) = MORPH_HOME +define setup-snapshot-data + @if [ -d "$(3)/geth-data/geth/chaindata" ]; then \ + echo "Snapshot data already in place at $(3), skipping setup."; \ + else \ + echo "Setting up snapshot data for $(3)..."; \ + if [ ! -d "$(1)" ]; then \ + if [ ! -f "$(1).tar.gz" ]; then \ + echo "Downloading $(1).tar.gz from $(2)..."; \ + wget -q --show-progress -O $(1).tar.gz $(2)/$(1).tar.gz || { echo "Error: download failed."; exit 1; }; \ + else \ + echo "Found existing $(1).tar.gz, skipping download."; \ + fi; \ + echo "Extracting $(1).tar.gz..."; \ + tar -xzf $(1).tar.gz || { echo "Error: extraction failed."; exit 1; }; \ + rm -f $(1).tar.gz; \ + else \ + echo "Found existing $(1)/ directory, skipping download."; \ + fi; \ + mkdir -p $(3)/geth-data $(3)/node-data/data; \ + echo "Moving geth data to $(3)/geth-data/..."; \ + mv $(1)/geth $(3)/geth-data/ || { echo "Error: failed to move geth data (may already exist)."; exit 1; }; \ + echo "Moving node data to $(3)/node-data/data/..."; \ + mv $(1)/data/* $(3)/node-data/data/ || { echo "Error: failed to move node data."; exit 1; }; \ + rm -rf $(1); \ + echo "Snapshot data ready at $(3)."; \ + fi +endef + +## quickstart targets (one-command setup and run) + +quickstart-hoodi-node: generate-jwt-hoodi + @echo "=== Quickstart: Hoodi Node (Docker) ===" + $(call setup-snapshot-data,$(HOODI_MPT_SNAPSHOT_NAME),https://snapshot.morphl2.io/hoodi,../hoodi) + docker-compose --env-file .env_hoodi up node + +quickstart-hoodi-node-binary: generate-jwt-hoodi build + @echo "=== Quickstart: Hoodi Node (Binary) ===" + $(call setup-snapshot-data,$(HOODI_MPT_SNAPSHOT_NAME),https://snapshot.morphl2.io/hoodi,../hoodi) + sh ./run-binary.sh node .env_hoodi + +quickstart-mainnet-node: generate-jwt + @echo "=== Quickstart: Mainnet Node (Docker) ===" + $(call setup-snapshot-data,$(MAINNET_MPT_SNAPSHOT_NAME),https://snapshot.morphl2.io/mainnet,../mainnet) + docker-compose --env-file .env up node + +quickstart-mainnet-node-binary: generate-jwt build + @echo "=== Quickstart: Mainnet Node (Binary) ===" + $(call setup-snapshot-data,$(MAINNET_MPT_SNAPSHOT_NAME),https://snapshot.morphl2.io/mainnet,../mainnet) + sh ./run-binary.sh node .env # Common function for download and decompress @@ -98,20 +219,18 @@ define download-and-decompress endef # Targets -download-and-decompress-holesky-snapshot: - $(call download-and-decompress,$(HOLESKY_SNAPSHOT_NAME),https://snapshot.morphl2.io/holesky) - -download-and-decompress-hoodi-snapshot: - $(call download-and-decompress,$(HOODI_SNAPSHOT_NAME),https://snapshot.morphl2.io/hoodi) download-and-decompress-mainnet-snapshot: - $(call download-and-decompress,$(MAINNET_SNAPSHOT_NAME),https://snapshot.morphl2.io/mainnet) + $(call download-and-decompress,$(MAINNET_MPT_SNAPSHOT_NAME),https://snapshot.morphl2.io/mainnet) -download-and-decompress-hoodi-mpt-snapshot: +download-and-decompress-hoodi-snapshot: $(call download-and-decompress,$(HOODI_MPT_SNAPSHOT_NAME),https://snapshot.morphl2.io/hoodi) -download-and-decompress-mainnet-mpt-snapshot: - $(call download-and-decompress,$(MAINNET_MPT_SNAPSHOT_NAME),https://snapshot.morphl2.io/mainnet) +download-and-decompress-mainnet-zk-snapshot: + $(call download-and-decompress,$(MAINNET_SNAPSHOT_NAME),https://snapshot.morphl2.io/mainnet) + +download-and-decompress-hoodi-zk-snapshot: + $(call download-and-decompress,$(HOODI_SNAPSHOT_NAME),https://snapshot.morphl2.io/hoodi) diff --git a/morph-node/bin/.gitignore b/morph-node/bin/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/morph-node/bin/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/morph-node/docker-compose.yml b/morph-node/docker-compose.yml index 050fb99..88dcc11 100644 --- a/morph-node/docker-compose.yml +++ b/morph-node/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.8' -services: - geth: +services: + geth: container_name: morph-geth image: ghcr.io/morph-l2/go-ethereum:2.2.1 restart: unless-stopped @@ -19,7 +19,7 @@ services: - MORPH_FLAG=${MORPH_FLAG} entrypoint: - "/bin/sh" - - "/entrypoint.sh" + - "/entrypoint.sh" node: container_name: morph-node @@ -39,17 +39,18 @@ services: - MORPH_NODE_L2_ENGINE_AUTH=/jwt-secret.txt - MORPH_NODE_L1_ETH_RPC=${L1_ETH_RPC} - MORPH_NODE_ROLLUP_ADDRESS=${ROLLUP_CONTRACT} + - NODE_EXTRA_FLAGS=${NODE_EXTRA_FLAGS:-} volumes: - "${MORPH_HOME}/node-data:/db" - "${JWT_SECRET_FILE}:/jwt-secret.txt" - command: > - morphnode - --home /db - --log.filename /db/node.log - ${NODE_EXTRA_FLAGS:-} + - "./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 @@ -60,19 +61,20 @@ services: - 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 need to replace it to a public network - 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_VALIDATOR_PRIVATE_KEY=0x0000000000000000000000000000000000000000000000000000000000000001 - MORPH_NODE_ROLLUP_ADDRESS=${ROLLUP_CONTRACT} - 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:-} volumes: - "${MORPH_HOME}/node-data:/db" - "${JWT_SECRET_FILE}:/jwt-secret.txt" - command: > - morphnode - --validator - --home /db + - "./entrypoint-node.sh:/entrypoint-node.sh" + entrypoint: + - "/bin/sh" + - "/entrypoint-node.sh" diff --git a/morph-node/entrypoint-geth-mpt.sh b/morph-node/entrypoint-geth-mpt.sh deleted file mode 100644 index b8603ea..0000000 --- a/morph-node/entrypoint-geth-mpt.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/sh - -if [ ! -f /jwt-secret.txt ]; then - echo "Error: jwt-secret.txt not found. Please create it before starting the service." - exit 1 -fi - -MORPH_FLAG=${MORPH_FLAG:-"morph"} - -COMMAND="geth \ ---$MORPH_FLAG \ ---morph-mpt \ ---datadir="./db" \ ---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-secret.txt" \ ---gcmode=archive \ ---log.filename=./db/geth.log \ ---metrics \ ---metrics.addr=0.0.0.0" - -eval $COMMAND diff --git a/morph-node/entrypoint-geth-zk.sh b/morph-node/entrypoint-geth-zk.sh new file mode 100644 index 0000000..f8e462e --- /dev/null +++ b/morph-node/entrypoint-geth-zk.sh @@ -0,0 +1,37 @@ +#!/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-geth.sh b/morph-node/entrypoint-geth.sh index 2370a01..64811d3 100644 --- a/morph-node/entrypoint-geth.sh +++ b/morph-node/entrypoint-geth.sh @@ -1,34 +1,38 @@ #!/bin/sh -if [ ! -f /jwt-secret.txt ]; then - echo "Error: jwt-secret.txt not found. Please create it before starting the service." +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"} - -COMMAND="geth \ ---$MORPH_FLAG \ ---datadir="./db" \ ---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-secret.txt" \ ---gcmode=archive \ ---log.filename=./db/geth.log \ ---metrics \ ---metrics.addr=0.0.0.0" +MORPH_FLAG=${MORPH_FLAG:-"morph"} -eval $COMMAND +exec "${GETH_BIN}" \ + "--${MORPH_FLAG}" \ + --morph-mpt \ + "--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 new file mode 100755 index 0000000..e0cb16d --- /dev/null +++ b/morph-node/entrypoint-node.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +NODE_BIN=${NODE_BINARY:-morphnode} +NODE_HOME=${NODE_HOME:-/db} +JWT_PATH=${JWT_SECRET_PATH:-/jwt-secret.txt} + +# L2 connection defaults (localhost for binary mode; Docker overrides via environment section) +export MORPH_NODE_L2_ETH_RPC=${MORPH_NODE_L2_ETH_RPC:-http://localhost:8545} +export MORPH_NODE_L2_ENGINE_RPC=${MORPH_NODE_L2_ENGINE_RPC:-http://localhost:8551} +export MORPH_NODE_L2_ENGINE_AUTH=${MORPH_NODE_L2_ENGINE_AUTH:-${JWT_PATH}} + +# Map .env variables to MORPH_NODE_* for binary mode (Docker sets these directly) +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 +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:-}} +export MORPH_NODE_VALIDATOR_PRIVATE_KEY=${MORPH_NODE_VALIDATOR_PRIVATE_KEY:-${VALIDATOR_PRIVATE_KEY:-}} +export MORPH_NODE_DERIVATION_START_HEIGHT=${MORPH_NODE_DERIVATION_START_HEIGHT:-${DERIVATION_START_HEIGHT:-}} +export MORPH_NODE_DERIVATION_BASE_HEIGHT=${MORPH_NODE_DERIVATION_BASE_HEIGHT:-${L2_BASE_HEIGHT:-}} +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:-}} + +COMMAND="${NODE_BIN} \ +--home ${NODE_HOME} \ +--log.filename ${NODE_HOME}/node.log \ +${NODE_EXTRA_FLAGS:-}" + +eval $COMMAND diff --git a/morph-node/run-binary.sh b/morph-node/run-binary.sh new file mode 100755 index 0000000..8b9daca --- /dev/null +++ b/morph-node/run-binary.sh @@ -0,0 +1,116 @@ +#!/bin/sh + +# Usage: run-binary.sh [override-env-file] +# mode: node | validator +# env-file: .env | .env_hoodi +# override-env-file: optional, e.g. .env_zk for ZK legacy mode + +MODE=${1:-node} +ENV_FILE=${2:-.env} +OVERRIDE_ENV_FILE=${3:-} + +# Source environment +set -a +. ./${ENV_FILE} +if [ -n "${OVERRIDE_ENV_FILE}" ]; then + . ./${OVERRIDE_ENV_FILE} +fi +set +a + +GETH_BINARY=${GETH_BINARY:-./bin/geth} +NODE_BINARY=${NODE_BINARY:-./bin/morphnode} + +# Check binaries +if [ ! -f "${GETH_BINARY}" ]; then + echo "Error: geth binary not found at ${GETH_BINARY}" + echo "Please download and place it in the bin/ directory." + exit 1 +fi + +if [ ! -f "${NODE_BINARY}" ]; then + echo "Error: morphnode binary not found at ${NODE_BINARY}" + echo "Please download and place it in the bin/ directory." + exit 1 +fi + +# Ensure data directories exist +mkdir -p "${MORPH_HOME}/geth-data" +mkdir -p "${MORPH_HOME}/node-data" + +# Cleanup on exit +cleanup() { + echo "" + echo "Stopping..." + [ -n "${GETH_PID:-}" ] && kill ${GETH_PID} 2>/dev/null + [ -n "${NODE_PID:-}" ] && kill ${NODE_PID} 2>/dev/null + rm -f .geth.pid .node.pid + exit +} +trap cleanup INT TERM + +# Validate entrypoint file +case "${GETH_ENTRYPOINT_FILE}" in + ./entrypoint-geth.sh|./entrypoint-geth-zk.sh) ;; + *) + echo "Error: invalid GETH_ENTRYPOINT_FILE: ${GETH_ENTRYPOINT_FILE}" + exit 1 + ;; +esac + +# Start geth +echo "Starting geth..." +GETH_BINARY=${GETH_BINARY} \ +GETH_DATADIR=${MORPH_HOME}/geth-data \ +JWT_SECRET_PATH=${JWT_SECRET_FILE} \ +MORPH_FLAG=${MORPH_FLAG} \ +sh ./${GETH_ENTRYPOINT_FILE} & +GETH_PID=$! +echo "${GETH_PID}" > .geth.pid + +# Wait for geth engine RPC (port 8551) +echo "Waiting for geth to be ready..." +for i in $(seq 1 30); do + if nc -z localhost 8551 2>/dev/null; then + echo "Geth is ready." + break + fi + if ! kill -0 ${GETH_PID} 2>/dev/null; then + echo "Error: geth process exited unexpectedly." + rm -f .geth.pid + exit 1 + fi + sleep 1 +done + +if ! nc -z localhost 8551 2>/dev/null; then + echo "Error: geth did not become ready within 30 seconds." + cleanup + 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)..." +NODE_BINARY=${NODE_BINARY} \ +NODE_HOME=${MORPH_HOME}/node-data \ +JWT_SECRET_PATH=${JWT_SECRET_FILE} \ +NODE_EXTRA_FLAGS="${NODE_EXTRA_FLAGS:-}" \ +sh ./entrypoint-node.sh & +NODE_PID=$! +echo "${NODE_PID}" > .node.pid + +echo "" +echo "=========================================" +echo " geth PID: ${GETH_PID}" +echo " morphnode PID: ${NODE_PID}" +echo " geth log: ${MORPH_HOME}/geth-data/geth.log" +echo " node log: ${MORPH_HOME}/node-data/node.log" +echo "=========================================" +echo "Press Ctrl+C to stop both processes." +echo "" + +wait