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