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 }