From 5e07a2b7a9e086460744b60661c71b297cbeb88d Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 25 Oct 2023 09:42:13 +0800 Subject: [PATCH 1/5] Problem: no require gas log in precompiles --- CHANGELOG.md | 4 ++++ app/app.go | 2 +- x/cronos/keeper/precompiles/relayer.go | 19 ++++++++++++++----- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 905bf90c07..5e6a7f3587 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ - [#1215](https://github.com/crypto-org-chain/cronos/pull/1215) Update ethermint to fix of concurrent write in fee history. - [#1217](https://github.com/crypto-org-chain/cronos/pull/1217) Use the default chain-id behavour in sdk. +### Improvements + +- [#](https://github.com/crypto-org-chain/cronos/pull/) Add required gas log in precompiles. + *October 17, 2023* ## v1.1.0-rc1 diff --git a/app/app.go b/app/app.go index b764b33675..305b17dca2 100644 --- a/app/app.go +++ b/app/app.go @@ -553,7 +553,7 @@ func New( tracer, evmS, []vm.PrecompiledContract{ - cronosprecompiles.NewRelayerContract(app.IBCKeeper, appCodec, gasConfig), + cronosprecompiles.NewRelayerContract(app.IBCKeeper, appCodec, gasConfig, app.Logger()), cronosprecompiles.NewIcaContract(&app.ICAAuthKeeper, &app.CronosKeeper, appCodec, gasConfig), }, allKeys, diff --git a/x/cronos/keeper/precompiles/relayer.go b/x/cronos/keeper/precompiles/relayer.go index 8154e271ae..78995077c9 100644 --- a/x/cronos/keeper/precompiles/relayer.go +++ b/x/cronos/keeper/precompiles/relayer.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" + "github.com/cometbft/cometbft/libs/log" ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" cronosevents "github.com/crypto-org-chain/cronos/v2/x/cronos/events" ) @@ -44,14 +45,16 @@ type RelayerContract struct { cdc codec.Codec ibcKeeper *ibckeeper.Keeper kvGasConfig storetypes.GasConfig + logger log.Logger } -func NewRelayerContract(ibcKeeper *ibckeeper.Keeper, cdc codec.Codec, kvGasConfig storetypes.GasConfig) vm.PrecompiledContract { +func NewRelayerContract(ibcKeeper *ibckeeper.Keeper, cdc codec.Codec, kvGasConfig storetypes.GasConfig, logger log.Logger) vm.PrecompiledContract { return &RelayerContract{ BaseContract: NewBaseContract(relayerContractAddress), ibcKeeper: ibcKeeper, cdc: cdc, kvGasConfig: kvGasConfig, + logger: logger.With("precompiles", "relayer"), } } @@ -60,13 +63,19 @@ func (bc *RelayerContract) Address() common.Address { } // RequiredGas calculates the contract gas use -func (bc *RelayerContract) RequiredGas(input []byte) uint64 { +func (bc *RelayerContract) RequiredGas(input []byte) (gas uint64) { + prefix := 0 + inputLen := 0 + defer func() { + bc.logger.Info("required", "gas", gas, "prefix", prefix, "len", inputLen) + }() // base cost to prevent large input size - baseCost := uint64(len(input)) * bc.kvGasConfig.WriteCostPerByte + inputLen = len(input) + baseCost := uint64(inputLen) * bc.kvGasConfig.WriteCostPerByte if len(input) < prefixSize4Bytes { - return 0 + return } - prefix := int(binary.LittleEndian.Uint32(input[:prefixSize4Bytes])) + prefix = int(binary.LittleEndian.Uint32(input[:prefixSize4Bytes])) requiredGas, ok := relayerGasRequiredByMethod[prefix] if ok { return requiredGas + baseCost From df59ecf00e400b0dadb4d78fe87fed25136b9270 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 25 Oct 2023 09:41:55 +0800 Subject: [PATCH 2/5] add log in ica --- app/app.go | 2 +- x/cronos/keeper/precompiles/ica.go | 24 +++++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/app.go b/app/app.go index 305b17dca2..c5214ef47b 100644 --- a/app/app.go +++ b/app/app.go @@ -554,7 +554,7 @@ func New( evmS, []vm.PrecompiledContract{ cronosprecompiles.NewRelayerContract(app.IBCKeeper, appCodec, gasConfig, 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..a03aadd2db 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 } } @@ -71,15 +74,23 @@ 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,11 +99,18 @@ func (ic *IcaContract) Address() common.Address { } // RequiredGas calculates the contract gas use -func (ic *IcaContract) RequiredGas(input []byte) uint64 { +func (ic *IcaContract) RequiredGas(input []byte) (gas uint64) { + method := "" + inputLen := 0 + defer func() { + ic.logger.Info("required", "gas", gas, "method", method, "len", inputLen) + }() // base cost to prevent large input size - baseCost := uint64(len(input)) * ic.kvGasConfig.WriteCostPerByte + inputLen = len(input) + baseCost := uint64(inputLen) * ic.kvGasConfig.WriteCostPerByte var methodID [4]byte copy(methodID[:], input[:4]) + method = icaMethodMap[methodID] requiredGas, ok := icaGasRequiredByMethod[methodID] if ok { return requiredGas + baseCost From 707a600d8f299b748fd9ca78ea42d72c8b6ba108 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 25 Oct 2023 09:41:58 +0800 Subject: [PATCH 3/5] add log in bank --- x/cronos/keeper/precompiles/bank.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/x/cronos/keeper/precompiles/bank.go b/x/cronos/keeper/precompiles/bank.go index cd0d35c306..9e29eb864e 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 } } @@ -61,11 +64,17 @@ type BankContract struct { bankKeeper types.BankKeeper cdc codec.Codec kvGasConfig storetypes.GasConfig + logger log.Logger } // 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{ + bankKeeper: bankKeeper, + cdc: cdc, + kvGasConfig: kvGasConfig, + logger: logger.With("precompiles", "bank"), + } } func (bc *BankContract) Address() common.Address { @@ -73,11 +82,18 @@ func (bc *BankContract) Address() common.Address { } // RequiredGas calculates the contract gas use -func (bc *BankContract) RequiredGas(input []byte) uint64 { +func (bc *BankContract) RequiredGas(input []byte) (gas uint64) { + method := "" + inputLen := 0 + defer func() { + bc.logger.Info("required", "gas", gas, "method", method, "len", inputLen) + }() // base cost to prevent large input size - baseCost := uint64(len(input)) * bc.kvGasConfig.WriteCostPerByte + inputLen = len(input) + baseCost := uint64(inputLen) * bc.kvGasConfig.WriteCostPerByte var methodID [4]byte copy(methodID[:], input[:4]) + method = bankMethodMap[methodID] requiredGas, ok := bankGasRequiredByMethod[methodID] if ok { return requiredGas + baseCost From a9d070e2550a79ff64915ca3e12a26d40e902415 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 25 Oct 2023 09:42:04 +0800 Subject: [PATCH 4/5] mv log gas to base --- x/cronos/keeper/precompiles/bank.go | 42 +++------ x/cronos/keeper/precompiles/base_contract.go | 46 +++++++++- x/cronos/keeper/precompiles/ica.go | 33 ++----- x/cronos/keeper/precompiles/relayer.go | 94 ++++++++++---------- 4 files changed, 111 insertions(+), 104 deletions(-) diff --git a/x/cronos/keeper/precompiles/bank.go b/x/cronos/keeper/precompiles/bank.go index 9e29eb864e..6a56b38f50 100644 --- a/x/cronos/keeper/precompiles/bank.go +++ b/x/cronos/keeper/precompiles/bank.go @@ -61,19 +61,25 @@ func EVMDenom(token common.Address) string { } type BankContract struct { - bankKeeper types.BankKeeper - cdc codec.Codec - kvGasConfig storetypes.GasConfig - logger log.Logger + 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, logger log.Logger) vm.PrecompiledContract { return &BankContract{ - bankKeeper: bankKeeper, - cdc: cdc, - kvGasConfig: kvGasConfig, - logger: logger.With("precompiles", "bank"), + BaseContract: NewBaseContract( + bankContractAddress, + kvGasConfig, + bankMethodMap, + bankGasRequiredByMethod, + false, + logger.With("precompiles", "bank"), + ), + cdc: cdc, + bankKeeper: bankKeeper, } } @@ -81,26 +87,6 @@ func (bc *BankContract) Address() common.Address { return bankContractAddress } -// RequiredGas calculates the contract gas use -func (bc *BankContract) RequiredGas(input []byte) (gas uint64) { - method := "" - inputLen := 0 - defer func() { - bc.logger.Info("required", "gas", gas, "method", method, "len", inputLen) - }() - // base cost to prevent large input size - inputLen = len(input) - baseCost := uint64(inputLen) * bc.kvGasConfig.WriteCostPerByte - var methodID [4]byte - copy(methodID[:], input[:4]) - method = bankMethodMap[methodID] - 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..e31355a6d1 100644 --- a/x/cronos/keeper/precompiles/base_contract.go +++ b/x/cronos/keeper/precompiles/base_contract.go @@ -1,6 +1,8 @@ package precompiles import ( + "github.com/cometbft/cometbft/libs/log" + storetypes "github.com/cosmos/cosmos-sdk/store/types" "github.com/ethereum/go-ethereum/common" ) @@ -10,18 +12,56 @@ type Registrable interface { type BaseContract interface { Registrable + RequiredGas(input []byte) uint64 } type baseContract struct { - address common.Address + address common.Address + kvGasConfig storetypes.GasConfig + 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, + kvGasConfig storetypes.GasConfig, + nameByMethod map[[4]byte]string, + gasByMethod map[[4]byte]uint64, + emptyGasIfInputLessThanPrefix bool, + logger log.Logger, +) BaseContract { return &baseContract{ - address: address, + address, + kvGasConfig, + 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.Info("required", "gas", gas, "method", method, "len", inputLen) + }() + if c.emptyGasIfInputLessThanPrefix && inputLen < 4 { + return + } + // base cost to prevent large input size + gas = uint64(inputLen) * c.kvGasConfig.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 a03aadd2db..b1a26dbfb1 100644 --- a/x/cronos/keeper/precompiles/ica.go +++ b/x/cronos/keeper/precompiles/ica.go @@ -73,8 +73,6 @@ type IcaContract struct { cdc codec.Codec icaauthKeeper types.Icaauthkeeper cronosKeeper types.CronosKeeper - kvGasConfig storetypes.GasConfig - logger log.Logger } func NewIcaContract( @@ -85,12 +83,17 @@ func NewIcaContract( logger log.Logger, ) vm.PrecompiledContract { return &IcaContract{ - BaseContract: NewBaseContract(icaContractAddress), + BaseContract: NewBaseContract( + icaContractAddress, + kvGasConfig, + icaMethodMap, + icaGasRequiredByMethod, + false, + logger.With("precompiles", "ica"), + ), cdc: cdc, icaauthKeeper: icaauthKeeper, cronosKeeper: cronosKeeper, - kvGasConfig: kvGasConfig, - logger: logger.With("precompiles", "ica"), } } @@ -98,26 +101,6 @@ func (ic *IcaContract) Address() common.Address { return icaContractAddress } -// RequiredGas calculates the contract gas use -func (ic *IcaContract) RequiredGas(input []byte) (gas uint64) { - method := "" - inputLen := 0 - defer func() { - ic.logger.Info("required", "gas", gas, "method", method, "len", inputLen) - }() - // base cost to prevent large input size - inputLen = len(input) - baseCost := uint64(inputLen) * ic.kvGasConfig.WriteCostPerByte - var methodID [4]byte - copy(methodID[:], input[:4]) - method = icaMethodMap[methodID] - 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 78995077c9..e0d207fbae 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" storetypes "github.com/cosmos/cosmos-sdk/store/types" @@ -17,44 +18,62 @@ import ( 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] = 200000 - relayerGasRequiredByMethod[prefixUpdateClient] = 400000 - relayerGasRequiredByMethod[prefixUpgradeClient] = 400000 - relayerGasRequiredByMethod[prefixSubmitMisbehaviour] = 100000 - relayerGasRequiredByMethod[prefixConnectionOpenInit] = 100000 - relayerGasRequiredByMethod[prefixConnectionOpenTry] = 100000 - relayerGasRequiredByMethod[prefixConnectionOpenAck] = 100000 - relayerGasRequiredByMethod[prefixConnectionOpenConfirm] = 100000 - relayerGasRequiredByMethod[prefixChannelOpenInit] = 100000 - relayerGasRequiredByMethod[prefixChannelOpenTry] = 100000 - relayerGasRequiredByMethod[prefixChannelOpenAck] = 100000 - relayerGasRequiredByMethod[prefixChannelOpenConfirm] = 100000 - relayerGasRequiredByMethod[prefixRecvPacket] = 250000 - relayerGasRequiredByMethod[prefixAcknowledgement] = 250000 - relayerGasRequiredByMethod[prefixTimeout] = 100000 - relayerGasRequiredByMethod[prefixTimeoutOnClose] = 100000 + assignMethodGas(prefixCreateClient, 200000) + assignMethodGas(prefixUpdateClient, 400000) + assignMethodGas(prefixUpgradeClient, 400000) + assignMethodGas(prefixSubmitMisbehaviour, 100000) + assignMethodGas(prefixConnectionOpenInit, 100000) + assignMethodGas(prefixConnectionOpenTry, 100000) + assignMethodGas(prefixConnectionOpenAck, 100000) + assignMethodGas(prefixConnectionOpenConfirm, 100000) + assignMethodGas(prefixChannelOpenInit, 100000) + assignMethodGas(prefixChannelOpenTry, 100000) + assignMethodGas(prefixChannelOpenAck, 100000) + assignMethodGas(prefixChannelOpenConfirm, 100000) + assignMethodGas(prefixRecvPacket, 250000) + assignMethodGas(prefixAcknowledgement, 250000) + assignMethodGas(prefixTimeout, 100000) + assignMethodGas(prefixTimeoutOnClose, 100000) } type RelayerContract struct { BaseContract - cdc codec.Codec - ibcKeeper *ibckeeper.Keeper - kvGasConfig storetypes.GasConfig - logger log.Logger + cdc codec.Codec + ibcKeeper *ibckeeper.Keeper } -func NewRelayerContract(ibcKeeper *ibckeeper.Keeper, cdc codec.Codec, kvGasConfig storetypes.GasConfig, logger log.Logger) vm.PrecompiledContract { +func NewRelayerContract( + ibcKeeper *ibckeeper.Keeper, + cdc codec.Codec, + kvGasConfig storetypes.GasConfig, + logger log.Logger, +) vm.PrecompiledContract { return &RelayerContract{ - BaseContract: NewBaseContract(relayerContractAddress), - ibcKeeper: ibcKeeper, - cdc: cdc, - kvGasConfig: kvGasConfig, - logger: logger.With("precompiles", "relayer"), + BaseContract: NewBaseContract( + relayerContractAddress, + kvGasConfig, + relayerMethodMap, + relayerGasRequiredByMethod, + true, + logger.With("precompiles", "relayer"), + ), + ibcKeeper: ibcKeeper, + cdc: cdc, } } @@ -62,27 +81,6 @@ func (bc *RelayerContract) Address() common.Address { return relayerContractAddress } -// RequiredGas calculates the contract gas use -func (bc *RelayerContract) RequiredGas(input []byte) (gas uint64) { - prefix := 0 - inputLen := 0 - defer func() { - bc.logger.Info("required", "gas", gas, "prefix", prefix, "len", inputLen) - }() - // base cost to prevent large input size - inputLen = len(input) - baseCost := uint64(inputLen) * bc.kvGasConfig.WriteCostPerByte - if len(input) < prefixSize4Bytes { - return - } - prefix = int(binary.LittleEndian.Uint32(input[:prefixSize4Bytes])) - requiredGas, ok := relayerGasRequiredByMethod[prefix] - if ok { - return requiredGas + baseCost - } - return baseCost -} - func (bc *RelayerContract) IsStateful() bool { return true } From 41f3ebcd0c331bd89240bd1232fb12bff90c1f72 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Wed, 25 Oct 2023 09:43:21 +0800 Subject: [PATCH 5/5] Update CHANGELOG.md Signed-off-by: mmsqe --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e6a7f3587..6bc2cc62a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ### Improvements -- [#](https://github.com/crypto-org-chain/cronos/pull/) Add required gas log in precompiles. +- [#1223](https://github.com/crypto-org-chain/cronos/pull/1223) Add required gas log in precompiles. *October 17, 2023*