Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
dae1917
feat(ante): wire ethermint NewEVMSigPreVerifier for lock-free admission
JayT106 Jun 24, 2026
17f5bde
chore: update CHANGELOG for #2120
JayT106 Jun 24, 2026
70c502f
fix(lint): sort ethante import before ante/cache
JayT106 Jun 24, 2026
604a3f0
chore(deps): update gomod2nix for ethermint 3247d33
JayT106 Jun 24, 2026
5c4abe4
test(mempool): add pre-verify rejection + non-EVM fall-through tests
JayT106 Jun 24, 2026
1fa8c4d
refactor(test): concise test comments
JayT106 Jun 24, 2026
b3e5689
fix(ante): wire SetPreVerify before InsertTxHandler snapshot; no Log …
JayT106 Jun 24, 2026
8ab07e4
test(integration): pass hex block number to eth_getBlockReceipts
JayT106 Jun 24, 2026
1dfb182
chore(deps): bump ethermint to 122de00
JayT106 Jun 25, 2026
df50c2d
refactor(mempool): drop EVM-specific comment, remove snapshot comment
JayT106 Jun 25, 2026
49f7030
refactor(mempool): trim InsertTxHandler comments
JayT106 Jun 25, 2026
678eed1
refactor(ante): source EVM sig pre-verifier from appmempool
JayT106 Jun 26, 2026
1a02a63
chore(deps): bump ethermint to c761415
JayT106 Jun 26, 2026
33403ea
Merge branch 'main' into jt/refactor-evm-sig-preverifier
JayT106 Jun 27, 2026
fd06832
refactor(mempool): own the pre-verifier registry in the app layer
JayT106 Jun 29, 2026
b94ed2c
chore(deps): bump ethermint to ff87a62f (registry removed)
JayT106 Jun 29, 2026
2d496fc
simplify comment
JayT106 Jun 29, 2026
d06e6d7
Merge branch 'main' into jt/refactor-evm-sig-preverifier
JayT106 Jun 30, 2026
481b23c
chore: apply review suggestions; repin ethermint to dadacd149b92 (dev…
JayT106 Jun 30, 2026
4dc1485
refactor(mempool): inline a.preVerify in InsertTxHandler closure
JayT106 Jun 30, 2026
418e095
chore(deps): repin ethermint to a639532d (develop HEAD)
JayT106 Jul 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* [#2089](https://github.com/crypto-org-chain/cronos/pull/2089) feat: upgrade to cosmos-sdk v0.54.3 + ibc-go v11 + cometbft v0.39.
* [#2081](https://github.com/crypto-org-chain/cronos/pull/2081) Upgrade go-ethereum version to `v1.16.9`, enable Osaka hardfork.
* [#2091](https://github.com/crypto-org-chain/cronos/pull/2091) feat(app): v0.54 upgrade perf optimizations + app-mempool feature.
* [#2120](https://github.com/crypto-org-chain/cronos/pull/2120) feat(ante): wire ethermint NewEVMSigPreVerifier for lock-free admission, via an app-owned PreVerifierRegistry that composes per-module verifiers.

### Bug fixes

Expand Down
7 changes: 6 additions & 1 deletion app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import (
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
"github.com/evmos/ethermint/ante/cache"
"github.com/evmos/ethermint/appmempool"
evmenc "github.com/evmos/ethermint/encoding"
"github.com/evmos/ethermint/ethereum/eip712"
evmapp "github.com/evmos/ethermint/evmd"
Expand Down Expand Up @@ -474,6 +475,7 @@ func New(
mpool = mempool.NoOpMempool{}
}
blockProposalHandler := NewProposalHandler(activeDecoder, identity, addressCodec)
chainId := cast.ToString(appOpts.Get(flags.FlagChainID))
mempoolType := cast.ToString(appOpts.Get(FlagMempoolType))
switch mempoolType {
case "", "flood", cronosmempool.TypeApp:
Expand Down Expand Up @@ -556,6 +558,10 @@ func New(

app.SetReapTxsHandler(cronosmempool.NewReapTxsHandler(mpool, txConfig.TxEncoder(), encCache, gossipTTL, txsPerBlock, logger.With("module", "app-mempool")))
manager := cronosmempool.NewManager(app, encCache, txConfig.TxEncoder(), mpool, signerExtractor, activeDecoder, txsPerBlock, ttlNumBlocks)
var preVerifiers cronosmempool.PreVerifierRegistry
// Register EVM module preverifier
preVerifiers.Register(appmempool.NewEVMSigPreVerifier(chainId, activeDecoder))
Comment thread
JayT106 marked this conversation as resolved.
manager.SetPreVerify(preVerifiers.Verify)
app.SetInsertTxHandler(manager.InsertTxHandler())
app.SetCheckTxHandler(manager.CheckTxHandler())
mempoolManager = manager
Expand All @@ -570,7 +576,6 @@ func New(
// only enable memiavl cache if neither block-stm nor optimistic execution is enabled, because it's not concurrency-safe.
cacheSize = cast.ToInt(appOpts.Get(memiavlstore.FlagCacheSize))
}
chainId := cast.ToString(appOpts.Get(flags.FlagChainID))
baseAppOptions = memiavlstore.SetupMemIAVL(logger, homePath, appOpts, false, false, cacheSize, chainId, baseAppOptions)

// The default value of optimisticExecution is enabled.
Expand Down
26 changes: 26 additions & 0 deletions app/mempool/admission_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,32 @@ func setupAdmissionApp(tb testing.TB, accounts int) *admissionFixture {
}
}

// TestPreVerifyRejectsTamperedSig: tampered From rejected lock-free before RunTx.
func TestPreVerifyRejectsTamperedSig(t *testing.T) {
f := setupAdmissionApp(t, 2)
other := f.accounts[1].Address
bad := f.signTransfer(t, &f.accounts[0], &other)
resp, err := f.app.InsertTx(&abci.RequestInsertTx{Tx: bad})
require.NoError(t, err)
require.NotEqual(t, abci.CodeTypeOK, resp.Code, "tampered From must be rejected by pre-verifier")
}

// TestPreVerifyPassesThroughNonEVMTx: non-EVM tx skips pre-verifier, fails antehandler.
func TestPreVerifyPassesThroughNonEVMTx(t *testing.T) {
f := setupAdmissionApp(t, 1)
builder := f.app.TxConfig().NewTxBuilder()
require.NoError(t, builder.SetMsgs(&banktypes.MsgSend{
FromAddress: sdk.AccAddress(f.accounts[0].Address.Bytes()).String(),
ToAddress: sdk.AccAddress(f.accounts[0].Address.Bytes()).String(),
Amount: sdk.NewCoins(),
}))
bz, err := f.app.TxConfig().TxEncoder()(builder.GetTx())
require.NoError(t, err)
resp, err := f.app.InsertTx(&abci.RequestInsertTx{Tx: bz})
require.NoError(t, err)
require.NotEqual(t, abci.CodeTypeOK, resp.Code, "unsigned tx must be rejected by antehandler")
}

// TestInsertTxConcurrentAdmission drives many concurrent InsertTx calls
// (pre-verify lock-free, then RunTx under the admission mutex). Run with -race
// to prove the path is concurrency-safe: the signer is pure and the decode cache
Expand Down
20 changes: 15 additions & 5 deletions app/mempool/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ type Manager struct {
encCache *EncoderCache
txEncoder sdk.TxEncoder
trace bool
// preVerify runs cheap verification lock-free before the tx admission mutex; set to nil for skip.
preVerify func([]byte) error

mpool sdkmempool.Mempool
signer sdkmempool.SignerExtractionAdapter
Expand Down Expand Up @@ -126,14 +128,22 @@ func (a *Manager) AdmissionMutex() *sync.Mutex {
return &a.mu
}

// SetPreVerify wires the lock-free pre-verification hook for mempool.type=app.
func (a *Manager) SetPreVerify(fn func([]byte) error) {
a.preVerify = fn
}

// InsertTxHandler validates peer-relayed txs via RunTx(ExecModeCheck) before
// admitting them. Flood protection relies on CometBFT peer limits, not this
// handler. Admitted txs register canonical bytes so ReapTxsHandler can skip
// proto.Marshal; re-encoding keeps non-minimal peer bytes out of the cache.
// admitting them. Admitted txs register canonical bytes so ReapTxsHandler can
// skip proto.Marshal; re-encoding keeps non-minimal peer bytes out of the cache.
func (a *Manager) InsertTxHandler() sdk.InsertTxHandler {
return func(req *abci.RequestInsertTx) (*abci.ResponseInsertTx, error) {
// Decode before locking: proto unmarshal is CPU-intensive; decoder and
// DecodeCache have their own locks. Bad txs return without acquiring mu.
if a.preVerify != nil {
if err := a.preVerify(req.Tx); err != nil {
_, code, _ := errorsmod.ABCIInfo(err, false)
return &abci.ResponseInsertTx{Code: code}, nil
Comment thread
JayT106 marked this conversation as resolved.
}
}
var tx sdk.Tx
if a.encCache != nil {
var err error
Expand Down
26 changes: 26 additions & 0 deletions app/mempool/preverify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package mempool

// PreVerifierRegistry collects lock-free admission pre-verifiers contributed by
// modules. The app composes them and hands Verify to the mempool manager, which
// runs it before the admission mutex (mempool.type=app). First rejection wins; a
// nil result defers to the locked admission path.
type PreVerifierRegistry struct {
verifiers []func([]byte) error
}

// Register adds a pre-verifier; nil is ignored.
func (r *PreVerifierRegistry) Register(v func([]byte) error) {
if v != nil {
r.verifiers = append(r.verifiers, v)
}
}

// Verify runs the registered pre-verifiers, returning the first rejection or nil.
func (r *PreVerifierRegistry) Verify(raw []byte) error {
for _, v := range r.verifiers {
if err := v(raw); err != nil {
return err
}
}
return nil
}
41 changes: 41 additions & 0 deletions app/mempool/preverify_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package mempool

import (
"errors"
"testing"

"github.com/stretchr/testify/require"
)

func TestPreVerifierRegistry(t *testing.T) {
reject := errors.New("reject")

t.Run("empty registry defers", func(t *testing.T) {
var r PreVerifierRegistry
require.NoError(t, r.Verify(nil))
})

t.Run("nil verifier ignored", func(t *testing.T) {
var r PreVerifierRegistry
r.Register(nil)
require.NoError(t, r.Verify(nil))
})

t.Run("first rejection wins, later verifiers not run", func(t *testing.T) {
var r PreVerifierRegistry
ran := false
r.Register(func([]byte) error { return reject })
r.Register(func([]byte) error { ran = true; return nil })
require.ErrorIs(t, r.Verify(nil), reject)
require.False(t, ran, "verifier after a rejection must not run")
})

t.Run("all defer", func(t *testing.T) {
var r PreVerifierRegistry
count := 0
r.Register(func([]byte) error { count++; return nil })
r.Register(func([]byte) error { count++; return nil })
require.NoError(t, r.Verify(nil))
require.Equal(t, 2, count)
})
}
13 changes: 7 additions & 6 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ require (
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/btcsuite/btcd v0.25.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.5 // indirect
github.com/btcsuite/btcd/btcutil v1.1.6 // indirect
github.com/btcsuite/btcd/btcutil v1.2.0 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cosmos/btree v1.0.0 // indirect
Expand All @@ -80,6 +80,7 @@ require (
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.72 // indirect
github.com/ipfs/go-cid v0.5.0 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/kcalvinalvin/anet v0.0.0-20251112173137-d8ddc1f6dbee // indirect
github.com/koron/go-ssdp v0.0.6 // indirect
github.com/ledgerwatch/erigon-lib v0.0.0-20230210071639-db0e7ed11263 // indirect
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
Expand Down Expand Up @@ -131,7 +132,7 @@ require (
github.com/quic-go/webtransport-go v0.10.0 // indirect
github.com/shirou/gopsutil/v4 v4.26.4 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/tidwall/gjson v1.18.0 // indirect
github.com/tidwall/gjson v1.19.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
Expand Down Expand Up @@ -265,7 +266,7 @@ require (
github.com/google/flatbuffers v25.2.10+incompatible // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/pprof v0.0.0-20260115054156-294ebfa9ad83 // indirect
github.com/google/pprof v0.0.0-20260402051712-545e8a4df936 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.15 // indirect
Expand Down Expand Up @@ -365,7 +366,7 @@ require (
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/arch v0.26.0 // indirect
golang.org/x/exp v0.0.0-20260508232706-74f9aab9d74a // indirect
golang.org/x/net v0.55.0 // indirect
golang.org/x/net v0.56.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sync v0.21.0 // indirect
golang.org/x/sys v0.46.0 // indirect
Expand Down Expand Up @@ -399,8 +400,8 @@ replace (
github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.4.2
// release/v1.16
github.com/ethereum/go-ethereum => github.com/crypto-org-chain/go-ethereum v1.10.20-0.20260521015249-663dca6c618e
// develop
github.com/evmos/ethermint => github.com/crypto-org-chain/ethermint v0.22.1-0.20260528204018-f6683e1e255b
// develop + appmempool refactor (#1016 EVM direct-insert, #1019 txpool, #1011 sig pre-verifier).
github.com/evmos/ethermint => github.com/crypto-org-chain/ethermint v0.22.1-0.20260702171011-a639532d9759
// Fix upstream GHSA-h395-qcrw-5vmq and GHSA-3vp4-m3rf-835h vulnerabilities.
// TODO Remove it: https://github.com/cosmos/cosmos-sdk/issues/10409
github.com/gin-gonic/gin => github.com/gin-gonic/gin v1.9.0
Expand Down
Loading
Loading