Skip to content

Conversation

@Unique-Divine
Copy link
Member

@Unique-Divine Unique-Divine commented Nov 3, 2025

evm: rewrite eth_estimateGas for panic safety and performance

  • Unified EstimateGas implementation; removed CallType abstraction.
  • Added panic safety via RecoverOutOfGasPanic to catch SDK/go-ethereum
    OOG panics as normal VM errors.
  • Runs each probe on gas-free context (infinite gas meter + zero KV cost),
    eliminating SDK store-gas panics.
  • Treats OOG as VM-level execution failure (vmError=true) instead of aborting.
  • Simplified probe logic: update only evmMsg.GasLimit per iteration.
  • Smart lower bound initialization (use gasUsed from full run at hi).
  • Skewed binary search and early-exit tolerance reduce iterations by ~60%.
  • Matches go-ethereum eth_estimateGas semantics and improves stability.

Purpose:

Outcome

eth_estimateGas is now:

  • Panic-safe under both Cosmos SDK and EVM gas errors.
  • Semantically aligned with go-ethereum.
  • ~60 % faster in convergence.
  • Simpler and more maintainable for future extensions (balance-based capping, blob support).

Summary

This PR rewrites Nibiru’s eth_estimateGas to be panic-safe,
deterministic, and aligned with go-ethereum’s semantics, while cutting
average binary-search iterations by ~60%.

1. Unified gas estimation

  • Removed CallType enum and EstimateGasForEvmCallType; logic is now consolidated in a single EstimateGas method.

  • Always executes under a consistent simulation context (rootCtx) with:

    • Infinite gas meter
    • Zero KV and transient gas configs
      This guarantees no store-gas panics during estimation.

2. Robust panic handling

  • Replaced HandleOutOfGasPanic(*error) with functional RecoverOutOfGasPanic(context string) (bool, error).

  • Classifies panics:

    • SDK/go-ethereum "out of gas" → VM error (vmError=true), continue search.
    • Unexpected panic → contextual diagnostic error ("unexpected panic in eth_estimateGas").
  • Prevents crashes that previously bubbled up to gRPC middleware.

3. Simplified probe semantics

  • Each binary-search probe creates a fresh SDB in a gas-free context.
  • Only evmMsg.GasLimit changes per iteration (evmMsg.GasLimit = gas).
  • Nonce handling matches ante-handler behavior (nonce + 1).

4. Performance improvements

  • Smart lower bound initialization:
    Execute once at max gas; set lo = result.GasUsed - 1.
  • Skewed bisection:
    Cap midpoint to lo * 2 when standard midpoint overshoots typical usage.
  • Early-exit tolerance:
    Stop when (hi - lo) / hi < 1.5%; wallets already apply 20–25% buffers.
  • Combined, these yield ~60% fewer iterations for typical contracts.

5. Error semantics

  • core.ErrIntrinsicGas treated as VM failure, not hard error.
  • Recovered OOGs (even without response) handled gracefully.
  • Canonicalized final cap error:
    "gas required exceeds allowance (<cap>)".

Behavioral outcomes

Aspect Old New
OOG panic Propagated to gRPC, crashed query Caught, treated as VM error
SDK store gas Could trigger panic Infinite gas meter (no panic)
Search iterations ~19 avg. ~8 avg. (-60%)
Error flow Pointer mutation, implicit Explicit (isOog, err) classifier

References

  • Geth reference: eth/gasestimator/gasestimator.go lines 123-191

Note

Rewrites eth_estimateGas for panic safety and faster convergence, updates context keys and binsearch logic, adjusts tests, and adds git-cliff changelog generation tooling.

  • EVM (gas estimation):
    • Unified Query/EstimateGas (removed CallType path) and rewrote logic to run probes on gas-free contexts with panic classification (treat OOG as VM failure).
    • Smart base-case run, biased/tolerant BinSearch (GasEstimateErrorRatioTolerance, midpoint skew), and cap/nonce handling fixes.
    • Added context keys CtxKeyEvmSimulation and CtxKeyGasEstimateZeroTolerance; removed old panic helper and CallType.
  • EVM state/trace:
    • Propagate simulation context via CtxKeyEvmSimulation in EthCall, TraceTx, TraceCall, and TraceBlock.
  • Tests:
    • Relax eth_estimateGas assertion in evm-e2e/test/eth_queries.test.ts.
    • Use zero-tolerance gas estimation in evmtest.GenerateEthTxMsgAndSigner.
  • Tooling/Changelog:
    • Add git-cliff config (cliff.toml) and just gen-changelog; generate CHANGELOG-UNRELEASED.md.
    • Remove .github/workflows/changelog-check.yml.

Written by Cursor Bugbot for commit dd6db35. This will update automatically on new commits. Configure here.

@Unique-Divine Unique-Divine requested a review from a team as a code owner November 3, 2025 15:22
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Refactors EVM gas-estimation and context keys: introduces typed context keys (CtxKeyEvmSimulation, CtxKeyGasEstimateZeroTolerance), removes CallType and an out-of-gas panic wrapper, replaces EstimateGas with a single tolerance-aware flow using an isolated probe StateDB and a skewed binary search, updates BinSearch signature/behavior, and adapts tests and CI changelog tooling.

Changes

Cohort / File(s) Summary
CI / Changelog tooling
\.github/workflows/changelog-check.yml, cliff.toml, justfile, CHANGELOG-UNRELEASED.md
Removed the old changelog-check workflow; added cliff.toml and justfile recipe gen-changelog; added CHANGELOG-UNRELEASED.md.
EVM constants & API surface
x/evm/const.go
Added typed contextKey and constants CtxKeyEvmSimulation, CtxKeyGasEstimateZeroTolerance; removed CallType and its constants.
EVM core (panic handling)
x/evm/evm.go
Removed HandleOutOfGasPanic recovery wrapper and related imports; SafeConsumeGas remains.
Gas estimation & tracing
x/evm/evmstate/grpc_query.go, x/evm/evmstate/keeper.go
Replaced previous EstimateGas wrapper with a single EstimateGas implementing an isolated probe SDB, initial hi probe, panic classification (OOG vs others), and tolerance-driven binary search; keeper now reads simulation flag from evm.CtxKeyEvmSimulation.
BinSearch and message utilities
x/evm/msg.go
Added GasEstimateErrorRatioTolerance; updated BinSearch signature to accept estimateTolerance, added relative-tolerance early exit, mid skewing toward lower gas, and immediate error propagation from executable.
Tests & test helpers
x/evm/evmstate/keeper_test.go, x/evm/evmtest/tx.go, evm-e2e/test/eth_queries.test.ts
Tests updated to use evm.CtxKeyEvmSimulation; added CheckTx-without-simulation test; GenerateEthTxMsgAndSigner sets CtxKeyGasEstimateZeroTolerance on context; e2e gas-estimate assertion relaxed to tolerance-based check.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant GRPC as EstimateGas
    participant ProbeSDB as Probe StateDB
    participant Prober as Probe Runner
    participant VM as EVM

    Client->>GRPC: EthCallRequest (with simulation flag)
    GRPC->>ProbeSDB: init fresh SDB (isolated gas meter, fresh nonce)
    GRPC->>Prober: run probe at hi
    Prober->>VM: Execute(tx @ hi)
    alt panic classified OOG
        VM-->>Prober: panic (OOG)
        Prober->>GRPC: treat as OOG -> adjust hi/lo
    else VM error/revert
        VM-->>Prober: VM error -> return error to client
    else success
        VM-->>Prober: success -> set lo/gasUsed
    end

    rect rgb(235,240,255)
      Note over GRPC,Prober: Binary search loop (skew mid toward lo, stop when relative tolerance met)
      loop binary search
        GRPC->>Prober: run with mid (skewed)
        Prober->>VM: Execute(tx @ mid)
        alt OOG or exec failure
            VM-->>Prober: failure -> hi = mid
        else success
            VM-->>Prober: success -> lo = mid
        end
      end
    end

    GRPC-->>Client: EstimateGasResponse (final estimate)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45–75 minutes

  • Files needing extra attention:
    • x/evm/evmstate/grpc_query.go — probe StateDB initialization, nonce/account handling, panic classification, and error mapping.
    • x/evm/msg.go — BinSearch numeric behavior: tolerance math, mid skew, and error propagation.
    • x/evm/const.go — removal of CallType public API; search for remaining references.
    • evm-e2e/test/eth_queries.test.ts — ensure e2e tolerance matches expected runtime variance.

Possibly related PRs

Suggested labels

x: evm

Suggested reviewers

  • k-yang

Poem

🐇 I hopped through contexts, keys, and gas,

I probed the high, then nudged the bounds to pass.
I skewed the mid to find a thriftier way,
Tolerance whispered when to stop the play.
No panic wrapper now — I bounced away.

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: rewriting eth_estimateGas with focus on panic safety and performance improvements.
Description check ✅ Passed The description comprehensively covers the Abstract section with issue reference, multiple detailed sections explaining the rewrite, performance improvements, error handling, and behavioral changes, going well beyond template requirements.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ud/eth-estimate-gas

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

❤️ Share

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

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request is an excellent and comprehensive rewrite of eth_estimateGas. The changes significantly improve panic safety, performance, and maintainability, aligning the implementation more closely with go-ethereum. The introduction of RecoverOutOfGasPanic and the gas-free context for probes are particularly strong improvements. My review includes a critical fix for a potential integer overflow in the new binary search logic and a suggestion to improve the clarity of the gas limit determination.

Comment on lines 357 to 375
// Determine the highest gas limit can be used during the estimation.
// Start with block gas limit
params := rootCtx.ConsensusParams()
if params != nil && params.Block != nil && params.Block.MaxGas > 0 {
hi = uint64(params.Block.MaxGas)
} else {
// Fallback to gasCap if block params not available
hi = req.GasCap
}

// Override with user-provided gas limit if it's valid
if args.Gas != nil && uint64(*args.Gas) >= gethparams.TxGas {
hi = uint64(*args.Gas)
} else {
// Query block gas limit
params := ctx.ConsensusParams()
if params != nil && params.Block != nil && params.Block.MaxGas > 0 {
hi = uint64(params.Block.MaxGas)
} else {
hi = req.GasCap
}
}

// TODO: Recap the highest gas limit with account's available balance.
// Recap the highest gas allowance with specified gascap.
if req.GasCap != 0 && hi > req.GasCap {
hi = req.GasCap
}

Choose a reason for hiding this comment

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

medium

The logic to determine the upper bound hi is functionally correct, but its structure could be clearer. It currently initializes hi from the block/request gas cap, then potentially overrides it with args.Gas, and finally caps it again with req.GasCap.

A more direct structure that first checks for args.Gas and then falls back to other limits would improve readability and maintainability, aligning more closely with the previous implementation and standard practice.

Copy link
Contributor

@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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4abe140 and a19d1db.

📒 Files selected for processing (8)
  • .github/workflows/changelog-check.yml (1 hunks)
  • x/evm/const.go (1 hunks)
  • x/evm/evm.go (1 hunks)
  • x/evm/evmstate/grpc_query.go (9 hunks)
  • x/evm/evmstate/keeper.go (1 hunks)
  • x/evm/evmstate/keeper_test.go (3 hunks)
  • x/evm/evmtest/tx.go (2 hunks)
  • x/evm/msg.go (1 hunks)
🧰 Additional context used
🧠 Learnings (12)
📓 Common learnings
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2076
File: x/evm/keeper/msg_server.go:115-116
Timestamp: 2024-10-13T05:48:51.771Z
Learning: In the `ApplyEvmTx` function within `x/evm/keeper/msg_server.go`, a zero value for `weiPerGas` is acceptable as it signifies that gas is free. There is no need to check for zero before performing the gas refund in this context.
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.
📚 Learning: 2024-12-06T16:10:34.174Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.

Applied to files:

  • x/evm/const.go
  • x/evm/msg.go
  • x/evm/evmtest/tx.go
  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-10-13T05:48:51.771Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2076
File: x/evm/keeper/msg_server.go:115-116
Timestamp: 2024-10-13T05:48:51.771Z
Learning: In the `ApplyEvmTx` function within `x/evm/keeper/msg_server.go`, a zero value for `weiPerGas` is acceptable as it signifies that gas is free. There is no need to check for zero before performing the gas refund in this context.

Applied to files:

  • x/evm/msg.go
  • x/evm/evmtest/tx.go
  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-12-06T11:54:38.275Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.

Applied to files:

  • x/evm/msg.go
  • x/evm/evmtest/tx.go
📚 Learning: 2025-09-16T00:14:44.279Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).

Applied to files:

  • x/evm/msg.go
  • x/evm/evmtest/tx.go
  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-09-10T08:13:40.130Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2379
File: x/evm/keeper/erc20.go:103-112
Timestamp: 2025-09-10T08:13:40.130Z
Learning: ERC20 utility functions in x/evm/keeper/erc20.go (Transfer, Mint, Burn) should use COMMIT_READONLY rather than COMMIT_ETH_TX because they are designed as building blocks for larger Ethereum transactions, particularly in precompiles where multiple operations happen with a persistent *vm.EVM object and vm.StateDB. The commit should happen at the transaction level, not at each individual ERC20 operation level.

Applied to files:

  • x/evm/evmtest/tx.go
📚 Learning: 2025-09-10T08:13:32.673Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2379
File: x/evm/keeper/erc20.go:75-78
Timestamp: 2025-09-10T08:13:32.673Z
Learning: ERC20 utility functions in x/evm/keeper/erc20.go (like Mint, Transfer, Burn) should use COMMIT_READONLY instead of COMMIT_ETH_TX because they are designed as building blocks for larger Ethereum transactions, particularly within precompiles where multiple operations happen with a persistent *vm.EVM object and vm.StateDB. The commit decision should happen at the transaction level, not at each individual ERC20 operation.

Applied to files:

  • x/evm/evmtest/tx.go
📚 Learning: 2024-11-04T20:38:45.909Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2093
File: x/evm/precompile/funtoken.go:85-87
Timestamp: 2024-11-04T20:38:45.909Z
Learning: In the `Run` methods of precompiled contracts in `x/evm/precompile/`, after handling errors from `OnRunStart`, it's unnecessary to check if `err` is nil before consuming gas with `contract.UseGas()`, as `err` will always be nil at that point.

Applied to files:

  • x/evm/evmtest/tx.go
📚 Learning: 2025-01-17T17:32:27.341Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/evmmodule/genesis_test.go:51-51
Timestamp: 2025-01-17T17:32:27.341Z
Learning: The `NewEVM()` method in TestDeps returns only `*vm.EVM` without an error value.

Applied to files:

  • x/evm/evmtest/tx.go
  • x/evm/evmstate/keeper_test.go
📚 Learning: 2025-01-17T17:32:27.341Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/evmmodule/genesis_test.go:51-51
Timestamp: 2025-01-17T17:32:27.341Z
Learning: The `NewEVM()` method in TestDeps returns `(*vm.EVM, *statedb.StateDB)` without an error value. The second return value is often discarded when only the EVM object is needed.

Applied to files:

  • x/evm/evmstate/grpc_query.go
  • x/evm/evmstate/keeper_test.go
📚 Learning: 2025-01-17T17:32:33.412Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/keeper/funtoken_from_coin_test.go:30-30
Timestamp: 2025-01-17T17:32:33.412Z
Learning: In test dependencies, `deps.NewEVM()` returns both an EVM object and a StateDB object with the signature `(*vm.EVM, *statedb.StateDB)`. The method is used in test files to create new EVM and StateDB instances for testing purposes.

Applied to files:

  • x/evm/evmstate/grpc_query.go
  • x/evm/evmstate/keeper_test.go
📚 Learning: 2025-09-16T00:11:38.994Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:80-90
Timestamp: 2025-09-16T00:11:38.994Z
Learning: The `WithLastErrApplyEvmMsg` method on sdk.Context in the Nibiru codebase is implemented as an in-place setter that mutates the context directly, unlike standard Cosmos SDK With* methods which return new contexts.

Applied to files:

  • x/evm/evmstate/grpc_query.go
  • x/evm/evmstate/keeper.go
🧬 Code graph analysis (5)
x/evm/msg.go (2)
x/evm/tx.pb.go (3)
  • MsgEthereumTxResponse (333-348)
  • MsgEthereumTxResponse (352-352)
  • MsgEthereumTxResponse (353-355)
api/eth/evm/v1/tx.pulsar.go (3)
  • MsgEthereumTxResponse (9205-9224)
  • MsgEthereumTxResponse (9239-9239)
  • MsgEthereumTxResponse (9242-9244)
x/evm/evmtest/tx.go (1)
x/evm/const.go (1)
  • GasEstimateZeroToleranceCtxKey (43-43)
x/evm/evmstate/grpc_query.go (5)
x/evm/const.go (2)
  • SimulationCtxKey (42-42)
  • GasEstimateZeroToleranceCtxKey (43-43)
x/evm/evm.go (1)
  • RecoverOutOfGasPanic (123-135)
eth/gas_limit.go (1)
  • NewInfiniteGasMeterWithLimit (42-47)
x/evm/errors.go (1)
  • NewRevertError (60-71)
x/evm/msg.go (2)
  • GasEstimateErrorRatioTolerance (518-518)
  • BinSearch (521-558)
x/evm/evmstate/keeper_test.go (1)
x/evm/const.go (1)
  • SimulationCtxKey (42-42)
x/evm/evmstate/keeper.go (1)
x/evm/const.go (1)
  • SimulationCtxKey (42-42)
⏰ 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). (7)
  • GitHub Check: heavy-tests
  • GitHub Check: Cursor Bugbot
  • GitHub Check: proto-gen-rs
  • GitHub Check: build
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: e2e-evm
🔇 Additional comments (1)
.github/workflows/changelog-check.yml (1)

1-1: Clean workflow name simplification.

The renaming from "Check changelog update" to "Changelog" improves clarity without affecting workflow behavior or logic.

cursor[bot]

This comment was marked as outdated.

Copy link
Contributor

@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

🧹 Nitpick comments (1)
x/evm/evmstate/grpc_query.go (1)

357-375: Consider restructuring the upper bound logic for clarity.

The logic is functionally correct but involves setting hi from block max gas, potentially overriding it with args.Gas, and then capping it again with req.GasCap. This creates a back-and-forth that can be hard to follow.

Consider a more direct structure:

// Determine the absolute maximum gas limit
var absoluteMax uint64
params := rootCtx.ConsensusParams()
if params != nil && params.Block != nil && params.Block.MaxGas > 0 {
    absoluteMax = uint64(params.Block.MaxGas)
} else {
    absoluteMax = req.GasCap
}

// Start with user-provided gas if valid, otherwise use the absolute maximum
hi := absoluteMax
if args.Gas != nil && uint64(*args.Gas) >= gethparams.TxGas {
    hi = min(uint64(*args.Gas), absoluteMax)
}

// Apply final cap with GasCap
if req.GasCap != 0 && hi > req.GasCap {
    hi = req.GasCap
}

This makes the precedence clearer: absolute max → user preference → final cap.

Based on learnings

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a19d1db and c0ebe60.

📒 Files selected for processing (6)
  • evm-e2e/test/eth_queries.test.ts (1 hunks)
  • x/evm/const.go (1 hunks)
  • x/evm/evmstate/grpc_query.go (9 hunks)
  • x/evm/evmstate/keeper.go (1 hunks)
  • x/evm/evmstate/keeper_test.go (3 hunks)
  • x/evm/evmtest/tx.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • x/evm/const.go
  • x/evm/evmtest/tx.go
  • x/evm/evmstate/keeper_test.go
  • x/evm/evmstate/keeper.go
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2076
File: x/evm/keeper/msg_server.go:115-116
Timestamp: 2024-10-13T05:48:51.771Z
Learning: In the `ApplyEvmTx` function within `x/evm/keeper/msg_server.go`, a zero value for `weiPerGas` is acceptable as it signifies that gas is free. There is no need to check for zero before performing the gas refund in this context.
📚 Learning: 2024-12-06T11:54:38.275Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.

Applied to files:

  • evm-e2e/test/eth_queries.test.ts
  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-12-06T16:10:34.174Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-09-16T00:14:44.279Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-10-13T05:48:51.771Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2076
File: x/evm/keeper/msg_server.go:115-116
Timestamp: 2024-10-13T05:48:51.771Z
Learning: In the `ApplyEvmTx` function within `x/evm/keeper/msg_server.go`, a zero value for `weiPerGas` is acceptable as it signifies that gas is free. There is no need to check for zero before performing the gas refund in this context.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-11-04T20:38:45.909Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2093
File: x/evm/precompile/funtoken.go:85-87
Timestamp: 2024-11-04T20:38:45.909Z
Learning: In the `Run` methods of precompiled contracts in `x/evm/precompile/`, after handling errors from `OnRunStart`, it's unnecessary to check if `err` is nil before consuming gas with `contract.UseGas()`, as `err` will always be nil at that point.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-01-17T17:32:27.341Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/evmmodule/genesis_test.go:51-51
Timestamp: 2025-01-17T17:32:27.341Z
Learning: The `NewEVM()` method in TestDeps returns `(*vm.EVM, *statedb.StateDB)` without an error value. The second return value is often discarded when only the EVM object is needed.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-01-17T17:32:33.412Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/keeper/funtoken_from_coin_test.go:30-30
Timestamp: 2025-01-17T17:32:33.412Z
Learning: In test dependencies, `deps.NewEVM()` returns both an EVM object and a StateDB object with the signature `(*vm.EVM, *statedb.StateDB)`. The method is used in test files to create new EVM and StateDB instances for testing purposes.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-09-16T00:11:38.994Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:80-90
Timestamp: 2025-09-16T00:11:38.994Z
Learning: The `WithLastErrApplyEvmMsg` method on sdk.Context in the Nibiru codebase is implemented as an in-place setter that mutates the context directly, unlike standard Cosmos SDK With* methods which return new contexts.

Applied to files:

  • x/evm/evmstate/grpc_query.go
🧬 Code graph analysis (2)
evm-e2e/test/eth_queries.test.ts (1)
evm-e2e/test/utils.ts (1)
  • INTRINSIC_TX_GAS (29-29)
x/evm/evmstate/grpc_query.go (5)
x/evm/const.go (2)
  • CtxKeyEvmSimulation (42-42)
  • CtxKeyGasEstimateZeroTolerance (43-43)
x/evm/evm.go (1)
  • RecoverOutOfGasPanic (123-135)
eth/gas_limit.go (1)
  • NewInfiniteGasMeterWithLimit (42-47)
x/evm/errors.go (1)
  • NewRevertError (60-71)
x/evm/msg.go (2)
  • GasEstimateErrorRatioTolerance (518-518)
  • BinSearch (521-558)
⏰ 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). (7)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: heavy-tests
  • GitHub Check: unit-tests
  • GitHub Check: build
  • GitHub Check: proto-gen-rs
  • GitHub Check: e2e-evm
  • GitHub Check: lint
🔇 Additional comments (6)
evm-e2e/test/eth_queries.test.ts (1)

23-32: LGTM! Tolerance-based assertion aligns with the new gas estimation flow.

The updated assertion correctly validates that the estimated gas for a simple value transfer is within 5% of the intrinsic gas cost. This aligns with the PR's introduction of tolerance-based gas estimation (GasEstimateErrorRatioTolerance = 0.015 in the backend).

x/evm/evmstate/grpc_query.go (5)

267-267: LGTM! Consistent context key migration.

The migration from SimulationContextKey to evm.CtxKeyEvmSimulation is applied consistently across all query methods (EthCall, EstimateGas, TraceTx, TraceCall, TraceBlock), aligning with the context key definitions in x/evm/const.go.

Also applies to: 321-321, 506-506, 603-603, 693-693


383-451: LGTM! Well-structured executable function with proper panic handling.

The executable function correctly:

  • Recovers SDK/EVM out-of-gas panics and treats them as VM failures (allowing binary search to continue)
  • Propagates unexpected panics as contextual errors
  • Creates a fresh StateDB for each probe with infinite gas meter and zero KV gas costs (preventing store-gas panics)
  • Handles account nonce increment to mirror the ante handler behavior
  • Treats core.ErrIntrinsicGas as a VM failure that requires raising the gas limit
  • Distinguishes consensus errors (abort search) from VM errors (continue search)

453-469: LGTM! Base case execution correctly validates and seeds the lower bound.

The base case logic properly:

  • Executes at the highest allowable gas limit to validate the transaction
  • Returns immediately on consensus errors
  • Distinguishes between different failure modes:
    • Execution reverts → return decoded revert error
    • Non-OOG VM errors → return the VM error
    • OOG at max limit → return "gas required exceeds allowance"

This approach efficiently validates the transaction and provides clear error messages.


472-476: LGTM! Underflow protection correctly implemented.

The code now properly handles the case where result.GasUsed == 0 by setting lo = 0 instead of attempting to subtract one (which would underflow to math.MaxUint64). This addresses the past review comment and prevents corruption of the binary search.


479-486: LGTM! Tolerance-based binary search enables performance improvements.

The tolerance handling correctly:

  • Defaults to evm.GasEstimateErrorRatioTolerance (~1.5%) for production use
  • Allows tests to set CtxKeyGasEstimateZeroTolerance for exact results
  • Passes the tolerance to the BinSearch function which implements skewed bisection

This aligns with the PR's goal of reducing average binary-search iterations by ~60% while maintaining accuracy.

cursor[bot]

This comment was marked as outdated.

Copy link
Contributor

@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: 2

♻️ Duplicate comments (1)
x/evm/evmstate/grpc_query.go (1)

357-375: Upper bound determination logic is confusing.

The logic initializes hi from the block gas limit or req.GasCap, then potentially overrides it with args.Gas, and finally caps it again with req.GasCap. A clearer structure would check args.Gas first, then fall back to block limit, then apply the cap. This makes the logic flow more intuitive and easier to maintain.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0ebe60 and c24babf.

📒 Files selected for processing (2)
  • x/evm/evm.go (0 hunks)
  • x/evm/evmstate/grpc_query.go (9 hunks)
💤 Files with no reviewable changes (1)
  • x/evm/evm.go
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2076
File: x/evm/keeper/msg_server.go:115-116
Timestamp: 2024-10-13T05:48:51.771Z
Learning: In the `ApplyEvmTx` function within `x/evm/keeper/msg_server.go`, a zero value for `weiPerGas` is acceptable as it signifies that gas is free. There is no need to check for zero before performing the gas refund in this context.
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.
📚 Learning: 2024-12-06T16:10:34.174Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-09-16T00:14:44.279Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-10-13T05:48:51.771Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2076
File: x/evm/keeper/msg_server.go:115-116
Timestamp: 2024-10-13T05:48:51.771Z
Learning: In the `ApplyEvmTx` function within `x/evm/keeper/msg_server.go`, a zero value for `weiPerGas` is acceptable as it signifies that gas is free. There is no need to check for zero before performing the gas refund in this context.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-11-04T20:38:45.909Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2093
File: x/evm/precompile/funtoken.go:85-87
Timestamp: 2024-11-04T20:38:45.909Z
Learning: In the `Run` methods of precompiled contracts in `x/evm/precompile/`, after handling errors from `OnRunStart`, it's unnecessary to check if `err` is nil before consuming gas with `contract.UseGas()`, as `err` will always be nil at that point.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-12-06T11:54:38.275Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-01-17T17:32:27.341Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/evmmodule/genesis_test.go:51-51
Timestamp: 2025-01-17T17:32:27.341Z
Learning: The `NewEVM()` method in TestDeps returns `(*vm.EVM, *statedb.StateDB)` without an error value. The second return value is often discarded when only the EVM object is needed.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-01-17T17:32:33.412Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/keeper/funtoken_from_coin_test.go:30-30
Timestamp: 2025-01-17T17:32:33.412Z
Learning: In test dependencies, `deps.NewEVM()` returns both an EVM object and a StateDB object with the signature `(*vm.EVM, *statedb.StateDB)`. The method is used in test files to create new EVM and StateDB instances for testing purposes.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-09-16T00:11:38.994Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:80-90
Timestamp: 2025-09-16T00:11:38.994Z
Learning: The `WithLastErrApplyEvmMsg` method on sdk.Context in the Nibiru codebase is implemented as an in-place setter that mutates the context directly, unlike standard Cosmos SDK With* methods which return new contexts.

Applied to files:

  • x/evm/evmstate/grpc_query.go
🧬 Code graph analysis (1)
x/evm/evmstate/grpc_query.go (4)
x/evm/const.go (2)
  • CtxKeyEvmSimulation (42-42)
  • CtxKeyGasEstimateZeroTolerance (43-43)
eth/gas_limit.go (1)
  • NewInfiniteGasMeterWithLimit (42-47)
x/evm/errors.go (1)
  • NewRevertError (60-71)
x/evm/msg.go (2)
  • GasEstimateErrorRatioTolerance (518-518)
  • BinSearch (521-558)
⏰ 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). (6)
  • GitHub Check: e2e-evm
  • GitHub Check: build
  • GitHub Check: proto-gen-rs
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: heavy-tests
🔇 Additional comments (4)
x/evm/evmstate/grpc_query.go (4)

267-267: LGTM! Context key refactoring is consistent.

The replacement of SimulationContextKey with evm.CtxKeyEvmSimulation is applied consistently across EthCall, TraceTx, TraceCall, and TraceBlock. This aligns with the new typed context keys introduced in x/evm/const.go.

Also applies to: 521-521, 618-618, 708-708


468-491: Good optimization: base case seeds the lower bound.

Executing at the maximum permissible gas first validates the transaction and provides an actual GasUsed value to seed a smarter lower bound for the binary search. The underflow protection at lines 487-491 correctly handles the edge case where GasUsed == 0.

This optimization aligns with the PR objective to reduce average binary-search iterations by ~60%.


430-454: Excellent panic-safety design.

Each probe constructs a fresh StateDB with:

  • InfiniteGasMeterWithLimit(evmMsg.GasLimit) to prevent SDK gas panics
  • Zero KVGasConfig and TransientKVGasConfig to eliminate store-gas consumption

Account nonce handling correctly mirrors the ante-handler behavior by incrementing to nonce + 1, ensuring consistency with transaction execution. This design isolates each probe from store-gas panics while maintaining correct state semantics.

Based on learnings: The pattern of assigning a new gas meter to the context is intentional and acceptable to isolate gas consumption.


494-501: Binary search with tolerance improves performance.

The implementation uses evm.GasEstimateErrorRatioTolerance (1.5%) for early exit, with an override path via evm.CtxKeyGasEstimateZeroTolerance for test scenarios requiring exact values. The skewed bisection logic in evm.BinSearch (capping midpoint to lo*2) further optimizes convergence toward the actual gas requirement.

Copy link
Contributor

@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 (1)
x/evm/evmstate/grpc_query.go (1)

469-469: Fix typo in comment.

"extermely" should be "extremely".

🧹 Nitpick comments (2)
x/evm/evmstate/grpc_query.go (2)

357-375: Consider restructuring upper bound logic for clarity.

The current logic initializes hi from block gas limit, then potentially overrides it with args.Gas, and finally caps it with req.GasCap. While functionally correct, this multi-step assignment could be more straightforward.

Consider checking args.Gas first (if valid and within bounds), then falling back to the minimum of block gas and req.GasCap. This would make the precedence more explicit and reduce the back-and-forth assignments.

Based on the previous review comment, would you like me to generate a clearer implementation that checks args.Gas first before falling back to block/cap limits?


399-399: Fix misleading comment.

