diff --git a/CHANGELOG.md b/CHANGELOG.md index 025ebb8dfe3a..d0e9ebaa256b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ * `x/crisis` * (crypto) [#24414](https://github.com/cosmos/cosmos-sdk/pull/24414) Remove sr25519 support, since it was removed in CometBFT v1.x (see: CometBFT [#3646](https://github.com/cometbft/cometbft/pull/3646)). +### API-BREAKING + +* (mempool) [#25338](https://github.com/cosmos/cosmos-sdk/pull/25338) Respect gas wanted returned by ante handler for mempool. + ### Features * [#24872](https://github.com/cosmos/cosmos-sdk/pull/24872) Support BLS 12-381 for cli `init`, `gentx`, `collect-gentx` diff --git a/baseapp/abci_utils.go b/baseapp/abci_utils.go index 9c53f0f6550b..7c6f4d2dbba8 100644 --- a/baseapp/abci_utils.go +++ b/baseapp/abci_utils.go @@ -201,7 +201,7 @@ type ( // to verify a transaction. ProposalTxVerifier interface { PrepareProposalVerifyTx(tx sdk.Tx) ([]byte, error) - ProcessProposalVerifyTx(txBz []byte) (sdk.Tx, error) + ProcessProposalVerifyTx(txBz []byte) (msg sdk.Tx, gasWanted uint64, err error) TxDecode(txBz []byte) (sdk.Tx, error) TxEncode(tx sdk.Tx) ([]byte, error) } @@ -276,7 +276,12 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan return nil, err } - stop := h.txSelector.SelectTxForProposal(ctx, uint64(req.MaxTxBytes), maxBlockGas, tx, txBz) + var txGasLimit uint64 + if gasTx, ok := tx.(sdk.GasTx); ok { + txGasLimit = gasTx.GetGas() + } + + stop := h.txSelector.SelectTxForProposal(ctx, uint64(req.MaxTxBytes), maxBlockGas, tx, txBz, txGasLimit) if stop { break } @@ -291,14 +296,14 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan selectedTxsNums int invalidTxs []sdk.Tx // invalid txs to be removed out of the loop to avoid dead lock ) - mempool.SelectBy(ctx, h.mempool, req.Txs, func(memTx sdk.Tx) bool { - unorderedTx, ok := memTx.(sdk.TxWithUnordered) + mempool.SelectBy(ctx, h.mempool, req.Txs, func(memTx mempool.Tx) bool { + unorderedTx, ok := memTx.Tx.(sdk.TxWithUnordered) isUnordered := ok && unorderedTx.GetUnordered() txSignersSeqs := make(map[string]uint64) // if the tx is unordered, we don't need to check the sequence, we just add it if !isUnordered { - signerData, err := h.signerExtAdapter.GetSigners(memTx) + signerData, err := h.signerExtAdapter.GetSigners(memTx.Tx) if err != nil { // propagate the error to the caller resError = err @@ -333,11 +338,11 @@ func (h *DefaultProposalHandler) PrepareProposalHandler() sdk.PrepareProposalHan // which calls mempool.Insert, in theory everything in the pool should be // valid. But some mempool implementations may insert invalid txs, so we // check again. - txBz, err := h.txVerifier.PrepareProposalVerifyTx(memTx) + txBz, err := h.txVerifier.PrepareProposalVerifyTx(memTx.Tx) if err != nil { - invalidTxs = append(invalidTxs, memTx) + invalidTxs = append(invalidTxs, memTx.Tx) } else { - stop := h.txSelector.SelectTxForProposal(ctx, uint64(req.MaxTxBytes), maxBlockGas, memTx, txBz) + stop := h.txSelector.SelectTxForProposal(ctx, uint64(req.MaxTxBytes), maxBlockGas, memTx.Tx, txBz, memTx.GasWanted) if stop { return false } @@ -409,17 +414,13 @@ func (h *DefaultProposalHandler) ProcessProposalHandler() sdk.ProcessProposalHan } for _, txBytes := range req.Txs { - tx, err := h.txVerifier.ProcessProposalVerifyTx(txBytes) + _, gasWanted, err := h.txVerifier.ProcessProposalVerifyTx(txBytes) if err != nil { return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, nil } if maxBlockGas > 0 { - gasTx, ok := tx.(GasTx) - if ok { - totalTxGas += gasTx.GetGas() - } - + totalTxGas += gasWanted if totalTxGas > uint64(maxBlockGas) { return &abci.ResponseProcessProposal{Status: abci.ResponseProcessProposal_REJECT}, nil } @@ -477,7 +478,7 @@ type TxSelector interface { // a proposal based on inclusion criteria defined by the TxSelector. It must // return if the caller should halt the transaction selection loop // (typically over a mempool) or otherwise. - SelectTxForProposal(ctx context.Context, maxTxBytes, maxBlockGas uint64, memTx sdk.Tx, txBz []byte) bool + SelectTxForProposal(ctx context.Context, maxTxBytes, maxBlockGas uint64, memTx sdk.Tx, txBz []byte, gasWanted uint64) bool } type defaultTxSelector struct { @@ -502,23 +503,16 @@ func (ts *defaultTxSelector) Clear() { ts.selectedTxs = nil } -func (ts *defaultTxSelector) SelectTxForProposal(_ context.Context, maxTxBytes, maxBlockGas uint64, memTx sdk.Tx, txBz []byte) bool { +func (ts *defaultTxSelector) SelectTxForProposal(_ context.Context, maxTxBytes, maxBlockGas uint64, memTx sdk.Tx, txBz []byte, gasWanted uint64) bool { txSize := uint64(cmttypes.ComputeProtoSizeForTxs([]cmttypes.Tx{txBz})) - var txGasLimit uint64 - if memTx != nil { - if gasTx, ok := memTx.(GasTx); ok { - txGasLimit = gasTx.GetGas() - } - } - // only add the transaction to the proposal if we have enough capacity if (txSize + ts.totalTxBytes) <= maxTxBytes { // If there is a max block gas limit, add the tx only if the limit has // not been met. if maxBlockGas > 0 { - if (txGasLimit + ts.totalTxGas) <= maxBlockGas { - ts.totalTxGas += txGasLimit + if (gasWanted + ts.totalTxGas) <= maxBlockGas { + ts.totalTxGas += gasWanted ts.totalTxBytes += txSize ts.selectedTxs = append(ts.selectedTxs, txBz) } diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 91ef3e1c8f9d..ec828e5c5a7d 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -873,7 +873,7 @@ func (app *BaseApp) runTx(mode sdk.ExecMode, txBytes []byte, tx sdk.Tx) (gInfo s switch mode { case execModeCheck: - err = app.mempool.Insert(ctx, tx) + err = app.mempool.InsertWithOption(ctx, tx, mempool.InsertOption{GasWanted: gasWanted}) if err != nil { return gInfo, nil, anteEvents, err } @@ -1067,18 +1067,18 @@ func (app *BaseApp) PrepareProposalVerifyTx(tx sdk.Tx) ([]byte, error) { // ProcessProposal state internally will be discarded. will be // returned if the transaction cannot be decoded. will be returned if // the transaction is valid, otherwise will be returned. -func (app *BaseApp) ProcessProposalVerifyTx(txBz []byte) (sdk.Tx, error) { +func (app *BaseApp) ProcessProposalVerifyTx(txBz []byte) (msg sdk.Tx, gasWanted uint64, err error) { tx, err := app.txDecoder(txBz) if err != nil { - return nil, err + return nil, 0, err } - _, _, _, err = app.runTx(execModeProcessProposal, txBz, tx) + gInfo, _, _, err := app.runTx(execModeProcessProposal, txBz, tx) if err != nil { - return nil, err + return nil, 0, err } - return tx, nil + return tx, gInfo.GasWanted, nil } func (app *BaseApp) TxDecode(txBytes []byte) (sdk.Tx, error) { diff --git a/baseapp/testutil/mock/mocks.go b/baseapp/testutil/mock/mocks.go index 51de61fa7156..1ac2102a0584 100644 --- a/baseapp/testutil/mock/mocks.go +++ b/baseapp/testutil/mock/mocks.go @@ -135,12 +135,13 @@ func (mr *MockProposalTxVerifierMockRecorder) PrepareProposalVerifyTx(tx any) *g } // ProcessProposalVerifyTx mocks base method. -func (m *MockProposalTxVerifier) ProcessProposalVerifyTx(txBz []byte) (types.Tx, error) { +func (m *MockProposalTxVerifier) ProcessProposalVerifyTx(txBz []byte) (types.Tx, uint64, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ProcessProposalVerifyTx", txBz) ret0, _ := ret[0].(types.Tx) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret1, _ := ret[1].(uint64) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 } // ProcessProposalVerifyTx indicates an expected call of ProcessProposalVerifyTx. @@ -216,17 +217,17 @@ func (mr *MockTxSelectorMockRecorder) Clear() *gomock.Call { } // SelectTxForProposal mocks base method. -func (m *MockTxSelector) SelectTxForProposal(ctx context.Context, maxTxBytes, maxBlockGas uint64, memTx types.Tx, txBz []byte) bool { +func (m *MockTxSelector) SelectTxForProposal(ctx context.Context, maxTxBytes, maxBlockGas uint64, memTx types.Tx, txBz []byte, gasWanted uint64) bool { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "SelectTxForProposal", ctx, maxTxBytes, maxBlockGas, memTx, txBz) + ret := m.ctrl.Call(m, "SelectTxForProposal", ctx, maxTxBytes, maxBlockGas, memTx, txBz, gasWanted) ret0, _ := ret[0].(bool) return ret0 } // SelectTxForProposal indicates an expected call of SelectTxForProposal. -func (mr *MockTxSelectorMockRecorder) SelectTxForProposal(ctx, maxTxBytes, maxBlockGas, memTx, txBz any) *gomock.Call { +func (mr *MockTxSelectorMockRecorder) SelectTxForProposal(ctx, maxTxBytes, maxBlockGas, memTx, txBz, gasWanted any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectTxForProposal", reflect.TypeOf((*MockTxSelector)(nil).SelectTxForProposal), ctx, maxTxBytes, maxBlockGas, memTx, txBz) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectTxForProposal", reflect.TypeOf((*MockTxSelector)(nil).SelectTxForProposal), ctx, maxTxBytes, maxBlockGas, memTx, txBz, gasWanted) } // SelectedTxs mocks base method. diff --git a/types/mempool/mempool.go b/types/mempool/mempool.go index 291e0f981f93..6a3e1ba975a7 100644 --- a/types/mempool/mempool.go +++ b/types/mempool/mempool.go @@ -7,11 +7,30 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) +type Tx struct { + Tx sdk.Tx + GasWanted uint64 +} + +func NewMempoolTx(tx sdk.Tx, gasWanted uint64) Tx { + return Tx{ + Tx: tx, + GasWanted: gasWanted, + } +} + +type InsertOption struct { + GasWanted uint64 +} + type Mempool interface { // Insert attempts to insert a Tx into the app-side mempool returning // an error upon failure. Insert(context.Context, sdk.Tx) error + // InsertWithOption with a custom option, e.g. gas wanted. + InsertWithOption(context.Context, sdk.Tx, InsertOption) error + // Select returns an Iterator over the app-side mempool. If txs are specified, // then they shall be incorporated into the Iterator. The Iterator is not thread-safe to use. Select(context.Context, [][]byte) Iterator @@ -31,7 +50,7 @@ type ExtMempool interface { Mempool // SelectBy use callback to iterate over the mempool, it's thread-safe to use. - SelectBy(context.Context, [][]byte, func(sdk.Tx) bool) + SelectBy(context.Context, [][]byte, func(Tx) bool) } // Iterator defines an app-side mempool iterator interface that is as minimal as @@ -43,7 +62,7 @@ type Iterator interface { Next() Iterator // Tx returns the transaction at the current position of the iterator. - Tx() sdk.Tx + Tx() Tx } var ( @@ -53,7 +72,7 @@ var ( // SelectBy is compatible with old interface to avoid breaking api. // In v0.52+, this function is removed and SelectBy is merged into Mempool interface. -func SelectBy(ctx context.Context, mempool Mempool, txs [][]byte, callback func(sdk.Tx) bool) { +func SelectBy(ctx context.Context, mempool Mempool, txs [][]byte, callback func(Tx) bool) { if ext, ok := mempool.(ExtMempool); ok { ext.SelectBy(ctx, txs, callback) return diff --git a/types/mempool/mempool_test.go b/types/mempool/mempool_test.go index d84baaebaa68..be18cf329d4e 100644 --- a/types/mempool/mempool_test.go +++ b/types/mempool/mempool_test.go @@ -139,7 +139,7 @@ func fetchTxs(iterator mempool.Iterator, maxBytes int64) []sdk.Tx { if numBytes += txSize; numBytes > maxBytes { break } - txs = append(txs, iterator.Tx()) + txs = append(txs, iterator.Tx().Tx) i := iterator.Next() iterator = i } diff --git a/types/mempool/noop.go b/types/mempool/noop.go index 2dd806b8598e..ff7f100c9210 100644 --- a/types/mempool/noop.go +++ b/types/mempool/noop.go @@ -16,8 +16,9 @@ var _ ExtMempool = (*NoOpMempool)(nil) // is FIFO-ordered by default. type NoOpMempool struct{} -func (NoOpMempool) Insert(context.Context, sdk.Tx) error { return nil } -func (NoOpMempool) Select(context.Context, [][]byte) Iterator { return nil } -func (NoOpMempool) SelectBy(context.Context, [][]byte, func(sdk.Tx) bool) {} -func (NoOpMempool) CountTx() int { return 0 } -func (NoOpMempool) Remove(sdk.Tx) error { return nil } +func (NoOpMempool) Insert(context.Context, sdk.Tx) error { return nil } +func (NoOpMempool) InsertWithOption(context.Context, sdk.Tx, InsertOption) error { return nil } +func (NoOpMempool) Select(context.Context, [][]byte) Iterator { return nil } +func (NoOpMempool) SelectBy(context.Context, [][]byte, func(Tx) bool) {} +func (NoOpMempool) CountTx() int { return 0 } +func (NoOpMempool) Remove(sdk.Tx) error { return nil } diff --git a/types/mempool/priority_nonce.go b/types/mempool/priority_nonce.go index 6fcc6a22290e..4deb69156e57 100644 --- a/types/mempool/priority_nonce.go +++ b/types/mempool/priority_nonce.go @@ -189,10 +189,10 @@ func (mp *PriorityNonceMempool[C]) NextSenderTx(sender string) sdk.Tx { } cursor := senderIndex.Front() - return cursor.Value.(sdk.Tx) + return cursor.Value.(Tx).Tx } -// Insert attempts to insert a Tx into the app-side mempool in O(log n) time, +// InsertWithOption attempts to insert a Tx into the app-side mempool in O(log n) time, // returning an error if unsuccessful. Sender and nonce are derived from the // transaction's first signature. // @@ -201,7 +201,7 @@ func (mp *PriorityNonceMempool[C]) NextSenderTx(sender string) sdk.Tx { // // Inserting a duplicate tx with a different priority overwrites the existing tx, // changing the total order of the mempool. -func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error { +func (mp *PriorityNonceMempool[C]) InsertWithOption(ctx context.Context, tx sdk.Tx, option InsertOption) error { mp.mtx.Lock() defer mp.mtx.Unlock() if mp.cfg.MaxTx > 0 && mp.priorityIndex.Len() >= mp.cfg.MaxTx { @@ -209,6 +209,7 @@ func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error } else if mp.cfg.MaxTx < 0 { return nil } + memTx := NewMempoolTx(tx, option.GasWanted) sigs, err := mp.cfg.SignerExtractor.GetSigners(tx) if err != nil { @@ -247,12 +248,12 @@ func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error // changes. sk := txMeta[C]{nonce: nonce, sender: sender} if oldScore, txExists := mp.scores[sk]; txExists { - if mp.cfg.TxReplacement != nil && !mp.cfg.TxReplacement(oldScore.priority, priority, senderIndex.Get(key).Value.(sdk.Tx), tx) { + if mp.cfg.TxReplacement != nil && !mp.cfg.TxReplacement(oldScore.priority, priority, senderIndex.Get(key).Value.(Tx).Tx, tx) { return fmt.Errorf( "tx doesn't fit the replacement rule, oldPriority: %v, newPriority: %v, oldTx: %v, newTx: %v", oldScore.priority, priority, - senderIndex.Get(key).Value.(sdk.Tx), + senderIndex.Get(key).Value.(Tx).Tx, tx, ) } @@ -270,7 +271,7 @@ func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error // Since senderIndex is scored by nonce, a changed priority will overwrite the // existing key. - key.senderElement = senderIndex.Set(key, tx) + key.senderElement = senderIndex.Set(key, memTx) mp.scores[sk] = txMeta[C]{priority: priority} mp.priorityIndex.Set(key, tx) @@ -278,6 +279,15 @@ func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error return nil } +func (mp *PriorityNonceMempool[C]) Insert(ctx context.Context, tx sdk.Tx) error { + var gasLimit uint64 + if gasTx, ok := tx.(sdk.GasTx); ok { + gasLimit = gasTx.GetGas() + } + + return mp.InsertWithOption(ctx, tx, InsertOption{GasWanted: gasLimit}) +} + func (i *PriorityNonceIterator[C]) iteratePriority() Iterator { // beginning of priority iteration if i.priorityNode == nil { @@ -341,8 +351,8 @@ func (i *PriorityNonceIterator[C]) Next() Iterator { return i } -func (i *PriorityNonceIterator[C]) Tx() sdk.Tx { - return i.senderCursors[i.sender].Value.(sdk.Tx) +func (i *PriorityNonceIterator[C]) Tx() Tx { + return i.senderCursors[i.sender].Value.(Tx) } // Select returns a set of transactions from the mempool, ordered by priority @@ -376,7 +386,7 @@ func (mp *PriorityNonceMempool[C]) doSelect(_ context.Context, _ [][]byte) Itera } // SelectBy will hold the mutex during the iteration, callback returns if continue. -func (mp *PriorityNonceMempool[C]) SelectBy(ctx context.Context, txs [][]byte, callback func(sdk.Tx) bool) { +func (mp *PriorityNonceMempool[C]) SelectBy(ctx context.Context, txs [][]byte, callback func(Tx) bool) { mp.mtx.Lock() defer mp.mtx.Unlock() diff --git a/types/mempool/priority_nonce_test.go b/types/mempool/priority_nonce_test.go index fc515e99cfa5..eb5a0311ea09 100644 --- a/types/mempool/priority_nonce_test.go +++ b/types/mempool/priority_nonce_test.go @@ -388,7 +388,7 @@ func (s *MempoolTestSuite) TestIterator() { // iterate through txs iterator := pool.Select(ctx, nil) for iterator != nil { - tx := iterator.Tx().(testTx) + tx := iterator.Tx().Tx.(testTx) require.Equal(t, tt.txs[tx.id].p, int(tx.priority)) require.Equal(t, tt.txs[tx.id].n, int(tx.nonce)) require.Equal(t, tt.txs[tx.id].a, tx.address) @@ -464,8 +464,8 @@ func (s *MempoolTestSuite) TestIteratorConcurrency() { }() var i int - pool.SelectBy(ctx, nil, func(memTx sdk.Tx) bool { - tx := memTx.(testTx) + pool.SelectBy(ctx, nil, func(memTx mempool.Tx) bool { + tx := memTx.Tx.(testTx) if tx.id < len(tt.txs) { require.Equal(t, tt.txs[tx.id].p, int(tx.priority)) require.Equal(t, tt.txs[tx.id].n, int(tx.nonce)) @@ -935,7 +935,7 @@ func TestNextSenderTx_TxReplacement(t *testing.T) { require.Equal(t, 1, mp.CountTx()) iter := mp.Select(ctx, nil) - require.Equal(t, tx, iter.Tx()) + require.Equal(t, tx, iter.Tx().Tx) } // test Priority with TxReplacement @@ -970,7 +970,7 @@ func TestNextSenderTx_TxReplacement(t *testing.T) { require.Equal(t, 1, mp.CountTx()) iter := mp.Select(ctx, nil) - require.Equal(t, txs[3], iter.Tx()) + require.Equal(t, txs[3], iter.Tx().Tx) } func TestPriorityNonceMempool_UnorderedTx_FailsForSequence(t *testing.T) { diff --git a/types/mempool/sender_nonce.go b/types/mempool/sender_nonce.go index b56f698dd142..33efba0a0d16 100644 --- a/types/mempool/sender_nonce.go +++ b/types/mempool/sender_nonce.go @@ -113,12 +113,12 @@ func (snm *SenderNonceMempool) NextSenderTx(sender string) sdk.Tx { } cursor := senderIndex.Front() - return cursor.Value.(sdk.Tx) + return cursor.Value.(Tx).Tx } -// Insert adds a tx to the mempool. It returns an error if the tx does not have +// InsertWithOption adds a tx to the mempool. It returns an error if the tx does not have // at least one signer. Note, priority is ignored. -func (snm *SenderNonceMempool) Insert(_ context.Context, tx sdk.Tx) error { +func (snm *SenderNonceMempool) InsertWithOption(_ context.Context, tx sdk.Tx, option InsertOption) error { snm.mtx.Lock() defer snm.mtx.Unlock() if snm.maxTx > 0 && len(snm.existingTx) >= snm.maxTx { @@ -128,6 +128,8 @@ func (snm *SenderNonceMempool) Insert(_ context.Context, tx sdk.Tx) error { return nil } + memTx := NewMempoolTx(tx, option.GasWanted) + sigs, err := tx.(signing.SigVerifiableTx).GetSignaturesV2() if err != nil { return err @@ -149,7 +151,7 @@ func (snm *SenderNonceMempool) Insert(_ context.Context, tx sdk.Tx) error { snm.senders[sender] = senderTxs } - senderTxs.Set(nonce, tx) + senderTxs.Set(nonce, memTx) key := txKey{nonce: nonce, address: sender} snm.existingTx[key] = true @@ -157,6 +159,15 @@ func (snm *SenderNonceMempool) Insert(_ context.Context, tx sdk.Tx) error { return nil } +func (snm *SenderNonceMempool) Insert(ctx context.Context, tx sdk.Tx) error { + var gasLimit uint64 + if gasTx, ok := tx.(sdk.GasTx); ok { + gasLimit = gasTx.GetGas() + } + + return snm.InsertWithOption(ctx, tx, InsertOption{GasWanted: gasLimit}) +} + // Select returns an iterator ordering transactions in the mempool with the lowest // nonce of a randomly selected sender first. // @@ -197,7 +208,7 @@ func (snm *SenderNonceMempool) doSelect(_ context.Context, _ [][]byte) Iterator } // SelectBy will hold the mutex during the iteration, callback returns if continue. -func (snm *SenderNonceMempool) SelectBy(ctx context.Context, txs [][]byte, callback func(sdk.Tx) bool) { +func (snm *SenderNonceMempool) SelectBy(ctx context.Context, txs [][]byte, callback func(Tx) bool) { snm.mtx.Lock() defer snm.mtx.Unlock() @@ -290,8 +301,8 @@ func (i *senderNonceMempoolIterator) Next() Iterator { return nil } -func (i *senderNonceMempoolIterator) Tx() sdk.Tx { - return i.currentTx.Value.(sdk.Tx) +func (i *senderNonceMempoolIterator) Tx() Tx { + return i.currentTx.Value.(Tx) } func removeAtIndex[T any](slice []T, index int) []T { diff --git a/types/mempool/sender_nonce_property_test.go b/types/mempool/sender_nonce_property_test.go index 58994d48e1f1..892ca5bb312a 100644 --- a/types/mempool/sender_nonce_property_test.go +++ b/types/mempool/sender_nonce_property_test.go @@ -96,7 +96,7 @@ func fetchAllTxs(iterator mempool.Iterator) []testTx { var txs []testTx for iterator != nil { tx := iterator.Tx() - txs = append(txs, tx.(testTx)) + txs = append(txs, tx.Tx.(testTx)) i := iterator.Next() iterator = i } diff --git a/types/tx_msg.go b/types/tx_msg.go index c32c23b1bfb2..94b30e60bd7e 100644 --- a/types/tx_msg.go +++ b/types/tx_msg.go @@ -106,6 +106,11 @@ type ( // doesn't require access to any other information. ValidateBasic() error } + + // GasTx defines an interface for a transaction that contains gas wanted for mempool + GasTx interface { + GetGas() uint64 + } ) // TxDecoder unmarshals transaction bytes