From 898ac1d25cd97c0b95af77e5bdaa9dfe7a454945 Mon Sep 17 00:00:00 2001 From: georgehao Date: Thu, 11 Apr 2024 11:15:09 +0800 Subject: [PATCH] feat: update batch/chunk proving status when finalize without proof (#1255) Co-authored-by: georgehao Co-authored-by: colin <102356659+colinlyguo@users.noreply.github.com> Co-authored-by: HAOYUatHZ <37070449+HAOYUatHZ@users.noreply.github.com> --- common/version/version.go | 2 +- .../internal/controller/relayer/l2_relayer.go | 18 ++++++++ .../controller/relayer/l2_relayer_test.go | 28 +++++++++++-- rollup/internal/orm/chunk.go | 42 +++++++++++++++++++ 4 files changed, 85 insertions(+), 5 deletions(-) diff --git a/common/version/version.go b/common/version/version.go index 50509e29e..cfad27122 100644 --- a/common/version/version.go +++ b/common/version/version.go @@ -5,7 +5,7 @@ import ( "runtime/debug" ) -var tag = "v4.3.85" +var tag = "v4.3.86" 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 023cb8e53..21ba90ba9 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -585,6 +585,24 @@ func (r *Layer2Relayer) finalizeBatch(dbBatch *orm.Batch, withProof bool) error log.Error("UpdateFinalizeTxHashAndRollupStatus failed", "index", dbBatch.Index, "batch hash", dbBatch.Hash, "tx hash", txHash.String(), "err", err) return err } + + // Updating the proving status when finalizing without proof, thus the coordinator could omit this task. + // it isn't a necessary step, so don't put in a transaction with UpdateFinalizeTxHashAndRollupStatus + if !withProof { + txErr := r.db.Transaction(func(tx *gorm.DB) error { + if updateErr := r.batchOrm.UpdateProvingStatus(r.ctx, dbBatch.Hash, types.ProvingTaskVerified); updateErr != nil { + return updateErr + } + if updateErr := r.chunkOrm.UpdateProvingStatusByBatchHash(r.ctx, dbBatch.Hash, types.ProvingTaskVerified); updateErr != nil { + return updateErr + } + return nil + }) + if txErr != nil { + log.Error("Updating chunk and batch proving status when finalizing without proof failure", "batchHash", dbBatch.Hash, "err", txErr) + } + } + r.metrics.rollupL2RelayerProcessCommittedBatchesFinalizedSuccessTotal.Inc() return nil } diff --git a/rollup/internal/controller/relayer/l2_relayer_test.go b/rollup/internal/controller/relayer/l2_relayer_test.go index 1a9b9988a..adacfdb0f 100644 --- a/rollup/internal/controller/relayer/l2_relayer_test.go +++ b/rollup/internal/controller/relayer/l2_relayer_test.go @@ -7,6 +7,7 @@ import ( "net/http" "strings" "testing" + "time" "github.com/agiledragon/gomonkey/v2" "github.com/gin-gonic/gin" @@ -181,9 +182,9 @@ func testL2RelayerFinalizeTimeoutBatches(t *testing.T) { err = l2BlockOrm.InsertL2Blocks(context.Background(), []*encoding.Block{block1, block2}) assert.NoError(t, err) chunkOrm := orm.NewChunk(db) - _, err = chunkOrm.InsertChunk(context.Background(), chunk1, codecVersion) + chunkDB1, err := chunkOrm.InsertChunk(context.Background(), chunk1, codecVersion) assert.NoError(t, err) - _, err = chunkOrm.InsertChunk(context.Background(), chunk2, codecVersion) + chunkDB2, err := chunkOrm.InsertChunk(context.Background(), chunk2, codecVersion) assert.NoError(t, err) batch := &encoding.Batch{ @@ -200,11 +201,30 @@ func testL2RelayerFinalizeTimeoutBatches(t *testing.T) { err = batchOrm.UpdateRollupStatus(context.Background(), dbBatch.Hash, types.RollupCommitted) assert.NoError(t, err) + err = chunkOrm.UpdateBatchHashInRange(context.Background(), chunkDB1.Index, chunkDB2.Index, dbBatch.Hash, nil) + assert.NoError(t, err) + // Check the database for the updated status using TryTimes. ok := utils.TryTimes(5, func() bool { relayer.ProcessCommittedBatches() - statuses, err := batchOrm.GetRollupStatusByHashList(context.Background(), []string{dbBatch.Hash}) - return err == nil && len(statuses) == 1 && statuses[0] == types.RollupFinalizing + time.Sleep(time.Second) + + batchInDB, batchErr := batchOrm.GetBatches(context.Background(), map[string]interface{}{"hash": dbBatch.Hash}, nil, 0) + if batchErr != nil { + return false + } + chunks, chunkErr := chunkOrm.GetChunksByBatchHash(context.Background(), dbBatch.Hash) + if chunkErr != nil { + return false + } + + batchStatus := len(batchInDB) == 1 && types.RollupStatus(batchInDB[0].RollupStatus) == types.RollupFinalizing && + types.ProvingStatus(batchInDB[0].ProvingStatus) == types.ProvingTaskVerified + + chunkStatus := len(chunks) == 2 && types.ProvingStatus(chunks[0].ProvingStatus) == types.ProvingTaskVerified && + types.ProvingStatus(chunks[1].ProvingStatus) == types.ProvingTaskVerified + + return batchStatus && chunkStatus }) assert.True(t, ok) relayer.StopSenders() diff --git a/rollup/internal/orm/chunk.go b/rollup/internal/orm/chunk.go index e348c0c67..7f4ccc1c0 100644 --- a/rollup/internal/orm/chunk.go +++ b/rollup/internal/orm/chunk.go @@ -140,6 +140,20 @@ func (o *Chunk) GetChunksGEIndex(ctx context.Context, index uint64, limit int) ( return chunks, nil } +// GetChunksByBatchHash retrieves chunks by batch hash +// for test +func (o *Chunk) GetChunksByBatchHash(ctx context.Context, batchHash string) ([]*Chunk, error) { + db := o.db.WithContext(ctx) + db = db.Model(&Chunk{}) + db = db.Where("batch_hash = ?", batchHash) + + var chunks []*Chunk + if err := db.Find(&chunks).Error; err != nil { + return nil, fmt.Errorf("Chunk.GetChunksByBatchHash error: %w", err) + } + return chunks, nil +} + // InsertChunk inserts a new chunk into the database. func (o *Chunk) InsertChunk(ctx context.Context, chunk *encoding.Chunk, codecVersion encoding.CodecVersion, dbTX ...*gorm.DB) (*Chunk, error) { if chunk == nil || len(chunk.Blocks) == 0 { @@ -242,6 +256,34 @@ func (o *Chunk) UpdateProvingStatus(ctx context.Context, hash string, status typ return nil } +// UpdateProvingStatusByBatchHash updates the proving_status for chunks within the specified batch_hash +func (o *Chunk) UpdateProvingStatusByBatchHash(ctx context.Context, batchHash string, status types.ProvingStatus, dbTX ...*gorm.DB) error { + updateFields := make(map[string]interface{}) + updateFields["proving_status"] = int(status) + + switch status { + case types.ProvingTaskAssigned: + updateFields["prover_assigned_at"] = time.Now() + case types.ProvingTaskUnassigned: + updateFields["prover_assigned_at"] = nil + case types.ProvingTaskVerified: + updateFields["proved_at"] = time.Now() + } + + db := o.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) + db = db.Model(&Chunk{}) + db = db.Where("batch_hash = ?", batchHash) + + if err := db.Updates(updateFields).Error; err != nil { + return fmt.Errorf("Chunk.UpdateProvingStatusByBatchHash error: %w, batch hash: %v, status: %v", err, batchHash, status.String()) + } + return nil +} + // UpdateBatchHashInRange updates the batch_hash for chunks within the specified range (inclusive). // The range is closed, i.e., it includes both start and end indices. func (o *Chunk) UpdateBatchHashInRange(ctx context.Context, startIndex uint64, endIndex uint64, batchHash string, dbTX ...*gorm.DB) error {