From 558f5ab63cca246bc165ba32d119cd6b984f9571 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Garamv=C3=B6lgyi?= Date: Sun, 29 Jun 2025 10:24:20 +0200 Subject: [PATCH 01/17] wip --- rollup/abi/validium_abi.go | 22 +++++++ .../internal/controller/relayer/l2_relayer.go | 58 ++++++++++++++++--- rollup/internal/utils/utils.go | 24 ++++++++ 3 files changed, 97 insertions(+), 7 deletions(-) create mode 100644 rollup/abi/validium_abi.go diff --git a/rollup/abi/validium_abi.go b/rollup/abi/validium_abi.go new file mode 100644 index 0000000000..37bd6189e2 --- /dev/null +++ b/rollup/abi/validium_abi.go @@ -0,0 +1,22 @@ +package bridgeabi + +import ( + "github.com/scroll-tech/go-ethereum/accounts/abi" + "github.com/scroll-tech/go-ethereum/accounts/abi/bind" +) + +var ( + // ValidiumABI holds information about Validium's context and available invokable methods. + ValidiumABI *abi.ABI +) + +func init() { + ValidiumABI, _ = ValidiumMetaData.GetAbi() +} + +// Generated manually from abigen. + +// ValidiumMetaData contains all meta data concerning the ScrollChain contract. +var ValidiumMetaData = &bind.MetaData{ + ABI: "[{\"type\":\"function\",\"name\":\"commitAndFinalizeBatch\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"finalizeStruct\",\"type\":\"tuple\",\"internalType\":\"struct ScrollChainInterface.FinalizeStruct\",\"components\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"zkProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"commitBatchWithBlobProof\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"chunks\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"skippedL1MessageBitmap\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"blobDataProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"commitBatches\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"lastBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatch\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_prevStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatch4844\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_blobDataProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatchWithProof\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"prevStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatchWithProof4844\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"prevStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"blobDataProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundlePostEuclidV2\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundlePostEuclidV2NoProof\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundleWithProof\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeEuclidInitialBatch\",\"inputs\":[{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"importGenesisBatch\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revertBatch\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"count\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revertBatch\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"CommitBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FinalizeBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RevertBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RevertBatch\",\"inputs\":[{\"name\":\"startBatchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"finishBatchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdateEnforcedBatchMode\",\"inputs\":[{\"name\":\"enabled\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"},{\"name\":\"lastCommittedBatchIndex\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"function\",\"name\":\"commitBatch\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"commitment\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundle\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"}]", +} diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 470b8e5d05..b3304cd48d 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -79,6 +79,7 @@ type Layer2Relayer struct { commitSender *sender.Sender finalizeSender *sender.Sender l1RollupABI *abi.ABI + validiumABI *abi.ABI l2GasOracleABI *abi.ABI @@ -172,6 +173,7 @@ func NewLayer2Relayer(ctx context.Context, l2Client *ethclient.Client, db *gorm. commitSender: commitSender, finalizeSender: finalizeSender, l1RollupABI: bridgeAbi.ScrollChainABI, + validiumABI: bridgeAbi.ValidiumABI, l2GasOracleABI: bridgeAbi.L2GasPriceOracleABI, batchStrategy: strategy, @@ -259,9 +261,12 @@ func (r *Layer2Relayer) initializeGenesis() error { return fmt.Errorf("failed to update genesis batch rollup status: %v", err) } + // validium version + // ... + // commit genesis batch on L1 // note: we do this inside the DB transaction so that we can revert all DB changes if this step fails - return r.commitGenesisBatch(dbBatch.Hash, dbBatch.BatchHeader, common.HexToHash(dbBatch.StateRoot)) + return r.commitGenesisBatch(dbBatch.Hash, dbBatch.BatchHeader) }) if err != nil { @@ -273,13 +278,15 @@ func (r *Layer2Relayer) initializeGenesis() error { return nil } -func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte, stateRoot common.Hash) error { +func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte) error { // encode "importGenesisBatch" transaction calldata - calldata, packErr := r.l1RollupABI.Pack("importGenesisBatch", batchHeader, stateRoot) + calldata, packErr := r.validiumABI.Pack("importGenesisBatch", batchHeader) if packErr != nil { - return fmt.Errorf("failed to pack importGenesisBatch with batch header: %v and state root: %v. error: %v", common.Bytes2Hex(batchHeader), stateRoot, packErr) + return fmt.Errorf("failed to pack importGenesisBatch with batch header: %v. error: %v", common.Bytes2Hex(batchHeader), packErr) } + log.Warn("Validium importGenesis", "calldata", common.Bytes2Hex(calldata)) + // submit genesis batch to L1 rollup contract txHash, _, err := r.commitSender.SendTransaction(batchHash, &r.cfg.RollupContractAddress, calldata, nil) if err != nil { @@ -467,9 +474,14 @@ func (r *Layer2Relayer) ProcessPendingBatches() { codecVersion := encoding.CodecVersion(firstBatch.CodecVersion) switch codecVersion { case encoding.CodecV7: - calldata, blobs, maxBlockHeight, totalGasUsed, err = r.constructCommitBatchPayloadCodecV7(batchesToSubmit, firstBatch, lastBatch) + // calldata, blobs, maxBlockHeight, totalGasUsed, err = r.constructCommitBatchPayloadCodecV7(batchesToSubmit, firstBatch, lastBatch) + // if err != nil { + // log.Error("failed to construct constructCommitBatchPayloadCodecV7 payload for V7", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "err", err) + // return + // } + calldata, blobs, maxBlockHeight, totalGasUsed, err = r.constructCommitBatchPayloadValidium(batchesToSubmit, firstBatch) if err != nil { - log.Error("failed to construct constructCommitBatchPayloadCodecV7 payload for V7", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "err", err) + log.Error("failed to construct constructCommitBatchPayloadValidium payload for V7", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "err", err) return } default: @@ -694,7 +706,11 @@ func (r *Layer2Relayer) finalizeBundle(bundle *orm.Bundle, withProof bool) error var calldata []byte switch encoding.CodecVersion(bundle.CodecVersion) { case encoding.CodecV7: - calldata, err = r.constructFinalizeBundlePayloadCodecV7(dbBatch, endChunk, aggProof) + // calldata, err = r.constructFinalizeBundlePayloadCodecV7(dbBatch, endChunk, aggProof) + // if err != nil { + // return fmt.Errorf("failed to construct finalizeBundle payload codecv7, bundle index: %v, last batch index: %v, err: %w", bundle.Index, dbBatch.Index, err) + // } + calldata, err = r.constructFinalizeBundlePayloadValidium(dbBatch, endChunk, aggProof) if err != nil { return fmt.Errorf("failed to construct finalizeBundle payload codecv7, bundle index: %v, last batch index: %v, err: %w", bundle.Index, dbBatch.Index, err) } @@ -955,6 +971,19 @@ func (r *Layer2Relayer) constructCommitBatchPayloadCodecV7(batchesToSubmit []*db return calldata, blobs, maxBlockHeight, totalGasUsed, nil } +func (r *Layer2Relayer) constructCommitBatchPayloadValidium(batchesToSubmit []*dbBatchWithChunksAndParent, batch *orm.Batch) ([]byte, []*kzg4844.Blob, uint64, uint64, error) { + var maxBlockHeight uint64 + var totalGasUsed uint64 + + version := encoding.CodecVersion(batchesToSubmit[0].Batch.CodecVersion) + commitment := common.Hash{} // todo + calldata, err := r.validiumABI.Pack("commitBatch", version, common.HexToHash(batch.ParentBatchHash), common.HexToHash(batch.StateRoot), common.HexToHash(batch.WithdrawRoot), commitment[:]) + if err != nil { + return nil, nil, 0, 0, fmt.Errorf("failed to pack commitBatches: %w", err) + } + return calldata, nil, maxBlockHeight, totalGasUsed, nil +} + func (r *Layer2Relayer) constructFinalizeBundlePayloadCodecV7(dbBatch *orm.Batch, endChunk *orm.Chunk, aggProof *message.OpenVMBundleProof) ([]byte, error) { if aggProof != nil { // finalizeBundle with proof. calldata, packErr := r.l1RollupABI.Pack( @@ -986,6 +1015,21 @@ func (r *Layer2Relayer) constructFinalizeBundlePayloadCodecV7(dbBatch *orm.Batch return calldata, nil } +func (r *Layer2Relayer) constructFinalizeBundlePayloadValidium(dbBatch *orm.Batch, endChunk *orm.Chunk, aggProof *message.OpenVMBundleProof) ([]byte, error) { + fmt.Println("packing finalizeBundle", len(dbBatch.BatchHeader), dbBatch.CodecVersion, dbBatch.BatchHeader, new(big.Int).SetUint64(endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk), common.HexToHash(dbBatch.StateRoot), common.HexToHash(dbBatch.WithdrawRoot)) + // finalizeBundle without proof. + calldata, packErr := r.validiumABI.Pack( + "finalizeBundle", + dbBatch.BatchHeader, + new(big.Int).SetUint64(endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk), + []byte{}, + ) + if packErr != nil { + return nil, fmt.Errorf("failed to pack finalizeBundlePostEuclidV2NoProof: %w", packErr) + } + return calldata, nil +} + // StopSenders stops the senders of the rollup-relayer to prevent querying the removed pending_transaction table in unit tests. // for unit test func (r *Layer2Relayer) StopSenders() { diff --git a/rollup/internal/utils/utils.go b/rollup/internal/utils/utils.go index 65b92c32c0..a67150323b 100644 --- a/rollup/internal/utils/utils.go +++ b/rollup/internal/utils/utils.go @@ -1,11 +1,13 @@ package utils import ( + "encoding/binary" "fmt" "time" "github.com/scroll-tech/da-codec/encoding" "github.com/scroll-tech/go-ethereum/common" + "github.com/scroll-tech/go-ethereum/crypto" ) // ChunkMetrics indicates the metrics for proposing a chunk. @@ -117,6 +119,22 @@ type BatchMetadata struct { ChallengeDigest common.Hash } +func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVersion) []byte { + emptyHash := common.Hash{} + + batchBytes := make([]byte, 105+32) // todo: commitment + batchBytes[0] = uint8(codecVersion) // version + binary.BigEndian.PutUint64(batchBytes[1:9], b.Index) // batch index + copy(batchBytes[9:41], b.ParentBatchHash[0:32]) // parentBatchHash + copy(batchBytes[41:73], b.StateRoot().Bytes()[0:32]) // postStateRoot + copy(batchBytes[73:105], b.WithdrawRoot().Bytes()[0:32]) // postWithdrawRoot + copy(batchBytes[105:137], emptyHash[0:32]) // data commitment + return batchBytes +} + +// // func hashBatchHeaderValidium() +// return crypto.Keccak256Hash(b.Encode()) + // GetBatchMetadata retrieves the metadata of a batch. func GetBatchMetadata(batch *encoding.Batch, codecVersion encoding.CodecVersion) (*BatchMetadata, error) { codec, err := encoding.CodecFromVersion(codecVersion) @@ -137,6 +155,12 @@ func GetBatchMetadata(batch *encoding.Batch, codecVersion encoding.CodecVersion) ChallengeDigest: daBatch.ChallengeDigest(), } + // validium + encoded := encodeBatchHeaderValidium(batch, codecVersion) + hash := crypto.Keccak256Hash(encoded) + batchMeta.BatchBytes = encoded + batchMeta.BatchHash = hash + batchMeta.BatchBlobDataProof, err = daBatch.BlobDataProofForPointEvaluation() if err != nil { return nil, fmt.Errorf("failed to get blob data proof, version: %v, err: %w", codecVersion, err) From fc5c8fb51cc2e9b2f76c73d3148304259ea40dbc Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Mon, 7 Jul 2025 16:24:57 +0800 Subject: [PATCH 02/17] merge validium features into rollup-relayer --- rollup/cmd/rollup_relayer/app/app.go | 1 + rollup/conf/config.json | 3 +- rollup/internal/config/relayer.go | 2 + .../internal/controller/relayer/l2_relayer.go | 111 ++++++++++++------ .../controller/watcher/batch_proposer.go | 17 ++- rollup/internal/orm/batch.go | 2 +- rollup/internal/utils/utils.go | 36 +++--- 7 files changed, 114 insertions(+), 58 deletions(-) diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index 168b58aeed..44096fcd81 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -108,6 +108,7 @@ func action(ctx *cli.Context) error { chunkProposer := watcher.NewChunkProposer(subCtx, cfg.L2Config.ChunkProposerConfig, minCodecVersion, genesis.Config, db, registry) batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, minCodecVersion, genesis.Config, db, registry) + batchProposer.SetValidiumMode(cfg.L2Config.RelayerConfig.ValidiumMode) bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, minCodecVersion, genesis.Config, db, registry) l2watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) diff --git a/rollup/conf/config.json b/rollup/conf/config.json index fbc942f6ee..c4133df485 100644 --- a/rollup/conf/config.json +++ b/rollup/conf/config.json @@ -36,6 +36,7 @@ "endpoint": "https://rpc.scroll.io", "l2_message_queue_address": "0x0000000000000000000000000000000000000000", "relayer_config": { + "validium_mode": false, "rollup_contract_address": "0x0000000000000000000000000000000000000000", "gas_price_oracle_address": "0x0000000000000000000000000000000000000000", "sender_config": { @@ -121,4 +122,4 @@ "maxOpenNum": 200, "maxIdleNum": 20 } -} \ No newline at end of file +} diff --git a/rollup/internal/config/relayer.go b/rollup/internal/config/relayer.go index bb1c7e2235..bf93f2f575 100644 --- a/rollup/internal/config/relayer.go +++ b/rollup/internal/config/relayer.go @@ -53,6 +53,8 @@ type ChainMonitor struct { // RelayerConfig loads relayer configuration items. // What we need to pay attention to is that type RelayerConfig struct { + // ValidiumMode indicates if the relayer is in validium mode. + ValidiumMode bool `json:"validium_mode"` // RollupContractAddress store the rollup contract address. RollupContractAddress common.Address `json:"rollup_contract_address,omitempty"` // GasPriceOracleContractAddress store the scroll messenger contract address. diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index b3304cd48d..977369845f 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -261,12 +261,9 @@ func (r *Layer2Relayer) initializeGenesis() error { return fmt.Errorf("failed to update genesis batch rollup status: %v", err) } - // validium version - // ... - // commit genesis batch on L1 // note: we do this inside the DB transaction so that we can revert all DB changes if this step fails - return r.commitGenesisBatch(dbBatch.Hash, dbBatch.BatchHeader) + return r.commitGenesisBatch(dbBatch.Hash, dbBatch.BatchHeader, common.HexToHash(dbBatch.StateRoot)) }) if err != nil { @@ -278,21 +275,32 @@ func (r *Layer2Relayer) initializeGenesis() error { return nil } -func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte) error { - // encode "importGenesisBatch" transaction calldata - calldata, packErr := r.validiumABI.Pack("importGenesisBatch", batchHeader) - if packErr != nil { - return fmt.Errorf("failed to pack importGenesisBatch with batch header: %v. error: %v", common.Bytes2Hex(batchHeader), packErr) - } +func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte, stateRoot common.Hash) error { + var calldata []byte + var packErr error - log.Warn("Validium importGenesis", "calldata", common.Bytes2Hex(calldata)) + if r.cfg.ValidiumMode { + // validium mode: only pass batchHeader + calldata, packErr = r.validiumABI.Pack("importGenesisBatch", batchHeader) + if packErr != nil { + return fmt.Errorf("failed to pack validium importGenesisBatch with batch header: %v. error: %v", common.Bytes2Hex(batchHeader), packErr) + } + log.Info("Validium importGenesis", "calldata", common.Bytes2Hex(calldata)) + } else { + // normal rollup mode: pass batchHeader and stateRoot + calldata, packErr = r.l1RollupABI.Pack("importGenesisBatch", batchHeader, stateRoot) + if packErr != nil { + return fmt.Errorf("failed to pack rollup importGenesisBatch with batch header: %v and state root: %v. error: %v", common.Bytes2Hex(batchHeader), stateRoot, packErr) + } + log.Info("Rollup importGenesis", "calldata", common.Bytes2Hex(calldata), "stateRoot", stateRoot) + } // submit genesis batch to L1 rollup contract txHash, _, err := r.commitSender.SendTransaction(batchHash, &r.cfg.RollupContractAddress, calldata, nil) if err != nil { return fmt.Errorf("failed to send import genesis batch tx to L1, error: %v", err) } - log.Info("importGenesisBatch transaction sent", "contract", r.cfg.RollupContractAddress, "txHash", txHash, "batchHash", batchHash) + log.Info("importGenesisBatch transaction sent", "contract", r.cfg.RollupContractAddress, "txHash", txHash, "batchHash", batchHash, "validium", r.cfg.ValidiumMode) // wait for confirmation // we assume that no other transactions are sent before initializeGenesis completes @@ -317,7 +325,7 @@ func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte) if !confirmation.IsSuccessful { return errors.New("import genesis batch tx failed") } - log.Info("Successfully committed genesis batch on L1", "txHash", confirmation.TxHash.String()) + log.Info("Successfully committed genesis batch on L1", "txHash", confirmation.TxHash.String(), "validium", r.cfg.ValidiumMode) return nil } } @@ -474,15 +482,18 @@ func (r *Layer2Relayer) ProcessPendingBatches() { codecVersion := encoding.CodecVersion(firstBatch.CodecVersion) switch codecVersion { case encoding.CodecV7: - // calldata, blobs, maxBlockHeight, totalGasUsed, err = r.constructCommitBatchPayloadCodecV7(batchesToSubmit, firstBatch, lastBatch) - // if err != nil { - // log.Error("failed to construct constructCommitBatchPayloadCodecV7 payload for V7", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "err", err) - // return - // } - calldata, blobs, maxBlockHeight, totalGasUsed, err = r.constructCommitBatchPayloadValidium(batchesToSubmit, firstBatch) - if err != nil { - log.Error("failed to construct constructCommitBatchPayloadValidium payload for V7", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "err", err) - return + if r.cfg.ValidiumMode { + calldata, maxBlockHeight, totalGasUsed, err = r.constructCommitBatchPayloadValidium(batchesToSubmit, firstBatch) + if err != nil { + log.Error("failed to construct validium payload for V7", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "err", err) + return + } + } else { + calldata, blobs, maxBlockHeight, totalGasUsed, err = r.constructCommitBatchPayloadCodecV7(batchesToSubmit, firstBatch, lastBatch) + if err != nil { + log.Error("failed to construct normal payload for V7", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "err", err) + return + } } default: log.Error("unsupported codec version in ProcessPendingBatches", "codecVersion", codecVersion, "start index", firstBatch, "end index", lastBatch.Index) @@ -706,13 +717,16 @@ func (r *Layer2Relayer) finalizeBundle(bundle *orm.Bundle, withProof bool) error var calldata []byte switch encoding.CodecVersion(bundle.CodecVersion) { case encoding.CodecV7: - // calldata, err = r.constructFinalizeBundlePayloadCodecV7(dbBatch, endChunk, aggProof) - // if err != nil { - // return fmt.Errorf("failed to construct finalizeBundle payload codecv7, bundle index: %v, last batch index: %v, err: %w", bundle.Index, dbBatch.Index, err) - // } - calldata, err = r.constructFinalizeBundlePayloadValidium(dbBatch, endChunk, aggProof) - if err != nil { - return fmt.Errorf("failed to construct finalizeBundle payload codecv7, bundle index: %v, last batch index: %v, err: %w", bundle.Index, dbBatch.Index, err) + if r.cfg.ValidiumMode { + calldata, err = r.constructFinalizeBundlePayloadValidium(dbBatch, endChunk, aggProof) + if err != nil { + return fmt.Errorf("failed to construct validium finalizeBundle payload, bundle index: %v, last batch index: %v, err: %w", bundle.Index, dbBatch.Index, err) + } + } else { + calldata, err = r.constructFinalizeBundlePayloadCodecV7(dbBatch, endChunk, aggProof) + if err != nil { + return fmt.Errorf("failed to construct normal finalizeBundle payload, bundle index: %v, last batch index: %v, err: %w", bundle.Index, dbBatch.Index, err) + } } default: return fmt.Errorf("unsupported codec version in finalizeBundle, bundle index: %v, version: %d", bundle.Index, bundle.CodecVersion) @@ -971,17 +985,40 @@ func (r *Layer2Relayer) constructCommitBatchPayloadCodecV7(batchesToSubmit []*db return calldata, blobs, maxBlockHeight, totalGasUsed, nil } -func (r *Layer2Relayer) constructCommitBatchPayloadValidium(batchesToSubmit []*dbBatchWithChunksAndParent, batch *orm.Batch) ([]byte, []*kzg4844.Blob, uint64, uint64, error) { +func (r *Layer2Relayer) constructCommitBatchPayloadValidium(batchesToSubmit []*dbBatchWithChunksAndParent, batch *orm.Batch) ([]byte, uint64, uint64, error) { var maxBlockHeight uint64 var totalGasUsed uint64 version := encoding.CodecVersion(batchesToSubmit[0].Batch.CodecVersion) - commitment := common.Hash{} // todo + + // Calculate metrics + for _, b := range batchesToSubmit { + // double check that all batches have the same version + batchVersion := encoding.CodecVersion(b.Batch.CodecVersion) + if batchVersion != version { + return nil, 0, 0, fmt.Errorf("codec version mismatch, expected: %d, got: %d for batches %d and %d", version, batchVersion, batchesToSubmit[0].Batch.Index, b.Batch.Index) + } + + for _, c := range b.Chunks { + if c.EndBlockNumber > maxBlockHeight { + maxBlockHeight = c.EndBlockNumber + } + totalGasUsed += c.TotalL2TxGas + } + } + + // Get the commitment from the batch data: for validium mode, we use the last L2 block hash as the commitment to the off-chain data + // Get the last chunk from the last batch to find the end block hash + lastBatch := batchesToSubmit[len(batchesToSubmit)-1] + lastChunk := lastBatch.Chunks[len(lastBatch.Chunks)-1] + commitment := common.HexToHash(lastChunk.EndBlockHash) + calldata, err := r.validiumABI.Pack("commitBatch", version, common.HexToHash(batch.ParentBatchHash), common.HexToHash(batch.StateRoot), common.HexToHash(batch.WithdrawRoot), commitment[:]) if err != nil { - return nil, nil, 0, 0, fmt.Errorf("failed to pack commitBatches: %w", err) + return nil, 0, 0, fmt.Errorf("failed to pack commitBatch: %w", err) } - return calldata, nil, maxBlockHeight, totalGasUsed, nil + log.Info("Validium commitBatch", "maxBlockHeight", maxBlockHeight, "commitment", commitment.Hex()) + return calldata, maxBlockHeight, totalGasUsed, nil } func (r *Layer2Relayer) constructFinalizeBundlePayloadCodecV7(dbBatch *orm.Batch, endChunk *orm.Chunk, aggProof *message.OpenVMBundleProof) ([]byte, error) { @@ -1000,7 +1037,8 @@ func (r *Layer2Relayer) constructFinalizeBundlePayloadCodecV7(dbBatch *orm.Batch return calldata, nil } - fmt.Println("packing finalizeBundlePostEuclidV2NoProof", len(dbBatch.BatchHeader), dbBatch.CodecVersion, dbBatch.BatchHeader, new(big.Int).SetUint64(endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk), common.HexToHash(dbBatch.StateRoot), common.HexToHash(dbBatch.WithdrawRoot)) + log.Info("Packing finalizeBundlePostEuclidV2NoProof", "batchHeaderLength", len(dbBatch.BatchHeader), "codecVersion", dbBatch.CodecVersion, "totalL1Messages", endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk, "stateRoot", dbBatch.StateRoot, "withdrawRoot", dbBatch.WithdrawRoot) + // finalizeBundle without proof. calldata, packErr := r.l1RollupABI.Pack( "finalizeBundlePostEuclidV2NoProof", @@ -1015,14 +1053,15 @@ func (r *Layer2Relayer) constructFinalizeBundlePayloadCodecV7(dbBatch *orm.Batch return calldata, nil } +// TODO: add proof support for validium finalizeBundle func (r *Layer2Relayer) constructFinalizeBundlePayloadValidium(dbBatch *orm.Batch, endChunk *orm.Chunk, aggProof *message.OpenVMBundleProof) ([]byte, error) { - fmt.Println("packing finalizeBundle", len(dbBatch.BatchHeader), dbBatch.CodecVersion, dbBatch.BatchHeader, new(big.Int).SetUint64(endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk), common.HexToHash(dbBatch.StateRoot), common.HexToHash(dbBatch.WithdrawRoot)) + log.Info("Packing validium finalizeBundle", "batchHeaderLength", len(dbBatch.BatchHeader), "codecVersion", dbBatch.CodecVersion, "totalL1Messages", endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk, "stateRoot", dbBatch.StateRoot, "withdrawRoot", dbBatch.WithdrawRoot) // finalizeBundle without proof. calldata, packErr := r.validiumABI.Pack( "finalizeBundle", dbBatch.BatchHeader, new(big.Int).SetUint64(endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk), - []byte{}, + aggProof.Proof(), ) if packErr != nil { return nil, fmt.Errorf("failed to pack finalizeBundlePostEuclidV2NoProof: %w", packErr) diff --git a/rollup/internal/controller/watcher/batch_proposer.go b/rollup/internal/controller/watcher/batch_proposer.go index 5f56bb199a..68b6831e6a 100644 --- a/rollup/internal/controller/watcher/batch_proposer.go +++ b/rollup/internal/controller/watcher/batch_proposer.go @@ -32,6 +32,7 @@ type BatchProposer struct { cfg *config.BatchProposerConfig replayMode bool + validiumMode bool minCodecVersion encoding.CodecVersion chainCfg *params.ChainConfig @@ -63,7 +64,8 @@ func NewBatchProposer(ctx context.Context, cfg *config.BatchProposerConfig, minC chunkOrm: orm.NewChunk(db), l2BlockOrm: orm.NewL2Block(db), cfg: cfg, - replayMode: false, + replayMode: false, // default is false, set to true when using proposer tool + validiumMode: false, // default is false, set to true when using validium mode minCodecVersion: minCodecVersion, chainCfg: chainCfg, @@ -128,6 +130,11 @@ func (p *BatchProposer) SetReplayDB(replayDB *gorm.DB) { p.replayMode = true } +// SetValidiumMode sets the validium mode for the BatchProposer. +func (p *BatchProposer) SetValidiumMode(validiumMode bool) { + p.validiumMode = validiumMode +} + // TryProposeBatch tries to propose a new batches. func (p *BatchProposer) TryProposeBatch() { p.batchProposerCircleTotal.Inc() @@ -171,7 +178,7 @@ func (p *BatchProposer) updateDBBatchInfo(batch *encoding.Batch, codecVersion en // recalculate batch metrics after truncation var calcErr error - metrics, calcErr = utils.CalculateBatchMetrics(batch, codecVersion) + metrics, calcErr = utils.CalculateBatchMetrics(batch, codecVersion, p.validiumMode) if calcErr != nil { return fmt.Errorf("failed to calculate batch metrics, batch index: %v, error: %w", batch.Index, calcErr) } @@ -287,7 +294,7 @@ func (p *BatchProposer) proposeBatch() error { batch.Blocks = append(batch.Blocks, chunk.Blocks...) batch.PostL1MessageQueueHash = common.HexToHash(dbChunks[i].PostL1MessageQueueHash) - metrics, calcErr := utils.CalculateBatchMetrics(&batch, codec.Version()) + metrics, calcErr := utils.CalculateBatchMetrics(&batch, codec.Version(), p.validiumMode) if calcErr != nil { return fmt.Errorf("failed to calculate batch metrics: %w", calcErr) } @@ -310,7 +317,7 @@ func (p *BatchProposer) proposeBatch() error { batch.PostL1MessageQueueHash = common.HexToHash(dbChunks[i-1].PostL1MessageQueueHash) batch.Blocks = batch.Blocks[:len(batch.Blocks)-len(lastChunk.Blocks)] - metrics, err = utils.CalculateBatchMetrics(&batch, codec.Version()) + metrics, err = utils.CalculateBatchMetrics(&batch, codec.Version(), p.validiumMode) if err != nil { return fmt.Errorf("failed to calculate batch metrics: %w", err) } @@ -320,7 +327,7 @@ func (p *BatchProposer) proposeBatch() error { } } - metrics, calcErr := utils.CalculateBatchMetrics(&batch, codec.Version()) + metrics, calcErr := utils.CalculateBatchMetrics(&batch, codec.Version(), p.validiumMode) if calcErr != nil { return fmt.Errorf("failed to calculate batch metrics: %w", calcErr) } diff --git a/rollup/internal/orm/batch.go b/rollup/internal/orm/batch.go index 5e036ac6f7..8de251d61c 100644 --- a/rollup/internal/orm/batch.go +++ b/rollup/internal/orm/batch.go @@ -323,7 +323,7 @@ func (o *Batch) InsertBatch(ctx context.Context, batch *encoding.Batch, codecVer startChunkIndex = parentBatch.EndChunkIndex + 1 } - batchMeta, err := rutils.GetBatchMetadata(batch, codecVersion) + batchMeta, err := rutils.GetBatchMetadata(batch, codecVersion, metrics.ValidiumMode) if err != nil { log.Error("failed to get batch metadata", "index", batch.Index, "total l1 message popped before", batch.TotalL1MessagePoppedBefore, "parent hash", batch.ParentBatchHash.Hex(), "number of chunks", numChunks, "err", err) diff --git a/rollup/internal/utils/utils.go b/rollup/internal/utils/utils.go index a67150323b..12af3ed134 100644 --- a/rollup/internal/utils/utils.go +++ b/rollup/internal/utils/utils.go @@ -60,15 +60,18 @@ type BatchMetrics struct { L1CommitBlobSize uint64 + ValidiumMode bool // default false: rollup mode + // timing metrics EstimateBlobSizeTime time.Duration } // CalculateBatchMetrics calculates batch metrics. -func CalculateBatchMetrics(batch *encoding.Batch, codecVersion encoding.CodecVersion) (*BatchMetrics, error) { +func CalculateBatchMetrics(batch *encoding.Batch, codecVersion encoding.CodecVersion, validiumMode bool) (*BatchMetrics, error) { metrics := &BatchMetrics{ NumChunks: uint64(len(batch.Chunks)), FirstBlockTimestamp: batch.Chunks[0].Blocks[0].Header.Time, + ValidiumMode: validiumMode, } codec, err := encoding.CodecFromVersion(codecVersion) @@ -119,24 +122,28 @@ type BatchMetadata struct { ChallengeDigest common.Hash } -func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVersion) []byte { - emptyHash := common.Hash{} - +// encodeBatchHeaderValidium encodes batch header for validium mode and returns both encoded bytes and hash +func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVersion) ([]byte, common.Hash) { batchBytes := make([]byte, 105+32) // todo: commitment batchBytes[0] = uint8(codecVersion) // version binary.BigEndian.PutUint64(batchBytes[1:9], b.Index) // batch index copy(batchBytes[9:41], b.ParentBatchHash[0:32]) // parentBatchHash copy(batchBytes[41:73], b.StateRoot().Bytes()[0:32]) // postStateRoot copy(batchBytes[73:105], b.WithdrawRoot().Bytes()[0:32]) // postWithdrawRoot - copy(batchBytes[105:137], emptyHash[0:32]) // data commitment - return batchBytes -} -// // func hashBatchHeaderValidium() -// return crypto.Keccak256Hash(b.Encode()) + var commitment common.Hash + if len(b.Blocks) > 0 { + lastBlock := b.Blocks[len(b.Blocks)-1] + commitment = lastBlock.Header.Hash() + } + copy(batchBytes[105:137], commitment[0:32]) // data commitment + + hash := crypto.Keccak256Hash(batchBytes) + return batchBytes, hash +} // GetBatchMetadata retrieves the metadata of a batch. -func GetBatchMetadata(batch *encoding.Batch, codecVersion encoding.CodecVersion) (*BatchMetadata, error) { +func GetBatchMetadata(batch *encoding.Batch, codecVersion encoding.CodecVersion, validiumMode bool) (*BatchMetadata, error) { codec, err := encoding.CodecFromVersion(codecVersion) if err != nil { return nil, fmt.Errorf("failed to get codec from version: %v, err: %w", codecVersion, err) @@ -155,11 +162,10 @@ func GetBatchMetadata(batch *encoding.Batch, codecVersion encoding.CodecVersion) ChallengeDigest: daBatch.ChallengeDigest(), } - // validium - encoded := encodeBatchHeaderValidium(batch, codecVersion) - hash := crypto.Keccak256Hash(encoded) - batchMeta.BatchBytes = encoded - batchMeta.BatchHash = hash + // If this function is used in Validium, we encode the batch header differently. + if validiumMode { + batchMeta.BatchBytes, batchMeta.BatchHash = encodeBatchHeaderValidium(batch, codecVersion) + } batchMeta.BatchBlobDataProof, err = daBatch.BlobDataProofForPointEvaluation() if err != nil { From 929724458dbb6e534d9d749ae207fbd95535996a Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Mon, 7 Jul 2025 19:29:11 +0800 Subject: [PATCH 03/17] add length checks --- common/version/version.go | 2 +- rollup/internal/controller/relayer/l2_relayer.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/common/version/version.go b/common/version/version.go index db128cc5e8..9989598fad 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.5.27" +var tag = "v4.5.28" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok { diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 71e61b65f1..baa9358714 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -1005,7 +1005,15 @@ func (r *Layer2Relayer) constructCommitBatchPayloadValidium(batchesToSubmit []*d // Get the commitment from the batch data: for validium mode, we use the last L2 block hash as the commitment to the off-chain data // Get the last chunk from the last batch to find the end block hash + if len(batchesToSubmit) == 0 { + return nil, 0, 0, fmt.Errorf("no batches to submit") + } + lastBatch := batchesToSubmit[len(batchesToSubmit)-1] + if len(lastBatch.Chunks) == 0 { + return nil, 0, 0, fmt.Errorf("last batch has no chunks") + } + lastChunk := lastBatch.Chunks[len(lastBatch.Chunks)-1] commitment := common.HexToHash(lastChunk.EndBlockHash) From c8ab62ed9a2004f9ab690c9f69117183f7db3373 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Mon, 7 Jul 2025 20:09:05 +0800 Subject: [PATCH 04/17] address AI's comments --- .../internal/controller/relayer/l2_relayer.go | 9 ++-- rollup/internal/utils/utils.go | 45 +++++++++++++++---- 2 files changed, 43 insertions(+), 11 deletions(-) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index baa9358714..1acc54db34 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -1057,10 +1057,13 @@ func (r *Layer2Relayer) constructFinalizeBundlePayloadCodecV7(dbBatch *orm.Batch return calldata, nil } -// TODO: add proof support for validium finalizeBundle func (r *Layer2Relayer) constructFinalizeBundlePayloadValidium(dbBatch *orm.Batch, endChunk *orm.Chunk, aggProof *message.OpenVMBundleProof) ([]byte, error) { log.Info("Packing validium finalizeBundle", "batchHeaderLength", len(dbBatch.BatchHeader), "codecVersion", dbBatch.CodecVersion, "totalL1Messages", endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk, "stateRoot", dbBatch.StateRoot, "withdrawRoot", dbBatch.WithdrawRoot) - // finalizeBundle without proof. + + if aggProof == nil { + return nil, fmt.Errorf("aggProof is required for validium finalizeBundle") + } + calldata, packErr := r.validiumABI.Pack( "finalizeBundle", dbBatch.BatchHeader, @@ -1068,7 +1071,7 @@ func (r *Layer2Relayer) constructFinalizeBundlePayloadValidium(dbBatch *orm.Batc aggProof.Proof(), ) if packErr != nil { - return nil, fmt.Errorf("failed to pack finalizeBundlePostEuclidV2NoProof: %w", packErr) + return nil, fmt.Errorf("failed to pack validium finalizeBundle: %w", packErr) } return calldata, nil } diff --git a/rollup/internal/utils/utils.go b/rollup/internal/utils/utils.go index 7333d60f8a..ceb0956b21 100644 --- a/rollup/internal/utils/utils.go +++ b/rollup/internal/utils/utils.go @@ -126,19 +126,48 @@ type BatchMetadata struct { // encodeBatchHeaderValidium encodes batch header for validium mode and returns both encoded bytes and hash func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVersion) ([]byte, common.Hash) { - batchBytes := make([]byte, 105+32) // todo: commitment - batchBytes[0] = uint8(codecVersion) // version - binary.BigEndian.PutUint64(batchBytes[1:9], b.Index) // batch index - copy(batchBytes[9:41], b.ParentBatchHash[0:32]) // parentBatchHash - copy(batchBytes[41:73], b.StateRoot().Bytes()[0:32]) // postStateRoot - copy(batchBytes[73:105], b.WithdrawRoot().Bytes()[0:32]) // postWithdrawRoot - + if b == nil { + return nil, common.Hash{} + } + + // Batch header field sizes + const ( + versionSize = 1 + indexSize = 8 + parentHashSize = 32 + stateRootSize = 32 + withdrawRootSize = 32 + commitmentSize = 32 + + // Total size of validium batch header + validiumBatchHeaderSize = versionSize + indexSize + parentHashSize + stateRootSize + withdrawRootSize + commitmentSize + ) + + batchBytes := make([]byte, validiumBatchHeaderSize) + + // Define offsets for each field + var ( + versionOffset = 0 + indexOffset = versionOffset + versionSize + parentHashOffset = indexOffset + indexSize + stateRootOffset = parentHashOffset + parentHashSize + withdrawRootOffset = stateRootOffset + stateRootSize + commitmentOffset = withdrawRootOffset + withdrawRootSize + ) + + batchBytes[versionOffset] = uint8(codecVersion) // version + binary.BigEndian.PutUint64(batchBytes[indexOffset:indexOffset+indexSize], b.Index) // batch index + copy(batchBytes[parentHashOffset:parentHashOffset+parentHashSize], b.ParentBatchHash[0:32]) // parentBatchHash + copy(batchBytes[stateRootOffset:stateRootOffset+stateRootSize], b.StateRoot().Bytes()[0:32]) // postStateRoot + copy(batchBytes[withdrawRootOffset:withdrawRootOffset+withdrawRootSize], b.WithdrawRoot().Bytes()[0:32]) // postWithdrawRoot + + // For validium mode, use the last block hash as commitment to the off-chain data var commitment common.Hash if len(b.Blocks) > 0 { lastBlock := b.Blocks[len(b.Blocks)-1] commitment = lastBlock.Header.Hash() } - copy(batchBytes[105:137], commitment[0:32]) // data commitment + copy(batchBytes[commitmentOffset:commitmentOffset+commitmentSize], commitment[0:32]) // data commitment hash := crypto.Keccak256Hash(batchBytes) return batchBytes, hash From e2745e9a81ac092fa6683bbf398410c3b865afed Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Mon, 7 Jul 2025 20:22:23 +0800 Subject: [PATCH 05/17] tweak --- rollup/internal/controller/relayer/l2_relayer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 1acc54db34..fe323ad215 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -287,7 +287,7 @@ func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte, } log.Info("Validium importGenesis", "calldata", common.Bytes2Hex(calldata)) } else { - // normal rollup mode: pass batchHeader and stateRoot + // rollup mode: pass batchHeader and stateRoot calldata, packErr = r.l1RollupABI.Pack("importGenesisBatch", batchHeader, stateRoot) if packErr != nil { return fmt.Errorf("failed to pack rollup importGenesisBatch with batch header: %v and state root: %v. error: %v", common.Bytes2Hex(batchHeader), stateRoot, packErr) From b5c10a000f2eca52399b037c9f9b6796973c1e73 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Mon, 7 Jul 2025 20:30:42 +0800 Subject: [PATCH 06/17] tweaks --- rollup/internal/utils/utils.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rollup/internal/utils/utils.go b/rollup/internal/utils/utils.go index ceb0956b21..eff74689b5 100644 --- a/rollup/internal/utils/utils.go +++ b/rollup/internal/utils/utils.go @@ -155,11 +155,11 @@ func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVer commitmentOffset = withdrawRootOffset + withdrawRootSize ) - batchBytes[versionOffset] = uint8(codecVersion) // version - binary.BigEndian.PutUint64(batchBytes[indexOffset:indexOffset+indexSize], b.Index) // batch index - copy(batchBytes[parentHashOffset:parentHashOffset+parentHashSize], b.ParentBatchHash[0:32]) // parentBatchHash - copy(batchBytes[stateRootOffset:stateRootOffset+stateRootSize], b.StateRoot().Bytes()[0:32]) // postStateRoot - copy(batchBytes[withdrawRootOffset:withdrawRootOffset+withdrawRootSize], b.WithdrawRoot().Bytes()[0:32]) // postWithdrawRoot + batchBytes[versionOffset] = uint8(codecVersion) // version + binary.BigEndian.PutUint64(batchBytes[indexOffset:indexOffset+indexSize], b.Index) // batch index + copy(batchBytes[parentHashOffset:parentHashOffset+parentHashSize], b.ParentBatchHash[0:parentHashSize]) // parentBatchHash + copy(batchBytes[stateRootOffset:stateRootOffset+stateRootSize], b.StateRoot().Bytes()[0:stateRootSize]) // postStateRoot + copy(batchBytes[withdrawRootOffset:withdrawRootOffset+withdrawRootSize], b.WithdrawRoot().Bytes()[0:withdrawRootSize]) // postWithdrawRoot // For validium mode, use the last block hash as commitment to the off-chain data var commitment common.Hash @@ -167,7 +167,7 @@ func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVer lastBlock := b.Blocks[len(b.Blocks)-1] commitment = lastBlock.Header.Hash() } - copy(batchBytes[commitmentOffset:commitmentOffset+commitmentSize], commitment[0:32]) // data commitment + copy(batchBytes[commitmentOffset:commitmentOffset+commitmentSize], commitment[0:commitmentSize]) // data commitment hash := crypto.Keccak256Hash(batchBytes) return batchBytes, hash From bd00cb4717b39479cc093a883d1fb85137354677 Mon Sep 17 00:00:00 2001 From: colin <102356659+colinlyguo@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:21:10 +0800 Subject: [PATCH 07/17] Update rollup/abi/validium_abi.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Péter Garamvölgyi --- rollup/abi/validium_abi.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollup/abi/validium_abi.go b/rollup/abi/validium_abi.go index 37bd6189e2..aa0c75f272 100644 --- a/rollup/abi/validium_abi.go +++ b/rollup/abi/validium_abi.go @@ -16,7 +16,7 @@ func init() { // Generated manually from abigen. -// ValidiumMetaData contains all meta data concerning the ScrollChain contract. +// ValidiumMetaData contains all meta data concerning the ScrollChainValidium contract. var ValidiumMetaData = &bind.MetaData{ ABI: "[{\"type\":\"function\",\"name\":\"commitAndFinalizeBatch\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"finalizeStruct\",\"type\":\"tuple\",\"internalType\":\"struct ScrollChainInterface.FinalizeStruct\",\"components\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"zkProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"commitBatchWithBlobProof\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"chunks\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"skippedL1MessageBitmap\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"blobDataProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"commitBatches\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"lastBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatch\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_prevStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatch4844\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_blobDataProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatchWithProof\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"prevStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatchWithProof4844\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"prevStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"blobDataProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundlePostEuclidV2\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundlePostEuclidV2NoProof\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundleWithProof\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeEuclidInitialBatch\",\"inputs\":[{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"importGenesisBatch\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revertBatch\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"count\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revertBatch\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"CommitBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FinalizeBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RevertBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RevertBatch\",\"inputs\":[{\"name\":\"startBatchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"finishBatchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdateEnforcedBatchMode\",\"inputs\":[{\"name\":\"enabled\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"},{\"name\":\"lastCommittedBatchIndex\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"function\",\"name\":\"commitBatch\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"commitment\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundle\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"}]", } From f4d6e67c90a6a555f1bb614fda2d53bb23aebfaf Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Tue, 8 Jul 2025 04:00:48 +0800 Subject: [PATCH 08/17] address comments --- rollup/abi/validium_abi.go | 2 +- rollup/cmd/rollup_relayer/app/app.go | 3 +- .../internal/controller/relayer/l2_relayer.go | 1 + .../controller/watcher/batch_proposer.go | 9 ++--- .../controller/watcher/batch_proposer_test.go | 8 ++--- .../watcher/bundle_proposer_test.go | 2 +- .../controller/watcher/proposer_tool.go | 2 +- rollup/internal/utils/utils.go | 33 +++++++++++-------- rollup/tests/rollup_test.go | 2 +- 9 files changed, 31 insertions(+), 31 deletions(-) diff --git a/rollup/abi/validium_abi.go b/rollup/abi/validium_abi.go index aa0c75f272..e0a6bf9fbb 100644 --- a/rollup/abi/validium_abi.go +++ b/rollup/abi/validium_abi.go @@ -18,5 +18,5 @@ func init() { // ValidiumMetaData contains all meta data concerning the ScrollChainValidium contract. var ValidiumMetaData = &bind.MetaData{ - ABI: "[{\"type\":\"function\",\"name\":\"commitAndFinalizeBatch\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"finalizeStruct\",\"type\":\"tuple\",\"internalType\":\"struct ScrollChainInterface.FinalizeStruct\",\"components\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"zkProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}]}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"commitBatchWithBlobProof\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"chunks\",\"type\":\"bytes[]\",\"internalType\":\"bytes[]\"},{\"name\":\"skippedL1MessageBitmap\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"blobDataProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"commitBatches\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"lastBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatch\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"_prevStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatch4844\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"_blobDataProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatchWithProof\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"prevStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBatchWithProof4844\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"prevStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"blobDataProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundlePostEuclidV2\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundlePostEuclidV2NoProof\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundleWithProof\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeEuclidInitialBatch\",\"inputs\":[{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"importGenesisBatch\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revertBatch\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"count\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revertBatch\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"event\",\"name\":\"CommitBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FinalizeBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RevertBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RevertBatch\",\"inputs\":[{\"name\":\"startBatchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"finishBatchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"UpdateEnforcedBatchMode\",\"inputs\":[{\"name\":\"enabled\",\"type\":\"bool\",\"indexed\":false,\"internalType\":\"bool\"},{\"name\":\"lastCommittedBatchIndex\",\"type\":\"uint256\",\"indexed\":false,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"function\",\"name\":\"commitBatch\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"commitment\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"finalizeBundle\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"}]", + ABI: "[{\"type\":\"constructor\",\"inputs\":[{\"name\":\"_chainId\",\"type\":\"uint64\",\"internalType\":\"uint64\"},{\"name\":\"_messageQueueV2\",\"type\":\"address\",\"internalType\":\"address\"},{\"name\":\"_verifier\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"DEFAULT_ADMIN_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"GENESIS_IMPORTER_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"PROVER_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"SEQUENCER_ROLE\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"commitBatch\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"internalType\":\"uint8\"},{\"name\":\"parentBatchHash\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"postStateRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"commitment\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"committedBatches\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"finalizeBundle\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"},{\"name\":\"totalL1MessagesPoppedOverall\",\"type\":\"uint256\",\"internalType\":\"uint256\"},{\"name\":\"aggrProof\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"getRoleAdmin\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"grantRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"hasRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"importGenesisBatch\",\"inputs\":[{\"name\":\"_batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"initialize\",\"inputs\":[{\"name\":\"_admin\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"isBatchFinalized\",\"inputs\":[{\"name\":\"_batchIndex\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"lastCommittedBatchIndex\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"lastFinalizedBatchIndex\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"layer2ChainId\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"uint64\",\"internalType\":\"uint64\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"messageQueueV2\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"paused\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"renounceRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revertBatch\",\"inputs\":[{\"name\":\"batchHeader\",\"type\":\"bytes\",\"internalType\":\"bytes\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"revokeRole\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"internalType\":\"address\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"setPause\",\"inputs\":[{\"name\":\"_status\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"outputs\":[],\"stateMutability\":\"nonpayable\"},{\"type\":\"function\",\"name\":\"stateRoots\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"supportsInterface\",\"inputs\":[{\"name\":\"interfaceId\",\"type\":\"bytes4\",\"internalType\":\"bytes4\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bool\",\"internalType\":\"bool\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"verifier\",\"inputs\":[],\"outputs\":[{\"name\":\"\",\"type\":\"address\",\"internalType\":\"address\"}],\"stateMutability\":\"view\"},{\"type\":\"function\",\"name\":\"withdrawRoots\",\"inputs\":[{\"name\":\"\",\"type\":\"uint256\",\"internalType\":\"uint256\"}],\"outputs\":[{\"name\":\"\",\"type\":\"bytes32\",\"internalType\":\"bytes32\"}],\"stateMutability\":\"view\"},{\"type\":\"event\",\"name\":\"CommitBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"FinalizeBatch\",\"inputs\":[{\"name\":\"batchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"batchHash\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"stateRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"},{\"name\":\"withdrawRoot\",\"type\":\"bytes32\",\"indexed\":false,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Initialized\",\"inputs\":[{\"name\":\"version\",\"type\":\"uint8\",\"indexed\":false,\"internalType\":\"uint8\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Paused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RevertBatch\",\"inputs\":[{\"name\":\"startBatchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"},{\"name\":\"finishBatchIndex\",\"type\":\"uint256\",\"indexed\":true,\"internalType\":\"uint256\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleAdminChanged\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"previousAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"newAdminRole\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleGranted\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"RoleRevoked\",\"inputs\":[{\"name\":\"role\",\"type\":\"bytes32\",\"indexed\":true,\"internalType\":\"bytes32\"},{\"name\":\"account\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"},{\"name\":\"sender\",\"type\":\"address\",\"indexed\":true,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"event\",\"name\":\"Unpaused\",\"inputs\":[{\"name\":\"account\",\"type\":\"address\",\"indexed\":false,\"internalType\":\"address\"}],\"anonymous\":false},{\"type\":\"error\",\"name\":\"ErrorBatchHeaderV0LengthTooSmall\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ErrorBatchIsAlreadyVerified\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ErrorBatchNotCommitted\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ErrorGenesisBatchImported\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ErrorIncorrectBatchHash\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ErrorInvalidGenesisBatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ErrorRevertFinalizedBatch\",\"inputs\":[]},{\"type\":\"error\",\"name\":\"ErrorStateRootIsZero\",\"inputs\":[]}]", } diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index 44096fcd81..96bb73c14d 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -107,8 +107,7 @@ func action(ctx *cli.Context) error { } chunkProposer := watcher.NewChunkProposer(subCtx, cfg.L2Config.ChunkProposerConfig, minCodecVersion, genesis.Config, db, registry) - batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, minCodecVersion, genesis.Config, db, registry) - batchProposer.SetValidiumMode(cfg.L2Config.RelayerConfig.ValidiumMode) + batchProposer := watcher.NewBatchProposer(subCtx, cfg.L2Config.BatchProposerConfig, minCodecVersion, genesis.Config, db, cfg.L2Config.RelayerConfig.ValidiumMode, registry) bundleProposer := watcher.NewBundleProposer(subCtx, cfg.L2Config.BundleProposerConfig, minCodecVersion, genesis.Config, db, registry) l2watcher := watcher.NewL2WatcherClient(subCtx, l2client, cfg.L2Config.Confirmations, cfg.L2Config.L2MessageQueueAddress, cfg.L2Config.WithdrawTrieRootSlot, genesis.Config, db, registry) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index fe323ad215..3bb5d025d1 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -1005,6 +1005,7 @@ func (r *Layer2Relayer) constructCommitBatchPayloadValidium(batchesToSubmit []*d // Get the commitment from the batch data: for validium mode, we use the last L2 block hash as the commitment to the off-chain data // Get the last chunk from the last batch to find the end block hash + // TODO: This is a temporary solution, we might use a larger commitment in the future if len(batchesToSubmit) == 0 { return nil, 0, 0, fmt.Errorf("no batches to submit") } diff --git a/rollup/internal/controller/watcher/batch_proposer.go b/rollup/internal/controller/watcher/batch_proposer.go index 811f2ba32a..522ce07cb7 100644 --- a/rollup/internal/controller/watcher/batch_proposer.go +++ b/rollup/internal/controller/watcher/batch_proposer.go @@ -54,7 +54,7 @@ type BatchProposer struct { } // NewBatchProposer creates a new BatchProposer instance. -func NewBatchProposer(ctx context.Context, cfg *config.BatchProposerConfig, minCodecVersion encoding.CodecVersion, chainCfg *params.ChainConfig, db *gorm.DB, reg prometheus.Registerer) *BatchProposer { +func NewBatchProposer(ctx context.Context, cfg *config.BatchProposerConfig, minCodecVersion encoding.CodecVersion, chainCfg *params.ChainConfig, db *gorm.DB, validiumMode bool, reg prometheus.Registerer) *BatchProposer { log.Info("new batch proposer", "batchTimeoutSec", cfg.BatchTimeoutSec, "maxBlobSize", maxBlobSize, "maxUncompressedBatchBytesSize", cfg.MaxUncompressedBatchBytesSize) p := &BatchProposer{ @@ -65,7 +65,7 @@ func NewBatchProposer(ctx context.Context, cfg *config.BatchProposerConfig, minC l2BlockOrm: orm.NewL2Block(db), cfg: cfg, replayMode: false, // default is false, set to true when using proposer tool - validiumMode: false, // default is false, set to true when using validium mode + validiumMode: validiumMode, minCodecVersion: minCodecVersion, chainCfg: chainCfg, @@ -130,11 +130,6 @@ func (p *BatchProposer) SetReplayDB(replayDB *gorm.DB) { p.replayMode = true } -// SetValidiumMode sets the validium mode for the BatchProposer. -func (p *BatchProposer) SetValidiumMode(validiumMode bool) { - p.validiumMode = validiumMode -} - // TryProposeBatch tries to propose a new batches. func (p *BatchProposer) TryProposeBatch() { p.batchProposerCircleTotal.Inc() diff --git a/rollup/internal/controller/watcher/batch_proposer_test.go b/rollup/internal/controller/watcher/batch_proposer_test.go index c446315d6d..526c93655f 100644 --- a/rollup/internal/controller/watcher/batch_proposer_test.go +++ b/rollup/internal/controller/watcher/batch_proposer_test.go @@ -100,7 +100,7 @@ func testBatchProposerLimitsCodecV7(t *testing.T) { DarwinV2Time: new(uint64), EuclidTime: new(uint64), EuclidV2Time: new(uint64), - }, db, nil) + }, db, false /* rollup mode */, nil) bp.TryProposeBatch() batches, err := batchOrm.GetBatches(context.Background(), map[string]interface{}{}, []string{}, 0) @@ -178,7 +178,7 @@ func testBatchProposerBlobSizeLimitCodecV7(t *testing.T) { MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, - }, encoding.CodecV7, chainConfig, db, nil) + }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) for i := 0; i < 2; i++ { bp.TryProposeBatch() @@ -246,7 +246,7 @@ func testBatchProposerMaxChunkNumPerBatchLimitCodecV7(t *testing.T) { MaxChunksPerBatch: 45, BatchTimeoutSec: math.MaxUint32, MaxUncompressedBatchBytesSize: math.MaxUint64, - }, encoding.CodecV7, chainConfig, db, nil) + }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) bp.TryProposeBatch() batches, err := batchOrm.GetBatches(context.Background(), map[string]interface{}{}, []string{}, 0) @@ -335,7 +335,7 @@ func testBatchProposerUncompressedBatchBytesLimitCodecV8(t *testing.T) { MaxChunksPerBatch: math.MaxInt32, // No chunk count limit BatchTimeoutSec: math.MaxUint32, // No timeout limit MaxUncompressedBatchBytesSize: 4 * 1024, // 4KiB limit - }, encoding.CodecV8, chainConfig, db, nil) + }, encoding.CodecV8, chainConfig, db, false /* rollup mode */, nil) bp.TryProposeBatch() diff --git a/rollup/internal/controller/watcher/bundle_proposer_test.go b/rollup/internal/controller/watcher/bundle_proposer_test.go index f631a60a18..7e2f27da43 100644 --- a/rollup/internal/controller/watcher/bundle_proposer_test.go +++ b/rollup/internal/controller/watcher/bundle_proposer_test.go @@ -103,7 +103,7 @@ func testBundleProposerLimitsCodecV7(t *testing.T) { MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: 0, MaxUncompressedBatchBytesSize: math.MaxUint64, - }, encoding.CodecV7, chainConfig, db, nil) + }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) cp.TryProposeChunk() // chunk1 contains block1 bap.TryProposeBatch() // batch1 contains chunk1 diff --git a/rollup/internal/controller/watcher/proposer_tool.go b/rollup/internal/controller/watcher/proposer_tool.go index 9ab53d91ce..b825073cfa 100644 --- a/rollup/internal/controller/watcher/proposer_tool.go +++ b/rollup/internal/controller/watcher/proposer_tool.go @@ -125,7 +125,7 @@ func NewProposerTool(ctx context.Context, cancel context.CancelFunc, cfg *config chunkProposer := NewChunkProposer(ctx, cfg.L2Config.ChunkProposerConfig, minCodecVersion, chainCfg, db, nil) chunkProposer.SetReplayDB(dbForReplay) - batchProposer := NewBatchProposer(ctx, cfg.L2Config.BatchProposerConfig, minCodecVersion, chainCfg, db, nil) + batchProposer := NewBatchProposer(ctx, cfg.L2Config.BatchProposerConfig, minCodecVersion, chainCfg, db, false /* rollup mode */, nil) batchProposer.SetReplayDB(dbForReplay) bundleProposer := NewBundleProposer(ctx, cfg.L2Config.BundleProposerConfig, minCodecVersion, chainCfg, db, nil) diff --git a/rollup/internal/utils/utils.go b/rollup/internal/utils/utils.go index eff74689b5..9a55b93e21 100644 --- a/rollup/internal/utils/utils.go +++ b/rollup/internal/utils/utils.go @@ -125,11 +125,20 @@ type BatchMetadata struct { } // encodeBatchHeaderValidium encodes batch header for validium mode and returns both encoded bytes and hash -func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVersion) ([]byte, common.Hash) { +func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVersion) ([]byte, common.Hash, error) { if b == nil { - return nil, common.Hash{} + return nil, common.Hash{}, fmt.Errorf("batch is nil, version: %v, index: %v", codecVersion, b.Index) } + if len(b.Blocks) == 0 { + return nil, common.Hash{}, fmt.Errorf("batch contains no blocks, version: %v, index: %v", codecVersion, b.Index) + } + + // For validium mode, use the last block hash as commitment to the off-chain data + // TODO: This is a temporary solution, we might use a larger commitment in the future + lastBlock := b.Blocks[len(b.Blocks)-1] + commitment := lastBlock.Header.Hash() + // Batch header field sizes const ( versionSize = 1 @@ -137,7 +146,7 @@ func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVer parentHashSize = 32 stateRootSize = 32 withdrawRootSize = 32 - commitmentSize = 32 + commitmentSize = 32 // TODO: 32 bytes for now, might use larger commitment in the future // Total size of validium batch header validiumBatchHeaderSize = versionSize + indexSize + parentHashSize + stateRootSize + withdrawRootSize + commitmentSize @@ -160,17 +169,10 @@ func encodeBatchHeaderValidium(b *encoding.Batch, codecVersion encoding.CodecVer copy(batchBytes[parentHashOffset:parentHashOffset+parentHashSize], b.ParentBatchHash[0:parentHashSize]) // parentBatchHash copy(batchBytes[stateRootOffset:stateRootOffset+stateRootSize], b.StateRoot().Bytes()[0:stateRootSize]) // postStateRoot copy(batchBytes[withdrawRootOffset:withdrawRootOffset+withdrawRootSize], b.WithdrawRoot().Bytes()[0:withdrawRootSize]) // postWithdrawRoot - - // For validium mode, use the last block hash as commitment to the off-chain data - var commitment common.Hash - if len(b.Blocks) > 0 { - lastBlock := b.Blocks[len(b.Blocks)-1] - commitment = lastBlock.Header.Hash() - } - copy(batchBytes[commitmentOffset:commitmentOffset+commitmentSize], commitment[0:commitmentSize]) // data commitment + copy(batchBytes[commitmentOffset:commitmentOffset+commitmentSize], commitment[0:commitmentSize]) // data commitment hash := crypto.Keccak256Hash(batchBytes) - return batchBytes, hash + return batchBytes, hash, nil } // GetBatchMetadata retrieves the metadata of a batch. @@ -195,12 +197,15 @@ func GetBatchMetadata(batch *encoding.Batch, codecVersion encoding.CodecVersion, // If this function is used in Validium, we encode the batch header differently. if validiumMode { - batchMeta.BatchBytes, batchMeta.BatchHash = encodeBatchHeaderValidium(batch, codecVersion) + batchMeta.BatchBytes, batchMeta.BatchHash, err = encodeBatchHeaderValidium(batch, codecVersion) + if err != nil { + return nil, fmt.Errorf("failed to encode batch header for validium, version: %v, index: %v, err: %w", codecVersion, batch.Index, err) + } } batchMeta.BatchBlobDataProof, err = daBatch.BlobDataProofForPointEvaluation() if err != nil { - return nil, fmt.Errorf("failed to get blob data proof, version: %v, err: %w", codecVersion, err) + return nil, fmt.Errorf("failed to get blob data proof, version: %v, index: %v, err: %w", codecVersion, batch.Index, err) } numChunks := len(batch.Chunks) diff --git a/rollup/tests/rollup_test.go b/rollup/tests/rollup_test.go index 14c1a22b31..4296d90146 100644 --- a/rollup/tests/rollup_test.go +++ b/rollup/tests/rollup_test.go @@ -128,7 +128,7 @@ func testCommitBatchAndFinalizeBundleCodecV7(t *testing.T) { MaxChunksPerBatch: math.MaxInt32, BatchTimeoutSec: 300, MaxUncompressedBatchBytesSize: math.MaxUint64, - }, encoding.CodecV7, chainConfig, db, nil) + }, encoding.CodecV7, chainConfig, db, false /* rollup mode */, nil) bup := watcher.NewBundleProposer(context.Background(), &config.BundleProposerConfig{ MaxBatchNumPerBundle: 2, From 7dfb8b5aee658ed0399590e7dea7d4954dac81da Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Tue, 8 Jul 2025 04:54:22 +0800 Subject: [PATCH 09/17] enforce single batch submission in validium mode --- rollup/cmd/rollup_relayer/app/app.go | 7 +++ .../internal/controller/relayer/l2_relayer.go | 46 +++++++------------ 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index 96bb73c14d..b776ef9557 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -96,6 +96,13 @@ func action(ctx *cli.Context) error { log.Crit("cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk must be greater than 0") } + if cfg.L2Config.RelayerConfig.ValidiumMode { + // Force single batch submission for validium mode, this looks a bit hacky but it avoids more changes in the relayer code. + cfg.L2Config.RelayerConfig.BatchSubmission.MinBatches = 1 + cfg.L2Config.RelayerConfig.BatchSubmission.MaxBatches = 1 + log.Info("Validium mode detected, forcing single batch submission", "minBatches", 1, "maxBatches", 1) + } + l2relayer, err := relayer.NewLayer2Relayer(ctx.Context, l2client, db, cfg.L2Config.RelayerConfig, genesis.Config, relayer.ServiceTypeL2RollupRelayer, registry) if err != nil { log.Crit("failed to create l2 relayer", "config file", cfgFile, "error", err) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 3bb5d025d1..689e63ba37 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -482,9 +482,13 @@ func (r *Layer2Relayer) ProcessPendingBatches() { switch codecVersion { case encoding.CodecV7, encoding.CodecV8: if r.cfg.ValidiumMode { - calldata, maxBlockHeight, totalGasUsed, err = r.constructCommitBatchPayloadValidium(batchesToSubmit, firstBatch) + if len(batchesToSubmit) != 1 { + log.Error("validium mode only supports committing one batch at a time", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "batches count", len(batchesToSubmit)) + return + } + calldata, maxBlockHeight, totalGasUsed, err = r.constructCommitBatchPayloadValidium(batchesToSubmit[0]) if err != nil { - log.Error("failed to construct validium payload", "codecVersion", codecVersion, "start index", firstBatch.Index, "end index", lastBatch.Index, "err", err) + log.Error("failed to construct validium payload", "codecVersion", codecVersion, "index", batchesToSubmit[0].Batch.Index, "err", err) return } } else { @@ -981,44 +985,28 @@ func (r *Layer2Relayer) constructCommitBatchPayloadCodecV7(batchesToSubmit []*db return calldata, blobs, maxBlockHeight, totalGasUsed, nil } -func (r *Layer2Relayer) constructCommitBatchPayloadValidium(batchesToSubmit []*dbBatchWithChunks, batch *orm.Batch) ([]byte, uint64, uint64, error) { +func (r *Layer2Relayer) constructCommitBatchPayloadValidium(batch *dbBatchWithChunks) ([]byte, uint64, uint64, error) { + // Calculate metrics var maxBlockHeight uint64 var totalGasUsed uint64 - - version := encoding.CodecVersion(batchesToSubmit[0].Batch.CodecVersion) - - // Calculate metrics - for _, b := range batchesToSubmit { - // double check that all batches have the same version - batchVersion := encoding.CodecVersion(b.Batch.CodecVersion) - if batchVersion != version { - return nil, 0, 0, fmt.Errorf("codec version mismatch, expected: %d, got: %d for batches %d and %d", version, batchVersion, batchesToSubmit[0].Batch.Index, b.Batch.Index) - } - - for _, c := range b.Chunks { - if c.EndBlockNumber > maxBlockHeight { - maxBlockHeight = c.EndBlockNumber - } - totalGasUsed += c.TotalL2TxGas + for _, c := range batch.Chunks { + if c.EndBlockNumber > maxBlockHeight { + maxBlockHeight = c.EndBlockNumber } + totalGasUsed += c.TotalL2TxGas } // Get the commitment from the batch data: for validium mode, we use the last L2 block hash as the commitment to the off-chain data - // Get the last chunk from the last batch to find the end block hash + // Get the last chunk from the batch to find the end block hash // TODO: This is a temporary solution, we might use a larger commitment in the future - if len(batchesToSubmit) == 0 { - return nil, 0, 0, fmt.Errorf("no batches to submit") - } - - lastBatch := batchesToSubmit[len(batchesToSubmit)-1] - if len(lastBatch.Chunks) == 0 { + if len(batch.Chunks) == 0 { return nil, 0, 0, fmt.Errorf("last batch has no chunks") } - lastChunk := lastBatch.Chunks[len(lastBatch.Chunks)-1] + lastChunk := batch.Chunks[len(batch.Chunks)-1] commitment := common.HexToHash(lastChunk.EndBlockHash) - - calldata, err := r.validiumABI.Pack("commitBatch", version, common.HexToHash(batch.ParentBatchHash), common.HexToHash(batch.StateRoot), common.HexToHash(batch.WithdrawRoot), commitment[:]) + version := encoding.CodecVersion(batch.Batch.CodecVersion) + calldata, err := r.validiumABI.Pack("commitBatch", version, common.HexToHash(batch.Batch.ParentBatchHash), common.HexToHash(batch.Batch.StateRoot), common.HexToHash(batch.Batch.WithdrawRoot), commitment[:]) if err != nil { return nil, 0, 0, fmt.Errorf("failed to pack commitBatch: %w", err) } From 609a7321ace53b798a055618c7f80c12ad6f4334 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Tue, 8 Jul 2025 22:33:14 +0800 Subject: [PATCH 10/17] add validium flag in initializeGenesis --- rollup/internal/controller/relayer/l2_relayer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 689e63ba37..fad50f0da8 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -244,7 +244,7 @@ func (r *Layer2Relayer) initializeGenesis() error { } var dbBatch *orm.Batch - dbBatch, err = r.batchOrm.InsertBatch(r.ctx, batch, encoding.CodecV0, rutils.BatchMetrics{}, dbTX) + dbBatch, err = r.batchOrm.InsertBatch(r.ctx, batch, encoding.CodecV0, rutils.BatchMetrics{ValidiumMode: r.cfg.ValidiumMode}, dbTX) if err != nil { return fmt.Errorf("failed to insert batch: %v", err) } From dee727b7fbcda564b2af26a56076ae9232ca29b4 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Tue, 8 Jul 2025 23:10:34 +0800 Subject: [PATCH 11/17] add Blocks in initializeGenesis batch init --- rollup/internal/controller/relayer/l2_relayer.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index fad50f0da8..1ca528e681 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -241,6 +241,7 @@ func (r *Layer2Relayer) initializeGenesis() error { TotalL1MessagePoppedBefore: 0, ParentBatchHash: common.Hash{}, Chunks: []*encoding.Chunk{chunk}, + Blocks: chunk.Blocks, } var dbBatch *orm.Batch From e28d936c0d2c4b37c8771ab04b06ed0704c9b226 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Wed, 9 Jul 2025 03:15:19 +0800 Subject: [PATCH 12/17] fix validium fake finalize --- rollup/internal/controller/relayer/l2_relayer.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 1ca528e681..0ce78bb9ae 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -1050,15 +1050,16 @@ func (r *Layer2Relayer) constructFinalizeBundlePayloadCodecV7(dbBatch *orm.Batch func (r *Layer2Relayer) constructFinalizeBundlePayloadValidium(dbBatch *orm.Batch, endChunk *orm.Chunk, aggProof *message.OpenVMBundleProof) ([]byte, error) { log.Info("Packing validium finalizeBundle", "batchHeaderLength", len(dbBatch.BatchHeader), "codecVersion", dbBatch.CodecVersion, "totalL1Messages", endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk, "stateRoot", dbBatch.StateRoot, "withdrawRoot", dbBatch.WithdrawRoot) - if aggProof == nil { - return nil, fmt.Errorf("aggProof is required for validium finalizeBundle") + var proof []byte + if aggProof != nil { + proof = aggProof.Proof() } calldata, packErr := r.validiumABI.Pack( "finalizeBundle", dbBatch.BatchHeader, new(big.Int).SetUint64(endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk), - aggProof.Proof(), + proof, ) if packErr != nil { return nil, fmt.Errorf("failed to pack validium finalizeBundle: %w", packErr) From 7c3be7f0c3b00ccc833f1973c03eb04b1f122418 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Wed, 9 Jul 2025 03:15:58 +0800 Subject: [PATCH 13/17] add a log --- rollup/internal/controller/relayer/l2_relayer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 0ce78bb9ae..b1ac99940c 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -1048,7 +1048,7 @@ func (r *Layer2Relayer) constructFinalizeBundlePayloadCodecV7(dbBatch *orm.Batch } func (r *Layer2Relayer) constructFinalizeBundlePayloadValidium(dbBatch *orm.Batch, endChunk *orm.Chunk, aggProof *message.OpenVMBundleProof) ([]byte, error) { - log.Info("Packing validium finalizeBundle", "batchHeaderLength", len(dbBatch.BatchHeader), "codecVersion", dbBatch.CodecVersion, "totalL1Messages", endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk, "stateRoot", dbBatch.StateRoot, "withdrawRoot", dbBatch.WithdrawRoot) + log.Info("Packing validium finalizeBundle", "batchHeaderLength", len(dbBatch.BatchHeader), "codecVersion", dbBatch.CodecVersion, "totalL1Messages", endChunk.TotalL1MessagesPoppedBefore+endChunk.TotalL1MessagesPoppedInChunk, "stateRoot", dbBatch.StateRoot, "withdrawRoot", dbBatch.WithdrawRoot, "withProof", aggProof != nil) var proof []byte if aggProof != nil { From 90282fc86335e5d1d6a1de1584315c32b52fcff4 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Wed, 9 Jul 2025 03:28:25 +0800 Subject: [PATCH 14/17] remove an unused config --- rollup/internal/config/relayer.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/rollup/internal/config/relayer.go b/rollup/internal/config/relayer.go index bf93f2f575..db2e274681 100644 --- a/rollup/internal/config/relayer.go +++ b/rollup/internal/config/relayer.go @@ -75,8 +75,6 @@ type RelayerConfig struct { // Indicates if bypass features specific to testing environments are enabled. EnableTestEnvBypassFeatures bool `json:"enable_test_env_bypass_features"` - // The timeout in seconds for finalizing a batch without proof, only used when EnableTestEnvBypassFeatures is true. - FinalizeBatchWithoutProofTimeoutSec uint64 `json:"finalize_batch_without_proof_timeout_sec"` // The timeout in seconds for finalizing a bundle without proof, only used when EnableTestEnvBypassFeatures is true. FinalizeBundleWithoutProofTimeoutSec uint64 `json:"finalize_bundle_without_proof_timeout_sec"` } From 72aa00ee5072450239869c4d10e777c67db18465 Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Wed, 9 Jul 2025 14:12:19 +0800 Subject: [PATCH 15/17] address comments --- rollup/cmd/rollup_relayer/app/app.go | 7 ------ .../internal/controller/relayer/l2_relayer.go | 23 ++++++++++++++----- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index b776ef9557..96bb73c14d 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -96,13 +96,6 @@ func action(ctx *cli.Context) error { log.Crit("cfg.L2Config.ChunkProposerConfig.MaxL2GasPerChunk must be greater than 0") } - if cfg.L2Config.RelayerConfig.ValidiumMode { - // Force single batch submission for validium mode, this looks a bit hacky but it avoids more changes in the relayer code. - cfg.L2Config.RelayerConfig.BatchSubmission.MinBatches = 1 - cfg.L2Config.RelayerConfig.BatchSubmission.MaxBatches = 1 - log.Info("Validium mode detected, forcing single batch submission", "minBatches", 1, "maxBatches", 1) - } - l2relayer, err := relayer.NewLayer2Relayer(ctx.Context, l2client, db, cfg.L2Config.RelayerConfig, genesis.Config, relayer.ServiceTypeL2RollupRelayer, registry) if err != nil { log.Crit("failed to create l2 relayer", "config file", cfgFile, "error", err) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index b1ac99940c..7fe6f82615 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -333,13 +333,16 @@ func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte, } // ProcessPendingBatches processes the pending batches by sending commitBatch transactions to layer 1. -// Pending batchess are submitted if one of the following conditions is met: +// Pending batches are submitted if one of the following conditions is met: // - the first batch is too old -> forceSubmit // - backlogCount > r.cfg.BatchSubmission.BacklogMax -> forceSubmit // - we have at least minBatches AND price hits a desired target price func (r *Layer2Relayer) ProcessPendingBatches() { + // Get effective batch limits based on validium mode + minBatches, maxBatches := r.getEffectiveBatchLimits() + // get pending batches from database in ascending order by their index. - dbBatches, err := r.batchOrm.GetFailedAndPendingBatches(r.ctx, r.cfg.BatchSubmission.MaxBatches) + dbBatches, err := r.batchOrm.GetFailedAndPendingBatches(r.ctx, maxBatches) if err != nil { log.Error("Failed to fetch pending L2 batches", "err", err) return @@ -448,21 +451,21 @@ func (r *Layer2Relayer) ProcessPendingBatches() { break } - if batchesToSubmitLen < r.cfg.BatchSubmission.MaxBatches { + if batchesToSubmitLen < maxBatches { batchesToSubmit = append(batchesToSubmit, &dbBatchWithChunks{ Batch: dbBatch, Chunks: dbChunks, }) } - if len(batchesToSubmit) >= r.cfg.BatchSubmission.MaxBatches { + if len(batchesToSubmit) >= maxBatches { break } } // we only submit batches if we have a timeout or if we have enough batches to submit - if !forceSubmit && len(batchesToSubmit) < r.cfg.BatchSubmission.MinBatches { - log.Debug("Not enough batches to submit", "count", len(batchesToSubmit), "minBatches", r.cfg.BatchSubmission.MinBatches, "maxBatches", r.cfg.BatchSubmission.MaxBatches) + if !forceSubmit && len(batchesToSubmit) < minBatches { + log.Debug("Not enough batches to submit", "count", len(batchesToSubmit), "minBatches", minBatches, "maxBatches", maxBatches) return } @@ -550,6 +553,14 @@ func (r *Layer2Relayer) ProcessPendingBatches() { log.Info("Sent the commitBatches tx to layer1", "batches count", len(batchesToSubmit), "start index", firstBatch.Index, "start hash", firstBatch.Hash, "end index", lastBatch.Index, "end hash", lastBatch.Hash, "tx hash", txHash.String()) } +// getEffectiveBatchLimits returns the effective min and max batch limits based on validium mode +func (r *Layer2Relayer) getEffectiveBatchLimits() (int, int) { + if r.cfg.ValidiumMode { + return 1, 1 // minBatches=1, maxBatches=1 + } + return r.cfg.BatchSubmission.MinBatches, r.cfg.BatchSubmission.MaxBatches +} + func (r *Layer2Relayer) contextIDFromBatches(codecVersion encoding.CodecVersion, batches []*dbBatchWithChunks) string { contextIDs := []string{fmt.Sprintf("v%d", codecVersion)} for _, batch := range batches { From de67222c15df9bbb5c63cbdeac0abafef1a178db Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Wed, 9 Jul 2025 15:01:57 +0800 Subject: [PATCH 16/17] tweaks --- rollup/internal/controller/relayer/l2_relayer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index 7fe6f82615..18110d7b17 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -338,7 +338,7 @@ func (r *Layer2Relayer) commitGenesisBatch(batchHash string, batchHeader []byte, // - backlogCount > r.cfg.BatchSubmission.BacklogMax -> forceSubmit // - we have at least minBatches AND price hits a desired target price func (r *Layer2Relayer) ProcessPendingBatches() { - // Get effective batch limits based on validium mode + // Get effective batch limits based on whether validium mode is enabled. minBatches, maxBatches := r.getEffectiveBatchLimits() // get pending batches from database in ascending order by their index. @@ -553,7 +553,7 @@ func (r *Layer2Relayer) ProcessPendingBatches() { log.Info("Sent the commitBatches tx to layer1", "batches count", len(batchesToSubmit), "start index", firstBatch.Index, "start hash", firstBatch.Hash, "end index", lastBatch.Index, "end hash", lastBatch.Hash, "tx hash", txHash.String()) } -// getEffectiveBatchLimits returns the effective min and max batch limits based on validium mode +// getEffectiveBatchLimits returns the effective min and max batch limits based on whether validium mode is enabled. func (r *Layer2Relayer) getEffectiveBatchLimits() (int, int) { if r.cfg.ValidiumMode { return 1, 1 // minBatches=1, maxBatches=1 From 9e4e9b47f6c9cd796c08480acc585ee2657f71ec Mon Sep 17 00:00:00 2001 From: colinlyguo Date: Wed, 9 Jul 2025 15:02:31 +0800 Subject: [PATCH 17/17] bump version --- common/version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/version/version.go b/common/version/version.go index 9989598fad..dedecf6097 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.5.28" +var tag = "v4.5.29" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok {