github.com/number571/tendermint@v0.34.11-gost/rpc/core/mempool.go (about)

     1  package core
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"time"
     8  
     9  	abci "github.com/number571/tendermint/abci/types"
    10  	mempl "github.com/number571/tendermint/internal/mempool"
    11  	tmpubsub "github.com/number571/tendermint/libs/pubsub"
    12  	ctypes "github.com/number571/tendermint/rpc/core/types"
    13  	rpctypes "github.com/number571/tendermint/rpc/jsonrpc/types"
    14  	"github.com/number571/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 (env *Environment) BroadcastTxAsync(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    24  	err := env.Mempool.CheckTx(ctx.Context(), tx, nil, mempl.TxInfo{})
    25  	if err != nil {
    26  		return nil, err
    27  	}
    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 (env *Environment) BroadcastTxSync(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) {
    36  	resCh := make(chan *abci.Response, 1)
    37  	err := env.Mempool.CheckTx(
    38  		ctx.Context(),
    39  		tx,
    40  		func(res *abci.Response) { resCh <- res },
    41  		mempl.TxInfo{},
    42  	)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  
    47  	res := <-resCh
    48  	r := res.GetCheckTx()
    49  
    50  	return &ctypes.ResultBroadcastTx{
    51  		Code:         r.Code,
    52  		Data:         r.Data,
    53  		Log:          r.Log,
    54  		Codespace:    r.Codespace,
    55  		MempoolError: r.MempoolError,
    56  		Hash:         tx.Hash(),
    57  	}, nil
    58  }
    59  
    60  // BroadcastTxCommit returns with the responses from CheckTx and DeliverTx.
    61  // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_commit
    62  func (env *Environment) BroadcastTxCommit(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) {
    63  	subscriber := ctx.RemoteAddr()
    64  
    65  	if env.EventBus.NumClients() >= env.Config.MaxSubscriptionClients {
    66  		return nil, fmt.Errorf("max_subscription_clients %d reached", env.Config.MaxSubscriptionClients)
    67  	} else if env.EventBus.NumClientSubscriptions(subscriber) >= env.Config.MaxSubscriptionsPerClient {
    68  		return nil, fmt.Errorf("max_subscriptions_per_client %d reached", env.Config.MaxSubscriptionsPerClient)
    69  	}
    70  
    71  	// Subscribe to tx being committed in block.
    72  	subCtx, cancel := context.WithTimeout(ctx.Context(), SubscribeTimeout)
    73  	defer cancel()
    74  	q := types.EventQueryTxFor(tx)
    75  	deliverTxSub, err := env.EventBus.Subscribe(subCtx, subscriber, q)
    76  	if err != nil {
    77  		err = fmt.Errorf("failed to subscribe to tx: %w", err)
    78  		env.Logger.Error("Error on broadcast_tx_commit", "err", err)
    79  		return nil, err
    80  	}
    81  	defer func() {
    82  		args := tmpubsub.UnsubscribeArgs{Subscriber: subscriber, Query: q}
    83  		if err := env.EventBus.Unsubscribe(context.Background(), args); err != nil {
    84  			env.Logger.Error("Error unsubscribing from eventBus", "err", err)
    85  		}
    86  	}()
    87  
    88  	// Broadcast tx and wait for CheckTx result
    89  	checkTxResCh := make(chan *abci.Response, 1)
    90  	err = env.Mempool.CheckTx(
    91  		ctx.Context(),
    92  		tx,
    93  		func(res *abci.Response) { checkTxResCh <- res },
    94  		mempl.TxInfo{},
    95  	)
    96  	if err != nil {
    97  		env.Logger.Error("Error on broadcastTxCommit", "err", err)
    98  		return nil, fmt.Errorf("error on broadcastTxCommit: %v", err)
    99  	}
   100  
   101  	checkTxResMsg := <-checkTxResCh
   102  	checkTxRes := checkTxResMsg.GetCheckTx()
   103  
   104  	if checkTxRes.Code != abci.CodeTypeOK {
   105  		return &ctypes.ResultBroadcastTxCommit{
   106  			CheckTx:   *checkTxRes,
   107  			DeliverTx: abci.ResponseDeliverTx{},
   108  			Hash:      tx.Hash(),
   109  		}, nil
   110  	}
   111  
   112  	// Wait for the tx to be included in a block or timeout.
   113  	select {
   114  	case msg := <-deliverTxSub.Out(): // The tx was included in a block.
   115  		deliverTxRes := msg.Data().(types.EventDataTx)
   116  		return &ctypes.ResultBroadcastTxCommit{
   117  			CheckTx:   *checkTxRes,
   118  			DeliverTx: deliverTxRes.Result,
   119  			Hash:      tx.Hash(),
   120  			Height:    deliverTxRes.Height,
   121  		}, nil
   122  	case <-deliverTxSub.Canceled():
   123  		var reason string
   124  		if deliverTxSub.Err() == nil {
   125  			reason = "Tendermint exited"
   126  		} else {
   127  			reason = deliverTxSub.Err().Error()
   128  		}
   129  		err = fmt.Errorf("deliverTxSub was canceled (reason: %s)", reason)
   130  		env.Logger.Error("Error on broadcastTxCommit", "err", err)
   131  		return &ctypes.ResultBroadcastTxCommit{
   132  			CheckTx:   *checkTxRes,
   133  			DeliverTx: abci.ResponseDeliverTx{},
   134  			Hash:      tx.Hash(),
   135  		}, err
   136  	case <-time.After(env.Config.TimeoutBroadcastTxCommit):
   137  		err = errors.New("timed out waiting for tx to be included in a block")
   138  		env.Logger.Error("Error on broadcastTxCommit", "err", err)
   139  		return &ctypes.ResultBroadcastTxCommit{
   140  			CheckTx:   *checkTxRes,
   141  			DeliverTx: abci.ResponseDeliverTx{},
   142  			Hash:      tx.Hash(),
   143  		}, err
   144  	}
   145  }
   146  
   147  // UnconfirmedTxs gets unconfirmed transactions (maximum ?limit entries)
   148  // including their number.
   149  // More: https://docs.tendermint.com/master/rpc/#/Info/unconfirmed_txs
   150  func (env *Environment) UnconfirmedTxs(ctx *rpctypes.Context, limitPtr *int) (*ctypes.ResultUnconfirmedTxs, error) {
   151  	// reuse per_page validator
   152  	limit := env.validatePerPage(limitPtr)
   153  
   154  	txs := env.Mempool.ReapMaxTxs(limit)
   155  	return &ctypes.ResultUnconfirmedTxs{
   156  		Count:      len(txs),
   157  		Total:      env.Mempool.Size(),
   158  		TotalBytes: env.Mempool.SizeBytes(),
   159  		Txs:        txs}, nil
   160  }
   161  
   162  // NumUnconfirmedTxs gets number of unconfirmed transactions.
   163  // More: https://docs.tendermint.com/master/rpc/#/Info/num_unconfirmed_txs
   164  func (env *Environment) NumUnconfirmedTxs(ctx *rpctypes.Context) (*ctypes.ResultUnconfirmedTxs, error) {
   165  	return &ctypes.ResultUnconfirmedTxs{
   166  		Count:      env.Mempool.Size(),
   167  		Total:      env.Mempool.Size(),
   168  		TotalBytes: env.Mempool.SizeBytes()}, nil
   169  }
   170  
   171  // CheckTx checks the transaction without executing it. The transaction won't
   172  // be added to the mempool either.
   173  // More: https://docs.tendermint.com/master/rpc/#/Tx/check_tx
   174  func (env *Environment) CheckTx(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultCheckTx, error) {
   175  	res, err := env.ProxyAppMempool.CheckTxSync(ctx.Context(), abci.RequestCheckTx{Tx: tx})
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  	return &ctypes.ResultCheckTx{ResponseCheckTx: *res}, nil
   180  }