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 }