mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 21:56:43 +00:00
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>
This commit is contained in:
parent
38a3a9c919
commit
b235afbccf
6 changed files with 53 additions and 28 deletions
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import (
|
||||||
const (
|
const (
|
||||||
VersionMajor = 5 // Major version component of the current release
|
VersionMajor = 5 // Major version component of the current release
|
||||||
VersionMinor = 1 // Minor version component of the current release
|
VersionMinor = 1 // Minor version component of the current release
|
||||||
VersionPatch = 6 // Patch version component of the current release
|
VersionPatch = 7 // Patch version component of the current release
|
||||||
VersionMeta = "mainnet" // Version metadata to append to the version string
|
VersionMeta = "mainnet" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,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)
|
||||||
|
|
||||||
|
|
@ -311,9 +311,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 +340,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 +362,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)
|
||||||
|
|
@ -360,18 +377,18 @@ func (s *RollupSyncService) decodeChunkBlockRanges(txData []byte) ([]*rawdb.Chun
|
||||||
// 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) (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]
|
||||||
|
|
||||||
|
|
@ -392,7 +409,7 @@ func validateBatch(event *L1FinalizeBatchEvent, parentBatchMeta *rawdb.Finalized
|
||||||
// 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,7 +417,10 @@ 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)
|
syscall.Kill(os.Getpid(), syscall.SIGTERM)
|
||||||
return 0, nil, fmt.Errorf("batch hash mismatch")
|
return 0, nil, fmt.Errorf("batch hash mismatch")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue