diff --git a/.gitignore b/.gitignore index 53e3e375a..3d14697c5 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,8 @@ secret.yml cosmoshub3.json exchanges.json juno_out.json -bin \ No newline at end of file +bin + +# emacs editor config +\#*\# +.\#* diff --git a/app/ante.go b/app/ante.go new file mode 100644 index 000000000..eca8d31c0 --- /dev/null +++ b/app/ante.go @@ -0,0 +1,97 @@ +package app + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/x/auth/ante" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + channelkeeper "github.com/cosmos/ibc-go/modules/core/04-channel/keeper" + ibcante "github.com/cosmos/ibc-go/modules/core/ante" +) + +// HandlerOptions extends the SDK's AnteHandler options by requiring the IBC +// channel keeper. +type HandlerOptions struct { + ante.HandlerOptions + + IBCChannelkeeper channelkeeper.Keeper +} + +type MinCommissionDecorator struct{} + +func NewMinCommissionDecorator() MinCommissionDecorator { + return MinCommissionDecorator{} +} + +func (MinCommissionDecorator) AnteHandle( + ctx sdk.Context, tx sdk.Tx, + simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { + msgs := tx.GetMsgs() + minCommissionRate := sdk.NewDecWithPrec(5, 2) + for _, m := range msgs { + switch msg := m.(type) { + case *stakingtypes.MsgCreateValidator: + // prevent new validators joining the set with + // commission set below 5% + c := msg.Commission + if c.Rate.LT(minCommissionRate) { + return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "commission can't be lower than 5%") + } + case *stakingtypes.MsgEditValidator: + // if commission rate is nil, it means only + // other fields are affected - skip + if msg.CommissionRate == nil { + continue + } + if msg.CommissionRate.LT(minCommissionRate) { + return ctx, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "commission can't be lower than 5%") + } + default: + continue + } + } + return next(ctx, tx, simulate) +} + +// NewAnteHandler returns an AnteHandler that checks and increments sequence +// numbers, checks signatures & account numbers, and deducts fees from the first +// signer. +func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { + if options.AccountKeeper == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for ante builder") + } + + if options.BankKeeper == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for ante builder") + } + + if options.SignModeHandler == nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") + } + + var sigGasConsumer = options.SigGasConsumer + if sigGasConsumer == nil { + sigGasConsumer = ante.DefaultSigVerificationGasConsumer + } + + anteDecorators := []sdk.AnteDecorator{ + ante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first + NewMinCommissionDecorator(), + ante.NewRejectExtensionOptionsDecorator(), + ante.NewMempoolFeeDecorator(), + ante.NewValidateBasicDecorator(), + ante.NewTxTimeoutHeightDecorator(), + ante.NewValidateMemoDecorator(options.AccountKeeper), + ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), + ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), + // SetPubKeyDecorator must be called before all signature verification decorators + ante.NewSetPubKeyDecorator(options.AccountKeeper), + ante.NewValidateSigCountDecorator(options.AccountKeeper), + ante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer), + ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), + ante.NewIncrementSequenceDecorator(options.AccountKeeper), + ibcante.NewAnteDecorator(options.IBCChannelkeeper), + } + + return sdk.ChainAnteDecorators(anteDecorators...), nil +} diff --git a/app/app.go b/app/app.go index f09f828c7..521c31160 100644 --- a/app/app.go +++ b/app/app.go @@ -105,7 +105,6 @@ import ( const ( AccountAddressPrefix = "juno" Name = "juno" - upgradeName = "moneta-alpha" ) // this line is used by starport scaffolding # stargate/wasm/app/enabledProposals @@ -524,13 +523,16 @@ func New( app.MountTransientStores(tkeys) app.MountMemoryStores(memKeys) - anteHandler, err := ante.NewAnteHandler( - ante.HandlerOptions{ - AccountKeeper: app.AccountKeeper, - BankKeeper: app.BankKeeper, - FeegrantKeeper: app.FeeGrantKeeper, - SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), - SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + anteHandler, err := NewAnteHandler( + HandlerOptions{ + HandlerOptions: ante.HandlerOptions{ + AccountKeeper: app.AccountKeeper, + BankKeeper: app.BankKeeper, + FeegrantKeeper: app.FeeGrantKeeper, + SignModeHandler: encodingConfig.TxConfig.SignModeHandler(), + SigGasConsumer: ante.DefaultSigVerificationGasConsumer, + }, + IBCChannelkeeper: app.IBCKeeper.ChannelKeeper, }, ) if err != nil { @@ -548,7 +550,7 @@ func New( panic(err) } - if upgradeInfo.Name == upgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { + if upgradeInfo.Name == "moneta-alpha" && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) { storeUpgrades := store.StoreUpgrades{ Added: []string{authz.ModuleName, feegrant.ModuleName, wasm.ModuleName}, } @@ -702,7 +704,32 @@ func (app *App) RegisterTendermintService(clientCtx client.Context) { // RegisterUpgradeHandlers returns upgrade handlers func (app *App) RegisterUpgradeHandlers(cfg module.Configurator) { - app.UpgradeKeeper.SetUpgradeHandler(upgradeName, func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + app.UpgradeKeeper.SetUpgradeHandler("moneta-alpha", func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + return app.mm.RunMigrations(ctx, cfg, vm) + }) + + app.UpgradeKeeper.SetUpgradeHandler("moneta-beta", func(ctx sdk.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + // force an update of validator min commission + validators := app.StakingKeeper.GetAllValidators(ctx) + // hard code this because we don't want + // a) a fork or + // b) immediate reaction with additional gov props + minCommissionRate := sdk.NewDecWithPrec(5, 2) + for _, v := range validators { + if v.Commission.Rate.LT(minCommissionRate) { + comm, err := app.StakingKeeper.UpdateValidatorCommission( + ctx, v, minCommissionRate) + if err != nil { + panic(err) + } + v.Commission = comm + + // call the before-modification hook since we're about to update the commission + app.StakingKeeper.BeforeValidatorModified(ctx, v.GetOperator()) + + app.StakingKeeper.SetValidator(ctx, v) + } + } return app.mm.RunMigrations(ctx, cfg, vm) }) }