The comment states "Non-OOG panics are not handled here," but they are actually handled in this else branch by setting oog=false and perr to a descriptive error.

Apply this diff to clarify the comment:

-		} else {
-			// Non-OOG panics are not handled here
+		} else {
+			// Handle non-OOG panics
 			oog, perr = false, fmt.Errorf(
 				`unexpected panic in eth_estimateGas { gas: %d }: %v`, gas, panicInfo)
 		}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c24babf and 8968faa.

📒 Files selected for processing (1)
  • x/evm/evmstate/grpc_query.go (9 hunks)
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.
📚 Learning: 2024-12-06T16:10:34.174Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-09-16T00:14:44.279Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-10-13T05:48:51.771Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2076
File: x/evm/keeper/msg_server.go:115-116
Timestamp: 2024-10-13T05:48:51.771Z
Learning: In the `ApplyEvmTx` function within `x/evm/keeper/msg_server.go`, a zero value for `weiPerGas` is acceptable as it signifies that gas is free. There is no need to check for zero before performing the gas refund in this context.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-11-04T20:38:45.909Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2093
File: x/evm/precompile/funtoken.go:85-87
Timestamp: 2024-11-04T20:38:45.909Z
Learning: In the `Run` methods of precompiled contracts in `x/evm/precompile/`, after handling errors from `OnRunStart`, it's unnecessary to check if `err` is nil before consuming gas with `contract.UseGas()`, as `err` will always be nil at that point.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-12-06T11:54:38.275Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-01-17T17:32:27.341Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/evmmodule/genesis_test.go:51-51
Timestamp: 2025-01-17T17:32:27.341Z
Learning: The `NewEVM()` method in TestDeps returns `(*vm.EVM, *statedb.StateDB)` without an error value. The second return value is often discarded when only the EVM object is needed.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-01-17T17:32:33.412Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/keeper/funtoken_from_coin_test.go:30-30
Timestamp: 2025-01-17T17:32:33.412Z
Learning: In test dependencies, `deps.NewEVM()` returns both an EVM object and a StateDB object with the signature `(*vm.EVM, *statedb.StateDB)`. The method is used in test files to create new EVM and StateDB instances for testing purposes.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-09-16T00:11:38.994Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:80-90
Timestamp: 2025-09-16T00:11:38.994Z
Learning: The `WithLastErrApplyEvmMsg` method on sdk.Context in the Nibiru codebase is implemented as an in-place setter that mutates the context directly, unlike standard Cosmos SDK With* methods which return new contexts.

Applied to files:

  • x/evm/evmstate/grpc_query.go
🧬 Code graph analysis (1)
x/evm/evmstate/grpc_query.go (4)
x/evm/const.go (2)
  • CtxKeyEvmSimulation (42-42)
  • CtxKeyGasEstimateZeroTolerance (43-43)
eth/gas_limit.go (1)
  • NewInfiniteGasMeterWithLimit (42-47)
x/evm/errors.go (1)
  • NewRevertError (60-71)
x/evm/msg.go (2)
  • GasEstimateErrorRatioTolerance (518-518)
  • BinSearch (521-558)
⏰ 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). (6)
  • GitHub Check: heavy-tests
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: e2e-evm
  • GitHub Check: proto-gen-rs
  • GitHub Check: build
🔇 Additional comments (7)
x/evm/evmstate/grpc_query.go (7)

267-267: LGTM! Context key updates are consistent.

The migration to evm.CtxKeyEvmSimulation is applied consistently across EthCall, TraceTx, TraceCall, and TraceBlock paths, aligning with the new typed context key pattern introduced in this PR.

Also applies to: 522-522, 619-619, 709-709


313-322: LGTM! Simplified API surface.

The new EstimateGas method signature removes the CallType abstraction and provides a cleaner public API. The initialization of rootCtx with the simulation flag is correct.


413-428: LGTM! Message reconstruction is correct.

The pattern of reconstructing evmMsg with only the GasLimit changed is clear and correct. The inline comment on line 418 helpfully marks the modified field.


430-455: LGTM! Gas-free simulation context is correctly configured.

The initialization creates an isolated probe environment:

  • Infinite gas meter with limit prevents SDK store-gas panics
  • Zero KV gas configs eliminate state access costs
  • Nonce increment matches ante-handler semantics

This aligns with the PR's panic-safety objectives. Based on learnings from the codebase, assigning a new gas meter to the context is an acceptable pattern for ensuring operations don't affect the parent context's gas consumption.


457-467: LGTM! Error handling semantics are correct.

The special treatment of core.ErrIntrinsicGas as a VM failure (allowing the search to continue) aligns with the PR's stated error semantics. Other errors properly abort the search.


488-492: LGTM! Underflow protection correctly implemented.

The check for result.GasUsed > 0 before subtracting prevents the underflow issue that was flagged in previous reviews. When GasUsed is zero, lo is correctly set to 0 instead of wrapping to math.MaxUint64.


494-502: LGTM! Binary search configuration is correct.

The tolerance-based early exit (defaulting to 1.5% per PR objectives) with support for zero-tolerance via context flag is correctly implemented. The call to evm.BinSearch with the new signature aligns with the refactored binary search logic mentioned in the PR objectives.

cursor[bot]

This comment was marked as outdated.

Copy link
Contributor

@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

🧹 Nitpick comments (2)
justfile (2)

61-61: Consider parameterizing or dynamically determining the version.

The version v2.7.0 is hardcoded. Consider making this a parameter or determining it dynamically using git tags.

Apply this diff to make the version a parameter with a default:

+# Generates CHANGELOG-UNRELEASED.md based on commits and pull requests.
+# Usage: just gen-changelog [last-version]
-gen-changelog:
+gen-changelog LAST_VER="v2.7.0":
   #!/usr/bin/env bash
   source contrib/bashlib.sh
   which_ok cargo
   if ! which_ok git-cliff; then 
     echo "Installing git-cliff with cargo"
     cargo install git-cliff
   fi 
   
   which_ok git-cliff

-  LAST_VER="v2.7.0"
   start_branch="$(git branch --show-current)"

63-65: Add safety check before switching branches.

Switching branches without checking for uncommitted changes could fail or leave the repository in an unexpected state. Add a check or use git stash to handle uncommitted changes.

Apply this diff to add a safety check:

   start_branch="$(git branch --show-current)"
