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