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