github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/internal/rpc/core/mempool.go (about) 1 package core 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "math/rand" 8 "time" 9 10 abci "github.com/ari-anchor/sei-tendermint/abci/types" 11 "github.com/ari-anchor/sei-tendermint/internal/mempool" 12 "github.com/ari-anchor/sei-tendermint/internal/state/indexer" 13 tmmath "github.com/ari-anchor/sei-tendermint/libs/math" 14 "github.com/ari-anchor/sei-tendermint/rpc/coretypes" 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: 23 // https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_async 24 // Deprecated and should be removed in 0.37 25 func (env *Environment) BroadcastTxAsync(ctx context.Context, req *coretypes.RequestBroadcastTx) (*coretypes.ResultBroadcastTx, error) { 26 go func() { _ = env.Mempool.CheckTx(ctx, req.Tx, nil, mempool.TxInfo{}) }() 27 28 return &coretypes.ResultBroadcastTx{Hash: req.Tx.Hash()}, nil 29 } 30 31 // Deprecated and should be remove in 0.37 32 func (env *Environment) BroadcastTxSync(ctx context.Context, req *coretypes.RequestBroadcastTx) (*coretypes.ResultBroadcastTx, error) { 33 return env.BroadcastTx(ctx, req) 34 } 35 36 // BroadcastTx returns with the response from CheckTx. Does not wait for 37 // DeliverTx result. 38 // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_sync 39 func (env *Environment) BroadcastTx(ctx context.Context, req *coretypes.RequestBroadcastTx) (*coretypes.ResultBroadcastTx, error) { 40 resCh := make(chan *abci.ResponseCheckTx, 1) 41 err := env.Mempool.CheckTx( 42 ctx, 43 req.Tx, 44 func(res *abci.ResponseCheckTx) { 45 select { 46 case <-ctx.Done(): 47 case resCh <- res: 48 } 49 }, 50 mempool.TxInfo{}, 51 ) 52 if err != nil { 53 return nil, err 54 } 55 56 select { 57 case <-ctx.Done(): 58 return nil, fmt.Errorf("broadcast confirmation not received: %w", ctx.Err()) 59 case r := <-resCh: 60 return &coretypes.ResultBroadcastTx{ 61 Code: r.Code, 62 Data: r.Data, 63 Codespace: r.Codespace, 64 Hash: req.Tx.Hash(), 65 }, nil 66 } 67 } 68 69 // BroadcastTxCommit returns with the responses from CheckTx and DeliverTx. 70 // More: https://docs.tendermint.com/master/rpc/#/Tx/broadcast_tx_commit 71 func (env *Environment) BroadcastTxCommit(ctx context.Context, req *coretypes.RequestBroadcastTx) (*coretypes.ResultBroadcastTxCommit, error) { 72 resCh := make(chan *abci.ResponseCheckTx, 1) 73 err := env.Mempool.CheckTx( 74 ctx, 75 req.Tx, 76 func(res *abci.ResponseCheckTx) { 77 select { 78 case <-ctx.Done(): 79 case resCh <- res: 80 } 81 }, 82 mempool.TxInfo{}, 83 ) 84 if err != nil { 85 return nil, err 86 } 87 88 select { 89 case <-ctx.Done(): 90 return nil, fmt.Errorf("broadcast confirmation not received: %w", ctx.Err()) 91 case r := <-resCh: 92 if r.Code != abci.CodeTypeOK { 93 return &coretypes.ResultBroadcastTxCommit{ 94 CheckTx: *r, 95 Hash: req.Tx.Hash(), 96 }, nil 97 } 98 99 if !indexer.KVSinkEnabled(env.EventSinks) { 100 return &coretypes.ResultBroadcastTxCommit{ 101 CheckTx: *r, 102 Hash: req.Tx.Hash(), 103 }, 104 errors.New("cannot confirm transaction because kvEventSink is not enabled") 105 } 106 107 startAt := time.Now() 108 timer := time.NewTimer(0) 109 defer timer.Stop() 110 111 count := 0 112 for { 113 count++ 114 select { 115 case <-ctx.Done(): 116 env.Logger.Error("error on broadcastTxCommit", 117 "duration", time.Since(startAt), 118 "err", err) 119 return &coretypes.ResultBroadcastTxCommit{ 120 CheckTx: *r, 121 Hash: req.Tx.Hash(), 122 }, fmt.Errorf("timeout waiting for commit of tx %s (%s)", 123 req.Tx.Hash(), time.Since(startAt)) 124 case <-timer.C: 125 txres, err := env.Tx(ctx, &coretypes.RequestTx{ 126 Hash: req.Tx.Hash(), 127 Prove: false, 128 }) 129 if err != nil { 130 jitter := 100*time.Millisecond + time.Duration(rand.Int63n(int64(time.Second))) // nolint: gosec 131 backoff := 100 * time.Duration(count) * time.Millisecond 132 timer.Reset(jitter + backoff) 133 continue 134 } 135 136 return &coretypes.ResultBroadcastTxCommit{ 137 CheckTx: *r, 138 TxResult: txres.TxResult, 139 Hash: req.Tx.Hash(), 140 Height: txres.Height, 141 }, nil 142 } 143 } 144 } 145 } 146 147 // UnconfirmedTxs gets unconfirmed transactions from the mempool in order of priority 148 // More: https://docs.tendermint.com/master/rpc/#/Info/unconfirmed_txs 149 func (env *Environment) UnconfirmedTxs(ctx context.Context, req *coretypes.RequestUnconfirmedTxs) (*coretypes.ResultUnconfirmedTxs, error) { 150 totalCount := env.Mempool.Size() 151 perPage := env.validatePerPage(req.PerPage.IntPtr()) 152 page, err := validatePage(req.Page.IntPtr(), perPage, totalCount) 153 if err != nil { 154 return nil, err 155 } 156 157 skipCount := validateSkipCount(page, perPage) 158 159 txs := env.Mempool.ReapMaxTxs(skipCount + tmmath.MinInt(perPage, totalCount-skipCount)) 160 result := txs[skipCount:] 161 162 return &coretypes.ResultUnconfirmedTxs{ 163 Count: len(result), 164 Total: totalCount, 165 TotalBytes: env.Mempool.SizeBytes(), 166 Txs: result, 167 }, nil 168 } 169 170 // NumUnconfirmedTxs gets number of unconfirmed transactions. 171 // More: https://docs.tendermint.com/master/rpc/#/Info/num_unconfirmed_txs 172 func (env *Environment) NumUnconfirmedTxs(ctx context.Context) (*coretypes.ResultUnconfirmedTxs, error) { 173 return &coretypes.ResultUnconfirmedTxs{ 174 Count: env.Mempool.Size(), 175 Total: env.Mempool.Size(), 176 TotalBytes: env.Mempool.SizeBytes()}, nil 177 } 178 179 // CheckTx checks the transaction without executing it. The transaction won't 180 // be added to the mempool either. 181 // More: https://docs.tendermint.com/master/rpc/#/Tx/check_tx 182 func (env *Environment) CheckTx(ctx context.Context, req *coretypes.RequestCheckTx) (*coretypes.ResultCheckTx, error) { 183 res, err := env.ProxyApp.CheckTx(ctx, &abci.RequestCheckTx{Tx: req.Tx}) 184 if err != nil { 185 return nil, err 186 } 187 return &coretypes.ResultCheckTx{ResponseCheckTx: *res}, nil 188 } 189 190 func (env *Environment) RemoveTx(ctx context.Context, req *coretypes.RequestRemoveTx) error { 191 return env.Mempool.RemoveTxByKey(req.TxKey) 192 }