Skip to content
Open
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
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,9 @@ contracts/mainnet.json
.env

# logs
*.log
*.log

# mpt-switch-test data
ops/mpt-switch-test/.testdata
ops/mpt-switch-test/bin
ops/mpt-switch-test/local-test/geth-data
9 changes: 9 additions & 0 deletions node/core/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ var (
)

type Config struct {
L2Legacy *types.L2Config `json:"l_2_legacy"`
L2 *types.L2Config `json:"l2"`
MptTime uint64 `json:"mpt_time"`
L2CrossDomainMessengerAddress common.Address `json:"cross_domain_messenger_address"`
SequencerAddress common.Address `json:"sequencer_address"`
GovAddress common.Address `json:"gov_address"`
Expand All @@ -42,6 +44,7 @@ type Config struct {
func DefaultConfig() *Config {
return &Config{
L2: new(types.L2Config),
L2Legacy: new(types.L2Config),
Logger: tmlog.NewTMLogger(tmlog.NewSyncWriter(os.Stdout)),
MaxL1MessageNumPerBlock: 100,
L2CrossDomainMessengerAddress: predeploys.L2CrossDomainMessengerAddr,
Expand Down Expand Up @@ -122,6 +125,12 @@ func (c *Config) SetCliContext(ctx *cli.Context) error {
c.L2.EngineAddr = l2EngineAddr
c.L2.JwtSecret = secret

l2LegacyEthAddr := ctx.GlobalString(flags.L2LegacyEthAddr.Name)
l2LegacyEngineAddr := ctx.GlobalString(flags.L2LegacyEngineAddr.Name)
c.L2Legacy.EthAddr = l2LegacyEthAddr
c.L2Legacy.EngineAddr = l2LegacyEngineAddr
c.L2Legacy.JwtSecret = secret // same secret
c.MptTime = ctx.GlobalUint64(flags.MptTime.Name)
if ctx.GlobalIsSet(flags.MaxL1MessageNumPerBlock.Name) {
c.MaxL1MessageNumPerBlock = ctx.GlobalUint64(flags.MaxL1MessageNumPerBlock.Name)
if c.MaxL1MessageNumPerBlock == 0 {
Expand Down
30 changes: 27 additions & 3 deletions node/core/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,15 @@ func getNextL1MsgIndex(client *types.RetryableClient) (uint64, error) {
func NewExecutor(newSyncFunc NewSyncerFunc, config *Config, tmPubKey crypto.PubKey) (*Executor, error) {
logger := config.Logger
logger = logger.With("module", "executor")
// legacy zk endpoint
laClient, err := authclient.DialContext(context.Background(), config.L2Legacy.EngineAddr, config.L2Legacy.JwtSecret)
if err != nil {
return nil, err
}
leClient, err := ethclient.Dial(config.L2Legacy.EthAddr)
if err != nil {
return nil, err
}
aClient, err := authclient.DialContext(context.Background(), config.L2.EngineAddr, config.L2.JwtSecret)
if err != nil {
return nil, err
Expand All @@ -79,7 +88,7 @@ func NewExecutor(newSyncFunc NewSyncerFunc, config *Config, tmPubKey crypto.PubK
return nil, err
}

l2Client := types.NewRetryableClient(aClient, eClient, config.Logger)
l2Client := types.NewRetryableClient(laClient, leClient, aClient, eClient, config.MptTime, config.Logger)
index, err := getNextL1MsgIndex(l2Client)
if err != nil {
return nil, err
Expand Down Expand Up @@ -276,7 +285,10 @@ func (e *Executor) DeliverBlock(txs [][]byte, metaData []byte, consensusData l2n
}

if wrappedBlock.Number <= height {
e.logger.Info("ignore it, the block was delivered", "block number", wrappedBlock.Number)
e.logger.Info("block already delivered by geth (via P2P sync)", "block_number", wrappedBlock.Number)
// Even if block was already delivered (e.g., synced via P2P), we still need to check
// if MPT switch should happen, otherwise sentry nodes won't switch to the correct geth.
e.l2Client.EnsureSwitched(context.Background(), wrappedBlock.Timestamp, wrappedBlock.Number)
if e.devSequencer {
return nil, consensusData.ValidatorSet, nil
}
Expand All @@ -286,6 +298,10 @@ func (e *Executor) DeliverBlock(txs [][]byte, metaData []byte, consensusData l2n
// We only accept the continuous blocks for now.
// It acts like full sync. Snap sync is not enabled until the Geth enables snapshot with zkTrie
if wrappedBlock.Number > height+1 {
e.logger.Error("!!! CRITICAL: Geth is behind - node BLOCKED !!!",
"consensus_block", wrappedBlock.Number,
"geth_height", height,
"action", "Switch to MPT-compatible geth IMMEDIATELY")
return nil, nil, types.ErrWrongBlockNumber
}

Expand Down Expand Up @@ -317,7 +333,15 @@ func (e *Executor) DeliverBlock(txs [][]byte, metaData []byte, consensusData l2n
}
err = e.l2Client.NewL2Block(context.Background(), l2Block, batchHash)
if err != nil {
e.logger.Error("failed to NewL2Block", "error", err)
e.logger.Error("========================================")
e.logger.Error("CRITICAL: Failed to deliver block to geth!")
e.logger.Error("========================================")
e.logger.Error("failed to NewL2Block",
"error", err,
"block_number", l2Block.Number,
"block_timestamp", l2Block.Timestamp)
e.logger.Error("HINT: If this occurs after MPT upgrade, your geth node may not support MPT blocks. " +
"Please ensure you are running an MPT-compatible geth node.")
return nil, nil, err
}

Expand Down
5 changes: 5 additions & 0 deletions node/core/sequencers.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ func (e *Executor) VerifySignature(tmPubKey []byte, messageHash []byte, blsSig [
e.logger.Info("we are in dev mode, do not verify the bls signature")
return true, nil
}
//// Skip BLS verification for non-sequencer nodes (they may not have correct sequencer set from their geth)
//if !e.isSequencer {
// e.logger.Debug("non-sequencer node, skip bls signature verification")
// return true, nil
//}
if len(e.valsByTmKey) == 0 {
return false, errors.New("no available sequencers found in layer2")
}
Expand Down
8 changes: 8 additions & 0 deletions node/derivation/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ const (

type Config struct {
L1 *types.L1Config `json:"l1"`
L2Legacy *types.L2Config `json:"l2_legacy"`
L2 *types.L2Config `json:"l2"`
MptTime uint64 `json:"mpt_time"`
BeaconRpc string `json:"beacon_rpc"`
RollupContractAddress common.Address `json:"rollup_contract_address"`
StartHeight uint64 `json:"start_height"`
Expand Down Expand Up @@ -135,6 +137,12 @@ func (c *Config) SetCliContext(ctx *cli.Context) error {
c.L2.EthAddr = l2EthAddr
c.L2.EngineAddr = l2EngineAddr
c.L2.JwtSecret = secret
l2LegacyEthAddr := ctx.GlobalString(flags.L2LegacyEthAddr.Name)
l2LegacyEngineAddr := ctx.GlobalString(flags.L2LegacyEngineAddr.Name)
c.L2Legacy.EthAddr = l2LegacyEthAddr
c.L2Legacy.EngineAddr = l2LegacyEngineAddr
c.L2Legacy.JwtSecret = secret // same secret
c.MptTime = ctx.GlobalUint64(flags.L2LegacyEthAddr.Name)
c.MetricsServerEnable = ctx.GlobalBool(flags.MetricsServerEnable.Name)
c.MetricsHostname = ctx.GlobalString(flags.MetricsHostname.Name)
c.MetricsPort = ctx.GlobalUint64(flags.MetricsPort.Name)
Expand Down
11 changes: 10 additions & 1 deletion node/derivation/derivation.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ func NewDerivationClient(ctx context.Context, cfg *Config, syncer *sync.Syncer,
if err != nil {
return nil, err
}
// legacy zk endpoint
laClient, err := authclient.DialContext(context.Background(), cfg.L2Legacy.EngineAddr, cfg.L2Legacy.JwtSecret)
if err != nil {
return nil, err
}
leClient, err := ethclient.Dial(cfg.L2Legacy.EthAddr)
if err != nil {
return nil, err
}
aClient, err := authclient.DialContext(context.Background(), cfg.L2.EngineAddr, cfg.L2.JwtSecret)
if err != nil {
return nil, err
Expand Down Expand Up @@ -129,7 +138,7 @@ func NewDerivationClient(ctx context.Context, cfg *Config, syncer *sync.Syncer,
logger: logger,
RollupContractAddress: cfg.RollupContractAddress,
confirmations: cfg.L1.Confirmations,
l2Client: types.NewRetryableClient(aClient, eClient, tmlog.NewTMLogger(tmlog.NewSyncWriter(os.Stdout))),
l2Client: types.NewRetryableClient(laClient, leClient, aClient, eClient, cfg.MptTime, tmlog.NewTMLogger(tmlog.NewSyncWriter(os.Stdout))),
cancel: cancel,
stop: make(chan struct{}),
startHeight: cfg.StartHeight,
Expand Down
21 changes: 21 additions & 0 deletions node/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,24 @@ var (
EnvVar: prefixEnvVar("L2_ENGINE_RPC"),
}

L2LegacyEthAddr = cli.StringFlag{
Name: "l2legacy.eth",
Usage: "Address of L2 legacy Engine JSON-RPC endpoints to use (eth namespace required)",
EnvVar: prefixEnvVar("L2_LEGACY_ETH_RPC"),
}

L2LegacyEngineAddr = cli.StringFlag{
Name: "l2legacy.engine",
Usage: "Address of L2 legacy Engine JSON-RPC endpoints to use (engine namespace required)",
EnvVar: prefixEnvVar("L2_LEGACY_ENGINE_RPC"),
}

MptTime = cli.Uint64Flag{
Name: "upgrade.mptTime",
Usage: "Batch index at which the sequencers start to upgrade the batch format",
EnvVar: prefixEnvVar("MPT_TIME"),
}
Comment on lines +43 to +47
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the flags.go file and examine the MptTime flag and UpgradeBatchTime flag
find . -name "flags.go" -type f | grep -E "node.*flags" | head -5

Repository: morph-l2/morph

Length of output: 79


🏁 Script executed:

# Check if node/flags/flags.go exists and read it
if [ -f "node/flags/flags.go" ]; then
  echo "=== Lines 43-47 (MptTime) ===" 
  sed -n '43,47p' node/flags/flags.go
  echo ""
  echo "=== Lines 240-250 (around UpgradeBatchTime) ===" 
  sed -n '240,250p' node/flags/flags.go
else
  echo "File not found. Searching for flags files:"
  find . -name "flags.go" -type f 2>/dev/null | head -10
fi

Repository: morph-l2/morph

Length of output: 608


Rename MptTime to clarify it represents a batch index, and distinguish its usage description from UpgradeBatchTime.

The flag name MptTime is misleading since it uses a "Time" suffix despite representing a batch index. Additionally, both MptTime and UpgradeBatchTime have identical usage text ("Batch index at which the sequencers start to upgrade the batch format"), which obscures their different purposes.

Consider:

  1. Renaming to reflect the batch index nature (e.g., MptUpgradeBatchIndex or MptSwitchBatchIndex)
  2. Updating the usage text to clarify the MPT-specific distinction (e.g., "Batch index at which sequencers switch from legacy to MPT-based batch format")
🤖 Prompt for AI Agents
In node/flags/flags.go around lines 43-47, the MptTime identifier and its Usage
text are misleading because the suffix "Time" suggests a timestamp while the
flag actually holds a batch index and duplicates the Usage of UpgradeBatchTime;
rename the flag to something clear (e.g., MptUpgradeBatchIndex or
MptSwitchBatchIndex), update the Usage string to explicitly state it is an
MPT-specific batch index (for example: "Batch index at which sequencers switch
from legacy to MPT-based batch format"), change the EnvVar key passed to
prefixEnvVar to a matching name, and update every reference in the codebase to
the new identifier and env var name to keep behavior consistent.


L2EngineJWTSecret = cli.StringFlag{
Name: "l2.jwt-secret",
Usage: "Path to JWT secret key. Keys are 32 bytes, hex encoded in a file. A new key will be generated if left empty.",
Expand Down Expand Up @@ -304,6 +322,9 @@ var Flags = []cli.Flag{
L2EthAddr,
L2EngineAddr,
L2EngineJWTSecret,
L2LegacyEthAddr,
L2LegacyEngineAddr,
MptTime,
MaxL1MessageNumPerBlock,
L2CrossDomainMessengerContractAddr,
L2SequencerAddr,
Expand Down
2 changes: 1 addition & 1 deletion node/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ require (
github.com/hashicorp/golang-lru v1.0.2
github.com/holiman/uint256 v1.2.4
github.com/klauspost/compress v1.17.9
github.com/morph-l2/go-ethereum v1.10.14-0.20251203083507-49fa27bcab24
github.com/morph-l2/go-ethereum v1.10.14-0.20251211075654-796834acba86
github.com/prometheus/client_golang v1.17.0
github.com/spf13/viper v1.13.0
github.com/stretchr/testify v1.10.0
Expand Down
4 changes: 2 additions & 2 deletions node/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@ github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqky
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/morph-l2/go-ethereum v1.10.14-0.20251203083507-49fa27bcab24 h1:r9eaQDNgjAxsuUchmoCFaAjL1TmUfjAmIlJjAtgUk8U=
github.com/morph-l2/go-ethereum v1.10.14-0.20251203083507-49fa27bcab24/go.mod h1:tiFPeidxjoCmLj18ne9H3KQdIGTCvRC30qlef06Fd9M=
github.com/morph-l2/go-ethereum v1.10.14-0.20251211075654-796834acba86 h1:4BgRnW5lZcgtVvK/WuDTNAfi5F5/VEb7FbDEvCksPHk=
github.com/morph-l2/go-ethereum v1.10.14-0.20251211075654-796834acba86/go.mod h1:tiFPeidxjoCmLj18ne9H3KQdIGTCvRC30qlef06Fd9M=
github.com/morph-l2/tendermint v0.3.2 h1:Gu6Uj2G6c3YP2NAKFi7A46JZaOCdD4zfZDKCjt0pDm8=
github.com/morph-l2/tendermint v0.3.2/go.mod h1:TtCzp9l6Z6yDUiwv3TbqKqw8Q8RKp3fSz5+adO1/Y8w=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
Expand Down
Loading