diff --git a/app/app.go b/app/app.go index 31f266a860..f9b3f70184 100644 --- a/app/app.go +++ b/app/app.go @@ -168,6 +168,7 @@ var ( wasmclient.UnpinCodesProposalHandler, wasmclient.UpdateDeploymentWhitelistProposalHandler, wasmclient.UpdateWASMContractMethodBlockedListProposalHandler, + wasmclient.GetCmdExtraProposal, ), params.AppModuleBasic{}, crisis.AppModuleBasic{}, @@ -775,6 +776,8 @@ func NewOKExChainApp( if err := app.ParamsKeeper.ApplyEffectiveUpgrade(ctx); err != nil { tmos.Exit(fmt.Sprintf("failed apply effective upgrade height info: %s", err)) } + + app.WasmKeeper.UpdateGasRegister(ctx) } app.ScopedIBCKeeper = scopedIBCKeeper diff --git a/libs/ibc-go/testing/simapp/app.go b/libs/ibc-go/testing/simapp/app.go index 4a817f6270..96183de0a2 100644 --- a/libs/ibc-go/testing/simapp/app.go +++ b/libs/ibc-go/testing/simapp/app.go @@ -186,6 +186,7 @@ var ( wasmclient.UnpinCodesProposalHandler, wasmclient.UpdateDeploymentWhitelistProposalHandler, wasmclient.UpdateWASMContractMethodBlockedListProposalHandler, + wasmclient.GetCmdExtraProposal, ), params.AppModuleBasic{}, crisis.AppModuleBasic{}, diff --git a/x/gov/ante/ante.go b/x/gov/ante/ante.go index f58eff13c3..ccf6d1fc16 100644 --- a/x/gov/ante/ante.go +++ b/x/gov/ante/ante.go @@ -11,6 +11,7 @@ import ( "github.com/okex/exchain/x/params" paramstypes "github.com/okex/exchain/x/params/types" stakingkeeper "github.com/okex/exchain/x/staking" + wasmtypes "github.com/okex/exchain/x/wasm/types" ) type AnteDecorator struct { @@ -50,6 +51,10 @@ func (ad AnteDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, ne if err := ad.pk.CheckMsgSubmitProposal(ctx, msg); err != nil { return ctx, err } + case *wasmtypes.ExtraProposal: + if !ad.sk.IsValidator(ctx, msg.Proposer) { + return ctx, wasmtypes.ErrProposerMustBeValidator + } } } } diff --git a/x/gov/types/content.go b/x/gov/types/content.go index 64c9928133..f18eabf740 100644 --- a/x/gov/types/content.go +++ b/x/gov/types/content.go @@ -10,6 +10,8 @@ import ( const ( MaxDescriptionLength int = 5000 MaxTitleLength int = 140 + MaxExtraBodyLength int = 5000 + MaxExtraActionLength int = 140 ) // Content defines an interface that a proposal must implement. It contains diff --git a/x/wasm/client/cli/gov_custom.go b/x/wasm/client/cli/gov_custom.go index 47f6b504eb..eea13dfce5 100644 --- a/x/wasm/client/cli/gov_custom.go +++ b/x/wasm/client/cli/gov_custom.go @@ -10,10 +10,12 @@ import ( "github.com/okex/exchain/libs/cosmos-sdk/codec" interfacetypes "github.com/okex/exchain/libs/cosmos-sdk/codec/types" sdk "github.com/okex/exchain/libs/cosmos-sdk/types" + "github.com/okex/exchain/libs/cosmos-sdk/version" "github.com/okex/exchain/libs/cosmos-sdk/x/auth" "github.com/okex/exchain/libs/cosmos-sdk/x/auth/client/utils" "github.com/okex/exchain/x/gov" govcli "github.com/okex/exchain/x/gov/client/cli" + utils2 "github.com/okex/exchain/x/wasm/client/utils" "github.com/okex/exchain/x/wasm/types" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -124,3 +126,58 @@ func ProposalUpdateWASMContractMethodBlockedListCmd(cdcP *codec.CodecProxy, reg return cmd } + +// GetCmdExtraProposal implements a command handler for submitting extra proposal transaction +func GetCmdExtraProposal(cdcP *codec.CodecProxy, reg interfacetypes.InterfaceRegistry) *cobra.Command { + return &cobra.Command{ + Use: "wasm-extra [proposal-file]", + Args: cobra.ExactArgs(1), + Short: "Submit a proposal for wasm extra.", + Long: strings.TrimSpace( + fmt.Sprintf(`Submit a proposal for wasm extra along with an initial deposit. +The proposal details must be supplied via a JSON file. +Example: +$ %s tx gov submit-proposal wasm-extra --from= +Where proposal.json contains like these: +# modify wasm gas factor +{ + "title":"modify wasm gas factor", + "description":"modify wasm gas factor", + "action": "GasFactor", + "extra": "{\"factor\":240000000}", + "deposit":[ + { + "denom":"%s", + "amount":"100.000000000000000000" + } + ] +} +`, version.ClientName, sdk.DefaultBondDenom, + )), + RunE: func(cmd *cobra.Command, args []string) error { + cdc := cdcP.GetCdc() + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContext().WithCodec(cdc) + + proposalJson, err := utils2.ParseExtraProposalJSON(cdc, args[0]) + if err != nil { + return err + } + + proposal := types.ExtraProposal{ + Title: proposalJson.Title, + Description: proposalJson.Description, + Action: proposalJson.Action, + Extra: proposalJson.Extra, + } + + if err := proposal.ValidateBasic(); err != nil { + return err + } + + msg := gov.NewMsgSubmitProposal(&proposal, proposalJson.Deposit, cliCtx.GetFromAddress()) + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } +} diff --git a/x/wasm/client/cli/gov_tx.go b/x/wasm/client/cli/gov_tx.go index 39603bfe94..fa6d953756 100644 --- a/x/wasm/client/cli/gov_tx.go +++ b/x/wasm/client/cli/gov_tx.go @@ -5,8 +5,6 @@ import ( "fmt" "strconv" - "github.com/spf13/cobra" - clientCtx "github.com/okex/exchain/libs/cosmos-sdk/client/context" "github.com/okex/exchain/libs/cosmos-sdk/codec" codectypes "github.com/okex/exchain/libs/cosmos-sdk/codec/types" @@ -16,6 +14,7 @@ import ( govcli "github.com/okex/exchain/x/gov/client/cli" govtypes "github.com/okex/exchain/x/gov/types" "github.com/okex/exchain/x/wasm/types" + "github.com/spf13/cobra" ) //func ProposalStoreCodeCmd() *cobra.Command { diff --git a/x/wasm/client/proposal_handler.go b/x/wasm/client/proposal_handler.go index 019c192e89..5498a61e80 100644 --- a/x/wasm/client/proposal_handler.go +++ b/x/wasm/client/proposal_handler.go @@ -36,3 +36,6 @@ var UpdateDeploymentWhitelistProposalHandler = govclient.NewProposalHandler(cli. // UpdateWASMContractMethodBlockedListProposalHandler is a custom proposal handler which defines methods blacklist of a contract. var UpdateWASMContractMethodBlockedListProposalHandler = govclient.NewProposalHandler(cli.ProposalUpdateWASMContractMethodBlockedListCmd, rest.EmptyProposalRestHandler) + +// GetCmdExtraProposal is a custom proposal handler which extra proposal. +var GetCmdExtraProposal = govclient.NewProposalHandler(cli.GetCmdExtraProposal, rest.EmptyProposalRestHandler) diff --git a/x/wasm/client/utils/utils.go b/x/wasm/client/utils/utils.go index bbe9adc7f9..8038fb7505 100644 --- a/x/wasm/client/utils/utils.go +++ b/x/wasm/client/utils/utils.go @@ -3,6 +3,10 @@ package utils import ( "bytes" "compress/gzip" + "io/ioutil" + + "github.com/okex/exchain/libs/cosmos-sdk/codec" + sdk "github.com/okex/exchain/libs/cosmos-sdk/types" ) var ( @@ -36,3 +40,25 @@ func GzipIt(input []byte) ([]byte, error) { return b.Bytes(), nil } + +// ExtraProposalJSON defines a ExtraProposal with a deposit used to parse +// manage treasures proposals from a JSON file. +type ExtraProposalJSON struct { + Title string `json:"title" yaml:"title"` + Description string `json:"description" yaml:"description"` + Deposit sdk.SysCoins `json:"deposit" yaml:"deposit"` + Action string `json:"action" yaml:"action"` + Extra string `json:"extra" yaml:"extra"` +} + +// ParseExtraProposalJSON parses json from proposal file to ExtraProposalJSON struct +func ParseExtraProposalJSON(cdc *codec.Codec, proposalFilePath string) ( + proposal ExtraProposalJSON, err error) { + contents, err := ioutil.ReadFile(proposalFilePath) + if err != nil { + return + } + + cdc.MustUnmarshalJSON(contents, &proposal) + return +} diff --git a/x/wasm/keeper/contract_keeper.go b/x/wasm/keeper/contract_keeper.go index 254bea6a41..de15070bfa 100644 --- a/x/wasm/keeper/contract_keeper.go +++ b/x/wasm/keeper/contract_keeper.go @@ -23,6 +23,8 @@ type decoratedKeeper interface { updateContractMethodBlockedList(ctx sdk.Context, blockedMethods *types.ContractMethods, isDelete bool) error GetParams(ctx sdk.Context) types.Params + + InvokeExtraProposal(ctx sdk.Context, action string, extra string) error } type PermissionedKeeper struct { @@ -99,3 +101,7 @@ func (p PermissionedKeeper) UpdateContractMethodBlockedList(ctx sdk.Context, blo func (p PermissionedKeeper) GetParams(ctx sdk.Context) types.Params { return p.nested.GetParams(ctx) } + +func (p PermissionedKeeper) InvokeExtraProposal(ctx sdk.Context, action string, extra string) error { + return p.nested.InvokeExtraProposal(ctx, action, extra) +} diff --git a/x/wasm/keeper/gas_register.go b/x/wasm/keeper/gas_register.go index fb0851e551..b0855fde07 100644 --- a/x/wasm/keeper/gas_register.go +++ b/x/wasm/keeper/gas_register.go @@ -30,6 +30,7 @@ const ( // Please note that all gas prices returned to wasmvm should have this multiplied. // Benchmarks and numbers were discussed in: https://github.com/okex/exchain/pull/634#issuecomment-938055852 DefaultGasMultiplier uint64 = 38_000_000 + BaseGasMultiplier uint64 = 1_000_000 // DefaultInstanceCost is how much SDK gas we charge each time we load a WASM instance. // Creating a new instance is costly, and this helps put a recursion limit to contracts calling contracts. // Benchmarks and numbers were discussed in: https://github.com/okex/exchain/pull/634#issuecomment-938056803 @@ -70,6 +71,12 @@ type GasRegister interface { ToWasmVMGas(source sdk.Gas) uint64 // FromWasmVMGas converts from wasmvm gas to sdk gas FromWasmVMGas(source uint64) sdk.Gas + + // GetGasMultiplier + GetGasMultiplier() uint64 + + // UpdateGasMultiplier + UpdateGasMultiplier(gasMultiplier uint64) bool } // WasmGasRegisterConfig config type @@ -116,16 +123,16 @@ type WasmGasRegister struct { } // NewDefaultWasmGasRegister creates instance with default values -func NewDefaultWasmGasRegister() WasmGasRegister { +func NewDefaultWasmGasRegister() *WasmGasRegister { return NewWasmGasRegister(DefaultGasRegisterConfig()) } // NewWasmGasRegister constructor -func NewWasmGasRegister(c WasmGasRegisterConfig) WasmGasRegister { +func NewWasmGasRegister(c WasmGasRegisterConfig) *WasmGasRegister { if c.GasMultiplier == 0 { - panic(sdkerrors.Wrap(sdkerrors.ErrLogic, "GasMultiplier can not be 0")) + panic(sdkerrors.Wrap(sdkerrors.ErrLogic, "GasFactor can not be 0")) } - return WasmGasRegister{ + return &WasmGasRegister{ c: c, } } @@ -225,3 +232,14 @@ func (g WasmGasRegister) ToWasmVMGas(source storetypes.Gas) uint64 { func (g WasmGasRegister) FromWasmVMGas(source uint64) sdk.Gas { return source / g.c.GasMultiplier } + +// GetGasMultiplier +func (g WasmGasRegister) GetGasMultiplier() uint64 { + return g.c.GasMultiplier +} + +// UpdateGasMultiplier +func (g *WasmGasRegister) UpdateGasMultiplier(gasMultiplier uint64) bool { + g.c.GasMultiplier = gasMultiplier + return true +} diff --git a/x/wasm/keeper/keeper.go b/x/wasm/keeper/keeper.go index 159b9f4117..2c6726a7cc 100644 --- a/x/wasm/keeper/keeper.go +++ b/x/wasm/keeper/keeper.go @@ -281,6 +281,63 @@ func (k Keeper) GetParams(ctx sdk.Context) types.Params { return params } +func (k Keeper) InvokeExtraProposal(ctx sdk.Context, action string, extra string) error { + switch action { + case types.ActionModifyGasFactor: + return k.modifyGasFactor(ctx, extra) + } + + return nil +} + +// UpdateGasRegister warning, only use it in beginblock +func (k *Keeper) UpdateGasRegister(ctx sdk.Context) { + if ctx.IsCheckTx() || ctx.IsTraceTx() { + return + } + + gasFactor := k.GetGasFactor(ctx) + if gasFactor != k.gasRegister.GetGasMultiplier() { + k.gasRegister.UpdateGasMultiplier(gasFactor) + } + return +} + +func (k *Keeper) modifyGasFactor(ctx sdk.Context, extra string) error { + result, err := types.NewActionModifyGasFactor(extra) + if err != nil { + return err + } + + value := result.MulInt64(int64(BaseGasMultiplier)).TruncateInt64() + if value <= 0 { + return types.ErrCodeInvalidGasFactor + } + k.SetGasFactor(ctx, uint64(value)) + return nil +} + +// get the gas factor +func (k Keeper) GetGasFactor(ctx sdk.Context) uint64 { + store := k.ada.NewStore(ctx.GasMeter(), ctx.KVStore(k.storeKey), nil) + + if !store.Has(types.KeyGasFactorPrefix) { + return DefaultGasMultiplier + } + + b := store.Get(types.KeyGasFactorPrefix) + if b != nil { + return sdk.BigEndianToUint64(b) + } + return DefaultGasMultiplier +} + +// set the gas factor +func (k Keeper) SetGasFactor(ctx sdk.Context, factor uint64) { + store := k.ada.NewStore(ctx.GasMeter(), ctx.KVStore(k.storeKey), nil) + store.Set(types.KeyGasFactorPrefix, sdk.Uint64ToBigEndian(factor)) +} + func (k Keeper) SetParams(ctx sdk.Context, ps types.Params) { watcher.SetParams(ps) k.paramSpace.SetParamSet(ctx, &ps) diff --git a/x/wasm/keeper/proposal_handler.go b/x/wasm/keeper/proposal_handler.go index ac44826050..ebdfb49a4e 100644 --- a/x/wasm/keeper/proposal_handler.go +++ b/x/wasm/keeper/proposal_handler.go @@ -59,6 +59,8 @@ func NewWasmProposalHandlerX(k types.ContractOpsKeeper, enabledProposalTypes []t return handleUpdateInstantiateConfigProposal(ctx, k, *c) case *types.UpdateDeploymentWhitelistProposal: return handleUpdateDeploymentWhitelistProposal(ctx, k, *c) + case *types.ExtraProposal: + return handleExtraProposal(ctx, k, *c) case *types.UpdateWASMContractMethodBlockedListProposal: return handleUpdateWASMContractMethodBlockedListProposal(ctx, k, *c) default: @@ -286,6 +288,10 @@ func handleUpdateDeploymentWhitelistProposal(ctx sdk.Context, k types.ContractOp return nil } +func handleExtraProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.ExtraProposal) (err error) { + return k.InvokeExtraProposal(ctx, p.Action, p.Extra) +} + func handleUpdateWASMContractMethodBlockedListProposal(ctx sdk.Context, k types.ContractOpsKeeper, p types.UpdateWASMContractMethodBlockedListProposal) error { if err := p.ValidateBasic(); err != nil { return err diff --git a/x/wasm/keeper/wasmtesting/gas_register.go b/x/wasm/keeper/wasmtesting/gas_register.go index 4873633b34..727842820f 100644 --- a/x/wasm/keeper/wasmtesting/gas_register.go +++ b/x/wasm/keeper/wasmtesting/gas_register.go @@ -64,3 +64,11 @@ func (m MockGasRegister) FromWasmVMGas(source uint64) sdk.Gas { } return m.FromWasmVMGasFn(source) } + +func (m MockGasRegister) GetGasMultiplier() uint64 { + return 0 +} + +func (m *MockGasRegister) UpdateGasMultiplier(gasMultiplier uint64) bool { + return true +} diff --git a/x/wasm/module.go b/x/wasm/module.go index 63f1e07830..b6f10c8779 100644 --- a/x/wasm/module.go +++ b/x/wasm/module.go @@ -179,12 +179,13 @@ func (AppModule) QuerierRoute() string { //} // BeginBlock returns the begin blocker for the wasm module. -func (am AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) { +func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { watcher.NewHeight() if tmtypes.DownloadDelta { keeper.GetWasmParamsCache().SetNeedParamsUpdate() keeper.GetWasmParamsCache().SetNeedBlockedUpdate() } + am.keeper.UpdateGasRegister(ctx) } // EndBlock returns the end blocker for the wasm module. It returns no validator diff --git a/x/wasm/proto/proposal_custom.proto b/x/wasm/proto/proposal_custom.proto index 4e1c8b07ed..7157b6625c 100644 --- a/x/wasm/proto/proposal_custom.proto +++ b/x/wasm/proto/proposal_custom.proto @@ -25,3 +25,10 @@ message Method { string name = 1; string extra = 2; } + +message ExtraProposal { + string title = 1; + string description = 2; + string action = 3; + string extra = 4; +} diff --git a/x/wasm/types/codec.go b/x/wasm/types/codec.go index b452f67410..5a49f5d08a 100644 --- a/x/wasm/types/codec.go +++ b/x/wasm/types/codec.go @@ -31,6 +31,7 @@ func RegisterLegacyAminoCodec(cdc *codec.Codec) { //nolint:staticcheck cdc.RegisterConcrete(&UpdateInstantiateConfigProposal{}, "wasm/UpdateInstantiateConfigProposal", nil) cdc.RegisterConcrete(&UpdateDeploymentWhitelistProposal{}, "wasm/UpdateDeploymentWhitelistProposal", nil) cdc.RegisterConcrete(&UpdateWASMContractMethodBlockedListProposal{}, "wasm/UpdateWASMContractMethodBlockedListProposal", nil) + cdc.RegisterConcrete(&ExtraProposal{}, "wasm/ExtraProposal", nil) } func RegisterInterfaces(registry types.InterfaceRegistry) { @@ -69,6 +70,7 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &UpdateInstantiateConfigProposal{}, &UpdateDeploymentWhitelistProposal{}, &UpdateWASMContractMethodBlockedListProposal{}, + &ExtraProposal{}, ) registry.RegisterInterface("ContractInfoExtension", (*ContractInfoExtension)(nil)) diff --git a/x/wasm/types/errors.go b/x/wasm/types/errors.go index b7ac84415f..cab9feca8d 100644 --- a/x/wasm/types/errors.go +++ b/x/wasm/types/errors.go @@ -1,6 +1,8 @@ package types import ( + "fmt" + sdk "github.com/okex/exchain/libs/cosmos-sdk/types" sdkErrors "github.com/okex/exchain/libs/cosmos-sdk/types/errors" ) @@ -88,6 +90,12 @@ var ( // ErrExceedMaxQueryStackSize error if max query stack size is exceeded ErrExceedMaxQueryStackSize = sdkErrors.Register(DefaultCodespace, 27, "max query stack size exceeded") + + ErrCodeInvalidGasFactor = sdkErrors.Register(ModuleName, 29, "invalid gas factor") + ErrHandleExtraProposal = sdkErrors.Register(DefaultCodespace, 30, "handle extra proposal error") + ErrUnknownExtraProposalAction = sdkErrors.Register(DefaultCodespace, 31, "extra proposal's action unknown") + + ErrProposerMustBeValidator = sdkErrors.Register(ModuleName, 32, "the proposal of proposer must be validator") ) type ErrNoSuchContract struct { @@ -106,7 +114,7 @@ func (m *ErrNoSuchContract) Codespace() string { return DefaultCodespace } -func GenerateUnauthorizeError(act AccessType) string{ +func GenerateUnauthorizeError(act AccessType) string { switch act { case AccessTypeNobody: return "Failed to create code, nobody allowed to upload contract" @@ -115,3 +123,7 @@ func GenerateUnauthorizeError(act AccessType) string{ } return "Failed to create code, unexpected error" } + +func ErrExtraProposalParams(desc string) sdk.Error { + return sdkErrors.New(DefaultCodespace, 28, fmt.Sprintf("wasm extra proposal error:%s", desc)) +} diff --git a/x/wasm/types/exported_keepers.go b/x/wasm/types/exported_keepers.go index 7663efc855..460e869375 100644 --- a/x/wasm/types/exported_keepers.go +++ b/x/wasm/types/exported_keepers.go @@ -68,6 +68,9 @@ type ContractOpsKeeper interface { // GetParams get params from paramsubspace. GetParams(ctx sdk.Context) Params + + // InvokeExtraProposal invoke extra proposal + InvokeExtraProposal(ctx sdk.Context, action string, extra string) error } // IBCContractKeeper IBC lifecycle event handler diff --git a/x/wasm/types/keys.go b/x/wasm/types/keys.go index 4078f7ceec..5afc19ba50 100644 --- a/x/wasm/types/keys.go +++ b/x/wasm/types/keys.go @@ -32,9 +32,11 @@ var ( PinnedCodeIndexPrefix = []byte{0x07} TXCounterPrefix = []byte{0x08} ContractMethodBlockedListPrefix = []byte{0x10} + GasFactorPrefix = []byte{0x11} - KeyLastCodeID = append(SequenceKeyPrefix, []byte("lastCodeId")...) - KeyLastInstanceID = append(SequenceKeyPrefix, []byte("lastContractId")...) + KeyLastCodeID = append(SequenceKeyPrefix, []byte("lastCodeId")...) + KeyLastInstanceID = append(SequenceKeyPrefix, []byte("lastContractId")...) + KeyGasFactorPrefix = append(GasFactorPrefix, []byte("gasFactor")...) ) // GetCodeKey constructs the key for retreiving the ID for the WASM code diff --git a/x/wasm/types/proposal.go b/x/wasm/types/proposal.go index e625d84322..071099ec72 100644 --- a/x/wasm/types/proposal.go +++ b/x/wasm/types/proposal.go @@ -25,6 +25,9 @@ const ( ProposalTypeUpdateInstantiateConfig ProposalType = "UpdateInstantiateConfig" ProposalTypeUpdateDeploymentWhitelist ProposalType = "UpdateDeploymentWhitelist" ProposalTypeUpdateWasmContractMethodBlockedList ProposalType = "UpdateWasmContractMethodBlockedList" + ProposalTypeExtra ProposalType = "WasmExtra" + + ActionModifyGasFactor = "GasFactor" ) // DisableAllProposals contains no wasm gov types. @@ -44,6 +47,7 @@ var EnableAllProposals = []ProposalType{ ProposalTypeUpdateInstantiateConfig, ProposalTypeUpdateDeploymentWhitelist, ProposalTypeUpdateWasmContractMethodBlockedList, + ProposalTypeExtra, } // NecessaryProposals contains necessary wasm gov types as keys. @@ -55,6 +59,7 @@ var NecessaryProposals = []ProposalType{ ProposalTypeUnpinCodes, ProposalTypeUpdateDeploymentWhitelist, ProposalTypeUpdateWasmContractMethodBlockedList, + ProposalTypeExtra, } // ConvertToProposals maps each key to a ProposalType and returns a typed list. @@ -88,6 +93,7 @@ func init() { // register new content types with the sdk govtypes.RegisterProposalType(string(ProposalTypeUpdateInstantiateConfig)) govtypes.RegisterProposalType(string(ProposalTypeUpdateDeploymentWhitelist)) govtypes.RegisterProposalType(string(ProposalTypeUpdateWasmContractMethodBlockedList)) + govtypes.RegisterProposalType(string(ProposalTypeExtra)) govtypes.RegisterProposalTypeCodec(&StoreCodeProposal{}, "wasm/StoreCodeProposal") govtypes.RegisterProposalTypeCodec(&InstantiateContractProposal{}, "wasm/InstantiateContractProposal") govtypes.RegisterProposalTypeCodec(&MigrateContractProposal{}, "wasm/MigrateContractProposal") @@ -100,6 +106,7 @@ func init() { // register new content types with the sdk govtypes.RegisterProposalTypeCodec(&UpdateInstantiateConfigProposal{}, "wasm/UpdateInstantiateConfigProposal") govtypes.RegisterProposalTypeCodec(&UpdateDeploymentWhitelistProposal{}, "wasm/UpdateDeploymentWhitelistProposal") govtypes.RegisterProposalTypeCodec(&UpdateWASMContractMethodBlockedListProposal{}, "wasm/UpdateWASMContractMethodBlockedListProposal") + govtypes.RegisterProposalTypeCodec(&ExtraProposal{}, "wasm/ExtraProposal") } // ProposalRoute returns the routing key of a parameter change proposal. diff --git a/x/wasm/types/proposal_custom.go b/x/wasm/types/proposal_custom.go index 660365dc89..04adee26c3 100644 --- a/x/wasm/types/proposal_custom.go +++ b/x/wasm/types/proposal_custom.go @@ -1,8 +1,12 @@ package types import ( + "encoding/json" "fmt" + "strings" + sdk "github.com/okex/exchain/libs/cosmos-sdk/types" + govtypes "github.com/okex/exchain/x/gov/types" ) const ( @@ -173,3 +177,78 @@ func FindContractMethods(cms []*ContractMethods, contractAddr string) *ContractM } return nil } + +var _ govtypes.Content = &ExtraProposal{} + +// ProposalRoute returns the routing key of a parameter change proposal. +func (p ExtraProposal) ProposalRoute() string { return RouterKey } + +// ProposalType returns the type +func (p ExtraProposal) ProposalType() string { + return string(ProposalTypeExtra) +} + +// ValidateBasic validates the proposal +func (p ExtraProposal) ValidateBasic() error { + if err := validateProposalCommons(p.Title, p.Description); err != nil { + return err + } + + if len(strings.TrimSpace(p.Action)) == 0 { + return govtypes.ErrInvalidProposalContent("extra proposal's action is required") + } + if len(p.Action) > govtypes.MaxExtraActionLength { + return govtypes.ErrInvalidProposalContent("extra proposal's action length is bigger than max length") + } + if len(strings.TrimSpace(p.Extra)) == 0 { + return govtypes.ErrInvalidProposalContent("extra proposal's extra is required") + } + if len(p.Extra) > govtypes.MaxExtraBodyLength { + return govtypes.ErrInvalidProposalContent("extra proposal's extra body length is bigger than max length") + } + switch p.Action { + case ActionModifyGasFactor: + _, err := NewActionModifyGasFactor(p.Extra) + return err + default: + return ErrUnknownExtraProposalAction + } +} + +type GasFactor struct { + Factor string `json:"factor" yaml:"factor"` +} + +func NewActionModifyGasFactor(data string) (sdk.Dec, error) { + var param GasFactor + err := json.Unmarshal([]byte(data), ¶m) + if err != nil { + return sdk.Dec{}, ErrExtraProposalParams("parse json error") + } + + result, err := sdk.NewDecFromStr(param.Factor) + if err != nil { + return sdk.Dec{}, ErrExtraProposalParams(fmt.Sprintf("parse factor error:%s", param.Factor)) + } + + if result.IsNil() || result.IsNegative() || result.IsZero() { + return sdk.Dec{}, ErrExtraProposalParams(fmt.Sprintf("parse factor error:%s", param.Factor)) + } + + return result, nil +} + +// MarshalYAML pretty prints the wasm byte code +func (p ExtraProposal) MarshalYAML() (interface{}, error) { + return struct { + Title string `yaml:"title"` + Description string `yaml:"description"` + Action string `yaml:"action"` + Extra string `yaml:"extra"` + }{ + Title: p.Title, + Description: p.Description, + Action: p.Action, + Extra: p.Extra, + }, nil +} diff --git a/x/wasm/types/proposal_custom.pb.go b/x/wasm/types/proposal_custom.pb.go index fb6cad647e..4461e5031f 100644 --- a/x/wasm/types/proposal_custom.pb.go +++ b/x/wasm/types/proposal_custom.pb.go @@ -232,11 +232,74 @@ func (m *Method) GetExtra() string { return "" } +type ExtraProposal struct { + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + Action string `protobuf:"bytes,3,opt,name=action,proto3" json:"action,omitempty"` + Extra string `protobuf:"bytes,4,opt,name=extra,proto3" json:"extra,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ExtraProposal) Reset() { *m = ExtraProposal{} } +func (m *ExtraProposal) String() string { return proto.CompactTextString(m) } +func (*ExtraProposal) ProtoMessage() {} +func (*ExtraProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_dd9d4d6e8a1d82c0, []int{4} +} +func (m *ExtraProposal) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ExtraProposal.Unmarshal(m, b) +} +func (m *ExtraProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ExtraProposal.Marshal(b, m, deterministic) +} +func (m *ExtraProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_ExtraProposal.Merge(m, src) +} +func (m *ExtraProposal) XXX_Size() int { + return xxx_messageInfo_ExtraProposal.Size(m) +} +func (m *ExtraProposal) XXX_DiscardUnknown() { + xxx_messageInfo_ExtraProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_ExtraProposal proto.InternalMessageInfo + +func (m *ExtraProposal) GetTitle() string { + if m != nil { + return m.Title + } + return "" +} + +func (m *ExtraProposal) GetDescription() string { + if m != nil { + return m.Description + } + return "" +} + +func (m *ExtraProposal) GetAction() string { + if m != nil { + return m.Action + } + return "" +} + +func (m *ExtraProposal) GetExtra() string { + if m != nil { + return m.Extra + } + return "" +} + func init() { proto.RegisterType((*UpdateDeploymentWhitelistProposal)(nil), "types.UpdateDeploymentWhitelistProposal") proto.RegisterType((*UpdateWASMContractMethodBlockedListProposal)(nil), "types.UpdateWASMContractMethodBlockedListProposal") proto.RegisterType((*ContractMethods)(nil), "types.ContractMethods") proto.RegisterType((*Method)(nil), "types.Method") + proto.RegisterType((*ExtraProposal)(nil), "types.ExtraProposal") } func init() { @@ -244,25 +307,27 @@ func init() { } var fileDescriptor_dd9d4d6e8a1d82c0 = []byte{ - // 315 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x92, 0xcf, 0x4a, 0x03, 0x31, - 0x10, 0xc6, 0xd9, 0xfe, 0xb3, 0x9d, 0xd6, 0x2a, 0x41, 0x64, 0xf1, 0xb4, 0xee, 0xc5, 0x45, 0xa1, - 0x85, 0x7a, 0x17, 0x5a, 0x7b, 0xb4, 0x20, 0x2b, 0x52, 0xf0, 0xa0, 0xec, 0x6e, 0x06, 0x1a, 0xdc, - 0xdd, 0x2c, 0xc9, 0x14, 0xdb, 0x27, 0xf0, 0xb9, 0x7c, 0x33, 0xd9, 0x24, 0x15, 0x5b, 0xaf, 0x5e, - 0x42, 0xe6, 0x9b, 0xcc, 0x97, 0xdf, 0x4c, 0x02, 0xe1, 0x66, 0xfc, 0x91, 0xe8, 0x62, 0x5c, 0x29, - 0x49, 0xb2, 0x5e, 0x2b, 0xa9, 0x93, 0xfc, 0x2d, 0x5b, 0x6b, 0x92, 0xc5, 0xc8, 0xa8, 0xac, 0x4d, - 0xdb, 0x0a, 0x75, 0xf8, 0xe9, 0xc1, 0xe5, 0x73, 0xc5, 0x13, 0xc2, 0x39, 0x56, 0xb9, 0xdc, 0x16, - 0x58, 0xd2, 0x72, 0x25, 0x08, 0x73, 0xa1, 0xe9, 0xd1, 0x55, 0xb2, 0x33, 0x68, 0x93, 0xa0, 0x1c, - 0x7d, 0x2f, 0xf0, 0xa2, 0x5e, 0x6c, 0x03, 0x16, 0x40, 0x9f, 0xa3, 0xce, 0x94, 0xa8, 0x48, 0xc8, - 0xd2, 0x6f, 0x98, 0xdc, 0x6f, 0x89, 0x5d, 0xc3, 0x29, 0x17, 0x9a, 0x94, 0x48, 0xd7, 0x24, 0xd5, - 0x94, 0x73, 0xa5, 0xfd, 0x66, 0xd0, 0x8c, 0x7a, 0xf1, 0x1f, 0x3d, 0xfc, 0xf2, 0xe0, 0xc6, 0x92, - 0x2c, 0xa7, 0x4f, 0x8b, 0x7b, 0x59, 0x92, 0x4a, 0x32, 0x5a, 0x20, 0xad, 0x24, 0x9f, 0xe5, 0x32, - 0x7b, 0x47, 0xfe, 0xf0, 0x1f, 0x4c, 0x77, 0x30, 0x4c, 0xad, 0x9d, 0xf5, 0xae, 0x89, 0xbc, 0xa8, - 0x3f, 0x39, 0x1f, 0x99, 0x89, 0x8c, 0xf6, 0x6f, 0xd6, 0xf1, 0xc1, 0x69, 0x76, 0x01, 0x5d, 0xa1, - 0xe7, 0x98, 0x23, 0xa1, 0xdf, 0x0a, 0xbc, 0xa8, 0x1b, 0xff, 0xc4, 0xe1, 0x2b, 0x9c, 0x1c, 0x94, - 0xb3, 0x10, 0x06, 0x99, 0x93, 0xea, 0x3e, 0x1d, 0xed, 0x9e, 0xc6, 0xae, 0xe0, 0xa8, 0x70, 0x2c, - 0x8d, 0xa0, 0x19, 0xf5, 0x27, 0xc7, 0x8e, 0xc5, 0x9a, 0xc4, 0xbb, 0x6c, 0x38, 0x81, 0x8e, 0x95, - 0x18, 0x83, 0x56, 0x99, 0x14, 0xbb, 0xe6, 0xcd, 0xbe, 0x9e, 0x08, 0x6e, 0x48, 0x25, 0xae, 0x6b, - 0x1b, 0xcc, 0x86, 0x2f, 0x03, 0xf7, 0x1d, 0x8c, 0x67, 0xda, 0x31, 0xef, 0x7f, 0xfb, 0x1d, 0x00, - 0x00, 0xff, 0xff, 0x73, 0x2c, 0x40, 0xd8, 0x25, 0x02, 0x00, 0x00, + // 341 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x52, 0x4d, 0x4b, 0xeb, 0x40, + 0x14, 0x25, 0x4d, 0xdb, 0xd7, 0xde, 0x7e, 0xbc, 0xc7, 0xf0, 0x28, 0xc1, 0x55, 0xcc, 0xc6, 0xa0, + 0xd0, 0x42, 0xdd, 0x0b, 0xad, 0x75, 0x67, 0x41, 0x22, 0x52, 0x70, 0xa1, 0x4c, 0x33, 0x03, 0x1d, + 0x4c, 0x32, 0x61, 0xe6, 0x16, 0xdb, 0x5f, 0xe0, 0xef, 0xf2, 0x9f, 0x49, 0x66, 0xa6, 0xda, 0xd6, + 0xa5, 0x6e, 0xc2, 0x9c, 0x73, 0x72, 0xef, 0x3d, 0xe7, 0x72, 0x21, 0xda, 0x8c, 0x5e, 0xa9, 0xce, + 0x47, 0xa5, 0x92, 0x28, 0xab, 0x6f, 0x29, 0x35, 0xcd, 0x9e, 0xd3, 0xb5, 0x46, 0x99, 0x0f, 0x0d, + 0x4b, 0x1a, 0xb8, 0x2d, 0xb9, 0x8e, 0xde, 0x3c, 0x38, 0x7d, 0x28, 0x19, 0x45, 0x3e, 0xe3, 0x65, + 0x26, 0xb7, 0x39, 0x2f, 0x70, 0xb1, 0x12, 0xc8, 0x33, 0xa1, 0xf1, 0xce, 0x55, 0x92, 0xff, 0xd0, + 0x40, 0x81, 0x19, 0x0f, 0xbc, 0xd0, 0x8b, 0xdb, 0x89, 0x05, 0x24, 0x84, 0x0e, 0xe3, 0x3a, 0x55, + 0xa2, 0x44, 0x21, 0x8b, 0xa0, 0x66, 0xb4, 0x7d, 0x8a, 0x9c, 0xc3, 0x3f, 0x26, 0x34, 0x2a, 0xb1, + 0x5c, 0xa3, 0x54, 0x13, 0xc6, 0x94, 0x0e, 0xfc, 0xd0, 0x8f, 0xdb, 0xc9, 0x37, 0x3e, 0x7a, 0xf7, + 0xe0, 0xc2, 0x3a, 0x59, 0x4c, 0xee, 0xe7, 0xd7, 0xb2, 0x40, 0x45, 0x53, 0x9c, 0x73, 0x5c, 0x49, + 0x36, 0xcd, 0x64, 0xfa, 0xc2, 0xd9, 0xed, 0x6f, 0x78, 0xba, 0x82, 0xfe, 0xd2, 0xb6, 0xb3, 0xbd, + 0x2b, 0x47, 0x5e, 0xdc, 0x19, 0x0f, 0x86, 0x66, 0x23, 0xc3, 0xc3, 0xc9, 0x3a, 0x39, 0xfa, 0x9b, + 0x9c, 0x40, 0x4b, 0xe8, 0x19, 0xcf, 0x38, 0xf2, 0xa0, 0x1e, 0x7a, 0x71, 0x2b, 0xf9, 0xc4, 0xd1, + 0x13, 0xfc, 0x3d, 0x2a, 0x27, 0x11, 0x74, 0x53, 0x47, 0x55, 0x39, 0x9d, 0xdb, 0x03, 0x8e, 0x9c, + 0xc1, 0x9f, 0xdc, 0x79, 0xa9, 0x85, 0x7e, 0xdc, 0x19, 0xf7, 0x9c, 0x17, 0xdb, 0x24, 0xd9, 0xa9, + 0xd1, 0x18, 0x9a, 0x96, 0x22, 0x04, 0xea, 0x05, 0xcd, 0x77, 0xe1, 0xcd, 0xbb, 0xda, 0x08, 0xdf, + 0xa0, 0xa2, 0x2e, 0xb5, 0x05, 0xd1, 0x1a, 0x7a, 0x37, 0xd5, 0xe3, 0xc7, 0x8b, 0x1b, 0x40, 0x93, + 0xa6, 0x46, 0xf4, 0x8d, 0xe8, 0xd0, 0xd7, 0xd8, 0xfa, 0xde, 0xd8, 0x69, 0xff, 0xb1, 0xeb, 0xae, + 0xd0, 0x44, 0x59, 0x36, 0xcd, 0xd9, 0x5d, 0x7e, 0x04, 0x00, 0x00, 0xff, 0xff, 0x1c, 0xb6, 0x74, + 0x86, 0x9c, 0x02, 0x00, 0x00, }