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