github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/txs/deliver/deliver.go (about)

     1  package deliver
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/ethereum/go-ethereum/common"
     7  	"github.com/fibonacci-chain/fbc/x/evm/watcher"
     8  
     9  	"github.com/fibonacci-chain/fbc/app/refund"
    10  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    11  	authexported "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/exported"
    12  	bam "github.com/fibonacci-chain/fbc/libs/system/trace"
    13  	"github.com/fibonacci-chain/fbc/x/evm/keeper"
    14  	"github.com/fibonacci-chain/fbc/x/evm/txs/base"
    15  	"github.com/fibonacci-chain/fbc/x/evm/types"
    16  )
    17  
    18  type Tx struct {
    19  	*base.Tx
    20  }
    21  
    22  func NewTx(config base.Config) *Tx {
    23  	return &Tx{
    24  		Tx: base.NewTx(config),
    25  	}
    26  }
    27  
    28  // SaveTx since the txCount is used by the stateDB, and a simulated tx is run only on the node it's submitted to,
    29  // then this will cause the txCount/stateDB of the node that ran the simulated tx to be different with the
    30  // other nodes, causing a consensus error
    31  func (tx *Tx) SaveTx(msg *types.MsgEthereumTx) {
    32  	tx.AnalyzeStart(bam.SaveTx)
    33  	defer tx.AnalyzeStop(bam.SaveTx)
    34  
    35  	// Prepare db for logs
    36  	tx.StateTransition.Csdb.Prepare(*tx.StateTransition.TxHash, tx.Keeper.Bhash, tx.Keeper.TxCount)
    37  	tx.StateTransition.Csdb.SetLogSize(tx.Keeper.LogSize)
    38  	tx.Keeper.TxCount++
    39  	if tx.Ctx.ParaMsg() != nil {
    40  		tx.Ctx.ParaMsg().HasRunEvmTx = true
    41  	}
    42  }
    43  
    44  func (tx *Tx) GetSenderAccount() authexported.Account {
    45  	pm := tx.Keeper.GenerateCSDBParams()
    46  	infCtx := tx.Ctx
    47  	infCtx.SetGasMeter(sdk.NewInfiniteGasMeter())
    48  
    49  	return pm.AccountKeeper.GetAccount(infCtx, tx.StateTransition.Sender.Bytes())
    50  }
    51  
    52  // resetWatcher when panic reset watcher
    53  func (tx *Tx) resetWatcher(account authexported.Account) {
    54  	// delete account which is already in Watcher.batch
    55  	if account != nil && tx.Ctx.GetWatcher().Enabled() {
    56  		tx.Ctx.GetWatcher().DeleteAccount(account)
    57  	}
    58  }
    59  
    60  // refundFeesWatcher fix account balance in watcher with refund fees
    61  func (tx *Tx) refundFeesWatcher(account authexported.Account, ethereumTx *types.MsgEthereumTx) {
    62  	// fix account balance in watcher with refund fees
    63  	if account == nil || !tx.Ctx.GetWatcher().Enabled() {
    64  		return
    65  	}
    66  	defer func() {
    67  		//panic was not allowed in this function
    68  		if e := recover(); e != nil {
    69  			tx.Ctx.Logger().Error(fmt.Sprintf("recovered panic at func refundFeesWatcher %v\n", e))
    70  		}
    71  	}()
    72  	gasConsumed := tx.Ctx.GasMeter().GasConsumed()
    73  	gasLimit := ethereumTx.Data.GasLimit
    74  	if gasConsumed >= gasLimit {
    75  		return
    76  	}
    77  
    78  	fixedFees := refund.CalculateRefundFees(gasConsumed, ethereumTx.GetFee(), ethereumTx.Data.Price)
    79  	coins := account.GetCoins().Add2(fixedFees)
    80  	account.SetCoins(coins) //ignore err, no err will be returned in SetCoins
    81  	tx.Ctx.GetWatcher().SaveAccount(account)
    82  }
    83  
    84  func (tx *Tx) Transition(config types.ChainConfig) (result base.Result, err error) {
    85  	result, err = tx.Tx.Transition(config)
    86  
    87  	if result.InnerTxs != nil {
    88  		tx.Keeper.AddInnerTx(tx.StateTransition.TxHash.Hex(), result.InnerTxs)
    89  	}
    90  	if result.Erc20Contracts != nil {
    91  		tx.Keeper.AddContract(result.Erc20Contracts)
    92  	}
    93  	return
    94  }
    95  func (tx *Tx) Commit(msg *types.MsgEthereumTx, result *base.Result) {
    96  	// update block bloom filter
    97  	if tx.Ctx.ParaMsg() == nil {
    98  		tx.Keeper.Bloom.Or(tx.Keeper.Bloom, result.ExecResult.Bloom)
    99  		tx.Keeper.Watcher.SaveTransactionReceipt(watcher.TransactionSuccess,
   100  			msg, *tx.StateTransition.TxHash,
   101  			tx.Keeper.Watcher.GetEvmTxIndex(), result.ResultData, tx.Ctx.GasMeter().GasConsumed())
   102  	} else {
   103  		// async mod goes immediately
   104  		index := tx.Keeper.LogsManages.Set(keeper.TxResult{
   105  			ResultData: result.ResultData,
   106  		})
   107  		tx.Ctx.ParaMsg().LogIndex = index
   108  	}
   109  	tx.Keeper.LogSize = tx.StateTransition.Csdb.GetLogSize()
   110  	if msg.Data.Recipient == nil && tx.Ctx.GetWatcher().Enabled() {
   111  		tx.StateTransition.Csdb.IteratorCode(func(addr common.Address, c types.CacheCode) bool {
   112  			tx.Ctx.GetWatcher().SaveContractCode(addr, c.Code, uint64(tx.Ctx.BlockHeight()))
   113  			tx.Ctx.GetWatcher().SaveContractCodeByHash(c.CodeHash, c.Code)
   114  			return true
   115  		})
   116  	}
   117  }
   118  
   119  func (tx *Tx) FinalizeWatcher(msg *types.MsgEthereumTx, err error, panic bool) {
   120  	if !tx.Ctx.GetWatcher().Enabled() {
   121  		return
   122  	}
   123  	account := tx.GetSenderAccount()
   124  	if panic {
   125  		tx.resetWatcher(account)
   126  		return
   127  	}
   128  	tx.refundFeesWatcher(account, msg)
   129  	// handle error
   130  	if err != nil {
   131  		// reset watcher
   132  		tx.resetWatcher(account)
   133  		return
   134  	}
   135  	tx.Ctx.GetWatcher().Finalize()
   136  }