github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/app/rpc/pendingtx/watcher.go (about) 1 package pendingtx 2 3 import ( 4 "fmt" 5 evmtypes "github.com/fibonacci-chain/fbc/x/evm/types" 6 "math/big" 7 8 "github.com/ethereum/go-ethereum/common" 9 "github.com/ethereum/go-ethereum/common/hexutil" 10 11 rpcfilters "github.com/fibonacci-chain/fbc/app/rpc/namespaces/eth/filters" 12 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context" 13 "github.com/fibonacci-chain/fbc/libs/tendermint/libs/log" 14 coretypes "github.com/fibonacci-chain/fbc/libs/tendermint/rpc/core/types" 15 tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types" 16 ) 17 18 type Watcher struct { 19 clientCtx context.CLIContext 20 events *rpcfilters.EventSystem 21 logger log.Logger 22 23 sender Sender 24 } 25 26 type Sender interface { 27 SendPending(hash []byte, tx *PendingTx) error 28 SendRmPending(hash []byte, tx *RmPendingTx) error 29 } 30 31 func NewWatcher(clientCtx context.CLIContext, log log.Logger, sender Sender) *Watcher { 32 return &Watcher{ 33 clientCtx: clientCtx, 34 events: rpcfilters.NewEventSystem(clientCtx.Client), 35 logger: log.With("module", "pendingtx-watcher"), 36 37 sender: sender, 38 } 39 } 40 41 func (w *Watcher) Start() { 42 pendingSub, _, err := w.events.SubscribePendingTxs() 43 if err != nil { 44 w.logger.Error("error creating block filter", "error", err.Error()) 45 } 46 47 rmPendingSub, _, err := w.events.SubscribeRmPendingTx() 48 if err != nil { 49 w.logger.Error("error creating block filter", "error", err.Error()) 50 } 51 52 go func(pendingCh <-chan coretypes.ResultEvent, rmPendingdCh <-chan coretypes.ResultEvent) { 53 for { 54 select { 55 case re := <-pendingCh: 56 data, ok := re.Data.(tmtypes.EventDataTx) 57 if !ok { 58 w.logger.Error(fmt.Sprintf("invalid pending tx data type %T, expected EventDataTx", re.Data)) 59 continue 60 } 61 txHash := common.BytesToHash(data.Tx.Hash(data.Height)) 62 w.logger.Debug("receive pending tx", "txHash=", txHash.String()) 63 64 tx, err := evmtypes.TxDecoder(w.clientCtx.Codec)(data.Tx, data.Height) 65 if err != nil { 66 w.logger.Error("failed to decode raw tx", "hash", txHash.String(), "error", err) 67 continue 68 } 69 70 var input string 71 var value *big.Int 72 var to *common.Address 73 ethTx, ok := tx.(*evmtypes.MsgEthereumTx) 74 if ok { 75 input = hexutil.Bytes(ethTx.Data.Payload).String() 76 value = ethTx.Data.Amount 77 to = ethTx.Data.Recipient 78 } else { 79 b, err := w.clientCtx.Codec.MarshalJSON(tx) 80 if err != nil { 81 w.logger.Error("failed to Marshal tx", "hash", txHash.String(), "error", err) 82 continue 83 } 84 input = string(b) 85 } 86 87 pendingTx := &PendingTx{ 88 From: tx.GetFrom(), 89 To: to, 90 Hash: txHash, 91 Nonce: hexutil.Uint64(data.Nonce), 92 Value: (*hexutil.Big)(value), 93 Gas: hexutil.Uint64(tx.GetGas()), 94 GasPrice: (*hexutil.Big)(tx.GetGasPrice()), 95 Input: input, 96 } 97 98 go func() { 99 w.logger.Debug("push pending tx to MQ", "txHash=", pendingTx.Hash.String()) 100 err = w.sender.SendPending(pendingTx.Hash.Bytes(), pendingTx) 101 102 if err != nil { 103 w.logger.Error("failed to send pending tx", "hash", pendingTx.Hash.String(), "error", err) 104 } 105 }() 106 case re := <-rmPendingdCh: 107 data, ok := re.Data.(tmtypes.EventDataRmPendingTx) 108 if !ok { 109 w.logger.Error(fmt.Sprintf("invalid rm pending tx data type %T, expected EventDataTx", re.Data)) 110 continue 111 } 112 txHash := common.BytesToHash(data.Hash).String() 113 go func() { 114 w.logger.Debug("push rm pending tx to MQ", "txHash=", txHash) 115 err = w.sender.SendRmPending(data.Hash, &RmPendingTx{ 116 From: data.From, 117 Hash: txHash, 118 Nonce: hexutil.Uint64(data.Nonce).String(), 119 Delete: true, 120 Reason: int(data.Reason), 121 }) 122 if err != nil { 123 w.logger.Error("failed to send rm pending tx", "hash", txHash, "error", err) 124 } 125 }() 126 } 127 } 128 }(pendingSub.Event(), rmPendingSub.Event()) 129 }