github.com/Oyster-zx/tendermint@v0.34.24-fork/rpc/core/mempool.go (about) 1 package core 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "time" 8 9 abci "github.com/tendermint/tendermint/abci/types" 10 mempl "github.com/tendermint/tendermint/mempool" 11 ctypes "github.com/tendermint/tendermint/rpc/core/types" 12 rpctypes "github.com/tendermint/tendermint/rpc/jsonrpc/types" 13 "github.com/tendermint/tendermint/types" 14 ) 15 16 //----------------------------------------------------------------------------- 17 // NOTE: tx should be signed, but this is only checked at the app level (not by Tendermint!) 18 19 // BroadcastTxAsync returns right away, with no response. Does not wait for 20 // CheckTx nor DeliverTx results. 21 // More: https://docs.tendermint.com/v0.34/rpc/#/Tx/broadcast_tx_async 22 func BroadcastTxAsync(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 23 err := env.Mempool.CheckTx(tx, nil, mempl.TxInfo{}) 24 25 if err != nil { 26 return nil, err 27 } 28 return &ctypes.ResultBroadcastTx{Hash: tx.Hash()}, nil 29 } 30 31 // BroadcastTxSync returns with the response from CheckTx. Does not wait for 32 // DeliverTx result. 33 // More: https://docs.tendermint.com/v0.34/rpc/#/Tx/broadcast_tx_sync 34 func BroadcastTxSync(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTx, error) { 35 resCh := make(chan *abci.Response, 1) 36 err := env.Mempool.CheckTx(tx, func(res *abci.Response) { 37 select { 38 case <-ctx.Context().Done(): 39 case resCh <- res: 40 } 41 42 }, mempl.TxInfo{}) 43 if err != nil { 44 return nil, err 45 } 46 47 select { 48 case <-ctx.Context().Done(): 49 return nil, fmt.Errorf("broadcast confirmation not received: %w", ctx.Context().Err()) 50 case res := <-resCh: 51 r := res.GetCheckTx() 52 return &ctypes.ResultBroadcastTx{ 53 Code: r.Code, 54 Data: r.Data, 55 Log: r.Log, 56 Codespace: r.Codespace, 57 Hash: tx.Hash(), 58 }, nil 59 } 60 } 61 62 // BroadcastTxCommit returns with the responses from CheckTx and DeliverTx. 63 // More: https://docs.tendermint.com/v0.34/rpc/#/Tx/broadcast_tx_commit 64 func BroadcastTxCommit(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultBroadcastTxCommit, error) { 65 subscriber := ctx.RemoteAddr() 66 67 if env.EventBus.NumClients() >= env.Config.MaxSubscriptionClients { 68 return nil, fmt.Errorf("max_subscription_clients %d reached", env.Config.MaxSubscriptionClients) 69 } else if env.EventBus.NumClientSubscriptions(subscriber) >= env.Config.MaxSubscriptionsPerClient { 70 return nil, fmt.Errorf("max_subscriptions_per_client %d reached", env.Config.MaxSubscriptionsPerClient) 71 } 72 73 // Subscribe to tx being committed in block. 74 subCtx, cancel := context.WithTimeout(ctx.Context(), SubscribeTimeout) 75 defer cancel() 76 q := types.EventQueryTxFor(tx) 77 deliverTxSub, err := env.EventBus.Subscribe(subCtx, subscriber, q) 78 if err != nil { 79 err = fmt.Errorf("failed to subscribe to tx: %w", err) 80 env.Logger.Error("Error on broadcast_tx_commit", "err", err) 81 return nil, err 82 } 83 defer func() { 84 if err := env.EventBus.Unsubscribe(context.Background(), subscriber, q); err != nil { 85 env.Logger.Error("Error unsubscribing from eventBus", "err", err) 86 } 87 }() 88 89 // Broadcast tx and wait for CheckTx result 90 checkTxResCh := make(chan *abci.Response, 1) 91 err = env.Mempool.CheckTx(tx, func(res *abci.Response) { 92 select { 93 case <-ctx.Context().Done(): 94 case checkTxResCh <- res: 95 } 96 }, mempl.TxInfo{}) 97 if err != nil { 98 env.Logger.Error("Error on broadcastTxCommit", "err", err) 99 return nil, fmt.Errorf("error on broadcastTxCommit: %v", err) 100 } 101 select { 102 case <-ctx.Context().Done(): 103 return nil, fmt.Errorf("broadcast confirmation not received: %w", ctx.Context().Err()) 104 case checkTxResMsg := <-checkTxResCh: 105 checkTxRes := checkTxResMsg.GetCheckTx() 106 if checkTxRes.Code != abci.CodeTypeOK { 107 return &ctypes.ResultBroadcastTxCommit{ 108 CheckTx: *checkTxRes, 109 DeliverTx: abci.ResponseDeliverTx{}, 110 Hash: tx.Hash(), 111 }, nil 112 } 113 114 // Wait for the tx to be included in a block or timeout. 115 select { 116 case msg := <-deliverTxSub.Out(): // The tx was included in a block. 117 deliverTxRes := msg.Data().(types.EventDataTx) 118 return &ctypes.ResultBroadcastTxCommit{ 119 CheckTx: *checkTxRes, 120 DeliverTx: deliverTxRes.Result, 121 Hash: tx.Hash(), 122 Height: deliverTxRes.Height, 123 }, nil 124 case <-deliverTxSub.Cancelled(): 125 var reason string 126 if deliverTxSub.Err() == nil { 127 reason = "Tendermint exited" 128 } else { 129 reason = deliverTxSub.Err().Error() 130 } 131 err = fmt.Errorf("deliverTxSub was cancelled (reason: %s)", reason) 132 env.Logger.Error("Error on broadcastTxCommit", "err", err) 133 return &ctypes.ResultBroadcastTxCommit{ 134 CheckTx: *checkTxRes, 135 DeliverTx: abci.ResponseDeliverTx{}, 136 Hash: tx.Hash(), 137 }, err 138 case <-time.After(env.Config.TimeoutBroadcastTxCommit): 139 err = errors.New("timed out waiting for tx to be included in a block") 140 env.Logger.Error("Error on broadcastTxCommit", "err", err) 141 return &ctypes.ResultBroadcastTxCommit{ 142 CheckTx: *checkTxRes, 143 DeliverTx: abci.ResponseDeliverTx{}, 144 Hash: tx.Hash(), 145 }, err 146 } 147 } 148 } 149 150 // UnconfirmedTxs gets unconfirmed transactions (maximum ?limit entries) 151 // including their number. 152 // More: https://docs.tendermint.com/v0.34/rpc/#/Info/unconfirmed_txs 153 func UnconfirmedTxs(ctx *rpctypes.Context, limitPtr *int) (*ctypes.ResultUnconfirmedTxs, error) { 154 // reuse per_page validator 155 limit := validatePerPage(limitPtr) 156 157 txs := env.Mempool.ReapMaxTxs(limit) 158 return &ctypes.ResultUnconfirmedTxs{ 159 Count: len(txs), 160 Total: env.Mempool.Size(), 161 TotalBytes: env.Mempool.SizeBytes(), 162 Txs: txs}, nil 163 } 164 165 // NumUnconfirmedTxs gets number of unconfirmed transactions. 166 // More: https://docs.tendermint.com/v0.34/rpc/#/Info/num_unconfirmed_txs 167 func NumUnconfirmedTxs(ctx *rpctypes.Context) (*ctypes.ResultUnconfirmedTxs, error) { 168 return &ctypes.ResultUnconfirmedTxs{ 169 Count: env.Mempool.Size(), 170 Total: env.Mempool.Size(), 171 TotalBytes: env.Mempool.SizeBytes()}, nil 172 } 173 174 // CheckTx checks the transaction without executing it. The transaction won't 175 // be added to the mempool either. 176 // More: https://docs.tendermint.com/v0.34/rpc/#/Tx/check_tx 177 func CheckTx(ctx *rpctypes.Context, tx types.Tx) (*ctypes.ResultCheckTx, error) { 178 res, err := env.ProxyAppMempool.CheckTxSync(abci.RequestCheckTx{Tx: tx}) 179 if err != nil { 180 return nil, err 181 } 182 return &ctypes.ResultCheckTx{ResponseCheckTx: *res}, nil 183 }