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