github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/evm/watcher/tx.go (about) 1 package watcher 2 3 import ( 4 "fmt" 5 6 "github.com/ethereum/go-ethereum/common" 7 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 8 tm "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 9 ctypes "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/core/types" 10 "github.com/fibonacci-chain/fbc/x/evm/types" 11 ) 12 13 type WatchTx interface { 14 GetTxWatchMessage() WatchMessage 15 GetTransaction() *Transaction 16 GetTxHash() common.Hash 17 GetFailedReceipts(cumulativeGas, gasUsed uint64) *TransactionReceipt 18 GetIndex() uint64 19 } 20 21 func (w *Watcher) RecordTxAndFailedReceipt(tx tm.TxEssentials, resp *tm.ResponseDeliverTx, txDecoder sdk.TxDecoder) { 22 if !w.Enabled() { 23 return 24 } 25 26 // record ResultTx always 27 if resp != nil { 28 txResult := &ctypes.ResultTx{ 29 Hash: tx.TxHash(), 30 Height: int64(w.height), 31 TxResult: *resp, 32 Tx: tx.GetRaw(), 33 } 34 w.saveStdTxResponse(txResult) 35 } 36 37 realTx, err := w.getRealTx(tx, txDecoder) 38 if err != nil { 39 return 40 } 41 watchTx := w.createWatchTx(realTx) 42 switch realTx.GetType() { 43 case sdk.EvmTxType: 44 if watchTx == nil { 45 return 46 } 47 w.saveTx(watchTx) 48 if resp != nil && !resp.IsOK() { 49 w.saveFailedReceipts(watchTx, uint64(resp.GasUsed)) 50 return 51 } 52 if resp != nil && resp.IsOK() && !w.IsRealEvmTx(resp) { // for evm2cm 53 msgs := realTx.GetMsgs() 54 if len(msgs) == 0 { 55 return 56 } 57 evmTx, ok := msgs[0].(*types.MsgEthereumTx) 58 if !ok { 59 return 60 } 61 w.SaveTransactionReceipt(TransactionSuccess, evmTx, watchTx.GetTxHash(), watchTx.GetIndex(), &types.ResultData{}, uint64(resp.GasUsed)) 62 } 63 case sdk.StdTxType: 64 w.blockStdTxs = append(w.blockStdTxs, common.BytesToHash(realTx.TxHash())) 65 } 66 } 67 68 func (w *Watcher) IsRealEvmTx(resp *tm.ResponseDeliverTx) bool { 69 for _, ev := range resp.Events { 70 if ev.Type == sdk.EventTypeMessage { 71 for _, attr := range ev.Attributes { 72 if string(attr.Key) == sdk.AttributeKeyModule && 73 string(attr.Value) == types.AttributeValueCategory { 74 return true 75 } 76 } 77 } 78 } 79 return false 80 } 81 82 func (w *Watcher) getRealTx(tx tm.TxEssentials, txDecoder sdk.TxDecoder) (sdk.Tx, error) { 83 var err error 84 realTx, _ := tx.(sdk.Tx) 85 if realTx == nil { 86 realTx, err = txDecoder(tx.GetRaw()) 87 if err != nil { 88 return nil, err 89 } 90 } 91 92 return realTx, nil 93 } 94 95 func (w *Watcher) createWatchTx(realTx sdk.Tx) WatchTx { 96 var txMsg WatchTx 97 switch realTx.GetType() { 98 case sdk.EvmTxType: 99 evmTx, err := w.extractEvmTx(realTx) 100 if err != nil { 101 return nil 102 } 103 txMsg = NewEvmTx(evmTx, common.BytesToHash(evmTx.TxHash()), w.blockHash, w.height, w.evmTxIndex) 104 w.evmTxIndex++ 105 } 106 107 return txMsg 108 } 109 110 func (w *Watcher) extractEvmTx(sdkTx sdk.Tx) (*types.MsgEthereumTx, error) { 111 var ok bool 112 var evmTx *types.MsgEthereumTx 113 // stdTx should only have one tx 114 msg := sdkTx.GetMsgs() 115 if len(msg) <= 0 { 116 return nil, fmt.Errorf("can not extract evm tx, len(msg) <= 0") 117 } 118 if evmTx, ok = msg[0].(*types.MsgEthereumTx); !ok { 119 return nil, fmt.Errorf("sdktx is not evm tx %v", sdkTx) 120 } 121 122 return evmTx, nil 123 } 124 125 func (w *Watcher) saveTx(tx WatchTx) { 126 if w == nil || tx == nil { 127 return 128 } 129 if w.InfuraKeeper != nil { 130 ethTx := tx.GetTransaction() 131 if ethTx != nil { 132 w.InfuraKeeper.OnSaveTransaction(*ethTx) 133 } 134 } 135 if txWatchMessage := tx.GetTxWatchMessage(); txWatchMessage != nil { 136 w.batch = append(w.batch, txWatchMessage) 137 } 138 w.blockTxs = append(w.blockTxs, tx.GetTxHash()) 139 } 140 141 func (w *Watcher) saveFailedReceipts(watchTx WatchTx, gasUsed uint64) { 142 if w == nil || watchTx == nil { 143 return 144 } 145 w.UpdateCumulativeGas(watchTx.GetIndex(), gasUsed) 146 receipt := watchTx.GetFailedReceipts(w.cumulativeGas[watchTx.GetIndex()], gasUsed) 147 if w.InfuraKeeper != nil { 148 w.InfuraKeeper.OnSaveTransactionReceipt(*receipt) 149 } 150 wMsg := NewMsgTransactionReceipt(*receipt, watchTx.GetTxHash()) 151 if wMsg != nil { 152 w.batch = append(w.batch, wMsg) 153 } 154 } 155 156 // SaveParallelTx saves parallel transactions and transactionReceipts to watcher 157 func (w *Watcher) SaveParallelTx(realTx sdk.Tx, resultData *types.ResultData, resp tm.ResponseDeliverTx) { 158 159 if !w.Enabled() { 160 return 161 } 162 163 // record ResultTx always 164 txResult := &ctypes.ResultTx{ 165 Hash: realTx.TxHash(), 166 Height: int64(w.height), 167 TxResult: resp, 168 Tx: realTx.GetRaw(), 169 } 170 w.saveStdTxResponse(txResult) 171 172 switch realTx.GetType() { 173 case sdk.EvmTxType: 174 msgs := realTx.GetMsgs() 175 evmTx, ok := msgs[0].(*types.MsgEthereumTx) 176 if !ok { 177 return 178 } 179 watchTx := NewEvmTx(evmTx, common.BytesToHash(evmTx.TxHash()), w.blockHash, w.height, w.evmTxIndex) 180 w.evmTxIndex++ 181 w.saveTx(watchTx) 182 183 // save transactionReceipts 184 if resp.IsOK() { 185 if resultData == nil { 186 resultData = &types.ResultData{} 187 } 188 w.SaveTransactionReceipt(TransactionSuccess, evmTx, watchTx.GetTxHash(), watchTx.GetIndex(), resultData, uint64(resp.GasUsed)) 189 } else { 190 w.saveFailedReceipts(watchTx, uint64(resp.GasUsed)) 191 } 192 case sdk.StdTxType: 193 w.blockStdTxs = append(w.blockStdTxs, common.BytesToHash(realTx.TxHash())) 194 } 195 }