diff --git a/CHANGELOG.md b/CHANGELOG.md index e432b45b7..315d4f9ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ - [\#467](https://github.com/cosmos/evm/pull/467) Replace GlobalEVMMempool by passing to JSONRPC on initiate. - [\#352](https://github.com/cosmos/evm/pull/352) Remove the creation of a Geth EVM instance, stateDB during the AnteHandler balance check. - [\#496](https://github.com/cosmos/evm/pull/496) Simplify mempool instantiation by using configs instead of objects. +- [\#512](https://github.com/cosmos/evm/pull/512) Add integration test for appside mempool. - [\#568](https://github.com/cosmos/evm/pull/568) Avoid unnecessary block notifications when the event bus is already set up. - [\#511](https://github.com/cosmos/evm/pull/511) Minor code cleanup for `AddPrecompileFn`. - [\#544](https://github.com/cosmos/evm/pull/544) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events. diff --git a/evmd/tests/integration/mempool/mempool_test.go b/evmd/tests/integration/mempool/mempool_test.go index 3714c9afc..8c3830dba 100644 --- a/evmd/tests/integration/mempool/mempool_test.go +++ b/evmd/tests/integration/mempool/mempool_test.go @@ -1,9 +1,10 @@ package mempool import ( - "github.com/cosmos/evm/evmd/tests/integration" "testing" + "github.com/cosmos/evm/evmd/tests/integration" + "github.com/stretchr/testify/suite" "github.com/cosmos/evm/tests/integration/mempool" diff --git a/tests/integration/mempool/test_helpers.go b/tests/integration/mempool/test_helpers.go new file mode 100644 index 000000000..69246265a --- /dev/null +++ b/tests/integration/mempool/test_helpers.go @@ -0,0 +1,152 @@ +package mempool + +import ( + "encoding/hex" + "fmt" + "math/big" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/tmhash" + + "github.com/cosmos/evm/testutil/integration/base/factory" + "github.com/cosmos/evm/testutil/keyring" + evmtypes "github.com/cosmos/evm/x/vm/types" + + sdkmath "cosmossdk.io/math" + + sdk "github.com/cosmos/cosmos-sdk/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +// Constants +const ( + TxGas = 100_000 +) + +// createCosmosSendTransactionWithKey creates a simple bank send transaction with the specified key +func (s *IntegrationTestSuite) createCosmosSendTx(key keyring.Key, gasPrice *big.Int) sdk.Tx { + feeDenom := "aatom" + + fromAddr := key.AccAddr + toAddr := s.keyring.GetKey(1).AccAddr + amount := sdk.NewCoins(sdk.NewInt64Coin(feeDenom, 1000)) + + bankMsg := banktypes.NewMsgSend(fromAddr, toAddr, amount) + + gasPriceConverted := sdkmath.NewIntFromBigInt(gasPrice) + + txArgs := factory.CosmosTxArgs{ + Msgs: []sdk.Msg{bankMsg}, + GasPrice: &gasPriceConverted, + } + tx, err := s.factory.BuildCosmosTx(key.Priv, txArgs) + s.Require().NoError(err) + + return tx +} + +// createEVMTransaction creates an EVM transaction using the provided key +func (s *IntegrationTestSuite) createEVMValueTransferTx(key keyring.Key, nonce int, gasPrice *big.Int) sdk.Tx { + to := s.keyring.GetKey(1).Addr + + if nonce < 0 { + s.Require().NoError(fmt.Errorf("nonce must be non-negative")) + } + + ethTxArgs := evmtypes.EvmTxArgs{ + Nonce: uint64(nonce), + To: &to, + Amount: big.NewInt(1000), + GasLimit: TxGas, + GasPrice: gasPrice, + Input: nil, + } + tx, err := s.factory.GenerateSignedEthTx(key.Priv, ethTxArgs) + s.Require().NoError(err) + + return tx +} + +// createEVMContractDeployTx creates an EVM transaction for contract deployment +func (s *IntegrationTestSuite) createEVMContractDeployTx(key keyring.Key, gasPrice *big.Int, data []byte) sdk.Tx { + ethTxArgs := evmtypes.EvmTxArgs{ + Nonce: 0, + To: nil, + Amount: nil, + GasLimit: TxGas, + GasPrice: gasPrice, + Input: data, + } + tx, err := s.factory.GenerateSignedEthTx(key.Priv, ethTxArgs) + s.Require().NoError(err) + + return tx +} + +// checkTxs call abci CheckTx for multipile transactions +func (s *IntegrationTestSuite) checkTxs(txs []sdk.Tx) error { + for _, tx := range txs { + if err := s.checkTx(tx); err != nil { + return err + } + } + return nil +} + +// checkTxs call abci CheckTx for a transaction +func (s *IntegrationTestSuite) checkTx(tx sdk.Tx) error { + txBytes, err := s.network.App.GetTxConfig().TxEncoder()(tx) + if err != nil { + return fmt.Errorf("failed to encode cosmos tx: %w", err) + } + + _, err = s.network.App.CheckTx(&abci.RequestCheckTx{ + Tx: txBytes, + Type: abci.CheckTxType_New, + }) + if err != nil { + return fmt.Errorf("failed to encode cosmos tx: %w", err) + } + + return nil +} + +// getTxHashes returns transaction hashes for multiple transactions +func (s *IntegrationTestSuite) getTxHashes(txs []sdk.Tx) []string { + txHashes := []string{} + for _, tx := range txs { + txHash := s.getTxHash(tx) + txHashes = append(txHashes, txHash) + } + + return txHashes +} + +// getTxHash returns transaction hash for a transaction +func (s *IntegrationTestSuite) getTxHash(tx sdk.Tx) string { + txEncoder := s.network.App.GetTxConfig().TxEncoder() + txBytes, err := txEncoder(tx) + s.Require().NoError(err) + + return hex.EncodeToString(tmhash.Sum(txBytes)) +} + +// calculateCosmosGasPrice calculates the gas price for a Cosmos transaction +func (s *IntegrationTestSuite) calculateCosmosGasPrice(feeAmount int64, gasLimit uint64) *big.Int { + return new(big.Int).Div(big.NewInt(feeAmount), big.NewInt(int64(gasLimit))) //#nosec G115 -- not concern, test +} + +// calculateCosmosEffectiveTip calculates the effective tip for a Cosmos transaction +// This aligns with EVM transaction prioritization: effective_tip = gas_price - base_fee +func (s *IntegrationTestSuite) calculateCosmosEffectiveTip(feeAmount int64, gasLimit uint64, baseFee *big.Int) *big.Int { + gasPrice := s.calculateCosmosGasPrice(feeAmount, gasLimit) + if baseFee == nil || baseFee.Sign() == 0 { + return gasPrice // No base fee, effective tip equals gas price + } + + if gasPrice.Cmp(baseFee) < 0 { + return big.NewInt(0) // Gas price lower than base fee, effective tip is zero + } + + return new(big.Int).Sub(gasPrice, baseFee) +} diff --git a/tests/integration/mempool/test_mempool_integration.go b/tests/integration/mempool/test_mempool_integration.go index f14671d0c..32e24a4a1 100644 --- a/tests/integration/mempool/test_mempool_integration.go +++ b/tests/integration/mempool/test_mempool_integration.go @@ -1,7 +1,6 @@ package mempool import ( - "fmt" "math/big" "github.com/ethereum/go-ethereum/common" @@ -9,25 +8,16 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/stretchr/testify/require" - "github.com/cosmos/evm/crypto/ethsecp256k1" "github.com/cosmos/evm/testutil/integration/evm/network" "github.com/cosmos/evm/testutil/keyring" evmtypes "github.com/cosmos/evm/x/vm/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/mempool" - "github.com/cosmos/cosmos-sdk/types/tx/signing" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" -) - -// Constants -const ( - TxGas = 21000 ) // TestMempoolInsert tests transaction insertion into the mempool func (s *IntegrationTestSuite) TestMempoolInsert() { - fmt.Printf("DEBUG: Starting TestMempoolInsert\n") testCases := []struct { name string setupTx func() sdk.Tx @@ -38,7 +28,7 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { { name: "cosmos transaction success", setupTx: func() sdk.Tx { - return s.createCosmosSendTransaction(big.NewInt(1000)) + return s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) }, wantError: false, verifyFunc: func() { @@ -49,9 +39,7 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { { name: "EVM transaction success", setupTx: func() sdk.Tx { - tx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) - return tx + return s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) }, wantError: false, verifyFunc: func() { @@ -65,10 +53,7 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { key := s.keyring.GetKey(0) data := []byte{0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0xf3} // Simple contract deployment - // Use the contract deployment helper - tx, err := s.createEVMContractDeployment(key, big.NewInt(1000000000), data) - s.Require().NoError(err) - return tx + return s.createEVMContractDeployTx(key, big.NewInt(1000000000), data) }, wantError: false, verifyFunc: func() { @@ -147,13 +132,10 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { }, } - for i, tc := range testCases { - fmt.Printf("DEBUG: TestMempoolInsert - Starting test case %d/%d: %s\n", i+1, len(testCases), tc.name) + for _, tc := range testCases { s.Run(tc.name, func() { - fmt.Printf("DEBUG: Running test case: %s\n", tc.name) // Reset test setup to ensure clean state s.SetupTest() - fmt.Printf("DEBUG: SetupTest completed for: %s\n", tc.name) tx := tc.setupTx() mpool := s.network.App.GetMempool() @@ -170,15 +152,12 @@ func (s *IntegrationTestSuite) TestMempoolInsert() { } tc.verifyFunc() - fmt.Printf("DEBUG: Completed test case: %s\n", tc.name) }) - fmt.Printf("DEBUG: TestMempoolInsert - Completed test case %d/%d: %s\n", i+1, len(testCases), tc.name) } } // TestMempoolRemove tests transaction removal from the mempool func (s *IntegrationTestSuite) TestMempoolRemove() { - fmt.Printf("DEBUG: Starting TestMempoolRemove\n") testCases := []struct { name string setupTx func() sdk.Tx @@ -190,7 +169,7 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { { name: "remove cosmos transaction success", setupTx: func() sdk.Tx { - return s.createCosmosSendTransaction(big.NewInt(1000)) + return s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) }, insertFirst: true, wantError: false, @@ -200,17 +179,16 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { }, }, { - name: "remove EVM transaction success", + name: "remove EVM transaction fail", setupTx: func() sdk.Tx { - tx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) - return tx + return s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) }, insertFirst: true, wantError: false, verifyFunc: func() { mpool := s.network.App.GetMempool() - s.Require().Equal(0, mpool.CountTx()) + // mempool.Remove can only remove invalid evm transaction + s.Require().Equal(1, mpool.CountTx()) }, }, { @@ -228,7 +206,7 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { { name: "remove non-existent transaction", setupTx: func() sdk.Tx { - return s.createCosmosSendTransaction(big.NewInt(1000)) + return s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) }, insertFirst: false, wantError: true, // Remove should error for non-existent transactions @@ -242,10 +220,8 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { for _, tc := range testCases { s.Run(tc.name, func() { - fmt.Printf("DEBUG: Running test case: %s\n", tc.name) // Reset test setup to ensure clean state s.SetupTest() - fmt.Printf("DEBUG: SetupTest completed for: %s\n", tc.name) tx := tc.setupTx() mpool := s.network.App.GetMempool() @@ -268,14 +244,12 @@ func (s *IntegrationTestSuite) TestMempoolRemove() { } tc.verifyFunc() - fmt.Printf("DEBUG: Completed test case: %s\n", tc.name) }) } } // TestMempoolSelect tests transaction selection from the mempool func (s *IntegrationTestSuite) TestMempoolSelect() { - fmt.Printf("DEBUG: Starting TestMempoolSelect\n") testCases := []struct { name string setupTxs func() @@ -292,7 +266,7 @@ func (s *IntegrationTestSuite) TestMempoolSelect() { { name: "single cosmos transaction", setupTxs: func() { - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000)) + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000)) mpool := s.network.App.GetMempool() err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) @@ -306,10 +280,10 @@ func (s *IntegrationTestSuite) TestMempoolSelect() { { name: "single EVM transaction", setupTxs: func() { - evmTx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) + mpool := s.network.App.GetMempool() - err = mpool.Insert(s.network.GetContext(), evmTx) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) }, verifyFunc: func(iterator mempool.Iterator) { @@ -344,7 +318,6 @@ func (s *IntegrationTestSuite) TestMempoolSelect() { // TestMempoolIterator tests iterator functionality func (s *IntegrationTestSuite) TestMempoolIterator() { - fmt.Printf("DEBUG: Starting TestMempoolIterator\n") testCases := []struct { name string setupTxs func() @@ -361,7 +334,7 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { { name: "single cosmos transaction iteration", setupTxs: func() { - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000)) + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000)) mpool := s.network.App.GetMempool() err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) @@ -374,10 +347,9 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { { name: "single EVM transaction iteration", setupTxs: func() { - evmTx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) mpool := s.network.App.GetMempool() - err = mpool.Insert(s.network.GetContext(), evmTx) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) }, verifyFunc: func(iterator mempool.Iterator) { @@ -398,11 +370,11 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { setupTxs: func() { mpool := s.network.App.GetMempool() - cosmosTx1 := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(0), big.NewInt(1000)) + cosmosTx1 := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) err := mpool.Insert(s.network.GetContext(), cosmosTx1) s.Require().NoError(err) - cosmosTx2 := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(1), big.NewInt(2000)) + cosmosTx2 := s.createCosmosSendTx(s.keyring.GetKey(1), big.NewInt(2000)) err = mpool.Insert(s.network.GetContext(), cosmosTx2) s.Require().NoError(err) }, @@ -423,13 +395,13 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { mpool := s.network.App.GetMempool() // Add EVM transaction - evmTx, err := s.createEVMTransaction(big.NewInt(2000)) - s.Require().NoError(err) - err = mpool.Insert(s.network.GetContext(), evmTx) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(2000)) + + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) // Add Cosmos transaction - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000)) + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000)) err = mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) }, @@ -461,7 +433,6 @@ func (s *IntegrationTestSuite) TestMempoolIterator() { // TestTransactionOrdering tests transaction ordering based on fees func (s *IntegrationTestSuite) TestTransactionOrdering() { - fmt.Printf("DEBUG: Starting TestTransactionOrdering\n") testCases := []struct { name string setupTxs func() @@ -471,18 +442,17 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { name: "mixed EVM and cosmos transaction ordering", setupTxs: func() { // Create EVM transaction with high gas price - highGasPriceEVMTx, err := s.createEVMTransaction(big.NewInt(5000000000)) - s.Require().NoError(err) + highGasPriceEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // Create Cosmos transactions with different fee amounts - highFeeCosmosTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(6), big.NewInt(5000000000)) - mediumFeeCosmosTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(7), big.NewInt(3000000000)) - lowFeeCosmosTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(8), big.NewInt(1000000000)) + highFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(6), big.NewInt(5000000000)) + mediumFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(7), big.NewInt(3000000000)) + lowFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(8), big.NewInt(1000000000)) mpool := s.network.App.GetMempool() // Insert in non-priority order - err = mpool.Insert(s.network.GetContext(), lowFeeCosmosTx) + err := mpool.Insert(s.network.GetContext(), lowFeeCosmosTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), highGasPriceEVMTx) s.Require().NoError(err) @@ -517,17 +487,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { name: "EVM-only transaction replacement", setupTxs: func() { // Create first EVM transaction with low fee - lowFeeEVMTx, err := s.createEVMTransaction(big.NewInt(1000000000)) // 1 gaatom - s.Require().NoError(err) + lowFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) // 1 gaatom // Create second EVM transaction with high fee - highFeeEVMTx, err := s.createEVMTransaction(big.NewInt(5000000000)) // 5 gaatom - s.Require().NoError(err) + highFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom mpool := s.network.App.GetMempool() // Insert low fee transaction first - err = mpool.Insert(s.network.GetContext(), lowFeeEVMTx) + err := mpool.Insert(s.network.GetContext(), lowFeeEVMTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), highFeeEVMTx) s.Require().NoError(err) @@ -549,17 +517,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { setupTxs: func() { key := s.keyring.GetKey(0) // Create first EVM transaction with low fee - lowFeeEVMTx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) // 1 gaatom - s.Require().NoError(err) + lowFeeEVMTx := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) // 1 gaatom // Create second EVM transaction with high fee - highFeeEVMTx, err := s.createEVMTransactionWithNonce(key, big.NewInt(5000000000), 0) // 5 gaatom - s.Require().NoError(err) + highFeeEVMTx := s.createEVMValueTransferTx(key, 0, big.NewInt(5000000000)) // 5 gaatom mpool := s.network.App.GetMempool() // Insert low fee transaction first - err = mpool.Insert(s.network.GetContext(), lowFeeEVMTx) + err := mpool.Insert(s.network.GetContext(), lowFeeEVMTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), highFeeEVMTx) s.Require().NoError(err) @@ -587,9 +553,9 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { { name: "cosmos-only transaction replacement", setupTxs: func() { - highFeeTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5 gaatom - lowFeeTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(0), big.NewInt(1000000000)) // 1 gaatom - mediumFeeTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(0), big.NewInt(3000000000)) // 3 gaatom + highFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5 gaatom + lowFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000000000)) // 1 gaatom + mediumFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(3000000000)) // 3 gaatom mpool := s.network.App.GetMempool() @@ -619,16 +585,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { setupTxs: func() { // Create transactions with equal effective tips (assuming base fee = 0) // EVM: 1000 aatom/gas effective tip - evmTx, err := s.createEVMTransaction(big.NewInt(1000000000)) // 1 gaatom/gas - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) // 1 gaatom/gas // Cosmos with same effective tip: 1000 * 200000 = 200000000 aatom total fee - cosmosTx := s.createCosmosSendTransaction(big.NewInt(1000000000)) // 1 gaatom/gas effective tip + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000000000)) // 1 gaatom/gas effective tip mpool := s.network.App.GetMempool() // Insert Cosmos first, then EVM - err = mpool.Insert(s.network.GetContext(), cosmosTx) + err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) @@ -662,16 +627,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { name: "mixed transactions with EVM having higher effective tip", setupTxs: func() { // Create EVM transaction with higher gas price - evmTx, err := s.createEVMTransaction(big.NewInt(5000000000)) // 5 gaatom/gas - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom/gas // Create Cosmos transaction with lower gas price - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000000000)) // 2 gaatom/gas + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000000000)) // 2 gaatom/gas mpool := s.network.App.GetMempool() // Insert Cosmos first, then EVM - err = mpool.Insert(s.network.GetContext(), cosmosTx) + err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) @@ -702,16 +666,15 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { name: "mixed transactions with Cosmos having higher effective tip", setupTxs: func() { // Create EVM transaction with lower gas price - evmTx, err := s.createEVMTransaction(big.NewInt(2000000000)) // 2000 aatom/gas - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(2000000000)) // 2000 aatom/gas // Create Cosmos transaction with higher gas price - cosmosTx := s.createCosmosSendTransaction(big.NewInt(5000000000)) // 5000 aatom/gas + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5000 aatom/gas mpool := s.network.App.GetMempool() // Insert EVM first, then Cosmos - err = mpool.Insert(s.network.GetContext(), evmTx) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) @@ -745,21 +708,18 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { // EVM: 8000, 4000, 2000 aatom/gas // Cosmos: 6000, 3000, 1000 aatom/gas - evmHigh, err := s.createEVMTransaction(big.NewInt(8000000000)) - s.Require().NoError(err) - evmMedium, err := s.createEVMTransactionWithKey(s.keyring.GetKey(1), big.NewInt(4000000000)) - s.Require().NoError(err) - evmLow, err := s.createEVMTransactionWithKey(s.keyring.GetKey(2), big.NewInt(2000000000)) - s.Require().NoError(err) + evmHigh := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(8000000000)) + evmMedium := s.createEVMValueTransferTx(s.keyring.GetKey(1), 0, big.NewInt(4000000000)) + evmLow := s.createEVMValueTransferTx(s.keyring.GetKey(2), 0, big.NewInt(2000000000)) - cosmosHigh := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(3), big.NewInt(6000000000)) - cosmosMedium := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(4), big.NewInt(3000000000)) - cosmosLow := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(5), big.NewInt(1000000000)) + cosmosHigh := s.createCosmosSendTx(s.keyring.GetKey(3), big.NewInt(6000000000)) + cosmosMedium := s.createCosmosSendTx(s.keyring.GetKey(4), big.NewInt(3000000000)) + cosmosLow := s.createCosmosSendTx(s.keyring.GetKey(5), big.NewInt(1000000000)) mpool := s.network.App.GetMempool() // Insert in random order - err = mpool.Insert(s.network.GetContext(), cosmosLow) + err := mpool.Insert(s.network.GetContext(), cosmosLow) s.Require().NoError(err) err = mpool.Insert(s.network.GetContext(), evmMedium) s.Require().NoError(err) @@ -859,7 +819,6 @@ func (s *IntegrationTestSuite) TestTransactionOrdering() { // TestSelectBy tests the SelectBy functionality with filters func (s *IntegrationTestSuite) TestSelectBy() { - fmt.Printf("DEBUG: Starting TestSelectBy\n") testCases := []struct { name string setupTxs func() @@ -879,7 +838,7 @@ func (s *IntegrationTestSuite) TestSelectBy() { { name: "single cosmos transaction - terminates properly", setupTxs: func() { - cosmosTx := s.createCosmosSendTransaction(big.NewInt(2000)) + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000)) mpool := s.network.App.GetMempool() err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) @@ -892,10 +851,9 @@ func (s *IntegrationTestSuite) TestSelectBy() { { name: "single EVM transaction - terminates properly", setupTxs: func() { - evmTx, err := s.createEVMTransaction(big.NewInt(1000000000)) - s.Require().NoError(err) + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) mpool := s.network.App.GetMempool() - err = mpool.Insert(s.network.GetContext(), evmTx) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) }, filterFunc: func(tx sdk.Tx) bool { @@ -910,7 +868,7 @@ func (s *IntegrationTestSuite) TestSelectBy() { // Add transactions with different fees for i := 1; i < 6; i++ { // Use different keys for different transactions - cosmosTx := s.createCosmosSendTransactionWithKey(s.keyring.GetKey(i), big.NewInt(int64(i*1000))) // 5000, 4000, 3000, 2000, 1000 + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(i), big.NewInt(int64(i*1000))) // 5000, 4000, 3000, 2000, 1000 err := mpool.Insert(s.network.GetContext(), cosmosTx) s.Require().NoError(err) } @@ -936,13 +894,10 @@ func (s *IntegrationTestSuite) TestSelectBy() { for i := 1; i < 4; i++ { keyIndex := i key := s.keyring.GetKey(keyIndex) - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account %d: %s\n", keyIndex, fromAddr.Hex()) // Use the helper method with specific nonce - evmTx, err := s.createEVMTransactionWithKey(key, big.NewInt(int64(i)*100000000000)) - s.Require().NoError(err) - err = mpool.Insert(s.network.GetContext(), evmTx) + evmTx := s.createEVMValueTransferTx(key, 0, big.NewInt(int64(i)*100000000000)) + err := mpool.Insert(s.network.GetContext(), evmTx) s.Require().NoError(err) } }, @@ -995,7 +950,6 @@ func (s *IntegrationTestSuite) TestSelectBy() { // TestMempoolHeightRequirement tests that mempool operations fail before block 2 func (s *IntegrationTestSuite) TestMempoolHeightRequirement() { - fmt.Printf("DEBUG: Starting TestMempoolHeightRequirement\n") // Create a fresh network at block 1 keyring := keyring.New(1) options := []network.ConfigOption{ @@ -1013,7 +967,7 @@ func (s *IntegrationTestSuite) TestMempoolHeightRequirement() { s.Require().Equal(int64(2), nw.GetContext().BlockHeight()) mpool := nw.App.GetMempool() - tx := s.createCosmosSendTransaction(big.NewInt(1000)) + tx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000)) // Should fail because mempool requires block height >= 2 err = mpool.Insert(nw.GetContext(), tx) @@ -1024,8 +978,6 @@ func (s *IntegrationTestSuite) TestMempoolHeightRequirement() { // TestEVMTransactionComprehensive tests comprehensive EVM transaction functionality func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { - fmt.Printf("DEBUG: Starting TestEVMTransactionComprehensive\n") - testCases := []struct { name string setupTx func() sdk.Tx @@ -1036,9 +988,7 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { { name: "EVM transaction with high gas price", setupTx: func() sdk.Tx { - tx, err := s.createEVMTransaction(big.NewInt(10000000000)) // 10 gaatom - s.Require().NoError(err) - return tx + return s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(10000000000)) // 10 gaatom }, wantError: false, verifyFunc: func() { @@ -1049,9 +999,7 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { { name: "EVM transaction with low gas price", setupTx: func() sdk.Tx { - tx, err := s.createEVMTransaction(big.NewInt(100000000)) // 0.1 gaatom - s.Require().NoError(err) - return tx + return s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(100000000)) // 0.1 gaatom }, wantError: false, verifyFunc: func() { @@ -1067,9 +1015,7 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { data := []byte{0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0xf3} // Simple contract deployment // Use the contract deployment helper - tx, err := s.createEVMContractDeployment(key, big.NewInt(1000000000), data) - s.Require().NoError(err) - return tx + return s.createEVMContractDeployTx(key, big.NewInt(1000000000), data) }, wantError: false, verifyFunc: func() { @@ -1082,11 +1028,9 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { setupTx: func() sdk.Tx { // Use key 0 again since this is a separate test (SetupTest resets state) key := s.keyring.GetKey(0) - to := common.HexToAddress("0x1234567890123456789012345678901234567890") // Use the value transfer helper - tx, err := s.createEVMValueTransfer(key, big.NewInt(1000000000), big.NewInt(1000000000000000000), to) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, 0, big.NewInt(1000000000)) return tx }, wantError: false, @@ -1097,13 +1041,10 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { }, } - for i, tc := range testCases { - fmt.Printf("DEBUG: TestEVMTransactionComprehensive - Starting test case %d/%d: %s\n", i+1, len(testCases), tc.name) + for _, tc := range testCases { s.Run(tc.name, func() { - fmt.Printf("DEBUG: Running test case: %s\n", tc.name) // Reset test setup to ensure clean state s.SetupTest() - fmt.Printf("DEBUG: SetupTest completed for: %s\n", tc.name) tx := tc.setupTx() mpool := s.network.App.GetMempool() @@ -1120,17 +1061,13 @@ func (s *IntegrationTestSuite) TestEVMTransactionComprehensive() { } tc.verifyFunc() - fmt.Printf("DEBUG: Completed test case: %s\n", tc.name) }) - fmt.Printf("DEBUG: TestEVMTransactionComprehensive - Completed test case %d/%d: %s\n", i+1, len(testCases), tc.name) } } // TestNonceGappedEVMTransactions tests the behavior of nonce-gapped EVM transactions // and the transition from queued to pending when gaps are filled func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { - fmt.Printf("DEBUG: Starting TestNonceGappedEVMTransactions\n") - testCases := []struct { name string setupTxs func() ([]sdk.Tx, []int) // Returns transactions and their expected nonces @@ -1145,8 +1082,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Insert transactions with gaps: nonces 0, 2, 4, 6 (missing 1, 3, 5) for i := 0; i <= 6; i += 2 { - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1169,15 +1105,13 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // First, insert transactions with gaps: nonces 0, 2, 4 for i := 0; i <= 4; i += 2 { - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } // Then fill the gap by inserting nonce 1 - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, 1) @@ -1199,8 +1133,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Insert transactions with multiple gaps: nonces 0, 3, 6, 9 for i := 0; i <= 9; i += 3 { - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1208,8 +1141,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Fill gaps by inserting nonces 1, 2, 4, 5, 7, 8 for i := 1; i <= 8; i++ { if i%3 != 0 { // Skip nonces that are already inserted - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1235,16 +1167,14 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Account 1: nonces 0, 2 (gap at 1) for i := 0; i <= 2; i += 2 { - tx, err := s.createEVMTransactionWithNonce(key1, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key1, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } // Account 2: nonces 0, 3 (gaps at 1, 2) for i := 0; i <= 3; i += 3 { - tx, err := s.createEVMTransactionWithNonce(key2, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key2, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1267,20 +1197,17 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { var nonces []int // Insert transaction with nonce 0 and low gas price - tx1, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 0) - s.Require().NoError(err) + tx1 := s.createEVMValueTransferTx(key, 0, big.NewInt(1000000000)) txs = append(txs, tx1) nonces = append(nonces, 0) // Insert transaction with nonce 1 - tx2, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) + tx2 := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) txs = append(txs, tx2) nonces = append(nonces, 1) // Replace nonce 0 transaction with higher gas price - tx3, err := s.createEVMTransactionWithNonce(key, big.NewInt(2000000000), 0) - s.Require().NoError(err) + tx3 := s.createEVMValueTransferTx(key, 0, big.NewInt(2000000000)) txs = append(txs, tx3) nonces = append(nonces, 0) @@ -1301,8 +1228,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Insert transactions with gaps: nonces 0, 3, 6, 9 for i := 0; i <= 9; i += 3 { - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1310,8 +1236,7 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { // Fill gaps by inserting nonces 1, 2, 4, 5, 7, 8 for i := 1; i <= 8; i++ { if i%3 != 0 { // Skip nonces that are already inserted - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) txs = append(txs, tx) nonces = append(nonces, i) } @@ -1325,370 +1250,22 @@ func (s *IntegrationTestSuite) TestNonceGappedEVMTransactions() { s.Require().Equal(10, count, "After filling all gaps, all 10 transactions should be pending") }, }, - { - name: "removing places subsequent transactions back into queued", - setupTxs: func() ([]sdk.Tx, []int) { - key := s.keyring.GetKey(0) - var txs []sdk.Tx - var nonces []int - - // Insert transactions with gaps: nonces 0, 1, 3, 4, 6, 7 - for i := 0; i <= 7; i++ { - if i != 1 { // Skip nonce 1 to create a gap - tx, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), i) - s.Require().NoError(err) - txs = append(txs, tx) - nonces = append(nonces, i) //#nosec G115 -- int overflow is not a concern here - } - } - - return txs, nonces - }, - verifyFunc: func(mpool mempool.Mempool) { - // Initially: nonces 0 should be pending, nonces 2, 3, 4, 5, 6, 7 should be queued - initialCount := mpool.CountTx() - s.Require().Equal(1, initialCount, "Initially only nonces 0, 1 should be pending") - key := s.keyring.GetKey(0) - - // Fill gap by inserting nonce 1 - tx1, err := s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) - err = mpool.Insert(s.network.GetContext(), tx1) - s.Require().NoError(err) - - // After filling gap: all nonce transactions should be in pending - countAfterFilling := mpool.CountTx() - s.Require().Equal(8, countAfterFilling, "After filling gap, only nonce 0 should be pending due to gap at nonce 1") - - // Remove nonce 1 transaction, dropping the rest (except for 0) into queued - tx1, err = s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) - err = mpool.Remove(tx1) - s.Require().NoError(err) - - // After removal: only nonce 0 should be pending, the rest get dropped to queued - countAfterRemoval := mpool.CountTx() - s.Require().Equal(1, countAfterRemoval, "After removing nonce 1, only nonce 0 should be pending") - - // Fill gap by inserting nonce 1 - tx1, err = s.createEVMTransactionWithNonce(key, big.NewInt(1000000000), 1) - s.Require().NoError(err) - err = mpool.Insert(s.network.GetContext(), tx1) - s.Require().NoError(err) - - // After filling gap: all transactions should be re-promoted and places into pending - countAfterFilling = mpool.CountTx() - s.Require().Equal(8, countAfterFilling, "After filling gap, only nonce 0 should be pending due to gap at nonce 1") - }, - }, } - for i, tc := range testCases { - fmt.Printf("DEBUG: TestNonceGappedEVMTransactions - Starting test case %d/%d: %s\n", i+1, len(testCases), tc.name) + for _, tc := range testCases { s.Run(tc.name, func() { - fmt.Printf("DEBUG: Running test case: %s\n", tc.name) // Reset test setup to ensure clean state s.SetupTest() - fmt.Printf("DEBUG: SetupTest completed for: %s\n", tc.name) - txs, nonces := tc.setupTxs() + txs, _ := tc.setupTxs() mpool := s.network.App.GetMempool() - // Insert transactions and track count changes - initialCount := mpool.CountTx() - fmt.Printf("DEBUG: Initial mempool count: %d\n", initialCount) - - for i, tx := range txs { + for _, tx := range txs { err := mpool.Insert(s.network.GetContext(), tx) s.Require().NoError(err) - - currentCount := mpool.CountTx() - fmt.Printf("DEBUG: After inserting nonce %d: count = %d\n", nonces[i], currentCount) } tc.verifyFunc(mpool) - fmt.Printf("DEBUG: Completed test case: %s\n", tc.name) }) - fmt.Printf("DEBUG: TestNonceGappedEVMTransactions - Completed test case %d/%d: %s\n", i+1, len(testCases), tc.name) - } -} - -// Helper methods - -// createCosmosSendTransactionWithKey creates a simple bank send transaction with the specified key -func (s *IntegrationTestSuite) createCosmosSendTransactionWithKey(key keyring.Key, gasPrice *big.Int) sdk.Tx { - feeDenom := "aatom" - gasLimit := uint64(TxGas) - - // Calculate fee amount from gas price: fee = gas_price * gas_limit - feeAmount := new(big.Int).Mul(gasPrice, big.NewInt(int64(gasLimit))) - - fmt.Printf("DEBUG: Creating cosmos transaction with gas price: %s aatom/gas, fee: %s %s\n", gasPrice.String(), feeAmount.String(), feeDenom) - - fromAddr := key.AccAddr - toAddr := s.keyring.GetKey(1).AccAddr - amount := sdk.NewCoins(sdk.NewInt64Coin(feeDenom, 1000)) - - bankMsg := banktypes.NewMsgSend(fromAddr, toAddr, amount) - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err := txBuilder.SetMsgs(bankMsg) - s.Require().NoError(err) - - txBuilder.SetFeeAmount(sdk.NewCoins(sdk.NewInt64Coin(feeDenom, feeAmount.Int64()))) - txBuilder.SetGasLimit(gasLimit) - - // Sign the transaction - privKey := key.Priv - // Create a dummy signature for testing - sigData := signing.SingleSignatureData{ - SignMode: signing.SignMode_SIGN_MODE_DIRECT, - Signature: []byte("dummy_signature_for_testing"), - } - sig := signing.SignatureV2{ - PubKey: privKey.PubKey(), - Data: &sigData, - Sequence: 0, } - err = txBuilder.SetSignatures(sig) - s.Require().NoError(err) - - fmt.Printf("DEBUG: Created cosmos transaction successfully\n") - return txBuilder.GetTx() -} - -// createCosmosSendTransaction creates a simple bank send transaction using the first key -func (s *IntegrationTestSuite) createCosmosSendTransaction(gasPrice *big.Int) sdk.Tx { - key := s.keyring.GetKey(0) - return s.createCosmosSendTransactionWithKey(key, gasPrice) -} - -// calculateCosmosGasPrice calculates the gas price for a Cosmos transaction -func (s *IntegrationTestSuite) calculateCosmosGasPrice(feeAmount int64, gasLimit uint64) *big.Int { - return new(big.Int).Div(big.NewInt(feeAmount), big.NewInt(int64(gasLimit))) //#nosec G115 -- not concern, test -} - -// calculateCosmosEffectiveTip calculates the effective tip for a Cosmos transaction -// This aligns with EVM transaction prioritization: effective_tip = gas_price - base_fee -func (s *IntegrationTestSuite) calculateCosmosEffectiveTip(feeAmount int64, gasLimit uint64, baseFee *big.Int) *big.Int { - gasPrice := s.calculateCosmosGasPrice(feeAmount, gasLimit) - if baseFee == nil || baseFee.Sign() == 0 { - return gasPrice // No base fee, effective tip equals gas price - } - - if gasPrice.Cmp(baseFee) < 0 { - return big.NewInt(0) // Gas price lower than base fee, effective tip is zero - } - - return new(big.Int).Sub(gasPrice, baseFee) -} - -// createEVMTransaction creates an EVM transaction using the provided key -func (s *IntegrationTestSuite) createEVMTransactionWithKey(key keyring.Key, gasPrice *big.Int) (sdk.Tx, error) { - fmt.Printf("DEBUG: Creating EVM transaction with gas price: %s\n", gasPrice.String()) - - privKey := key.Priv - - // Convert Cosmos address to EVM address - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account: %s\n", fromAddr.Hex()) - - to := common.HexToAddress("0x1234567890123456789012345678901234567890") - ethTx := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: 0, - To: &to, - Value: big.NewInt(1000), - Gas: TxGas, - GasPrice: gasPrice, - Data: nil, - }) - - // Convert to ECDSA private key for signing - ethPrivKey, ok := privKey.(*ethsecp256k1.PrivKey) - if !ok { - return nil, fmt.Errorf("expected ethsecp256k1.PrivKey, got %T", privKey) - } - - ecdsaPrivKey, err := ethPrivKey.ToECDSA() - if err != nil { - return nil, err - } - - signer := ethtypes.HomesteadSigner{} - signedTx, err := ethtypes.SignTx(ethTx, signer, ecdsaPrivKey) - if err != nil { - return nil, err - } - - msgEthTx := &evmtypes.MsgEthereumTx{} - msgEthTx.FromEthereumTx(signedTx) - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err = txBuilder.SetMsgs(msgEthTx) - if err != nil { - return nil, err - } - - fmt.Printf("DEBUG: Created EVM transaction successfully\n") - return txBuilder.GetTx(), nil -} - -// createEVMTransaction creates an EVM transaction using the first key -func (s *IntegrationTestSuite) createEVMTransaction(gasPrice *big.Int) (sdk.Tx, error) { - key := s.keyring.GetKey(0) - return s.createEVMTransactionWithKey(key, gasPrice) -} - -// createEVMContractDeployment creates an EVM transaction for contract deployment -func (s *IntegrationTestSuite) createEVMContractDeployment(key keyring.Key, gasPrice *big.Int, data []byte) (sdk.Tx, error) { - fmt.Printf("DEBUG: Creating EVM contract deployment transaction with gas price: %s\n", gasPrice.String()) - - privKey := key.Priv - - // Convert Cosmos address to EVM address - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account: %s\n", fromAddr.Hex()) - - ethTx := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: 0, - To: nil, // nil for contract deployment - Value: big.NewInt(0), - Gas: 100000, - GasPrice: gasPrice, - Data: data, - }) - - // Convert to ECDSA private key for signing - ethPrivKey, ok := privKey.(*ethsecp256k1.PrivKey) - if !ok { - return nil, fmt.Errorf("expected ethsecp256k1.PrivKey, got %T", privKey) - } - - ecdsaPrivKey, err := ethPrivKey.ToECDSA() - if err != nil { - return nil, err - } - - signer := ethtypes.HomesteadSigner{} - signedTx, err := ethtypes.SignTx(ethTx, signer, ecdsaPrivKey) - if err != nil { - return nil, err - } - - msgEthTx := &evmtypes.MsgEthereumTx{} - msgEthTx.FromEthereumTx(signedTx) - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err = txBuilder.SetMsgs(msgEthTx) - if err != nil { - return nil, err - } - - fmt.Printf("DEBUG: Created EVM contract deployment transaction successfully\n") - return txBuilder.GetTx(), nil -} - -// createEVMValueTransfer creates an EVM transaction for value transfer -func (s *IntegrationTestSuite) createEVMValueTransfer(key keyring.Key, gasPrice *big.Int, value *big.Int, to common.Address) (sdk.Tx, error) { - fmt.Printf("DEBUG: Creating EVM value transfer transaction with gas price: %s\n", gasPrice.String()) - - privKey := key.Priv - - // Convert Cosmos address to EVM address - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account: %s\n", fromAddr.Hex()) - - ethTx := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: 0, - To: &to, - Value: value, - Gas: TxGas, - GasPrice: gasPrice, - Data: nil, - }) - - // Convert to ECDSA private key for signing - ethPrivKey, ok := privKey.(*ethsecp256k1.PrivKey) - if !ok { - return nil, fmt.Errorf("expected ethsecp256k1.PrivKey, got %T", privKey) - } - - ecdsaPrivKey, err := ethPrivKey.ToECDSA() - if err != nil { - return nil, err - } - - signer := ethtypes.HomesteadSigner{} - signedTx, err := ethtypes.SignTx(ethTx, signer, ecdsaPrivKey) - if err != nil { - return nil, err - } - - msgEthTx := &evmtypes.MsgEthereumTx{} - msgEthTx.FromEthereumTx(signedTx) - if err != nil { - return nil, err - } - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err = txBuilder.SetMsgs(msgEthTx) - if err != nil { - return nil, err - } - - fmt.Printf("DEBUG: Created EVM value transfer transaction successfully\n") - return txBuilder.GetTx(), nil -} - -// createEVMTransactionWithNonce creates an EVM transaction with a specific nonce -func (s *IntegrationTestSuite) createEVMTransactionWithNonce(key keyring.Key, gasPrice *big.Int, nonce int) (sdk.Tx, error) { - fmt.Printf("DEBUG: Creating EVM transaction with gas price: %s and nonce: %d\n", gasPrice.String(), nonce) - - privKey := key.Priv - - // Convert Cosmos address to EVM address - fromAddr := common.BytesToAddress(key.AccAddr.Bytes()) - fmt.Printf("DEBUG: Using prefunded account: %s\n", fromAddr.Hex()) - - to := common.HexToAddress("0x1234567890123456789012345678901234567890") - ethTx := ethtypes.NewTx(ðtypes.LegacyTx{ - Nonce: uint64(nonce), //#nosec G115 -- int overflow is not a concern here - To: &to, - Value: big.NewInt(1000), - Gas: TxGas, - GasPrice: gasPrice, - Data: nil, - }) - - // Convert to ECDSA private key for signing - ethPrivKey, ok := privKey.(*ethsecp256k1.PrivKey) - if !ok { - return nil, fmt.Errorf("expected ethsecp256k1.PrivKey, got %T", privKey) - } - - ecdsaPrivKey, err := ethPrivKey.ToECDSA() - if err != nil { - return nil, err - } - - signer := ethtypes.HomesteadSigner{} - signedTx, err := ethtypes.SignTx(ethTx, signer, ecdsaPrivKey) - if err != nil { - return nil, err - } - - msgEthTx := &evmtypes.MsgEthereumTx{} - msgEthTx.FromEthereumTx(signedTx) - if err != nil { - return nil, err - } - - txBuilder := s.network.App.GetTxConfig().NewTxBuilder() - err = txBuilder.SetMsgs(msgEthTx) - if err != nil { - return nil, err - } - - fmt.Printf("DEBUG: Created EVM transaction successfully\n") - return txBuilder.GetTx(), nil } diff --git a/tests/integration/mempool/test_mempool_integration_abci.go b/tests/integration/mempool/test_mempool_integration_abci.go new file mode 100644 index 000000000..b4aa655f0 --- /dev/null +++ b/tests/integration/mempool/test_mempool_integration_abci.go @@ -0,0 +1,449 @@ +package mempool + +import ( + "encoding/hex" + "math/big" + + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cometbft/cometbft/crypto/tmhash" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/mempool" +) + +// TestTransactionOrderingWithABCIMethodCalls tests transaction ordering based on fees +func (s *IntegrationTestSuite) TestTransactionOrderingWithABCIMethodCalls() { + testCases := []struct { + name string + setupTxs func() ([]sdk.Tx, []string) + // TODO: remove bypass option after anteHandler is fixed. + // Current anteHandler rejects valid high-gas transaction to replace low-gas transaction + // So, all replacement test cases fail. + bypass bool + }{ + { + name: "mixed EVM and cosmos transaction ordering", + setupTxs: func() ([]sdk.Tx, []string) { + // Create EVM transaction with high gas price + highGasPriceEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) + + // Create Cosmos transactions with different fee amounts + highFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(6), big.NewInt(5000000000)) + mediumFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(7), big.NewInt(3000000000)) + lowFeeCosmosTx := s.createCosmosSendTx(s.keyring.GetKey(8), big.NewInt(2000000000)) + + // Input txs in order + inputTxs := []sdk.Tx{lowFeeCosmosTx, highGasPriceEVMTx, mediumFeeCosmosTx, highFeeCosmosTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{highGasPriceEVMTx, highFeeCosmosTx, mediumFeeCosmosTx, lowFeeCosmosTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + }, + { + name: "EVM-only transaction replacement", + setupTxs: func() ([]sdk.Tx, []string) { + // Create first EVM transaction with low fee + lowFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(2000000000)) // 2 gaatom + + // Create second EVM transaction with high fee + highFeeEVMTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom + + // Input txs in order + inputTxs := []sdk.Tx{lowFeeEVMTx, highFeeEVMTx} + + // Expected Txs in order + expectedTxs := []sdk.Tx{highFeeEVMTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "EVM-only transaction ordering", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + // Create first EVM transaction with low fee + lowFeeEVMTx := s.createEVMValueTransferTx(key, 1, big.NewInt(2000000000)) // 2 gaatom + + // Create second EVM transaction with high fee + highFeeEVMTx := s.createEVMValueTransferTx(key, 0, big.NewInt(5000000000)) // 5 gaatom + + // Input txs in order + inputTxs := []sdk.Tx{lowFeeEVMTx, highFeeEVMTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{highFeeEVMTx, lowFeeEVMTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + }, + { + name: "cosmos-only transaction replacement", + setupTxs: func() ([]sdk.Tx, []string) { + highFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5 gaatom + lowFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000000000)) // 2 gaatom + mediumFeeTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(3000000000)) // 3 gaatom + + // Input txs in order + inputTxs := []sdk.Tx{mediumFeeTx, lowFeeTx, highFeeTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{highFeeTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "mixed EVM and Cosmos transactions with equal effective tips", + setupTxs: func() ([]sdk.Tx, []string) { + // Create transactions with equal effective tips (assuming base fee = 0) + // EVM: 1000 aatom/gas effective tip + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(1000000000)) // 1 gaatom/gas + + // Cosmos with same effective tip: 1000 * 200000 = 200000000 aatom total fee + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(1000000000)) // 1 gaatom/gas effective tip + + // Input txs in order + inputTxs := []sdk.Tx{cosmosTx, evmTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{evmTx, cosmosTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "mixed transactions with EVM having higher effective tip", + setupTxs: func() ([]sdk.Tx, []string) { + // Create EVM transaction with higher gas price + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(5000000000)) // 5 gaatom/gas + + // Create Cosmos transaction with lower gas price + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(2000000000)) // 2 gaatom/gas + + // Input txs in order + inputTxs := []sdk.Tx{cosmosTx, evmTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{evmTx, cosmosTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "mixed transactions with Cosmos having higher effective tip", + setupTxs: func() ([]sdk.Tx, []string) { + // Create EVM transaction with lower gas price + evmTx := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(2000000000)) // 2000 aatom/gas + + // Create Cosmos transaction with higher gas price + cosmosTx := s.createCosmosSendTx(s.keyring.GetKey(0), big.NewInt(5000000000)) // 5000 aatom/gas + + // Input txs in order + inputTxs := []sdk.Tx{evmTx, cosmosTx} + + // Expected txs in order + expectedTxs := []sdk.Tx{cosmosTx, evmTx} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + bypass: true, + }, + { + name: "mixed transaction ordering with multiple effective tips", + setupTxs: func() ([]sdk.Tx, []string) { + // Create multiple transactions with different gas prices + // EVM: 10000, 8000, 6000 aatom/gas + // Cosmos: 9000, 7000, 5000 aatom/gas + + evmHigh := s.createEVMValueTransferTx(s.keyring.GetKey(0), 0, big.NewInt(10000000000)) + evmMedium := s.createEVMValueTransferTx(s.keyring.GetKey(1), 0, big.NewInt(8000000000)) + evmLow := s.createEVMValueTransferTx(s.keyring.GetKey(2), 0, big.NewInt(6000000000)) + + cosmosHigh := s.createCosmosSendTx(s.keyring.GetKey(3), big.NewInt(9000000000)) + cosmosMedium := s.createCosmosSendTx(s.keyring.GetKey(4), big.NewInt(7000000000)) + cosmosLow := s.createCosmosSendTx(s.keyring.GetKey(5), big.NewInt(5000000000)) + + // Input txs in order + inputTxs := []sdk.Tx{cosmosHigh, cosmosMedium, cosmosLow, evmHigh, evmMedium, evmLow} + + // Expected txs in order + expectedTxs := []sdk.Tx{evmHigh, cosmosHigh, evmMedium, cosmosMedium, evmLow, cosmosLow} + expTxHashes := s.getTxHashes(expectedTxs) + + return inputTxs, expTxHashes + }, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + // Reset test setup to ensure clean state + s.SetupTest() + + txs, expTxHashes := tc.setupTxs() + + // Call CheckTx for transactions + err := s.checkTxs(txs) + s.Require().NoError(err) + + // Call FinalizeBlock to make finalizeState before calling PrepareProposal + _, err = s.network.FinalizeBlock() + s.Require().NoError(err) + + // Call PrepareProposal to selcet transactions from mempool and make proposal + prepareProposalRes, err := s.network.App.PrepareProposal(&abci.RequestPrepareProposal{ + MaxTxBytes: 1_000_000, + Height: 1, + }) + s.Require().NoError(err) + + if tc.bypass { + return + } + + // Check whether expected transactions are included and returned as pending state in mempool + mpool := s.network.App.GetMempool() + iterator := mpool.Select(s.network.GetContext(), nil) + for _, txHash := range expTxHashes { + actualTxHash := s.getTxHash(iterator.Tx()) + s.Require().Equal(txHash, actualTxHash) + + iterator = iterator.Next() + } + + // Check whether expected transactions are selcted by PrepareProposal + txHashes := make([]string, 0) + for _, txBytes := range prepareProposalRes.Txs { + txHash := hex.EncodeToString(tmhash.Sum(txBytes)) + txHashes = append(txHashes, txHash) + } + s.Require().Equal(expTxHashes, txHashes) + }) + } +} + +// TestNonceGappedEVMTransactionsWithABCIMethodCalls tests the behavior of nonce-gapped EVM transactions +// and the transition from queued to pending when gaps are filled +func (s *IntegrationTestSuite) TestNonceGappedEVMTransactionsWithABCIMethodCalls() { + testCases := []struct { + name string + setupTxs func() ([]sdk.Tx, []string) // Returns transactions and their expected nonces + verifyFunc func(mpool mempool.Mempool) + bypass bool + }{ + { + name: "insert transactions with nonce gaps", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + var txs []sdk.Tx + + // Insert transactions with gaps: nonces 0, 2, 4, 6 (missing 1, 3, 5) + for i := 0; i <= 6; i += 2 { + tx := s.createEVMValueTransferTx(key, i, big.NewInt(2000000000)) + txs = append(txs, tx) + } + + // Expected txs in order + expectedTxs := txs[:1] + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // Only nonce 0 should be pending (the first consecutive transaction) + // nonces 2, 4, 6 should be queued + count := mpool.CountTx() + s.Require().Equal(1, count, "Only nonce 0 should be pending, others should be queued") + }, + }, + { + name: "fill nonce gap and verify pending count increases", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + var txs []sdk.Tx + + // First, insert transactions with gaps: nonces 0, 2, 4 + for i := 0; i <= 4; i += 2 { + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) + txs = append(txs, tx) + } + + // Then fill the gap by inserting nonce 1 + tx := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) + txs = append(txs, tx) + + // Expected txs in order + expectedTxs := []sdk.Tx{txs[0], txs[3], txs[1]} + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // After filling nonce 1, transactions 0, 1, 2 should be pending + // nonce 4 should still be queued + count := mpool.CountTx() + s.Require().Equal(3, count, "After filling gap, nonces 0, 1, 2 should be pending") + }, + }, + { + name: "fill multiple nonce gaps", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + var txs []sdk.Tx + + // Insert transactions with multiple gaps: nonces 0, 3, 6, 9 + for i := 0; i <= 9; i += 3 { + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) + txs = append(txs, tx) + + } + + // Fill gaps by inserting nonces 1, 2, 4, 5, 7, 8 + for i := 1; i <= 8; i++ { + if i%3 != 0 { // Skip nonces that are already inserted + tx := s.createEVMValueTransferTx(key, i, big.NewInt(1000000000)) + txs = append(txs, tx) + + } + } + + // Expected txs in order + expectedTxs := []sdk.Tx{txs[0], txs[4], txs[5], txs[1], txs[6], txs[7], txs[2], txs[8], txs[9], txs[3]} + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // After filling all gaps, all transactions should be pending + count := mpool.CountTx() + s.Require().Equal(10, count, "After filling all gaps, all 10 transactions should be pending") + }, + }, + { + name: "test different accounts with nonce gaps", + setupTxs: func() ([]sdk.Tx, []string) { + var txs []sdk.Tx + + // Use different keys for different accounts + key1 := s.keyring.GetKey(0) + key2 := s.keyring.GetKey(1) + + // Account 1: nonces 0, 2 (gap at 1) + for i := 0; i <= 2; i += 2 { + tx := s.createEVMValueTransferTx(key1, i, big.NewInt(1000000000)) + txs = append(txs, tx) + } + + // Account 2: nonces 0, 3 (gaps at 1, 2) + for i := 0; i <= 3; i += 3 { + tx := s.createEVMValueTransferTx(key2, i, big.NewInt(1000000000)) + txs = append(txs, tx) + } + + // Expected txs in order + expectedTxs := []sdk.Tx{txs[0], txs[2]} + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // Account 1: nonce 0 pending, nonce 2 queued + // Account 2: nonce 0 pending, nonce 3 queued + // Total: 2 pending transactions + count := mpool.CountTx() + s.Require().Equal(2, count, "Only nonce 0 from each account should be pending") + }, + }, + { + name: "test replacement transactions with higher gas price", + setupTxs: func() ([]sdk.Tx, []string) { + key := s.keyring.GetKey(0) + var txs []sdk.Tx + + // Insert transaction with nonce 0 and low gas price + tx1 := s.createEVMValueTransferTx(key, 0, big.NewInt(1000000000)) + txs = append(txs, tx1) + + // Insert transaction with nonce 1 + tx2 := s.createEVMValueTransferTx(key, 1, big.NewInt(1000000000)) + txs = append(txs, tx2) + + // Replace nonce 0 transaction with higher gas price + tx3 := s.createEVMValueTransferTx(key, 0, big.NewInt(2000000000)) + txs = append(txs, tx3) + + // Expected txs in order + expectedTxs := []sdk.Tx{txs[2], txs[1]} + expTxHashes := s.getTxHashes(expectedTxs) + + return txs, expTxHashes + }, + verifyFunc: func(mpool mempool.Mempool) { + // After replacement, both nonces 0 and 1 should be pending + count := mpool.CountTx() + s.Require().Equal(2, count, "After replacement, both transactions should be pending") + }, + bypass: true, + }, + } + + for _, tc := range testCases { + s.Run(tc.name, func() { + s.SetupTest() + + txs, expTxHashes := tc.setupTxs() + + // Call CheckTx for transactions + err := s.checkTxs(txs) + s.Require().NoError(err) + + // Call FinalizeBlock to make finalizeState before calling PrepareProposal + _, err = s.network.FinalizeBlock() + s.Require().NoError(err) + + // Call PrepareProposal to selcet transactions from mempool and make proposal + prepareProposalRes, err := s.network.App.PrepareProposal(&abci.RequestPrepareProposal{ + MaxTxBytes: 1_000_000, + Height: 1, + }) + s.Require().NoError(err) + + mpool := s.network.App.GetMempool() + iterator := mpool.Select(s.network.GetContext(), nil) + + if tc.bypass { + return + } + + // Check whether expected transactions are included and returned as pending state in mempool + for _, txHash := range expTxHashes { + actualTxHash := s.getTxHash(iterator.Tx()) + s.Require().Equal(txHash, actualTxHash) + + iterator = iterator.Next() + } + tc.verifyFunc(mpool) + + // Check whether expected transactions are selcted by PrepareProposal + txHashes := make([]string, 0) + for _, txBytes := range prepareProposalRes.Txs { + txHash := hex.EncodeToString(tmhash.Sum(txBytes)) + txHashes = append(txHashes, txHash) + } + s.Require().Equal(expTxHashes, txHashes) + }) + } +} diff --git a/testutil/integration/evm/network/abci.go b/testutil/integration/evm/network/abci.go index fc5bf9c54..a1bdb7fa3 100644 --- a/testutil/integration/evm/network/abci.go +++ b/testutil/integration/evm/network/abci.go @@ -30,6 +30,27 @@ func (n *IntegrationNetwork) NextBlockWithTxs(txBytes ...[]byte) (*abcitypes.Res return n.finalizeBlockAndCommit(time.Second, txBytes...) } +// FinalizeBlock is a helper function that runs FinalizeBlock logic +// without Commit and initializing context. +func (n *IntegrationNetwork) FinalizeBlock() (*abcitypes.ResponseFinalizeBlock, error) { + header := n.ctx.BlockHeader() + // Update block header and BeginBlock + header.Height++ + header.AppHash = n.app.LastCommitID().Hash + // Calculate new block time after duration + newBlockTime := header.Time.Add(time.Second) + header.Time = newBlockTime + + // FinalizeBlock to run endBlock, deliverTx & beginBlock logic + req := buildFinalizeBlockReq(header, n.valSet.Validators) + + res, err := n.app.FinalizeBlock(req) + if err != nil { + return nil, err + } + return res, nil +} + // finalizeBlockAndCommit is a private helper function that runs the FinalizeBlock logic // with the provided txBytes, updates the context and // commits the changes to have a block time after the given duration.