github.com/okex/exchain@v1.8.0/libs/tendermint/rpc/core/mempool.go (about)

     1  package core
     2  
     3  import (
     4  	"context"
     5  	"crypto/sha256"
     6  	"fmt"
     7  	"time"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/okex/exchain/libs/cosmos-sdk/baseapp"
    12  	abci "github.com/okex/exchain/libs/tendermint/abci/types"
    13  	"github.com/okex/exchain/libs/tendermint/config"
    14  	mempl "github.com/okex/exchain/libs/tendermint/mempool"
    15  	ctypes "github.com/okex/exchain/libs/tendermint/rpc/core/types"
    16  	rpctypes "github.com/okex/exchain/libs/tendermint/rpc/jsonrpc/types"
    17  	"github.com/okex/exchain/libs/tendermint/types"
    18  )
    19  
    20  //-----------------------------------------------------------------------------
    21  // NOTE: tx should be signed, but this is only checked at the app level (not by Tendermint!)
    22  
    23  // BroadcastTxAsync returns right away, with no response. Does not wait for
    24  // CheckTx nor DeliverTx results.
    25  // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_async
    26  func BroadcastTxAsync(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    27  	rtx := mempl.GetRealTxFromWrapCMTx(tx)
    28  	err := env.Mempool.CheckTx(tx, nil, mempl.TxInfo{})
    29  
    30  	if err != nil {
    31  		return nil, err
    32  	}
    33  	return &ctypes.ResultBroadcastTx{Hash: rtx.Hash(env.BlockStore.Height())}, nil
    34  }
    35  
    36  // BroadcastTxSync returns with the response from CheckTx. Does not wait for
    37  // DeliverTx result.
    38  // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_sync
    39  func BroadcastTxSync(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    40  	resCh := make(chan *abci.Response, 1)
    41  	rtx := mempl.GetRealTxFromWrapCMTx(tx)
    42  	err := env.Mempool.CheckTx(tx, func(res *abci.Response) {
    43  		resCh <- res
    44  	}, mempl.TxInfo{})
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	res := <-resCh
    49  	r := res.GetCheckTx()
    50  	// reset r.Data for compatibility with cosmwasmJS
    51  	r.Data = nil
    52  	return &ctypes.ResultBroadcastTx{
    53  		Code:      r.Code,
    54  		Data:      r.Data,
    55  		Log:       r.Log,
    56  		Codespace: r.Codespace,
    57  		Hash:      rtx.Hash(env.BlockStore.Height()),
    58  	}, nil
    59  }
    60  
    61  // BroadcastTxCommit returns with the responses from CheckTx and DeliverTx.
    62  // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_commit
    63  func BroadcastTxCommit(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
    64  	subscriber := ctx.RemoteAddr()
    65  
    66  	if env.EventBus.NumClients() >= config.DynamicConfig.GetMaxSubscriptionClients() {
    67  		return nil, fmt.Errorf("max_subscription_clients %d reached", config.DynamicConfig.GetMaxSubscriptionClients())
    68  	} else if env.EventBus.NumClientSubscriptions(subscriber) >= env.Config.MaxSubscriptionsPerClient {
    69  		return nil, fmt.Errorf("max_subscriptions_per_client %d reached", env.Config.MaxSubscriptionsPerClient)
    70  	}
    71  
    72  	// Subscribe to tx being committed in block.
    73  	subCtx, cancel := context.WithTimeout(ctx.Context(), SubscribeTimeout)
    74  	defer cancel()
    75  
    76  	rtx := mempl.GetRealTxFromWrapCMTx(tx)
    77  	q := types.EventQueryTxFor(rtx, env.BlockStore.Height())
    78  	deliverTxSub, err := env.EventBus.Subscribe(subCtx, subscriber, q)
    79  	if err != nil {
    80  		err = fmt.Errorf("failed to subscribe to tx: %w", err)
    81  		env.Logger.Error("Error on broadcast_tx_commit", "err", err)
    82  		return nil, err
    83  	}
    84  	defer env.EventBus.Unsubscribe(context.Background(), subscriber, q)
    85  
    86  	// Broadcast tx and wait for CheckTx result
    87  	checkTxResCh := make(chan *abci.Response, 1)
    88  	err = env.Mempool.CheckTx(tx, func(res *abci.Response) {
    89  		checkTxResCh <- res
    90  	}, mempl.TxInfo{})
    91  	if err != nil {
    92  		env.Logger.Error("Error on broadcastTxCommit", "err", err)
    93  		return nil, fmt.Errorf("error on broadcastTxCommit: %v", err)
    94  	}
    95  	checkTxResMsg := <-checkTxResCh
    96  	checkTxRes := checkTxResMsg.GetCheckTx()
    97  	if checkTxRes.Code != abci.CodeTypeOK {
    98  		return &ctypes.ResultBroadcastTxCommit{
    99  			CheckTx:   *checkTxRes,
   100  			DeliverTx: abci.ResponseDeliverTx{},
   101  			Hash:      rtx.Hash(env.BlockStore.Height()),
   102  		}, nil
   103  	}
   104  
   105  	// Wait for the tx to be included in a block or timeout.
   106  	select {
   107  	case msg := <-deliverTxSub.Out(): // The tx was included in a block.
   108  		deliverTxRes := msg.Data().(types.EventDataTx)
   109  		return &ctypes.ResultBroadcastTxCommit{
   110  			CheckTx:   *checkTxRes,
   111  			DeliverTx: deliverTxRes.Result,
   112  			Hash:      rtx.Hash(env.BlockStore.Height()),
   113  			Height:    deliverTxRes.Height,
   114  		}, nil
   115  	case <-deliverTxSub.Cancelled():
   116  		var reason string
   117  		if deliverTxSub.Err() == nil {
   118  			reason = "Tendermint exited"
   119  		} else {
   120  			reason = deliverTxSub.Err().Error()
   121  		}
   122  		err = fmt.Errorf("deliverTxSub was cancelled (reason: %s)", reason)
   123  		env.Logger.Error("Error on broadcastTxCommit", "err", err)
   124  		return &ctypes.ResultBroadcastTxCommit{
   125  			CheckTx:   *checkTxRes,
   126  			DeliverTx: abci.ResponseDeliverTx{},
   127  			Hash:      rtx.Hash(env.BlockStore.Height()),
   128  		}, err
   129  	case <-time.After(env.Config.TimeoutBroadcastTxCommit):
   130  		err = errors.New("timed out waiting for tx to be included in a block")
   131  		env.Logger.Error("Error on broadcastTxCommit", "err", err)
   132  		return &ctypes.ResultBroadcastTxCommit{
   133  			CheckTx:   *checkTxRes,
   134  			DeliverTx: abci.ResponseDeliverTx{},
   135  			Hash:      rtx.Hash(env.BlockStore.Height()),
   136  		}, err
   137  	}
   138  }
   139  
   140  // UnconfirmedTxs gets unconfirmed transactions (maximum ?limit entries)
   141  // including their number.
   142  // More: https://docs.tendermint.com/master/rpc/#/Info/unconfirmed_txs
   143  func UnconfirmedTxs(ctx *rpctypes.Context, limit int) (*ctypes.ResultUnconfirmedTxs, error) {
   144  
   145  	txs := env.Mempool.ReapMaxTxs(limit)
   146  	return &ctypes.ResultUnconfirmedTxs{
   147  		Count:      len(txs),
   148  		Total:      env.Mempool.Size(),
   149  		TotalBytes: env.Mempool.TxsBytes(),
   150  		Txs:        txs}, nil
   151  }
   152  
   153  // NumUnconfirmedTxs gets number of unconfirmed transactions.
   154  // More: https://docs.tendermint.com/master/rpc/#/Info/num_unconfirmed_txs
   155  func NumUnconfirmedTxs(ctx *rpctypes.Context) (*ctypes.ResultUnconfirmedTxs, error) {
   156  	return &ctypes.ResultUnconfirmedTxs{
   157  		Count:      env.Mempool.Size(),
   158  		Total:      env.Mempool.Size(),
   159  		TotalBytes: env.Mempool.TxsBytes()}, nil
   160  }
   161  
   162  func TxSimulateGasCost(ctx *rpctypes.Context, hash string) (*ctypes.ResponseTxSimulateGas, error) {
   163  	return &ctypes.ResponseTxSimulateGas{
   164  		GasCost: env.Mempool.GetTxSimulateGas(hash),
   165  	}, nil
   166  }
   167  
   168  func UserUnconfirmedTxs(address string, limit int) (*ctypes.ResultUserUnconfirmedTxs, error) {
   169  	txs := env.Mempool.ReapUserTxs(address, limit)
   170  	return &ctypes.ResultUserUnconfirmedTxs{
   171  		Count: len(txs),
   172  		Txs:   txs}, nil
   173  }
   174  
   175  func TmUserUnconfirmedTxs(ctx *rpctypes.Context, address string, limit int) (*ctypes.ResultUserUnconfirmedTxs, error) {
   176  	return UserUnconfirmedTxs(address, limit)
   177  }
   178  
   179  func UserNumUnconfirmedTxs(address string) (*ctypes.ResultUserUnconfirmedTxs, error) {
   180  	nums := env.Mempool.ReapUserTxsCnt(address)
   181  	return &ctypes.ResultUserUnconfirmedTxs{
   182  		Count: nums}, nil
   183  }
   184  
   185  func TmUserNumUnconfirmedTxs(ctx *rpctypes.Context, address string) (*ctypes.ResultUserUnconfirmedTxs, error) {
   186  	return UserNumUnconfirmedTxs(address)
   187  }
   188  
   189  func GetUnconfirmedTxByHash(hash [sha256.Size]byte) (types.Tx, error) {
   190  	return env.Mempool.GetTxByHash(hash)
   191  }
   192  
   193  func GetAddressList() (*ctypes.ResultUnconfirmedAddresses, error) {
   194  	addressList := env.Mempool.GetAddressList()
   195  	return &ctypes.ResultUnconfirmedAddresses{
   196  		Addresses: addressList,
   197  	}, nil
   198  }
   199  
   200  func TmGetAddressList(ctx *rpctypes.Context) (*ctypes.ResultUnconfirmedAddresses, error) {
   201  	return GetAddressList()
   202  }
   203  
   204  func GetPendingNonce(address string) (*ctypes.ResultPendingNonce, bool) {
   205  	nonce, ok := env.Mempool.GetPendingNonce(address)
   206  	if !ok {
   207  		return nil, false
   208  	}
   209  	return &ctypes.ResultPendingNonce{
   210  		Nonce: nonce,
   211  	}, true
   212  }
   213  
   214  func GetEnableDeleteMinGPTx(ctx *rpctypes.Context) (*ctypes.ResultEnableDeleteMinGPTx, error) {
   215  	status := env.Mempool.GetEnableDeleteMinGPTx()
   216  	return &ctypes.ResultEnableDeleteMinGPTx{Enable: status}, nil
   217  }
   218  
   219  func GetPendingTxs(ctx *rpctypes.Context) (*ctypes.ResultPendingTxs, error) {
   220  	pendingTx := make(map[string]map[string]types.WrappedMempoolTx)
   221  	if baseapp.IsMempoolEnablePendingPool() {
   222  		pendingTx = env.Mempool.GetPendingPoolTxsBytes()
   223  	}
   224  	return &ctypes.ResultPendingTxs{Txs: pendingTx}, nil
   225  }