Skip to content

feat(app): v0.54 upgrade perf optimizations + app-mempool feature#2091

Merged
thomas-nguy merged 247 commits into
mainfrom
feat/cosmos-sdk-v0.54-upgrade-wip
Jun 23, 2026
Merged

feat(app): v0.54 upgrade perf optimizations + app-mempool feature#2091
thomas-nguy merged 247 commits into
mainfrom
feat/cosmos-sdk-v0.54-upgrade-wip

Conversation

@JayT106

@JayT106 JayT106 commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Builds on #2089 (cosmos-sdk v0.54 upgrade): v0.54 perf optimizations + opt-in app-side mempool. Default mempool stays flood; all app-mempool hooks dormant until mempool.type=app.

  • mempool.type=app opt-in app-side mempool; unrecognized value panics at startup
  • Admitter runs the AnteHandler via RunTx(ExecModeCheck) at admission (p2p InsertTx + RPC CheckTx), serialized by one mutex — fixes the shared-checkState race under CometBFT's concurrent InsertTx
  • App.Commit holds the admission mutex only across BaseApp.Commit's checkState reset; the O(pool) snapshot + expired sweep + candidate selection run lock-free (mempool + encCache are self-locked). Only the RunTx(ReCheck) batch re-acquires the mutex — deep-pool scans no longer stall ingest for the full commit cycle
  • app-side recheck after each commit (CometBFT's app-mempool Update() is a no-op) — re-runs ante in ExecModeReCheck for senders touched by the block, plus a TimeoutHeight sweep that evicts expired txs; candidate cap defaults to one block's tx budget so stale txs don't accumulate
  • mempool-ttl-num-blocks (default 120, 0 disables) evicts pool txs older than N blocks by arrival height, independent of per-tx TimeoutHeight (EVM txs carry TimeoutHeight 0 = never expire). Drains txs the proposal keeps skipping (baseFee gate, blocklist) whose sender never commits and would otherwise pin a pool slot forever. Arrival tracked lazily on first RecheckTxs sighting (no admission-path cost, no new lock — RecheckTxs is serial per Commit); the arrival map rebuilds from each cycle's snapshot so included/evicted txs self-reconcile. Eviction is a plain pool+cache drop, no AnteHandler rerun
  • gossip-only ReapTxsHandler with throttle (mempool-gossip-ttl / mempool-txs-per-block) — spreads a large pool across ticks instead of flooding libp2p
  • sharded LRU tx-decode cache + EncoderCache of canonical bytes — eliminates double-decode/proto.Marshal across PrepareProposal/Reap/FinalizeBlock; fast PrepareProposal skips PrepareProposalVerifyTx (ante already ran at insert)
  • PrepareProposal: cache-enabled mempool.type=app uses the NoCheckProposalTxVerifier fast path; flood and app+cache-disabled wire the SDK DefaultProposalHandler directly. ExtTxSelector enforces the blocklist + gas/byte caps in all paths (no bespoke no-op handler)
  • pin COSMOS_SDK_CONFIG_SCOPE — skips os.Executable/os.Hostname on the bech32 hot path (~34× faster sdk.GetConfig)
  • pin cometBFT to v0.39.4-…-22d5a9f
  • testground: +100% TPS (PriorityNonceMempool, 3 validators, batch simple transfer)

Config

mempool.type (CometBFT config.toml):

Value Behavior
flood (default) / "" upstream flood mempool; no app-side hooks
app app-side mempool: admission ante, recheck, gossip-throttled reap

[cronos] (app.toml) — new keys:

Key Default Purpose
tx-cache-size 0 (derive) shared LRU capacity for the encoder + decoder tx caches; 0 = derive from mempool-txs-per-block (2×, or disabled when unlimited); -1 disables both
tx-cache-max-tx-bytes 65536 per-tx payload cap for both caches; larger txs encode/decode but aren't cached. Must not exceed mempool.max_tx_bytes (panics at startup if it does)
mempool-gossip-ttl 15s re-gossip suppression window (mempool.type=app); a reaped tx isn't re-broadcast until it elapses; <=0 uses default
mempool-txs-per-block 2900 one block's tx budget (cronos mainnet empirical); caps both the gossip-reap count per 500ms tick and the recheck-batch size per Commit cycle; 0 = unlimited (also disables tx-cache-size auto-derive)
mempool-ttl-num-blocks 120 evicts mempool.type=app txs older than N blocks by arrival height (independent of per-tx TimeoutHeight); drains proposal-skipped txs whose sender never commits; 0 disables

Known limitations (mempool.type=app)

  • Recheck is committed-sender-scoped, not a full-pool sweep: a sender whose txs sit unconfirmed for many blocks isn't rechecked until its own sender lands in a committed block (or a TimeoutHeight sweep fires).
  • The TimeoutHeight sweep can evict a middle nonce and leave a higher nonce of the same untouched sender in the pool with a nonce gap; that tx may be reaped into a proposal and fail the AnteHandler at FinalizeBlock.

JayT106 and others added 10 commits May 21, 2026 15:02
- bump cosmos-sdk v0.53.4→v0.54.3, ibc-go v10→v11, cometbft v0.38→v0.39.3,
  Go 1.25.8→1.25.9
- migrate cosmossdk.io/{store,log,x/evidence,x/feegrant,x/upgrade,x/tx}
  standalone modules to in-tree github.com/cosmos/cosmos-sdk paths
  (store/v2, log/v2, contrib/x/crisis)
- pin replaces: cosmos-sdk fork (PR #1812 staking queue optimization),
  ethermint fork (PR #894), cronos-store fork (PR #57)
- app.go: drop traceStore from New(); SetCommitMultiStoreTracer removed;
  ICAControllerKeeper/ICAHostKeeper/TransferKeeper as pointer; drop
  subspaces from IBC/ICA/Transfer NewKeeper; gov adds
  CalculateVoteResultsAndVotingPower; RegisterNodeService takes
  EarliestVersion func; remove ParamKeyTable for ibcclient/transfer/ica
- ExtTxSelector: drop gasWanted arg; remove SelectTxForProposalFast (no
  Noopmempool path)
- IBCConversionModule: forward SetICS4Wrapper to underlying app
- ibccallbacks v11: NewIBCMiddleware(ck, max) +
  SetUnderlyingApplication + SetICS4Wrapper composition pattern
- blockstm.NewSTMRunner → txnrunner.NewSTMRunner
- AppCreator/AppExporter: drop io.Writer
- AccountKeeper.NextAccountNumber takes (ctx, AccountI)
- e2ee/keyring: ErrUnknownBacked → ErrUnknownBackend
- add v6.0.0-sdk54 upgrade handler with staking v6 migration + StoreUpgrades
- bump CI Go to 1.25.9

Plan: docs/architecture/cosmos-sdk-v0.54-upgrade-plan.md

IBC v2 routes deferred to follow-up PR.
Signed-off-by: JayT106 <JayT106@users.noreply.github.com>
- fix(exchange): add Name() to ExchangeContract to satisfy vm.PrecompiledContract
- fix(upgrades): move PopulateQueuePendingSlots after RunMigrations so indexes
  are built on fully-migrated queue keys
- test(proposal): add test proving ExtTxSelector validates with original memTx
  but forwards nil to parent to bypass block-gas enforcement
- docs(middleware): clarify IBCConversionModule only implements IBCModule, not
  full porttypes.Middleware (missing SetUnderlyingApplication)
The Added set is empty (no store-key churn from v0.53→v0.54 in this
app), so wiring UpgradeStoreLoader was strictly redundant — and worse
than letting the caller fall back to MaxVersionStoreLoader, which is
cronos's custom loader and the loader used at every other height.
Always return false so the caller installs MaxVersionStoreLoader for
both regular and upgrade-height boots.

Drops the upgradeInfo read, the StoreUpgrades literal, and the
storetypes import.
Previous test asserted parent.lastMemTx==nil (old buggy behavior).
Replace with:
- assertion that real memTx reaches parent unmodified
- gas-cap integration test: gasCapSelector rejects second tx when
  first already consumed 60k of 100k budget, proving the nil-was-bug fix
CI repeatedly hits transient nixpkgs check-phase failures inside
python3.13-cherrypy-18.10.0 (e.g. ToolTests::testCombinedTools), which
cascades into cachecontrol → poetry → shell.nix and breaks the
integration_tests entry point. The CI test runner uses test-env (a
poetry2nix-built environment from pyproject.toml/poetry.lock) — the
poetry binary itself is not invoked at runtime, only useful for local
dev when updating dependencies. Drop it from shell.nix so a flaky
upstream cherrypy unit test cannot fail the whole suite.

Devs who need poetry for lock updates can `nix-shell -p poetry` or
`nix run nixpkgs#poetry` ad hoc.
@JayT106
JayT106 requested a review from a team as a code owner May 29, 2026 17:42
@JayT106
JayT106 requested review from ApacCronos and thomas-nguy and removed request for a team May 29, 2026 17:42
@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds app-side mempool support with sharded tx-decode cache and encoder cache, new InsertTx/ReapTxs ABCI handlers and fast proposal paths, extensive unit and integration tests, and CI/testground/build configuration updates.

Changes

App-side mempool with transaction decode and encode caches

Layer / File(s) Summary
Feature flags, config defaults, and dependency pins
CHANGELOG.md, cmd/cronosd/config/config.go, cmd/cronosd/config/toml.go, cmd/cronosd/main.go, go.mod, gomod2nix.toml
Adds tx-decode cache config fields/defaults, TOML template entry, SDK config scope init, and dependency pins for xxhash/cometbft.
Sharded tx decode cache
app/decode_cache.go
Implements 16-shard LRU decode cache with xxhash-based sharding, per-shard locking, collision-safe equality checks, eviction, and a caching decoder wrapper.
Decode cache tests
app/decode_cache_test.go
Comprehensive tests covering hits/misses, error-not-cached, distinct payloads, LRU eviction and bounds, concurrent correctness, payload-size skipping, custom caps, and defaults.
Encoder cache for canonical bytes
app/mempool/encode_cache.go
Adds EncoderCache and exported TxGetter callback; Register/Bytes methods store/retrieve canonical proto-encoded tx bytes keyed by tx pointer identity.
InsertTx admission handler with seen cache
app/mempool/insert.go
New InsertTx handler running RunTx(ExecModeCheck), optional per-block seen-cache dedup, error→ABCI code mapping, and optional encoder-cache registration with dependency checks and fallback behavior.
InsertTx handler tests and benchmarks
app/mempool/insert_test.go
Unit tests for accept/reject/retry, seen-cache dedup/eviction/height-clear, ExecModeCheck verification, encoder-cache registration/fallback/non-registration, plus benchmarks for cache-hit/miss and membership.
ReapTxs handler for proposal building
app/mempool/reap.go
Adds TypeApp and NewReapTxsHandler that snapshots priority-ordered mempool txs, encodes via EncoderCache/txEncoder, skips on encode errors, and applies MaxBytes/MaxGas prefix-scan caps.
ReapTxs handler tests
app/mempool/reap_test.go
Tests for gas/bytes caps, uncapped/empty cases, single-tx gas-cap edge, per-sender nonce ordering, cross-sender priority ordering, and concurrent insert/reap stress.
Fast proposal preparation paths
app/proposal.go
Introduces fastNoOpPrepareProposal (NoOp/nil mempool fast path) and fastPrepareProposalAppMempool (app mempool fast path using encoder cache, wire-size accounting, and optional gas capping).
Proposal path tests
app/proposal_test.go
Adds tests for fastNoOpPrepareProposal and fastPrepareProposalAppMempool covering delegation, filtering, decoding paths, MaxTxBytes/gas caps, encoder-cache behavior, and edge cases.
App constructor wiring for decode cache and mempool
app/app.go
Wires activeDecoder into BaseApp and block-stm, builds blockProposalHandler from activeDecoder, branches on mempool.type to install app-side ABCI hooks, and stores txDecoder = activeDecoder.
Integration tests and fixtures
integration_tests/configs/mempool_app.jsonnet, integration_tests/test_app_mempool.py
Integration fixture and tests for chain boot, ETH tx submission/receipt, contract deploy/call, per-sender ordering, admission-time rejects (bad sig, intrinsic gas), and same-nonce replacement behavior.
CI and build infrastructure
.github/workflows/build.yml, Makefile, testground/Dockerfile, testground/README.md, testground/scripts/setup-udp-buffers.sh, nix/testenv.nix
Adds conditional race-detector mempool test CI step, test-race-mempool Make target, Dockerfile RocksDB/Go/vendor changes, UDP buffer setup script and docs, and testenv preferWheels.
Testground libp2p/topology updates
testground/benchmark/benchmark/peer.py, testground/benchmark/benchmark/stateless.py, testground/benchmark/benchmark/topology.py, testground/benchmark/benchmark/types.py, testground/benchmark-options.json
Derives libp2p peer ID from node_key, adds libp2p_id to PeerPacket, connect_all_libp2p helper, conditional bootstrap peer wiring and readiness logic, and expanded benchmark options for mempool/app settings.

Sequence Diagram(s)

sequenceDiagram
  participant CometBFT
  participant InsertHandler as InsertTx Handler
  participant AppRunTx as App.RunTx
  participant SeenCache
  participant EncoderCache
  CometBFT->>InsertHandler: InsertTx(req.Tx)
  InsertHandler->>SeenCache: HasAtHeight(hash, height)
  alt hit
    SeenCache-->>InsertHandler: true
    InsertHandler->>CometBFT: OK
  else miss
    InsertHandler->>AppRunTx: RunTx(tx, ExecModeCheck)
    AppRunTx-->>InsertHandler: success/error
    alt success
      InsertHandler->>SeenCache: Add(hash)
      InsertHandler->>EncoderCache: Register(tx, canonicalBytes)
      InsertHandler->>CometBFT: OK
    else failure
      InsertHandler->>CometBFT: CodeTypeRetry or error
    end
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

nix, simulation

Suggested reviewers

  • thomas-nguy

🐰 A rabbit hops through caches so fine,
Decode and encode, in perfect line,
The mempool now sleek, with ABCI hooks,
Proposals bloom fast—take a closer look!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.42% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title clearly describes the main changes: v0.54 upgrade performance optimizations and the new app-mempool feature, both of which are well-represented in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cosmos-sdk-v0.54-upgrade-wip

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

This comment has been minimized.

JayT106 added a commit that referenced this pull request May 29, 2026
@socket-security

socket-security Bot commented May 29, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedgolang/​github.com/​cometbft/​cometbft@​v0.39.3 ⏵ v0.39.4-0.20260526181141-22d5a9f7654075 +110010010070

View full report

@JayT106 JayT106 changed the title feat(app): v0.54 upgrade handler fixes + new perf optimizations + app-mempool feature feat(app): v0.54 upgrade perf optimizations + app-mempool feature May 29, 2026
- upgrades.go: extract planName const; clarify PopulateQueuePendingSlots is idempotent
- precompiles/ica: early-return baseCost on unknown method ID before SubmitMsgsMethodName check
- middleware/conversion: invert ack.Success() guard to early-return on failure, flatten nesting
JayT106 added a commit that referenced this pull request May 29, 2026
@JayT106
JayT106 force-pushed the feat/cosmos-sdk-v0.54-upgrade-wip branch from ac47a5d to 584bce6 Compare May 29, 2026 17:53
JayT106 added 5 commits May 29, 2026 14:09
Commit a0fc282 updated tests to verify memTx is forwarded to the parent
selector (for gas-cap enforcement), but left three gaps:
- gasOnlyTx helper type was never defined
- proposal.go still passed nil to parent
- old test asserted the old nil-forwarding behavior

Add gasOnlyTx (implements sdk.FeeTx), update SelectTxForProposal to pass
memTx through to parent, and replace the stale nil-assertion test with one
that checks the real memTx reaches both ValidateTx and the parent.
cosmos-sdk v0.54 removed NewDefaultProposalHandlerFast, regressing
per-block proposer cost for nodes running NoOp mempool (archives /
non-priority validators) by re-running TxDecode + AnteHandler per tx.
Reintroduce the fast path locally: when the mempool is nil or NoOp,
filter req.Txs at byte-level via the cronos block-list ValidateTx and
honor req.MaxTxBytes; otherwise delegate to the upstream default
handler so priority mempool ordering semantics are preserved.

Adds unit tests covering: non-NoOp delegation, NoOp filtering with
order preservation, MaxTxBytes boundary, MaxTxBytes <= 0, nil mempool
fast path, and empty req.Txs.
Five subtests duplicated the same `t.Fatal` default-handler stub and
three duplicated the `acceptAll` validator. Hoist `mustNotInvoke` and
`acceptAll` to the parent test scope so each subtest only states what
is unique about its case. No behavior change; same six subtests still
pass.
JayT106 added 2 commits June 18, 2026 15:39
golangci-lint 2.1.6 nolintlint flags these as unused (SA1019 does not
fire on these telemetry/govcli/sim-config calls), so --fix strips them.
Match CI to keep the working tree clean.
cronos_app_no_replace used base_port 26401, overlapping cronos_app_mempool's
26400 range. pystarport spaces validators by 10 (node i = base + i*10, each
spanning base..base+8), so a 3-validator chain at 26400 occupies 26400-26428.
Both fixtures are module-scoped and alive simultaneously, so node1/node2 of
the 26401 chain failed to bind -> crash-loop (FATAL) -> no first block ->
'wait for block 1 timeout'. Move to 26450 (clear of the 26400 range).
Comment thread app/mempool/admitter.go Outdated
The type owns recheck/TTL eviction in addition to admission, so Admitter
understated its role. Rename type, constructors, App accessor/field, and
the admitter.go/admitter_test.go files to match.

Addresses PR #2091 review nitpick.
Comment thread app/mempool/manager.go Dismissed
Comment thread app/mempool/manager.go Fixed
Comment thread app/mempool/manager.go Dismissed
revive (exported rule) flags mempool.MempoolManager as a stutter. Rename
the type to Manager (constructors NewManager/newManager); package-qualified
cronosmempool.Manager keeps the reviewer's intent. App.MempoolManager()
accessor unchanged — it doesn't stutter.
JayT106 added a commit that referenced this pull request Jun 22, 2026
App.Commit() ran RecheckTxs() synchronously, so the O(N) pool scan plus
RunTx(ReCheck) batch landed on the consensus-critical path every block and
CometBFT could not advance until it finished — a regression vs upstream flood,
which rechecks after Commit returns.

Move recheck to a single-flight async worker:

- Manager gains a buffered-1 recheckTrigger; Commit fires TriggerRecheck()
  (non-blocking, coalescing) instead of calling RecheckTxs() inline.
- recheckWorker drains triggers on one goroutine; recheckMu serializes the
  worker, the inline fallback, and direct test calls, keeping the lock-free
  arrival map single-writer.
- Staging is the source of truth, so a dropped/coalesced wakeup loses no
  senders. Cross-block overlap stays safe: RunTx(ReCheck) under a.mu still
  serializes against the next Commit's checkState reset.
- App.Close() stops the worker before BaseApp/store teardown so a late
  recheck never reads a closing store.

Tests built via newManager keep recheckTrigger nil and run synchronously,
so existing recheck tests are unaffected.

Refs PR #2091 discussion r3413717119.
Comment thread app/mempool/manager.go Fixed
Comment thread app/mempool/manager.go Fixed
@JayT106
JayT106 force-pushed the feat/cosmos-sdk-v0.54-upgrade-wip branch from f4e31ed to e3e0a4b Compare June 23, 2026 00:20
@thomas-nguy
thomas-nguy enabled auto-merge June 23, 2026 06:50
@thomas-nguy
thomas-nguy added this pull request to the merge queue Jun 23, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 23, 2026
@songgaoye
songgaoye added this pull request to the merge queue Jun 23, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 23, 2026
@thomas-nguy
thomas-nguy added this pull request to the merge queue Jun 23, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 23, 2026
@thomas-nguy
thomas-nguy added this pull request to the merge queue Jun 23, 2026
Merged via the queue into main with commit d6b567f Jun 23, 2026
40 checks passed
@thomas-nguy
thomas-nguy deleted the feat/cosmos-sdk-v0.54-upgrade-wip branch June 23, 2026 14:04
JayT106 added a commit to JayT106/cronos that referenced this pull request Jun 23, 2026
App.Commit() ran RecheckTxs() synchronously, so the O(N) pool scan plus
RunTx(ReCheck) batch landed on the consensus-critical path every block and
CometBFT could not advance until it finished — a regression vs upstream flood,
which rechecks after Commit returns.

Move recheck to a single-flight async worker:

- Manager gains a buffered-1 recheckTrigger; Commit fires TriggerRecheck()
  (non-blocking, coalescing) instead of calling RecheckTxs() inline.
- recheckWorker drains triggers on one goroutine; recheckMu serializes the
  worker, the inline fallback, and direct test calls, keeping the lock-free
  arrival map single-writer.
- Staging is the source of truth, so a dropped/coalesced wakeup loses no
  senders. Cross-block overlap stays safe: RunTx(ReCheck) under a.mu still
  serializes against the next Commit's checkState reset.
- App.Close() stops the worker before BaseApp/store teardown so a late
  recheck never reads a closing store.

Tests built via newManager keep recheckTrigger nil and run synchronously,
so existing recheck tests are unaffected.

Refs PR crypto-org-chain#2091 discussion r3413717119.
pull Bot pushed a commit to learn2grid/cronos that referenced this pull request Jul 11, 2026
…to-org-chain#2118)

* perf(mempool): run post-Commit recheck async off consensus path

App.Commit() ran RecheckTxs() synchronously, so the O(N) pool scan plus
RunTx(ReCheck) batch landed on the consensus-critical path every block and
CometBFT could not advance until it finished — a regression vs upstream flood,
which rechecks after Commit returns.

Move recheck to a single-flight async worker:

- Manager gains a buffered-1 recheckTrigger; Commit fires TriggerRecheck()
  (non-blocking, coalescing) instead of calling RecheckTxs() inline.
- recheckWorker drains triggers on one goroutine; recheckMu serializes the
  worker, the inline fallback, and direct test calls, keeping the lock-free
  arrival map single-writer.
- Staging is the source of truth, so a dropped/coalesced wakeup loses no
  senders. Cross-block overlap stays safe: RunTx(ReCheck) under a.mu still
  serializes against the next Commit's checkState reset.
- App.Close() stops the worker before BaseApp/store teardown so a late
  recheck never reads a closing store.

Tests built via newManager keep recheckTrigger nil and run synchronously,
so existing recheck tests are unaffected.

Refs PR crypto-org-chain#2091 discussion r3413717119.

* chore(changelog): add crypto-org-chain#2118 async recheck entry

* chore(changelog): align crypto-org-chain#2118 entry to PR title

* style(mempool): tighten recheckMu/recheckTrigger field comments

* fix(mempool): address PR crypto-org-chain#2118 review feedback

- Group recheckTrigger/stop/workerDone/stopOnce into recheckAsync sub-struct
  so recheck worker lifecycle fields are clearly scoped (per thomas-nguy).
- Fix shutdown race: recheckWorker re-checks async.stop after dequeuing a
  trigger, so a Close() racing a buffered trigger skips the redundant recheck
  instead of blocking store teardown (per songgaoye).
- Document stale-tx window on TriggerRecheck: PrepareProposal may race the
  async worker; behavior matches CometBFT flood-mempool (per songgaoye).
- Add async lifecycle tests: worker wakes on trigger, coalesced triggers
  preserve staged senders, concurrent commits are race-safe, Close waits
  for in-flight RecheckTxs (per songgaoye).

* style(mempool): tighten async recheck comments

* feat(mempool): add WaitForRecheck so PrepareProposal sees a clean pool

The async recheck worker could still be running when PrepareProposal
starts on the next block, letting stale-nonce/balance txs enter proposals.

Changes:
- Each TriggerRecheck call creates a per-trigger ready gate (chan struct{})
  and threads it through the trigger channel so the worker closes exactly
  the right gate after each run — no shared-field close race.
- WaitForRecheck() reads the latest gate under readyMu and blocks on it;
  if no recheck is pending the gate is pre-closed and the call is instant.
- PrepareProposal now calls WaitForRecheck() before inner proposal handler.
- Add TestWaitForRecheck_BlocksUntilWorkerDone to cover the new path.

* fix(mempool): WaitForRecheck respects ctx deadline; deduplicate test setup

- WaitForRecheck(ctx) now selects on ctx.Done() alongside the ready gate so
  a stuck recheck worker cannot halt block production past the proposal deadline.
- PrepareProposal passes its sdk.Context to WaitForRecheck.
- Extract startAsyncWorker helper to remove 6-line async field setup
  duplicated in TestClose_WaitsForInFlight and TestWaitForRecheck_BlocksUntilWorkerDone.

* refactor(mempool/test): simplify async test helpers

- newAsyncRecheckFixture now calls startAsyncWorker to eliminate 5-line
  duplication of async field setup between the two helpers.
- Extract waitUntil(t, cond, timeout, msg) to replace 4 identical
  deadline-poll loops across the test file.

* fix(app): return empty proposal if WaitForRecheck times out

If the async recheck worker doesn't finish before the PrepareProposal
context deadline, return an empty block rather than selecting from a
potentially-stale pool. An empty block is preferable to including txs
with invalid nonces/balances that would fail at EVM execution. In
practice this path is never taken: recheck finishes well before the
proposal deadline in the normal inter-block gap.

* fix(mempool/test): prevent test hang on assertion failure

Both blocking-runner tests (TestClose_WaitsForInFlight and
TestWaitForRecheck_BlocksUntilWorkerDone) could hang indefinitely if an
assertion failed while RunTx was blocked: deferred Close() would wait
on the worker, which was waiting on the unblock channel that nothing
would ever close.

Fix by wrapping unblock in sync.Once (idempotent close) and calling it
before Close() in cleanup/defer, so shutdown is safe regardless of
which code path exits the test.

Also fixes goroutine leak in TestClose_WaitsForInFlight: startAsyncWorker
had no cleanup, so a waitUntil timeout would leave the worker goroutine
running.

Also fixes struct field comment alignment in recheckAsync (golangci-lint).

* style(mempool): trim async recheck comments to why-only

Remove test function doc comments; keep only design rationale in
async-specific code (recheckAsync struct, TriggerRecheck, recheckWorker,
Close, WaitForRecheck, PrepareProposal/Commit/FinalizeBlock wiring).

* feat(app): count recheck-timeout empty proposals for alerting

Operators can alert on cronos_mempool_recheck_proposal_timeout to
detect when recheck consistently misses the proposal deadline.

* refactor(mempool): extract recheckWorker struct with recheck/run/stop/wait

Move async recheck lifecycle out of Manager into a recheckWorker struct
with focused methods:
- recheck(): coalescing trigger dispatch
- run(fn): worker goroutine loop
- stop(): idempotent shutdown
- wait(ctx): gate for PrepareProposal

Manager.TriggerRecheck/Close/WaitForRecheck become thin wrappers.
Struct and methods live in recheck_worker.go.

* style(mempool): clarify worker nil-trigger comment

* update comment

* fix(mempool): remove unused recheckAsync type

* refactor(mempool): move worker init into recheckWorker.init()

* fix(mempool): close orphaned recheck gate on quit race, bound PrepareProposal wait

- recheckWorker.run(): outer select could pick the quit case over an
  already-buffered trigger, leaving that gate unclosed forever; any
  WaitForRecheck blocked on it would hang. Drain-and-close on quit too.
- app.go PrepareProposal: cosmos-sdk's ctx carries no deadline, so the
  documented "ctx cancellation bounds the wait" safety net was dead code.
  Wrap it with a real context.WithTimeout before calling WaitForRecheck.

* style(mempool): trim test doc comments

* fix(mempool): check recheck-wait ctx error before canceling it

cancel() unconditionally sets ctx.Err(), so checking Err() after
calling it always looked timed out. Every PrepareProposal call took
the empty-proposal branch, so no tx was ever included in a block.

* refactor(mempool): extract duplicated eviction and sender-merge logic

selectTxs had two nearly identical eviction blocks (timeout vs TTL), and
StageSkippedSenders/StageRecheckSenders duplicated the same merge-not-overwrite
logic for recheckSenders. Pulled both into named helpers (evictForRecheck,
mergeRecheckSenders); no behavior change.

* test(mempool): extract WaitForRecheckTimedOut, add cancel-order regression test

The cancel()-before-Err() bug fixed in 1ddf52f lived entirely inside app.go's
PrepareProposal closure, which no unit test touched — it only surfaced through a
full integration test run. Extracted the wait/cancel/check sequence into
Manager.WaitForRecheckTimedOut so it's directly testable, and added tests
asserting timedOut=false when recheck completes in time and timedOut=true when
it's still stuck past the deadline.

* test(mempool): cover recheckWorker.stop idempotency

stop() claims to be idempotent via sync.Once; add a direct test for it.

* style(mempool): trim recheck comments

Cut duplication (worker.wait vs Manager.WaitForRecheck said the same
thing twice) and shortened a few multi-line comments to one line,
keeping the non-obvious why.

* fix(mempool): remove ReCheck failures from the pool, not just the encoder cache

runRecheck only called a.encCache.Evict(tx) on a ReCheck(RunTx) failure.
BaseApp itself removes a tx from the pool on ante-handler recheck failure,
but not on a msg-execution-level failure (post-ante) — that error path
returns without touching the mempool. So a tx that failed full ReCheck
execution could stay in the pool and get reselected into a future proposal.

Switch to a.evict(tx), the existing helper that removes from both the pool
and the encoder cache, matching the pattern already used elsewhere (e.g.
selectTxs's TTL/timeout eviction). Predates PR crypto-org-chain#2118 — this bug was in the
prior synchronous recheck path too — but fixing it here since it surfaced
during review of the async recheck change.

Added TestRecheckTxs_MsgExecFailureEvictsFromPool: the existing test stub
always removed from the pool on failure (mirroring only the ante path), so
none of the existing tests actually covered the msg-execution-failure gap.

* style(mempool): trim recheckRunner comment, drop test doc comment

* fix(mempool): close WaitForRecheckTimedOut boundary race, dedup test worker init

wait() picked ctx.Done() over an already-closed ready gate at random when both
fired near-simultaneously, misreporting a completed recheck as timed out right
at the 1.5s PrepareProposal boundary. wait() now returns whether ctx fired
first and rechecks ready non-blocking before answering, so a near-simultaneous
completion is no longer misreported. This also drops the ctx.Err()-after-cancel
snapshot Manager relied on.

startAsyncWorker in recheck_async_test.go duplicated recheckWorker.init()'s
body instead of calling it; now calls init() directly.

* style(mempool): trim wait comment

* refactor(mempool): encapsulate PrepareProposal wiring in AppMempoolProposalHandler

Moves the inline PrepareProposal closure out of app.go into a named
AppMempoolProposalHandler type in proposal.go, per review feedback on
PR crypto-org-chain#2118. Same behavior, just given a name and a home next to the
other proposal-handling types.

* docs(mempool): make a few comments plainer to read

Reworded a handful of comments in manager.go and recheck_worker.go
that leaned on jargon or shorthand (ctor, "single-writer; see
recheckMu", "orphaned unclosed") into plainer sentences. No behavior
change.

* fix(mempool): rename AppMempoolProposalHandler to MempoolProposalHandler

golangci-lint's revive rule flagged the name as stuttering
(app.AppMempoolProposalHandler). Renamed per the linter's own
suggestion.

* style(mempool): tighten MempoolProposalHandler doc comment

* refactor(mempool): move ExtTxSelector + signer-adapter wiring into NewMempoolProposalHandler

Caller now just builds a DefaultProposalHandler and passes it in; the
constructor wires the tx selector and signer extraction adapter, so
app.go's call site is a plain wrapper over DefaultProposalHandler.

Addresses review comments on PR crypto-org-chain#2118.

* small optimisation

* rework on comments

* rework comments

* restore deleted code by mistake

* fix(mempool): address review nits on recheckWorker lifecycle and evictForRecheck

Store fn as a recheckWorker field instead of threading it through init/run.
Replace init with a newRecheckWorker constructor and split goroutine launch
into start(), mirroring the existing stop() lifecycle. Document readyMu's
dual role guarding ready and serializing recheck() against stop(). Hoist the
recheckSenders nil-check in evictForRecheck out of the per-signer loop.

* style: fix goimports formatting in app.go

golangci-lint --fix removed a stray blank line inside the import block.

* fix(mempool): address review nits on ExtTxSelector.Clear and CacheProposalTxVerifier embed

Clear gateSkipped alongside the selector's other per-round state so Clear()
fully resets it regardless of caller.

Narrow CacheProposalTxVerifier's embed from *baseapp.BaseApp to the
baseapp.ProposalTxVerifier interface it actually implements, so it doesn't
promote BaseApp's whole method set.

* fix(mempool): rename CacheProposalTxVerifier constructor param, take interface

app was a misleading name for a baseapp.ProposalTxVerifier; also widen the
param type from the concrete *baseapp.BaseApp to the interface it needs.

* fix(mempool): fix regressions from Clear/embed review-nit commit

Clear() zeroing gateSkipped wiped it before the wrapper could drain it,
since DefaultProposalHandler defers Clear() inside h.inner() first —
silently disabled the stranded-sender recheck feature. Narrowing
CacheProposalTxVerifier's embed to an interface made PrepareProposalVerifyTx
panic on a cache hit: forming a bound method value off a nil interface
panics in Go, unlike a nil pointer embed.

---------

Signed-off-by: JayT106 <JayT106@users.noreply.github.com>
Co-authored-by: Thomas Nguy <thomas.nguy@crypto.com>
pull Bot pushed a commit to SPPRAGUE/cronos that referenced this pull request Jul 11, 2026
…hain#2119)

* feat(mempool): submit EVM RPC txs via app-mempool direct insert

Under mempool.type=app, route eth_sendRawTransaction/sendTransaction/etherbase
straight into the app mempool via ethermint's MempoolTxInserter
(crypto-org-chain/ethermint#1016) instead of BroadcastTx -> CheckTx. EVM RPC
now gets a correct synchronous ABCI response and back-pressure (CodeTypeRetry
on capacity), sharing one admission path with p2p gossip.

- Manager: extract shared admit(); InsertTxHandler becomes a thin adapter;
  add Manager.InsertTx returning code+codespace+log for the RPC caller.
- App: add InsertMempoolTx + MempoolInsertEnabled. The ethermint server gates
  registration on MempoolInsertEnabled(), so the default flood mempool keeps
  the unchanged BroadcastTx submission path.
- Bump ethermint pin to the gated-interface follow-up.

Addresses PR crypto-org-chain#2091 review r3361761130 (divergent RPC vs gossip admission).

* chore(changelog): fill PR number crypto-org-chain#2119

* chore(changelog): align crypto-org-chain#2119 entry to PR title

* style(mempool): tighten InsertMempoolTx/admit comments

* fix(app): guard InsertMempoolTx against nil mempool manager

Address PR crypto-org-chain#2119 review: InsertMempoolTx relied on ethermint gating the call on
MempoolInsertEnabled(), a cross-repo contract. Add a nil guard returning
ErrNotSupported (matching the other mempoolManager call sites) so a stray call
returns a code instead of panicking. Add wrapped-capacity and flood-gate tests.

* fix(ci): regenerate gomod2nix.toml for ethermint pin + drop redundant uint32 casts

- gomod2nix.toml still pinned the pre-crypto-org-chain#1003 ethermint, so the Nix build failed
  with 'undefined: ethermintserver.MempoolTxInserter'. Regenerate to match the
  go.mod pin (crypto-org-chain#1016, b8b15b3); also pulls the new transitive deps.
- Drop unnecessary uint32(abci.CodeTypeOK) conversions flagged by unconvert.

* test(integration): pass hex block number to eth_getBlockReceipts

The ethermint bump changes GetBlockReceipts param from BlockNumber to
BlockNumberOrHash. BlockNumber accepted a plain decimal int (cast.ToUint64
fallback on missing 0x prefix); BlockNumberOrHash does not, so the raw int
arg now returns an error and the response has no 'result'. Pass hex().

* docs(mempool): tighten insert-tx comments, align changelog wording

* refactor(mempool): drop MempoolInsertEnabled, decline direct insert via nil response

InsertMempoolTx now returns (nil, nil) when mempool.type != app, so ethermint
falls back to BroadcastTx — no separate predicate gating registration. Re-pin
ethermint to the matching single-method MempoolTxInserter interface.

* remove wordy comments

* chore(deps): repin ethermint to appmempool refactor; use appmempool.Inserter

Ethermint moved the app-mempool contracts into a new appmempool package and
dropped the package-global inserter registration (stack crypto-org-chain#1016+crypto-org-chain#1019+crypto-org-chain#1011).

- Bump ethermint pin to 562fa2a2 (go.mod, go.sum, gomod2nix.toml).
- Repoint root.go interface assertion: server.MempoolTxInserter -> appmempool.Inserter.
  App.InsertMempoolTx signature is unchanged, so ethermint StartJSONRPC casts it
  automatically; no app wiring change.

* refactor(mempool): move InsertTx response build into Manager

Address review: App.InsertMempoolTx no longer constructs the sdk.TxResponse.
Manager.InsertTx now returns *sdk.TxResponse; App is a thin delegate (nil-decline
gate + forward), keeping mempool response logic in the mempool package.

* refactor(mempool): expose inserter via appmempool.InserterProvider

The InsertMempoolTx method now lives on the mempool Manager, which satisfies
ethermint's appmempool.Inserter directly. App implements the new InserterProvider
(MempoolInserter), returning the manager or nil under flood mode. This keeps all
mempool response logic in the mempool package and removes the (nil,nil) decline
sentinel from app.go.

Repin ethermint to 2ae3aaf8 (adds appmempool.InserterProvider).

* chore(deps): repin ethermint to crypto-org-chain#1016 head (1389b15f)

crypto-org-chain#2119 depends only on appmempool.Inserter/InserterProvider, which live in
ethermint crypto-org-chain#1016. Pin directly to that PR head instead of the full sig-preverifier
stack tip. Inserter API unchanged, so no cronos code change.

* test(mempool): isolate tamper-reject case; tighten inserter comments

- admission_test: tamper a fresh account so the forged-From rejection
  isn't confounded by nonce/check-state from the prior accepted tx
  (CodeRabbit r3483469252).
- app.go / root.go: trim MempoolInserter / InserterProvider comments to
  the design decision (avoid BaseApp.InsertTx clash).

* chore(deps): repin ethermint crypto-org-chain#1016; adapt to MempoolClient interface

PR crypto-org-chain#1016 replaced appmempool.Inserter/InserterProvider with
MempoolClient (InsertTx + PendingTxs) and MempoolClientProvider.

- repin ethermint to d61c063f (PR head); regen gomod2nix.toml
- Manager: InsertMempoolTx -> InsertTx; add PendingTxs (nil; app
  mempool holds generic sdk.Tx, not decoded MsgEthereumTx)
- App: MempoolInserter() -> MempoolClient() via MempoolClientProvider
  (promoted BaseApp.InsertTx still blocks direct MempoolClient impl)

* fix(lint): gci import formatting in app/app.go and app/mempool/manager.go

- Remove extra blank line in app/app.go import section (line 52)
- Reorder imports in app/mempool/manager.go to follow gci section rules:
  standard → default → cosmossdk.io → github.com/cosmos/cosmos-sdk

* chore(deps): repin ethermint crypto-org-chain#1016 head (66efb289)

Picks up main merge into the PR branch (go-metrics 0.5.4 -> 0.6.0).
appmempool.MempoolClient interface unchanged; no code change.
Regenerate gomod2nix.toml.

* refactor: move MempoolClientProvider assertion to app.go

Compile-time assert lives next to *App and its MempoolClient method;
drop the now-unused appmempool import from root.go.

* chore(deps): repin ethermint crypto-org-chain#1016 head (2f1ceeab)

MempoolClientProvider removed; pass MempoolClient explicitly. Adapt:
- Remove MempoolClientProvider compile-time assertion in app/app.go
- Manager.PendingTxs() return type: []*MsgEthereumTx → []sdk.Tx (drops evmtypes dep)

* docs(mempool): note nil-tx path is intentional when encCache disabled

BaseApp.RunTx accepts nil sdk.Tx and falls back to txBytes; cacheTx is
a no-op without encCache, so passing nil is safe.

* refactor(mempool): trim verbose comments on InsertTx/PendingTxs

* chore(deps): repin ethermint crypto-org-chain#1016 head (6f932cde)
github-merge-queue Bot pushed a commit that referenced this pull request Jul 11, 2026
* feat(mempool): submit EVM RPC txs via app-mempool direct insert

Under mempool.type=app, route eth_sendRawTransaction/sendTransaction/etherbase
straight into the app mempool via ethermint's MempoolTxInserter
(crypto-org-chain/ethermint#1016) instead of BroadcastTx -> CheckTx. EVM RPC
now gets a correct synchronous ABCI response and back-pressure (CodeTypeRetry
on capacity), sharing one admission path with p2p gossip.

- Manager: extract shared admit(); InsertTxHandler becomes a thin adapter;
  add Manager.InsertTx returning code+codespace+log for the RPC caller.
- App: add InsertMempoolTx + MempoolInsertEnabled. The ethermint server gates
  registration on MempoolInsertEnabled(), so the default flood mempool keeps
  the unchanged BroadcastTx submission path.
- Bump ethermint pin to the gated-interface follow-up.

Addresses PR #2091 review r3361761130 (divergent RPC vs gossip admission).

* chore(changelog): fill PR number #2119

* chore(changelog): align #2119 entry to PR title

* style(mempool): tighten InsertMempoolTx/admit comments

* fix(app): guard InsertMempoolTx against nil mempool manager

Address PR #2119 review: InsertMempoolTx relied on ethermint gating the call on
MempoolInsertEnabled(), a cross-repo contract. Add a nil guard returning
ErrNotSupported (matching the other mempoolManager call sites) so a stray call
returns a code instead of panicking. Add wrapped-capacity and flood-gate tests.

* fix(ci): regenerate gomod2nix.toml for ethermint pin + drop redundant uint32 casts

- gomod2nix.toml still pinned the pre-#1003 ethermint, so the Nix build failed
  with 'undefined: ethermintserver.MempoolTxInserter'. Regenerate to match the
  go.mod pin (#1016, b8b15b3); also pulls the new transitive deps.
- Drop unnecessary uint32(abci.CodeTypeOK) conversions flagged by unconvert.

* test(integration): pass hex block number to eth_getBlockReceipts

The ethermint bump changes GetBlockReceipts param from BlockNumber to
BlockNumberOrHash. BlockNumber accepted a plain decimal int (cast.ToUint64
fallback on missing 0x prefix); BlockNumberOrHash does not, so the raw int
arg now returns an error and the response has no 'result'. Pass hex().

* docs(mempool): tighten insert-tx comments, align changelog wording

* refactor(mempool): drop MempoolInsertEnabled, decline direct insert via nil response

InsertMempoolTx now returns (nil, nil) when mempool.type != app, so ethermint
falls back to BroadcastTx — no separate predicate gating registration. Re-pin
ethermint to the matching single-method MempoolTxInserter interface.

* remove wordy comments

* chore(deps): repin ethermint to appmempool refactor; use appmempool.Inserter

Ethermint moved the app-mempool contracts into a new appmempool package and
dropped the package-global inserter registration (stack #1016+#1019+#1011).

- Bump ethermint pin to 562fa2a2 (go.mod, go.sum, gomod2nix.toml).
- Repoint root.go interface assertion: server.MempoolTxInserter -> appmempool.Inserter.
  App.InsertMempoolTx signature is unchanged, so ethermint StartJSONRPC casts it
  automatically; no app wiring change.

* refactor(mempool): move InsertTx response build into Manager

Address review: App.InsertMempoolTx no longer constructs the sdk.TxResponse.
Manager.InsertTx now returns *sdk.TxResponse; App is a thin delegate (nil-decline
gate + forward), keeping mempool response logic in the mempool package.

* refactor(mempool): expose inserter via appmempool.InserterProvider

The InsertMempoolTx method now lives on the mempool Manager, which satisfies
ethermint's appmempool.Inserter directly. App implements the new InserterProvider
(MempoolInserter), returning the manager or nil under flood mode. This keeps all
mempool response logic in the mempool package and removes the (nil,nil) decline
sentinel from app.go.

Repin ethermint to 2ae3aaf8 (adds appmempool.InserterProvider).

* chore(deps): repin ethermint to #1016 head (1389b15f)

#2119 depends only on appmempool.Inserter/InserterProvider, which live in
ethermint #1016. Pin directly to that PR head instead of the full sig-preverifier
stack tip. Inserter API unchanged, so no cronos code change.

* test(mempool): isolate tamper-reject case; tighten inserter comments

- admission_test: tamper a fresh account so the forged-From rejection
  isn't confounded by nonce/check-state from the prior accepted tx
  (CodeRabbit r3483469252).
- app.go / root.go: trim MempoolInserter / InserterProvider comments to
  the design decision (avoid BaseApp.InsertTx clash).

* chore(deps): repin ethermint #1016; adapt to MempoolClient interface

PR #1016 replaced appmempool.Inserter/InserterProvider with
MempoolClient (InsertTx + PendingTxs) and MempoolClientProvider.

- repin ethermint to d61c063f (PR head); regen gomod2nix.toml
- Manager: InsertMempoolTx -> InsertTx; add PendingTxs (nil; app
  mempool holds generic sdk.Tx, not decoded MsgEthereumTx)
- App: MempoolInserter() -> MempoolClient() via MempoolClientProvider
  (promoted BaseApp.InsertTx still blocks direct MempoolClient impl)

* fix(lint): gci import formatting in app/app.go and app/mempool/manager.go

- Remove extra blank line in app/app.go import section (line 52)
- Reorder imports in app/mempool/manager.go to follow gci section rules:
  standard → default → cosmossdk.io → github.com/cosmos/cosmos-sdk

* chore(deps): repin ethermint #1016 head (66efb289)

Picks up main merge into the PR branch (go-metrics 0.5.4 -> 0.6.0).
appmempool.MempoolClient interface unchanged; no code change.
Regenerate gomod2nix.toml.

* refactor: move MempoolClientProvider assertion to app.go

Compile-time assert lives next to *App and its MempoolClient method;
drop the now-unused appmempool import from root.go.

* chore(deps): repin ethermint #1016 head (2f1ceeab)

MempoolClientProvider removed; pass MempoolClient explicitly. Adapt:
- Remove MempoolClientProvider compile-time assertion in app/app.go
- Manager.PendingTxs() return type: []*MsgEthereumTx → []sdk.Tx (drops evmtypes dep)

* docs(mempool): note nil-tx path is intentional when encCache disabled

BaseApp.RunTx accepts nil sdk.Tx and falls back to txBytes; cacheTx is
a no-op without encCache, so passing nil is safe.

* refactor(mempool): trim verbose comments on InsertTx/PendingTxs

* chore(deps): repin ethermint #1016 head (6f932cde)

* feat(mempool): back txpool RPC with app mempool PendingTxs

Repin ethermint to PR #1019 head (stacked on #1016), which wires the txpool
RPC namespace (content/inspect/status/contentFrom) to MempoolClient.PendingTxs.

Implement Manager.PendingTxs: lock-free PoolSnapshot scan returning pooled EVM
messages; skips non-EVM/multi-message txs; nil mpool reports none.

* docs(changelog): add #2127 txpool RPC PendingTxs entry

* fix(mempool): address PendingTxs review nits

- Rename PoolSnapshot telemetry label recheck→pool; snapshot is now called
  from both recheck and txpool RPC paths so the label was misleading
- Drop over-eager capacity hint in PendingTxs; EVM:non-EVM ratio unknown
- Add missing blank line in manager_test.go (gofmt / CI lint fix)

* test(mempool): integration tests for txpool RPC namespace

Covers txpool_content, txpool_inspect, txpool_status, txpool_contentFrom:
- shape tests (always pass): verify endpoints respond with {pending,queued}
- test_txpool_pending_tx_visible: submit tx, query pool immediately, assert
  tx appears in all four endpoints; @flaky(3) for reap_interval race.

* refactor(test): simplify txpool shape tests; add inspect xfail guard

Extract _assert_pool_dict_shape to deduplicate the 3 identical dict-shape
assertions. Add missing pytest.xfail guard for inspect_sender None case
(timing race path identified in code review).

* fix(lint): black format + wrap long lines in txpool tests

* fix(test): enable txpool JSON-RPC namespace for app-mempool suite

default.jsonnet's api list omits txpool, overriding ethermint's default
namespace set. mempool_app.jsonnet never restored it, so all txpool_*
RPC calls in test_app_mempool.py hit an unregistered namespace and
returned no "result" key.

* chore(deps): repin ethermint #1034 head (de2396e91b19)

github.com/crypto-org-chain/ethermint v0.22.1-0.20260707200522-de2396e91b19

* fix(test): move txpool api override to app-config in mempool_app.jsonnet

json-rpc lives under app-config in pystarport's schema, not config
(config maps to config.toml; app-config maps to app.toml). The
previous override nested json-rpc under config, so it silently
patched an unused config.toml section instead of app.toml, and the
txpool namespace was never actually enabled on the running node.

* chore(deps): repin ethermint #1051 head (ea6791fbb8f0)

Ethermint's MempoolClient interface gained CountTx() for O(1)
txpool_status. Add Manager.CountTx() to satisfy it.

* test(mempool): cover Manager.CountTx unit + integration

Add TestManagerCountTx (nil mpool -> 0, populated pool -> exact count)
and tighten test_txpool_pending_tx_visible's status assertion from a
loose >= 1 to a before/after delta, so it actually verifies CountTx()
counted the submitted tx instead of just "something is pending".

* fix(nix): bump go_1_25 overlay pin to 1.25.11

go.mod's go directive moved to 1.25.11 (ethermint #1051 repin), but the
nix overlay still pinned go1.25.9 and CI has no network access to fetch
the newer toolchain on demand. Every nix-based build/integration job
failed with "toolchain not available". Bump the overlay's version and
source hash to match.

* fix(ci): bump stale go-version 1.25.9 pins to 1.25.11

lint.yml, codeql-analysis.yml, and sims.yml each hardcode
actions/setup-go's go-version separately from the nix toolchain. go.mod
now requires go >= 1.25.11 (bumped by the ethermint #1051 repin), so
these jobs failed with GOTOOLCHAIN=local: toolchain not available.

* fix(testground): bump golang base image 1.25.9 -> 1.25.11

Same toolchain mismatch as the CI workflows: go.mod requires go
>= 1.25.11 since the ethermint #1051 repin.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants