mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-15 00:48:01 -05:00
315 lines
11 KiB
Go
315 lines
11 KiB
Go
package orm
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/scroll-tech/go-ethereum/log"
|
|
"gorm.io/gorm"
|
|
|
|
"scroll-tech/common/types"
|
|
"scroll-tech/common/types/message"
|
|
|
|
bridgeTypes "scroll-tech/bridge/internal/types"
|
|
)
|
|
|
|
// BlockBatch is structure of stored block batch message
|
|
type BlockBatch struct {
|
|
db *gorm.DB `gorm:"column:-"`
|
|
|
|
Hash string `json:"hash" gorm:"column:hash"`
|
|
Index uint64 `json:"index" gorm:"column:index"`
|
|
StartBlockNumber uint64 `json:"start_block_number" gorm:"column:start_block_number"`
|
|
StartBlockHash string `json:"start_block_hash" gorm:"column:start_block_hash"`
|
|
EndBlockNumber uint64 `json:"end_block_number" gorm:"column:end_block_number"`
|
|
EndBlockHash string `json:"end_block_hash" gorm:"column:end_block_hash"`
|
|
ParentHash string `json:"parent_hash" gorm:"column:parent_hash"`
|
|
StateRoot string `json:"state_root" gorm:"column:state_root"`
|
|
TotalTxNum uint64 `json:"total_tx_num" gorm:"column:total_tx_num"`
|
|
TotalL1TxNum uint64 `json:"total_l1_tx_num" gorm:"column:total_l1_tx_num"`
|
|
TotalL2Gas uint64 `json:"total_l2_gas" gorm:"column:total_l2_gas"`
|
|
ProvingStatus int `json:"proving_status" gorm:"column:proving_status;default:1"`
|
|
Proof []byte `json:"proof" gorm:"column:proof"`
|
|
ProofTimeSec uint64 `json:"proof_time_sec" gorm:"column:proof_time_sec;default:0"`
|
|
RollupStatus int `json:"rollup_status" gorm:"column:rollup_status;default:1"`
|
|
CommitTxHash string `json:"commit_tx_hash" gorm:"column:commit_tx_hash;default:NULL"`
|
|
OracleStatus int `json:"oracle_status" gorm:"column:oracle_status;default:1"`
|
|
OracleTxHash string `json:"oracle_tx_hash" gorm:"column:oracle_tx_hash;default:NULL"`
|
|
FinalizeTxHash string `json:"finalize_tx_hash" gorm:"column:finalize_tx_hash;default:NULL"`
|
|
CreatedAt time.Time `json:"created_at" gorm:"column:created_at;default:CURRENT_TIMESTAMP()"`
|
|
ProverAssignedAt *time.Time `json:"prover_assigned_at" gorm:"column:prover_assigned_at;default:NULL"`
|
|
ProvedAt *time.Time `json:"proved_at" gorm:"column:proved_at;default:NULL"`
|
|
CommittedAt *time.Time `json:"committed_at" gorm:"column:committed_at;default:NULL"`
|
|
FinalizedAt *time.Time `json:"finalized_at" gorm:"column:finalized_at;default:NULL"`
|
|
}
|
|
|
|
// NewBlockBatch create an blockBatchOrm instance
|
|
func NewBlockBatch(db *gorm.DB) *BlockBatch {
|
|
return &BlockBatch{db: db}
|
|
}
|
|
|
|
// TableName define the BlockBatch table name
|
|
func (*BlockBatch) TableName() string {
|
|
return "block_batch"
|
|
}
|
|
|
|
// GetBatchCount get the batch count
|
|
func (o *BlockBatch) GetBatchCount() (int64, error) {
|
|
var count int64
|
|
if err := o.db.Model(&BlockBatch{}).Count(&count).Error; err != nil {
|
|
return 0, err
|
|
}
|
|
return count, nil
|
|
}
|
|
|
|
// GetBlockBatches get the select block batches
|
|
func (o *BlockBatch) GetBlockBatches(fields map[string]interface{}, orderByList []string, limit int) ([]BlockBatch, error) {
|
|
var blockBatches []BlockBatch
|
|
db := o.db
|
|
for key, value := range fields {
|
|
db = db.Where(key, value)
|
|
}
|
|
|
|
for _, orderBy := range orderByList {
|
|
db = db.Order(orderBy)
|
|
}
|
|
|
|
if limit != 0 {
|
|
db = db.Limit(limit)
|
|
}
|
|
|
|
if err := db.Find(&blockBatches).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return blockBatches, nil
|
|
}
|
|
|
|
// GetBlockBatchesHashByRollupStatus get the block batches by rollup status
|
|
func (o *BlockBatch) GetBlockBatchesHashByRollupStatus(status types.RollupStatus, limit int) ([]string, error) {
|
|
var blockBatches []BlockBatch
|
|
err := o.db.Select("hash").Where("rollup_status", int(status)).Order("index ASC").Limit(limit).Find(&blockBatches).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var hashes []string
|
|
for _, v := range blockBatches {
|
|
hashes = append(hashes, v.Hash)
|
|
}
|
|
return hashes, nil
|
|
}
|
|
|
|
// GetVerifiedProofByHash get verified proof and instance comments by hash
|
|
func (o *BlockBatch) GetVerifiedProofByHash(hash string) (*message.AggProof, error) {
|
|
result := o.db.Model(&BlockBatch{}).Select("proof").Where("hash", hash).Where("proving_status", int(types.ProvingTaskVerified)).Row()
|
|
if result.Err() != nil {
|
|
return nil, result.Err()
|
|
}
|
|
|
|
var proofBytes []byte
|
|
if err := result.Scan(&proofBytes); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var proof message.AggProof
|
|
if err := json.Unmarshal(proofBytes, &proof); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &proof, nil
|
|
}
|
|
|
|
// GetLatestBatch get the latest batch
|
|
// because we will `initializeGenesis()` when we start the `L2Watcher`, so a batch must exist.
|
|
func (o *BlockBatch) GetLatestBatch() (*BlockBatch, error) {
|
|
var blockBatch BlockBatch
|
|
err := o.db.Order("index DESC").Limit(1).First(&blockBatch).Error
|
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return nil, err
|
|
}
|
|
return &blockBatch, nil
|
|
}
|
|
|
|
// GetLatestBatchByRollupStatus get the latest block batch by rollup status
|
|
func (o *BlockBatch) GetLatestBatchByRollupStatus(rollupStatuses []types.RollupStatus) (*BlockBatch, error) {
|
|
var tmpRollupStatus []int
|
|
for _, v := range rollupStatuses {
|
|
tmpRollupStatus = append(tmpRollupStatus, int(v))
|
|
}
|
|
var blockBatch BlockBatch
|
|
err := o.db.Where("rollup_status IN (?)", tmpRollupStatus).Order("index DESC").Limit(1).First(&blockBatch).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &blockBatch, nil
|
|
}
|
|
|
|
// GetRollupStatusByHashList get rollup status by hash list
|
|
func (o *BlockBatch) GetRollupStatusByHashList(hashes []string) ([]types.RollupStatus, error) {
|
|
if len(hashes) == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
var blockBatches []BlockBatch
|
|
err := o.db.Select("hash, rollup_status").Where("hash IN (?)", hashes).Find(&blockBatches).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var (
|
|
statuses []types.RollupStatus
|
|
_statusMap = make(map[string]types.RollupStatus, len(hashes))
|
|
)
|
|
for _, _batch := range blockBatches {
|
|
_statusMap[_batch.Hash] = types.RollupStatus(_batch.RollupStatus)
|
|
}
|
|
for _, _hash := range hashes {
|
|
statuses = append(statuses, _statusMap[_hash])
|
|
}
|
|
|
|
return statuses, nil
|
|
}
|
|
|
|
// InsertBlockBatchByBatchData insert a block batch data by the BatchData
|
|
func (o *BlockBatch) InsertBlockBatchByBatchData(tx *gorm.DB, batchData *bridgeTypes.BatchData) (int64, error) {
|
|
var db *gorm.DB
|
|
if tx != nil {
|
|
db = tx
|
|
} else {
|
|
db = o.db
|
|
}
|
|
|
|
numBlocks := len(batchData.Batch.Blocks)
|
|
insertBlockBatch := BlockBatch{
|
|
Hash: batchData.Hash().Hex(),
|
|
Index: batchData.Batch.BatchIndex,
|
|
StartBlockNumber: batchData.Batch.Blocks[0].BlockNumber,
|
|
StartBlockHash: batchData.Batch.Blocks[0].BlockHash.Hex(),
|
|
EndBlockNumber: batchData.Batch.Blocks[numBlocks-1].BlockNumber,
|
|
EndBlockHash: batchData.Batch.Blocks[numBlocks-1].BlockHash.Hex(),
|
|
ParentHash: batchData.Batch.ParentBatchHash.Hex(),
|
|
StateRoot: batchData.Batch.NewStateRoot.Hex(),
|
|
TotalTxNum: batchData.TotalTxNum,
|
|
TotalL1TxNum: batchData.TotalL1TxNum,
|
|
TotalL2Gas: batchData.TotalL2Gas,
|
|
CreatedAt: time.Now(),
|
|
}
|
|
result := db.Create(&insertBlockBatch)
|
|
if result.Error != nil {
|
|
log.Error("failed to insert block batch by batchData", "err", result.Error)
|
|
return 0, result.Error
|
|
}
|
|
return result.RowsAffected, nil
|
|
}
|
|
|
|
// UpdateProvingStatus update the proving status
|
|
func (o *BlockBatch) UpdateProvingStatus(hash string, status types.ProvingStatus) 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.ProvingTaskProved, types.ProvingTaskVerified:
|
|
updateFields["proved_at"] = time.Now()
|
|
default:
|
|
}
|
|
|
|
if err := o.db.Model(&BlockBatch{}).Where("hash", hash).Updates(updateFields).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UpdateRollupStatus update the rollup status
|
|
func (o *BlockBatch) UpdateRollupStatus(ctx context.Context, hash string, status types.RollupStatus) error {
|
|
updateFields := make(map[string]interface{})
|
|
updateFields["rollup_status"] = int(status)
|
|
|
|
switch status {
|
|
case types.RollupCommitted:
|
|
updateFields["committed_at"] = time.Now()
|
|
case types.RollupFinalized:
|
|
updateFields["finalized_at"] = time.Now()
|
|
}
|
|
if err := o.db.Model(&BlockBatch{}).WithContext(ctx).Where("hash", hash).Updates(updateFields).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UpdateSkippedBatches update the skipped batches
|
|
func (o *BlockBatch) UpdateSkippedBatches() (int64, error) {
|
|
provingStatusList := []interface{}{
|
|
int(types.ProvingTaskSkipped),
|
|
int(types.ProvingTaskFailed),
|
|
}
|
|
result := o.db.Model(&BlockBatch{}).Where("rollup_status", int(types.RollupCommitted)).
|
|
Where("proving_status IN (?)", provingStatusList).Update("rollup_status", int(types.RollupFinalizationSkipped))
|
|
if result.Error != nil {
|
|
return 0, result.Error
|
|
}
|
|
return result.RowsAffected, nil
|
|
}
|
|
|
|
// UpdateCommitTxHashAndRollupStatus update the commit tx hash and rollup status
|
|
func (o *BlockBatch) UpdateCommitTxHashAndRollupStatus(ctx context.Context, hash string, commitTxHash string, status types.RollupStatus) error {
|
|
updateFields := make(map[string]interface{})
|
|
updateFields["commit_tx_hash"] = commitTxHash
|
|
updateFields["rollup_status"] = int(status)
|
|
if status == types.RollupCommitted {
|
|
updateFields["committed_at"] = time.Now()
|
|
}
|
|
if err := o.db.WithContext(ctx).Model(&BlockBatch{}).Where("hash", hash).Updates(updateFields).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UpdateFinalizeTxHashAndRollupStatus update the finalize tx hash and rollup status
|
|
func (o *BlockBatch) UpdateFinalizeTxHashAndRollupStatus(ctx context.Context, hash string, finalizeTxHash string, status types.RollupStatus) error {
|
|
updateFields := make(map[string]interface{})
|
|
updateFields["finalize_tx_hash"] = finalizeTxHash
|
|
updateFields["rollup_status"] = int(status)
|
|
if status == types.RollupFinalized {
|
|
updateFields["finalized_at"] = time.Now()
|
|
}
|
|
if err := o.db.WithContext(ctx).Model(&BlockBatch{}).Where("hash", hash).Updates(updateFields).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UpdateL2GasOracleStatusAndOracleTxHash update the l2 gas oracle status and oracle tx hash
|
|
func (o *BlockBatch) UpdateL2GasOracleStatusAndOracleTxHash(ctx context.Context, hash string, status types.GasOracleStatus, txHash string) error {
|
|
updateFields := make(map[string]interface{})
|
|
updateFields["oracle_status"] = int(status)
|
|
updateFields["oracle_tx_hash"] = txHash
|
|
if err := o.db.WithContext(ctx).Model(&BlockBatch{}).Where("hash", hash).Updates(updateFields).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// UpdateProofByHash update the block batch proof by hash
|
|
// for unit test
|
|
func (o *BlockBatch) UpdateProofByHash(ctx context.Context, hash string, proof *message.AggProof, proofTimeSec uint64) error {
|
|
proofBytes, err := json.Marshal(proof)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
updateFields := make(map[string]interface{})
|
|
updateFields["proof"] = proofBytes
|
|
updateFields["proof_time_sec"] = proofTimeSec
|
|
err = o.db.WithContext(ctx).Model(&BlockBatch{}).Where("hash", hash).Updates(updateFields).Error
|
|
if err != nil {
|
|
log.Error("failed to update proof", "err", err)
|
|
}
|
|
return err
|
|
}
|