+  # Ensure we're on a clean working tree or stash changes
+  if ! git diff-index --quiet HEAD --; then
+    log_info "Uncommitted changes detected. Stashing..."
+    git stash push -m "gen-changelog: auto-stash before branch switch"
+    STASHED=1
+  fi
   git checkout main
   git-cliff "$LAST_VER.." -o CHANGELOG-UNRELEASED.md
   git checkout "$start_branch"
+  if [ "${STASHED:-0}" -eq 1 ]; then
+    log_info "Restoring stashed changes..."
+    git stash pop
+  fi
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8968faa and 5ef5c85.

📒 Files selected for processing (4)
  • .github/workflows/changelog-check.yml (0 hunks)
  • CHANGELOG-UNRELEASED.md (1 hunks)
  • cliff.toml (1 hunks)
  • justfile (1 hunks)
💤 Files with no reviewable changes (1)
  • .github/workflows/changelog-check.yml
🧰 Additional context used
🧠 Learnings (1)
📓 Common learnings
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.
🪛 LanguageTool
CHANGELOG-UNRELEASED.md

[uncategorized] ~13-~13: If this is a compound adjective that modifies the following noun, use a hyphen.
Context: ...ing using gocovmerge; bring README more up to date in [#2416](https://github.com/NibiruCha...

(EN_COMPOUND_ADJECTIVE_INTERNAL)


[uncategorized] ~29-~29: The official name of this software platform is spelled with a capital “H”.
Context: ...3ed1821105)) by @Unique-Divine * feat(.github/pr-title-lint): Enable "/", capital let...

(GITHUB)

⏰ 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). (7)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: proto-gen-rs
  • GitHub Check: build
  • GitHub Check: e2e-evm
  • GitHub Check: unit-tests
  • GitHub Check: lint
  • GitHub Check: heavy-tests

Comment on lines +488 to +492
if result.GasUsed > 0 {
lo = result.GasUsed - 1
} else {
lo = 0
}
Copy link
Contributor

@onikonychev onikonychev Nov 3, 2025

Choose a reason for hiding this comment

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

this is great, it could transform binary search into a couple of tries only

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it's likely the first run will get the value neeeded

@codecov
Copy link

codecov bot commented Nov 3, 2025

Codecov Report

❌ Patch coverage is 65.47619% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.26%. Comparing base (4abe140) to head (f0bf277).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
x/evm/evmstate/grpc_query.go 66.21% 17 Missing and 8 partials ⚠️
x/evm/msg.go 0.00% 4 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #2424   +/-   ##
=======================================
  Coverage   59.26%   59.26%           
=======================================
  Files         359      359           
  Lines       24205    24216   +11     
=======================================
+ Hits        14344    14352    +8     
  Misses       8635     8635           
