github.com/pokt-network/tendermint@v0.32.11-0.20230426215212-59310158d3e9/rpc/core/mempool.go (about)

     1  package core
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"time"
     7  
     8  	"github.com/pkg/errors"
     9  
    10  	abci "github.com/tendermint/tendermint/abci/types"
    11  	mempl "github.com/tendermint/tendermint/mempool"
    12  	ctypes "github.com/tendermint/tendermint/rpc/core/types"
    13  	rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types"
    14  	"github.com/tendermint/tendermint/types"
    15  )
    16  
    17  //-----------------------------------------------------------------------------
    18  // NOTE: tx should be signed, but this is only checked at the app level (not by Tendermint!)
    19  
    20  // BroadcastTxAsync returns right away, with no response. Does not wait for
    21  // CheckTx nor DeliverTx results.
    22  // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_async
    23  func BroadcastTxAsync(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    24  	err := env.Mempool.CheckTx(tx, nil, mempl.TxInfo{})
    25  
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  	return &ctypes.ResultBroadcastTx{Hash: tx.Hash()}, nil
    30  }
    31  
    32  // BroadcastTxSync returns with the response from CheckTx. Does not wait for
    33  // DeliverTx result.
    34  // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_sync
    35  func BroadcastTxSync(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    36  	resCh := make(chan *abci.Response, 1)
    37  	err := env.Mempool.CheckTx(tx, func(res *abci.Response) {
    38  		resCh <- res
    39  	}, mempl.TxInfo{})
    40  	if err != nil {
    41  		return nil, err
    42  	}
    43  	res := <-resCh
    44  	r := res.GetCheckTx()
    45  	return &ctypes.ResultBroadcastTx{
    46  		Code:      r.Code,
    47  		Data:      r.Data,
    48  		Log:       r.Log,
    49  		Codespace: r.Codespace,
    50  		Hash:      tx.Hash(),
    51  	}, nil
    52  }
    53  
    54  // BroadcastTxCommit returns with the responses from CheckTx and DeliverTx.
    55  // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_commit
    56  func BroadcastTxCommit(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
    57  	subscriber := ctx.RemoteAddr()
    58  
    59  	if env.EventBus.NumClients() >= env.Config.MaxSubscriptionClients {
    60  		return nil, fmt.Errorf("max_subscription_clients %d reached", env.Config.MaxSubscriptionClients)
    61  	} else if env.EventBus.NumClientSubscriptions(subscriber) >= env.Config.MaxSubscriptionsPerClient {
    62  		return nil, fmt.Errorf("max_subscriptions_per_client %d reached", env.Config.MaxSubscriptionsPerClient)
    63  	}
    64  
    65  	// Subscribe to tx being committed in block.
    66  	subCtx, cancel := context.WithTimeout(ctx.Context(), SubscribeTimeout)
    67  	defer cancel()
    68  	q := types.EventQueryTxFor(tx)
    69  	deliverTxSub, err := env.EventBus.Subscribe(subCtx, subscriber, q)
    70  	if err != nil {
    71  		err = fmt.Errorf("failed to subscribe to tx: %w", err)
    72  		env.Logger.Error("Error on broadcast_tx_commit", "err", err)
    73  		return nil, err
    74  	}
    75  	defer env.EventBus.Unsubscribe(context.Background(), subscriber, q)
    76  
    77  	// Broadcast tx and wait for CheckTx result
    78  	checkTxResCh := make(chan *abci.Response, 1)
    79  	err = env.Mempool.CheckTx(tx, func(res *abci.Response) {
    80  		checkTxResCh <- res
    81  	}, mempl.TxInfo{})
    82  	if err != nil {
    83  		env.Logger.Error("Error on broadcastTxCommit", "err", err)
    84  		return nil, fmt.Errorf("error on broadcastTxCommit: %v", err)
    85  	}
    86  	checkTxResMsg := <-checkTxResCh
    87  	checkTxRes := checkTxResMsg.GetCheckTx()
    88  	if checkTxRes.Code != abci.CodeTypeOK {
    89  		return &ctypes.ResultBroadcastTxCommit{
    90  			CheckTx:   *checkTxRes,
    91  			DeliverTx: abci.ResponseDeliverTx{},
    92  			Hash:      tx.Hash(),
    93  		}, nil
    94  	}
    95  
    96  	// Wait for the tx to be included in a block or timeout.
    97  	select {
    98  	case msg := <-deliverTxSub.Out(): // The tx was included in a block.
    99  		deliverTxRes := msg.Data().(types.EventDataTx)
   100  		return &ctypes.ResultBroadcastTxCommit{
   101  			CheckTx:   *checkTxRes,
   102  			DeliverTx: deliverTxRes.Result,
   103  			Hash:      tx.Hash(),
   104  			Height:    deliverTxRes.Height,
   105  		}, nil
   106  	case <-deliverTxSub.Cancelled():
   107  		var reason string
   108  		if deliverTxSub.Err() == nil {
   109  			reason = "Tendermint exited"
   110  		} else {
   111  			reason = deliverTxSub.Err().Error()
   112  		}
   113  		err = fmt.Errorf("deliverTxSub was cancelled (reason: %s)", reason)
   114  		env.Logger.Error("Error on broadcastTxCommit", "err", err)
   115  		return &ctypes.ResultBroadcastTxCommit{
   116  			CheckTx:   *checkTxRes,
   117  			DeliverTx: abci.ResponseDeliverTx{},
   118  			Hash:      tx.Hash(),
   119  		}, err
   120  	case <-time.After(env.Config.TimeoutBroadcastTxCommit):
   121  		err = errors.New("timed out waiting for tx to be included in a block")
   122  		env.Logger.Error("Error on broadcastTxCommit", "err", err)
   123  		return &ctypes.ResultBroadcastTxCommit{
   124  			CheckTx:   *checkTxRes,
   125  			DeliverTx: abci.ResponseDeliverTx{},
   126  			Hash:      tx.Hash(),
   127  		}, err
   128  	}
   129  }
   130  
   131  // UnconfirmedTxs gets unconfirmed transactions (maximum ?limit entries)
   132  // including their number.
   133  // More: https://docs.tendermint.com/master/rpc/#/Info/unconfirmed_txs
   134  func UnconfirmedTxs(ctx *rpctypes.Context, limit int) (*ctypes.ResultUnconfirmedTxs, error) {
   135  	// reuse per_page validator
   136  	limit = validatePerPage(limit)
   137  
   138  	txs := env.Mempool.ReapMaxTxs(limit)
   139  	return &ctypes.ResultUnconfirmedTxs{
   140  		Count:      len(txs),
   141  		Total:      env.Mempool.Size(),
   142  		TotalBytes: env.Mempool.TxsBytes(),
   143  		Txs:        txs}, nil
   144  }
   145  
   146  // NumUnconfirmedTxs gets number of unconfirmed transactions.
   147  // More: https://docs.tendermint.com/master/rpc/#/Info/num_unconfirmed_txs
   148  func NumUnconfirmedTxs(ctx *rpctypes.Context) (*ctypes.ResultUnconfirmedTxs, error) {
   149  	return &ctypes.ResultUnconfirmedTxs{
   150  		Count:      env.Mempool.Size(),
   151  		Total:      env.Mempool.Size(),
   152  		TotalBytes: env.Mempool.TxsBytes()}, nil
   153  }