Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
- [\#1061](https://github.com/cosmos/evm/pull/1061) Block nested ICS20 forwarding in source callbacks.
- [\#1050](https://github.com/cosmos/evm/pull/1050) Align precompile gas calculation with expected EVM gas semantics.
- [\#1107](https://github.com/cosmos/evm/pull/1107) Skip StateDB commit error transactions during receipt conversion to prevent `invalid message index` errors in block RPCs.
- [\#1183](https://github.com/cosmos/evm/pull/1183) Align eth_call's KV gas accounting with deliverTx so it stops rejecting valid estimateGas results for native precompile txs.
- [\#1216](https://github.com/cosmos/evm/pull/1216) Fix blocking on mempool event bus unsubscribe.

## v0.6.0
Expand Down
35 changes: 35 additions & 0 deletions tests/integration/x/vm/test_grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/holiman/uint256"
"github.com/stretchr/testify/require"

bankprecompile "github.com/cosmos/evm/precompiles/bank"
"github.com/cosmos/evm/server/config"
testconstants "github.com/cosmos/evm/testutil/constants"
"github.com/cosmos/evm/testutil/integration/evm/factory"
Expand Down Expand Up @@ -2211,6 +2212,40 @@ func (s *KeeperTestSuite) TestEthCall() {
}
}

// TestEthCallGasMatchesDeliverTxForNativePrecompile asserts that EthCall and
// a broadcasted tx report the same GasUsed when targeting a native precompile,
// covering the BuildEvmExecutionCtx call added to EthCall.
func (s *KeeperTestSuite) TestEthCallGasMatchesDeliverTxForNativePrecompile() {
s.SetupTest()

sender := s.Keyring.GetKey(0)
to := common.HexToAddress(types.BankPrecompileAddress)
data, err := bankprecompile.ABI.Pack(bankprecompile.BalancesMethod, sender.Addr)
s.Require().NoError(err)

gas := hexutil.Uint64(500_000)
args, err := json.Marshal(&types.TransactionArgs{
From: &sender.Addr, To: &to, Data: (*hexutil.Bytes)(&data), Gas: &gas,
})
s.Require().NoError(err)

callRes, err := s.Network.GetEvmClient().EthCall(s.Network.GetContext(), &types.EthCallRequest{
Args: args, GasCap: config.DefaultGasCap,
})
s.Require().NoError(err)
s.Require().Empty(callRes.VmError)

txRes, err := s.Factory.ExecuteEthTx(sender.Priv, types.EvmTxArgs{
To: &to, GasLimit: uint64(gas), Input: data,
})
s.Require().NoError(err)
deliverRes, err := types.DecodeTxResponse(txRes.Data)
s.Require().NoError(err)
s.Require().Empty(deliverRes.VmError)

s.Require().Equal(deliverRes.GasUsed, callRes.GasUsed)
}

func (s *KeeperTestSuite) TestBalance() {
testCases := []struct {
name string
Expand Down
6 changes: 6 additions & 0 deletions x/vm/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@ func (k Keeper) EthCall(c context.Context, req *types.EthCallRequest) (_ *types.
}
}

// Align eth_call's KV gas accounting with deliverTx: clear KV/transient gas
// configs so EVM-internal cosmos-sdk store ops (e.g. precompile.FlushToCacheCtx)
// don't charge gas. Otherwise eth_call would report a stricter floor than
// real broadcast for txs reaching native precompiles.
ctx = evmante.BuildEvmExecutionCtx(ctx)

var args types.TransactionArgs
err = json.Unmarshal(req.Args, &args)
if err != nil {
Expand Down
24 changes: 24 additions & 0 deletions x/vm/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package keeper

import (
"testing"

"github.com/stretchr/testify/require"

storetypes "github.com/cosmos/cosmos-sdk/store/v2/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

// buildTraceCtx must zero KV gas configs so simulation matches deliverTx
// (whose ante also zeroes KV via BuildEvmExecutionCtx). SLOAD/SSTORE gas
// accounting then remains opcode-driven and does not consume KV gas, and
// pre-precompile cosmos-sdk store ops (e.g. stateDB.FlushToCacheCtx) are
// free — same as on real chain.
func TestBuildTraceCtxZeroesKVGasConfig(t *testing.T) {
parent := sdk.Context{}.
WithKVGasConfig(storetypes.KVGasConfig()).
WithTransientKVGasConfig(storetypes.TransientGasConfig())
traceCtx := buildTraceCtx(parent, 1_000_000)
require.Equal(t, storetypes.GasConfig{}, traceCtx.KVGasConfig())
require.Equal(t, storetypes.GasConfig{}, traceCtx.TransientKVGasConfig())
}
Loading