Skip to content

Conversation

cloudgray
Copy link
Contributor

@cloudgray cloudgray commented Sep 2, 2025

Description

Summary

This PR implements comprehensive end-to-end testing for appside mempool functionality, adding robust test infrastructure and extensive test cases to verify mempool behavior across different transaction types and node configurations.

Closes #581

System Tests Directory Structure

  • clients/ - Multi-client support infrastructure
    • Ethereum client integration for EVM transaction handling
    • Cosmos client integration for native Cosmos transaction support
  • mempool/ - Dedicated mempool test suite implementation
    • Comprehensive test cases using structured test suite pattern
    • Deterministic testing with nonce and baseFee tracking

Test Mechanism

2.1 Persistent Node Architecture

  • Single node startup for multiple test cases execution
  • evmd nodes remain running throughout entire test suite
  • Test suite maintains deterministic state by tracking:
    • Account nonces across all test cases
    • BaseFee progression for optimal gas pricing

2.2 Common Verification Framework

  • Action-based test structure: Each test case broken into smaller
    verification steps
  • Inter-test validation: Between every test case, suite performs:
    • Verification that expected pending transactions are actually pending
      (or committed)
    • Confirmation that expected queued transactions are properly queued
      on target nodes only
  • Final state verification: After all actions complete, suite waits for
    pending transactions to commit

Test Coverage Checklist

  • Multi-node transaction broadcasting - All test cases execute with transactions broadcast across multiple nodes
  • Ethereum-only transaction scenarios:
    • Queued transactions remain unbroadcast until promotion conditions met
    • Pending transactions broadcast immediately (including queue-to-pending promotions)
    • Same account transactions sent to different nodes handled correctly
  • Cosmos-only transaction scenarios - Native Cosmos transaction mempool behavior
  • Mixed transaction scenarios - Ethereum + Cosmos transactions broadcasted together
  • Transaction type mixing - LegacyFeeTx and DynamicFeeTx combined scenarios

Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • tackled an existing issue or discussed with a team member
  • left instructions on how to review the changes
  • targeted the main branch

@cloudgray cloudgray marked this pull request as ready for review September 9, 2025 08:13
@cloudgray cloudgray requested review from a team as code owners September 9, 2025 08:13
@cloudgray cloudgray requested review from vladjdk and aljo242 September 9, 2025 08:13
if m.HasEventBus() {
if m.eventBus != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did we make this change? seems out of scope for this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, It seems that when I merge conflict from main branch, something wrong happens.
I'll rollback that changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed! (d089213)

Copy link
Member

@vladjdk vladjdk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, lovely test setup! I think this will make it significantly easier to write E2E tests in the future, which is something I applaud you for doing.

I left a few comments, mostly regarding the separation of Pending and Committed as end-states, as transactions get gossiped differently in the consensus phase (commit) vs. the mempool phase (unconfirmed).

Queued map[string]map[string]*RPCTransaction `json:"queued"`
}

type RPCTransaction struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have this type here. Let's use that instead of copying.

PrivKey *ethsecp256k1.PrivKey
}

type TxPoolResult struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto, same file as the RPCTransaction.

cosmossdk.io/systemtests v1.3.0
github.com/ethereum/go-ethereum v1.15.5
github.com/cometbft/cometbft/v2 v2.0.0-rc1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we using V2 and RCs here?

type TestSuite interface {
// Test Lifecycle
BeforeEach(t *testing.T)
AfterEach(t *testing.T)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
AfterEach(t *testing.T)
AfterEachCase(t *testing.T)

// Test Lifecycle
BeforeEach(t *testing.T)
AfterEach(t *testing.T)
JustAfterEach(t *testing.T)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
JustAfterEach(t *testing.T)
AfterEachAction(t *testing.T)

func(s TestSuite) {
tx1, err := s.SendCosmosTx(t, s.Node(0), "acc0", 0, s.BaseFeeX2(), big.NewInt(1))
require.NoError(t, err, "failed to send tx")
_, err = s.SendEthTx(t, s.Node(1), "acc0", 0, s.BaseFee(), nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

func(s TestSuite) {
_, err := s.SendEthTx(t, s.Node(0), "acc0", 0, s.BaseFee(), nil)
require.NoError(t, err, "failed to send tx")
tx2, err := s.SendCosmosTx(t, s.Node(1), "acc0", 0, s.BaseFeeX2(), big.NewInt(1))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

func(s TestSuite) {
tx1, err := s.SendEthTx(t, s.Node(0), "acc0", 0, s.BaseFeeX2(), big.NewInt(1))
require.NoError(t, err, "failed to send tx")
_, err = s.SendCosmosTx(t, s.Node(1), "acc0", 0, s.BaseFee(), nil)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto

},
},
{
name: "legacy should always not tx replace dynamic fee tx",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name: "legacy should always not tx replace dynamic fee tx",
name: "legacy should never replace dynamic fee tx",

}

// CheckPendingOrCommitted checks if the given tx is either pending or committed within the timeout duration
func (s *SystemTestSuite) CheckPendingOrCommitted(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do CheckPending and CheckCommitted as two separate calls as they function differently in Comet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Test: e2e test for appside mempool is needed
3 participants