mirror of
https://github.com/scroll-tech/scroll.git
synced 2026-01-14 16:37:56 -05:00
126 lines
3.8 KiB
Go
126 lines
3.8 KiB
Go
package orm
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"scroll-tech/common/types"
|
|
)
|
|
|
|
// L1Block is structure of stored l1 block message
|
|
type L1Block struct {
|
|
db *gorm.DB `gorm:"column:-"`
|
|
|
|
// block
|
|
Number uint64 `json:"number" gorm:"column:number"`
|
|
Hash string `json:"hash" gorm:"column:hash"`
|
|
BaseFee uint64 `json:"base_fee" gorm:"column:base_fee"`
|
|
|
|
// oracle
|
|
GasOracleStatus int16 `json:"oracle_status" gorm:"column:oracle_status;default:1"`
|
|
OracleTxHash string `json:"oracle_tx_hash" gorm:"column:oracle_tx_hash;default:NULL"`
|
|
|
|
// metadata
|
|
CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
|
|
UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
|
|
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"column:deleted_at;default:NULL"`
|
|
}
|
|
|
|
// NewL1Block create an l1Block instance
|
|
func NewL1Block(db *gorm.DB) *L1Block {
|
|
return &L1Block{db: db}
|
|
}
|
|
|
|
// TableName define the L1Block table name
|
|
func (*L1Block) TableName() string {
|
|
return "l1_block"
|
|
}
|
|
|
|
// GetLatestL1BlockHeight get the latest l1 block height
|
|
func (o *L1Block) GetLatestL1BlockHeight(ctx context.Context) (uint64, error) {
|
|
db := o.db.WithContext(ctx)
|
|
db = db.Model(&L1Block{})
|
|
db = db.Select("COALESCE(MAX(number), 0)")
|
|
|
|
var maxNumber uint64
|
|
if err := db.Row().Scan(&maxNumber); err != nil {
|
|
return 0, fmt.Errorf("L1Block.GetLatestL1BlockHeight error: %w", err)
|
|
}
|
|
return maxNumber, nil
|
|
}
|
|
|
|
// GetL1Blocks get the l1 blocks
|
|
func (o *L1Block) GetL1Blocks(ctx context.Context, fields map[string]interface{}) ([]L1Block, error) {
|
|
db := o.db.WithContext(ctx)
|
|
db = db.Model(&L1Block{})
|
|
|
|
for key, value := range fields {
|
|
db = db.Where(key, value)
|
|
}
|
|
|
|
db = db.Order("number ASC")
|
|
|
|
var l1Blocks []L1Block
|
|
if err := db.Find(&l1Blocks).Error; err != nil {
|
|
return nil, fmt.Errorf("L1Block.GetL1Blocks error: %w, fields: %v", err, fields)
|
|
}
|
|
return l1Blocks, nil
|
|
}
|
|
|
|
// InsertL1Blocks batch inserts l1 blocks.
|
|
// If there's a block number conflict (e.g., due to reorg), soft deletes the existing block and inserts the new one.
|
|
func (o *L1Block) InsertL1Blocks(ctx context.Context, blocks []L1Block) error {
|
|
if len(blocks) == 0 {
|
|
return nil
|
|
}
|
|
|
|
return o.db.Transaction(func(tx *gorm.DB) error {
|
|
minBlockNumber := blocks[0].Number
|
|
for _, block := range blocks[1:] {
|
|
if block.Number < minBlockNumber {
|
|
minBlockNumber = block.Number
|
|
}
|
|
}
|
|
|
|
db := tx.WithContext(ctx)
|
|
db = db.Model(&L1Block{})
|
|
db = db.Where("number >= ?", minBlockNumber)
|
|
result := db.Delete(&L1Block{})
|
|
|
|
if result.Error != nil {
|
|
return fmt.Errorf("L1Block.InsertL1Blocks error: soft deleting blocks failed, block numbers starting from: %v, error: %w", minBlockNumber, result.Error)
|
|
}
|
|
|
|
// If the number of deleted blocks exceeds the limit (input length + 64), treat it as an anomaly.
|
|
// Because reorg with >= 64 blocks is very unlikely to happen.
|
|
if result.RowsAffected >= int64(len(blocks)+64) {
|
|
return fmt.Errorf("L1Block.InsertL1Blocks error: too many blocks were deleted, count: %d", result.RowsAffected)
|
|
}
|
|
|
|
if err := db.Create(&blocks).Error; err != nil {
|
|
return fmt.Errorf("L1Block.InsertL1Blocks error: %w", err)
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// UpdateL1GasOracleStatusAndOracleTxHash update l1 gas oracle status and oracle tx hash
|
|
func (o *L1Block) UpdateL1GasOracleStatusAndOracleTxHash(ctx context.Context, blockHash string, status types.GasOracleStatus, txHash string) error {
|
|
updateFields := map[string]interface{}{
|
|
"oracle_status": int(status),
|
|
"oracle_tx_hash": txHash,
|
|
}
|
|
|
|
db := o.db.WithContext(ctx)
|
|
db = db.Model(&L1Block{})
|
|
db = db.Where("hash", blockHash)
|
|
|
|
if err := db.Updates(updateFields).Error; err != nil {
|
|
return fmt.Errorf("L1Block.UpdateL1GasOracleStatusAndOracleTxHash error: %w, block hash: %v, status: %v, tx hash: %v", err, blockHash, status.String(), txHash)
|
|
}
|
|
return nil
|
|
}
|