From 0737d5d3e37dede97f3013e38a7967e8d8d9381d Mon Sep 17 00:00:00 2001 From: colin <102356659+colinlyguo@users.noreply.github.com> Date: Wed, 10 Jul 2024 11:54:37 +0800 Subject: [PATCH] feat(bridge-history): generate withdraw proofs by bundle (#1415) --- bridge-history-api/conf/config.json | 4 +- .../internal/controller/fetcher/l2_fetcher.go | 2 +- .../internal/logic/event_update.go | 39 ++++++++++--- .../internal/logic/l1_event_parser.go | 1 + .../internal/orm/batch_event.go | 55 +++++++++---------- common/version/version.go | 2 +- 6 files changed, 63 insertions(+), 40 deletions(-) diff --git a/bridge-history-api/conf/config.json b/bridge-history-api/conf/config.json index a2a975bcd..4ade09774 100644 --- a/bridge-history-api/conf/config.json +++ b/bridge-history-api/conf/config.json @@ -19,7 +19,7 @@ "ScrollChainAddr": "0xa13BAF47339d63B743e7Da8741db5456DAc1E556", "GatewayRouterAddr": "0xF8B1378579659D8F7EE5f3C929c2f3E332E41Fd6", "MessageQueueAddr": "0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B", - "BatchBridgeGatewayAddr": "0x0000000000000000000000000000000000000000" + "BatchBridgeGatewayAddr": "0x5Bcfd99c34cf7E06fc756f6f5aE7400504852bc4" }, "L2": { "confirmation": 0, @@ -39,7 +39,7 @@ "PufferGatewayAddr": "0x9eBf2f33526CD571f8b2ad312492cb650870CFd6", "GatewayRouterAddr": "0x4C0926FF5252A435FD19e10ED15e5a249Ba19d79", "MessageQueueAddr": "0x5300000000000000000000000000000000000000", - "BatchBridgeGatewayAddr": "0x0000000000000000000000000000000000000000" + "BatchBridgeGatewayAddr": "0xa1a12158bE6269D7580C63eC5E609Cdc0ddD82bC" }, "db": { "dsn": "postgres://postgres:123456@localhost:5444/test?sslmode=disable", diff --git a/bridge-history-api/internal/controller/fetcher/l2_fetcher.go b/bridge-history-api/internal/controller/fetcher/l2_fetcher.go index 03e909247..2eba55c0e 100644 --- a/bridge-history-api/internal/controller/fetcher/l2_fetcher.go +++ b/bridge-history-api/internal/controller/fetcher/l2_fetcher.go @@ -141,7 +141,7 @@ func (c *L2MessageFetcher) fetchAndSaveEvents(confirmation uint64) { return } - if updateErr := c.eventUpdateLogic.UpdateL1BatchIndexAndStatus(c.ctx, c.l2SyncHeight); updateErr != nil { + if updateErr := c.eventUpdateLogic.UpdateL2WithdrawMessageProofs(c.ctx, c.l2SyncHeight); updateErr != nil { log.Error("failed to update L1 batch index and status", "from", from, "to", to, "err", updateErr) return } diff --git a/bridge-history-api/internal/logic/event_update.go b/bridge-history-api/internal/logic/event_update.go index 6ecaf0962..00c93a0f6 100644 --- a/bridge-history-api/internal/logic/event_update.go +++ b/bridge-history-api/internal/logic/event_update.go @@ -125,6 +125,11 @@ func (b *EventUpdateLogic) L1InsertOrUpdate(ctx context.Context, l1FetcherResult } func (b *EventUpdateLogic) updateL2WithdrawMessageInfos(ctx context.Context, batchIndex, startBlock, endBlock uint64) error { + if startBlock > endBlock { + log.Warn("start block is greater than end block", "start", startBlock, "end", endBlock) + return nil + } + l2WithdrawMessages, err := b.crossMessageOrm.GetL2WithdrawalsByBlockRange(ctx, startBlock, endBlock) if err != nil { log.Error("failed to get L2 withdrawals by batch index", "batch index", batchIndex, "err", err) @@ -173,24 +178,42 @@ func (b *EventUpdateLogic) updateL2WithdrawMessageInfos(ctx context.Context, bat return nil } -// UpdateL1BatchIndexAndStatus updates L1 finalized batch index and status -func (b *EventUpdateLogic) UpdateL1BatchIndexAndStatus(ctx context.Context, height uint64) error { - finalizedBatches, err := b.batchEventOrm.GetFinalizedBatchesLEBlockHeight(ctx, height) +// UpdateL2WithdrawMessageProofs updates L2 withdrawal message proofs. +func (b *EventUpdateLogic) UpdateL2WithdrawMessageProofs(ctx context.Context, height uint64) error { + lastUpdatedFinalizedBlockHeight, err := b.batchEventOrm.GetLastUpdatedFinalizedBlockHeight(ctx) if err != nil { - log.Error("failed to get batches >= block height", "error", err) + log.Error("failed to get last updated finalized block height", "error", err) + return err + } + + finalizedBatches, err := b.batchEventOrm.GetUnupdatedFinalizedBatchesLEBlockHeight(ctx, height) + if err != nil { + log.Error("failed to get unupdated finalized batches >= block height", "error", err) return err } for _, finalizedBatch := range finalizedBatches { - log.Info("update finalized batch info of L2 withdrawals", "index", finalizedBatch.BatchIndex, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber) - if updateErr := b.updateL2WithdrawMessageInfos(ctx, finalizedBatch.BatchIndex, finalizedBatch.StartBlockNumber, finalizedBatch.EndBlockNumber); updateErr != nil { - log.Error("failed to update L2 withdraw message infos", "index", finalizedBatch.BatchIndex, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", updateErr) + log.Info("update finalized batch or bundle info of L2 withdrawals", "index", finalizedBatch.BatchIndex, "lastUpdatedFinalizedBlockHeight", lastUpdatedFinalizedBlockHeight, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber) + // This method is compatible with both "finalize by batch" and "finalize by bundle" modes: + // - In "finalize by batch" mode, each batch emits a FinalizedBatch event. + // - In "finalize by bundle" mode, all batches in the bundle emit only one FinalizedBatch event, using the last batch's index and hash. + // + // The method updates two types of information in L2 withdrawal messages: + // 1. Withdraw proof generation: + // - finalize by batch: Generates proofs for each batch. + // - finalize by bundle: Generates proofs for the entire bundle at once. + // 2. Batch index updating: + // - finalize by batch: Updates the batch index for withdrawal messages in each processed batch. + // - finalize by bundle: Updates the batch index for all withdrawal messages in the bundle, using the index of the last batch in the bundle. + if updateErr := b.updateL2WithdrawMessageInfos(ctx, finalizedBatch.BatchIndex, lastUpdatedFinalizedBlockHeight+1, finalizedBatch.EndBlockNumber); updateErr != nil { + log.Error("failed to update L2 withdraw message infos", "index", finalizedBatch.BatchIndex, "lastUpdatedFinalizedBlockHeight", lastUpdatedFinalizedBlockHeight, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", updateErr) return updateErr } if dbErr := b.batchEventOrm.UpdateBatchEventStatus(ctx, finalizedBatch.BatchIndex); dbErr != nil { - log.Error("failed to update batch event status as updated", "index", finalizedBatch.BatchIndex, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", dbErr) + log.Error("failed to update batch event status as updated", "index", finalizedBatch.BatchIndex, "lastUpdatedFinalizedBlockHeight", lastUpdatedFinalizedBlockHeight, "start", finalizedBatch.StartBlockNumber, "end", finalizedBatch.EndBlockNumber, "error", dbErr) return dbErr } + lastUpdatedFinalizedBlockHeight = finalizedBatch.EndBlockNumber b.eventUpdateLogicL1FinalizeBatchEventL2BlockUpdateHeight.Set(float64(finalizedBatch.EndBlockNumber)) } return nil diff --git a/bridge-history-api/internal/logic/l1_event_parser.go b/bridge-history-api/internal/logic/l1_event_parser.go index 8f87775ab..837ae3765 100644 --- a/bridge-history-api/internal/logic/l1_event_parser.go +++ b/bridge-history-api/internal/logic/l1_event_parser.go @@ -273,6 +273,7 @@ func (e *L1EventParser) ParseL1BatchEventLogs(ctx context.Context, logs []types. l1BatchEvents = append(l1BatchEvents, &orm.BatchEvent{ BatchStatus: int(btypes.BatchStatusTypeFinalized), BatchIndex: event.BatchIndex.Uint64(), + BatchHash: event.BatchHash.String(), L1BlockNumber: vlog.BlockNumber, }) } diff --git a/bridge-history-api/internal/orm/batch_event.go b/bridge-history-api/internal/orm/batch_event.go index 02e214cb2..6812dc3ba 100644 --- a/bridge-history-api/internal/orm/batch_event.go +++ b/bridge-history-api/internal/orm/batch_event.go @@ -53,8 +53,26 @@ func (c *BatchEvent) GetBatchEventSyncedHeightInDB(ctx context.Context) (uint64, return batch.L1BlockNumber, nil } -// GetFinalizedBatchesLEBlockHeight returns the finalized batches with end block <= given block height in db. -func (c *BatchEvent) GetFinalizedBatchesLEBlockHeight(ctx context.Context, blockHeight uint64) ([]*BatchEvent, error) { +// GetLastUpdatedFinalizedBlockHeight returns the last updated finalized block height in db. +func (c *BatchEvent) GetLastUpdatedFinalizedBlockHeight(ctx context.Context) (uint64, error) { + var batch BatchEvent + db := c.db.WithContext(ctx) + db = db.Model(&BatchEvent{}) + db = db.Where("batch_status = ?", btypes.BatchStatusTypeFinalized) + db = db.Where("update_status = ?", btypes.UpdateStatusTypeUpdated) + db = db.Order("batch_index desc") + if err := db.First(&batch).Error; err != nil { + if err == gorm.ErrRecordNotFound { + // No finalized batch found, return genesis batch's end block number. + return 0, nil + } + return 0, fmt.Errorf("failed to get last updated finalized block height, error: %w", err) + } + return batch.EndBlockNumber, nil +} + +// GetUnupdatedFinalizedBatchesLEBlockHeight returns the finalized batches with end block <= given block height in db. +func (c *BatchEvent) GetUnupdatedFinalizedBatchesLEBlockHeight(ctx context.Context, blockHeight uint64) ([]*BatchEvent, error) { var batches []*BatchEvent db := c.db.WithContext(ctx) db = db.Model(&BatchEvent{}) @@ -66,16 +84,13 @@ func (c *BatchEvent) GetFinalizedBatchesLEBlockHeight(ctx context.Context, block if err == gorm.ErrRecordNotFound { return nil, nil } - return nil, fmt.Errorf("failed to get batches >= block height, error: %w", err) + return nil, fmt.Errorf("failed to get unupdated finalized batches >= block height, error: %w", err) } return batches, nil } // InsertOrUpdateBatchEvents inserts a new batch event or updates an existing one based on the BatchStatusType. func (c *BatchEvent) InsertOrUpdateBatchEvents(ctx context.Context, l1BatchEvents []*BatchEvent) error { - var maxFinalizedBatchIndex uint64 - var containsFinalizedEvent bool - var maxL1BlockNumber uint64 for _, l1BatchEvent := range l1BatchEvents { db := c.db db = db.WithContext(ctx) @@ -92,13 +107,12 @@ func (c *BatchEvent) InsertOrUpdateBatchEvents(ctx context.Context, l1BatchEvent return fmt.Errorf("failed to insert or ignore batch event, error: %w", err) } case btypes.BatchStatusTypeFinalized: - containsFinalizedEvent = true - // get the maxFinalizedBatchIndex, which signals all the batch before it are all finalized - if l1BatchEvent.BatchIndex > maxFinalizedBatchIndex { - maxFinalizedBatchIndex = l1BatchEvent.BatchIndex - } - if l1BatchEvent.L1BlockNumber > maxL1BlockNumber { - maxL1BlockNumber = l1BatchEvent.L1BlockNumber + db = db.Where("batch_index = ?", l1BatchEvent.BatchIndex) + db = db.Where("batch_hash = ?", l1BatchEvent.BatchHash) + updateFields["batch_status"] = btypes.BatchStatusTypeFinalized + updateFields["l1_block_number"] = l1BatchEvent.L1BlockNumber + if err := db.Updates(updateFields).Error; err != nil { + return fmt.Errorf("failed to update batch event, error: %w", err) } case btypes.BatchStatusTypeReverted: db = db.Where("batch_index = ?", l1BatchEvent.BatchIndex) @@ -113,21 +127,6 @@ func (c *BatchEvent) InsertOrUpdateBatchEvents(ctx context.Context, l1BatchEvent } } } - if containsFinalizedEvent { - db := c.db - db = db.WithContext(ctx) - db = db.Model(&BatchEvent{}) - updateFields := make(map[string]interface{}) - // After darwin, FinalizeBatch event signals a range of batches are finalized, - // thus losing the batch hash info. Meanwhile, only batch_index is enough to update finalized batches. - db = db.Where("batch_index <= ?", maxFinalizedBatchIndex) - db = db.Where("batch_status != ?", btypes.BatchStatusTypeFinalized) - updateFields["batch_status"] = btypes.BatchStatusTypeFinalized - updateFields["l1_block_number"] = maxL1BlockNumber - if err := db.Updates(updateFields).Error; err != nil { - return fmt.Errorf("failed to update batch event, error: %w", err) - } - } return nil } diff --git a/common/version/version.go b/common/version/version.go index 3d7f87a15..fac0fafce 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.4.23" +var tag = "v4.4.24" var commit = func() string { if info, ok := debug.ReadBuildInfo(); ok {