diff --git a/app/ante/decorators.go b/app/ante/decorators.go index 9e2d668b3..9753c7d2a 100644 --- a/app/ante/decorators.go +++ b/app/ante/decorators.go @@ -63,11 +63,15 @@ func (vtd ValidateTokenDecorator) AnteHandle( } // ValidateServiceDecorator is responsible for checking the permission to execute MsgCallService -type ValidateServiceDecorator struct{} +type ValidateServiceDecorator struct { + SimulateTest bool +} // NewValidateServiceDecorator returns an instance of ServiceAuthDecorator -func NewValidateServiceDecorator() ValidateServiceDecorator { - return ValidateServiceDecorator{} +func NewValidateServiceDecorator(simulateTest bool) ValidateServiceDecorator { + return ValidateServiceDecorator{ + SimulateTest: simulateTest, + } } // AnteHandle checks the transaction @@ -77,6 +81,10 @@ func (vsd ValidateServiceDecorator) AnteHandle( simulate bool, next sdk.AnteHandler, ) (sdk.Context, error) { + if vsd.SimulateTest { + return next(ctx, tx, simulate) + } + for _, msg := range tx.GetMsgs() { switch msg := msg.(type) { case *servicetypes.MsgCallService: @@ -85,6 +93,7 @@ func (vsd ValidateServiceDecorator) AnteHandle( } } } + return next(ctx, tx, simulate) } diff --git a/app/ante/handler_options.go b/app/ante/handler_options.go index 38f13e4ae..49115cc6a 100644 --- a/app/ante/handler_options.go +++ b/app/ante/handler_options.go @@ -31,6 +31,7 @@ type HandlerOptions struct { FeeMarketKeeper ethante.FeeMarketKeeper BypassMinFeeMsgTypes []string MaxTxGasWanted uint64 + SimulationTest bool } // newCosmosAnteHandler creates the default ante handler for Ethereum transactions @@ -85,7 +86,7 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { NewValidateTokenDecorator(options.TokenKeeper), tokenkeeper.NewValidateTokenFeeDecorator(options.TokenKeeper, options.BankKeeper), oraclekeeper.NewValidateOracleAuthDecorator(options.OracleKeeper, options.GuardianKeeper), - NewValidateServiceDecorator(), + NewValidateServiceDecorator(options.SimulationTest), ante.NewIncrementSequenceDecorator(options.AccountKeeper), ibcante.NewRedundantRelayDecorator(options.IBCKeeper), ) diff --git a/app/app.go b/app/app.go index acdf3686b..8eb1d28c9 100644 --- a/app/app.go +++ b/app/app.go @@ -177,6 +177,13 @@ func NewIrisApp( app.MountMemoryStores(app.MemoryStoreKeys()) maxGasWanted := cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted)) + + simulationTest := false + opt = appOpts.Get(params.SimulationTest) + if opt, ok := opt.(bool); ok { + simulationTest = opt + } + anteHandler := irishubante.NewAnteHandler( irishubante.HandlerOptions{ HandlerOptions: ante.HandlerOptions{ @@ -195,6 +202,7 @@ func NewIrisApp( FeeMarketKeeper: app.FeeMarketKeeper, BypassMinFeeMsgTypes: []string{}, MaxTxGasWanted: maxGasWanted, + SimulationTest: simulationTest, }, ) diff --git a/app/export.go b/app/export.go index e7ba6a2ab..22e8d7413 100644 --- a/app/export.go +++ b/app/export.go @@ -3,8 +3,6 @@ package app import ( "encoding/json" "fmt" - "log" - tmproto "github.com/cometbft/cometbft/proto/tendermint/types" storetypes "cosmossdk.io/store/types" @@ -72,9 +70,9 @@ func (app *IrisApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [ allowedAddrsMap := make(map[string]bool) for _, addr := range jailAllowedAddrs { - _, err := sdk.ValAddressFromBech32(addr) + _, err := app.InterfaceRegistry().SigningContext().ValidatorAddressCodec().StringToBytes(addr) if err != nil { - log.Fatal(err) + panic(err) } allowedAddrsMap[addr] = true } @@ -85,31 +83,32 @@ func (app *IrisApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [ /* Handle fee distribution state. */ // withdraw all validator commission - app.StakingKeeper.IterateValidators( - ctx, - func(_ int64, val stakingtypes.ValidatorI) (stop bool) { - if _, err := app.DistrKeeper.WithdrawValidatorCommission(ctx, sdk.ValAddress(val.GetOperator())); err != nil { - panic(err) - } - return false - }, - ) + err := app.StakingKeeper.IterateValidators(ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { + valBz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator()) + if err != nil { + panic(err) + } + _, _ = app.DistrKeeper.WithdrawValidatorCommission(ctx, valBz) + return false + }) + if err != nil { + panic(err) + } // withdraw all delegator rewards dels, err := app.StakingKeeper.GetAllDelegations(ctx) if err != nil { panic(err) } + for _, delegation := range dels { valAddr, err := sdk.ValAddressFromBech32(delegation.ValidatorAddress) if err != nil { panic(err) } - delAddr, err := sdk.AccAddressFromBech32(delegation.DelegatorAddress) - if err != nil { - panic(err) - } + delAddr := sdk.MustAccAddressFromBech32(delegation.DelegatorAddress) + _, _ = app.DistrKeeper.WithdrawDelegationRewards(ctx, delAddr, valAddr) } @@ -124,11 +123,15 @@ func (app *IrisApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [ ctx = ctx.WithBlockHeight(0) // reinitialize all validators - app.StakingKeeper.IterateValidators( + err = app.StakingKeeper.IterateValidators( ctx, func(_ int64, val stakingtypes.ValidatorI) (stop bool) { + valBz, err := app.StakingKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator()) + if err != nil { + panic(err) + } // donate any unwithdrawn outstanding reward fraction tokens to the community pool - scraps, err := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, sdk.ValAddress(val.GetOperator())) + scraps, err := app.DistrKeeper.GetValidatorOutstandingRewardsCoins(ctx, valBz) if err != nil { panic(err) } @@ -136,18 +139,20 @@ func (app *IrisApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [ if err != nil { panic(err) } - feePool.CommunityPool = feePool.CommunityPool.Add(scraps...) if err := app.DistrKeeper.FeePool.Set(ctx, feePool); err != nil { panic(err) } - if err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, sdk.ValAddress(val.GetOperator())); err != nil { + if err := app.DistrKeeper.Hooks().AfterValidatorCreated(ctx, valBz); err != nil { panic(err) } return false }, ) + if err != nil { + panic(err) + } // reinitialize all delegations for _, del := range dels { @@ -174,28 +179,31 @@ func (app *IrisApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [ /* Handle staking state. */ // iterate through redelegations, reset creation height - app.StakingKeeper.IterateRedelegations( - ctx, - func(_ int64, red stakingtypes.Redelegation) (stop bool) { - for i := range red.Entries { - red.Entries[i].CreationHeight = 0 - } - app.StakingKeeper.SetRedelegation(ctx, red) - return false - }, - ) + err = app.StakingKeeper.IterateRedelegations(ctx, func(_ int64, red stakingtypes.Redelegation) (stop bool) { + for i := range red.Entries { + red.Entries[i].CreationHeight = 0 + } + err = app.StakingKeeper.SetRedelegation(ctx, red) + if err != nil { + panic(err) + } + return false + }) + if err != nil { + panic(err) + } // iterate through unbonding delegations, reset creation height - app.StakingKeeper.IterateUnbondingDelegations( - ctx, - func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) { - for i := range ubd.Entries { - ubd.Entries[i].CreationHeight = 0 - } - app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) - return false - }, - ) + app.StakingKeeper.IterateUnbondingDelegations(ctx, func(_ int64, ubd stakingtypes.UnbondingDelegation) (stop bool) { + for i := range ubd.Entries { + ubd.Entries[i].CreationHeight = 0 + } + err = app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + if err != nil { + panic(err) + } + return false + }) // Iterate through validators by power descending, reset bond heights, and // update bond intra-tx counters. @@ -207,7 +215,7 @@ func (app *IrisApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [ addr := sdk.ValAddress(stakingtypes.AddressFromValidatorsKey(iter.Key())) validator, err := app.StakingKeeper.GetValidator(ctx, addr) if err != nil { - panic(err) + panic("expected validator, not found") } validator.UnbondingHeight = 0 @@ -215,7 +223,8 @@ func (app *IrisApp) prepForZeroHeightGenesis(ctx sdk.Context, jailAllowedAddrs [ validator.Jailed = true } - if err := app.StakingKeeper.SetValidator(ctx, validator); err != nil { + err = app.StakingKeeper.SetValidator(ctx, validator) + if err != nil { panic(err) } counter++ diff --git a/app/params/params.go b/app/params/params.go index b6aa5fb55..995644449 100644 --- a/app/params/params.go +++ b/app/params/params.go @@ -4,4 +4,5 @@ package params const ( StakePerAccount = "stake_per_account" InitiallyBondedValidators = "initially_bonded_validators" + SimulationTest = "simulation_test" ) diff --git a/app/sim_bench_test.go b/app/sim_bench_test.go index 0e3524145..884ac78e3 100644 --- a/app/sim_bench_test.go +++ b/app/sim_bench_test.go @@ -11,6 +11,8 @@ import ( simtypes "github.com/cosmos/cosmos-sdk/types/simulation" "github.com/cosmos/cosmos-sdk/x/simulation" simcli "github.com/cosmos/cosmos-sdk/x/simulation/client/cli" + + "github.com/irisnet/irishub/v4/app/params" ) // Profile with: @@ -51,7 +53,9 @@ func BenchmarkFullAppSimulation(b *testing.B) { nil, true, encfg, - EmptyAppOptions{}, + SimTestAppOptions{ + options: map[string]interface{}{params.SimulationTest: true}, + }, interBlockCacheOpt(), ) @@ -118,7 +122,9 @@ func BenchmarkInvariants(b *testing.B) { nil, true, encfg, - EmptyAppOptions{}, + SimTestAppOptions{ + options: map[string]interface{}{params.SimulationTest: true}, + }, interBlockCacheOpt(), ) diff --git a/app/sim_test.go b/app/sim_test.go index 32023104e..f23741a5e 100644 --- a/app/sim_test.go +++ b/app/sim_test.go @@ -196,7 +196,7 @@ func TestAppImportExport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newApp := createApp(logger, db, encfg, fauxMerkleModeOpt) + newApp := createApp(logger, newDB, encfg, fauxMerkleModeOpt) require.Equal(t, "IrisApp", newApp.Name()) var genesisState iristypes.GenesisState @@ -366,13 +366,16 @@ func TestAppSimulationAfterImport(t *testing.T) { require.NoError(t, os.RemoveAll(newDir)) }() - newApp := createApp(logger, db, encfg, fauxMerkleModeOpt) + newApp := createApp(logger, newDB, encfg, fauxMerkleModeOpt) require.Equal(t, "IrisApp", newApp.Name()) - newApp.InitChain(&abci.RequestInitChain{ + _, err = newApp.InitChain(&abci.RequestInitChain{ AppStateBytes: exported.AppState, + ChainId: AppChainID, }) + require.NoError(t, err) + _, _, err = simulation.SimulateFromSeed( t, os.Stdout, @@ -475,6 +478,16 @@ func (ao EmptyAppOptions) Get(o string) interface{} { return nil } +// SimTestAppOptions is a stub implementing AppOptions +type SimTestAppOptions struct { + options map[string]interface{} +} + +// Get implements AppOptions +func (o SimTestAppOptions) Get(key string) interface{} { + return o.options[key] +} + func createApp( logger log.Logger, db dbm.DB, @@ -491,7 +504,9 @@ func createApp( nil, true, encodingConfig, - EmptyAppOptions{}, + SimTestAppOptions{ + options: map[string]interface{}{params.SimulationTest: true}, + }, baseAppOptions..., ) } diff --git a/go.mod b/go.mod index bbda93398..c131c5db4 100644 --- a/go.mod +++ b/go.mod @@ -11,16 +11,16 @@ require ( github.com/cosmos/gogoproto v1.7.0 github.com/cosmos/iavl v1.2.0 // indirect github.com/evmos/ethermint v0.22.0 - mods.irisnet.org/modules/coinswap v0.0.0-20241209074433-1380d52b7709 - mods.irisnet.org/modules/farm v0.0.0-20241209074433-1380d52b7709 - mods.irisnet.org/modules/htlc v0.0.0-20241209074433-1380d52b7709 - mods.irisnet.org/modules/mt v0.0.0-20241209074433-1380d52b7709 - mods.irisnet.org/modules/nft v0.0.0-20241209074433-1380d52b7709 - mods.irisnet.org/modules/oracle v0.0.0-20241209074433-1380d52b7709 - mods.irisnet.org/modules/random v0.0.0-20241209074433-1380d52b7709 - mods.irisnet.org/modules/record v0.0.0-20241209074433-1380d52b7709 - mods.irisnet.org/modules/service v0.0.0-20241209074433-1380d52b7709 - mods.irisnet.org/modules/token v0.0.0-20241209074433-1380d52b7709 + mods.irisnet.org/modules/coinswap v0.0.0-20241217080151-0ad41be03ac6 + mods.irisnet.org/modules/farm v0.0.0-20241217080151-0ad41be03ac6 + mods.irisnet.org/modules/htlc v0.0.0-20241217080151-0ad41be03ac6 + mods.irisnet.org/modules/mt v0.0.0-20241217080151-0ad41be03ac6 + mods.irisnet.org/modules/nft v0.0.0-20241217080151-0ad41be03ac6 + mods.irisnet.org/modules/oracle v0.0.0-20241217080151-0ad41be03ac6 + mods.irisnet.org/modules/random v0.0.0-20241217080151-0ad41be03ac6 + mods.irisnet.org/modules/record v0.0.0-20241217080151-0ad41be03ac6 + mods.irisnet.org/modules/service v0.0.0-20241217080151-0ad41be03ac6 + mods.irisnet.org/modules/token v0.0.0-20241217080151-0ad41be03ac6 ) require ( diff --git a/go.sum b/go.sum index 0c8c7a17f..559452dc1 100644 --- a/go.sum +++ b/go.sum @@ -2065,26 +2065,26 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= mods.irisnet.org/api v0.0.0-20241121030837-903540d1123f h1:tJoTbTqFBZUnCLL+juHEuQLNNdftSXwSlqGoKa8OOxw= mods.irisnet.org/api v0.0.0-20241121030837-903540d1123f/go.mod h1:TpMaRRYSpqsXdeX4gDVFRj9ggedQ60Zcjs4iE2DIhsc= -mods.irisnet.org/modules/coinswap v0.0.0-20241209074433-1380d52b7709 h1:i5lbpX0nC0O8nubflu99ifh716T6kMCvDhhJHsrooFk= -mods.irisnet.org/modules/coinswap v0.0.0-20241209074433-1380d52b7709/go.mod h1:nv52g5ZDWv/C1ydtxLygP2wSYz6M4OuF6BygKy7RqGA= -mods.irisnet.org/modules/farm v0.0.0-20241209074433-1380d52b7709 h1:5bNfktWvUg3FCm8fNO7QAXasGciPLPntz+iKHLh+bKM= -mods.irisnet.org/modules/farm v0.0.0-20241209074433-1380d52b7709/go.mod h1:yYrnhmxDCnvI45u1cpeRZ2GPJUmRK+8KFXDtOJGpENE= -mods.irisnet.org/modules/htlc v0.0.0-20241209074433-1380d52b7709 h1:RJfiSwR9QgbKNqlsonXCw3Unm5mggvIZ2iYVpn4Bew4= -mods.irisnet.org/modules/htlc v0.0.0-20241209074433-1380d52b7709/go.mod h1:2pWkSnxVKCzB3WH+q47rKffY4Plma+mRTGSWd4jfbp8= -mods.irisnet.org/modules/mt v0.0.0-20241209074433-1380d52b7709 h1:MFlghrXXMChdC1xOF9ulfdDzlwdN7UddvMjwaud7W9o= -mods.irisnet.org/modules/mt v0.0.0-20241209074433-1380d52b7709/go.mod h1:Dw1zm350HiRuNjrnwZnV4XGB8PNf1SXmjGJA5Xslg0Q= -mods.irisnet.org/modules/nft v0.0.0-20241209074433-1380d52b7709 h1:VhhLzJknCMQO7HVSVwSVkYKreYm9bk/8P5E8FEZ6KZ8= -mods.irisnet.org/modules/nft v0.0.0-20241209074433-1380d52b7709/go.mod h1:VjySqJfECBW8cApFB8W66Yk6tMR2oJEc7FTDaHfeg8I= -mods.irisnet.org/modules/oracle v0.0.0-20241209074433-1380d52b7709 h1:nDqnB+kyIUkIfRB2LcfdnqDNEnbXHnBIfnEkMWIlO8w= -mods.irisnet.org/modules/oracle v0.0.0-20241209074433-1380d52b7709/go.mod h1:XAGzG55xpV01PwvryVPeaHtARZIqEUJcMv/vxaVcVC0= -mods.irisnet.org/modules/random v0.0.0-20241209074433-1380d52b7709 h1:DWbsZNjeCYzQ6lD7ogoezrHURjc0s4Kkpkn275TGHfo= -mods.irisnet.org/modules/random v0.0.0-20241209074433-1380d52b7709/go.mod h1:1ele5fpZ/rFMbwu1LTz2MwDg3sJDYcCtDW5SDfYRpTg= -mods.irisnet.org/modules/record v0.0.0-20241209074433-1380d52b7709 h1:rmGVgGMdfR8j9jqNfhwDyf5Tsr8IrdaTqxaiHMKnzRU= -mods.irisnet.org/modules/record v0.0.0-20241209074433-1380d52b7709/go.mod h1:n8gRooDvJ5B44EJRZ+UlDz0GcXQeNwjH2tjpnVx7nd8= -mods.irisnet.org/modules/service v0.0.0-20241209074433-1380d52b7709 h1:luRpAYMuG4YYLuf1tUuUzlkEjh41EHc3j5KSiVD82/o= -mods.irisnet.org/modules/service v0.0.0-20241209074433-1380d52b7709/go.mod h1:B1nKRNYn1VLqpvNbmbDSYagqL56sj0MIceXJi/DKg6s= -mods.irisnet.org/modules/token v0.0.0-20241209074433-1380d52b7709 h1:dGuMYcTXIRgmpJHFrSFOV5g4Xc09WSVhz0n8HkbZQoE= -mods.irisnet.org/modules/token v0.0.0-20241209074433-1380d52b7709/go.mod h1:fHJzeEBPhE9vaa4aye90+WFtHjZyGRvkWRpJeBSc9/k= +mods.irisnet.org/modules/coinswap v0.0.0-20241217080151-0ad41be03ac6 h1:8QnufoVSKUdiLPqJwByZF6yz5zt9qyhSaT08No50pMA= +mods.irisnet.org/modules/coinswap v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:nv52g5ZDWv/C1ydtxLygP2wSYz6M4OuF6BygKy7RqGA= +mods.irisnet.org/modules/farm v0.0.0-20241217080151-0ad41be03ac6 h1:SA28lvYjEgOylkZJyuRVDIK4uGBHmtMGJvyAshUJJFk= +mods.irisnet.org/modules/farm v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:yYrnhmxDCnvI45u1cpeRZ2GPJUmRK+8KFXDtOJGpENE= +mods.irisnet.org/modules/htlc v0.0.0-20241217080151-0ad41be03ac6 h1:JPzUkLdXY/0YzlgQ4wsmiI35Karrssb77dopt67qvqU= +mods.irisnet.org/modules/htlc v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:2pWkSnxVKCzB3WH+q47rKffY4Plma+mRTGSWd4jfbp8= +mods.irisnet.org/modules/mt v0.0.0-20241217080151-0ad41be03ac6 h1:DyW+fBjjzJ4/h60sfvL0nkewudIZFRFPGvAZPj+8a+c= +mods.irisnet.org/modules/mt v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:Dw1zm350HiRuNjrnwZnV4XGB8PNf1SXmjGJA5Xslg0Q= +mods.irisnet.org/modules/nft v0.0.0-20241217080151-0ad41be03ac6 h1:RHgx9ggA5/lsNKXvQ7ezJpCfJBhKjlBBAfoaOTKNMnU= +mods.irisnet.org/modules/nft v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:VjySqJfECBW8cApFB8W66Yk6tMR2oJEc7FTDaHfeg8I= +mods.irisnet.org/modules/oracle v0.0.0-20241217080151-0ad41be03ac6 h1:1Xj4j7f639GMZ+MAbwNljQb0DZ5IdXDqQYNoDlppVXk= +mods.irisnet.org/modules/oracle v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:XAGzG55xpV01PwvryVPeaHtARZIqEUJcMv/vxaVcVC0= +mods.irisnet.org/modules/random v0.0.0-20241217080151-0ad41be03ac6 h1:ScX6qHG3V49eQHkeQmJ5awp7I8ixou+obxxWd4/wTcU= +mods.irisnet.org/modules/random v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:1ele5fpZ/rFMbwu1LTz2MwDg3sJDYcCtDW5SDfYRpTg= +mods.irisnet.org/modules/record v0.0.0-20241217080151-0ad41be03ac6 h1:PJu+56Be8F+mPj35jqeMvXl/bRZDtwrF9GL6j0w5ivQ= +mods.irisnet.org/modules/record v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:n8gRooDvJ5B44EJRZ+UlDz0GcXQeNwjH2tjpnVx7nd8= +mods.irisnet.org/modules/service v0.0.0-20241217080151-0ad41be03ac6 h1:U6IzrFgN8GXhdNHXxA5isDgQX7DeSfeVDqvLzs6cc4o= +mods.irisnet.org/modules/service v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:B1nKRNYn1VLqpvNbmbDSYagqL56sj0MIceXJi/DKg6s= +mods.irisnet.org/modules/token v0.0.0-20241217080151-0ad41be03ac6 h1:hlzR6ghnSujPC9VCwrpBVU6cBb+M9KyfbJz5SrnIef8= +mods.irisnet.org/modules/token v0.0.0-20241217080151-0ad41be03ac6/go.mod h1:fHJzeEBPhE9vaa4aye90+WFtHjZyGRvkWRpJeBSc9/k= mods.irisnet.org/simapp v0.0.0-20241125071105-d76ae25d05d2 h1:9AGZYpMjpk1gItviL31vsehmen119HtcuOKwv8WWpZo= mods.irisnet.org/simapp v0.0.0-20241125071105-d76ae25d05d2/go.mod h1:t7FSQJkJOgXq1/LdhpBeOu7TS8hLQkAMMx9fL5w53PY= nhooyr.io/websocket v1.8.6 h1:s+C3xAMLwGmlI31Nyn/eAehUlZPwfYZu2JXM621Q5/k=