diff --git a/CHANGELOG.md b/CHANGELOG.md index d6210d412a..fc52827267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,10 @@ - [#1232](https://github.com/crypto-org-chain/cronos/pull/1232) Adjust require gas in relayer precompile to be closed with actual consumed. +### Improvements + +- [#1223](https://github.com/crypto-org-chain/cronos/pull/1223) Add required gas log in precompiles. + *October 17, 2023* ## v1.1.0-rc1 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/bank.go b/x/cronos/keeper/precompiles/bank.go index cd0d35c306..578e2ff51d 100644 --- a/x/cronos/keeper/precompiles/bank.go +++ b/x/cronos/keeper/precompiles/bank.go @@ -4,6 +4,7 @@ import ( "errors" "math/big" + "github.com/cometbft/cometbft/libs/log" storetypes "github.com/cosmos/cosmos-sdk/store/types" sdkmath "cosmossdk.io/math" @@ -31,6 +32,7 @@ var ( bankABI abi.ABI bankContractAddress = common.BytesToAddress([]byte{100}) bankGasRequiredByMethod = map[[4]byte]uint64{} + bankMethodMap = map[[4]byte]string{} ) func init() { @@ -50,6 +52,7 @@ func init() { default: bankGasRequiredByMethod[methodID] = 0 } + bankMethodMap[methodID] = methodName } } @@ -58,33 +61,32 @@ func EVMDenom(token common.Address) string { } type BankContract struct { - bankKeeper types.BankKeeper - cdc codec.Codec - kvGasConfig storetypes.GasConfig + BaseContract + + bankKeeper types.BankKeeper + cdc codec.Codec } // NewBankContract creates the precompiled contract to manage native tokens -func NewBankContract(bankKeeper types.BankKeeper, cdc codec.Codec, kvGasConfig storetypes.GasConfig) vm.PrecompiledContract { - return &BankContract{bankKeeper, cdc, kvGasConfig} +func NewBankContract(bankKeeper types.BankKeeper, cdc codec.Codec, kvGasConfig storetypes.GasConfig, logger log.Logger) vm.PrecompiledContract { + return &BankContract{ + BaseContract: NewBaseContract( + bankContractAddress, + kvGasConfig.WriteCostPerByte, + bankMethodMap, + bankGasRequiredByMethod, + false, + logger.With("precompiles", "bank"), + ), + cdc: cdc, + bankKeeper: bankKeeper, + } } func (bc *BankContract) Address() common.Address { return bankContractAddress } -// RequiredGas calculates the contract gas use -func (bc *BankContract) RequiredGas(input []byte) uint64 { - // base cost to prevent large input size - baseCost := uint64(len(input)) * bc.kvGasConfig.WriteCostPerByte - var methodID [4]byte - copy(methodID[:], input[:4]) - requiredGas, ok := bankGasRequiredByMethod[methodID] - if ok { - return requiredGas + baseCost - } - return baseCost -} - func (bc *BankContract) IsStateful() bool { return true } diff --git a/x/cronos/keeper/precompiles/base_contract.go b/x/cronos/keeper/precompiles/base_contract.go index a50e1a2a38..5193a39931 100644 --- a/x/cronos/keeper/precompiles/base_contract.go +++ b/x/cronos/keeper/precompiles/base_contract.go @@ -1,6 +1,7 @@ package precompiles import ( + "github.com/cometbft/cometbft/libs/log" "github.com/ethereum/go-ethereum/common" ) @@ -10,18 +11,56 @@ type Registrable interface { type BaseContract interface { Registrable + RequiredGas(input []byte) uint64 } type baseContract struct { - address common.Address + address common.Address + writeCostPerByte uint64 + nameByMethod map[[4]byte]string + gasByMethod map[[4]byte]uint64 + emptyGasIfInputLessThanPrefix bool + logger log.Logger } -func NewBaseContract(address common.Address) BaseContract { +func NewBaseContract( + address common.Address, + writeCostPerByte uint64, + nameByMethod map[[4]byte]string, + gasByMethod map[[4]byte]uint64, + emptyGasIfInputLessThanPrefix bool, + logger log.Logger, +) BaseContract { return &baseContract{ - address: address, + address, + writeCostPerByte, + nameByMethod, + gasByMethod, + emptyGasIfInputLessThanPrefix, + logger, } } func (c *baseContract) RegistryKey() common.Address { return c.address } + +// RequiredGas calculates the contract gas use +func (c *baseContract) RequiredGas(input []byte) (gas uint64) { + var methodID [4]byte + copy(methodID[:], input[:4]) + inputLen := len(input) + defer func() { + method := c.nameByMethod[methodID] + c.logger.Debug("required", "gas", gas, "method", method, "len", inputLen) + }() + if c.emptyGasIfInputLessThanPrefix && inputLen < 4 { + return + } + // base cost to prevent large input size + gas = uint64(inputLen) * c.writeCostPerByte + if requiredGas, ok := c.gasByMethod[methodID]; ok { + gas += requiredGas + } + return +} diff --git a/x/cronos/keeper/precompiles/ica.go b/x/cronos/keeper/precompiles/ica.go index 9a63608392..179540ec2b 100644 --- a/x/cronos/keeper/precompiles/ica.go +++ b/x/cronos/keeper/precompiles/ica.go @@ -6,6 +6,7 @@ import ( "math/big" "time" + "github.com/cometbft/cometbft/libs/log" storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/cosmos/cosmos-sdk/codec" @@ -34,6 +35,7 @@ var ( icaCallbackABI abi.ABI icaContractAddress = common.BytesToAddress([]byte{102}) icaGasRequiredByMethod = map[[4]byte]uint64{} + icaMethodMap = map[[4]byte]string{} ) func init() { @@ -57,6 +59,7 @@ func init() { default: icaGasRequiredByMethod[methodID] = 0 } + icaMethodMap[methodID] = methodName } } @@ -70,16 +73,27 @@ type IcaContract struct { cdc codec.Codec icaauthKeeper types.Icaauthkeeper cronosKeeper types.CronosKeeper - kvGasConfig storetypes.GasConfig } -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), + BaseContract: NewBaseContract( + icaContractAddress, + kvGasConfig.WriteCostPerByte, + icaMethodMap, + icaGasRequiredByMethod, + false, + logger.With("precompiles", "ica"), + ), cdc: cdc, icaauthKeeper: icaauthKeeper, cronosKeeper: cronosKeeper, - kvGasConfig: kvGasConfig, } } @@ -87,19 +101,6 @@ func (ic *IcaContract) Address() common.Address { return icaContractAddress } -// 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 - var methodID [4]byte - copy(methodID[:], input[:4]) - requiredGas, ok := icaGasRequiredByMethod[methodID] - if ok { - return requiredGas + baseCost - } - return baseCost -} - func (ic *IcaContract) IsStateful() bool { return true } diff --git a/x/cronos/keeper/precompiles/relayer.go b/x/cronos/keeper/precompiles/relayer.go index 439a0080f7..a9cdcd1abe 100644 --- a/x/cronos/keeper/precompiles/relayer.go +++ b/x/cronos/keeper/precompiles/relayer.go @@ -3,6 +3,7 @@ package precompiles import ( "encoding/binary" "errors" + "fmt" "github.com/cometbft/cometbft/libs/log" @@ -12,34 +13,45 @@ import ( "github.com/ethereum/go-ethereum/core/vm" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" cronosevents "github.com/crypto-org-chain/cronos/v2/x/cronos/events" "github.com/crypto-org-chain/cronos/v2/x/cronos/types" ) var ( relayerContractAddress = common.BytesToAddress([]byte{101}) - relayerGasRequiredByMethod = map[int]uint64{} + relayerGasRequiredByMethod = map[[4]byte]uint64{} + relayerMethodMap = map[[4]byte]string{} ) +func assignMethodGas(prefix int, gas uint64) { + data := make([]byte, 4) + binary.LittleEndian.PutUint32(data, uint32(prefix)) + var id [4]byte + copy(id[:], data[:4]) + relayerMethodMap[id] = fmt.Sprintf("%d", prefix) + relayerGasRequiredByMethod[id] = gas +} + func init() { - relayerGasRequiredByMethod[prefixCreateClient] = 117462 - relayerGasRequiredByMethod[prefixUpdateClient] = 111894 - relayerGasRequiredByMethod[prefixUpgradeClient] = 400000 - relayerGasRequiredByMethod[prefixSubmitMisbehaviour] = 100000 - relayerGasRequiredByMethod[prefixConnectionOpenInit] = 19755 - relayerGasRequiredByMethod[prefixConnectionOpenTry] = 38468 - relayerGasRequiredByMethod[prefixConnectionOpenAck] = 29603 - relayerGasRequiredByMethod[prefixConnectionOpenConfirm] = 12865 - relayerGasRequiredByMethod[prefixChannelOpenInit] = 68701 - relayerGasRequiredByMethod[prefixChannelOpenTry] = 70562 - relayerGasRequiredByMethod[prefixChannelOpenAck] = 22127 - relayerGasRequiredByMethod[prefixChannelOpenConfirm] = 21190 - relayerGasRequiredByMethod[prefixChannelCloseInit] = 100000 - relayerGasRequiredByMethod[prefixChannelCloseConfirm] = 31199 - relayerGasRequiredByMethod[prefixRecvPacket] = 144025 - relayerGasRequiredByMethod[prefixAcknowledgement] = 61781 - relayerGasRequiredByMethod[prefixTimeout] = 104283 - relayerGasRequiredByMethod[prefixTimeoutOnClose] = 100000 + assignMethodGas(prefixCreateClient, 117462) + assignMethodGas(prefixUpdateClient, 111894) + assignMethodGas(prefixUpgradeClient, 400000) + assignMethodGas(prefixSubmitMisbehaviour, 100000) + assignMethodGas(prefixConnectionOpenInit, 19755) + assignMethodGas(prefixConnectionOpenTry, 38468) + assignMethodGas(prefixConnectionOpenAck, 29603) + assignMethodGas(prefixConnectionOpenConfirm, 12865) + assignMethodGas(prefixChannelOpenInit, 68701) + assignMethodGas(prefixChannelOpenTry, 70562) + assignMethodGas(prefixChannelOpenAck, 22127) + assignMethodGas(prefixChannelOpenConfirm, 21190) + assignMethodGas(prefixChannelCloseInit, 100000) + assignMethodGas(prefixChannelCloseConfirm, 31199) + assignMethodGas(prefixRecvPacket, 144025) + assignMethodGas(prefixAcknowledgement, 61781) + assignMethodGas(prefixTimeout, 104283) + assignMethodGas(prefixTimeoutOnClose, 100000) } type RelayerContract struct { @@ -50,12 +62,24 @@ type RelayerContract struct { logger log.Logger } -func NewRelayerContract(ibcKeeper types.IbcKeeper, cdc codec.Codec, logger log.Logger) vm.PrecompiledContract { +func NewRelayerContract( + ibcKeeper *ibckeeper.Keeper, + cdc codec.Codec, + logger log.Logger, +) vm.PrecompiledContract { + bcLogger := logger.With("precompiles", "relayer") return &RelayerContract{ - BaseContract: NewBaseContract(relayerContractAddress), - ibcKeeper: ibcKeeper, - cdc: cdc, - logger: logger.With("precompiles", "relayer"), + BaseContract: NewBaseContract( + relayerContractAddress, + authtypes.DefaultTxSizeCostPerByte, + relayerMethodMap, + relayerGasRequiredByMethod, + true, + bcLogger, + ), + ibcKeeper: ibcKeeper, + cdc: cdc, + logger: bcLogger, } } @@ -66,24 +90,16 @@ func (bc *RelayerContract) Address() common.Address { // RequiredGas calculates the contract gas use // `max(0, len(input) * DefaultTxSizeCostPerByte + requiredGasTable[methodPrefix] - intrinsicGas)` func (bc *RelayerContract) RequiredGas(input []byte) (gas uint64) { - if len(input) < prefixSize4Bytes { - return 0 - } intrinsicGas, err := core.IntrinsicGas(input, nil, false, true, true) if err != nil { return 0 } - prefix := int(binary.LittleEndian.Uint32(input[:prefixSize4Bytes])) - requiredGas, ok := relayerGasRequiredByMethod[prefix] - if !ok { - requiredGas = 0 - } - // base cost to prevent large input size - baseCost := uint64(len(input)) * authtypes.DefaultTxSizeCostPerByte + + total := bc.BaseContract.RequiredGas(input) defer func() { - bc.logger.Debug("required", "gas", gas, "method", prefix, "len", len(input), "intrinsic", intrinsicGas) + bc.logger.Debug("required", "gas", gas, "intrinsic", intrinsicGas, "total", total) }() - total := requiredGas + baseCost + if total < intrinsicGas { return 0 }