- Partials     1226     1229    +3     
Files with missing lines Coverage Δ
x/evm/const.go 41.66% <ø> (ø)
x/evm/evm.go 50.00% <ø> (+12.90%) ⬆️
x/evm/evmstate/keeper.go 75.00% <100.00%> (ø)
x/evm/evmtest/tx.go 55.28% <100.00%> (+0.87%) ⬆️
x/evm/msg.go 62.88% <0.00%> (-0.79%) ⬇️
x/evm/evmstate/grpc_query.go 80.30% <66.21%> (-2.61%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@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

♻️ Duplicate comments (1)
x/evm/evmstate/grpc_query.go (1)

488-492: Prevent potential infinite loop when GasUsed is zero.

If result.GasUsed is zero, lo is set to 0. When passed to evm.BinSearch, the skew logic (mid = lo * 2) would set mid = 0, causing executable(0) to fail repeatedly with the same state (lo=0, hi=hi), resulting in an infinite loop.

While GasUsed=0 is extremely unlikely in practice (EVM always consumes at least 21000 intrinsic gas), defensive programming suggests ensuring lo >= 1 or lo >= gethparams.TxGas to avoid this edge case.

Apply this diff to ensure a minimum lower bound:

 // Set smart lower bound based on actual gas used
 if result.GasUsed > 0 {
 	lo = result.GasUsed - 1
 } else {
-	lo = 0
+	// Ensure lo is at least 1 to avoid infinite loop in BinSearch skew logic
+	lo = 1
 }

Or more conservatively, set it to the intrinsic gas cost:

 // Set smart lower bound based on actual gas used
 if result.GasUsed > 0 {
 	lo = result.GasUsed - 1
 } else {
-	lo = 0
+	// Fallback to intrinsic gas cost if GasUsed is unexpectedly zero
+	lo = gethparams.TxGas - 1
 }
🧹 Nitpick comments (2)
justfile (2)

63-63: Consider updating main branch before generating changelog.

The script checks out main but doesn't ensure it's up-to-date with the remote. This could result in an incomplete or stale changelog if local main is behind origin/main.

Add a fetch and pull before checking out:

   LAST_VER="v2.7.0"
   start_branch="$(git branch --show-current)"
+  git fetch origin main
   git checkout main
+  git pull origin main
   git-cliff "$LAST_VER.." -o CHANGELOG-UNRELEASED.md

61-61: Consider making the last version configurable.

The LAST_VER value is hardcoded and will require manual updates for each release. Consider making it a parameter or detecting it automatically.

Option 1 - Make it a recipe parameter with a default:

-gen-changelog:
+gen-changelog LAST_VER="v2.7.0":
   #!/usr/bin/env bash
   source contrib/bashlib.sh
   which_ok cargo
   if ! which_ok git-cliff; then 
     echo "Installing git-cliff with cargo"
     cargo install git-cliff
   fi 
   
   which_ok git-cliff

-  LAST_VER="v2.7.0"
   start_branch="$(git branch --show-current)"

Option 2 - Auto-detect the latest tag:

-  LAST_VER="v2.7.0"
+  LAST_VER="$(git describe --tags --abbrev=0)"
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5ef5c85 and f0bf277.

📒 Files selected for processing (3)
  • cliff.toml (1 hunks)
  • justfile (1 hunks)
  • x/evm/evmstate/grpc_query.go (9 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • cliff.toml
🧰 Additional context used
🧠 Learnings (10)
📓 Common learnings
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2424
File: x/evm/msg.go:536-545
Timestamp: 2025-11-03T17:12:06.110Z
Learning: In the BinSearch function used for gas estimation in x/evm/msg.go, the lower bound `lo` is always initialized to at least the intrinsic gas cost (21000), never zero. This ensures that the skew logic `mid = lo * 2` always produces a valid positive midpoint value.
📚 Learning: 2025-09-16T00:14:44.279Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:92-97
Timestamp: 2025-09-16T00:14:44.279Z
Learning: In the EthereumTx function in x/evm/keeper/msg_server.go, the existing pattern of checking `if evmResp != nil` before calling SafeConsumeGas is correct because the control flow already handles the nil case through an early return when there's a consensus error (applyErr != nil && evmResp == nil).

Applied to files:

  • justfile
  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-12-06T16:10:34.174Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension.go:0-0
Timestamp: 2024-12-06T16:10:34.174Z
Learning: In `x/evm/keeper/bank_extension.go`, assigning a new `GasMeter` to the context within the `NibiruBankKeeper.ForceGasInvariant` function is intentional and acceptable. This ensures that subsequent operations do not affect the parent `ctx`'s gas consumption.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-11-03T17:12:06.110Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2424
File: x/evm/msg.go:536-545
Timestamp: 2025-11-03T17:12:06.110Z
Learning: In the BinSearch function used for gas estimation in x/evm/msg.go, the lower bound `lo` is always initialized to at least the intrinsic gas cost (21000), never zero. This ensures that the skew logic `mid = lo * 2` always produces a valid positive midpoint value.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-10-13T05:48:51.771Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2076
File: x/evm/keeper/msg_server.go:115-116
Timestamp: 2024-10-13T05:48:51.771Z
Learning: In the `ApplyEvmTx` function within `x/evm/keeper/msg_server.go`, a zero value for `weiPerGas` is acceptable as it signifies that gas is free. There is no need to check for zero before performing the gas refund in this context.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-12-06T11:54:38.275Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2119
File: x/evm/keeper/bank_extension_test.go:67-71
Timestamp: 2024-12-06T11:54:38.275Z
Learning: When writing tests in `x/evm/keeper/bank_extension_test.go`, prefer comparing gas consumption values as formatted strings using `fmt.Sprintf("%d", value)` instead of numeric values directly in `s.Equalf`. This avoids hexadecimal representations that are hard to read in shell outputs.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2024-11-04T20:38:45.909Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2093
File: x/evm/precompile/funtoken.go:85-87
Timestamp: 2024-11-04T20:38:45.909Z
Learning: In the `Run` methods of precompiled contracts in `x/evm/precompile/`, after handling errors from `OnRunStart`, it's unnecessary to check if `err` is nil before consuming gas with `contract.UseGas()`, as `err` will always be nil at that point.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-01-17T17:32:27.341Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/evmmodule/genesis_test.go:51-51
Timestamp: 2025-01-17T17:32:27.341Z
Learning: The `NewEVM()` method in TestDeps returns `(*vm.EVM, *statedb.StateDB)` without an error value. The second return value is often discarded when only the EVM object is needed.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-01-17T17:32:33.412Z
Learnt from: k-yang
Repo: NibiruChain/nibiru PR: 2165
File: x/evm/keeper/funtoken_from_coin_test.go:30-30
Timestamp: 2025-01-17T17:32:33.412Z
Learning: In test dependencies, `deps.NewEVM()` returns both an EVM object and a StateDB object with the signature `(*vm.EVM, *statedb.StateDB)`. The method is used in test files to create new EVM and StateDB instances for testing purposes.

Applied to files:

  • x/evm/evmstate/grpc_query.go
📚 Learning: 2025-09-16T00:11:38.994Z
Learnt from: Unique-Divine
Repo: NibiruChain/nibiru PR: 2385
File: x/evm/keeper/msg_server.go:80-90
Timestamp: 2025-09-16T00:11:38.994Z
Learning: The `WithLastErrApplyEvmMsg` method on sdk.Context in the Nibiru codebase is implemented as an in-place setter that mutates the context directly, unlike standard Cosmos SDK With* methods which return new contexts.

Applied to files:

  • x/evm/evmstate/grpc_query.go
🧬 Code graph analysis (1)
x/evm/evmstate/grpc_query.go (5)
x/evm/const.go (2)
  • CtxKeyEvmSimulation (42-42)
  • CtxKeyGasEstimateZeroTolerance (43-43)
x/evm/query.pb.go (6)
  • EthCallRequest (711-720)
  • EthCallRequest (724-724)
  • EthCallRequest (725-727)
  • EstimateGasResponse (784-787)
  • EstimateGasResponse (791-791)
  • EstimateGasResponse (792-794)
eth/gas_limit.go (1)
  • NewInfiniteGasMeterWithLimit (42-47)
x/evm/errors.go (1)
  • NewRevertError (60-71)
x/evm/msg.go (2)
  • GasEstimateErrorRatioTolerance (518-518)
  • BinSearch (521-558)
⏰ 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). (6)
  • GitHub Check: proto-gen-rs
  • GitHub Check: unit-tests
  • GitHub Check: build
  • GitHub Check: lint
  • GitHub Check: heavy-tests
  • GitHub Check: e2e-evm

Comment on lines +63 to +65
git checkout main
git-cliff "$LAST_VER.." -o CHANGELOG-UNRELEASED.md
git checkout "$start_branch"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add error handling for git checkout commands.

The git checkout commands lack error handling. If git checkout main fails (e.g., due to uncommitted changes or missing branch), the script continues and runs git-cliff on the wrong branch. If git checkout "$start_branch" fails, the user is left on the main branch unexpectedly.

Apply this diff to add error handling:

-  git checkout main
-  git-cliff "$LAST_VER.." -o CHANGELOG-UNRELEASED.md
-  git checkout "$start_branch"
+  git checkout main || { log_error "Failed to checkout main branch"; exit 1; }
+  git-cliff "$LAST_VER.." -o CHANGELOG-UNRELEASED.md || { log_error "git-cliff failed"; git checkout "$start_branch"; exit 1; }
+  git checkout "$start_branch" || { log_error "Failed to return to branch $start_branch"; exit 1; }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In justfile around lines 63-65, the two git checkout commands lack error
handling; ensure each git checkout is checked and the script aborts or restores
state on failure: after running git checkout main, verify it succeeded and if
not print a clear error and exit so git-cliff won't run on the wrong branch;
after running git checkout "$start_branch", verify it succeeded and if not print
an error and either attempt to return to the previous branch (if known) or exit
with a non-zero status so the user is not left on main unexpectedly.

@Unique-Divine Unique-Divine merged commit 37dba0a into main Nov 3, 2025
10 checks passed
@Unique-Divine Unique-Divine deleted the ud/eth-estimate-gas branch November 3, 2025 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants