github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/infura/engine.go (about)

     1  package infura
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
     8  	"github.com/fibonacci-chain/fbc/x/infura/types"
     9  	"gorm.io/driver/mysql"
    10  	"gorm.io/gorm"
    11  	"gorm.io/gorm/logger"
    12  )
    13  
    14  const batchSize = 1000
    15  
    16  func newStreamEngine(cfg *types.Config, logger log.Logger) (types.IStreamEngine, error) {
    17  	if cfg.MysqlUrl == "" {
    18  		return nil, errors.New("infura.mysql-url is empty")
    19  	}
    20  	return newMySQLEngine(cfg.MysqlUrl, cfg.MysqlUser, cfg.MysqlPass, cfg.MysqlDB, logger)
    21  }
    22  
    23  type MySQLEngine struct {
    24  	db     *gorm.DB
    25  	logger log.Logger
    26  }
    27  
    28  func newMySQLEngine(url, user, pass, dbName string, l log.Logger) (types.IStreamEngine, error) {
    29  	dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
    30  		user, pass, url, dbName)
    31  
    32  	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
    33  		SkipDefaultTransaction: true,
    34  		Logger:                 logger.Default.LogMode(logger.Info),
    35  	})
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	db.AutoMigrate(&types.TransactionReceipt{}, &types.TransactionLog{},
    40  		&types.LogTopic{}, &types.Block{}, &types.Transaction{}, &types.ContractCode{})
    41  	return &MySQLEngine{
    42  		db:     db,
    43  		logger: l,
    44  	}, nil
    45  }
    46  
    47  func (e *MySQLEngine) Write(streamData types.IStreamData) bool {
    48  	e.logger.Debug("Begin MySqlEngine write")
    49  	data := streamData.ConvertEngineData()
    50  	trx := e.db.Begin()
    51  	// write TransactionReceipts
    52  	for i := 0; i < len(data.TransactionReceipts); i += batchSize {
    53  		end := i + batchSize
    54  		if end > len(data.TransactionReceipts) {
    55  			end = len(data.TransactionReceipts)
    56  		}
    57  		ret := trx.CreateInBatches(data.TransactionReceipts[i:end], len(data.TransactionReceipts[i:end]))
    58  		if ret.Error != nil {
    59  			return e.rollbackWithError(trx, ret.Error)
    60  		}
    61  	}
    62  
    63  	// write Block
    64  	ret := trx.Omit("Transactions").Create(data.Block)
    65  	if ret.Error != nil {
    66  		return e.rollbackWithError(trx, ret.Error)
    67  	}
    68  
    69  	// write Transactions
    70  	for i := 0; i < len(data.Block.Transactions); i += batchSize {
    71  		end := i + batchSize
    72  		if end > len(data.Block.Transactions) {
    73  			end = len(data.Block.Transactions)
    74  		}
    75  		ret := trx.CreateInBatches(data.Block.Transactions[i:end], len(data.Block.Transactions[i:end]))
    76  		if ret.Error != nil {
    77  			return e.rollbackWithError(trx, ret.Error)
    78  		}
    79  	}
    80  
    81  	// write contract code
    82  	for _, code := range data.ContractCodes {
    83  		ret := trx.Create(code)
    84  		if ret.Error != nil {
    85  			return e.rollbackWithError(trx, ret.Error)
    86  		}
    87  	}
    88  
    89  	trx.Commit()
    90  	e.logger.Debug("End MySqlEngine write")
    91  	return true
    92  }
    93  
    94  func (e *MySQLEngine) rollbackWithError(trx *gorm.DB, err error) bool {
    95  	trx.Rollback()
    96  	e.logger.Error(err.Error())
    97  	return false
    98  }