sync rollup_sync_service fixes (#860)

* feat(rollup): add fallback if TransactionByHash fails in getting commitBatch calldata (#601)

* feat(rollup): add fallback if TransactionByHash fails in getting commitBatch calldata

* Update rollup/rollup_sync_service/rollup_sync_service.go

Co-authored-by: Péter Garamvölgyi <peter@scroll.io>

* change log.Warn to log.Debug

---------

Co-authored-by: Péter Garamvölgyi <peter@scroll.io>

* fix(rollup sync service): remove syscall.Kill (#636)

* fix(rollup sync service): remove syscall.Kill

* bump version

* fix(api-backend): disable finalized tag when rollup verify is disabled (#722)

---------

Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com>
Co-authored-by: Péter Garamvölgyi <peter@scroll.io>
This commit is contained in:
HAOYUatHZ 2024-06-26 17:38:00 +08:00 committed by GitHub
parent b521e62626
commit a83c05c9c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 88 additions and 45 deletions

View file

@ -28,7 +28,7 @@ type FinalizedBatchMeta struct {
func WriteRollupEventSyncedL1BlockNumber(db ethdb.KeyValueWriter, l1BlockNumber uint64) { func WriteRollupEventSyncedL1BlockNumber(db ethdb.KeyValueWriter, l1BlockNumber uint64) {
value := big.NewInt(0).SetUint64(l1BlockNumber).Bytes() value := big.NewInt(0).SetUint64(l1BlockNumber).Bytes()
if err := db.Put(rollupEventSyncedL1BlockNumberKey, value); err != nil { if err := db.Put(rollupEventSyncedL1BlockNumberKey, value); err != nil {
log.Crit("failed to store rollup event synced L1 block number for rollup event", "err", err) log.Crit("failed to store rollup event synced L1 block number for rollup event", "L1 block number", l1BlockNumber, "value", value, "err", err)
} }
} }
@ -44,7 +44,7 @@ func ReadRollupEventSyncedL1BlockNumber(db ethdb.Reader) *uint64 {
number := new(big.Int).SetBytes(data) number := new(big.Int).SetBytes(data)
if !number.IsUint64() { if !number.IsUint64() {
log.Crit("unexpected rollup event synced L1 block number in database", "number", number) log.Crit("unexpected rollup event synced L1 block number in database", "data", data, "number", number)
} }
rollupEventSyncedL1BlockNumber := number.Uint64() rollupEventSyncedL1BlockNumber := number.Uint64()
@ -54,12 +54,12 @@ func ReadRollupEventSyncedL1BlockNumber(db ethdb.Reader) *uint64 {
// WriteBatchChunkRanges writes the block ranges for each chunk within a batch to the database. // WriteBatchChunkRanges writes the block ranges for each chunk within a batch to the database.
// It serializes the chunk ranges using RLP and stores them under a key derived from the batch index. // It serializes the chunk ranges using RLP and stores them under a key derived from the batch index.
func WriteBatchChunkRanges(db ethdb.KeyValueWriter, batchIndex uint64, chunkBlockRanges []*ChunkBlockRange) { func WriteBatchChunkRanges(db ethdb.KeyValueWriter, batchIndex uint64, chunkBlockRanges []*ChunkBlockRange) {
bytes, err := rlp.EncodeToBytes(chunkBlockRanges) value, err := rlp.EncodeToBytes(chunkBlockRanges)
if err != nil { if err != nil {
log.Crit("failed to RLP encode batch chunk ranges", "batch index", batchIndex, "err", err) log.Crit("failed to RLP encode batch chunk ranges", "batch index", batchIndex, "err", err)
} }
if err := db.Put(batchChunkRangesKey(batchIndex), bytes); err != nil { if err := db.Put(batchChunkRangesKey(batchIndex), value); err != nil {
log.Crit("failed to store batch chunk ranges", "batch index", batchIndex, "err", err) log.Crit("failed to store batch chunk ranges", "batch index", batchIndex, "value", value, "err", err)
} }
} }
@ -92,12 +92,12 @@ func ReadBatchChunkRanges(db ethdb.Reader, batchIndex uint64) []*ChunkBlockRange
// WriteFinalizedBatchMeta stores the metadata of a finalized batch in the database. // WriteFinalizedBatchMeta stores the metadata of a finalized batch in the database.
func WriteFinalizedBatchMeta(db ethdb.KeyValueWriter, batchIndex uint64, finalizedBatchMeta *FinalizedBatchMeta) { func WriteFinalizedBatchMeta(db ethdb.KeyValueWriter, batchIndex uint64, finalizedBatchMeta *FinalizedBatchMeta) {
var err error var err error
bytes, err := rlp.EncodeToBytes(finalizedBatchMeta) value, err := rlp.EncodeToBytes(finalizedBatchMeta)
if err != nil { if err != nil {
log.Crit("failed to RLP encode batch metadata", "batch index", batchIndex, "err", err) log.Crit("failed to RLP encode batch metadata", "batch index", batchIndex, "finalized batch meta", finalizedBatchMeta, "err", err)
} }
if err := db.Put(batchMetaKey(batchIndex), bytes); err != nil { if err := db.Put(batchMetaKey(batchIndex), value); err != nil {
log.Crit("failed to store batch metadata", "batch index", batchIndex, "err", err) log.Crit("failed to store batch metadata", "batch index", batchIndex, "value", value, "err", err)
} }
} }
@ -108,7 +108,7 @@ func ReadFinalizedBatchMeta(db ethdb.Reader, batchIndex uint64) *FinalizedBatchM
return nil return nil
} }
if err != nil { if err != nil {
log.Crit("failed to read finalized batch metadata from database", "err", err) log.Crit("failed to read finalized batch metadata from database", "batch index", batchIndex, "err", err)
} }
fbm := new(FinalizedBatchMeta) fbm := new(FinalizedBatchMeta)
@ -122,7 +122,7 @@ func ReadFinalizedBatchMeta(db ethdb.Reader, batchIndex uint64) *FinalizedBatchM
func WriteFinalizedL2BlockNumber(db ethdb.KeyValueWriter, l2BlockNumber uint64) { func WriteFinalizedL2BlockNumber(db ethdb.KeyValueWriter, l2BlockNumber uint64) {
value := big.NewInt(0).SetUint64(l2BlockNumber).Bytes() value := big.NewInt(0).SetUint64(l2BlockNumber).Bytes()
if err := db.Put(finalizedL2BlockNumberKey, value); err != nil { if err := db.Put(finalizedL2BlockNumberKey, value); err != nil {
log.Crit("failed to store finalized L2 block number for rollup event", "err", err) log.Crit("failed to store finalized L2 block number for rollup event", "L2 block number", l2BlockNumber, "value", value, "err", err)
} }
} }
@ -133,12 +133,12 @@ func ReadFinalizedL2BlockNumber(db ethdb.Reader) *uint64 {
return nil return nil
} }
if err != nil { if err != nil {
log.Crit("failed to read finalized L2 block number from database", "err", err) log.Crit("failed to read finalized L2 block number from database", "key", finalizedL2BlockNumberKey, "err", err)
} }
number := new(big.Int).SetBytes(data) number := new(big.Int).SetBytes(data)
if !number.IsUint64() { if !number.IsUint64() {
log.Crit("unexpected finalized L2 block number in database", "number", number) log.Crit("unexpected finalized L2 block number in database", "data", data, "number", number)
} }
finalizedL2BlockNumber := number.Uint64() finalizedL2BlockNumber := number.Uint64()

View file

@ -92,6 +92,9 @@ func (b *EthAPIBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumb
// return block, nil // return block, nil
// } // }
if number == rpc.FinalizedBlockNumber { if number == rpc.FinalizedBlockNumber {
if !b.eth.config.EnableRollupVerify {
return nil, errors.New("sync L1 finalized batch feature not enabled, cannot query L2 finalized block height")
}
finalizedBlockHeightPtr := rawdb.ReadFinalizedL2BlockNumber(b.eth.ChainDb()) finalizedBlockHeightPtr := rawdb.ReadFinalizedL2BlockNumber(b.eth.ChainDb())
if finalizedBlockHeightPtr == nil { if finalizedBlockHeightPtr == nil {
return nil, errors.New("L2 finalized block height not found in database") return nil, errors.New("L2 finalized block height not found in database")
@ -152,6 +155,9 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
// return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil // return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
// } // }
if number == rpc.FinalizedBlockNumber { if number == rpc.FinalizedBlockNumber {
if !b.eth.config.EnableRollupVerify {
return nil, errors.New("sync L1 finalized batch feature not enabled, cannot query L2 finalized block height")
}
finalizedBlockHeightPtr := rawdb.ReadFinalizedL2BlockNumber(b.eth.ChainDb()) finalizedBlockHeightPtr := rawdb.ReadFinalizedL2BlockNumber(b.eth.ChainDb())
if finalizedBlockHeightPtr == nil { if finalizedBlockHeightPtr == nil {
return nil, errors.New("L2 finalized block height not found in database") return nil, errors.New("L2 finalized block height not found in database")

View file

@ -248,7 +248,7 @@ func New(stack *node.Node, config *ethconfig.Config, l1Client sync_service.EthCl
eth.syncService.Start() eth.syncService.Start()
if config.EnableRollupVerify { if config.EnableRollupVerify {
// initialize and start rollup event sync service // initialize and start rollup event sync service
eth.rollupSyncService, err = rollup_sync_service.NewRollupSyncService(context.Background(), chainConfig, eth.chainDb, l1Client, eth.blockchain, stack.Config().L1DeploymentBlock) eth.rollupSyncService, err = rollup_sync_service.NewRollupSyncService(context.Background(), chainConfig, eth.chainDb, l1Client, eth.blockchain, stack)
if err != nil { if err != nil {
return nil, fmt.Errorf("cannot initialize rollup event sync service: %w", err) return nil, fmt.Errorf("cannot initialize rollup event sync service: %w", err)
} }

View file

@ -132,7 +132,7 @@ func DecodeChunkBlockRanges(chunks [][]byte) ([]*rawdb.ChunkBlockRange, error) {
numBlocks := int(chunk[0]) numBlocks := int(chunk[0])
if len(chunk) < 1+numBlocks*blockContextByteSize { if len(chunk) < 1+numBlocks*blockContextByteSize {
return nil, fmt.Errorf("chunk size doesn't match with numBlocks") return nil, fmt.Errorf("chunk size doesn't match with numBlocks, byte length of chunk: %v, expected length: %v", len(chunk), 1+numBlocks*blockContextByteSize)
} }
blockContexts := make([]*BlockContext, numBlocks) blockContexts := make([]*BlockContext, numBlocks)

View file

@ -68,3 +68,7 @@ func (m *mockEthClient) TransactionByHash(ctx context.Context, txHash common.Has
} }
return &tx, false, nil return &tx, false, nil
} }
func (m *mockEthClient) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
return nil, nil
}

View file

@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"os" "os"
"reflect" "reflect"
"syscall"
"time" "time"
"github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi"
@ -16,8 +15,8 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rollup/rcfg" "github.com/ethereum/go-ethereum/rollup/rcfg"
"github.com/ethereum/go-ethereum/rollup/sync_service" "github.com/ethereum/go-ethereum/rollup/sync_service"
"github.com/ethereum/go-ethereum/rollup/withdrawtrie" "github.com/ethereum/go-ethereum/rollup/withdrawtrie"
@ -54,9 +53,10 @@ type RollupSyncService struct {
l1RevertBatchEventSignature common.Hash l1RevertBatchEventSignature common.Hash
l1FinalizeBatchEventSignature common.Hash l1FinalizeBatchEventSignature common.Hash
bc *core.BlockChain bc *core.BlockChain
stack *node.Node
} }
func NewRollupSyncService(ctx context.Context, genesisConfig *params.ChainConfig, db ethdb.Database, l1Client sync_service.EthClient, bc *core.BlockChain, l1DeploymentBlock uint64) (*RollupSyncService, error) { func NewRollupSyncService(ctx context.Context, genesisConfig *params.ChainConfig, db ethdb.Database, l1Client sync_service.EthClient, bc *core.BlockChain, stack *node.Node) (*RollupSyncService, error) {
// terminate if the caller does not provide an L1 client (e.g. in tests) // terminate if the caller does not provide an L1 client (e.g. in tests)
if l1Client == nil || (reflect.ValueOf(l1Client).Kind() == reflect.Ptr && reflect.ValueOf(l1Client).IsNil()) { if l1Client == nil || (reflect.ValueOf(l1Client).Kind() == reflect.Ptr && reflect.ValueOf(l1Client).IsNil()) {
log.Warn("No L1 client provided, L1 rollup sync service will not run") log.Warn("No L1 client provided, L1 rollup sync service will not run")
@ -80,8 +80,8 @@ func NewRollupSyncService(ctx context.Context, genesisConfig *params.ChainConfig
// Initialize the latestProcessedBlock with the block just before the L1 deployment block. // Initialize the latestProcessedBlock with the block just before the L1 deployment block.
// This serves as a default value when there's no L1 rollup events synced in the database. // This serves as a default value when there's no L1 rollup events synced in the database.
var latestProcessedBlock uint64 var latestProcessedBlock uint64
if l1DeploymentBlock > 0 { if stack.Config().L1DeploymentBlock > 0 {
latestProcessedBlock = l1DeploymentBlock - 1 latestProcessedBlock = stack.Config().L1DeploymentBlock - 1
} }
block := rawdb.ReadRollupEventSyncedL1BlockNumber(db) block := rawdb.ReadRollupEventSyncedL1BlockNumber(db)
@ -103,6 +103,7 @@ func NewRollupSyncService(ctx context.Context, genesisConfig *params.ChainConfig
l1RevertBatchEventSignature: scrollChainABI.Events["RevertBatch"].ID, l1RevertBatchEventSignature: scrollChainABI.Events["RevertBatch"].ID,
l1FinalizeBatchEventSignature: scrollChainABI.Events["FinalizeBatch"].ID, l1FinalizeBatchEventSignature: scrollChainABI.Events["FinalizeBatch"].ID,
bc: bc, bc: bc,
stack: stack,
} }
return &service, nil return &service, nil
@ -196,7 +197,7 @@ func (s *RollupSyncService) parseAndUpdateRollupEventLogs(logs []types.Log, endB
chunkBlockRanges, err := s.getChunkRanges(batchIndex, &vLog) chunkBlockRanges, err := s.getChunkRanges(batchIndex, &vLog)
if err != nil { if err != nil {
return fmt.Errorf("failed to get chunk ranges, err: %w", err) return fmt.Errorf("failed to get chunk ranges, batch index: %v, err: %w", batchIndex, err)
} }
rawdb.WriteBatchChunkRanges(s.db, batchIndex, chunkBlockRanges) rawdb.WriteBatchChunkRanges(s.db, batchIndex, chunkBlockRanges)
@ -223,7 +224,7 @@ func (s *RollupSyncService) parseAndUpdateRollupEventLogs(logs []types.Log, endB
return fmt.Errorf("failed to get local node info, batch index: %v, err: %w", batchIndex, err) return fmt.Errorf("failed to get local node info, batch index: %v, err: %w", batchIndex, err)
} }
endBlock, finalizedBatchMeta, err := validateBatch(event, parentBatchMeta, chunks) endBlock, finalizedBatchMeta, err := validateBatch(event, parentBatchMeta, chunks, s.stack)
if err != nil { if err != nil {
return fmt.Errorf("fatal: validateBatch failed: finalize event: %v, err: %w", event, err) return fmt.Errorf("fatal: validateBatch failed: finalize event: %v, err: %w", event, err)
} }
@ -311,9 +312,26 @@ func (s *RollupSyncService) getChunkRanges(batchIndex uint64, vLog *types.Log) (
return []*rawdb.ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 0}}, nil return []*rawdb.ChunkBlockRange{{StartBlockNumber: 0, EndBlockNumber: 0}}, nil
} }
tx, _, err := s.client.client.TransactionByHash(context.Background(), vLog.TxHash) tx, _, err := s.client.client.TransactionByHash(s.ctx, vLog.TxHash)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get transaction, err: %w", err) log.Debug("failed to get transaction by hash, probably an unindexed transaction, fetching the whole block to get the transaction",
"tx hash", vLog.TxHash.Hex(), "block number", vLog.BlockNumber, "block hash", vLog.BlockHash.Hex(), "err", err)
block, err := s.client.client.BlockByHash(s.ctx, vLog.BlockHash)
if err != nil {
return nil, fmt.Errorf("failed to get block by hash, block number: %v, block hash: %v, err: %w", vLog.BlockNumber, vLog.BlockHash.Hex(), err)
}
found := false
for _, txInBlock := range block.Transactions() {
if txInBlock.Hash() == vLog.TxHash {
tx = txInBlock
found = true
break
}
}
if !found {
return nil, fmt.Errorf("transaction not found in the block, tx hash: %v, block number: %v, block hash: %v", vLog.TxHash.Hex(), vLog.BlockNumber, vLog.BlockHash.Hex())
}
} }
return s.decodeChunkBlockRanges(tx.Data()) return s.decodeChunkBlockRanges(tx.Data())
@ -323,17 +341,17 @@ func (s *RollupSyncService) getChunkRanges(batchIndex uint64, vLog *types.Log) (
func (s *RollupSyncService) decodeChunkBlockRanges(txData []byte) ([]*rawdb.ChunkBlockRange, error) { func (s *RollupSyncService) decodeChunkBlockRanges(txData []byte) ([]*rawdb.ChunkBlockRange, error) {
const methodIDLength = 4 const methodIDLength = 4
if len(txData) < methodIDLength { if len(txData) < methodIDLength {
return nil, fmt.Errorf("transaction data is too short") return nil, fmt.Errorf("transaction data is too short, length of tx data: %v, minimum length required: %v", len(txData), methodIDLength)
} }
method, err := s.scrollChainABI.MethodById(txData[:methodIDLength]) method, err := s.scrollChainABI.MethodById(txData[:methodIDLength])
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get method by ID, ID: %v, err: %w", txData[:4], err) return nil, fmt.Errorf("failed to get method by ID, ID: %v, err: %w", txData[:methodIDLength], err)
} }
values, err := method.Inputs.Unpack(txData[methodIDLength:]) values, err := method.Inputs.Unpack(txData[methodIDLength:])
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to unpack transaction data using ABI: %v", err) return nil, fmt.Errorf("failed to unpack transaction data using ABI, tx data: %v, err: %w", txData, err)
} }
type commitBatchArgs struct { type commitBatchArgs struct {
@ -345,11 +363,11 @@ func (s *RollupSyncService) decodeChunkBlockRanges(txData []byte) ([]*rawdb.Chun
var args commitBatchArgs var args commitBatchArgs
err = method.Inputs.Copy(&args, values) err = method.Inputs.Copy(&args, values)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to decode calldata into commitBatch args, err: %w", err) return nil, fmt.Errorf("failed to decode calldata into commitBatch args, values: %+v, err: %w", values, err)
} }
if args.Version != batchHeaderVersion { if args.Version != batchHeaderVersion {
return nil, fmt.Errorf("unexpected batch version, expected: %d, got: %v", batchHeaderVersion, args.Version) return nil, fmt.Errorf("unexpected batch version, expected: %v, got: %v", batchHeaderVersion, args.Version)
} }
return DecodeChunkBlockRanges(args.Chunks) return DecodeChunkBlockRanges(args.Chunks)
@ -358,41 +376,41 @@ func (s *RollupSyncService) decodeChunkBlockRanges(txData []byte) ([]*rawdb.Chun
// validateBatch verifies the consistency between the L1 contract and L2 node data. // validateBatch verifies the consistency between the L1 contract and L2 node data.
// The function will terminate the node and exit if any consistency check fails. // The function will terminate the node and exit if any consistency check fails.
// It returns the number of the end block, a finalized batch meta data, and an error if any. // It returns the number of the end block, a finalized batch meta data, and an error if any.
func validateBatch(event *L1FinalizeBatchEvent, parentBatchMeta *rawdb.FinalizedBatchMeta, chunks []*Chunk) (uint64, *rawdb.FinalizedBatchMeta, error) { func validateBatch(event *L1FinalizeBatchEvent, parentBatchMeta *rawdb.FinalizedBatchMeta, chunks []*Chunk, stack *node.Node) (uint64, *rawdb.FinalizedBatchMeta, error) {
if len(chunks) == 0 { if len(chunks) == 0 {
return 0, nil, fmt.Errorf("invalid argument: length of chunks is 0") return 0, nil, fmt.Errorf("invalid argument: length of chunks is 0, batch index: %v", event.BatchIndex.Uint64())
} }
startChunk := chunks[0] startChunk := chunks[0]
if len(startChunk.Blocks) == 0 { if len(startChunk.Blocks) == 0 {
return 0, nil, fmt.Errorf("invalid argument: block count of start chunk is 0") return 0, nil, fmt.Errorf("invalid argument: block count of start chunk is 0, batch index: %v", event.BatchIndex.Uint64())
} }
startBlock := startChunk.Blocks[0] startBlock := startChunk.Blocks[0]
endChunk := chunks[len(chunks)-1] endChunk := chunks[len(chunks)-1]
if len(endChunk.Blocks) == 0 { if len(endChunk.Blocks) == 0 {
return 0, nil, fmt.Errorf("invalid argument: block count of end chunk is 0") return 0, nil, fmt.Errorf("invalid argument: block count of end chunk is 0, batch index: %v", event.BatchIndex.Uint64())
} }
endBlock := endChunk.Blocks[len(endChunk.Blocks)-1] endBlock := endChunk.Blocks[len(endChunk.Blocks)-1]
localStateRoot := endBlock.Header.Root localStateRoot := endBlock.Header.Root
if localStateRoot != event.StateRoot { if localStateRoot != event.StateRoot {
log.Error("State root mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "l1 finalized state root", event.StateRoot.Hex(), "l2 state root", localStateRoot.Hex()) log.Error("State root mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "l1 finalized state root", event.StateRoot.Hex(), "l2 state root", localStateRoot.Hex())
syscall.Kill(os.Getpid(), syscall.SIGTERM) stack.Close()
return 0, nil, fmt.Errorf("state root mismatch") os.Exit(1)
} }
localWithdrawRoot := endBlock.WithdrawRoot localWithdrawRoot := endBlock.WithdrawRoot
if localWithdrawRoot != event.WithdrawRoot { if localWithdrawRoot != event.WithdrawRoot {
log.Error("Withdraw root mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "l1 finalized withdraw root", event.WithdrawRoot.Hex(), "l2 withdraw root", localWithdrawRoot.Hex()) log.Error("Withdraw root mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "l1 finalized withdraw root", event.WithdrawRoot.Hex(), "l2 withdraw root", localWithdrawRoot.Hex())
syscall.Kill(os.Getpid(), syscall.SIGTERM) stack.Close()
return 0, nil, fmt.Errorf("withdraw root mismatch") os.Exit(1)
} }
// Note: All params for NewBatchHeader are calculated locally based on the block data. // Note: All params for NewBatchHeader are calculated locally based on the block data.
batchHeader, err := NewBatchHeader(batchHeaderVersion, event.BatchIndex.Uint64(), parentBatchMeta.TotalL1MessagePopped, parentBatchMeta.BatchHash, chunks) batchHeader, err := NewBatchHeader(batchHeaderVersion, event.BatchIndex.Uint64(), parentBatchMeta.TotalL1MessagePopped, parentBatchMeta.BatchHash, chunks)
if err != nil { if err != nil {
return 0, nil, fmt.Errorf("failed to construct batch header, err: %w", err) return 0, nil, fmt.Errorf("failed to construct batch header, batch index: %v, err: %w", event.BatchIndex.Uint64(), err)
} }
// Note: If the batch headers match, this ensures the consistency of blocks and transactions // Note: If the batch headers match, this ensures the consistency of blocks and transactions
@ -400,10 +418,13 @@ func validateBatch(event *L1FinalizeBatchEvent, parentBatchMeta *rawdb.Finalized
localBatchHash := batchHeader.Hash() localBatchHash := batchHeader.Hash()
if localBatchHash != event.BatchHash { if localBatchHash != event.BatchHash {
log.Error("Batch hash mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "parent TotalL1MessagePopped", parentBatchMeta.TotalL1MessagePopped, "l1 finalized batch hash", event.BatchHash.Hex(), "l2 batch hash", localBatchHash.Hex()) log.Error("Batch hash mismatch", "batch index", event.BatchIndex.Uint64(), "start block", startBlock.Header.Number.Uint64(), "end block", endBlock.Header.Number.Uint64(), "parent batch hash", parentBatchMeta.BatchHash.Hex(), "parent TotalL1MessagePopped", parentBatchMeta.TotalL1MessagePopped, "l1 finalized batch hash", event.BatchHash.Hex(), "l2 batch hash", localBatchHash.Hex())
chunksJson, _ := json.Marshal(chunks) chunksJson, err := json.Marshal(chunks)
if err != nil {
log.Error("marshal chunks failed", "err", err)
}
log.Error("Chunks", "chunks", string(chunksJson)) log.Error("Chunks", "chunks", string(chunksJson))
syscall.Kill(os.Getpid(), syscall.SIGTERM) stack.Close()
return 0, nil, fmt.Errorf("batch hash mismatch") os.Exit(1)
} }
totalL1MessagePopped := parentBatchMeta.TotalL1MessagePopped totalL1MessagePopped := parentBatchMeta.TotalL1MessagePopped

View file

@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb/memorydb" "github.com/ethereum/go-ethereum/ethdb/memorydb"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
@ -32,7 +33,12 @@ func TestRollupSyncServiceStartAndStop(t *testing.T) {
db := rawdb.NewDatabase(memorydb.New()) db := rawdb.NewDatabase(memorydb.New())
l1Client := &mockEthClient{} l1Client := &mockEthClient{}
bc := &core.BlockChain{} bc := &core.BlockChain{}
service, err := NewRollupSyncService(context.Background(), genesisConfig, db, l1Client, bc, 1) stack, err := node.New(&node.DefaultConfig)
if err != nil {
t.Fatalf("Failed to new P2P node: %v", err)
}
defer stack.Close()
service, err := NewRollupSyncService(context.Background(), genesisConfig, db, l1Client, bc, stack)
if err != nil { if err != nil {
t.Fatalf("Failed to new rollup sync service: %v", err) t.Fatalf("Failed to new rollup sync service: %v", err)
} }
@ -112,7 +118,12 @@ func TestGetChunkRanges(t *testing.T) {
commitBatchRLP: rlpData, commitBatchRLP: rlpData,
} }
bc := &core.BlockChain{} bc := &core.BlockChain{}
service, err := NewRollupSyncService(context.Background(), genesisConfig, db, l1Client, bc, 1) stack, err := node.New(&node.DefaultConfig)
if err != nil {
t.Fatalf("Failed to new P2P node: %v", err)
}
defer stack.Close()
service, err := NewRollupSyncService(context.Background(), genesisConfig, db, l1Client, bc, stack)
if err != nil { if err != nil {
t.Fatalf("Failed to new rollup sync service: %v", err) t.Fatalf("Failed to new rollup sync service: %v", err)
} }
@ -169,7 +180,7 @@ func TestValidateBatch(t *testing.T) {
StateRoot: chunk3.Blocks[len(chunk3.Blocks)-1].Header.Root, StateRoot: chunk3.Blocks[len(chunk3.Blocks)-1].Header.Root,
WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk3.Blocks[len(chunk3.Blocks)-1].WithdrawRoot,
} }
endBlock1, finalizedBatchMeta1, err := validateBatch(event1, parentBatchMeta1, []*Chunk{chunk1, chunk2, chunk3}) endBlock1, finalizedBatchMeta1, err := validateBatch(event1, parentBatchMeta1, []*Chunk{chunk1, chunk2, chunk3}, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(13), endBlock1) assert.Equal(t, uint64(13), endBlock1)
@ -193,7 +204,7 @@ func TestValidateBatch(t *testing.T) {
StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root, StateRoot: chunk4.Blocks[len(chunk4.Blocks)-1].Header.Root,
WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot, WithdrawRoot: chunk4.Blocks[len(chunk4.Blocks)-1].WithdrawRoot,
} }
endBlock2, finalizedBatchMeta2, err := validateBatch(event2, parentBatchMeta2, []*Chunk{chunk4}) endBlock2, finalizedBatchMeta2, err := validateBatch(event2, parentBatchMeta2, []*Chunk{chunk4}, nil)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, uint64(17), endBlock2) assert.Equal(t, uint64(17), endBlock2)

View file

@ -18,4 +18,5 @@ type EthClient interface {
HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error)
SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)
TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error)
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
} }