diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2b39191017..33565ae832 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -137,7 +137,7 @@ jobs: mainnet-upgrade-v1-v3: runs-on: ubuntu-latest - timeout-minutes: 10 + timeout-minutes: 20 steps: - uses: actions/checkout@v3 - uses: technote-space/get-diff-action@v6.1.0 diff --git a/.gitignore b/.gitignore index e47e396595..bdbdc57200 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ contrib/scripts/cosmos-genesis-tinkerer contrib/scripts/tinkered_genesis.json contrib/scripts/preprocessing.json contrib/scripts/umeed-releases +# preprocessing can appear from the shell curdir that is cosmos-genesis-tinkerer is running +preprocessing.json # Dependency directories (remove the comment below to include it) # vendor/ diff --git a/CHANGELOG.md b/CHANGELOG.md index b7e77127a1..19c5c62dd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## [Unreleased] +### State Machine Breaking + +- [#1326](https://github.com/umee-network/umee/pull/1326) Setting protocol controlled min gas price. + ### API Breaking - [1029](https://github.com/umee-network/umee/pull/1029) Removed MsgSetCollateral(addr,denom,bool), and replaced with MsgAddCollateral(addr,coin) and MsgRemoveCollateral(addr,coin) diff --git a/ante/fee-notes.md b/ante/fee-notes.md new file mode 100644 index 0000000000..82379a7835 --- /dev/null +++ b/ante/fee-notes.md @@ -0,0 +1,56 @@ +# Notes about Gas prices and gas used + +NOTES: + +- the gas used depends on the current state of the chain +- the gas records below are based on the empty state +- user is charged the gas-limit, even if tx consumed less gas + +| operation | gas used | +| :--------------------------------------------- | -------: | +| x/bank send | 31'029 | +| x/group create | 68'908 | +| x/oracle MsgAggregateExchangeRateVote (3 curr) | 66'251 | +| x/oracle MsgAggregateExchangeRateVote (6 curr) | 69'726 | +| default gas limit | 200'000 | + +## Target price (in USD cent) for x/bank send + +| umee price (usd cent) | gas price in uumee | fee (usd cent) | +| --------------------: | -----------------: | -------------: | +| 2 | 0.2 | 0.0124 | +| 2 | 0.1 | 0.0062 | +| 2 | 0.02 | 0.00124 | +| 5 | 0.2 | 0.031 | +| 5 | 0.1 | 0.0155 | +| 5 | 0.02 | 0.0031 | + +## Target price (in USD cent) for validator oracle txs (with 6 currencies) per day + +There are roughly 10tx / minute and 14400 per day. +Validator has to do 2 tx (prevote and vote) every 5 blocks. +Validator will need to do `5760 = 2*14400/5` tx. +In table below we assume the same price scheme as above, but in the code most likely we will apply a fixed discount (eg 10x). + +The prices are indicative. For some transactions (especially oracle) fees can be disabled. +See fee.go file for details. + +| umee price (usd cent) | gas price in uumee | fee (usd cent) | +| --------------------: | -----------------: | -------------: | +| 2 | 0.2 | 161.28 | +| 2 | 0.1 | 80.64 | +| 2 | 0.02 | 16.128 | +| 5 | 0.2 | 403.2 | +| 5 | 0.1 | 201.6 | +| 5 | 0.02 | 40.32 | + +## Target price (in USD) for default gas limit + +| umee price (usd cent) | gas price in uumee | fee (usd cent) | +| --------------------: | -----------------: | -------------: | +| 2 | 0.2 | 0.08 | +| 2 | 0.1 | 0.04 | +| 2 | 0.02 | 0.008 | +| 5 | 0.2 | 0.2 | +| 5 | 0.1 | 0.1 | +| 5 | 0.02 | 0.02 | diff --git a/ante/fee.go b/ante/fee.go index 3505826ded..1ddba04b41 100644 --- a/ante/fee.go +++ b/ante/fee.go @@ -6,12 +6,13 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" + appparams "github.com/umee-network/umee/v3/app/params" leveragetypes "github.com/umee-network/umee/v3/x/leverage/types" oracletypes "github.com/umee-network/umee/v3/x/oracle/types" ) // MaxMsgGasUsage defines the maximum gas allowed for an oracle transaction. -const MaxMsgGasUsage = uint64(100000) +const MaxMsgGasUsage = uint64(100_000) // FeeAndPriority ensures tx has enough fee coins to pay for the gas at the CheckTx time // to early remove transactions from the mempool without enough attached fee. @@ -24,37 +25,55 @@ func FeeAndPriority(ctx sdk.Context, tx sdk.Tx) (sdk.Coins, int64, error) { return nil, 0, sdkerrors.ErrTxDecode.Wrap("Tx must be a FeeTx") } - feeCoins := feeTx.GetFee() - gas := feeTx.GetGas() + providedFees := feeTx.GetFee() + gasLimit := feeTx.GetGas() msgs := feeTx.GetMsgs() isOracleOrGravity := IsOracleOrGravityTx(msgs) - chargeFees := !isOracleOrGravity || gas > uint64(len(msgs))*MaxMsgGasUsage - - if ctx.IsCheckTx() && chargeFees { - minGasPrices := ctx.MinGasPrices() - if !minGasPrices.IsZero() { - requiredFees := make(sdk.Coins, len(minGasPrices)) - - // Determine the required fees by multiplying each required minimum gas - // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). - glDec := sdk.NewDec(int64(gas)) - for i, gp := range minGasPrices { - fee := gp.Amount.Mul(glDec) - requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) - } + priority := getTxPriority(isOracleOrGravity, msgs) + chargeFees := !isOracleOrGravity || gasLimit > uint64(len(msgs))*MaxMsgGasUsage + // we also don't charge transaction fees for the first block, for the genesis transactions. + if !chargeFees || ctx.BlockHeight() == 0 { + return sdk.Coins{}, priority, nil + } - if !feeCoins.IsAnyGTE(requiredFees) { - return nil, 0, sdkerrors.ErrInsufficientFee.Wrapf( - "insufficient fees; got: %s required: %s", feeCoins, requiredFees) - } + var err error + if ctx.IsCheckTx() { + err = checkFees(ctx.MinGasPrices(), providedFees, gasLimit) + } else { + err = checkFees(nil, providedFees, gasLimit) + } + if err != nil { + err = sdkerrors.Wrap(err, msgs[0].String()) + } + return providedFees, priority, err +} + +func checkFees(minGasPrices sdk.DecCoins, fees sdk.Coins, gasLimit uint64) error { + if minGasPrices != nil { + // check minGasPrices set by validator + if err := AssertMinProtocolGasPrice(minGasPrices); err != nil { + return err } + } else { + // in deliverTx = use protocol min gas price + minGasPrices = sdk.DecCoins{appparams.MinMinGasPrice} } - priority := getTxPriority(isOracleOrGravity, msgs) - if !chargeFees { - return sdk.Coins{}, priority, nil + requiredFees := make(sdk.Coins, len(minGasPrices)) + + // Determine the required fees by multiplying each required minimum gas + // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). + glDec := sdk.NewDec(int64(gasLimit)) + for i, gp := range minGasPrices { + fee := gp.Amount.Mul(glDec) + requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) } - return feeCoins, priority, nil + + if !fees.IsAnyGTE(requiredFees) { + return sdkerrors.ErrInsufficientFee.Wrapf( + "insufficient fees; got: %s required: %s", fees, requiredFees) + } + return nil } // IsOracleOrGravityTx checks if all messages are oracle messages @@ -68,9 +87,8 @@ func IsOracleOrGravityTx(msgs []sdk.Msg) bool { *oracletypes.MsgAggregateExchangeRateVote: continue - // TODO: remove messages which should not be "free": + // TODO: revisit free gravity msg set case *gbtypes.MsgValsetConfirm, - *gbtypes.MsgRequestBatch, *gbtypes.MsgConfirmBatch, *gbtypes.MsgERC20DeployedClaim, *gbtypes.MsgConfirmLogicCall, @@ -90,6 +108,21 @@ func IsOracleOrGravityTx(msgs []sdk.Msg) bool { return true } +// AssertMinProtocolGasPrice returns an error if the provided gasPrices are lower then +// the required by protocol. +func AssertMinProtocolGasPrice(gasPrices sdk.DecCoins) error { + for _, c := range gasPrices { + if c.Denom == appparams.MinMinGasPrice.Denom { + if c.Amount.LT(appparams.MinMinGasPrice.Amount) { + break // go to error below + } + return nil + } + } + return sdkerrors.ErrInsufficientFee.Wrapf( + "gas price too small; got: %v required min: %v", gasPrices, appparams.MinMinGasPrice) +} + // getTxPriority returns naive tx priority based on the lowest fee amount (regardless of the // denom) and oracle tx check. // Dirty optimization: since we already check if msgs are oracle or gravity messages, then we diff --git a/ante/fee_test.go b/ante/fee_test.go index 4323a23b7b..3a8d6230fa 100644 --- a/ante/fee_test.go +++ b/ante/fee_test.go @@ -5,8 +5,11 @@ import ( "github.com/cosmos/cosmos-sdk/testutil/testdata" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + signing "github.com/cosmos/cosmos-sdk/x/auth/signing" "github.com/umee-network/umee/v3/ante" + appparams "github.com/umee-network/umee/v3/app/params" + "github.com/umee-network/umee/v3/util/coin" oracletypes "github.com/umee-network/umee/v3/x/oracle/types" ) @@ -18,32 +21,73 @@ func (suite *IntegrationTestSuite) TestFeeAndPriority() { msgs := testdata.NewTestMsg(addr1) require.NoError(suite.txBuilder.SetMsgs(msgs)) - fee := sdk.NewCoins(sdk.NewInt64Coin("atom", 150)) - gasLimit := 200000 - suite.txBuilder.SetFeeAmount(fee) - suite.txBuilder.SetGasLimit(uint64(gasLimit)) - - // Test1: validator min gas price check - // Ante should fail when validator min gas price is above the transaction gas limit - minGasPrice := sdk.NewDecCoinFromDec("atom", sdk.NewDecFromInt(fee[0].Amount).QuoInt64(int64(gasLimit/2))) + minGas := appparams.MinMinGasPrice + mkFee := func(factor string) sdk.Coins { + return coin.NewDecBld(minGas).Scale(int64(appparams.DefaultGasLimit)).ScaleStr(factor).ToCoins() + } + mkGas := func(denom, factor string) sdk.DecCoins { + if denom == "" { + denom = minGas.Denom + } + f := sdk.MustNewDecFromStr(factor) + return sdk.DecCoins{sdk.NewDecCoinFromDec(denom, minGas.Amount.Mul(f))} + } + mkTx := func(fee sdk.Coins) signing.Tx { + suite.txBuilder.SetFeeAmount(fee) + tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID()) + require.NoError(err) + return tx + } + + suite.txBuilder.SetGasLimit(appparams.DefaultGasLimit) + // we set fee to 2*gasLimit*minGasPrice + fee := mkFee("2") + tx := mkTx(fee) + + // + // Test CheckTX + // ctx := suite.ctx. - WithMinGasPrices([]sdk.DecCoin{minGasPrice}). + WithMinGasPrices(sdk.DecCoins{minGas}). WithIsCheckTx(true) - tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID()) - require.NoError(err) - _, _, err = ante.FeeAndPriority(ctx, tx) - require.ErrorIs(sdkerrors.ErrInsufficientFee, err) - // Test2: min gas price not checked in DeliverTx - ctx = suite.ctx.WithIsCheckTx(false) + // min-gas-settings should work suite.checkFeeAnte(tx, fee, ctx) - // Test3: should not error when min gas price is same or lower than the fee - ctx = ctx.WithMinGasPrices(sdk.NewDecCoinsFromCoins(fee...)) - suite.checkFeeAnte(tx, fee, ctx) + // should work when exact fee is provided + suite.checkFeeAnte(tx, fee, ctx.WithMinGasPrices(mkGas("", "2"))) + + // should fail when not enough fee is provided + suite.checkFeeFailed(tx, ctx.WithMinGasPrices(mkGas("", "3"))) - ctx = ctx.WithMinGasPrices([]sdk.DecCoin{sdk.NewDecCoin(fee[0].Denom, fee[0].Amount.QuoRaw(2))}) + // should fail when other denom is required + suite.checkFeeFailed(tx, ctx.WithMinGasPrices(mkGas("other", "1"))) + + // should fail when some fee doesn't include all gas denoms + ctx = ctx.WithMinGasPrices(sdk.DecCoins{minGas, + sdk.NewDecCoinFromDec("other", sdk.NewDec(10))}) + suite.checkFeeFailed(tx, ctx) + + // + // Test DeliverTx + // + ctx = suite.ctx. + WithMinGasPrices(sdk.DecCoins{minGas}). + WithIsCheckTx(false) + + // ctx.MinGasPrice shouldn't matter suite.checkFeeAnte(tx, fee, ctx) + suite.checkFeeAnte(tx, fee, ctx.WithMinGasPrices(mkGas("", "3"))) + suite.checkFeeAnte(tx, fee, ctx.WithMinGasPrices(mkGas("other", "1"))) + suite.checkFeeAnte(tx, fee, ctx.WithMinGasPrices(sdk.DecCoins{})) + + // should fail when not enough fee is provided + suite.checkFeeFailed(mkTx(mkFee("0.5")), ctx) + suite.checkFeeFailed(mkTx(sdk.Coins{}), ctx) + + // should work when more fees are applied + fee = append(fee, sdk.NewInt64Coin("other", 10)) + suite.checkFeeAnte(mkTx(fee), fee, ctx) // Test4: ensure no fees for oracle msgs require.NoError(suite.txBuilder.SetMsgs( @@ -62,6 +106,11 @@ func (suite *IntegrationTestSuite) TestFeeAndPriority() { suite.checkFeeAnte(oracleTx, sdk.Coins{}, suite.ctx.WithIsCheckTx(false)) } +func (suite *IntegrationTestSuite) checkFeeFailed(tx sdk.Tx, ctx sdk.Context) { + _, _, err := ante.FeeAndPriority(ctx, tx) + suite.Require().ErrorIs(sdkerrors.ErrInsufficientFee, err) +} + func (suite *IntegrationTestSuite) checkFeeAnte(tx sdk.Tx, feeExpected sdk.Coins, ctx sdk.Context) { require := suite.Require() fee, _, err := ante.FeeAndPriority(ctx, tx) diff --git a/ante/spam_prevention.go b/ante/spam_prevention.go index d3d3070650..794cb855ea 100644 --- a/ante/spam_prevention.go +++ b/ante/spam_prevention.go @@ -64,6 +64,7 @@ func (spd *SpamPreventionDecorator) CheckOracleSpam(ctx sdk.Context, msgs []sdk. err = spd.validate(ctx, msg.Feeder, msg.Validator, spd.oracleVoteMap, curHeight, "vote") default: // non oracle msg: stop validation! + // NOTE: only tx which contains only oracle Msgs are considered oracle-prioritized return nil } if err != nil { diff --git a/app/app.go b/app/app.go index a858a62182..babe3a8576 100644 --- a/app/app.go +++ b/app/app.go @@ -110,6 +110,7 @@ import ( customante "github.com/umee-network/umee/v3/ante" appparams "github.com/umee-network/umee/v3/app/params" "github.com/umee-network/umee/v3/swagger" + "github.com/umee-network/umee/v3/util/genmap" uibctransfer "github.com/umee-network/umee/v3/x/ibctransfer" uibctransferkeeper "github.com/umee-network/umee/v3/x/ibctransfer/keeper" "github.com/umee-network/umee/v3/x/leverage" @@ -121,22 +122,6 @@ import ( oracletypes "github.com/umee-network/umee/v3/x/oracle/types" ) -const ( - // Name defines the application name of the Umee network. - Name = "umee" - - // BondDenom defines the native staking token denomination. - BondDenom = "uumee" - - // DisplayDenom defines the name, symbol, and display value of the umee token. - DisplayDenom = "UMEE" - - // MaxAddrLen is the maximum allowed length (in bytes) for an address. - // - // NOTE: In the SDK, the default value is 255. - MaxAddrLen = 20 -) - var ( _ CosmosApp = (*UmeeApp)(nil) _ servertypes.Application = (*UmeeApp)(nil) @@ -244,6 +229,8 @@ type UmeeApp struct { // simulation manager sm *module.SimulationManager + // simulation manager to create state + StateSimulationManager *module.SimulationManager // module configurator configurator module.Configurator @@ -255,13 +242,7 @@ func init() { panic(fmt.Sprintf("failed to get user home directory: %s", err)) } - DefaultNodeHome = filepath.Join(userHomeDir, fmt.Sprintf(".%s", Name)) - - // XXX: If other upstream or external application's depend on any of Umee's - // CLI or command functionality, then this would require us to move the - // SetAddressConfig call to somewhere external such as the root command - // constructor and anywhere else we contract the app. - SetAddressConfig() + DefaultNodeHome = filepath.Join(userHomeDir, fmt.Sprintf(".%s", appparams.Name)) } func New( @@ -280,7 +261,7 @@ func New( legacyAmino := encodingConfig.Amino interfaceRegistry := encodingConfig.InterfaceRegistry - bApp := baseapp.NewBaseApp(Name, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) + bApp := baseapp.NewBaseApp(appparams.Name, logger, db, encodingConfig.TxConfig.TxDecoder(), baseAppOptions...) bApp.SetCommitMultiStoreTracer(traceStore) // TODO // bApp.SetVersion(version.Version) @@ -347,7 +328,7 @@ func New( app.GetSubspace(authtypes.ModuleName), authtypes.ProtoBaseAccount, maccPerms, - AccountAddressPrefix, + appparams.AccountAddressPrefix, ) app.BankKeeper = bankkeeper.NewBaseKeeper( appCodec, @@ -648,14 +629,14 @@ func New( overrideModules := map[string]module.AppModuleSimulation{ authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts), } - // TODO: Ensure x/leverage implements simulator and then use app.mm.Modules directly. - simModules := map[string]module.AppModule{} - for name, m := range app.mm.Modules { - if name != leveragetypes.ModuleName { - simModules[name] = m - } - } - app.sm = module.NewSimulationManagerFromAppModules(simModules, overrideModules) + + simStateModules := genmap.Pick(app.mm.Modules, + []string{stakingtypes.ModuleName, authtypes.ModuleName, oracletypes.ModuleName}) + // TODO: Ensure x/leverage implements simulator and add it here: + simTestModules := genmap.Pick(simStateModules, []string{oracletypes.ModuleName}) + + app.StateSimulationManager = module.NewSimulationManagerFromAppModules(simStateModules, overrideModules) + app.sm = module.NewSimulationManagerFromAppModules(simTestModules, nil) app.sm.RegisterStoreDecoders() diff --git a/app/modules.go b/app/modules.go index c1cc68a792..08e552d5e8 100644 --- a/app/modules.go +++ b/app/modules.go @@ -20,6 +20,8 @@ import ( slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" "github.com/cosmos/cosmos-sdk/x/staking" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + appparams "github.com/umee-network/umee/v3/app/params" ) // BankModule defines a custom wrapper around the x/bank module's AppModuleBasic @@ -32,20 +34,20 @@ type BankModule struct { func (BankModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { umeeMetadata := banktypes.Metadata{ Description: "The native staking token of the Umee network.", - Base: BondDenom, - Name: DisplayDenom, - Display: DisplayDenom, - Symbol: DisplayDenom, + Base: appparams.BondDenom, + Name: appparams.DisplayDenom, + Display: appparams.DisplayDenom, + Symbol: appparams.DisplayDenom, DenomUnits: []*banktypes.DenomUnit{ { - Denom: BondDenom, + Denom: appparams.BondDenom, Exponent: 0, Aliases: []string{ "microumee", }, }, { - Denom: DisplayDenom, + Denom: appparams.DisplayDenom, Exponent: 6, Aliases: []string{}, }, @@ -66,11 +68,10 @@ type StakingModule struct { // DefaultGenesis returns custom Umee x/staking module genesis state. func (StakingModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - params := stakingtypes.DefaultParams() - params.BondDenom = BondDenom - + p := stakingtypes.DefaultParams() + p.BondDenom = appparams.BondDenom return cdc.MustMarshalJSON(&stakingtypes.GenesisState{ - Params: params, + Params: p, }) } @@ -83,7 +84,7 @@ type CrisisModule struct { // DefaultGenesis returns custom Umee x/crisis module genesis state. func (CrisisModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { return cdc.MustMarshalJSON(&crisistypes.GenesisState{ - ConstantFee: sdk.NewCoin(BondDenom, sdk.NewInt(1000)), + ConstantFee: sdk.NewCoin(appparams.BondDenom, sdk.NewInt(1000)), }) } @@ -96,7 +97,7 @@ type MintModule struct { // DefaultGenesis returns custom Umee x/mint module genesis state. func (MintModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { genState := minttypes.DefaultGenesisState() - genState.Params.MintDenom = BondDenom + genState.Params.MintDenom = appparams.BondDenom return cdc.MustMarshalJSON(genState) } @@ -109,7 +110,7 @@ type GovModule struct { // DefaultGenesis returns custom Umee x/gov module genesis state. func (GovModule) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage { - minDeposit := sdk.NewCoins(sdk.NewCoin(BondDenom, govv1.DefaultMinDepositTokens)) + minDeposit := sdk.NewCoins(sdk.NewCoin(appparams.BondDenom, govv1.DefaultMinDepositTokens)) genState := govv1.DefaultGenesisState() genState.DepositParams.MinDeposit = minDeposit diff --git a/app/params/app_settings.go b/app/params/app_settings.go new file mode 100644 index 0000000000..5283de0bdd --- /dev/null +++ b/app/params/app_settings.go @@ -0,0 +1,39 @@ +package params + +import ( + "log" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +const ( + // Name defines the application name of the Umee network. + Name = "umee" + + // BondDenom defines the native staking token denomination. + BondDenom = "uumee" + + // DisplayDenom defines the name, symbol, and display value of the umee token. + DisplayDenom = "UMEE" + + // DefaultGasLimit - set to the same value as cosmos-sdk flags.DefaultGasLimit + // this value is currently only used in tests. + DefaultGasLimit = 200000 +) + +var ( + // MinMinGasPrice is the minimum value a validator can set for `minimum-gas-prices` his app.toml config + MinMinGasPrice = sdk.NewDecCoinFromDec(BondDenom, sdk.MustNewDecFromStr("0.05")) +) + +func init() { + // XXX: If other upstream or external application's depend on any of Umee's + // CLI or command functionality, then this would require us to move the + // SetAddressConfig call to somewhere external such as the root command + // constructor and anywhere else we contract the app. + SetAddressConfig() + + if AccountAddressPrefix != Name { + log.Fatal("AccountAddresPrefix must equal Name") + } +} diff --git a/app/prefix.go b/app/params/prefix.go similarity index 98% rename from app/prefix.go rename to app/params/prefix.go index 6015ea9705..db75fd93e6 100644 --- a/app/prefix.go +++ b/app/params/prefix.go @@ -1,4 +1,4 @@ -package app +package params import ( sdk "github.com/cosmos/cosmos-sdk/types" diff --git a/app/test_helpers.go b/app/test_helpers.go index 1e076b6784..770549fcb9 100644 --- a/app/test_helpers.go +++ b/app/test_helpers.go @@ -28,6 +28,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" dbm "github.com/tendermint/tm-db" + "github.com/umee-network/umee/v3/app/params" leveragetypes "github.com/umee-network/umee/v3/x/leverage/types" oracletypes "github.com/umee-network/umee/v3/x/oracle/types" ) @@ -71,7 +72,7 @@ func Setup(t *testing.T, isCheckTx bool, invCheckPeriod uint) *UmeeApp { acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) balance := banktypes.Balance{ Address: acc.GetAddress().String(), - Coins: sdk.NewCoins(sdk.NewCoin(BondDenom, sdk.NewInt(10000000000000000))), + Coins: sdk.NewCoins(sdk.NewCoin(params.BondDenom, sdk.NewInt(10000000000000000))), } app := SetupWithGenesisValSet(t, valSet, []authtypes.GenesisAccount{acc}, balance) @@ -168,7 +169,7 @@ func GenesisStateWithValSet(codec codec.Codec, genesisState map[string]json.RawM defaultStParams.MaxValidators, defaultStParams.MaxEntries, defaultStParams.HistoricalEntries, - BondDenom, + params.BondDenom, defaultStParams.MinCommissionRate, ) // set validators and delegations @@ -183,13 +184,13 @@ func GenesisStateWithValSet(codec codec.Codec, genesisState map[string]json.RawM for range delegations { // add delegated tokens to total supply - totalSupply = totalSupply.Add(sdk.NewCoin(BondDenom, bondAmt)) + totalSupply = totalSupply.Add(sdk.NewCoin(params.BondDenom, bondAmt)) } // add bonded amount to bonded pool module account balances = append(balances, banktypes.Balance{ Address: authtypes.NewModuleAddress(stakingtypes.BondedPoolName).String(), - Coins: sdk.Coins{sdk.NewCoin(BondDenom, bondAmt)}, + Coins: sdk.Coins{sdk.NewCoin(params.BondDenom, bondAmt)}, }) // update total supply @@ -241,8 +242,8 @@ func IntegrationTestNetworkConfig() network.Config { panic(err) } leverageGenState.Registry = append(leverageGenState.Registry, leveragetypes.Token{ - BaseDenom: BondDenom, - SymbolDenom: DisplayDenom, + BaseDenom: params.BondDenom, + SymbolDenom: params.DisplayDenom, Exponent: 6, ReserveFactor: sdk.MustNewDecFromStr("0.1"), CollateralWeight: sdk.MustNewDecFromStr("0.05"), @@ -276,7 +277,7 @@ func IntegrationTestNetworkConfig() network.Config { // are not running a price-feeder. oracleGenState.Params.VotePeriod = 1000 oracleGenState.ExchangeRates = append(oracleGenState.ExchangeRates, oracletypes.NewExchangeRateTuple( - DisplayDenom, sdk.MustNewDecFromStr("34.21"), + params.DisplayDenom, sdk.MustNewDecFromStr("34.21"), )) bz, err = cdc.MarshalJSON(&oracleGenState) @@ -304,8 +305,8 @@ func IntegrationTestNetworkConfig() network.Config { cfg.LegacyAmino = encCfg.Amino cfg.InterfaceRegistry = encCfg.InterfaceRegistry cfg.GenesisState = appGenState - cfg.BondDenom = BondDenom - cfg.MinGasPrices = fmt.Sprintf("0.000006%s", BondDenom) + cfg.BondDenom = params.BondDenom + cfg.MinGasPrices = params.MinMinGasPrice.String() cfg.AppConstructor = func(val network.Validator) servertypes.Application { return New( val.Ctx.Logger, diff --git a/cmd/umeed/cmd/app_creator.go b/cmd/umeed/cmd/app_creator.go index ec34236218..bb45b595c0 100644 --- a/cmd/umeed/cmd/app_creator.go +++ b/cmd/umeed/cmd/app_creator.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + stdlog "log" "path/filepath" "github.com/cosmos/cosmos-sdk/baseapp" @@ -19,12 +20,13 @@ import ( "github.com/tendermint/tendermint/libs/log" dbm "github.com/tendermint/tm-db" + "github.com/umee-network/umee/v3/ante" umeeapp "github.com/umee-network/umee/v3/app" - "github.com/umee-network/umee/v3/app/params" + appparams "github.com/umee-network/umee/v3/app/params" ) type appCreator struct { - encCfg params.EncodingConfig + encCfg appparams.EncodingConfig moduleManager module.BasicManager } @@ -65,6 +67,9 @@ func (a appCreator) newApp( cast.ToUint32(appOpts.Get(server.FlagStateSyncSnapshotKeepRecent)), ) + minGasPrices := cast.ToString(appOpts.Get(server.FlagMinGasPrices)) + mustMinUmeeGasPrice(minGasPrices) + return umeeapp.New( logger, db, traceStore, true, skipUpgradeHeights, cast.ToString(appOpts.Get(flags.FlagHome)), @@ -72,7 +77,7 @@ func (a appCreator) newApp( a.encCfg, appOpts, baseapp.SetPruning(pruningOpts), - baseapp.SetMinGasPrices(cast.ToString(appOpts.Get(server.FlagMinGasPrices))), + baseapp.SetMinGasPrices(minGasPrices), baseapp.SetMinRetainBlocks(cast.ToUint64(appOpts.Get(server.FlagMinRetainBlocks))), baseapp.SetHaltHeight(cast.ToUint64(appOpts.Get(server.FlagHaltHeight))), baseapp.SetHaltTime(cast.ToUint64(appOpts.Get(server.FlagHaltTime))), @@ -83,6 +88,17 @@ func (a appCreator) newApp( ) } +func mustMinUmeeGasPrice(minGasPrices string) { + gasPrices, err := sdk.ParseDecCoins(minGasPrices) + if err != nil { + stdlog.Fatalf("invalid minimum gas prices: %v", err) + } + if err := ante.AssertMinProtocolGasPrice(gasPrices); err != nil { + stdlog.Fatal("minimum-gas-price config in app.toml must be at least ", + appparams.MinMinGasPrice, " [", err, "]") + } +} + // appExport creates a new simapp, optionally at a given height. func (a appCreator) appExport( logger log.Logger, diff --git a/cmd/umeed/cmd/debug.go b/cmd/umeed/cmd/debug.go index 14201983df..8b5af3a45c 100644 --- a/cmd/umeed/cmd/debug.go +++ b/cmd/umeed/cmd/debug.go @@ -11,7 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/spf13/cobra" - umeeapp "github.com/umee-network/umee/v3/app" + appparams "github.com/umee-network/umee/v3/app/params" ) const ( @@ -80,7 +80,7 @@ $ %s debug addr cosmos1e0jnq2sun3dzjh8p2xq95kk0expwmd7shwjpfg }, } - cmd.Flags().String(flagBech32HRP, umeeapp.AccountAddressPrefix, + cmd.Flags().String(flagBech32HRP, appparams.AccountAddressPrefix, "Input Bech32 HRP (use only when address input is a Bech32 address") return cmd } diff --git a/cmd/umeed/cmd/root.go b/cmd/umeed/cmd/root.go index c94ba1c47c..dbae6ab85b 100644 --- a/cmd/umeed/cmd/root.go +++ b/cmd/umeed/cmd/root.go @@ -11,6 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" + serverconfig "github.com/cosmos/cosmos-sdk/server/config" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" @@ -23,11 +24,11 @@ import ( tmcli "github.com/tendermint/tendermint/libs/cli" umeeapp "github.com/umee-network/umee/v3/app" - "github.com/umee-network/umee/v3/app/params" + appparams "github.com/umee-network/umee/v3/app/params" ) // NewRootCmd returns the root command handler for the Umee daemon. -func NewRootCmd() (*cobra.Command, params.EncodingConfig) { +func NewRootCmd() (*cobra.Command, appparams.EncodingConfig) { encodingConfig := umeeapp.MakeEncodingConfig() moduleManager := umeeapp.ModuleBasics @@ -40,10 +41,10 @@ func NewRootCmd() (*cobra.Command, params.EncodingConfig) { WithAccountRetriever(types.AccountRetriever{}). WithBroadcastMode(flags.BroadcastBlock). WithHomeDir(umeeapp.DefaultNodeHome). - WithViper(umeeapp.Name) + WithViper(appparams.Name) rootCmd := &cobra.Command{ - Use: umeeapp.Name + "d", + Use: appparams.Name + "d", Short: "Umee application network daemon and client", Long: `A daemon and client for interacting with the Umee network. Umee is a Universal Capital Facility that can collateralize assets on one blockchain @@ -66,8 +67,9 @@ towards borrowing assets on another blockchain.`, return err } - tmConfig := initTendermintConfig() - return server.InterceptConfigsPreRunHandler(cmd, "", nil, tmConfig) + appTmpl, appCfg := initAppConfig() + tmCfg := initTendermintConfig() + return server.InterceptConfigsPreRunHandler(cmd, appTmpl, appCfg, tmCfg) }, } @@ -93,6 +95,45 @@ func initTendermintConfig() *tmcfg.Config { return cfg } +// initAppConfig helps to override default appConfig template and configs. +// return "", nil if no custom configuration is required for the application. +func initAppConfig() (string, interface{}) { + // WASMConfig defines configuration for the wasm module. + type WASMConfig struct { + // This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries + QueryGasLimit uint64 `mapstructure:"query_gas_limit"` + + LruSize uint64 `mapstructure:"lru_size"` + } + + type CustomAppConfig struct { + serverconfig.Config + WASM WASMConfig `mapstructure:"wasm"` + } + + // here we set a default initial app.toml values for validators. + srvCfg := serverconfig.DefaultConfig() + srvCfg.MinGasPrices = "" // validators MUST set mininum-gas-prices in their app.toml, otherwise the app will halt. + + customAppConfig := CustomAppConfig{ + Config: *srvCfg, + WASM: WASMConfig{ + LruSize: 1, + QueryGasLimit: 300000, + }, + } + + customAppTemplate := serverconfig.DefaultConfigTemplate + ` +[wasm] +# This is the maximum sdk gas (wasm and storage) that we allow for any x/wasm "smart" queries +query_gas_limit = 300000 +# This is the number of wasm vm instances we keep cached in memory for speed-up +# Warning: this is currently unstable and may lead to crashes, best to keep for 0 unless testing locally +lru_size = 0` + + return customAppTemplate, customAppConfig +} + func initRootCmd(rootCmd *cobra.Command, a appCreator) { // We allow two variants of the gentx command: // diff --git a/cmd/umeed/main.go b/cmd/umeed/main.go index 8483e7d4a0..dea9658196 100644 --- a/cmd/umeed/main.go +++ b/cmd/umeed/main.go @@ -7,12 +7,13 @@ import ( svrcmd "github.com/cosmos/cosmos-sdk/server/cmd" umeeapp "github.com/umee-network/umee/v3/app" + appparams "github.com/umee-network/umee/v3/app/params" "github.com/umee-network/umee/v3/cmd/umeed/cmd" ) func main() { rootCmd, _ := cmd.NewRootCmd() - if err := svrcmd.Execute(rootCmd, strings.ToUpper(umeeapp.Name), umeeapp.DefaultNodeHome); err != nil { + if err := svrcmd.Execute(rootCmd, strings.ToUpper(appparams.Name), umeeapp.DefaultNodeHome); err != nil { os.Exit(1) } } diff --git a/contrib/scripts/blocks.sh b/contrib/scripts/blocks.sh index 52207d1a9b..bb42b592e2 100755 --- a/contrib/scripts/blocks.sh +++ b/contrib/scripts/blocks.sh @@ -1,4 +1,4 @@ -#!/bin/bash -eux +#!/bin/bash -eu # File with commonly used functions for other scripts diff --git a/contrib/scripts/process_genesis.sh b/contrib/scripts/process_genesis.sh index 44acf6980b..d52df03584 100755 --- a/contrib/scripts/process_genesis.sh +++ b/contrib/scripts/process_genesis.sh @@ -1,4 +1,4 @@ -#!/bin/bash -eux +#!/bin/bash -eu CWD="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" diff --git a/contrib/scripts/single-node.sh b/contrib/scripts/single-node.sh index a57f393879..771303287b 100755 --- a/contrib/scripts/single-node.sh +++ b/contrib/scripts/single-node.sh @@ -1,4 +1,4 @@ -#!/bin/bash -eux +#!/bin/bash -eu # USAGE: # ./single-gen.sh