Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,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.

- [\#1186](https://github.com/cosmos/evm/pull/1186) Align charged gas with EIP-7623 calldata floor after refunds.

## v0.6.0

Expand Down
53 changes: 53 additions & 0 deletions tests/integration/x/vm/test_state_transition.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package vm

import (
"bytes"
"errors"
"fmt"
"math"
Expand Down Expand Up @@ -915,6 +916,32 @@ func (s *KeeperTestSuite) TestApplyMessage() {
}
}

// TestApplyMessageInternalFloor verifies EIP-7623 floor is charged on internal calls.
func (s *KeeperTestSuite) TestApplyMessageInternalFloor() {
s.EnableFeemarket = true
defer func() { s.EnableFeemarket = false }()
s.SetupTest()

sender := s.Keyring.GetKey(0)
recipient := s.Keyring.GetAddr(1)
calldata := bytes.Repeat([]byte{0x01}, 2048)
coreMsg, err := s.Factory.GenerateGethCoreMsg(sender.Priv, types.EvmTxArgs{
To: &recipient,
Amount: big.NewInt(100),
Input: calldata,
GasLimit: 110_000,
})
s.Require().NoError(err)

stateDB := statedb.New(s.Network.GetContext(), s.Network.App.GetEVMKeeper(), statedb.NewEmptyTxConfig())
// internal=true: the path used by x/vm/keeper.CallEVM.
res, err := s.Network.App.GetEVMKeeper().ApplyMessage(s.Network.GetContext(), stateDB, *coreMsg, nil, true, false, true)
s.Require().NoError(err)
s.Require().False(res.Failed())
floorDataGas := params.TxGas + params.TxCostFloorPerToken*params.TxTokenPerNonZeroByte*uint64(len(calldata))
s.Require().Equal(floorDataGas, res.GasUsed)
}

func (s *KeeperTestSuite) TestApplyMessageWithConfig() {
s.EnableFeemarket = true
defer func() { s.EnableFeemarket = false }()
Expand All @@ -938,6 +965,8 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() {
},
}

calldata := bytes.Repeat([]byte{0x01}, 2048)

testCases := []struct {
name string
getMessage func() core.Message
Expand Down Expand Up @@ -1134,6 +1163,30 @@ func (s *KeeperTestSuite) TestApplyMessageWithConfig() {
expVMErr: false,
expectedGasUsed: params.TxGas,
},
{
// EIP-7623: calldata floor clamps gasUsed when it exceeds intrinsic
// and the Cosmos minGasMultiplier floor.
name: "success - EIP-7623 floor data gas binds gas used",
getMessage: func() core.Message {
sender := s.Keyring.GetKey(0)
recipient := s.Keyring.GetAddr(1)
msg, err := s.Factory.GenerateGethCoreMsg(sender.Priv, types.EvmTxArgs{
To: &recipient,
Amount: big.NewInt(100),
Input: calldata,
GasLimit: 110_000,
})
s.Require().NoError(err)
return *msg
},
getEVMParams: types.DefaultParams,
getFeeMarketParams: feemarkettypes.DefaultParams,
overrides: nil,
expErr: false,
expVMErr: false,
expectedGasUsed: params.TxGas + params.TxCostFloorPerToken*params.TxTokenPerNonZeroByte*uint64(len(calldata)),
postCheck: nil,
},
{
name: "call contract tx with config param EnableCall = false",
getMessage: func() core.Message {
Expand Down
7 changes: 6 additions & 1 deletion x/vm/keeper/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -462,8 +462,9 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, stateDB *statedb.StateD
// eth_estimateGas will check for this exact error
return nil, errorsmod.Wrap(core.ErrIntrinsicGas, "apply message")
}
var floorDataGas uint64
if rules.IsPrague {
floorDataGas, err := core.FloorDataGas(msg.Data)
floorDataGas, err = core.FloorDataGas(msg.Data)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -593,6 +594,10 @@ func (k *Keeper) ApplyMessageWithConfig(ctx sdk.Context, stateDB *statedb.StateD
if !internal {
gasUsed = math.LegacyMaxDec(gasUsed, minimumGasUsed)
}
// EIP-7623: charged gas must be at least the calldata floor after refunds.
if rules.IsPrague {
gasUsed = math.LegacyMaxDec(gasUsed, math.LegacyNewDec(int64(floorDataGas))) //#nosec G115 -- floorDataGas is bounded by msg.GasLimit (checked above), well below MaxInt64
}
// reset leftoverGas, to be used by the tracingHooks
leftoverGas = msg.GasLimit - gasUsed.TruncateInt().Uint64()

Expand Down
Loading