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 }