mirror of
https://github.com/0glabs/0g-chain.git
synced 2025-04-01 14:26:02 +00:00
fix(evmutil): implement gas validation for EVM calls - Add MaxGasLimit constant (30M gas) - Replace infinite gas meter with limited gas meter - Add validation for gas estimation and usage - Add unit tests for gas validation - Add new error type for gas limit exceeded
This commit is contained in:
parent
11b62b3305
commit
2fcc7916c6
@ -25,12 +25,16 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/evmos/ethermint/server/config"
|
||||
evmtypes "github.com/evmos/ethermint/x/evm/types"
|
||||
|
||||
"github.com/0glabs/0g-chain/x/evmutil/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// MaxGasLimit defines the maximum gas that can be used in EVM execution
|
||||
MaxGasLimit = uint64(30_000_000)
|
||||
)
|
||||
|
||||
// CallEVM performs a smart contract method call using given args
|
||||
func (k Keeper) CallEVM(
|
||||
ctx sdk.Context,
|
||||
@ -89,7 +93,15 @@ func (k Keeper) CallEVMWithData(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ethGasContext := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
// Use a limited gas meter instead of infinite
|
||||
maxGas := ctx.GasMeter().Limit()
|
||||
if maxGas == 0 {
|
||||
maxGas = MaxGasLimit
|
||||
}
|
||||
if maxGas > MaxGasLimit {
|
||||
return nil, errorsmod.Wrapf(types.ErrGasLimitExceeded, "requested gas %d exceeds limit %d", maxGas, MaxGasLimit)
|
||||
}
|
||||
ethGasContext := ctx.WithGasMeter(sdk.NewGasMeter(maxGas))
|
||||
|
||||
// EstimateGas applies the transaction against current block state to get
|
||||
// optimal gas value. Since this is done right before the ApplyMessage
|
||||
@ -100,12 +112,17 @@ func (k Keeper) CallEVMWithData(
|
||||
// apply, tx order is the same, etc.)
|
||||
gasRes, err := k.evmKeeper.EstimateGas(sdk.WrapSDKContext(ethGasContext), &evmtypes.EthCallRequest{
|
||||
Args: args,
|
||||
GasCap: config.DefaultGasCap,
|
||||
GasCap: maxGas,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errorsmod.Wrap(evmtypes.ErrVMExecution, err.Error())
|
||||
}
|
||||
|
||||
// Validate estimated gas is within limits
|
||||
if gasRes.Gas > maxGas {
|
||||
return nil, errorsmod.Wrapf(types.ErrGasLimitExceeded, "estimated gas %d exceeds limit %d", gasRes.Gas, maxGas)
|
||||
}
|
||||
|
||||
msg := ethtypes.NewMessage(
|
||||
from,
|
||||
to,
|
||||
@ -129,6 +146,11 @@ func (k Keeper) CallEVMWithData(
|
||||
return nil, errorsmod.Wrap(evmtypes.ErrVMExecution, res.VmError)
|
||||
}
|
||||
|
||||
// Validate gas used is within limits
|
||||
if res.GasUsed > maxGas {
|
||||
return nil, errorsmod.Wrapf(types.ErrGasLimitExceeded, "gas used %d exceeds limit %d", res.GasUsed, maxGas)
|
||||
}
|
||||
|
||||
ctx.GasMeter().ConsumeGas(res.GasUsed, "evm gas consumed")
|
||||
|
||||
return res, nil
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/evmos/ethermint/x/evm/statedb"
|
||||
"github.com/evmos/ethermint/x/evm/types"
|
||||
|
||||
"github.com/0glabs/0g-chain/x/evmutil/keeper"
|
||||
"github.com/0glabs/0g-chain/x/evmutil/testutil"
|
||||
)
|
||||
|
||||
@ -135,3 +136,56 @@ func (suite *evmKeeperTestSuite) TestEvmKeeper_SetAccount() {
|
||||
func TestEvmKeeperTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(evmKeeperTestSuite))
|
||||
}
|
||||
|
||||
func (suite *evmKeeperTestSuite) TestCallEVMWithData_GasLimits() {
|
||||
// Setup test contract
|
||||
addr := testutil.GenerateAddress()
|
||||
contract := types.NewInternalEVMAddress(addr)
|
||||
from := common.BytesToAddress(suite.Key1.PubKey().Address())
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
gasLimit uint64
|
||||
expPass bool
|
||||
}{
|
||||
{
|
||||
"success - gas within limits",
|
||||
keeper.MaxGasLimit - 1,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"success - gas at max limit",
|
||||
keeper.MaxGasLimit,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"fail - gas exceeds max limit",
|
||||
keeper.MaxGasLimit + 1,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
ctx := suite.Ctx.WithGasMeter(sdk.NewGasMeter(tc.gasLimit))
|
||||
|
||||
// Create dummy contract call data
|
||||
data := crypto.Keccak256([]byte("test"))
|
||||
|
||||
// Execute contract call
|
||||
_, err := suite.App.EvmutilKeeper.CallEVMWithData(
|
||||
ctx,
|
||||
from,
|
||||
&contract,
|
||||
data,
|
||||
)
|
||||
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
suite.Require().ErrorIs(err, types.ErrGasLimitExceeded)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -12,4 +12,5 @@ var (
|
||||
ErrInvalidCosmosDenom = errorsmod.Register(ModuleName, 7, "invalid cosmos denom")
|
||||
ErrSDKConversionNotEnabled = errorsmod.Register(ModuleName, 8, "sdk.Coin not enabled to convert to ERC20 token")
|
||||
ErrInsufficientConversionAmount = errorsmod.Register(ModuleName, 9, "insufficient conversion amount")
|
||||
ErrGasLimitExceeded = errorsmod.Register(ModuleName, 10, "gas limit exceeded maximum allowed")
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user