github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/client/context/broadcast.go (about)

     1  package context
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags"
     8  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     9  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    10  	"github.com/fibonacci-chain/fbc/libs/tendermint/mempool"
    11  	"github.com/fibonacci-chain/fbc/libs/tendermint/types"
    12  )
    13  
    14  // BroadcastTx broadcasts a transactions either synchronously or asynchronously
    15  // based on the context parameters. The result of the broadcast is parsed into
    16  // an intermediate structure which is logged if the context has a logger
    17  // defined.
    18  func (ctx CLIContext) BroadcastTx(txBytes []byte) (res sdk.TxResponse, err error) {
    19  	switch ctx.BroadcastMode {
    20  	case flags.BroadcastSync:
    21  		res, err = ctx.BroadcastTxSync(txBytes)
    22  
    23  	case flags.BroadcastAsync:
    24  		res, err = ctx.BroadcastTxAsync(txBytes)
    25  
    26  	case flags.BroadcastBlock:
    27  		res, err = ctx.BroadcastTxCommit(txBytes)
    28  
    29  	default:
    30  		return sdk.TxResponse{}, fmt.Errorf("unsupported return type %s; supported types: sync, async, block", ctx.BroadcastMode)
    31  	}
    32  
    33  	return res, err
    34  }
    35  
    36  // CheckTendermintError checks if the error returned from BroadcastTx is a
    37  // Tendermint error that is returned before the tx is submitted due to
    38  // precondition checks that failed. If an Tendermint error is detected, this
    39  // function returns the correct code back in TxResponse.
    40  //
    41  // TODO: Avoid brittle string matching in favor of error matching. This requires
    42  // a change to Tendermint's RPCError type to allow retrieval or matching against
    43  // a concrete error type.
    44  func (ctx CLIContext) CheckTendermintError(err error, txBytes []byte) *sdk.TxResponse {
    45  	if err == nil {
    46  		return nil
    47  	}
    48  	var height int64
    49  	lastHeight, err2 := ctx.Client.LatestBlockNumber()
    50  	if err2 == nil {
    51  		height = lastHeight
    52  	} else {
    53  		// default new tx hash
    54  		height = types.GetMilestoneVenusHeight()
    55  	}
    56  
    57  	errStr := strings.ToLower(err.Error())
    58  	txHash := fmt.Sprintf("%X", types.Tx(txBytes).Hash(height))
    59  
    60  	switch {
    61  	case strings.Contains(errStr, strings.ToLower(mempool.ErrTxInCache.Error())):
    62  		return &sdk.TxResponse{
    63  			Code:   sdkerrors.ErrTxInMempoolCache.ABCICode(),
    64  			RawLog: errStr,
    65  			TxHash: txHash,
    66  		}
    67  
    68  	case strings.Contains(errStr, "mempool is full"):
    69  		return &sdk.TxResponse{
    70  			Code:   sdkerrors.ErrMempoolIsFull.ABCICode(),
    71  			RawLog: errStr,
    72  			TxHash: txHash,
    73  		}
    74  
    75  	case strings.Contains(errStr, "tx too large"):
    76  		return &sdk.TxResponse{
    77  			Code:   sdkerrors.ErrTxTooLarge.ABCICode(),
    78  			RawLog: errStr,
    79  			TxHash: txHash,
    80  		}
    81  
    82  	default:
    83  		return nil
    84  	}
    85  }
    86  
    87  // BroadcastTxCommit broadcasts transaction bytes to a Tendermint node and
    88  // waits for a commit. An error is only returned if there is no RPC node
    89  // connection or if broadcasting fails.
    90  //
    91  // NOTE: This should ideally not be used as the request may timeout but the tx
    92  // may still be included in a block. Use BroadcastTxAsync or BroadcastTxSync
    93  // instead.
    94  func (ctx CLIContext) BroadcastTxCommit(txBytes []byte) (sdk.TxResponse, error) {
    95  	node, err := ctx.GetNode()
    96  	if err != nil {
    97  		return sdk.TxResponse{}, err
    98  	}
    99  
   100  	res, err := node.BroadcastTxCommit(txBytes)
   101  	if err != nil {
   102  		if errRes := ctx.CheckTendermintError(err, txBytes); errRes != nil {
   103  			return *errRes, nil
   104  		}
   105  
   106  		return sdk.NewResponseFormatBroadcastTxCommit(res), err
   107  	}
   108  
   109  	if !res.CheckTx.IsOK() {
   110  		return sdk.NewResponseFormatBroadcastTxCommit(res), nil
   111  	}
   112  
   113  	if !res.DeliverTx.IsOK() {
   114  		return sdk.NewResponseFormatBroadcastTxCommit(res), nil
   115  	}
   116  
   117  	return sdk.NewResponseFormatBroadcastTxCommit(res), nil
   118  }
   119  
   120  // BroadcastTxSync broadcasts transaction bytes to a Tendermint node
   121  // synchronously (i.e. returns after CheckTx execution).
   122  func (ctx CLIContext) BroadcastTxSync(txBytes []byte) (sdk.TxResponse, error) {
   123  	node, err := ctx.GetNode()
   124  	if err != nil {
   125  		return sdk.TxResponse{}, err
   126  	}
   127  
   128  	res, err := node.BroadcastTxSync(txBytes)
   129  	if errRes := ctx.CheckTendermintError(err, txBytes); errRes != nil {
   130  		return *errRes, nil
   131  	}
   132  
   133  	return sdk.NewResponseFormatBroadcastTx(res), err
   134  }
   135  
   136  // BroadcastTxAsync broadcasts transaction bytes to a Tendermint node
   137  // asynchronously (i.e. returns immediately).
   138  func (ctx CLIContext) BroadcastTxAsync(txBytes []byte) (sdk.TxResponse, error) {
   139  	node, err := ctx.GetNode()
   140  	if err != nil {
   141  		return sdk.TxResponse{}, err
   142  	}
   143  
   144  	res, err := node.BroadcastTxAsync(txBytes)
   145  	if errRes := ctx.CheckTendermintError(err, txBytes); errRes != nil {
   146  		return *errRes, nil
   147  	}
   148  
   149  	return sdk.NewResponseFormatBroadcastTx(res), err
   150  }