diff --git a/app/app.go b/app/app.go index 569522587d..a646d208a5 100644 --- a/app/app.go +++ b/app/app.go @@ -506,6 +506,11 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b // `loadLatest` is set to true. ctx := app.BaseApp.NewUncachedContext(true, tmproto.Header{}) app.capabilityKeeper.InitializeAndSeal(ctx) + + // Initialize pinned codes in wasmvm as they are not persisted there + if err := app.wasmKeeper.InitializePinnedCodes(ctx); err != nil { + panic(err) + } } app.scopedIBCKeeper = scopedIBCKeeper diff --git a/doc/proto.md b/doc/proto.md index 262d98b8a1..a1ae498748 100644 --- a/doc/proto.md +++ b/doc/proto.md @@ -18,7 +18,9 @@ - [ClearAdminProposal](#cosmwasm.wasm.v1beta1.ClearAdminProposal) - [InstantiateContractProposal](#cosmwasm.wasm.v1beta1.InstantiateContractProposal) - [MigrateContractProposal](#cosmwasm.wasm.v1beta1.MigrateContractProposal) + - [PinCodesProposal](#cosmwasm.wasm.v1beta1.PinCodesProposal) - [StoreCodeProposal](#cosmwasm.wasm.v1beta1.StoreCodeProposal) + - [UnpinCodesProposal](#cosmwasm.wasm.v1beta1.UnpinCodesProposal) - [UpdateAdminProposal](#cosmwasm.wasm.v1beta1.UpdateAdminProposal) - [x/wasm/internal/types/query.proto](#x/wasm/internal/types/query.proto) @@ -94,6 +96,7 @@ Code struct encompasses CodeInfo and CodeBytes | code_id | [uint64](#uint64) | | | | code_info | [CodeInfo](#cosmwasm.wasm.v1beta1.CodeInfo) | | | | code_bytes | [bytes](#bytes) | | | +| pinned | [bool](#bool) | | Pinned to wasmvm cache | @@ -294,6 +297,23 @@ MigrateContractProposal gov proposal content type to migrate a contract. + + +### PinCodesProposal +PinCodesProposal gov proposal content type to pin a set of code ids in the wasmvm cache. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| title | [string](#string) | | Title is a short summary | +| description | [string](#string) | | Description is a human readable text | +| code_ids | [uint64](#uint64) | repeated | CodeIDs references the new WASM codes | + + + + + + ### StoreCodeProposal @@ -315,6 +335,23 @@ StoreCodeProposal gov proposal content type to submit WASM code to the system + + +### UnpinCodesProposal +UnpinCodesProposal gov proposal content type to unpin a set of code ids in the wasmvm cache. + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| title | [string](#string) | | Title is a short summary | +| description | [string](#string) | | Description is a human readable text | +| code_ids | [uint64](#uint64) | repeated | CodeIDs references the WASM codes | + + + + + + ### UpdateAdminProposal @@ -943,7 +980,7 @@ CodeInfo is data for the uploaded contract WASM code | Field | Type | Label | Description | | ----- | ---- | ----- | ----------- | -| code_hash | [bytes](#bytes) | | CodeHash is the unique CodeID | +| code_hash | [bytes](#bytes) | | CodeHash is the unique identifier created by wasmvm | | creator | [string](#string) | | Creator address who initially stored the code | | source | [string](#string) | | Source is a valid absolute HTTPS URI to the contract's source code, optional | | builder | [string](#string) | | Builder is a valid docker image name with tag, optional | diff --git a/go.mod b/go.mod index 77cdeeb003..ed2b82abed 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.7.0 + github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca github.com/tendermint/tendermint v0.34.8 github.com/tendermint/tm-db v0.6.4 golang.org/x/net v0.0.0-20201209123823-ac852fbbde11 // indirect diff --git a/go.sum b/go.sum index 8c3454428d..9d6c3efb41 100644 --- a/go.sum +++ b/go.sum @@ -17,10 +17,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d h1:nalkkPQcITbvhmL4+C4cKA87NW0tfm3Kl9VXRoPywFg= github.com/ChainSafe/go-schnorrkel v0.0.0-20200405005733-88cbf1b4c40d/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4= -github.com/CosmWasm/wasmvm v0.13.1-0.20210125204657-16df1fdaf712 h1:8gMCeYi0In+3R+ox44SfXoY9a7KXngH8sDwsg+eLwB4= -github.com/CosmWasm/wasmvm v0.13.1-0.20210125204657-16df1fdaf712/go.mod h1:Id107qllDJyJjVQQsKMOy2YYF98sqPJ2t+jX1QES40A= -github.com/CosmWasm/wasmvm v0.14.0-alpha1 h1:n6cKrufXvaAzDaUfw1wEr39hNBLv3BY2usUnShmAFwQ= -github.com/CosmWasm/wasmvm v0.14.0-alpha1/go.mod h1:Id107qllDJyJjVQQsKMOy2YYF98sqPJ2t+jX1QES40A= github.com/CosmWasm/wasmvm v0.14.0-alpha2 h1:IF+ZNYe6XxKmAZaAzX/Y2dXB1v3l+J0+Vyz69CtojOQ= github.com/CosmWasm/wasmvm v0.14.0-alpha2/go.mod h1:Id107qllDJyJjVQQsKMOy2YYF98sqPJ2t+jX1QES40A= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= diff --git a/x/wasm/internal/keeper/bench_test.go b/x/wasm/internal/keeper/bench_test.go new file mode 100644 index 0000000000..42fe9cf6a5 --- /dev/null +++ b/x/wasm/internal/keeper/bench_test.go @@ -0,0 +1,55 @@ +package keeper + +import ( + "github.com/CosmWasm/wasmd/x/wasm/internal/types" + "github.com/stretchr/testify/require" + "github.com/syndtr/goleveldb/leveldb/opt" + dbm "github.com/tendermint/tm-db" + "testing" +) + +func BenchmarkExecution(b *testing.B) { + + specs := map[string]struct { + pinned bool + db func() dbm.DB + }{ + "unpinned, memory db": { + db: func() dbm.DB { return dbm.NewMemDB() }, + }, + "pinned, memory db": { + db: func() dbm.DB { return dbm.NewMemDB() }, + pinned: true, + }, + "unpinned, level db": { + db: func() dbm.DB { + levelDB, err := dbm.NewGoLevelDBWithOpts("testing", b.TempDir(), &opt.Options{BlockCacher: opt.NoCacher}) + require.NoError(b, err) + return levelDB + }, + }, + "pinned, level db": { + db: func() dbm.DB { + levelDB, err := dbm.NewGoLevelDBWithOpts("testing", b.TempDir(), &opt.Options{BlockCacher: opt.NoCacher}) + require.NoError(b, err) + return levelDB + }, + pinned: true, + }, + } + for name, spec := range specs { + b.Run(name, func(b *testing.B) { + wasmConfig := types.WasmConfig{MemoryCacheSize: 0} + ctx, keepers := createTestInput(b, false, SupportedFeatures, nil, nil, wasmConfig, spec.db()) + example := InstantiateHackatomExampleContract(b, ctx, keepers) + if spec.pinned { + require.NoError(b, keepers.WasmKeeper.PinCode(ctx, example.CodeID)) + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, err := keepers.WasmKeeper.QuerySmart(ctx, example.Contract, []byte(`{"verifier":{}}`)) + require.NoError(b, err) + } + }) + } +} diff --git a/x/wasm/internal/keeper/genesis.go b/x/wasm/internal/keeper/genesis.go index 809f91ed97..391b45f936 100644 --- a/x/wasm/internal/keeper/genesis.go +++ b/x/wasm/internal/keeper/genesis.go @@ -27,6 +27,11 @@ func InitGenesis(ctx sdk.Context, keeper *Keeper, data types.GenesisState, staki if code.CodeID > maxCodeID { maxCodeID = code.CodeID } + if code.Pinned { + if err := keeper.PinCode(ctx, code.CodeID); err != nil { + return nil, sdkerrors.Wrapf(err, "contract number %d", i) + } + } } var maxContractID int @@ -88,6 +93,7 @@ func ExportGenesis(ctx sdk.Context, keeper *Keeper) *types.GenesisState { CodeID: codeID, CodeInfo: info, CodeBytes: bytecode, + Pinned: keeper.IsPinnedCode(ctx, codeID), }) return false }) @@ -104,7 +110,6 @@ func ExportGenesis(ctx sdk.Context, keeper *Keeper) *types.GenesisState { } // redact contract info contract.Created = nil - genState.Contracts = append(genState.Contracts, types.Contract{ ContractAddress: addr.String(), ContractInfo: contract, diff --git a/x/wasm/internal/keeper/genesis_test.go b/x/wasm/internal/keeper/genesis_test.go index f2f389a7ee..c3de008a16 100644 --- a/x/wasm/internal/keeper/genesis_test.go +++ b/x/wasm/internal/keeper/genesis_test.go @@ -51,15 +51,21 @@ func TestGenesisExportImport(t *testing.T) { contract types.ContractInfo stateModels []types.Model history []types.ContractCodeHistoryEntry + pinned bool ) f.Fuzz(&codeInfo) f.Fuzz(&contract) f.Fuzz(&stateModels) f.NilChance(0).Fuzz(&history) + f.Fuzz(&pinned) creatorAddr, err := sdk.AccAddressFromBech32(codeInfo.Creator) require.NoError(t, err) codeID, err := srcKeeper.Create(srcCtx, creatorAddr, wasmCode, codeInfo.Source, codeInfo.Builder, &codeInfo.InstantiateConfig) require.NoError(t, err) + if pinned { + srcKeeper.PinCode(srcCtx, codeID) + } + contract.CodeID = codeID contractAddr := srcKeeper.generateContractAddress(srcCtx, codeID) srcKeeper.storeContractInfo(srcCtx, contractAddr, &contract) @@ -217,6 +223,24 @@ func TestGenesisInit(t *testing.T) { }, Params: types.DefaultParams(), }}, + "codes with same checksum can be pinned": { + src: types.GenesisState{ + Codes: []types.Code{ + { + CodeID: firstCodeID, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + Pinned: true, + }, + { + CodeID: 2, + CodeInfo: myCodeInfo, + CodeBytes: wasmCode, + Pinned: true, + }, + }, + Params: types.DefaultParams(), + }}, "happy path: code id in info and contract do match": { src: types.GenesisState{ Codes: []types.Code{{ @@ -405,6 +429,9 @@ func TestGenesisInit(t *testing.T) { spec.msgHandlerMock.verifyCalls(t) spec.stakingMock.verifyCalls(t) assert.Equal(t, spec.stakingMock.validatorUpdate, gotValidatorSet) + for _, c := range spec.src.Codes { + assert.Equal(t, c.Pinned, keeper.IsPinnedCode(ctx, c.CodeID)) + } }) } } diff --git a/x/wasm/internal/keeper/keeper.go b/x/wasm/internal/keeper/keeper.go index 2721b262a1..c48592320b 100644 --- a/x/wasm/internal/keeper/keeper.go +++ b/x/wasm/internal/keeper/keeper.go @@ -100,7 +100,6 @@ func NewKeeper( if err != nil { panic(err) } - // set KeyTable if it has not already been set if !paramSpace.HasKeyTable() { paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable()) @@ -220,7 +219,9 @@ func (k Keeper) Instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A } func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins, authZ AuthorizationPolicy) (sdk.AccAddress, []byte, error) { - ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: init") + if !k.IsPinnedCode(ctx, codeID) { + ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: init") + } // create contract address contractAddress := k.generateContractAddress(ctx, codeID) @@ -317,13 +318,15 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A // Execute executes the contract instance func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, msg []byte, coins sdk.Coins) (*sdk.Result, error) { - ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: execute") - contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) if err != nil { return nil, err } + if !k.IsPinnedCode(ctx, contractInfo.CodeID) { + ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: execute") + } + // add more funds if !coins.IsZero() { if k.bankKeeper.BlockedAddr(caller) { @@ -371,7 +374,9 @@ func (k Keeper) Migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller } func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte, authZ AuthorizationPolicy) (*sdk.Result, error) { - ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: migrate") + if !k.IsPinnedCode(ctx, newCodeID) { + ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: migrate") + } contractInfo := k.GetContractInfo(ctx, contractAddress) if contractInfo == nil { @@ -444,13 +449,15 @@ func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller // another native Go module directly. Thus, the keeper doesn't place any access controls on it, that is the // responsibility or the app developer (who passes the wasm.Keeper in app.go) func (k Keeper) Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte) (*sdk.Result, error) { - ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: sudo") - contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddress) if err != nil { return nil, err } + if !k.IsPinnedCode(ctx, contractInfo.CodeID) { + ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: sudo") + } + env := types.NewEnv(ctx, contractAddress) // prepare querier @@ -536,12 +543,14 @@ func (k Keeper) GetContractHistory(ctx sdk.Context, contractAddr sdk.AccAddress) // QuerySmart queries the smart contract itself. func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error) { - ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: query") - - _, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) + contractInfo, codeInfo, prefixStore, err := k.contractInstance(ctx, contractAddr) if err != nil { return nil, err } + if !k.IsPinnedCode(ctx, contractInfo.CodeID) { + ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: query") + } + // prepare querier querier := QueryHandler{ Ctx: ctx, @@ -577,12 +586,12 @@ func (k Keeper) contractInstance(ctx sdk.Context, contractAddress sdk.AccAddress var contractInfo types.ContractInfo k.cdc.MustUnmarshalBinaryBare(contractBz, &contractInfo) - contractInfoBz := store.Get(types.GetCodeKey(contractInfo.CodeID)) - if contractInfoBz == nil { - return contractInfo, types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "contract info") + codeInfoBz := store.Get(types.GetCodeKey(contractInfo.CodeID)) + if codeInfoBz == nil { + return contractInfo, types.CodeInfo{}, prefix.Store{}, sdkerrors.Wrap(types.ErrNotFound, "code info") } var codeInfo types.CodeInfo - k.cdc.MustUnmarshalBinaryBare(contractInfoBz, &codeInfo) + k.cdc.MustUnmarshalBinaryBare(codeInfoBz, &codeInfo) prefixStoreKey := types.GetContractStorePrefix(contractAddress) prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey) return contractInfo, codeInfo, prefixStore, nil @@ -693,6 +702,59 @@ func (k Keeper) dispatchMessages(ctx sdk.Context, contractAddr sdk.AccAddress, i return nil } +// PinCode pins the wasm contract in wasmvm cache +func (k Keeper) PinCode(ctx sdk.Context, codeID uint64) error { + codeInfo := k.GetCodeInfo(ctx, codeID) + if codeInfo == nil { + return sdkerrors.Wrap(types.ErrNotFound, "code info") + } + + if err := k.wasmer.Pin(codeInfo.CodeHash); err != nil { + return sdkerrors.Wrap(types.ErrPinContractFailed, err.Error()) + } + store := ctx.KVStore(k.storeKey) + // store 1 byte to not run into `nil` debugging issues + store.Set(types.GetPinnedCodeIndexPrefix(codeID), []byte{1}) + return nil +} + +// UnpinCode removes the wasm contract from wasmvm cache +func (k Keeper) UnpinCode(ctx sdk.Context, codeID uint64) error { + codeInfo := k.GetCodeInfo(ctx, codeID) + if codeInfo == nil { + return sdkerrors.Wrap(types.ErrNotFound, "code info") + } + if err := k.wasmer.Unpin(codeInfo.CodeHash); err != nil { + return sdkerrors.Wrap(types.ErrUnpinContractFailed, err.Error()) + } + + store := ctx.KVStore(k.storeKey) + store.Delete(types.GetPinnedCodeIndexPrefix(codeID)) + return nil +} + +// IsPinnedCode returns true when codeID is pinned in wasmvm cache +func (k Keeper) IsPinnedCode(ctx sdk.Context, codeID uint64) bool { + store := ctx.KVStore(k.storeKey) + return store.Has(types.GetPinnedCodeIndexPrefix(codeID)) +} + +// InitializePinnedCodes updates wasmvm to pin to cache all contracts marked as pinned +func (k Keeper) InitializePinnedCodes(ctx sdk.Context) error { + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.PinnedCodeIndexPrefix) + iter := store.Iterator(nil, nil) + for ; iter.Valid(); iter.Next() { + codeInfo := k.GetCodeInfo(ctx, types.ParsePinnedCodeIndex(iter.Value())) + if codeInfo == nil { + return sdkerrors.Wrap(types.ErrNotFound, "code info") + } + if err := k.wasmer.Pin(codeInfo.CodeHash); err != nil { + return sdkerrors.Wrap(types.ErrPinContractFailed, err.Error()) + } + } + return nil +} + func gasForContract(ctx sdk.Context) uint64 { meter := ctx.GasMeter() if meter.IsOutOfGas() { diff --git a/x/wasm/internal/keeper/keeper_test.go b/x/wasm/internal/keeper/keeper_test.go index 8afa6cd3f9..e938302521 100644 --- a/x/wasm/internal/keeper/keeper_test.go +++ b/x/wasm/internal/keeper/keeper_test.go @@ -282,7 +282,7 @@ func TestInstantiate(t *testing.T) { gasAfter := ctx.GasMeter().GasConsumed() if types.EnableGasVerification { - require.Equal(t, uint64(0x118c0), gasAfter-gasBefore) + require.Equal(t, uint64(0x11ca8), gasAfter-gasBefore) } // ensure it is stored properly @@ -515,7 +515,7 @@ func TestExecute(t *testing.T) { // make sure gas is properly deducted from ctx gasAfter := ctx.GasMeter().GasConsumed() if types.EnableGasVerification { - require.Equal(t, uint64(0x11d39), gasAfter-gasBefore) + require.Equal(t, uint64(0x12121), gasAfter-gasBefore) } // ensure bob now exists and got both payments released bobAcct = accKeeper.GetAccount(ctx, bob) diff --git a/x/wasm/internal/keeper/proposal_handler.go b/x/wasm/internal/keeper/proposal_handler.go index 937996e2e4..878c6a9fc9 100644 --- a/x/wasm/internal/keeper/proposal_handler.go +++ b/x/wasm/internal/keeper/proposal_handler.go @@ -2,6 +2,8 @@ package keeper import ( "fmt" + "strconv" + "strings" "github.com/CosmWasm/wasmd/x/wasm/internal/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -9,8 +11,18 @@ import ( govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) +// governing contains a subset of the wasm keeper used by gov processes +type governing interface { + create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte, source string, builder string, instantiateAccess *types.AccessConfig, authZ AuthorizationPolicy) (codeID uint64, err error) + instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.AccAddress, initMsg []byte, label string, deposit sdk.Coins, authZ AuthorizationPolicy) (sdk.AccAddress, []byte, error) + migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller sdk.AccAddress, newCodeID uint64, msg []byte, authZ AuthorizationPolicy) (*sdk.Result, error) + setContractAdmin(ctx sdk.Context, contractAddress, caller, newAdmin sdk.AccAddress, authZ AuthorizationPolicy) error + PinCode(ctx sdk.Context, codeID uint64) error + UnpinCode(ctx sdk.Context, codeID uint64) error +} + // NewWasmProposalHandler creates a new governance Handler for wasm proposals -func NewWasmProposalHandler(k Keeper, enabledProposalTypes []types.ProposalType) govtypes.Handler { +func NewWasmProposalHandler(k governing, enabledProposalTypes []types.ProposalType) govtypes.Handler { enabledTypes := make(map[string]struct{}, len(enabledProposalTypes)) for i := range enabledProposalTypes { enabledTypes[string(enabledProposalTypes[i])] = struct{}{} @@ -33,13 +45,17 @@ func NewWasmProposalHandler(k Keeper, enabledProposalTypes []types.ProposalType) return handleUpdateAdminProposal(ctx, k, *c) case *types.ClearAdminProposal: return handleClearAdminProposal(ctx, k, *c) + case *types.PinCodesProposal: + return handlePinCodesProposal(ctx, k, *c) + case *types.UnpinCodesProposal: + return handleUnpinCodesProposal(ctx, k, *c) default: return sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized wasm proposal content type: %T", c) } } } -func handleStoreCodeProposal(ctx sdk.Context, k Keeper, p types.StoreCodeProposal) error { +func handleStoreCodeProposal(ctx sdk.Context, k governing, p types.StoreCodeProposal) error { if err := p.ValidateBasic(); err != nil { return err } @@ -62,7 +78,7 @@ func handleStoreCodeProposal(ctx sdk.Context, k Keeper, p types.StoreCodeProposa return nil } -func handleInstantiateProposal(ctx sdk.Context, k Keeper, p types.InstantiateContractProposal) error { +func handleInstantiateProposal(ctx sdk.Context, k governing, p types.InstantiateContractProposal) error { if err := p.ValidateBasic(); err != nil { return err } @@ -90,7 +106,7 @@ func handleInstantiateProposal(ctx sdk.Context, k Keeper, p types.InstantiateCon return nil } -func handleMigrateProposal(ctx sdk.Context, k Keeper, p types.MigrateContractProposal) error { +func handleMigrateProposal(ctx sdk.Context, k governing, p types.MigrateContractProposal) error { if err := p.ValidateBasic(); err != nil { return err } @@ -125,7 +141,7 @@ func handleMigrateProposal(ctx sdk.Context, k Keeper, p types.MigrateContractPro return nil } -func handleUpdateAdminProposal(ctx sdk.Context, k Keeper, p types.UpdateAdminProposal) error { +func handleUpdateAdminProposal(ctx sdk.Context, k governing, p types.UpdateAdminProposal) error { if err := p.ValidateBasic(); err != nil { return err } @@ -151,7 +167,7 @@ func handleUpdateAdminProposal(ctx sdk.Context, k Keeper, p types.UpdateAdminPro return nil } -func handleClearAdminProposal(ctx sdk.Context, k Keeper, p types.ClearAdminProposal) error { +func handleClearAdminProposal(ctx sdk.Context, k governing, p types.ClearAdminProposal) error { if err := p.ValidateBasic(); err != nil { return err } @@ -171,3 +187,49 @@ func handleClearAdminProposal(ctx sdk.Context, k Keeper, p types.ClearAdminPropo ctx.EventManager().EmitEvent(ourEvent) return nil } + +func handlePinCodesProposal(ctx sdk.Context, k governing, p types.PinCodesProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + for _, v := range p.CodeIDs { + if err := k.PinCode(ctx, v); err != nil { + return sdkerrors.Wrapf(err, "code id: %d", v) + } + } + s := make([]string, len(p.CodeIDs)) + for i, v := range p.CodeIDs { + s[i] = strconv.FormatUint(v, 10) + } + ourEvent := sdk.NewEvent( + types.EventTypePinCode, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyCodeIDs, strings.Join(s, ",")), + ) + ctx.EventManager().EmitEvent(ourEvent) + + return nil +} + +func handleUnpinCodesProposal(ctx sdk.Context, k governing, p types.UnpinCodesProposal) error { + if err := p.ValidateBasic(); err != nil { + return err + } + for _, v := range p.CodeIDs { + if err := k.UnpinCode(ctx, v); err != nil { + return sdkerrors.Wrapf(err, "code id: %d", v) + } + } + s := make([]string, len(p.CodeIDs)) + for i, v := range p.CodeIDs { + s[i] = strconv.FormatUint(v, 10) + } + ourEvent := sdk.NewEvent( + types.EventTypeUnpinCode, + sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), + sdk.NewAttribute(types.AttributeKeyCodeIDs, strings.Join(s, ",")), + ) + ctx.EventManager().EmitEvent(ourEvent) + + return nil +} diff --git a/x/wasm/internal/keeper/proposal_integration_test.go b/x/wasm/internal/keeper/proposal_integration_test.go index 95f4105198..0807feee41 100644 --- a/x/wasm/internal/keeper/proposal_integration_test.go +++ b/x/wasm/internal/keeper/proposal_integration_test.go @@ -4,6 +4,9 @@ import ( "bytes" "encoding/hex" "encoding/json" + "errors" + "github.com/CosmWasm/wasmd/x/wasm/internal/keeper/wasmtesting" + wasmvm "github.com/CosmWasm/wasmvm" "io/ioutil" "testing" @@ -346,3 +349,178 @@ func TestUpdateParamsProposal(t *testing.T) { }) } } + +func TestPinCodesProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking", nil, nil) + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + + mock := wasmtesting.MockWasmer{ + CreateFn: wasmtesting.NoOpCreateFn, + AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn, + } + var ( + hackatom = StoreHackatomExampleContract(t, ctx, keepers) + hackatomDuplicate = StoreHackatomExampleContract(t, ctx, keepers) + otherContract = StoreRandomContract(t, ctx, keepers, &mock) + gotPinnedChecksums []wasmvm.Checksum + ) + checksumCollector := func(checksum wasmvm.Checksum) error { + gotPinnedChecksums = append(gotPinnedChecksums, checksum) + return nil + } + specs := map[string]struct { + srcCodeIDs []uint64 + mockFn func(checksum wasmvm.Checksum) error + expPinned []wasmvm.Checksum + expErr bool + }{ + "pin one": { + srcCodeIDs: []uint64{hackatom.CodeID}, + mockFn: checksumCollector, + }, + "pin multiple": { + srcCodeIDs: []uint64{hackatom.CodeID, otherContract.CodeID}, + mockFn: checksumCollector, + }, + "pin same code id": { + srcCodeIDs: []uint64{hackatom.CodeID, hackatomDuplicate.CodeID}, + mockFn: checksumCollector, + }, + "pin non existing code id": { + srcCodeIDs: []uint64{999}, + mockFn: checksumCollector, + expErr: true, + }, + "pin empty code id list": { + srcCodeIDs: []uint64{}, + mockFn: checksumCollector, + expErr: true, + }, + "wasmvm failed with error": { + srcCodeIDs: []uint64{hackatom.CodeID}, + mockFn: func(_ wasmvm.Checksum) error { + return errors.New("test, ignore") + }, + expErr: true, + }, + } + parentCtx := ctx + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + gotPinnedChecksums = nil + ctx, _ := parentCtx.CacheContext() + mock.PinFn = spec.mockFn + proposal := types.PinCodesProposal{ + Title: "Foo", + Description: "Bar", + CodeIDs: spec.srcCodeIDs, + } + + // when stored + storedProposal, gotErr := govKeeper.SubmitProposal(ctx, &proposal) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + gotErr = handler(ctx, storedProposal.GetContent()) + require.NoError(t, gotErr) + + // then + for i := range spec.srcCodeIDs { + c := wasmKeeper.GetCodeInfo(ctx, spec.srcCodeIDs[i]) + require.Equal(t, wasmvm.Checksum(c.CodeHash), gotPinnedChecksums[i]) + } + }) + } +} +func TestUnpinCodesProposal(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, "staking", nil, nil) + govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper + + mock := wasmtesting.MockWasmer{ + CreateFn: wasmtesting.NoOpCreateFn, + AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn, + } + var ( + hackatom = StoreHackatomExampleContract(t, ctx, keepers) + hackatomDuplicate = StoreHackatomExampleContract(t, ctx, keepers) + otherContract = StoreRandomContract(t, ctx, keepers, &mock) + gotUnpinnedChecksums []wasmvm.Checksum + ) + checksumCollector := func(checksum wasmvm.Checksum) error { + gotUnpinnedChecksums = append(gotUnpinnedChecksums, checksum) + return nil + } + specs := map[string]struct { + srcCodeIDs []uint64 + mockFn func(checksum wasmvm.Checksum) error + expUnpinned []wasmvm.Checksum + expErr bool + }{ + "unpin one": { + srcCodeIDs: []uint64{hackatom.CodeID}, + mockFn: checksumCollector, + }, + "unpin multiple": { + srcCodeIDs: []uint64{hackatom.CodeID, otherContract.CodeID}, + mockFn: checksumCollector, + }, + "unpin same code id": { + srcCodeIDs: []uint64{hackatom.CodeID, hackatomDuplicate.CodeID}, + mockFn: checksumCollector, + }, + "unpin non existing code id": { + srcCodeIDs: []uint64{999}, + mockFn: checksumCollector, + expErr: true, + }, + "unpin empty code id list": { + srcCodeIDs: []uint64{}, + mockFn: checksumCollector, + expErr: true, + }, + "wasmvm failed with error": { + srcCodeIDs: []uint64{hackatom.CodeID}, + mockFn: func(_ wasmvm.Checksum) error { + return errors.New("test, ignore") + }, + expErr: true, + }, + } + parentCtx := ctx + for msg, spec := range specs { + t.Run(msg, func(t *testing.T) { + gotUnpinnedChecksums = nil + ctx, _ := parentCtx.CacheContext() + mock.UnpinFn = spec.mockFn + proposal := types.UnpinCodesProposal{ + Title: "Foo", + Description: "Bar", + CodeIDs: spec.srcCodeIDs, + } + + // when stored + storedProposal, gotErr := govKeeper.SubmitProposal(ctx, &proposal) + if spec.expErr { + require.Error(t, gotErr) + return + } + require.NoError(t, gotErr) + + // and proposal execute + handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) + gotErr = handler(ctx, storedProposal.GetContent()) + require.NoError(t, gotErr) + + // then + for i := range spec.srcCodeIDs { + c := wasmKeeper.GetCodeInfo(ctx, spec.srcCodeIDs[i]) + require.Equal(t, wasmvm.Checksum(c.CodeHash), gotUnpinnedChecksums[i]) + } + }) + } +} diff --git a/x/wasm/internal/keeper/recurse_test.go b/x/wasm/internal/keeper/recurse_test.go index 5a45725a06..01fd965568 100644 --- a/x/wasm/internal/keeper/recurse_test.go +++ b/x/wasm/internal/keeper/recurse_test.go @@ -57,9 +57,9 @@ func initRecurseContract(t *testing.T) (contract sdk.AccAddress, creator sdk.Acc func TestGasCostOnQuery(t *testing.T) { const ( - GasNoWork uint64 = 43_074 + GasNoWork uint64 = 44_074 // Note: about 100 SDK gas (10k wasmer gas) for each round of sha256 - GasWork50 uint64 = 48_744 // this is a little shy of 50k gas - to keep an eye on the limit + GasWork50 uint64 = 49_744 // this is a little shy of 50k gas - to keep an eye on the limit GasReturnUnhashed uint64 = 287 GasReturnHashed uint64 = 262 @@ -224,7 +224,7 @@ func TestLimitRecursiveQueryGas(t *testing.T) { const ( // Note: about 100 SDK gas (10k wasmer gas) for each round of sha256 - GasWork2k uint64 = 271_797 // = InstanceCost + x // we have 6x gas used in cpu than in the instance + GasWork2k uint64 = 272_797 // = InstanceCost + x // we have 6x gas used in cpu than in the instance // This is overhead for calling into a sub-contract GasReturnHashed uint64 = 265 ) diff --git a/x/wasm/internal/keeper/test_common.go b/x/wasm/internal/keeper/test_common.go index 712e32f532..3f04f7caef 100644 --- a/x/wasm/internal/keeper/test_common.go +++ b/x/wasm/internal/keeper/test_common.go @@ -4,11 +4,6 @@ import ( "encoding/binary" "encoding/json" "fmt" - "github.com/tendermint/tendermint/libs/rand" - "io/ioutil" - "testing" - "time" - "github.com/CosmWasm/wasmd/x/wasm/internal/types" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/codec" @@ -40,7 +35,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" - transfer "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer" + "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer" ibctransfertypes "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer/types" ibc "github.com/cosmos/cosmos-sdk/x/ibc/core" ibchost "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host" @@ -63,10 +58,20 @@ import ( "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto/ed25519" "github.com/tendermint/tendermint/libs/log" + "github.com/tendermint/tendermint/libs/rand" tmproto "github.com/tendermint/tendermint/proto/tendermint/types" dbm "github.com/tendermint/tm-db" + "io/ioutil" + "time" ) +type TestingT interface { + Errorf(format string, args ...interface{}) + FailNow() + TempDir() string + Helper() +} + var ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, bank.AppModuleBasic{}, @@ -86,11 +91,11 @@ var ModuleBasics = module.NewBasicManager( transfer.AppModuleBasic{}, ) -func MakeTestCodec(t *testing.T) codec.Marshaler { +func MakeTestCodec(t TestingT) codec.Marshaler { return MakeEncodingConfig(t).Marshaler } -func MakeEncodingConfig(_ *testing.T) params2.EncodingConfig { +func MakeEncodingConfig(_ TestingT) params2.EncodingConfig { amino := codec.NewLegacyAmino() interfaceRegistry := codectypes.NewInterfaceRegistry() marshaler := codec.NewProtoCodec(interfaceRegistry) @@ -128,12 +133,28 @@ type TestKeepers struct { } // CreateDefaultTestInput common settings for CreateTestInput -func CreateDefaultTestInput(t *testing.T) (sdk.Context, TestKeepers) { +func CreateDefaultTestInput(t TestingT) (sdk.Context, TestKeepers) { return CreateTestInput(t, false, "staking", nil, nil) } // encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default) -func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, encoders *MessageEncoders, queriers *QueryPlugins) (sdk.Context, TestKeepers) { +func CreateTestInput(t TestingT, isCheckTx bool, supportedFeatures string, encoders *MessageEncoders, queriers *QueryPlugins) (sdk.Context, TestKeepers) { + // Load default wasm config + wasmConfig := types.DefaultWasmConfig() + db := dbm.NewMemDB() + return createTestInput(t, isCheckTx, supportedFeatures, encoders, queriers, wasmConfig, db) +} + +// encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default) +func createTestInput( + t TestingT, + isCheckTx bool, + supportedFeatures string, + encoders *MessageEncoders, + queriers *QueryPlugins, + wasmConfig types.WasmConfig, + db dbm.DB, +) (sdk.Context, TestKeepers) { tempDir := t.TempDir() keyWasm := sdk.NewKVStoreKey(types.StoreKey) @@ -148,7 +169,6 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc keyCapability := sdk.NewKVStoreKey(capabilitytypes.StoreKey) keyCapabilityTransient := storetypes.NewMemoryStoreKey(capabilitytypes.MemStoreKey) - db := dbm.NewMemDB() ms := store.NewCommitMultiStore(db) ms.MountStoreWithDB(keyWasm, sdk.StoreTypeIAVL, db) ms.MountStoreWithDB(keyAcc, sdk.StoreTypeIAVL, db) @@ -260,9 +280,6 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc stakingtypes.RegisterQueryServer(querier, stakingkeeper.Querier{Keeper: stakingKeeper}) distributiontypes.RegisterQueryServer(querier, distKeeper) - // Load default wasm config - wasmConfig := types.DefaultWasmConfig() - keeper := NewKeeper( appCodec, keyWasm, @@ -290,7 +307,7 @@ func CreateTestInput(t *testing.T, isCheckTx bool, supportedFeatures string, enc AddRoute(govtypes.RouterKey, govtypes.ProposalHandler). AddRoute(paramproposal.RouterKey, params.NewParamChangeProposalHandler(paramsKeeper)). AddRoute(distributiontypes.RouterKey, distribution.NewCommunityPoolSpendProposalHandler(distKeeper)). - AddRoute(types.RouterKey, NewWasmProposalHandler(keeper, types.EnableAllProposals)) + AddRoute(types.RouterKey, NewWasmProposalHandler(&keeper, types.EnableAllProposals)) govKeeper := govkeeper.NewKeeper( appCodec, keyGov, paramsKeeper.Subspace(govtypes.ModuleName).WithKeyTable(govtypes.ParamKeyTable()), authKeeper, bankKeeper, stakingKeeper, govRouter, @@ -388,12 +405,12 @@ func handleExecute(ctx sdk.Context, k *Keeper, msg *types.MsgExecuteContract) (* return res, nil } -func RandomAccountAddress(_ *testing.T) sdk.AccAddress { +func RandomAccountAddress(_ TestingT) sdk.AccAddress { _, _, addr := keyPubAddr() return addr } -func RandomBech32AccountAddress(t *testing.T) string { +func RandomBech32AccountAddress(t TestingT) string { return RandomAccountAddress(t).String() } @@ -404,19 +421,19 @@ type ExampleContract struct { CodeID uint64 } -func StoreHackatomExampleContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) ExampleContract { +func StoreHackatomExampleContract(t TestingT, ctx sdk.Context, keepers TestKeepers) ExampleContract { return StoreExampleContract(t, ctx, keepers, "./testdata/hackatom.wasm") } -func StoreBurnerExampleContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) ExampleContract { +func StoreBurnerExampleContract(t TestingT, ctx sdk.Context, keepers TestKeepers) ExampleContract { return StoreExampleContract(t, ctx, keepers, "./testdata/burner.wasm") } -func StoreIBCReflectContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) ExampleContract { +func StoreIBCReflectContract(t TestingT, ctx sdk.Context, keepers TestKeepers) ExampleContract { return StoreExampleContract(t, ctx, keepers, "./testdata/ibc_reflect.wasm") } -func StoreReflectContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) uint64 { +func StoreReflectContract(t TestingT, ctx sdk.Context, keepers TestKeepers) uint64 { wasmCode, err := ioutil.ReadFile("./testdata/reflect.wasm") require.NoError(t, err) @@ -426,7 +443,7 @@ func StoreReflectContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) ui return codeID } -func StoreExampleContract(t *testing.T, ctx sdk.Context, keepers TestKeepers, wasmFile string) ExampleContract { +func StoreExampleContract(t TestingT, ctx sdk.Context, keepers TestKeepers, wasmFile string) ExampleContract { anyAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)) creator, _, creatorAddr := keyPubAddr() fundAccounts(t, ctx, keepers.AccountKeeper, keepers.BankKeeper, creatorAddr, anyAmount) @@ -447,7 +464,7 @@ type ExampleContractInstance struct { } // SeedNewContractInstance sets the mock wasmerEngine in keeper and calls store + instantiate to init the contract's metadata -func SeedNewContractInstance(t *testing.T, ctx sdk.Context, keepers TestKeepers, mock types.WasmerEngine) ExampleContractInstance { +func SeedNewContractInstance(t TestingT, ctx sdk.Context, keepers TestKeepers, mock types.WasmerEngine) ExampleContractInstance { t.Helper() exampleContract := StoreRandomContract(t, ctx, keepers, mock) contractAddr, _, err := keepers.WasmKeeper.Instantiate(ctx, exampleContract.CodeID, exampleContract.CreatorAddr, exampleContract.CreatorAddr, []byte(`{}`), "", nil) @@ -459,7 +476,7 @@ func SeedNewContractInstance(t *testing.T, ctx sdk.Context, keepers TestKeepers, } // StoreRandomContract sets the mock wasmerEngine in keeper and calls store -func StoreRandomContract(t *testing.T, ctx sdk.Context, keepers TestKeepers, mock types.WasmerEngine) ExampleContract { +func StoreRandomContract(t TestingT, ctx sdk.Context, keepers TestKeepers, mock types.WasmerEngine) ExampleContract { t.Helper() anyAmount := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000)) creator, _, creatorAddr := keyPubAddr() @@ -482,7 +499,7 @@ type HackatomExampleInstance struct { } // InstantiateHackatomExampleContract load and instantiate the "./testdata/hackatom.wasm" contract -func InstantiateHackatomExampleContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) HackatomExampleInstance { +func InstantiateHackatomExampleContract(t TestingT, ctx sdk.Context, keepers TestKeepers) HackatomExampleInstance { contract := StoreHackatomExampleContract(t, ctx, keepers) verifier, _, verifierAddr := keyPubAddr() @@ -513,7 +530,7 @@ type HackatomExampleInitMsg struct { Beneficiary sdk.AccAddress `json:"beneficiary"` } -func (m HackatomExampleInitMsg) GetBytes(t *testing.T) []byte { +func (m HackatomExampleInitMsg) GetBytes(t TestingT) []byte { initMsgBz, err := json.Marshal(m) require.NoError(t, err) return initMsgBz @@ -527,7 +544,7 @@ type IBCReflectExampleInstance struct { } // InstantiateIBCReflectContract load and instantiate the "./testdata/ibc_reflect.wasm" contract -func InstantiateIBCReflectContract(t *testing.T, ctx sdk.Context, keepers TestKeepers) IBCReflectExampleInstance { +func InstantiateIBCReflectContract(t TestingT, ctx sdk.Context, keepers TestKeepers) IBCReflectExampleInstance { reflectID := StoreReflectContract(t, ctx, keepers) ibcReflectID := StoreIBCReflectContract(t, ctx, keepers).CodeID @@ -550,7 +567,7 @@ type IBCReflectInitMsg struct { ReflectCodeID uint64 `json:"reflect_code_id"` } -func (m IBCReflectInitMsg) GetBytes(t *testing.T) []byte { +func (m IBCReflectInitMsg) GetBytes(t TestingT) []byte { initMsgBz, err := json.Marshal(m) require.NoError(t, err) return initMsgBz @@ -560,19 +577,19 @@ type BurnerExampleInitMsg struct { Payout sdk.AccAddress `json:"payout"` } -func (m BurnerExampleInitMsg) GetBytes(t *testing.T) []byte { +func (m BurnerExampleInitMsg) GetBytes(t TestingT) []byte { initMsgBz, err := json.Marshal(m) require.NoError(t, err) return initMsgBz } -func createFakeFundedAccount(t *testing.T, ctx sdk.Context, am authkeeper.AccountKeeper, bank bankkeeper.Keeper, coins sdk.Coins) sdk.AccAddress { +func createFakeFundedAccount(t TestingT, ctx sdk.Context, am authkeeper.AccountKeeper, bank bankkeeper.Keeper, coins sdk.Coins) sdk.AccAddress { _, _, addr := keyPubAddr() fundAccounts(t, ctx, am, bank, addr, coins) return addr } -func fundAccounts(t *testing.T, ctx sdk.Context, am authkeeper.AccountKeeper, bank bankkeeper.Keeper, addr sdk.AccAddress, coins sdk.Coins) { +func fundAccounts(t TestingT, ctx sdk.Context, am authkeeper.AccountKeeper, bank bankkeeper.Keeper, addr sdk.AccAddress, coins sdk.Coins) { acc := am.NewAccountWithAddress(ctx, addr) am.SetAccount(ctx, acc) require.NoError(t, bank.SetBalances(ctx, addr, coins)) diff --git a/x/wasm/internal/keeper/wasmtesting/mock_engine.go b/x/wasm/internal/keeper/wasmtesting/mock_engine.go index 9af8f45794..c2da0fa419 100644 --- a/x/wasm/internal/keeper/wasmtesting/mock_engine.go +++ b/x/wasm/internal/keeper/wasmtesting/mock_engine.go @@ -30,6 +30,8 @@ type MockWasmer struct { IBCPacketReceiveFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCReceiveResponse, uint64, error) IBCPacketAckFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, ack wasmvmtypes.IBCAcknowledgement, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) IBCPacketTimeoutFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, packet wasmvmtypes.IBCPacket, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (*wasmvmtypes.IBCBasicResponse, uint64, error) + PinFn func(checksum wasmvm.Checksum) error + UnpinFn func(checksum wasmvm.Checksum) error } func (m *MockWasmer) IBCChannelOpen(codeID wasmvm.Checksum, env wasmvmtypes.Env, channel wasmvmtypes.IBCChannel, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64) (uint64, error) { @@ -138,6 +140,20 @@ func (m *MockWasmer) Cleanup() { m.CleanupFn() } +func (m *MockWasmer) Pin(checksum wasmvm.Checksum) error { + if m.PinFn == nil { + panic("not supposed to be called!") + } + return m.PinFn(checksum) +} + +func (m *MockWasmer) Unpin(checksum wasmvm.Checksum) error { + if m.UnpinFn == nil { + panic("not supposed to be called!") + } + return m.UnpinFn(checksum) +} + var AlwaysPanicMockWasmer = &MockWasmer{} // selfCallingInstMockWasmer prepares a Wasmer mock that calls itself on instantiation. diff --git a/x/wasm/internal/types/codec.go b/x/wasm/internal/types/codec.go index 1ea87a299a..edfe0ab3ab 100644 --- a/x/wasm/internal/types/codec.go +++ b/x/wasm/internal/types/codec.go @@ -17,6 +17,8 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgMigrateContract{}, "wasm/MsgMigrateContract", nil) cdc.RegisterConcrete(&MsgUpdateAdmin{}, "wasm/MsgUpdateAdmin", nil) cdc.RegisterConcrete(&MsgClearAdmin{}, "wasm/MsgClearAdmin", nil) + cdc.RegisterConcrete(&PinCodesProposal{}, "wasm/PinCodesProposal", nil) + cdc.RegisterConcrete(&UnpinCodesProposal{}, "wasm/UnpinCodesProposal", nil) cdc.RegisterConcrete(&StoreCodeProposal{}, "wasm/StoreCodeProposal", nil) cdc.RegisterConcrete(&InstantiateContractProposal{}, "wasm/InstantiateContractProposal", nil) @@ -44,6 +46,8 @@ func RegisterInterfaces(registry types.InterfaceRegistry) { &MigrateContractProposal{}, &UpdateAdminProposal{}, &ClearAdminProposal{}, + &PinCodesProposal{}, + &UnpinCodesProposal{}, ) msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) diff --git a/x/wasm/internal/types/errors.go b/x/wasm/internal/types/errors.go index 5de0725ee1..5e8799913f 100644 --- a/x/wasm/internal/types/errors.go +++ b/x/wasm/internal/types/errors.go @@ -57,4 +57,10 @@ var ( // ErrUnsupportedForContract error when a feature is used that is not supported for/ by this contract ErrUnsupportedForContract = sdkErrors.Register(DefaultCodespace, 17, "unsupported for this contract") + + // ErrPinContractFailed error for pinning contract failures + ErrPinContractFailed = sdkErrors.Register(DefaultCodespace, 18, "pinning contract failed") + + // ErrUnpinContractFailed error for unpinning contract failures + ErrUnpinContractFailed = sdkErrors.Register(DefaultCodespace, 19, "unpinning contract failed") ) diff --git a/x/wasm/internal/types/events.go b/x/wasm/internal/types/events.go new file mode 100644 index 0000000000..2f48e5847c --- /dev/null +++ b/x/wasm/internal/types/events.go @@ -0,0 +1,12 @@ +package types + +const ( + EventTypePinCode = "pin_code" + EventTypeUnpinCode = "unpin_code" +) +const ( // event attributes + AttributeKeyContract = "contract_address" + AttributeKeyCodeID = "code_id" + AttributeKeyCodeIDs = "code_ids" + AttributeKeySigner = "signer" +) diff --git a/x/wasm/internal/types/genesis.pb.go b/x/wasm/internal/types/genesis.pb.go index 067c8e5a64..25cd5d06d2 100644 --- a/x/wasm/internal/types/genesis.pb.go +++ b/x/wasm/internal/types/genesis.pb.go @@ -207,6 +207,8 @@ type Code struct { CodeID uint64 `protobuf:"varint,1,opt,name=code_id,json=codeId,proto3" json:"code_id,omitempty"` CodeInfo CodeInfo `protobuf:"bytes,2,opt,name=code_info,json=codeInfo,proto3" json:"code_info"` CodeBytes []byte `protobuf:"bytes,3,opt,name=code_bytes,json=codeBytes,proto3" json:"code_bytes,omitempty"` + // Pinned to wasmvm cache + Pinned bool `protobuf:"varint,4,opt,name=pinned,proto3" json:"pinned,omitempty"` } func (m *Code) Reset() { *m = Code{} } @@ -263,6 +265,13 @@ func (m *Code) GetCodeBytes() []byte { return nil } +func (m *Code) GetPinned() bool { + if m != nil { + return m.Pinned + } + return false +} + // Contract struct encompasses ContractAddress, ContractInfo, and ContractState type Contract struct { ContractAddress string `protobuf:"bytes,1,opt,name=contract_address,json=contractAddress,proto3" json:"contract_address,omitempty"` @@ -390,47 +399,48 @@ func init() { } var fileDescriptor_52f9f2715025dba8 = []byte{ - // 638 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x94, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0x86, 0xe3, 0x26, 0x4e, 0x93, 0x69, 0xa0, 0xd5, 0xb6, 0x88, 0x28, 0xa5, 0x4e, 0x49, 0x2e, - 0xad, 0x80, 0x98, 0x96, 0x23, 0x27, 0xdc, 0x22, 0x9a, 0x56, 0x45, 0xc8, 0x95, 0x40, 0xea, 0x25, - 0x72, 0xec, 0xa9, 0xb1, 0xa8, 0xbd, 0x21, 0xbb, 0x29, 0xf1, 0x4b, 0x20, 0xc4, 0x53, 0xf5, 0xd8, - 0x23, 0xa7, 0x08, 0xa5, 0x37, 0x9e, 0x02, 0xed, 0x7a, 0xed, 0xba, 0xa2, 0x2e, 0x17, 0x27, 0x33, - 0xfb, 0xcf, 0xb7, 0x33, 0xb3, 0xb3, 0x0b, 0xdd, 0xa9, 0xf9, 0xcd, 0x61, 0xa1, 0x19, 0x44, 0x1c, - 0xc7, 0x91, 0x73, 0x6e, 0xf2, 0x78, 0x84, 0xcc, 0xf4, 0x31, 0x42, 0x16, 0xb0, 0xde, 0x68, 0x4c, - 0x39, 0x25, 0x8f, 0x5c, 0xca, 0x42, 0x21, 0xeb, 0xc9, 0xcf, 0xc5, 0xce, 0x10, 0xb9, 0xb3, 0xd3, - 0x5a, 0xf3, 0xa9, 0x4f, 0xa5, 0xc2, 0x14, 0xff, 0x12, 0x71, 0xeb, 0xe9, 0xdd, 0x44, 0xf9, 0x55, - 0x12, 0xa3, 0x40, 0x32, 0x4d, 0xd6, 0x3b, 0x97, 0x3a, 0x34, 0xde, 0x25, 0x19, 0x9c, 0x70, 0x87, - 0x23, 0x79, 0x0d, 0xd5, 0x91, 0x33, 0x76, 0x42, 0xd6, 0xd4, 0x36, 0xb5, 0xad, 0xa5, 0xdd, 0x8d, - 0xde, 0x9d, 0x19, 0xf5, 0x3e, 0x48, 0x91, 0x55, 0xb9, 0x9c, 0xb5, 0x4b, 0xb6, 0x0a, 0x21, 0x87, - 0xa0, 0xbb, 0xd4, 0x43, 0xd6, 0x5c, 0xd8, 0x2c, 0x6f, 0x2d, 0xed, 0xae, 0x17, 0xc4, 0xee, 0x51, - 0x0f, 0xad, 0xc7, 0x22, 0xf2, 0xcf, 0xac, 0xbd, 0x2c, 0x23, 0x9e, 0xd3, 0x30, 0xe0, 0x18, 0x8e, - 0x78, 0x6c, 0x27, 0x08, 0x72, 0x0a, 0x75, 0x97, 0x46, 0x7c, 0xec, 0xb8, 0x9c, 0x35, 0xcb, 0x92, - 0xd7, 0x2e, 0xe4, 0x25, 0x3a, 0x6b, 0x5d, 0x31, 0x57, 0xb3, 0xc8, 0x1c, 0xf7, 0x06, 0x27, 0xd8, - 0x0c, 0xbf, 0x4e, 0x30, 0x72, 0x91, 0x35, 0x2b, 0xf7, 0xb2, 0x4f, 0x94, 0xee, 0x86, 0x9d, 0x45, - 0xe6, 0xd9, 0x99, 0x93, 0x0c, 0xa1, 0xe6, 0x63, 0x34, 0x08, 0x99, 0xcf, 0x9a, 0xba, 0x44, 0x3f, - 0x2b, 0x40, 0xe7, 0xfb, 0x2e, 0x8c, 0x63, 0xe6, 0x33, 0xab, 0xa5, 0xb6, 0x21, 0x29, 0x24, 0xb7, - 0xcb, 0xa2, 0x9f, 0x88, 0x5a, 0x3f, 0x17, 0x60, 0x51, 0x05, 0x90, 0x7d, 0x00, 0xc6, 0xe9, 0x18, - 0x07, 0xa2, 0x6d, 0xea, 0xd0, 0xba, 0x05, 0x3b, 0x1e, 0x33, 0xff, 0x44, 0x68, 0xc5, 0x01, 0x1c, - 0x94, 0xec, 0x3a, 0x4b, 0x0d, 0x32, 0x84, 0xb5, 0x20, 0x62, 0xdc, 0x89, 0x78, 0xe0, 0x70, 0xc1, - 0x4a, 0x5a, 0xd5, 0x5c, 0x90, 0xbc, 0x17, 0xc5, 0xbc, 0xfe, 0x4d, 0x54, 0x7a, 0x0c, 0x07, 0x25, - 0x7b, 0x35, 0xf8, 0xd7, 0x4d, 0x3e, 0xc2, 0x0a, 0x4e, 0xd1, 0x9d, 0xe4, 0xf9, 0x65, 0xc9, 0xdf, - 0x2e, 0xe6, 0xbf, 0x4d, 0x22, 0x72, 0xec, 0x65, 0xbc, 0xed, 0xb2, 0x74, 0x28, 0xb3, 0x49, 0xd8, - 0xf9, 0xae, 0x41, 0x45, 0xd6, 0xd2, 0x85, 0x45, 0xd1, 0x8b, 0x41, 0xe0, 0xc9, 0x76, 0x54, 0x2c, - 0x98, 0xcf, 0xda, 0x55, 0xb1, 0xd4, 0xdf, 0xb7, 0xab, 0x62, 0xa9, 0xef, 0x11, 0x4b, 0x8c, 0x97, - 0x10, 0x45, 0x67, 0x54, 0x55, 0xd9, 0xbe, 0x67, 0x5c, 0xfb, 0xd1, 0x19, 0x55, 0xc3, 0x5e, 0x73, - 0x95, 0x4d, 0x36, 0x00, 0x24, 0x63, 0x18, 0x73, 0x64, 0xb2, 0x94, 0x86, 0x2d, 0xa9, 0x96, 0x70, - 0x74, 0xae, 0x34, 0xa8, 0x65, 0xc5, 0x6f, 0xc3, 0x4a, 0x5a, 0xf4, 0xc0, 0xf1, 0xbc, 0x31, 0xb2, - 0xe4, 0x86, 0xd5, 0xed, 0xe5, 0xd4, 0xff, 0x26, 0x71, 0x93, 0xf7, 0xf0, 0x20, 0x93, 0xe6, 0xd2, - 0xeb, 0xfe, 0x67, 0xfa, 0x73, 0x29, 0x36, 0xdc, 0x9c, 0x8f, 0xf4, 0xe1, 0x61, 0xc6, 0x63, 0x62, - 0xd8, 0xd4, 0x75, 0x7a, 0x52, 0xd4, 0x75, 0xea, 0xe1, 0xb9, 0x22, 0x65, 0x99, 0xc8, 0x29, 0xed, - 0x58, 0x50, 0x4b, 0x2f, 0x04, 0xd9, 0x84, 0x6a, 0xe0, 0x0d, 0xbe, 0x60, 0x2c, 0xeb, 0x68, 0x58, - 0xf5, 0xf9, 0xac, 0xad, 0xf7, 0xf7, 0x8f, 0x30, 0xb6, 0xf5, 0xc0, 0x3b, 0xc2, 0x98, 0xac, 0x81, - 0x7e, 0xe1, 0x9c, 0x4f, 0x50, 0x16, 0x50, 0xb1, 0x13, 0xc3, 0x3a, 0xbc, 0x9c, 0x1b, 0xda, 0xd5, - 0xdc, 0xd0, 0x7e, 0xcf, 0x0d, 0xed, 0xc7, 0xb5, 0x51, 0xba, 0xba, 0x36, 0x4a, 0xbf, 0xae, 0x8d, - 0xd2, 0xe9, 0x4b, 0x3f, 0xe0, 0x9f, 0x27, 0xc3, 0x9e, 0x4b, 0x43, 0x73, 0x8f, 0xb2, 0xf0, 0x93, - 0x78, 0xb9, 0x44, 0x6a, 0x9e, 0x39, 0x55, 0xbf, 0xb7, 0xdf, 0xb1, 0x61, 0x55, 0xbe, 0x62, 0xaf, - 0xfe, 0x06, 0x00, 0x00, 0xff, 0xff, 0x65, 0x4f, 0x62, 0x92, 0x5c, 0x05, 0x00, 0x00, + // 656 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x84, 0x94, 0xc1, 0x6e, 0xd3, 0x4c, + 0x10, 0xc7, 0xe3, 0x26, 0x4e, 0x93, 0x69, 0xbe, 0xaf, 0xd5, 0xb6, 0x80, 0x95, 0x52, 0x27, 0x24, + 0x97, 0x56, 0x40, 0x4c, 0xcb, 0x91, 0x13, 0x6e, 0x11, 0x4d, 0xab, 0x22, 0xe4, 0x4a, 0x20, 0xf5, + 0x12, 0x39, 0xf6, 0xd4, 0x58, 0xd4, 0xde, 0x90, 0xdd, 0x94, 0xe4, 0x2d, 0x10, 0x0f, 0xc1, 0xb3, + 0xf4, 0xd8, 0x23, 0xa7, 0x08, 0xa5, 0x37, 0x9e, 0x02, 0xed, 0x7a, 0xe3, 0xb8, 0xa2, 0x2e, 0x17, + 0x27, 0x33, 0xfb, 0x9f, 0xdf, 0xce, 0xcc, 0xce, 0x2e, 0xb4, 0xc7, 0xd6, 0x57, 0x97, 0x45, 0x56, + 0x18, 0x73, 0x1c, 0xc6, 0xee, 0x85, 0xc5, 0x27, 0x03, 0x64, 0x56, 0x80, 0x31, 0xb2, 0x90, 0x75, + 0x06, 0x43, 0xca, 0x29, 0x79, 0xe0, 0x51, 0x16, 0x09, 0x59, 0x47, 0x7e, 0x2e, 0x77, 0xfb, 0xc8, + 0xdd, 0xdd, 0xfa, 0x46, 0x40, 0x03, 0x2a, 0x15, 0x96, 0xf8, 0x97, 0x88, 0xeb, 0x4f, 0xee, 0x26, + 0xca, 0xaf, 0x92, 0x98, 0x39, 0x92, 0x71, 0xb2, 0xde, 0xba, 0xd2, 0xa1, 0xf6, 0x36, 0xc9, 0xe0, + 0x94, 0xbb, 0x1c, 0xc9, 0x2b, 0x28, 0x0f, 0xdc, 0xa1, 0x1b, 0x31, 0x43, 0x6b, 0x6a, 0xdb, 0x2b, + 0x7b, 0x5b, 0x9d, 0x3b, 0x33, 0xea, 0xbc, 0x97, 0x22, 0xbb, 0x74, 0x35, 0x6d, 0x14, 0x1c, 0x15, + 0x42, 0x8e, 0x40, 0xf7, 0xa8, 0x8f, 0xcc, 0x58, 0x6a, 0x16, 0xb7, 0x57, 0xf6, 0x36, 0x73, 0x62, + 0xf7, 0xa9, 0x8f, 0xf6, 0x23, 0x11, 0xf9, 0x7b, 0xda, 0x58, 0x95, 0x11, 0xcf, 0x68, 0x14, 0x72, + 0x8c, 0x06, 0x7c, 0xe2, 0x24, 0x08, 0x72, 0x06, 0x55, 0x8f, 0xc6, 0x7c, 0xe8, 0x7a, 0x9c, 0x19, + 0x45, 0xc9, 0x6b, 0xe4, 0xf2, 0x12, 0x9d, 0xbd, 0xa9, 0x98, 0xeb, 0x69, 0x64, 0x86, 0xbb, 0xc0, + 0x09, 0x36, 0xc3, 0x2f, 0x23, 0x8c, 0x3d, 0x64, 0x46, 0xe9, 0x5e, 0xf6, 0xa9, 0xd2, 0x2d, 0xd8, + 0x69, 0x64, 0x96, 0x9d, 0x3a, 0x49, 0x1f, 0x2a, 0x01, 0xc6, 0xbd, 0x88, 0x05, 0xcc, 0xd0, 0x25, + 0xfa, 0x69, 0x0e, 0x3a, 0xdb, 0x77, 0x61, 0x9c, 0xb0, 0x80, 0xd9, 0x75, 0xb5, 0x0d, 0x99, 0x43, + 0x32, 0xbb, 0x2c, 0x07, 0x89, 0xa8, 0xfe, 0x7d, 0x09, 0x96, 0x55, 0x00, 0x39, 0x00, 0x60, 0x9c, + 0x0e, 0xb1, 0x27, 0xda, 0xa6, 0x0e, 0xad, 0x9d, 0xb3, 0xe3, 0x09, 0x0b, 0x4e, 0x85, 0x56, 0x1c, + 0xc0, 0x61, 0xc1, 0xa9, 0xb2, 0xb9, 0x41, 0xfa, 0xb0, 0x11, 0xc6, 0x8c, 0xbb, 0x31, 0x0f, 0x5d, + 0x2e, 0x58, 0x49, 0xab, 0x8c, 0x25, 0xc9, 0x7b, 0x9e, 0xcf, 0xeb, 0x2e, 0xa2, 0xe6, 0xc7, 0x70, + 0x58, 0x70, 0xd6, 0xc3, 0xbf, 0xdd, 0xe4, 0x03, 0xac, 0xe1, 0x18, 0xbd, 0x51, 0x96, 0x5f, 0x94, + 0xfc, 0x9d, 0x7c, 0xfe, 0x9b, 0x24, 0x22, 0xc3, 0x5e, 0xc5, 0xdb, 0x2e, 0x5b, 0x87, 0x22, 0x1b, + 0x45, 0xad, 0x1f, 0x1a, 0x94, 0x64, 0x2d, 0x6d, 0x58, 0x16, 0xbd, 0xe8, 0x85, 0xbe, 0x6c, 0x47, + 0xc9, 0x86, 0xd9, 0xb4, 0x51, 0x16, 0x4b, 0xdd, 0x03, 0xa7, 0x2c, 0x96, 0xba, 0x3e, 0xb1, 0xc5, + 0x78, 0x09, 0x51, 0x7c, 0x4e, 0x55, 0x95, 0x8d, 0x7b, 0xc6, 0xb5, 0x1b, 0x9f, 0x53, 0x35, 0xec, + 0x15, 0x4f, 0xd9, 0x64, 0x0b, 0x40, 0x32, 0xfa, 0x13, 0x8e, 0x4c, 0x96, 0x52, 0x73, 0x24, 0xd5, + 0x16, 0x0e, 0xf2, 0x10, 0xca, 0x83, 0x30, 0x8e, 0xd1, 0x37, 0x4a, 0x4d, 0x6d, 0xbb, 0xe2, 0x28, + 0xab, 0x75, 0xad, 0x41, 0x25, 0x6d, 0xca, 0x0e, 0xac, 0xcd, 0x9b, 0xd1, 0x73, 0x7d, 0x7f, 0x88, + 0x2c, 0xb9, 0x79, 0x55, 0x67, 0x75, 0xee, 0x7f, 0x9d, 0xb8, 0xc9, 0x3b, 0xf8, 0x2f, 0x95, 0x66, + 0xd2, 0x6e, 0xff, 0xe3, 0x56, 0x64, 0x52, 0xaf, 0x79, 0x19, 0x1f, 0xe9, 0xc2, 0xff, 0x29, 0x8f, + 0x89, 0x21, 0x54, 0xd7, 0xec, 0x71, 0xde, 0x69, 0x50, 0x1f, 0x2f, 0x14, 0x29, 0xcd, 0x44, 0x4e, + 0x6f, 0xcb, 0x86, 0xca, 0xfc, 0xa2, 0x90, 0x26, 0x94, 0x43, 0xbf, 0xf7, 0x19, 0x27, 0xb2, 0x8e, + 0x9a, 0x5d, 0x9d, 0x4d, 0x1b, 0x7a, 0xf7, 0xe0, 0x18, 0x27, 0x8e, 0x1e, 0xfa, 0xc7, 0x38, 0x21, + 0x1b, 0xa0, 0x5f, 0xba, 0x17, 0x23, 0x94, 0x05, 0x94, 0x9c, 0xc4, 0xb0, 0x8f, 0xae, 0x66, 0xa6, + 0x76, 0x3d, 0x33, 0xb5, 0x5f, 0x33, 0x53, 0xfb, 0x76, 0x63, 0x16, 0xae, 0x6f, 0xcc, 0xc2, 0xcf, + 0x1b, 0xb3, 0x70, 0xf6, 0x22, 0x08, 0xf9, 0xa7, 0x51, 0xbf, 0xe3, 0xd1, 0xc8, 0xda, 0xa7, 0x2c, + 0xfa, 0x28, 0x5e, 0x34, 0x91, 0x9a, 0x6f, 0x8d, 0xd5, 0xef, 0xed, 0xf7, 0xad, 0x5f, 0x96, 0xaf, + 0xdb, 0xcb, 0x3f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xa3, 0xad, 0xe9, 0xdd, 0x74, 0x05, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -637,6 +647,16 @@ func (m *Code) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.Pinned { + i-- + if m.Pinned { + dAtA[i] = 1 + } else { + dAtA[i] = 0 + } + i-- + dAtA[i] = 0x20 + } if len(m.CodeBytes) > 0 { i -= len(m.CodeBytes) copy(dAtA[i:], m.CodeBytes) @@ -860,6 +880,9 @@ func (m *Code) Size() (n int) { if l > 0 { n += 1 + l + sovGenesis(uint64(l)) } + if m.Pinned { + n += 2 + } return n } @@ -1401,6 +1424,26 @@ func (m *Code) Unmarshal(dAtA []byte) error { m.CodeBytes = []byte{} } iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Pinned", wireType) + } + var v int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.Pinned = bool(v != 0) default: iNdEx = preIndex skippy, err := skipGenesis(dAtA[iNdEx:]) diff --git a/x/wasm/internal/types/genesis.proto b/x/wasm/internal/types/genesis.proto index 1564306278..b7c2df4b45 100644 --- a/x/wasm/internal/types/genesis.proto +++ b/x/wasm/internal/types/genesis.proto @@ -32,6 +32,8 @@ message Code { uint64 code_id = 1 [(gogoproto.customname) = "CodeID"]; CodeInfo code_info = 2 [(gogoproto.nullable) = false]; bytes code_bytes = 3; + // Pinned to wasmvm cache + bool pinned = 4; } // Contract struct encompasses ContractAddress, ContractInfo, and ContractState diff --git a/x/wasm/internal/types/keys.go b/x/wasm/internal/types/keys.go index a92d7465a1..e0415ca0d4 100644 --- a/x/wasm/internal/types/keys.go +++ b/x/wasm/internal/types/keys.go @@ -21,12 +21,6 @@ const ( RouterKey = ModuleName ) -const ( // event attributes - AttributeKeyContract = "contract_address" - AttributeKeyCodeID = "code_id" - AttributeKeySigner = "signer" -) - // nolint var ( CodeKeyPrefix = []byte{0x01} @@ -35,6 +29,7 @@ var ( SequenceKeyPrefix = []byte{0x04} ContractCodeHistoryElementPrefix = []byte{0x05} ContractByCodeIDAndCreatedSecondaryIndexPrefix = []byte{0x06} + PinnedCodeIndexPrefix = []byte{0x07} KeyLastCodeID = append(SequenceKeyPrefix, []byte("lastCodeId")...) KeyLastInstanceID = append(SequenceKeyPrefix, []byte("lastContractId")...) @@ -96,3 +91,17 @@ func GetContractCodeHistoryElementPrefix(contractAddr sdk.AccAddress) []byte { copy(r[prefixLen:], contractAddr) return r } + +// GetPinnedCodeIndexPrefix returns the key prefix for a code id pinned into the wasmvm cache +func GetPinnedCodeIndexPrefix(codeID uint64) []byte { + prefixLen := len(PinnedCodeIndexPrefix) + r := make([]byte, prefixLen+8) + copy(r[0:], PinnedCodeIndexPrefix) + copy(r[prefixLen:], sdk.Uint64ToBigEndian(codeID)) + return r +} + +// ParsePinnedCodeIndex converts the serialized code ID back. +func ParsePinnedCodeIndex(s []byte) uint64 { + return sdk.BigEndianToUint64(s) +} diff --git a/x/wasm/internal/types/proposal.go b/x/wasm/internal/types/proposal.go index 7ab985b630..57d8c36b1e 100644 --- a/x/wasm/internal/types/proposal.go +++ b/x/wasm/internal/types/proposal.go @@ -18,6 +18,8 @@ const ( ProposalTypeMigrateContract ProposalType = "MigrateContract" ProposalTypeUpdateAdmin ProposalType = "UpdateAdmin" ProposalTypeClearAdmin ProposalType = "ClearAdmin" + ProposalTypePinCodes ProposalType = "PinCodes" + ProposalTypeUnpinCodes ProposalType = "UnpinCodes" ) // DisableAllProposals contains no wasm gov types. @@ -30,6 +32,8 @@ var EnableAllProposals = []ProposalType{ ProposalTypeMigrateContract, ProposalTypeUpdateAdmin, ProposalTypeClearAdmin, + ProposalTypePinCodes, + ProposalTypeUnpinCodes, } // ConvertToProposals maps each key to a ProposalType and returns a typed list. @@ -56,11 +60,15 @@ func init() { // register new content types with the sdk govtypes.RegisterProposalType(string(ProposalTypeMigrateContract)) govtypes.RegisterProposalType(string(ProposalTypeUpdateAdmin)) govtypes.RegisterProposalType(string(ProposalTypeClearAdmin)) + govtypes.RegisterProposalType(string(ProposalTypePinCodes)) + govtypes.RegisterProposalType(string(ProposalTypeUnpinCodes)) govtypes.RegisterProposalTypeCodec(StoreCodeProposal{}, "wasm/StoreCodeProposal") govtypes.RegisterProposalTypeCodec(InstantiateContractProposal{}, "wasm/InstantiateContractProposal") govtypes.RegisterProposalTypeCodec(MigrateContractProposal{}, "wasm/MigrateContractProposal") govtypes.RegisterProposalTypeCodec(UpdateAdminProposal{}, "wasm/UpdateAdminProposal") govtypes.RegisterProposalTypeCodec(ClearAdminProposal{}, "wasm/ClearAdminProposal") + govtypes.RegisterProposalTypeCodec(PinCodesProposal{}, "wasm/PinCodesProposal") + govtypes.RegisterProposalTypeCodec(UnpinCodesProposal{}, "wasm/UnpinCodesProposal") } // ProposalRoute returns the routing key of a parameter change proposal. @@ -345,6 +353,70 @@ func (p ClearAdminProposal) String() string { `, p.Title, p.Description, p.Contract) } +// ProposalRoute returns the routing key of a parameter change proposal. +func (p PinCodesProposal) ProposalRoute() string { return RouterKey } + +// GetTitle returns the title of the proposal +func (p *PinCodesProposal) GetTitle() string { return p.Title } + +// GetDescription returns the human readable description of the proposal +func (p PinCodesProposal) GetDescription() string { return p.Description } + +// ProposalType returns the type +func (p PinCodesProposal) ProposalType() string { return string(ProposalTypePinCodes) } + +// ValidateBasic validates the proposal +func (p PinCodesProposal) ValidateBasic() error { + if err := validateProposalCommons(p.Title, p.Description); err != nil { + return err + } + if len(p.CodeIDs) == 0 { + return sdkerrors.Wrap(ErrEmpty, "code ids") + } + return nil +} + +// String implements the Stringer interface. +func (p PinCodesProposal) String() string { + return fmt.Sprintf(`Pin Wasm Codes Proposal: + Title: %s + Description: %s + Codes: %v +`, p.Title, p.Description, p.CodeIDs) +} + +// ProposalRoute returns the routing key of a parameter change proposal. +func (p UnpinCodesProposal) ProposalRoute() string { return RouterKey } + +// GetTitle returns the title of the proposal +func (p *UnpinCodesProposal) GetTitle() string { return p.Title } + +// GetDescription returns the human readable description of the proposal +func (p UnpinCodesProposal) GetDescription() string { return p.Description } + +// ProposalType returns the type +func (p UnpinCodesProposal) ProposalType() string { return string(ProposalTypeUnpinCodes) } + +// ValidateBasic validates the proposal +func (p UnpinCodesProposal) ValidateBasic() error { + if err := validateProposalCommons(p.Title, p.Description); err != nil { + return err + } + if len(p.CodeIDs) == 0 { + return sdkerrors.Wrap(ErrEmpty, "code ids") + } + return nil +} + +// String implements the Stringer interface. +func (p UnpinCodesProposal) String() string { + return fmt.Sprintf(`Unpin Wasm Codes Proposal: + Title: %s + Description: %s + Codes: %v +`, p.Title, p.Description, p.CodeIDs) +} + func validateProposalCommons(title, description string) error { if strings.TrimSpace(title) != title { return sdkerrors.Wrap(govtypes.ErrInvalidProposalContent, "proposal title must not start/end with white spaces") diff --git a/x/wasm/internal/types/proposal.pb.go b/x/wasm/internal/types/proposal.pb.go index 77abf8ef63..825380daf0 100644 --- a/x/wasm/internal/types/proposal.pb.go +++ b/x/wasm/internal/types/proposal.pb.go @@ -263,12 +263,98 @@ func (m *ClearAdminProposal) XXX_DiscardUnknown() { var xxx_messageInfo_ClearAdminProposal proto.InternalMessageInfo +// PinCodesProposal gov proposal content type to pin a set of code ids in the wasmvm cache. +type PinCodesProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + // CodeIDs references the new WASM codes + CodeIDs []uint64 `protobuf:"varint,3,rep,packed,name=code_ids,json=codeIds,proto3" json:"code_ids,omitempty" yaml:"code_ids"` +} + +func (m *PinCodesProposal) Reset() { *m = PinCodesProposal{} } +func (*PinCodesProposal) ProtoMessage() {} +func (*PinCodesProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_00b43267813130fb, []int{5} +} +func (m *PinCodesProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *PinCodesProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_PinCodesProposal.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *PinCodesProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_PinCodesProposal.Merge(m, src) +} +func (m *PinCodesProposal) XXX_Size() int { + return m.Size() +} +func (m *PinCodesProposal) XXX_DiscardUnknown() { + xxx_messageInfo_PinCodesProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_PinCodesProposal proto.InternalMessageInfo + +// UnpinCodesProposal gov proposal content type to unpin a set of code ids in the wasmvm cache. +type UnpinCodesProposal struct { + // Title is a short summary + Title string `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty" yaml:"title"` + // Description is a human readable text + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` + // CodeIDs references the WASM codes + CodeIDs []uint64 `protobuf:"varint,3,rep,packed,name=code_ids,json=codeIds,proto3" json:"code_ids,omitempty" yaml:"code_ids"` +} + +func (m *UnpinCodesProposal) Reset() { *m = UnpinCodesProposal{} } +func (*UnpinCodesProposal) ProtoMessage() {} +func (*UnpinCodesProposal) Descriptor() ([]byte, []int) { + return fileDescriptor_00b43267813130fb, []int{6} +} +func (m *UnpinCodesProposal) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *UnpinCodesProposal) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_UnpinCodesProposal.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *UnpinCodesProposal) XXX_Merge(src proto.Message) { + xxx_messageInfo_UnpinCodesProposal.Merge(m, src) +} +func (m *UnpinCodesProposal) XXX_Size() int { + return m.Size() +} +func (m *UnpinCodesProposal) XXX_DiscardUnknown() { + xxx_messageInfo_UnpinCodesProposal.DiscardUnknown(m) +} + +var xxx_messageInfo_UnpinCodesProposal proto.InternalMessageInfo + func init() { proto.RegisterType((*StoreCodeProposal)(nil), "cosmwasm.wasm.v1beta1.StoreCodeProposal") proto.RegisterType((*InstantiateContractProposal)(nil), "cosmwasm.wasm.v1beta1.InstantiateContractProposal") proto.RegisterType((*MigrateContractProposal)(nil), "cosmwasm.wasm.v1beta1.MigrateContractProposal") proto.RegisterType((*UpdateAdminProposal)(nil), "cosmwasm.wasm.v1beta1.UpdateAdminProposal") proto.RegisterType((*ClearAdminProposal)(nil), "cosmwasm.wasm.v1beta1.ClearAdminProposal") + proto.RegisterType((*PinCodesProposal)(nil), "cosmwasm.wasm.v1beta1.PinCodesProposal") + proto.RegisterType((*UnpinCodesProposal)(nil), "cosmwasm.wasm.v1beta1.UnpinCodesProposal") } func init() { @@ -276,48 +362,54 @@ func init() { } var fileDescriptor_00b43267813130fb = []byte{ - // 654 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x94, 0x4f, 0x6f, 0xd3, 0x3e, - 0x18, 0xc7, 0x9b, 0x6d, 0x4d, 0x3b, 0xb7, 0xfa, 0x69, 0xbf, 0xd0, 0x8d, 0x30, 0x50, 0x5a, 0x32, - 0x0e, 0xbd, 0x90, 0x6c, 0x43, 0x02, 0x09, 0x89, 0x43, 0x53, 0x2e, 0x3b, 0x54, 0x9a, 0x32, 0xc1, - 0xa4, 0x5d, 0x22, 0x27, 0xf1, 0x32, 0x43, 0x62, 0x47, 0xb6, 0x4b, 0xd7, 0x77, 0xc1, 0x0b, 0xe0, - 0x05, 0x4c, 0xbc, 0x92, 0x1d, 0x77, 0x1c, 0x97, 0xc2, 0xba, 0x0b, 0x67, 0x8e, 0x9c, 0x90, 0x9d, - 0xac, 0x74, 0xd2, 0x84, 0x26, 0xf1, 0xe7, 0x62, 0xe7, 0xc9, 0xf3, 0x7d, 0xfe, 0xf8, 0x93, 0x27, - 0x06, 0x8f, 0x8e, 0xdd, 0x11, 0xe4, 0x99, 0x8b, 0x89, 0x40, 0x8c, 0xc0, 0xd4, 0x15, 0xe3, 0x1c, - 0x71, 0x37, 0x67, 0x34, 0xa7, 0x1c, 0xa6, 0x4e, 0xce, 0xa8, 0xa0, 0xc6, 0x6a, 0x44, 0x79, 0x26, - 0x75, 0x8e, 0x5a, 0xde, 0x6d, 0x85, 0x48, 0xc0, 0xad, 0xf5, 0x56, 0x42, 0x13, 0xaa, 0x14, 0xae, - 0x7c, 0x2a, 0xc4, 0xeb, 0x96, 0x14, 0x53, 0xee, 0x86, 0x90, 0x23, 0xb7, 0x94, 0xba, 0x11, 0xc5, - 0xa4, 0xf4, 0x3f, 0xbc, 0xb9, 0xa4, 0x5a, 0x0b, 0x89, 0x7d, 0xb2, 0x00, 0xfe, 0xdf, 0x13, 0x94, - 0xa1, 0x3e, 0x8d, 0xd1, 0x6e, 0xd9, 0x8b, 0xd1, 0x02, 0x55, 0x81, 0x45, 0x8a, 0x4c, 0xad, 0xa3, - 0x75, 0x97, 0xfd, 0xc2, 0x30, 0x3a, 0xa0, 0x11, 0x23, 0x1e, 0x31, 0x9c, 0x0b, 0x4c, 0x89, 0xb9, - 0xa0, 0x7c, 0xf3, 0xaf, 0x8c, 0x55, 0xa0, 0xb3, 0x21, 0x09, 0x20, 0x37, 0x17, 0x8b, 0x40, 0x36, - 0x24, 0x3d, 0x6e, 0x3c, 0x05, 0xff, 0xc9, 0x3e, 0x82, 0x70, 0x2c, 0x50, 0x10, 0xd1, 0x18, 0x99, - 0x4b, 0x1d, 0xad, 0xdb, 0xf4, 0x56, 0xa6, 0x93, 0x76, 0x73, 0xbf, 0xb7, 0x37, 0xf0, 0xc6, 0x42, - 0x35, 0xe0, 0x37, 0xa5, 0xee, 0xca, 0x32, 0xd6, 0x80, 0xce, 0xe9, 0x90, 0x45, 0xc8, 0xac, 0xaa, - 0x74, 0xa5, 0x65, 0x98, 0xa0, 0x16, 0x0e, 0x71, 0x1a, 0x23, 0x66, 0xea, 0xca, 0x71, 0x65, 0x1a, - 0x07, 0x60, 0x0d, 0x13, 0x2e, 0x20, 0x11, 0x18, 0x0a, 0x14, 0xe4, 0x88, 0x65, 0x98, 0x73, 0xd9, - 0x6d, 0xad, 0xa3, 0x75, 0x1b, 0xdb, 0x1b, 0xce, 0x8d, 0x7c, 0x9d, 0x5e, 0x14, 0x21, 0xce, 0xfb, - 0x94, 0x1c, 0xe2, 0xc4, 0x5f, 0x9d, 0x4b, 0xb1, 0x3b, 0xcb, 0x60, 0x7f, 0x5a, 0x00, 0xf7, 0x77, - 0x7e, 0x7a, 0xfa, 0x94, 0x08, 0x06, 0x23, 0xf1, 0xb7, 0xa0, 0xb5, 0x40, 0x15, 0xc6, 0x19, 0x26, - 0x8a, 0xd5, 0xb2, 0x5f, 0x18, 0xc6, 0x06, 0xa8, 0x49, 0x80, 0x01, 0x8e, 0x15, 0x93, 0x25, 0x0f, - 0x4c, 0x27, 0x6d, 0x5d, 0xd2, 0xda, 0x79, 0xe9, 0xeb, 0xd2, 0xb5, 0x13, 0xcb, 0xd0, 0x14, 0x86, - 0x28, 0x2d, 0xe9, 0x14, 0x86, 0xf1, 0x0c, 0xd4, 0x31, 0xc1, 0x22, 0xc8, 0x78, 0xa2, 0x68, 0x34, - 0xbd, 0x07, 0xdf, 0x27, 0x6d, 0x13, 0x91, 0x88, 0xc6, 0x98, 0x24, 0xee, 0x1b, 0x4e, 0x89, 0xe3, - 0xc3, 0xd1, 0x00, 0x71, 0x0e, 0x13, 0xe4, 0xd7, 0xa4, 0x7a, 0xc0, 0x13, 0x03, 0x82, 0xea, 0xe1, - 0x90, 0xc4, 0xdc, 0xac, 0x77, 0x16, 0xbb, 0x8d, 0xed, 0x7b, 0x4e, 0x31, 0x76, 0x8e, 0x1c, 0xbb, - 0x19, 0xc1, 0x3e, 0xc5, 0xc4, 0xdb, 0x3c, 0x9d, 0xb4, 0x2b, 0x1f, 0x3f, 0xb7, 0xbb, 0x09, 0x16, - 0x47, 0xc3, 0xd0, 0x89, 0x68, 0xe6, 0x96, 0x33, 0x5a, 0x6c, 0x8f, 0x79, 0xfc, 0xb6, 0x9c, 0x3f, - 0x19, 0xc0, 0xfd, 0x22, 0xb3, 0xfd, 0x55, 0x03, 0x77, 0x07, 0x38, 0x61, 0xff, 0x80, 0xeb, 0x3a, - 0xa8, 0x47, 0x65, 0x89, 0x12, 0xed, 0xcc, 0xbe, 0x1d, 0xdd, 0x17, 0xa0, 0x91, 0x15, 0xad, 0x2a, - 0x94, 0xfa, 0x2d, 0x50, 0x82, 0x32, 0x60, 0xc0, 0x13, 0xfb, 0x83, 0x06, 0xee, 0xbc, 0xca, 0x63, - 0x28, 0x50, 0x4f, 0x7e, 0xd1, 0xdf, 0x3e, 0xe6, 0x16, 0x58, 0x26, 0x68, 0x14, 0x14, 0xb3, 0xa2, - 0x4e, 0xea, 0xb5, 0xbe, 0x4d, 0xda, 0x2b, 0x63, 0x98, 0xa5, 0xcf, 0xed, 0x99, 0xcb, 0xf6, 0xeb, - 0x04, 0x8d, 0x54, 0xc9, 0x5f, 0x21, 0xb0, 0x8f, 0x80, 0xd1, 0x4f, 0x11, 0x64, 0x7f, 0xa6, 0xb9, - 0xf9, 0x4a, 0x8b, 0xd7, 0x2b, 0x79, 0xaf, 0x4f, 0x2f, 0xac, 0xca, 0xf9, 0x85, 0x55, 0x39, 0x99, - 0x5a, 0xda, 0xe9, 0xd4, 0xd2, 0xce, 0xa6, 0x96, 0xf6, 0x65, 0x6a, 0x69, 0xef, 0x2f, 0xad, 0xca, - 0xd9, 0xa5, 0x55, 0x39, 0xbf, 0xb4, 0x2a, 0x07, 0x9b, 0x73, 0xa3, 0xd4, 0xa7, 0x3c, 0xdb, 0x97, - 0x17, 0x9a, 0xfc, 0x77, 0x63, 0xf7, 0xb8, 0xdc, 0xaf, 0x5f, 0x6f, 0xa1, 0xae, 0x6e, 0xb6, 0x27, - 0x3f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd4, 0xcb, 0x63, 0x29, 0x71, 0x05, 0x00, 0x00, + // 742 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x55, 0xcb, 0x6e, 0xe3, 0x36, + 0x14, 0xb5, 0xe2, 0xf8, 0x11, 0xda, 0x68, 0x5d, 0xd5, 0x49, 0xd5, 0xb4, 0x90, 0x5c, 0xa5, 0x28, + 0xbc, 0xa9, 0x94, 0xa4, 0x40, 0x5f, 0x40, 0x17, 0x96, 0xbb, 0xc9, 0xc2, 0x40, 0xa0, 0x20, 0x0d, + 0x90, 0x8d, 0x41, 0x4b, 0x8c, 0xc2, 0x56, 0x22, 0x05, 0x91, 0xae, 0xe3, 0xbf, 0xe8, 0x07, 0xf4, + 0x03, 0x82, 0x6e, 0x8a, 0xfe, 0x45, 0x96, 0x59, 0xa6, 0x1b, 0xcd, 0xc4, 0xd9, 0xcc, 0xda, 0xcb, + 0x59, 0x0d, 0x48, 0xca, 0x1e, 0x67, 0x10, 0x0c, 0x02, 0xcc, 0x03, 0x98, 0x8d, 0xe4, 0xcb, 0x7b, + 0x78, 0xcf, 0xe1, 0xb9, 0xd7, 0x22, 0xf8, 0xfa, 0xc2, 0x9d, 0x40, 0x96, 0xb8, 0x98, 0x70, 0x94, + 0x11, 0x18, 0xbb, 0x7c, 0x9a, 0x22, 0xe6, 0xa6, 0x19, 0x4d, 0x29, 0x83, 0xb1, 0x93, 0x66, 0x94, + 0x53, 0x7d, 0x33, 0xa0, 0x2c, 0x11, 0x38, 0x47, 0x3e, 0xfe, 0xdc, 0x1b, 0x21, 0x0e, 0xf7, 0xb6, + 0xdb, 0x11, 0x8d, 0xa8, 0x44, 0xb8, 0xe2, 0x97, 0x02, 0x6f, 0x9b, 0x02, 0x4c, 0x99, 0x3b, 0x82, + 0x0c, 0xb9, 0x05, 0xd4, 0x0d, 0x28, 0x26, 0x45, 0xfe, 0xab, 0x87, 0x29, 0xe5, 0x53, 0x41, 0xec, + 0xcb, 0x35, 0xf0, 0xc9, 0x11, 0xa7, 0x19, 0xea, 0xd3, 0x10, 0x1d, 0x16, 0x5a, 0xf4, 0x36, 0xa8, + 0x70, 0xcc, 0x63, 0x64, 0x68, 0x1d, 0xad, 0xbb, 0xe1, 0xab, 0x40, 0xef, 0x80, 0x46, 0x88, 0x58, + 0x90, 0xe1, 0x94, 0x63, 0x4a, 0x8c, 0x35, 0x99, 0x5b, 0x5d, 0xd2, 0x37, 0x41, 0x35, 0x1b, 0x93, + 0x21, 0x64, 0x46, 0x59, 0x6d, 0xcc, 0xc6, 0xa4, 0xc7, 0xf4, 0xef, 0xc1, 0x47, 0x42, 0xc7, 0x70, + 0x34, 0xe5, 0x68, 0x18, 0xd0, 0x10, 0x19, 0xeb, 0x1d, 0xad, 0xdb, 0xf4, 0x5a, 0xb3, 0xdc, 0x6a, + 0x9e, 0xf4, 0x8e, 0x06, 0xde, 0x94, 0x4b, 0x01, 0x7e, 0x53, 0xe0, 0x16, 0x91, 0xbe, 0x05, 0xaa, + 0x8c, 0x8e, 0xb3, 0x00, 0x19, 0x15, 0x59, 0xae, 0x88, 0x74, 0x03, 0xd4, 0x46, 0x63, 0x1c, 0x87, + 0x28, 0x33, 0xaa, 0x32, 0xb1, 0x08, 0xf5, 0x53, 0xb0, 0x85, 0x09, 0xe3, 0x90, 0x70, 0x0c, 0x39, + 0x1a, 0xa6, 0x28, 0x4b, 0x30, 0x63, 0x42, 0x6d, 0xad, 0xa3, 0x75, 0x1b, 0xfb, 0x3b, 0xce, 0x83, + 0xfe, 0x3a, 0xbd, 0x20, 0x40, 0x8c, 0xf5, 0x29, 0x39, 0xc3, 0x91, 0xbf, 0xb9, 0x52, 0xe2, 0x70, + 0x59, 0xc1, 0xfe, 0x7f, 0x0d, 0x7c, 0x71, 0xf0, 0x32, 0xd3, 0xa7, 0x84, 0x67, 0x30, 0xe0, 0xef, + 0xca, 0xb4, 0x36, 0xa8, 0xc0, 0x30, 0xc1, 0x44, 0x7a, 0xb5, 0xe1, 0xab, 0x40, 0xdf, 0x01, 0x35, + 0x61, 0xe0, 0x10, 0x87, 0xd2, 0x93, 0x75, 0x0f, 0xcc, 0x72, 0xab, 0x2a, 0xdc, 0x3a, 0xf8, 0xd5, + 0xaf, 0x8a, 0xd4, 0x41, 0x28, 0xb6, 0xc6, 0x70, 0x84, 0xe2, 0xc2, 0x1d, 0x15, 0xe8, 0x3f, 0x80, + 0x3a, 0x26, 0x98, 0x0f, 0x13, 0x16, 0x49, 0x37, 0x9a, 0xde, 0x97, 0xcf, 0x73, 0xcb, 0x40, 0x24, + 0xa0, 0x21, 0x26, 0x91, 0xfb, 0x3b, 0xa3, 0xc4, 0xf1, 0xe1, 0x64, 0x80, 0x18, 0x83, 0x11, 0xf2, + 0x6b, 0x02, 0x3d, 0x60, 0x91, 0x0e, 0x41, 0xe5, 0x6c, 0x4c, 0x42, 0x66, 0xd4, 0x3b, 0xe5, 0x6e, + 0x63, 0xff, 0x73, 0x47, 0x8d, 0x9d, 0x23, 0xc6, 0x6e, 0xe9, 0x60, 0x9f, 0x62, 0xe2, 0xed, 0x5e, + 0xe5, 0x56, 0xe9, 0x9f, 0x27, 0x56, 0x37, 0xc2, 0xfc, 0x7c, 0x3c, 0x72, 0x02, 0x9a, 0xb8, 0xc5, + 0x8c, 0xaa, 0xd7, 0xb7, 0x2c, 0xfc, 0xa3, 0x98, 0x3f, 0xb1, 0x81, 0xf9, 0xaa, 0xb2, 0xfd, 0x4c, + 0x03, 0x9f, 0x0d, 0x70, 0x94, 0xbd, 0x07, 0x5f, 0xb7, 0x41, 0x3d, 0x28, 0x28, 0x0a, 0x6b, 0x97, + 0xf1, 0xe3, 0xdc, 0xfd, 0x05, 0x34, 0x12, 0x25, 0x55, 0x5a, 0x59, 0x7d, 0x84, 0x95, 0xa0, 0xd8, + 0x30, 0x60, 0x91, 0xfd, 0xb7, 0x06, 0x3e, 0x3d, 0x4e, 0x43, 0xc8, 0x51, 0x4f, 0x74, 0xf4, 0x8d, + 0x8f, 0xb9, 0x07, 0x36, 0x08, 0x9a, 0x0c, 0xd5, 0xac, 0xc8, 0x93, 0x7a, 0xed, 0x79, 0x6e, 0xb5, + 0xa6, 0x30, 0x89, 0x7f, 0xb6, 0x97, 0x29, 0xdb, 0xaf, 0x13, 0x34, 0x91, 0x94, 0xaf, 0xb3, 0xc0, + 0x3e, 0x07, 0x7a, 0x3f, 0x46, 0x30, 0x7b, 0x3b, 0xe2, 0x56, 0x99, 0xca, 0xaf, 0x30, 0xfd, 0xab, + 0x81, 0xd6, 0x21, 0x26, 0xc2, 0x5d, 0xb6, 0x24, 0xfa, 0xe6, 0x1e, 0x91, 0xd7, 0x9a, 0xe7, 0x56, + 0x53, 0x9d, 0x44, 0x2e, 0xdb, 0x0b, 0xea, 0x1f, 0x1f, 0xa0, 0xf6, 0xb6, 0xe6, 0xb9, 0xa5, 0x2b, + 0xf4, 0x4a, 0xd2, 0xbe, 0x2f, 0xe9, 0x27, 0x21, 0x49, 0xf6, 0x58, 0x0c, 0x46, 0xb9, 0xbb, 0xee, + 0x99, 0xb3, 0xdc, 0xaa, 0xa9, 0x26, 0xb3, 0x79, 0x6e, 0x7d, 0xac, 0x2a, 0x2c, 0x40, 0xb6, 0x5f, + 0x53, 0x8d, 0x67, 0xf6, 0x7f, 0x1a, 0xd0, 0x8f, 0x49, 0xfa, 0x21, 0x69, 0xf6, 0x7e, 0xbb, 0xba, + 0x35, 0x4b, 0x37, 0xb7, 0x66, 0xe9, 0x72, 0x66, 0x6a, 0x57, 0x33, 0x53, 0xbb, 0x9e, 0x99, 0xda, + 0xd3, 0x99, 0xa9, 0xfd, 0x75, 0x67, 0x96, 0xae, 0xef, 0xcc, 0xd2, 0xcd, 0x9d, 0x59, 0x3a, 0xdd, + 0x5d, 0xf9, 0xc3, 0xf6, 0x29, 0x4b, 0x4e, 0xc4, 0xb5, 0x21, 0xbe, 0x90, 0xa1, 0x7b, 0x51, 0xbc, + 0xef, 0x5f, 0x22, 0xa3, 0xaa, 0xbc, 0x3f, 0xbe, 0x7b, 0x11, 0x00, 0x00, 0xff, 0xff, 0x98, 0x84, + 0x18, 0xe8, 0xd7, 0x06, 0x00, 0x00, } func (this *StoreCodeProposal) Equal(that interface{}) bool { @@ -514,6 +606,76 @@ func (this *ClearAdminProposal) Equal(that interface{}) bool { } return true } +func (this *PinCodesProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*PinCodesProposal) + if !ok { + that2, ok := that.(PinCodesProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if len(this.CodeIDs) != len(that1.CodeIDs) { + return false + } + for i := range this.CodeIDs { + if this.CodeIDs[i] != that1.CodeIDs[i] { + return false + } + } + return true +} +func (this *UnpinCodesProposal) Equal(that interface{}) bool { + if that == nil { + return this == nil + } + + that1, ok := that.(*UnpinCodesProposal) + if !ok { + that2, ok := that.(UnpinCodesProposal) + if ok { + that1 = &that2 + } else { + return false + } + } + if that1 == nil { + return this == nil + } else if this == nil { + return false + } + if this.Title != that1.Title { + return false + } + if this.Description != that1.Description { + return false + } + if len(this.CodeIDs) != len(that1.CodeIDs) { + return false + } + for i := range this.CodeIDs { + if this.CodeIDs[i] != that1.CodeIDs[i] { + return false + } + } + return true +} func (m *StoreCodeProposal) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -833,6 +995,116 @@ func (m *ClearAdminProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *PinCodesProposal) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PinCodesProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *PinCodesProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CodeIDs) > 0 { + dAtA3 := make([]byte, len(m.CodeIDs)*10) + var j2 int + for _, num := range m.CodeIDs { + for num >= 1<<7 { + dAtA3[j2] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j2++ + } + dAtA3[j2] = uint8(num) + j2++ + } + i -= j2 + copy(dAtA[i:], dAtA3[:j2]) + i = encodeVarintProposal(dAtA, i, uint64(j2)) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *UnpinCodesProposal) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *UnpinCodesProposal) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *UnpinCodesProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.CodeIDs) > 0 { + dAtA5 := make([]byte, len(m.CodeIDs)*10) + var j4 int + for _, num := range m.CodeIDs { + for num >= 1<<7 { + dAtA5[j4] = uint8(uint64(num)&0x7f | 0x80) + num >>= 7 + j4++ + } + dAtA5[j4] = uint8(num) + j4++ + } + i -= j4 + copy(dAtA[i:], dAtA5[:j4]) + i = encodeVarintProposal(dAtA, i, uint64(j4)) + i-- + dAtA[i] = 0x1a + } + if len(m.Description) > 0 { + i -= len(m.Description) + copy(dAtA[i:], m.Description) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Description))) + i-- + dAtA[i] = 0x12 + } + if len(m.Title) > 0 { + i -= len(m.Title) + copy(dAtA[i:], m.Title) + i = encodeVarintProposal(dAtA, i, uint64(len(m.Title))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintProposal(dAtA []byte, offset int, v uint64) int { offset -= sovProposal(v) base := offset @@ -1001,6 +1273,54 @@ func (m *ClearAdminProposal) Size() (n int) { return n } +func (m *PinCodesProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if len(m.CodeIDs) > 0 { + l = 0 + for _, e := range m.CodeIDs { + l += sovProposal(uint64(e)) + } + n += 1 + sovProposal(uint64(l)) + l + } + return n +} + +func (m *UnpinCodesProposal) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.Title) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + l = len(m.Description) + if l > 0 { + n += 1 + l + sovProposal(uint64(l)) + } + if len(m.CodeIDs) > 0 { + l = 0 + for _, e := range m.CodeIDs { + l += sovProposal(uint64(e)) + } + n += 1 + sovProposal(uint64(l)) + l + } + return n +} + func sovProposal(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2154,6 +2474,392 @@ func (m *ClearAdminProposal) Unmarshal(dAtA []byte) error { } return nil } +func (m *PinCodesProposal) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PinCodesProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PinCodesProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.CodeIDs) == 0 { + m.CodeIDs = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field CodeIDs", wireType) + } + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *UnpinCodesProposal) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: UnpinCodesProposal: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: UnpinCodesProposal: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Title", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Title = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Description = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType == 0 { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } else if wireType == 2 { + var packedLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + packedLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if packedLen < 0 { + return ErrInvalidLengthProposal + } + postIndex := iNdEx + packedLen + if postIndex < 0 { + return ErrInvalidLengthProposal + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + var elementCount int + var count int + for _, integer := range dAtA[iNdEx:postIndex] { + if integer < 128 { + count++ + } + } + elementCount = count + if elementCount != 0 && len(m.CodeIDs) == 0 { + m.CodeIDs = make([]uint64, 0, elementCount) + } + for iNdEx < postIndex { + var v uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProposal + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + v |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + m.CodeIDs = append(m.CodeIDs, v) + } + } else { + return fmt.Errorf("proto: wrong wireType = %d for field CodeIDs", wireType) + } + default: + iNdEx = preIndex + skippy, err := skipProposal(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) < 0 { + return ErrInvalidLengthProposal + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipProposal(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/wasm/internal/types/proposal.proto b/x/wasm/internal/types/proposal.proto index 98bdb6fe11..e87aafbf40 100644 --- a/x/wasm/internal/types/proposal.proto +++ b/x/wasm/internal/types/proposal.proto @@ -85,3 +85,29 @@ message ClearAdminProposal { // Contract is the address of the smart contract string contract = 3; } + +// PinCodesProposal gov proposal content type to pin a set of code ids in the wasmvm cache. +message PinCodesProposal { + // Title is a short summary + string title = 1 [(gogoproto.moretags) = "yaml:\"title\""]; + // Description is a human readable text + string description = 2 [(gogoproto.moretags) = "yaml:\"description\""]; + // CodeIDs references the new WASM codes + repeated uint64 code_ids = 3 [ + (gogoproto.customname) = "CodeIDs", + (gogoproto.moretags) = "yaml:\"code_ids\"" + ]; +} + +// UnpinCodesProposal gov proposal content type to unpin a set of code ids in the wasmvm cache. +message UnpinCodesProposal { + // Title is a short summary + string title = 1 [(gogoproto.moretags) = "yaml:\"title\""]; + // Description is a human readable text + string description = 2 [(gogoproto.moretags) = "yaml:\"description\""]; + // CodeIDs references the WASM codes + repeated uint64 code_ids = 3 [ + (gogoproto.customname) = "CodeIDs", + (gogoproto.moretags) = "yaml:\"code_ids\"" + ]; +} diff --git a/x/wasm/internal/types/proposal_test.go b/x/wasm/internal/types/proposal_test.go index c3148f6e6c..15f15592f4 100644 --- a/x/wasm/internal/types/proposal_test.go +++ b/x/wasm/internal/types/proposal_test.go @@ -515,6 +515,30 @@ func TestProposalStrings(t *testing.T) { Title: Foo Description: Bar Contract: cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5 +`, + }, + "pin codes": { + src: &PinCodesProposal{ + Title: "Foo", + Description: "Bar", + CodeIDs: []uint64{1, 2, 3}, + }, + exp: `Pin Wasm Codes Proposal: + Title: Foo + Description: Bar + Codes: [1 2 3] +`, + }, + "unpin codes": { + src: &UnpinCodesProposal{ + Title: "Foo", + Description: "Bar", + CodeIDs: []uint64{3, 2, 1}, + }, + exp: `Unpin Wasm Codes Proposal: + Title: Foo + Description: Bar + Codes: [3 2 1] `, }, } @@ -608,6 +632,20 @@ contract: cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5 exp: `title: Foo description: Bar contract: cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5 +`, + }, + "pin codes": { + src: &PinCodesProposal{ + Title: "Foo", + Description: "Bar", + CodeIDs: []uint64{1, 2, 3}, + }, + exp: `title: Foo +description: Bar +code_ids: +- 1 +- 2 +- 3 `, }, } diff --git a/x/wasm/internal/types/types.pb.go b/x/wasm/internal/types/types.pb.go index cf7fa3aa46..35cba507cd 100644 --- a/x/wasm/internal/types/types.pb.go +++ b/x/wasm/internal/types/types.pb.go @@ -212,7 +212,7 @@ var xxx_messageInfo_Params proto.InternalMessageInfo // CodeInfo is data for the uploaded contract WASM code type CodeInfo struct { - // CodeHash is the unique CodeID + // CodeHash is the unique identifier created by wasmvm CodeHash []byte `protobuf:"bytes,1,opt,name=code_hash,json=codeHash,proto3" json:"code_hash,omitempty"` // Creator address who initially stored the code Creator string `protobuf:"bytes,2,opt,name=creator,proto3" json:"creator,omitempty"` diff --git a/x/wasm/internal/types/types.proto b/x/wasm/internal/types/types.proto index 7328436ed0..0ea99dc245 100644 --- a/x/wasm/internal/types/types.proto +++ b/x/wasm/internal/types/types.proto @@ -44,7 +44,7 @@ message Params { // CodeInfo is data for the uploaded contract WASM code message CodeInfo { - // CodeHash is the unique CodeID + // CodeHash is the unique identifier created by wasmvm bytes code_hash = 1; // Creator address who initially stored the code string creator = 2; diff --git a/x/wasm/internal/types/wasmer_engine.go b/x/wasm/internal/types/wasmer_engine.go index 8aba3fd31c..2d4b0d89e6 100644 --- a/x/wasm/internal/types/wasmer_engine.go +++ b/x/wasm/internal/types/wasmer_engine.go @@ -197,4 +197,15 @@ type WasmerEngine interface { gasMeter wasmvm.GasMeter, gasLimit uint64, ) (*wasmvmtypes.IBCBasicResponse, uint64, error) + + // Pin pins a code to an in-memory cache, such that is + // always loaded quickly when executed. + // Pin is idempotent. + Pin(checksum wasmvm.Checksum) error + + // Unpin removes the guarantee of a contract to be pinned (see Pin). + // After calling this, the code may or may not remain in memory depending on + // the implementor's choice. + // Unpin is idempotent. + Unpin(checksum wasmvm.Checksum) error }