diff --git a/CHANGELOG.md b/CHANGELOG.md index d6210d412a..057be4244a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ ### State Machine Breaking - [#1232](https://github.com/crypto-org-chain/cronos/pull/1232) Adjust require gas in relayer precompile to be closed with actual consumed. +- [#1237](https://github.com/crypto-org-chain/cronos/pull/1237) Adjust require gas in ica precompile to be closed with actual consumed. *October 17, 2023* diff --git a/app/app.go b/app/app.go index 846a19f5aa..9190270759 100644 --- a/app/app.go +++ b/app/app.go @@ -537,7 +537,7 @@ func New( evmS, []vm.PrecompiledContract{ cronosprecompiles.NewRelayerContract(app.IBCKeeper, appCodec, app.Logger()), - cronosprecompiles.NewIcaContract(&app.ICAAuthKeeper, &app.CronosKeeper, appCodec, gasConfig), + cronosprecompiles.NewIcaContract(&app.ICAAuthKeeper, &app.CronosKeeper, appCodec, gasConfig, app.Logger()), }, allKeys, ) diff --git a/x/cronos/keeper/precompiles/ica.go b/x/cronos/keeper/precompiles/ica.go index 9a63608392..5fc414e033 100644 --- a/x/cronos/keeper/precompiles/ica.go +++ b/x/cronos/keeper/precompiles/ica.go @@ -6,7 +6,9 @@ import ( "math/big" "time" + "github.com/cometbft/cometbft/libs/log" storetypes "github.com/cosmos/cosmos-sdk/store/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -20,6 +22,7 @@ import ( icaauthtypes "github.com/crypto-org-chain/cronos/v2/x/icaauth/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" ) @@ -33,6 +36,7 @@ var ( icaABI abi.ABI icaCallbackABI abi.ABI icaContractAddress = common.BytesToAddress([]byte{102}) + icaMethodNamedByMethod = map[[4]byte]string{} icaGasRequiredByMethod = map[[4]byte]uint64{} ) @@ -49,14 +53,15 @@ func init() { copy(methodID[:], icaABI.Methods[methodName].ID[:4]) switch methodName { case RegisterAccountMethodName: - icaGasRequiredByMethod[methodID] = 300000 + icaGasRequiredByMethod[methodID] = 231455 case QueryAccountMethodName: - icaGasRequiredByMethod[methodID] = 100000 + icaGasRequiredByMethod[methodID] = 1000 + 1000 // HasCost + ReadFlat case SubmitMsgsMethodName: - icaGasRequiredByMethod[methodID] = 300000 + icaGasRequiredByMethod[methodID] = 83086 default: icaGasRequiredByMethod[methodID] = 0 } + icaMethodNamedByMethod[methodID] = methodName } } @@ -71,15 +76,17 @@ type IcaContract struct { icaauthKeeper types.Icaauthkeeper cronosKeeper types.CronosKeeper kvGasConfig storetypes.GasConfig + logger log.Logger } -func NewIcaContract(icaauthKeeper types.Icaauthkeeper, cronosKeeper types.CronosKeeper, cdc codec.Codec, kvGasConfig storetypes.GasConfig) vm.PrecompiledContract { +func NewIcaContract(icaauthKeeper types.Icaauthkeeper, cronosKeeper types.CronosKeeper, cdc codec.Codec, kvGasConfig storetypes.GasConfig, logger log.Logger) vm.PrecompiledContract { return &IcaContract{ BaseContract: NewBaseContract(icaContractAddress), cdc: cdc, icaauthKeeper: icaauthKeeper, cronosKeeper: cronosKeeper, kvGasConfig: kvGasConfig, + logger: logger.With("precompiles", "ica"), } } @@ -88,16 +95,35 @@ func (ic *IcaContract) Address() common.Address { } // RequiredGas calculates the contract gas use -func (ic *IcaContract) RequiredGas(input []byte) uint64 { - // base cost to prevent large input size - baseCost := uint64(len(input)) * ic.kvGasConfig.WriteCostPerByte +// write `max(0, len(input) * DefaultTxSizeCostPerByte + requiredGasTable[methodPrefix] - intrinsicGas)` +// query `len(input) * ReadCostPerByte + HasCost + ReadFlat` +func (ic *IcaContract) RequiredGas(input []byte) (gas uint64) { var methodID [4]byte copy(methodID[:], input[:4]) requiredGas, ok := icaGasRequiredByMethod[methodID] - if ok { - return requiredGas + baseCost + if !ok { + requiredGas = 0 + } + // base cost to prevent large input size + baseCost := uint64(0) + method := icaMethodNamedByMethod[methodID] + intrinsicGas, err := core.IntrinsicGas(input, nil, false, true, true) + if err != nil { + return 0 + } + if method == QueryAccountMethodName { + baseCost = uint64(len(input)) * ic.kvGasConfig.ReadCostPerByte + } else { + baseCost = uint64(len(input)) * authtypes.DefaultTxSizeCostPerByte + } + defer func() { + ic.logger.Debug("required", "gas", gas, "method", method, "len", len(input), "intrinsic", intrinsicGas) + }() + total := requiredGas + baseCost + if total < intrinsicGas { + return 0 } - return baseCost + return total - intrinsicGas } func (ic *IcaContract) IsStateful() bool {