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  }