Skip to content

Conversation

@djm07073
Copy link
Contributor

@djm07073 djm07073 commented Jun 18, 2025

This PR applies changes based on go-ethereum v1.15.11:

  1. StateDB Interface Update
  1. Tracer Refactor
  • Moved logging and tracing logic out of *state.StateDB into a wrapper that implements vm.StateDB.
  • Upstream PR: ethereum/go-ethereum#30569
  • Introduced a new hooked StateDB to handle custom tracing.

Summary by CodeRabbit

  • New Features

    • Per-call SetCode authorizations: RPCs, txs, queries, and EVM calls accept and enforce auth_list for authorized code deployments.
  • Refactor

    • Unified address/caller handling across EVM and precompiles.
    • EVM call/create APIs extended to carry per-call authorization data and related plumbing.
  • Chores

    • Large dependency refresh and test build-tag updates.
    • Indexer now records bloom-indexing and pruning progress; upgrade handler v1.2.0 added.
  • Tests

    • Expanded tests and updated mocks covering conversions, authorizations, and tracing.

@djm07073 djm07073 requested a review from a team as a code owner June 18, 2025 04:14
@coderabbitai
Copy link

coderabbitai bot commented Jun 18, 2025

Walkthrough

Unifies EVM caller/address types, threads per-call SetCode authorizations through APIs and protos, refactors EVM context/tracing and StateDB (introducing HookedStateDB), updates precompiles and test mocks, bumps dependencies, and adds indexer pruning/bloom bookkeeping plus many test and call-site adjustments.

Changes

Cohort / File(s) Change Summary
Module deps
go.mod, integration-tests/go.mod
Large dependency/version updates and replace directives (go-ethereum → initia-labs/evm fork); crypto stack reorganizations and new indirects.
EVM keeper / context / tracing
x/evm/keeper/... (context.go, context_utils.go, query_server.go, msg_server.go, context_test.go, keeper/*)
Refactor of EVM context/tracing: added prepareSDKContext, decorateTracing, chargeIntrinsicGas (now accepts auth list), applyAuthorizations; moved intrinsic gas handling; introduced auth-list conversion/validation and threaded []coretypes.SetCodeAuthorization through validateArguments, queries, msg server, and EVMCall/EVMCreate signatures.
EVMCall API propagation
x/evm/keeper/*.go, app/*, integration-tests/*, x/bank/keeper/grpc_query_test.go, app/ibc-hooks/*
EVMCall/EVMCreate signatures extended with an extra auth parameter; many call sites and tests updated to pass the new trailing argument (commonly nil).
State DB refactor
x/evm/state/statedb.go, x/evm/state/statedb_hooked.go, x/evm/state/statedb_test.go
Overhauled StateDB: ERC20-based balance ops (mint/burn) returning uint256, removed inlined tracer, changed many method signatures/returns (SetCode, SetState, Add/SubBalance, SelfDestruct variants, SetNonce), added AccessEvents/Finalise/Commit/Logs, and introduced HookedStateDB wrapper to emit tracing callbacks.
Precompiles & mocks
x/evm/precompiles/*/contract.go, x/evm/precompiles/*/contract_test.go, x/evm/precompiles/testing/mock.go, deleted local *common_test.go mocks
Switched ExtendedRun callers from vm.ContractRefcommon.Address; removed local MockStateDB files in favor of precompiletesting mocks; updated mock field names and method signatures.
Types / txutils / proto
x/evm/types/*, proto/minievm/evm/v1/*.proto
Added SetCode authorization messages and conversions/validation, extended MsgCall with AuthList, added proto fields (auth_list) and types (AccessTuple, SetCodeAuthorization), changed ExecuteRequest.Caller to common.Address, and wired authorizations through conversion and tx utils.
JSON-RPC tracer
jsonrpc/backend/tracer.go
Removed evmtypes alias, switched references to types, and updated tracer directory New call to include types.DefaultChainConfig(sdkCtx).
app/checktx
app/checktx/handler.go
Updated core.IntrinsicGas call to pass explicit empty auth slice matching new signature.
Indexer / pruning
indexer/bloom.go, indexer/prune.go, indexer/indexer.go, indexer/prune_test.go
Persist prune results and record last pruned / last bloom-indexed heights; added atomic counters and getters; tests now wait on heights rather than boolean flags.
Makefile / coverage
Makefile, .codecov.yml
Added test build tag to test targets and excluded **/mock.go from coverage.
JSON-RPC / txn handling
jsonrpc/types/tx.go, jsonrpc/types/tx_test.go
Added support for coretypes.SetCodeTxType in RPC transaction conversion; updated tests and signer selection.
App upgrade
app/app.go, app/upgrades/v1_2_0/upgrade.go
Upgrade registration moved to v1_2_0 and new upgrade handler added to normalize params and replace on-chain ERC20 wrapper/factory code, then run migrations.
Tests & utilities
x/evm/keeper/txutils_test.go, x/evm/types/txutils_test.go, many tests across repo
Large test updates and additions: SetCode conversion/validation tests, RPC signer change in some tests, encoding config registration, and numerous call-site changes to match new APIs and signatures.
Misc refactors
indexer/*, app/ibc-hooks/*, x/evm/keeper/*
Multiple call-site updates to satisfy new EVMCall signatures; small behavior changes (gas-price math aliasing, build/context helpers).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Client
    participant MsgServer
    participant Validator
    participant Keeper
    participant EVM
    participant StateDB
    participant HookedStateDB
    participant TracingHooks

    Client->>MsgServer: submit MsgCall / Query (AccessList + AuthList)
    MsgServer->>Validator: validateArguments(..., setCodeAuthorizations)
    Validator-->>MsgServer: caller, input, value, accessList, authList
    MsgServer->>Keeper: EVMCall(caller, to, input, value, accessList, authList)
    alt tracing enabled
        Keeper->>EVM: build EVM + decorateTracing
        EVM->>HookedStateDB: wrap StateDB with hooks
        EVM->>HookedStateDB: execute call/create (mutations)
        HookedStateDB->>TracingHooks: emit On* events (balance/code/storage/logs)
        HookedStateDB-->>EVM: results + logs
    else tracing disabled
        Keeper->>EVM: execute with plain StateDB
        EVM->>StateDB: execute call/create
        StateDB-->>EVM: results + logs
    end
    EVM-->>Keeper: result, logs
    Keeper-->>MsgServer: reply
    MsgServer-->>Client: response
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~180+ minutes

Poem

I'm a rabbit in the dev burrow bright,
Hopping through state and tracing light.
I carry auths and mend the calls,
I swap mocks, rebalance halls.
Tests cheer—code springs, the burrow delights! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly and accurately describes the PR’s two primary focuses — the Pectra upgrade (the go-ethereum/StateDB and tracer/dependency updates) and EIP-7702 support (SetCodeAuthorization additions and flow) — which match the changes in the diff; it is concise, specific, and free of noisy details.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bump/v1.15.11

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🔭 Outside diff range comments (3)
x/evm/state/statedb.go (1)

760-786: Broken return type due to wrong package reference after the import fix.

After aliasing, update the stub methods accordingly:

-func (s *StateDB) AccessEvents() *state.AccessEvents {
+func (s *StateDB) AccessEvents() *corestate.AccessEvents {

Same aliasing applies to any other reference (*state.AccessEvents, *state.StateDB, …).

x/evm/state/statedb_test.go (2)

64-70: Unhandled return values – compilation will fail.

AddBalance and SubBalance now return *uint256.Int.
Go requires you to bind or discard the value:

-	stateDB.AddBalance(... )
-	stateDB.SubBalance(... )
+	_, _ = stateDB.AddBalance(... )
+	_, _ = stateDB.SubBalance(... )

270-278: SelfDestruct6780 returns two values – they must be captured or discarded.

-	stateDB.SelfDestruct6780(contractAddr)
+	_, _ = stateDB.SelfDestruct6780(contractAddr)

(The earlier SelfDestruct call has the same issue.)
Otherwise the test will not compile.

♻️ Duplicate comments (12)
x/evm/state/statedb_test.go (1)

325-333: Same issue inside the “same-tx” test case – capture or discard both return values:

-	stateDB.SelfDestruct6780(contractAddr)
+	_, _ = stateDB.SelfDestruct6780(contractAddr)
x/evm/precompiles/cosmos/contract_test.go (11)

130-134: Same change as above – looks good.


175-179: Same change as above – looks good.


219-223: Same change as above – looks good.


251-255: Same change as above – looks good.


295-297: Same change as above – looks good.

Also applies to: 301-306


381-384: Same change as above – looks good.

Also applies to: 390-396


422-425: Same change as above – looks good.


478-480: Same change as above – looks good.

Also applies to: 483-484


524-527: Same change as above – looks good.

Also applies to: 530-531


566-569: Same change as above – looks good.

Also applies to: 572-573


598-603: Same change as above – looks good.

🧹 Nitpick comments (5)
app/checktx/handler.go (1)

172-173: Minor: pass nil instead of empty slice when no authorizations

If no SetCodeAuthorization entries are needed, nil is clearer and avoids an unnecessary allocation:

-intrGas, err := core.IntrinsicGas(ethTx.Data(), ethTx.AccessList(), []coretypes.SetCodeAuthorization{}, ethTx.To() == nil, true, true, true)
+intrGas, err := core.IntrinsicGas(ethTx.Data(), ethTx.AccessList(), nil, ethTx.To() == nil, true, true, true)
x/evm/precompiles/jsonutils/contract_test.go (1)

109-117: Tests now pass a zero address as the caller – consider using a descriptive constant

Using common.Address{} works, but a well-named var (e.g. zeroAddr) or an explanatory comment would make the intent explicit and future refactors easier to grep for.

No functional change required – purely readability.

Also applies to: 165-173, 228-233, 288-295, 347-353, 411-418, 485-492, 544-551

x/evm/state/statedb.go (1)

122-143: Add/Sub balance now return nil – consider returning the updated balance.

AddBalance / SubBalance always return nil, making the new return value useless and forcing callers to sprinkle _ everywhere.
Either:

  1. Return the new balance to give the API meaning; or
  2. Change the interface back to void.

Keeping an always-nil return just adds noise.

Also applies to: 146-167

x/evm/precompiles/erc20_registry/common_test.go (1)

90-97: Replace panic("unimplemented") with safe no-op stubs in the test mock

MockStateDB now satisfies the expanded interface, but every mutated method panics.
During future refactors a single extra call path will hard-fail all tests.

Consider returning zero-values instead of panicking, e.g.:

func (m *MockStateDB) AddBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason) *uint256.Int {
    return nil // no-op for tests
}

This keeps the mock lightweight yet prevents brittle test failures.
(Methods that must not be called can still panic explicitly and be documented.)

Also applies to: 200-227, 239-242, 255-269

x/evm/precompiles/cosmos/contract_test.go (1)

84-88: Reduce duplicated “out-of-gas” assertions.

Every test repeats the triple-step pattern:

  1. call with gasLimit-1, expect revert + “out of gas” string,
  2. call with ample gas, expect success.

This boilerplate clutters the tests and hides the core intent of each case. Extracting a helper will make future tests shorter and easier to scan:

+func assertOutOfGas(t *testing.T, p *precompiles.CosmosPrecompile, caller common.Address,
+	input []byte, gas uint64, readOnly bool) {
+	output, _, err := p.ExtendedRun(caller, input, gas-1, readOnly)
+	require.ErrorIs(t, err, vm.ErrExecutionReverted)
+	require.Contains(t, string(output), "out of gas")
+}

Example usage:

-// out of gas error
-output, _, err := cosmosPrecompile.ExtendedRun(evmAddr, inputBz, precompiles.IS_BLOCKED_ADDRESS_GAS-1, true)
-require.ErrorIs(t, err, vm.ErrExecutionReverted)
-require.Contains(t, string(output), "out of gas")
+assertOutOfGas(t, cosmosPrecompile, evmAddr, inputBz, precompiles.IS_BLOCKED_ADDRESS_GAS, true)

This keeps each test focused on its unique assertions.

Also applies to: 130-134, 175-179, 219-223, 251-255, 295-297, 381-384, 422-425, 478-480, 524-527, 566-569, 598-603

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3edc63c and 241463c.

⛔ Files ignored due to path filters (2)
  • go.sum is excluded by !**/*.sum
  • integration-tests/go.sum is excluded by !**/*.sum
📒 Files selected for processing (21)
  • app/checktx/handler.go (1 hunks)
  • go.mod (9 hunks)
  • indexer/abci.go (1 hunks)
  • integration-tests/go.mod (9 hunks)
  • jsonrpc/backend/tracer.go (2 hunks)
  • x/evm/keeper/context.go (11 hunks)
  • x/evm/precompiles/cosmos/common_test.go (6 hunks)
  • x/evm/precompiles/cosmos/contract.go (3 hunks)
  • x/evm/precompiles/cosmos/contract_test.go (16 hunks)
  • x/evm/precompiles/erc20_registry/common_test.go (7 hunks)
  • x/evm/precompiles/erc20_registry/contract.go (6 hunks)
  • x/evm/precompiles/erc20_registry/contract_test.go (5 hunks)
  • x/evm/precompiles/jsonutils/common_test.go (7 hunks)
  • x/evm/precompiles/jsonutils/contract.go (2 hunks)
  • x/evm/precompiles/jsonutils/contract_test.go (9 hunks)
  • x/evm/state/statedb.go (23 hunks)
  • x/evm/state/statedb_hooked.go (1 hunks)
  • x/evm/state/statedb_test.go (5 hunks)
  • x/evm/types/dispatch.go (1 hunks)
  • x/evm/types/expected_keeper.go (1 hunks)
  • x/evm/types/tracer.go (0 hunks)
💤 Files with no reviewable changes (1)
  • x/evm/types/tracer.go
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: golangci-lint
  • GitHub Check: Run test and upload codecov
  • GitHub Check: Analyze (go)
🔇 Additional comments (22)
go.mod (4)

29-29: Bump go-ethereum to v1.15.11
The direct dependency is now aligned with upstream v1.15.11. Ensure that all StateDB interface changes from the new version are accounted for in your implementation.


35-35: Upgrade holiman/uint256 to v1.3.2
The uint256 library has been bumped to v1.3.2. No known breaking changes—tests should cover any edge cases around overflow behavior.


56-59: Refresh Go extended modules
Updated golang.org/x/crypto, golang.org/x/net, and golang.org/x/sync to their latest minor releases. These versions include security patches and performance improvements.


302-302: Point go-ethereum replace to initia-labs/evm fork
The replace directive now references the initia-labs/evm fork at the specified commit. Verify that the new hooked StateDB wrapper correctly implements tracing and matches the updated interface.

integration-tests/go.mod (9)

10-10: Align integration tests with go-ethereum v1.15.11
The integration suite now depends on go-ethereum v1.15.11 to match the main module. Run end-to-end traces to confirm compatibility.


51-51: Upgrade bits-and-blooms/bitset to v1.20.0
The indirect bitset dependency is bumped to v1.20.0. No API changes are expected.


64-65: Bump ConsenSys cryptography libs
Updated github.com/consensys/bavard and github.com/consensys/gnark-crypto to their latest minor releases. Ensure zero-knowledge proofs still validate correctly.


78-79: Refresh Crate-crypto KZG and IPA
The KZG and IPA libraries from Crate Crypto have been upgraded. Double-check any polynomial commitment flows in your tests.


90-91: Align Ethereum auxiliary modules
Upgraded ethereum/c-kzg-4844/v2 and ethereum/go-verkle to their stable releases. Run integration tests that exercise the KZG and Verkle tree functionality.


138-138: Upgrade holiman/uint256 in tests
Mirrors the bump in the main module. Test vector arithmetic to ensure consistency.


146-150: Update kvindexer submodules to v0.2.x/v0.3.x
Indexed data paths have been bumped—verify that block, NFT, and transaction indexers work end-to-end.


221-230: Refresh Go extended modules in tests
The integration tests now use the latest golang.org/x packages (crypto, net, sync, sys, term, text, time). Confirm no test harness regressions occur.


283-283: Redirect go-ethereum in integration tests
The replace rule now points to the updated initia-labs/evm fork. Ensure the integration suite picks up the correct binary and that tracing behaves as expected.

indexer/abci.go (1)

146-146: Verify MergeBloom call – possible type mismatch

coretypes.MergeBloom(receipts) will not compile if the upstream signature expects a []coretypes.Bloom (or variadic Bloom) rather than []*coretypes.Receipt.
Double-check the 1.15.11 API; if the function indeed takes blooms, convert first:

blooms := make([]coretypes.Bloom, len(receipts))
for i, r := range receipts {
	blooms[i] = r.Bloom
}
Bloom: coretypes.MergeBloom(blooms...),

Please confirm with a quick build or grep before merging.

x/evm/types/dispatch.go (1)

6-12: LGTM – caller now common.Address

The import change and the Caller field update correctly align the struct with the new upstream interfaces.

x/evm/types/expected_keeper.go (1)

95-98: Interface updated – ensure every implementation compiles

Commit() and Logs() are now required while SetTracer was removed.
Run go vet ./... to verify all concrete StateDB implementations and mocks satisfy the interface; CI will fail otherwise.

x/evm/precompiles/cosmos/contract.go (1)

287-299: Nice refactor – caller handling is now straightforward

The switch from vm.ContractRef to raw common.Address simplifies the signer comparison logic and removes a layer of indirection. Implementation looks correct and the error paths remain intact.

x/evm/precompiles/erc20_registry/contract.go (1)

47-55: Nice simplification of caller handling.

Switching from vm.ContractRef to plain common.Address removes unnecessary wrapping – good cleanup.

x/evm/precompiles/cosmos/common_test.go (1)

200-204: Returning nil from PointCache avoids panic – good.

Keeps the mock lean while satisfying the interface.

x/evm/precompiles/jsonutils/common_test.go (1)

195-199: PointCache stub updated sensibly.

Returning nil instead of panicking matches expected behaviour in tests.

x/evm/keeper/context.go (1)

268-291: Looks good – tracing setup cleanly separates hooked & bare StateDB

The conditional wrap via trySetupTracing sets evm.StateDB for both traced and non-traced paths and restores state on cleanup. Implementation reads clearly. No issues found.

x/evm/precompiles/cosmos/contract_test.go (1)

83-88: ExtendedRun caller argument now correctly uses common.Address.

Switching from vm.AccountRef(evmAddr) to the raw evmAddr matches the new ExtendedRun signature – the test compiles and the runtime behaviour is preserved.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
x/evm/state/statedb_hooked.go (2)

34-42: Hooks fire with incorrect “prev / new” balances – capture prev first
prev is fetched after mutating the balance, so both prev and newBalance are off by one operation, double-subtracting in traces. Same issue was flagged earlier and remains unfixed.

 func (s *HookedStateDB) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) *uint256.Int {
-    s.StateDB.SubBalance(addr, amount, reason)
-    if s.hooks.OnBalanceChange != nil && !amount.IsZero() {
-        prev := s.StateDB.GetBalance(addr)
-        newBalance := new(uint256.Int).Sub(prev, amount)
-        s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
+    if amount.IsZero() {
+        return nil
+    }
+    prev := s.StateDB.GetBalance(addr)              // capture before mutation
+    s.StateDB.SubBalance(addr, amount, reason)      // mutate
+    if s.hooks.OnBalanceChange != nil {
+        newBalance := new(uint256.Int).Sub(prev, amount)
+        s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
     }
     return nil
 }

46-53: Same off-by-one bug in AddBalance
prev is read after the balance has already been increased, so traces report a balance that is too high by amount.

 func (s *HookedStateDB) AddBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) *uint256.Int {
-    s.StateDB.AddBalance(addr, amount, reason)
-    if s.hooks.OnBalanceChange != nil && !amount.IsZero() {
-        prev := s.StateDB.GetBalance(addr)
-        newBalance := new(uint256.Int).Add(prev, amount)
-        s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
+    if amount.IsZero() {
+        return nil
+    }
+    prev := s.StateDB.GetBalance(addr)              // capture before mutation
+    s.StateDB.AddBalance(addr, amount, reason)      // mutate
+    if s.hooks.OnBalanceChange != nil {
+        newBalance := new(uint256.Int).Add(prev, amount)
+        s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
     }
     return nil
 }
🧹 Nitpick comments (1)
x/evm/state/statedb_hooked.go (1)

24-30: Nil-safety: guard against a nil stateDb argument
NewHookedState assumes stateDb is non-nil. A defensive check helps avoid a hard‐to-diagnose panic in callers that accidentally pass nil.

 func NewHookedState(stateDb *StateDB, hooks *tracing.Hooks) *HookedStateDB {
-    s := &HookedStateDB{stateDb, hooks}
+    if stateDb == nil {
+        panic("stateDb must not be nil")
+    }
+    s := &HookedStateDB{stateDb, hooks}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 241463c and fa31ec1.

📒 Files selected for processing (2)
  • x/evm/state/statedb.go (23 hunks)
  • x/evm/state/statedb_hooked.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • x/evm/state/statedb.go
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: golangci-lint
  • GitHub Check: Run test and upload codecov
  • GitHub Check: Analyze (go)
🔇 Additional comments (1)
x/evm/state/statedb_hooked.go (1)

55-63: Nonce hook ordering looks good
Capturing prev before mutation and supporting both V1/V2 hook signatures is correct. No issues spotted.

@djm07073 djm07073 self-assigned this Jun 19, 2025
@beer-1 beer-1 changed the title Bump/v1.15.11 feat: Pectra upgrade + EIP7702 support Sep 12, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

♻️ Duplicate comments (3)
x/evm/state/statedb_hooked.go (3)

30-38: Balance-change hooks fire with wrong "prev" / "new" values

prev is captured after calling StateDB.SubBalance, so it already contains the updated balance. As a result, the hook receives prev = newBalance, and newBalance = prev-amount → double-subtracts, reporting incorrect deltas to tracers.

Fix by grabbing prev before mutating:

 func (s *HookedStateDB) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
+    prev := s.StateDB.GetBalance(addr)              // capture pre-state
     s.StateDB.SubBalance(addr, amount, reason)      // mutate
     if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
-        prev := s.StateDB.GetBalance(addr)
         newBalance := new(uint256.Int).Sub(prev, amount)
         s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
     }
     return uint256.Int{}
 }

41-49: Balance-change hooks fire with wrong "prev" / "new" values

Same issue as SubBalance: prev is captured after calling StateDB.AddBalance, resulting in prev = newBalance and newBalance = prev+amount → double-adds.

Fix by capturing prev before mutation:

 func (s *HookedStateDB) AddBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
+    prev := s.StateDB.GetBalance(addr)
     s.StateDB.AddBalance(addr, amount, reason)
     if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
-        prev := s.StateDB.GetBalance(addr)
         newBalance := new(uint256.Int).Add(prev, amount)
         s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
     }
     return uint256.Int{}
 }

52-59: Incorrect nonce values passed to hooks

The nonce change hooks are receiving the wrong old/new values. After SetNonce is called, GetNonce returns the new value, not the old one.

Capture the old nonce before mutation:

 func (s *HookedStateDB) SetNonce(address common.Address, nonce uint64, reason tracing.NonceChangeReason) {
+    oldNonce := s.StateDB.GetNonce(address)
     s.StateDB.SetNonce(address, nonce, reason)
     if s.hooks != nil && s.hooks.OnNonceChangeV2 != nil {
-        s.hooks.OnNonceChangeV2(address, s.StateDB.GetNonce(address), nonce, reason)
+        s.hooks.OnNonceChangeV2(address, oldNonce, nonce, reason)
     } else if s.hooks != nil && s.hooks.OnNonceChange != nil {
-        s.hooks.OnNonceChange(address, s.StateDB.GetNonce(address), nonce)
+        s.hooks.OnNonceChange(address, oldNonce, nonce)
     }
 }
🧹 Nitpick comments (32)
jsonrpc/types/tx_test.go (1)

35-35: Prefer LatestSignerForChainID to reduce future fork churn.

Using a fork-agnostic signer avoids changing tests on the next hard fork while still covering Prague semantics today.

Apply this minimal change:

- signedTx, err := coretypes.SignTx(tx, coretypes.NewPragueSigner(chainID), privateKey)
+ signedTx, err := coretypes.SignTx(tx, coretypes.LatestSignerForChainID(chainID), privateKey)

LatestSignerForChainID yields a signer that includes Prague support. (pkg.go.dev)

Also applies to: 70-70, 104-104

indexer/prune.go (1)

53-58: Clarify semantics of last pruned height (consider storing pruned boundary).

Storing curHeight signals “prune ran at height H,” not “data pruned up to H-retainHeight.” If consumers (or tests) rely on “how far data is pruned,” store minHeight instead, or document/rename to avoid confusion.

Option A (boundary semantics):

- // update the last pruned height
- e.lastPrunedHeight.Store(curHeight)
+ // update the last pruned boundary (how far data is pruned)
+ e.lastPrunedHeight.Store(minHeight)

Option B (keep current behavior): add a comment/docstring that this is the “last prune trigger height,” not the pruned boundary.

indexer/prune_test.go (1)

138-143: Make waits bounded and less flaky.

Replace the busy-wait loops with Eventually to avoid indefinite spins and flakiness.

- for {
-   time.Sleep(100 * time.Millisecond)
-   if indexer.GetLastBloomIndexedHeight() < nextSectionHeight { continue } else { break }
- }
+ require.Eventually(t,
+   func() bool { return indexer.GetLastBloomIndexedHeight() >= nextSectionHeight },
+   10*time.Second, 100*time.Millisecond,
+   "bloom indexing did not reach section boundary %d", nextSectionHeight)

- for {
-   time.Sleep(100 * time.Millisecond)
-   if indexer.GetLastPrunedHeight() < nextSectionHeight { continue } else { break }
- }
+ require.Eventually(t,
+   func() bool { return indexer.GetLastPrunedHeight() >= nextSectionHeight },
+   10*time.Second, 100*time.Millisecond,
+   "pruning did not reach section boundary %d", nextSectionHeight)

Also applies to: 148-153, 161-166, 171-176

indexer/indexer.go (2)

310-312: Document getter semantics (trigger height vs. boundary).

If prune.go stores curHeight, clarify via docstring that this returns the last prune trigger height; otherwise switch to boundary and document that.

+// GetLastPrunedHeight returns the last prune trigger height (not the pruned boundary).
 func (e *EVMIndexerImpl) GetLastPrunedHeight() uint64 {

314-316: Align naming/semantics with bloom indexing progress.

If bloom.go is updated to store the processed section boundary, add a brief comment to reflect that. If not, rename to GetLastBloomObservedHeight for clarity.

+// GetLastBloomIndexedHeight returns the end height of the last fully indexed bloom section.
 func (e *EVMIndexerImpl) GetLastBloomIndexedHeight() uint64 {
.codecov.yml (1)

41-41: Add trailing newline and consider generalizing mock ignore pattern

  • YAMLlint flags a missing newline at EOF.
  • Optional: If the intent is to exclude all Go mocks from coverage, broaden the pattern beyond a single filename.

Apply:

   - "tests/"
-  - "**/mock.go"
+  - "**/mock.go"
+  - "**/*_mock.go"
+  - "**/mocks/**"
+
integration-tests/go.mod (1)

247-247: Typo in comment

“repalces” → “replaces”.

-// cosmos repalces
+// cosmos replaces
x/evm/types/txutils.go (1)

434-459: SetCodeTx construction looks correct; minor robustness nit

MustFromBig will panic on nil; unlikely here but consider FromBig + explicit error to avoid panics in edge cases.

Example tweak:

- txData = &coretypes.SetCodeTx{
-   ChainID:    uint256.MustFromBig(ethChainID),
+ cid, rV, sV, vV := uint256.FromBig(ethChainID), uint256.FromBig(new(big.Int).SetBytes(r)), uint256.FromBig(new(big.Int).SetBytes(s)), uint256.FromBig(new(big.Int).SetBytes(v))
+ if cid == nil || rV == nil || sV == nil || vV == nil { return nil, nil, ErrTxConversionFailed }
+ txData = &coretypes.SetCodeTx{
+   ChainID:    *cid,
    ...
-   R:          uint256.MustFromBig(new(big.Int).SetBytes(r)),
-   S:          uint256.MustFromBig(new(big.Int).SetBytes(s)),
-   V:          uint256.MustFromBig(new(big.Int).SetBytes(v)),
+   R:          *rV,
+   S:          *sV,
+   V:          *vV,
x/evm/types/setcode_test.go (2)

225-226: Consider using more realistic signature values for testing.

The test uses large numerical strings for R and S values, but these aren't representative of actual ECDSA signature components. Consider using realistic 256-bit values or crypto.GenerateKey() to create valid signatures for more comprehensive testing.

-	validR, _ := new(big.Int).SetString("1234567890123456789012345678901234567890123456789012345678901", 10)
-	validS, _ := new(big.Int).SetString("1234567890123456789012345678901234567890123456789012345678901", 10)
+	// Use realistic 256-bit values for ECDSA signature components
+	validR, _ := new(big.Int).SetString("89565891926547004231252920425935692360644145829622209833684329913297188986597", 10)
+	validS, _ := new(big.Int).SetString("12158399299693830322967808612713398636155367887041628176798871954788371653930", 10)

386-387: Consider improving test error message assertion.

Instead of using require.Contains for error message validation, consider checking for specific error types when possible, as string matching can be fragile if error messages change.

 err := ValidateAuthorization(ctx, auth)
 // The signature validation will fail because we're using invalid signature values
 // This is expected behavior - the test validates that signature validation is working
 require.Error(t, err)
-require.Contains(t, err.Error(), "invalid transaction v, r, s values")
+// Check for the actual error type if available, or use a more specific assertion
+// For example: require.ErrorIs(t, err, core.ErrInvalidSignature)
+require.Contains(t, err.Error(), "invalid transaction v, r, s values")
x/evm/types/txutils_test.go (1)

272-347: Consider extracting transaction creation helper to reduce duplication.

The createTestEthTx function has significant duplication in transaction data structure creation. Consider extracting common fields into a helper struct or using a builder pattern to improve maintainability.

+type testTxParams struct {
+    txType      uint8
+    to          *common.Address
+    value       *big.Int
+    data        []byte
+    gasLimit    uint64
+    gasPrice    *big.Int
+    accessList  coretypes.AccessList
+    authList    []coretypes.SetCodeAuthorization
+}
+
 func createTestEthTx(txType uint8, to *common.Address, value *big.Int, data []byte, gasLimit uint64, gasPrice *big.Int, accessList coretypes.AccessList, authList []coretypes.SetCodeAuthorization) *coretypes.Transaction {
+    params := testTxParams{
+        txType:     txType,
+        to:         to,
+        value:      value,
+        data:       data,
+        gasLimit:   gasLimit,
+        gasPrice:   gasPrice,
+        accessList: accessList,
+        authList:   authList,
+    }
+    return createTestEthTxFromParams(params)
+}
+
+func createTestEthTxFromParams(params testTxParams) *coretypes.Transaction {
     var txData coretypes.TxData
 
     ethChainID := big.NewInt(3068811972085126) // Correct chain ID for minievm-1
 
-    switch txType {
+    switch params.txType {
     case coretypes.LegacyTxType:
         txData = &coretypes.LegacyTx{
             Nonce:    0,
-            GasPrice: gasPrice,
-            Gas:      gasLimit,
-            To:       to,
-            Value:    value,
-            Data:     data,
+            GasPrice: params.gasPrice,
+            Gas:      params.gasLimit,
+            To:       params.to,
+            Value:    params.value,
+            Data:     params.data,
         }
     // ... similar changes for other cases
x/evm/keeper/msg_server.go (1)

286-295: Consider batching authorization validation for better performance.

Currently, authorizations are validated one by one in a loop. For transactions with many authorizations, consider batching the validation to reduce overhead.

 // validate set code authorizations
 var authList []coretypes.SetCodeAuthorization
 if len(setCodeAuthorizations) > 0 {
     authList, err = types.ConvertCosmosSetCodeAuthorizationsToEth(setCodeAuthorizations)
     if err != nil {
         return common.Address{}, nil, nil, nil, nil, err
     }
+    // Consider parallel validation for large authorization lists
+    if len(authList) > 10 {
+        // Implement parallel validation with error collection
+    } else {
         for _, auth := range authList {
             err = types.ValidateAuthorization(sdk.UnwrapSDKContext(ctx), auth)
             if err != nil {
                 return common.Address{}, nil, nil, nil, nil, err
             }
         }
+    }
 }
x/evm/types/tracer.go (3)

29-73: Panic early on nil evm/tracer for clearer failure mode

Right now, a nil tracer panics via field access; make it explicit (keeps Test “create_tracing_with_nil_tracer” passing).

 func NewTracing(evm *vm.EVM, tracer *tracing.Hooks) *Tracing {
+	if evm == nil || tracer == nil {
+		panic("NewTracing: evm and tracer must be non-nil")
+	}
 	return &Tracing{

83-92: Defensive copy/default for BaseFee in VMContext

If evm.Context.BaseFee is nil or later mutated, downstream tracers may trip. Copy it and default to 0 when nil.

 func tracingContext(evm *vm.EVM) *tracing.VMContext {
-	return &tracing.VMContext{
+	baseFee := evm.Context.BaseFee
+	if baseFee == nil {
+		baseFee = new(big.Int)
+	} else {
+		baseFee = new(big.Int).Set(baseFee)
+	}
+	return &tracing.VMContext{
 		Coinbase:    evm.Context.Coinbase,
 		BlockNumber: evm.Context.BlockNumber,
 		Time:        evm.Context.Time,
 		Random:      evm.Context.Random,
-		BaseFee:     evm.Context.BaseFee,
+		BaseFee:     baseFee,
 		StateDB:     evm.StateDB,
 	}
 }

94-98: Consider DynamicFeeTx for tracer helper

LegacyTx works, but DynamicFeeTx better reflects post-EIP-1559 flows. If consumers assume legacy, keep as-is.

-	return coretypes.NewTx(&coretypes.LegacyTx{
+	return coretypes.NewTx(&coretypes.DynamicFeeTx{
 		Gas: gasLimit,
 	})
x/evm/types/tracer_test.go (1)

39-40: Strengthen BaseFee assertions by setting a non-nil value

Asserting nil == nil is vacuous. Set BaseFee in the test contexts to a concrete value so we actually validate propagation.

Example change (apply to the relevant test EVM contexts before calling NewTracing/tracingContext):

evm.Context.BaseFee = big.NewInt(1_000_000_000) // 1 gwei

Also applies to: 101-102

x/evm/keeper/erc20.go (2)

208-214: Prefer contractAddr.Hex() in event attribute over ABI-encoded ret slicing

Using the unpacked address improves clarity and avoids relying on ABI padding.

Example:

sdkCtx.EventManager().EmitEvent(
  sdk.NewEvent(
    types.EventTypeERC20Created,
    sdk.NewAttribute(types.AttributeKeyDenom, denom),
    sdk.NewAttribute(types.AttributeKeyContract, contractAddr.Hex()),
  ),
)

68-76: Receiver name inconsistency (“K” vs “k”)

Minor style nit: unify the method receiver name to k for consistency with the rest of the file.

x/evm/keeper/precompiles_test.go (1)

33-71: Add a focused test that exercises non-nil auth_list

Given the new EIP-7702 flow, consider one positive/negative test that supplies a concrete auth_list to EVMCall and validates SetCode-gated behavior.

x/evm/keeper/msg_server_test.go (1)

112-116: Prefer EVMStaticCall for read-only queries.

These calls only read state and then assert no logs. Using EVMStaticCall avoids accidental writes and simplifies the assertions.

-	queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz, nil, nil, nil)
+	queryRes, err := input.EVMKeeper.EVMStaticCall(ctx, caller, contractAddr, queryInputBz, nil)
 	require.NoError(t, err)
 	require.Equal(t, uint256.NewInt(0).Bytes32(), [32]byte(queryRes))
-	require.Empty(t, logs)
@@
-	queryRes, logs, err = input.EVMKeeper.EVMCall(ctx, caller, contractAddr, queryInputBz, nil, nil, nil)
+	queryRes, err = input.EVMKeeper.EVMStaticCall(ctx, caller, contractAddr, queryInputBz, nil)
 	require.NoError(t, err)
 	require.Equal(t, uint256.NewInt(1).Bytes32(), [32]byte(queryRes))
-	require.Empty(t, logs)

Also applies to: 130-134

x/evm/precompiles/jsonutils/contract_test.go (1)

99-116: Good adaptation to ExtendedRun(caller, ...); minor DRY and resiliency nits.

  • Repeated stateDB + precompile setup can be factored to a small helper to reduce duplication.
  • Out-of-gas assertions depend on "out of gas" literal in revert data; this string may change across upstream versions. As a safety, keep ErrorIs(ErrExecutionReverted) and optionally assert a prefix rather than substring.

Example helper to reduce repetition (optional, not a required change):

func newJSONUtils(t *testing.T) (*precompiles.JSONUtilsPrecompile, sdk.Context) {
  t.Helper()
  ctx, _, _ := setup()
  db := precompiletesting.NewMockStateDB(ctx)
  c, err := precompiles.NewJSONUtilsPrecompile(db)
  require.NoError(t, err)
  return c, ctx
}

Also applies to: 155-172, 218-234, 279-295, 338-354, 401-418, 475-492, 534-551

app/ibc-hooks/ack_test.go (1)

90-94: Use EVMStaticCall for read-only checks.

These verify-only reads don’t need EVMCall or logs; static calls reduce surface area and make intent explicit.

Apply this pattern at each site:

- queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil, nil, nil)
+ queryRes, err := input.EVMKeeper.EVMStaticCall(ctx, evmAddr, contractAddr, queryInputBz, nil)
  require.NoError(t, err)
  require.Equal(t, ..., [32]byte(queryRes))
- require.Empty(t, logs)

Also applies to: 105-109, 117-121, 200-204, 215-219, 227-231

proto/minievm/evm/v1/types.proto (2)

105-113: Clarify address and storage key formats in AccessTuple docs.

Suggest documenting expected encodings (0x-prefixed 20-byte EVM address; storage keys as 0x-prefixed 32-byte hex) to avoid bech32/hex ambiguity.

 message AccessTuple {
-  // Address of the contract that will be accessed during the transaction execution.
+  // Address of the contract that will be accessed during the transaction execution.
+  // 0x-prefixed, 20-byte EVM address (hex).
   string address = 1;
 
-  // A list of storage keys that the transaction will interact with within the specified contract.
-  // These keys represent specific storage slots in the contract's storage that are accessed or modified.
+  // Storage keys (0x-prefixed, 32-byte hex) that the transaction may read/write in the contract.
   repeated string storage_keys = 2;
 }

127-133: Document signing domain and address format for SetCodeAuthorization.

To ensure interoperable validation, specify:

  • Expected address format (EVM hex).
  • Chain ID semantics (EIP-155 / eth_chainId string).
  • Signature scheme and message to sign (domain separator, exact fields, hashing).
 message SetCodeAuthorization {
-  string chain_id = 1;
-  string address = 2;
+  // EVM chain identifier used in the signing domain (string form, e.g. "0x1").
+  string chain_id = 1;
+  // Authorized EVM address (0x-prefixed, 20-byte hex).
+  string address = 2;
   uint64 nonce = 3;
-  bytes signature = 4;
+  // Signature over a well-defined message (specify hashing and domain separation in docs).
+  bytes signature = 4;
 }
proto/minievm/evm/v1/tx.proto (1)

143-146: Confirm omitempty intent for auth_list.

AccessList uses (amino.dont_omitempty)=true, while AuthList relies on default omitempty. If intentional for backward compatibility, LGTM; otherwise consider mirroring AccessList’s explicitness for consistency.

app/ibc-hooks/receive_test.go (1)

225-229: Static call is sufficient here.

Read-only verification of count can use EVMStaticCall; removes logs plumbing and avoids any accidental writes.

-	queryRes, logs, err := input.EVMKeeper.EVMCall(ctx, evmAddr, contractAddr, queryInputBz, nil, nil, nil)
+	queryRes, err := input.EVMKeeper.EVMStaticCall(ctx, evmAddr, contractAddr, queryInputBz, nil)
 	require.NoError(t, err)
 	require.Equal(t, uint256.NewInt(1).Bytes32(), [32]byte(queryRes))
-	require.Empty(t, logs)
x/evm/keeper/erc20_test.go (1)

33-35: Arity update LGTM; consider a thin helper to cut repetition.

The extra nil parameter is correct. To improve readability, add a small wrapper in tests to pass the defaulted args.

Example:

func evmCallNoAuth(ctx sdk.Context, k *keeper.EVMKeeper, from, to common.Address, input []byte) ([]byte, []types.Log, error) {
  return k.EVMCall(ctx, from, to, input, nil, nil, nil)
}

Then:

- ret, _, err := input.EVMKeeper.EVMCall(ctx, caller, factoryAddr, inputBz, nil, nil, nil)
+ ret, _, err := evmCallNoAuth(ctx, &input.EVMKeeper, caller, factoryAddr, inputBz)

Also applies to: 60-63, 78-85, 102-108, 120-126, 139-145, 157-163, 175-177, 549-555, 730-731, 767-769

x/evm/keeper/query_server.go (2)

56-59: Validate and normalize mixed address formats in AccessList/AuthList.

Ensure validateArguments enforces EVM-hex formatting for access/auth entries, rejects duplicates, and checks value overflows. If already done inside validateArguments, nothing else to do.


36-157: Trace timeout handling is sound; minor nit.

If you want slightly clearer UX on timeouts, consider prefixing the error string with a stable sentinel (e.g., "timeout: ...") to make client-side detection easier. Optional.

x/evm/keeper/context_test.go (2)

573-575: Consider using require.Equal for more informative test failures.

The current approach using t.Fatalf with manual comparison could be improved for better test diagnostics.

- code, want := state.GetCode(addr1), coretypes.AddressToDelegation(auth1.Address)
- if !bytes.Equal(code, want) {
-     t.Fatalf("addr1 code incorrect: got %s, want %s", common.Bytes2Hex(code), common.Bytes2Hex(want))
- }
+ code := state.GetCode(addr1)
+ want := coretypes.AddressToDelegation(auth1.Address)
+ require.Equal(t, want, code, "addr1 code incorrect")

576-579: Consider using require.Equal for consistency.

Similar to the previous comment, use require.Equal for better test consistency.

- code, want = state.GetCode(addr2), coretypes.AddressToDelegation(auth2.Address)
- if !bytes.Equal(code, want) {
-     t.Fatalf("addr2 code incorrect: got %s, want %s", common.Bytes2Hex(code), common.Bytes2Hex(want))
- }
+ code = state.GetCode(addr2)
+ want = coretypes.AddressToDelegation(auth2.Address)
+ require.Equal(t, want, code, "addr2 code incorrect")
x/evm/keeper/context_utils.go (1)

6-7: Remove unused import.

The fmt import appears to be used only for error formatting in the new functions. Consider if all error cases truly need formatted errors or if some could use error wrapping instead.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 92ec4b4 and 8fcad63.

⛔ Files ignored due to path filters (5)
  • go.sum is excluded by !**/*.sum
  • integration-tests/go.sum is excluded by !**/*.sum
  • x/evm/types/query.pb.go is excluded by !**/*.pb.go
  • x/evm/types/tx.pb.go is excluded by !**/*.pb.go
  • x/evm/types/types.pb.go is excluded by !**/*.pb.go
📒 Files selected for processing (47)
  • .codecov.yml (1 hunks)
  • app/ibc-hooks/ack_test.go (6 hunks)
  • app/ibc-hooks/receive_test.go (1 hunks)
  • app/ibc-hooks/timeout_test.go (4 hunks)
  • go.mod (9 hunks)
  • indexer/abci.go (1 hunks)
  • indexer/bloom.go (1 hunks)
  • indexer/indexer.go (3 hunks)
  • indexer/prune.go (1 hunks)
  • indexer/prune_test.go (3 hunks)
  • integration-tests/erc721_transfer_test.go (1 hunks)
  • integration-tests/go.mod (9 hunks)
  • integration-tests/wrapper_test.go (4 hunks)
  • jsonrpc/backend/tracer.go (4 hunks)
  • jsonrpc/types/tx_test.go (3 hunks)
  • proto/minievm/evm/v1/query.proto (1 hunks)
  • proto/minievm/evm/v1/tx.proto (1 hunks)
  • proto/minievm/evm/v1/types.proto (2 hunks)
  • x/bank/keeper/grpc_query_test.go (1 hunks)
  • x/evm/keeper/common_test.go (2 hunks)
  • x/evm/keeper/context.go (16 hunks)
  • x/evm/keeper/context_test.go (18 hunks)
  • x/evm/keeper/context_utils.go (4 hunks)
  • x/evm/keeper/erc20.go (4 hunks)
  • x/evm/keeper/erc20_test.go (11 hunks)
  • x/evm/keeper/erc721.go (3 hunks)
  • x/evm/keeper/fuzz_test.go (1 hunks)
  • x/evm/keeper/genesis.go (1 hunks)
  • x/evm/keeper/msg_server.go (5 hunks)
  • x/evm/keeper/msg_server_test.go (2 hunks)
  • x/evm/keeper/precompiles_test.go (14 hunks)
  • x/evm/keeper/query_server.go (2 hunks)
  • x/evm/keeper/txutils_test.go (10 hunks)
  • x/evm/precompiles/cosmos/contract_test.go (26 hunks)
  • x/evm/precompiles/cosmos/types.go (1 hunks)
  • x/evm/precompiles/erc20_registry/contract_test.go (7 hunks)
  • x/evm/precompiles/jsonutils/contract_test.go (18 hunks)
  • x/evm/precompiles/testing/mock.go (8 hunks)
  • x/evm/state/statedb.go (13 hunks)
  • x/evm/state/statedb_hooked.go (1 hunks)
  • x/evm/state/statedb_test.go (7 hunks)
  • x/evm/types/expected_keeper.go (1 hunks)
  • x/evm/types/setcode_test.go (1 hunks)
  • x/evm/types/tracer.go (1 hunks)
  • x/evm/types/tracer_test.go (2 hunks)
  • x/evm/types/txutils.go (10 hunks)
  • x/evm/types/txutils_test.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • indexer/abci.go
  • x/evm/precompiles/erc20_registry/contract_test.go
  • jsonrpc/backend/tracer.go
  • x/evm/types/expected_keeper.go
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.codecov.yml

[error] 41-41: no new line character at the end of file

(new-line-at-end-of-file)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: golangci-lint
  • GitHub Check: Run test and upload codecov
  • GitHub Check: Analyze (go)
🔇 Additional comments (65)
jsonrpc/types/tx_test.go (2)

35-35: LGTM: Switching to NewPragueSigner matches Pectra/EIP-7702 rules.

Using coretypes.NewPragueSigner is correct for v1.15.11-era signing (covers legacy, 2930, 1559, 4844, and 7702 set-code txs). (pkg.go.dev)

Also applies to: 70-70, 104-104


117-173: No additional test required — SetCodeTx (0x04) auth‑list round‑trip is already covered.
Repo already contains tests exercising SetCodeTx and SetCodeAuthorization conversions that preserve the auth list (e.g. TestSetCodeAuthorizationRoundTrip and tests that construct/sign SetCodeTx with authList via createTestEthTx/setCodeTx).

indexer/bloom.go (1)

90-92: ```shell
#!/bin/bash
set -euo pipefail
echo "PWD: $(pwd)"

echo "---- print indexer/bloom.go (with line numbers) ----"
if [ -f indexer/bloom.go ]; then cat -n indexer/bloom.go | sed -n '1,400p'; else echo "indexer/bloom.go not found"; fi

echo "---- show surrounding lines for Store(height) ----"
rg -n "Store\(height\)" -C6 || true

echo "---- search for 'section' and 'SectionSize' in repo ----"
rg -n --hidden '\bsection\b' -S || true
rg -n --hidden 'SectionSize' -S || true

echo "---- search for 'evmconfig' in repo ----"
rg -n --hidden 'evmconfig' -S || true

echo "---- print indexer/indexer.go (with line numbers) ----"
if [ -f indexer/indexer.go ]; then cat -n indexer/indexer.go | sed -n '1,420p'; else echo "indexer/indexer.go not found"; fi


</blockquote></details>
<details>
<summary>indexer/prune_test.go (2)</summary><blockquote>

`155-155`: **No action needed.**

Comment-only change; nothing to review.

---

`129-133`: **Resolved — go.mod already targets Go 1.23.6 (>= 1.22)**

Root and integration go.mod declare `go 1.23.6`, so the integer-range `for` usage is supported; ensure CI uses the same toolchain.

</blockquote></details>
<details>
<summary>indexer/indexer.go (2)</summary><blockquote>

`102-107`: **LGTM: atomic fields for progress and running state.**

Appropriate use of atomic types for cross-goroutine reads/writes.

---

`187-192`: **LGTM: proper initialization in constructor.**

Fields are instantiated; no races on first Load/Store.

</blockquote></details>
<details>
<summary>x/evm/keeper/genesis.go (1)</summary><blockquote>

`85-85`: **EVMCall arity update looks correct**

Passing nil for the new authList arg is appropriate for setFactory.

</blockquote></details>
<details>
<summary>x/evm/keeper/common_test.go (1)</summary><blockquote>

`43-45`: **Good addition: register cryptocodec in test encodings**

Ensures crypto types are available in both amino and interface registry. 



Also applies to: 89-91

</blockquote></details>
<details>
<summary>x/evm/keeper/fuzz_test.go (1)</summary><blockquote>

`59-60`: **EVMCall signature adjustment acknowledged**

Extra trailing nil matches the new API.

</blockquote></details>
<details>
<summary>x/evm/keeper/erc721.go (3)</summary><blockquote>

`126-127`: **Transfers: EVMCall updated arity is correct**

No auth list needed; nil is fine.

---

`143-144`: **Burn: EVMCall updated arity is correct**

Invocation is consistent with new API.

---

`195-196`: **Mint: EVMCall updated arity is correct**

Caller and args remain unchanged; nil auth is appropriate.

</blockquote></details>
<details>
<summary>integration-tests/go.mod (1)</summary><blockquote>

`10-11`: **CI/go toolchain + geth fork replace verified — no action required**

- .github workflows (test.yml, lint.yml, build-*.yml) use actions/setup-go with go-version: 1.23.
- go.mod and integration-tests/go.mod declare go 1.23.6 (go.mod:3; integration-tests/go.mod:3).
- Both modules include a replace mapping github.com/ethereum/go-ethereum => github.com/initia-labs/evm (go.mod:302; integration-tests/go.mod:283).

</blockquote></details>
<details>
<summary>x/evm/types/txutils.go (6)</summary><blockquote>

`130-134`: **Signer handling includes SetCodeTxType — good**

v/r/s extraction logic covers 7702 alongside legacy/1559.

---

`281-283`: **Supported types updated to include SetCodeTxType**

Early-return filter is consistent with new tx type.

---

`519-539`: **ETH→Cosmos authorization conversion — LGTM**

Signature packing (R||S||V) and decimal chainID serialization are consistent.

---

`541-576`: **Cosmos→ETH authorization conversion — LGTM**

Length checks and address decoding are sound; returns typed 7702 auths.

---

`579-594`: **Authorization validator is appropriate; ensure it’s enforced**

ChainID check (allow zero), nonce overflow, and Authority() verification cover key cases. Confirm this runs in ante/handler for MsgCall with AuthList.

---

`169-179`: **Auth validation implemented and invoked in handler**

ValidateAuthorization is implemented (x/evm/types/txutils.go) and called for each auth in the msg handler (x/evm/keeper/msg_server.go:291); tests exercise chainID and signature checks — confirm whether nonce validation is required and present.

</blockquote></details>
<details>
<summary>go.mod (1)</summary><blockquote>

`111-112`: **Security review required for new cryptographic dependencies**

File: go.mod (lines 111–112). gh API query returned no known advisories for github.com/crate-crypto/go-eth-kzg, but introducing crypto libraries still requires a manual security review. Actions:
- Verify provenance and pin/approve the exact versions (github.com/crate-crypto/go-eth-kzg v1.3.0; github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a).
- Run SCA scanners (Dependabot/Snyk/OSV), audit or peer-review cryptographic code, and review transitive deps (gnark-crypto, c-kzg-4844).
- Enforce go.sum/module checksum verification in CI.

</blockquote></details>
<details>
<summary>x/evm/keeper/msg_server.go (1)</summary><blockquote>

`263-299`: **LGTM! Authorization validation implementation is thorough.**

The `validateArguments` function correctly handles the new SetCode authorization flow:
1. Properly converts Cosmos authorizations to Ethereum format
2. Validates each authorization against the current chain context
3. Returns appropriate errors on validation failure

The implementation aligns well with EIP-7702 requirements.

</blockquote></details>
<details>
<summary>proto/minievm/evm/v1/query.proto (1)</summary><blockquote>

`202-204`: **Add (amino.dont_omitempty) = true to auth_list and regenerate protos**

Mirror access_list to avoid accidental omission in amino JSON.

```diff
-  repeated SetCodeAuthorization auth_list = 7 [(gogoproto.nullable) = false];
+  repeated SetCodeAuthorization auth_list = 7 [
+    (gogoproto.nullable) = false,
+    (amino.dont_omitempty) = true
+  ];

Regenerate protos and confirm generated files (e.g. query.pb.go and other language bindings) include the change (run the rg/fd checks you used). Current search output shows only the generated Go file containing AuthList without an omitempty tag, so regeneration is required.

integration-tests/erc721_transfer_test.go (1)

80-81: EVMCall signature update looks correct

Callsite updated to pass the new trailing auth parameter (nil here). No further changes needed.

x/bank/keeper/grpc_query_test.go (1)

167-168: EVMCall arity bump acknowledged

Test adjusted to 7-arg EVMCall. LGTM.

app/ibc-hooks/timeout_test.go (1)

85-85: EVMCall arity updates (nil auth) are consistent

Repo sweep shows all EVMCall call sites include nil for the added auth parameter — no changes required.

x/evm/keeper/erc20.go (1)

106-106: Approve — nil auth_list is correct for these EVMCall sites

These calls invoke token/factory functions (sudoBurn/sudoMint/sudoTransfer/create) which do not perform SetCode; applyAuthorizations only applies SetCode when a non-empty authList (SetCode tx / EIP‑7702) is provided, so passing nil is correct.
Applies to x/evm/keeper/erc20.go lines 106, 155, 188, 287 (and the analogous call sites found by the repo scan).

x/evm/keeper/precompiles_test.go (1)

66-66: All EVMCall sites updated to new signature

Calls now pass the trailing auth arg (nil). Looks good.

Also applies to: 96-96, 140-140, 176-176, 208-208, 228-228, 272-272, 513-513, 530-530, 551-551

x/evm/precompiles/jsonutils/contract_test.go (1)

13-16: Imports change LGTM; consistent with new ExtendedRun signature and test scaffolding.

Also applies to: 29-33

x/evm/keeper/query_server.go (3)

45-48: Better input validation path.

Converting sender via AddressCodec and surfacing InvalidArgument is correct and matches the rest of the service. LGTM.


112-119: EVMCreate/EVMCall argument propagation looks correct.

Access lists are carried to both create/call; auth list only to call. Matches expected EIP-7702 behavior. LGTM.


112-119: Repo-wide sanity check — find any 6-arg EVMCall usages

Run the script below and fix any EVMCall callsites that report args=6.

#!/bin/bash
# Repo-wide search for EVMCall call sites and report argument counts (excludes vendor/.git/node_modules/dist/build)
set -euo pipefail
python3 - <<'PY'
import os, re, sys
root='.'
skip_dirs = {'vendor', '.git', 'node_modules', 'dist', 'build'}
pat = re.compile(r'\bEVMCall\s*\(')
total = 0
for dirpath, dirnames, filenames in os.walk(root):
    dirnames[:] = [d for d in dirnames if d not in skip_dirs]
    for fname in filenames:
        if not fname.endswith('.go'):
            continue
        path = os.path.join(dirpath, fname)
        try:
            s = open(path, 'r', encoding='utf-8', errors='ignore').read()
        except Exception as e:
            print(f"SKIP {path}: {e}", file=sys.stderr)
            continue
        for m in pat.finditer(s):
            start = m.end()
            i = start
            depth = 1
            in_string = None
            escaped = False
            while i < len(s) and depth > 0:
                ch = s[i]
                if escaped:
                    escaped = False
                elif ch == '\\':
                    escaped = True
                elif in_string:
                    if ch == in_string:
                        in_string = None
                else:
                    if ch in ('"', "'", '`'):
                        in_string = ch
                    elif ch == '(':
                        depth += 1
                    elif ch == ')':
                        depth -= 1
                i += 1
            if depth != 0:
                continue
            args_text = s[start:i-1].strip()
            if not args_text:
                arg_count = 0
            else:
                depth2 = 0
                in_string = None
                escaped = False
                commas = 0
                for ch in args_text:
                    if escaped:
                        escaped = False
                    elif ch == '\\':
                        escaped = True
                    elif in_string:
                        if ch == in_string:
                            in_string = None
                    else:
                        if ch in ('"', "'", '`'):
                            in_string = ch
                        elif ch == '(':
                            depth2 += 1
                        elif ch == ')':
                            depth2 -= 1
                        elif ch == ',' and depth2 == 0:
                            commas += 1
                arg_count = commas + 1
            lineno = s.count('\\n', 0, m.start()) + 1
            snippet = s[m.start():i].splitlines()[0][:300].replace('\\n',' ')
            print(f"{path}:{lineno}: args={arg_count}: {snippet}")
            total += 1
print(f"TOTAL EVMCall occurrences: {total}")
PY
integration-tests/wrapper_test.go (4)

148-149: LGTM! API change correctly applied.

The addition of the nil parameter as the seventh argument to EVMCall is consistent with the PR's broader API update for EIP7702 authorization support.


159-160: LGTM! Consistent API update.

The nil authorization parameter is correctly added to the second EVMCall invocation.


195-196: LGTM! API change consistently applied in approve operation.

The authorization parameter is correctly passed as nil when approving the wrapper contract.


464-465: LGTM! Authorization parameter added to unwrapRemote.

The nil authorization parameter is correctly added to the EVMCall for the approve operation in the unwrap flow.

x/evm/keeper/context_test.go (3)

103-104: LGTM! Authorization parameter correctly added to all EVMCall invocations.

The addition of the nil authorization parameter is consistently applied across all test cases.

Also applies to: 112-113, 122-123


509-586: Well-structured EIP7702 test implementation!

The test comprehensively covers the EIP7702 SetCodeAuthorization functionality:

  • Properly sets up signers with funding
  • Creates and signs authorizations with appropriate chain ID handling
  • Deploys code and sets up delegation chains
  • Verifies both delegation setup and storage writes

The test effectively validates the core EIP7702 functionality.


3-25: Incorrect — bytes and fmt are used in x/evm/keeper/context_test.go

fmt.Sprintf at lines 280, 301, 343, 384, 402, 493; bytes.Equal at lines 573 and 577 — imports are used, no removal required.

Likely an incorrect or invalid review comment.

x/evm/precompiles/cosmos/contract_test.go (3)

36-37: LGTM! Successful migration to precompiletesting mocks.

The transition from local mocks to the centralized precompiletesting package improves code organization and maintainability. Field renaming (Accounts, BlockedAddresses) follows Go naming conventions.

Also applies to: 61-62


85-86: LGTM! Caller type correctly updated to common.Address.

The change from vm.AccountRef(evmAddr) to direct evmAddr aligns with the updated ExtendedRun signature that now accepts common.Address directly.

Also applies to: 89-90


318-319: Verify ExecuteRequest.Caller type change — ensure consumers accept common.Address

Automated grep/ast-grep returned no matches; manual verification required. ExecuteRequest.Caller now holds raw evmAddr (common.Address) instead of vm.AccountRef(evmAddr); confirm all consumers, tests, and the ExecuteRequest type expect common.Address and update any vm.AccountRef(...) usages.

Location: x/evm/precompiles/cosmos/contract_test.go (lines 318–319, 397–398)

x/evm/keeper/context_utils.go (4)

96-113: Well-implemented recursive depth control!

The function properly manages recursive depth to prevent stack overflow attacks, with a clear maximum depth limit. The context-based approach for tracking depth is clean and thread-safe.


115-142: Excellent tracing implementation with proper cleanup!

The decorator pattern for adding tracing support is well-designed:

  • Clean separation of concerns
  • Proper state restoration via cleanup function
  • No-op path for non-traced execution

The hooked StateDB wrapper enables comprehensive tracing without modifying core execution logic.


144-154: LGTM! Proper intrinsic gas calculation for EIP7702.

The function correctly includes the authorization list in intrinsic gas calculation, which is essential for EIP7702 support. The detailed error message aids debugging.


195-234: Comprehensive EIP7702 authorization implementation!

The implementation correctly handles all aspects of SetCodeAuthorization:

  • Signature validation and public key extraction
  • Access list management
  • Nonce verification to prevent replay attacks
  • Gas refunds for existing accounts
  • Proper delegation setup

This is a critical security component that appears well-implemented.

x/evm/state/statedb_test.go (4)

196-197: LGTM! API updates correctly applied.

The addition of the nil authorization parameter to EVMCall is consistent with the broader API changes for EIP7702 support.

Also applies to: 201-202


273-274: Method name corrected to match Go-ethereum conventions.

The rename from Selfdestruct6780 to SelfDestruct6780 aligns with Go naming conventions and matches the upstream go-ethereum implementation.


306-307: LGTM! Direct caller usage in EVM methods.

The removal of vm.AccountRef wrapper aligns with the simplified API where addresses are passed directly.

Also applies to: 317-318, 327-328


358-359: Tracing support properly integrated.

The addition of the reason parameter to SetNonce enables detailed tracing of nonce changes, which is valuable for debugging and auditing EVM execution.

Also applies to: 361-362

x/evm/precompiles/testing/mock.go (4)

1-1: LGTM! Package rename aligns with Go conventions

The package rename from cosmosprecompile_test to precompiletesting follows Go naming conventions and better reflects its purpose as a testing utility package.


96-98: Good: Updated return types align with new StateDB interface

The updated method signatures now properly return values (uint256.Int, []byte, common.Hash) as required by the new StateDB interface, replacing the previous void returns.

Also applies to: 211-213, 216-218, 221-223, 226-228, 231-233, 246-248


201-203: Correct: PointCache returns nil instead of panicking

Returning nil for PointCache() is appropriate since it's not used in the current implementation, making tests more stable.


280-283: Improved field visibility for test mocks

Making mock fields public (Codec, Accounts, BlockedAddresses, Routes, DenomMap, AddrMap) improves testability by allowing test code to directly set up mock state.

Also applies to: 330-332, 343-344, 353-355

x/evm/keeper/context.go (5)

188-204: LGTM! Proper StateDB interface usage and tracing decoration

The refactoring properly separates StateDB creation, tracing decoration, and EVM configuration. The cleanup function ensures proper resource management for tracing.


285-287: Good addition: SetCodeAuthorization support

The addition of applyAuthorizations properly implements EIP-7702 support for delegated code execution.


323-327: Correct: StateDB commits through interface

The type assertion to types.StateDB interface and calling Commit() maintains proper abstraction while allowing for decorated StateDB implementations.

Also applies to: 446-450


221-221: LGTM! Proper intrinsic gas calculation with auth list

The chargeIntrinsicGas calls correctly include the authList parameter for EIP-7702 authorization support.

Also applies to: 272-272, 393-393


576-576: Consistent nil parameters for EVMCall

The call to EVMCall with nil values for value, accessList, and authList is appropriate for callback execution.

x/evm/state/statedb.go (6)

127-148: LGTM! Clean ERC20-based balance operations

The AddBalance and SubBalance implementations properly delegate to ERC20 sudoMint/sudoBurn operations, maintaining consistency with the ERC20-based fee model. The comments clearly explain that return values are for interface compliance only.

Also applies to: 153-174


382-421: Well-implemented SetCode with account conversion

The SetCode implementation properly handles:

  • Base account to contract account conversion
  • Preservation of AccountNumber, Sequence, and PubKey (for EIP-7702)
  • Previous code retrieval and return
  • Code hash and size storage

490-502: Good addition: SetNonceAndPubKey for EIP-7702

The new method supports setting both nonce and public key atomically, which is essential for EIP-7702 SetCodeAuthorization support.


551-566: Correct SelfDestruct implementations

Both SelfDestruct and SelfDestruct6780 properly return previous balances and handle the distinction between same-transaction and cross-transaction self-destructs as per EIP-6780.

Also applies to: 569-586


589-595: Proper SetState with previous value return

SetState correctly captures and returns the previous state value before updating, supporting proper state transition tracking.


812-819: Appropriate no-op implementations

The AccessEvents and Finalise methods are correctly implemented as no-ops since state finalization is handled in Commit, matching the EVM interface requirements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (4)
x/evm/types/txutils_test.go (1)

339-349: Don’t ignore keygen/sign errors; make helper test-aware.

You're still discarding errors from ecdsa.GenerateKey and coretypes.SignTx, which can mask failures in tests. Convert this helper into a test helper accepting *testing.T, use crypto.GenerateKey (or rand.Reader directly), and assert errors. Also guard SetCodeTx’s non-nil To to avoid potential panics later.

-func createTestEthTx(txType uint8, to *common.Address, value *big.Int, data []byte, gasLimit uint64, gasPrice *big.Int, accessList coretypes.AccessList, authList []coretypes.SetCodeAuthorization) *coretypes.Transaction {
+func createTestEthTx(t *testing.T, txType uint8, to *common.Address, value *big.Int, data []byte, gasLimit uint64, gasPrice *big.Int, accessList coretypes.AccessList, authList []coretypes.SetCodeAuthorization) *coretypes.Transaction {
+	t.Helper()
   var txData coretypes.TxData
-  ethChainID := big.NewInt(3068811972085126) // Correct chain ID for minievm-1
+  ethChainID := big.NewInt(3068811972085126) // minievm-1

   switch txType {
@@
-  case coretypes.SetCodeTxType:
+  case coretypes.SetCodeTxType:
+    if to == nil {
+      t.Fatalf("SetCodeTx requires a non-nil 'to' address")
+    }
     txData = &coretypes.SetCodeTx{
@@
-  ethTx := coretypes.NewTx(txData)
-
-  // Generate a real private key and sign the transaction
-  randBytes := make([]byte, 64)
-  _, err := rand.Read(randBytes)
-  if err != nil {
-    panic(err)
-  }
-  reader := bytes.NewReader(randBytes)
-  privKey, _ := ecdsa.GenerateKey(crypto.S256(), reader)
-  signer := coretypes.LatestSignerForChainID(ethChainID)
-  signedTx, _ := coretypes.SignTx(ethTx, signer, privKey)
-  return signedTx
+  ethTx := coretypes.NewTx(txData)
+  privKey, err := crypto.GenerateKey()
+  require.NoError(t, err)
+  signer := coretypes.LatestSignerForChainID(ethChainID)
+  signedTx, err := coretypes.SignTx(ethTx, signer, privKey)
+  require.NoError(t, err)
+  return signedTx
 }

Apply the mechanical call-site change below.

-ethTx: createTestEthTx(
+ethTx: createTestEthTx(t,

Affects lines: 386-395, 401-410, 416-439, 445-463, 469-487, 873-882, 1050-1059, 1114-1123, 1185-1194.

x/evm/state/statedb_hooked.go (3)

29-38: Fix balance-change hook ordering and return the correct previous balance

Hooks use post-mutation state and the method returns a zero value. Capture pre-state by value, emit prev→new after mutation, and return prev.

 func (s *HookedStateDB) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
-	s.StateDB.SubBalance(addr, amount, reason)
-	if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
-		prev := s.StateDB.GetBalance(addr)
-		newBalance := new(uint256.Int).Sub(prev, amount)
-		s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
-	}
-	return uint256.Int{}
+	// capture pre-state by value to avoid aliasing
+	prev := *s.StateDB.GetBalance(addr)
+	s.StateDB.SubBalance(addr, amount, reason)
+	if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
+		newBal := *s.StateDB.GetBalance(addr)
+		s.hooks.OnBalanceChange(addr, prev.ToBig(), newBal.ToBig(), reason)
+	}
+	return prev
 }

40-49: Same issues in AddBalance: wrong prev/new and zero return

Mirror the SubBalance fix: capture prev, mutate, emit prev→new, return prev.

 func (s *HookedStateDB) AddBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
-	s.StateDB.AddBalance(addr, amount, reason)
-	if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
-		prev := s.StateDB.GetBalance(addr)
-		newBalance := new(uint256.Int).Add(prev, amount)
-		s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
-	}
-	return uint256.Int{}
+	prev := *s.StateDB.GetBalance(addr)
+	s.StateDB.AddBalance(addr, amount, reason)
+	if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
+		newBal := *s.StateDB.GetBalance(addr)
+		s.hooks.OnBalanceChange(addr, prev.ToBig(), newBal.ToBig(), reason)
+	}
+	return prev
 }

139-158: Commit: deferred commit clobbers returned errors; also callback returns shadowed err

Preserve walk errors and commit errors without overwriting; return nil from callback unless you actually produce an error.

-func (s *HookedStateDB) Commit() (err error) {
-	defer func() {
-		err = s.StateDB.Commit()
-	}()
+func (s *HookedStateDB) Commit() (err error) {
+	defer func() {
+		if cerr := s.StateDB.Commit(); cerr != nil && err == nil {
+			err = cerr
+		}
+	}()

 	if s.hooks != nil && s.hooks.OnBalanceChange != nil {
-		return s.memStoreSelfDestruct.Walk(s.ctx, nil, func(key []byte) (stop bool, err error) {
+		if walkErr := s.memStoreSelfDestruct.Walk(s.ctx, nil, func(key []byte) (stop bool, err error) {
 			addr := common.BytesToAddress(key)

 			// If ether was sent to account post-selfdestruct it is burnt.
 			if bal := s.GetBalance(addr); bal.Sign() != 0 {
 				s.hooks.OnBalanceChange(addr, bal.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn)
 			}

-			return false, err
-		})
+			return false, nil
+		}); walkErr != nil {
+			return walkErr
+		}
 	}

 	return nil
 }
🧹 Nitpick comments (5)
x/evm/types/txutils_test.go (3)

651-653: Brittle string match on error.

Error strings from go-ethereum can change. Prefer require.ErrorContains with a broader substring, or drop the substring assertion.

- require.Contains(t, err.Error(), "invalid chain id for signer")
+ require.ErrorContains(t, err, "chain id")

254-263: Mock address codec: note on unchecked inputs.

BytesToString/StringToBytes accept any length and always succeed. Fine for tests, but add a brief comment to make this explicit to future readers.


276-278: Minor: de-duplicate chain ID and use a helper for address pointers.

The minievm chain ID literal is repeated. Define a module-level constant and a small addrPtr helper to reduce noise from &[]addr{...}[0].

Additional changes outside this hunk:

// near top-level (after imports)
const minievmChainID = 3068811972085126

func addrPtr(a common.Address) *common.Address { return &a }

Then replace:

  • big.NewInt(3068811972085126) -> big.NewInt(minievmChainID)
  • &[]common.Address{common.HexToAddress("0x...")}[0] -> addrPtr(common.HexToAddress("0x..."))


Also applies to: 290-299, 300-311, 312-323

</blockquote></details>
<details>
<summary>x/evm/state/statedb_hooked.go (2)</summary><blockquote>

`62-72`: **Nit: use EmptyCodeHash symmetry for new code too**

For readability, mirror prev-hash handling and avoid recomputing when code is empty.


```diff
 	prev := s.StateDB.SetCode(address, code)
 	if s.hooks != nil && s.hooks.OnCodeChange != nil {
 		prevHash := evmtypes.EmptyCodeHash
 		if len(prev) != 0 {
 			prevHash = crypto.Keccak256Hash(prev)
 		}
-		s.hooks.OnCodeChange(address, prevHash, prev, crypto.Keccak256Hash(code), code)
+		newHash := evmtypes.EmptyCodeHash
+		if len(code) != 0 {
+			newHash = crypto.Keccak256Hash(code)
+		}
+		s.hooks.OnCodeChange(address, prevHash, prev, newHash, code)
 	}

144-155: Don't access StateDB internals from the wrapper — add and use a StateDB walker for self-destructed accounts.

  • s.memStoreSelfDestruct and s.ctx are private internals; expose a method (e.g., StateDB.WalkSelfDestructed(ctx, fn)) and call it here to preserve encapsulation.
  • If adding an API isn't possible now, qualify the access via s.StateDB.memStoreSelfDestruct (not s.memStoreSelfDestruct) and add a TODO to replace it with a proper method.
    Location: x/evm/state/statedb_hooked.go:144-155
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 8fcad63 and aefed67.

📒 Files selected for processing (2)
  • x/evm/state/statedb_hooked.go (1 hunks)
  • x/evm/types/txutils_test.go (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: golangci-lint
  • GitHub Check: Run test and upload codecov
  • GitHub Check: Analyze (go)
🔇 Additional comments (9)
x/evm/types/txutils_test.go (4)

108-183: Gas enforcement tests look solid.

Good coverage of boundary conditions: unlimited senders, caps, zero values disabling enforcement.


202-219: Rounding tests: clear and useful.

The rounding-up behaviors are exercised for both 18 and 0 decimals.


221-252: Access list conversion round-trip is well covered.

Nice checks for checksum casing and 32-byte padding.


531-547: Good metadata verification.

Decoding memo into txMetadata and checking type/gas limits strengthens the round‑trip test.

x/evm/state/statedb_hooked.go (5)

75-81: Storage hook looks good

Emits only on actual change; simple and correct.


84-104: SelfDestruct: correct ordering and emissions

Pre-capture code/hash, emit balance-to-zero and code wipe. Looks correct.


107-127: SelfDestruct6780: LGTM

Conditional emissions align with changed flag. Good.


130-136: Log hook ordering is correct

Underlying AddLog first, then emit. Good.


29-49: No callers depend on AddBalance/SubBalance return value — safe to return prev.
Repo scan found calls only in x/evm/state/statedb_test.go, x/evm/state/statedb.go, and x/evm/keeper/msg_server.go; none assign or inspect the returned value.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (3)
x/evm/state/statedb_hooked.go (3)

30-38: Balance-change hooks fire with wrong "prev" / "new" values

The SubBalance method captures the previous balance after calling StateDB.SubBalance, meaning it gets the already-updated balance. As a result, the hook receives incorrect values where prev equals the new balance.

Apply this fix to capture the balance before mutation:

 func (s *HookedStateDB) SubBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
-	s.StateDB.SubBalance(addr, amount, reason)
-	if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
-		prev := s.StateDB.GetBalance(addr)
-		newBalance := new(uint256.Int).Sub(prev, amount)
+	prev := s.StateDB.GetBalance(addr)              // capture pre-state
+	s.StateDB.SubBalance(addr, amount, reason)      // mutate
+	if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
+		newBalance := new(uint256.Int).Sub(prev, amount)
 		s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
-	}
-	return uint256.Int{}
+	}
+	return prev
 }

41-49: Balance-change hooks fire with wrong "prev" / "new" values

The AddBalance method has the same issue as SubBalance - it captures the previous balance after calling StateDB.AddBalance, resulting in incorrect hook values.

Apply this fix:

 func (s *HookedStateDB) AddBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
-	s.StateDB.AddBalance(addr, amount, reason)
-	if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
-		prev := s.StateDB.GetBalance(addr)
-		newBalance := new(uint256.Int).Add(prev, amount)
+	prev := s.StateDB.GetBalance(addr)
+	s.StateDB.AddBalance(addr, amount, reason)
+	if s.hooks != nil && s.hooks.OnBalanceChange != nil && !amount.IsZero() {
+		newBalance := new(uint256.Int).Add(prev, amount)
 		s.hooks.OnBalanceChange(addr, prev.ToBig(), newBalance.ToBig(), reason)
-	}
-	return uint256.Int{}
+	}
+	return prev
 }

140-159: Multiple issues with the Commit method

There are several problems with this implementation:

  1. Deferred error handling: The deferred commit doesn't capture its error value
  2. Undefined field access: Direct access to memStoreSelfDestruct and ctx fields that are unexported in the embedded StateDB
  3. Wrong return logic: The function may return nil even when the underlying commit fails

The field access issue needs to be resolved by exposing a method on StateDB or making the necessary fields accessible. For the error handling:

 func (s *HookedStateDB) Commit() (err error) {
-	defer func() {
-		err = s.StateDB.Commit()
-	}()
+	defer func() {
+		if cerr := s.StateDB.Commit(); cerr != nil && err == nil {
+			err = cerr
+		}
+	}()

 	if s.hooks != nil && s.hooks.OnBalanceChange != nil {
-		return s.memStoreSelfDestruct.Walk(s.ctx, nil, func(key []byte) (stop bool, err error) {
+		// This needs to be exposed through a method on StateDB
+		// For example: s.StateDB.WalkSelfDestructed(func(addr common.Address) error { ... })
+		return s.StateDB.WalkSelfDestructed(func(addr common.Address) error {
-			addr := common.BytesToAddress(key)
-
 			// If ether was sent to account post-selfdestruct it is burnt.
 			if bal := s.GetBalance(addr); bal.Sign() != 0 {
 				s.hooks.OnBalanceChange(addr, bal.ToBig(), new(big.Int), tracing.BalanceDecreaseSelfdestructBurn)
 			}

-			return false, err
+			return nil
 		})
 	}

 	return nil
 }
🧹 Nitpick comments (2)
jsonrpc/types/tx.go (1)

136-150: SetCodeTx: guard against nil deref and MustFromBig panics.
*rpcTx.To will panic if To is nil; MustFromBig(rpcTx.X.ToInt()) will also panic if any of ChainID/GasTipCap/GasFeeCap/Value/V/R/S are nil. Either enforce invariants or add lightweight preconditions.

Minimal defensive option within this case:

 case coretypes.SetCodeTxType:
-    return coretypes.NewTx((&coretypes.SetCodeTx{
+    // Required fields for SetCodeTx; avoid panics on nil.
+    if rpcTx.To == nil ||
+        rpcTx.ChainID == nil || rpcTx.GasTipCap == nil || rpcTx.GasFeeCap == nil ||
+        rpcTx.Value == nil || rpcTx.V == nil || rpcTx.R == nil || rpcTx.S == nil {
+        return nil
+    }
+    return coretypes.NewTx((&coretypes.SetCodeTx{
         ChainID:    uint256.MustFromBig(rpcTx.ChainID.ToInt()),
         Nonce:      uint64(rpcTx.Nonce),
         GasTipCap:  uint256.MustFromBig(rpcTx.GasTipCap.ToInt()),
         GasFeeCap:  uint256.MustFromBig(rpcTx.GasFeeCap.ToInt()),
         Gas:        uint64(rpcTx.Gas),
         To:         *rpcTx.To,
         Value:      uint256.MustFromBig(rpcTx.Value.ToInt()),
         Data:       rpcTx.Input,
         AccessList: accessList,
         V:          uint256.MustFromBig(rpcTx.V.ToInt()),
         R:          uint256.MustFromBig(rpcTx.R.ToInt()),
         S:          uint256.MustFromBig(rpcTx.S.ToInt()),
     }))
jsonrpc/types/tx_test.go (1)

120-153: SetCodeTx test is solid; drop redundant V/R/S initialization.
coretypes.SignTx overwrites signature fields; pre-setting them adds noise.

Apply within the SetCodeTx literal:

 		AccessList: nil,
-		V:          uint256.MustFromBig(big.NewInt(0)),
-		R:          uint256.MustFromBig(big.NewInt(0)),
-		S:          uint256.MustFromBig(big.NewInt(0)),
 	})
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between aefed67 and df89ee1.

📒 Files selected for processing (5)
  • jsonrpc/types/tx.go (2 hunks)
  • jsonrpc/types/tx_test.go (5 hunks)
  • x/evm/precompiles/testing/mock.go (8 hunks)
  • x/evm/state/statedb_hooked.go (1 hunks)
  • x/evm/types/txutils_test.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • x/evm/types/txutils_test.go
  • x/evm/precompiles/testing/mock.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Run test and upload codecov
  • GitHub Check: golangci-lint
  • GitHub Check: Analyze (go)
🔇 Additional comments (12)
jsonrpc/types/tx.go (1)

8-9: uint256 import is appropriate for SetCodeTx fields.
Aligned with go-ethereum’s uint256-based fields for EIP-7702.

jsonrpc/types/tx_test.go (4)

8-10: New imports are correct.
uint256 and require are needed for SetCodeTx construction and assertions.


38-41: Switch to Prague signer is correct.
Using NewPragueSigner aligns with Prague/EIP‑7702 semantics.


73-76: Prague signer for AccessList test looks good.
Consistent with network rule set in the rest of the suite.


107-110: Prague signer for DynamicFee test looks good.
Matches the upgrade baseline.

x/evm/state/statedb_hooked.go (7)

52-60: LGTM! Nonce hook correctly captures pre-state

The SetNonce method correctly captures the previous nonce before calling StateDB.SetNonce, ensuring accurate hook values. The implementation properly handles both V1 and V2 hook variants.


63-73: LGTM! Code change hooks implemented correctly

The SetCode method properly captures the previous code before setting new code and correctly computes the hash for empty code. The hook receives accurate previous and new code values.


76-82: LGTM! Storage change hooks work correctly

The SetState method properly captures the previous storage value and only triggers the hook when the value actually changes, preventing unnecessary event noise.


85-105: LGTM! SelfDestruct hooks implemented correctly

The SelfDestruct method correctly captures the previous code and balance state before performing the destruction, then emits appropriate hooks for both balance and code changes. The order of operations is proper.


108-128: LGTM! SelfDestruct6780 hooks implemented correctly

The SelfDestruct6780 method correctly handles the EIP-6780 variant of self-destruct, properly checking the changed flag before emitting hooks. This prevents spurious events when the destruction has no effect.


131-137: LGTM! AddLog hook correctly forwards logs

The AddLog method properly delegates to the underlying StateDB first (allowing it to modify the log) before emitting the hook event.


14-27: LGTM! Clean wrapper implementation

The HookedStateDB structure and constructor are well-designed. The embedding of *StateDB provides access to all base functionality while allowing selective method overrides for tracing. The interface compliance check is appropriate.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (4)
app/upgrades/v1_2_0/upgrade.go (4)

3-13: Add fmt import for contextual error wrapping.

Follow‑up diffs below wrap returned errors with context; they require adding fmt.

 import (
 	"context"
 
 	upgradetypes "cosmossdk.io/x/upgrade/types"
 	"github.com/cosmos/cosmos-sdk/types/module"
 	"github.com/ethereum/go-ethereum/common/hexutil"
 
 	"github.com/initia-labs/minievm/app/upgrades"
 	"github.com/initia-labs/minievm/app/upgrades/contracts/erc20_factory"
 	"github.com/initia-labs/minievm/app/upgrades/contracts/erc20_wrapper"
+	"fmt"
 )

23-37: Wrap errors with actionable context.

This will simplify debugging failed upgrades in the field.

-			params, err := app.GetEVMKeeper().Params.Get(ctx)
-			if err != nil {
-				return nil, err
-			}
+			params, err := app.GetEVMKeeper().Params.Get(ctx)
+			if err != nil {
+				return nil, fmt.Errorf("get EVM params: %w", err)
+			}
 
-			err = params.NormalizeAddresses(app.GetAccountKeeper().AddressCodec())
-			if err != nil {
-				return nil, err
-			}
+			if err = params.NormalizeAddresses(app.GetAccountKeeper().AddressCodec()); err != nil {
+				return nil, fmt.Errorf("normalize EVM params addresses: %w", err)
+			}
 
-			err = app.GetEVMKeeper().Params.Set(ctx, params)
-			if err != nil {
-				return nil, err
-			}
+			if err = app.GetEVMKeeper().Params.Set(ctx, params); err != nil {
+				return nil, fmt.Errorf("set EVM params: %w", err)
+			}

39-52: Add error context and consider idempotency guard.

  • Wrap errors with contract and address context.
  • Optional: skip ReplaceCodeAndCodeHash when the existing code hash already matches to avoid redundant writes (if not already handled inside that helper).
-			wrapperAddr, err := app.GetEVMKeeper().GetERC20WrapperAddr(ctx)
-			if err != nil {
-				return nil, err
-			}
+			wrapperAddr, err := app.GetEVMKeeper().GetERC20WrapperAddr(ctx)
+			if err != nil {
+				return nil, fmt.Errorf("get ERC20 wrapper address: %w", err)
+			}
 			wrapperRuntimeCode, err := hexutil.Decode(erc20_wrapper.Erc20WrapperBin)
-			if err != nil {
-				return nil, err
-			}
+			if err != nil {
+				return nil, fmt.Errorf("decode ERC20 wrapper runtime code: %w", err)
+			}
 			wrapperCodeHash := upgrades.CodeHash(wrapperRuntimeCode)
-			if err := upgrades.ReplaceCodeAndCodeHash(ctx, app, wrapperAddr.Bytes(), wrapperRuntimeCode, wrapperCodeHash); err != nil {
-				return nil, err
-			}
+			if err := upgrades.ReplaceCodeAndCodeHash(ctx, app, wrapperAddr.Bytes(), wrapperRuntimeCode, wrapperCodeHash); err != nil {
+				return nil, fmt.Errorf("replace wrapper code at %x: %w", wrapperAddr.Bytes(), err)
+			}

Can you confirm whether ReplaceCodeAndCodeHash is a no‑op when the code hash is unchanged? If not, I recommend pre‑checking and skipping the write.


53-66: Mirror the same improvements for the factory contract step.

-			factoryAddr, err := app.GetEVMKeeper().GetERC20FactoryAddr(ctx)
-			if err != nil {
-				return nil, err
-			}
+			factoryAddr, err := app.GetEVMKeeper().GetERC20FactoryAddr(ctx)
+			if err != nil {
+				return nil, fmt.Errorf("get ERC20 factory address: %w", err)
+			}
 			factoryRuntimeCode, err := hexutil.Decode(erc20_factory.Erc20FactoryBin)
-			if err != nil {
-				return nil, err
-			}
+			if err != nil {
+				return nil, fmt.Errorf("decode ERC20 factory runtime code: %w", err)
+			}
 			factoryCodeHash := upgrades.CodeHash(factoryRuntimeCode)
-			if err := upgrades.ReplaceCodeAndCodeHash(ctx, app, factoryAddr.Bytes(), factoryRuntimeCode, factoryCodeHash); err != nil {
-				return nil, err
-			}
+			if err := upgrades.ReplaceCodeAndCodeHash(ctx, app, factoryAddr.Bytes(), factoryRuntimeCode, factoryCodeHash); err != nil {
+				return nil, fmt.Errorf("replace factory code at %x: %w", factoryAddr.Bytes(), err)
+			}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between df89ee1 and d41b795.

📒 Files selected for processing (2)
  • app/app.go (2 hunks)
  • app/upgrades/v1_2_0/upgrade.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: golangci-lint
  • GitHub Check: Run test and upload codecov
  • GitHub Check: Analyze (go)
🔇 Additional comments (3)
app/upgrades/v1_2_0/upgrade.go (1)

15-15: Double‑check plan name alignment with governance plan.

Ensure the on‑chain upgrade plan name is exactly "v1.2.0" (case/spacing sensitive) or this handler won’t execute.

Would you confirm the scheduled plan name matches?

app/app.go (2)

274-274: Registering v1.2.0 handlers under loadLatest is correct.

Matches existing pattern and avoids unnecessary registration during init.


67-67: Approve — upgrade import updated to v1_2_0

Change looks good; the provided search (rg -n 'upgrades/v1_1_9') returned no output — manually confirm there are no remaining references to v1_1_9 before merge.

Copy link
Member

@beer-1 beer-1 left a comment

Choose a reason for hiding this comment

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

LGTM

@beer-1 beer-1 merged commit 4756749 into main Sep 17, 2025
8 checks passed
@beer-1 beer-1 deleted the bump/v1.15.11 branch September 17, 2025 03:32
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.

3 participants