package keeper import ( "bytes" "encoding/hex" "encoding/json" "io/ioutil" "testing" "github.com/CosmWasm/wasmd/x/wasm/internal/types" sdk "github.com/cosmos/cosmos-sdk/types" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/params/types/proposal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestStoreCodeProposal(t *testing.T) { ctx, keepers := CreateTestInput(t, false, "staking", nil, nil) govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper wasmKeeper.setParams(ctx, types.Params{ CodeUploadAccess: types.AllowNobody, InstantiateDefaultPermission: types.AccessTypeNobody, MaxWasmCodeSize: types.DefaultMaxWasmCodeSize, }) wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm") require.NoError(t, err) myActorAddress := RandomBech32AccountAddress(t) src := types.StoreCodeProposalFixture(func(p *types.StoreCodeProposal) { p.RunAs = myActorAddress p.WASMByteCode = wasmCode p.Source = "https://example.com/mysource" p.Builder = "foo/bar:v0.0.0" }) // when stored storedProposal, err := govKeeper.SubmitProposal(ctx, src) require.NoError(t, err) // and proposal execute handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) err = handler(ctx, storedProposal.GetContent()) require.NoError(t, err) // then cInfo := wasmKeeper.GetCodeInfo(ctx, 1) require.NotNil(t, cInfo) assert.Equal(t, myActorAddress, cInfo.Creator) assert.Equal(t, "foo/bar:v0.0.0", cInfo.Builder) assert.Equal(t, "https://example.com/mysource", cInfo.Source) storedCode, err := wasmKeeper.GetByteCode(ctx, 1) require.NoError(t, err) assert.Equal(t, wasmCode, storedCode) } func TestInstantiateProposal(t *testing.T) { ctx, keepers := CreateTestInput(t, false, "staking", nil, nil) govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper wasmKeeper.setParams(ctx, types.Params{ CodeUploadAccess: types.AllowNobody, InstantiateDefaultPermission: types.AccessTypeNobody, MaxWasmCodeSize: types.DefaultMaxWasmCodeSize, }) wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm") require.NoError(t, err) require.NoError(t, wasmKeeper.importCode(ctx, 1, types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)), wasmCode), ) var ( oneAddress sdk.AccAddress = bytes.Repeat([]byte{0x1}, sdk.AddrLen) otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, sdk.AddrLen) ) src := types.InstantiateContractProposalFixture(func(p *types.InstantiateContractProposal) { p.CodeID = firstCodeID p.RunAs = oneAddress.String() p.Admin = otherAddress.String() p.Label = "testing" }) // when stored storedProposal, err := govKeeper.SubmitProposal(ctx, src) require.NoError(t, err) // and proposal execute handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) err = handler(ctx, storedProposal.GetContent()) require.NoError(t, err) // then contractAddr, err := sdk.AccAddressFromBech32("cosmos18vd8fpwxzck93qlwghaj6arh4p7c5n89uzcee5") require.NoError(t, err) cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) require.NotNil(t, cInfo) assert.Equal(t, uint64(1), cInfo.CodeID) assert.Equal(t, oneAddress.String(), cInfo.Creator) assert.Equal(t, otherAddress.String(), cInfo.Admin) assert.Equal(t, "testing", cInfo.Label) expHistory := []types.ContractCodeHistoryEntry{{ Operation: types.ContractCodeHistoryOperationTypeInit, CodeID: src.CodeID, Updated: types.NewAbsoluteTxPosition(ctx), Msg: src.InitMsg, }} assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddr)) } func TestMigrateProposal(t *testing.T) { ctx, keepers := CreateTestInput(t, false, "staking", nil, nil) govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper wasmKeeper.setParams(ctx, types.Params{ CodeUploadAccess: types.AllowNobody, InstantiateDefaultPermission: types.AccessTypeNobody, MaxWasmCodeSize: types.DefaultMaxWasmCodeSize, }) wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm") require.NoError(t, err) codeInfoFixture := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)) require.NoError(t, wasmKeeper.importCode(ctx, 1, codeInfoFixture, wasmCode)) require.NoError(t, wasmKeeper.importCode(ctx, 2, codeInfoFixture, wasmCode)) var ( anyAddress sdk.AccAddress = bytes.Repeat([]byte{0x1}, sdk.AddrLen) otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, sdk.AddrLen) contractAddr = contractAddress(1, 1) ) contractInfoFixture := types.ContractInfoFixture(func(c *types.ContractInfo) { c.Label = "testing" c.Admin = anyAddress.String() }) key, err := hex.DecodeString("636F6E666967") require.NoError(t, err) m := types.Model{Key: key, Value: []byte(`{"verifier":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","beneficiary":"AAAAAAAAAAAAAAAAAAAAAAAAAAA=","funder":"AQEBAQEBAQEBAQEBAQEBAQEBAQE="}`)} require.NoError(t, wasmKeeper.importContract(ctx, contractAddr, &contractInfoFixture, []types.Model{m})) migMsg := struct { Verifier sdk.AccAddress `json:"verifier"` }{Verifier: otherAddress} migMsgBz, err := json.Marshal(migMsg) require.NoError(t, err) src := types.MigrateContractProposal{ Title: "Foo", Description: "Bar", CodeID: 2, Contract: contractAddr.String(), MigrateMsg: migMsgBz, RunAs: otherAddress.String(), } // when stored storedProposal, err := govKeeper.SubmitProposal(ctx, &src) require.NoError(t, err) // and proposal execute handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) err = handler(ctx, storedProposal.GetContent()) require.NoError(t, err) // then require.NoError(t, err) cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) require.NotNil(t, cInfo) assert.Equal(t, uint64(2), cInfo.CodeID) assert.Equal(t, anyAddress.String(), cInfo.Admin) assert.Equal(t, "testing", cInfo.Label) expHistory := []types.ContractCodeHistoryEntry{{ Operation: types.ContractCodeHistoryOperationTypeGenesis, CodeID: firstCodeID, Updated: types.NewAbsoluteTxPosition(ctx), }, { Operation: types.ContractCodeHistoryOperationTypeMigrate, CodeID: src.CodeID, Updated: types.NewAbsoluteTxPosition(ctx), Msg: src.MigrateMsg, }} assert.Equal(t, expHistory, wasmKeeper.GetContractHistory(ctx, contractAddr)) } func TestAdminProposals(t *testing.T) { var ( otherAddress sdk.AccAddress = bytes.Repeat([]byte{0x2}, sdk.AddrLen) contractAddr = contractAddress(1, 1) ) wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm") require.NoError(t, err) specs := map[string]struct { state types.ContractInfo srcProposal govtypes.Content expAdmin sdk.AccAddress }{ "update with different admin": { state: types.ContractInfoFixture(), srcProposal: &types.UpdateAdminProposal{ Title: "Foo", Description: "Bar", Contract: contractAddr.String(), NewAdmin: otherAddress.String(), }, expAdmin: otherAddress, }, "update with old admin empty": { state: types.ContractInfoFixture(func(info *types.ContractInfo) { info.Admin = "" }), srcProposal: &types.UpdateAdminProposal{ Title: "Foo", Description: "Bar", Contract: contractAddr.String(), NewAdmin: otherAddress.String(), }, expAdmin: otherAddress, }, "clear admin": { state: types.ContractInfoFixture(), srcProposal: &types.ClearAdminProposal{ Title: "Foo", Description: "Bar", Contract: contractAddr.String(), }, expAdmin: nil, }, "clear with old admin empty": { state: types.ContractInfoFixture(func(info *types.ContractInfo) { info.Admin = "" }), srcProposal: &types.ClearAdminProposal{ Title: "Foo", Description: "Bar", Contract: contractAddr.String(), }, expAdmin: nil, }, } for msg, spec := range specs { t.Run(msg, func(t *testing.T) { ctx, keepers := CreateTestInput(t, false, "staking", nil, nil) govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper wasmKeeper.setParams(ctx, types.Params{ CodeUploadAccess: types.AllowNobody, InstantiateDefaultPermission: types.AccessTypeNobody, MaxWasmCodeSize: types.DefaultMaxWasmCodeSize, }) codeInfoFixture := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)) require.NoError(t, wasmKeeper.importCode(ctx, 1, codeInfoFixture, wasmCode)) require.NoError(t, wasmKeeper.importContract(ctx, contractAddr, &spec.state, []types.Model{})) // when stored storedProposal, err := govKeeper.SubmitProposal(ctx, spec.srcProposal) require.NoError(t, err) // and execute proposal handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) err = handler(ctx, storedProposal.GetContent()) require.NoError(t, err) // then cInfo := wasmKeeper.GetContractInfo(ctx, contractAddr) require.NotNil(t, cInfo) assert.Equal(t, spec.expAdmin.String(), cInfo.Admin) }) } } func TestUpdateParamsProposal(t *testing.T) { ctx, keepers := CreateTestInput(t, false, "staking", nil, nil) govKeeper, wasmKeeper := keepers.GovKeeper, keepers.WasmKeeper var ( cdc = keepers.WasmKeeper.cdc myAddress sdk.AccAddress = make([]byte, sdk.AddrLen) oneAddressAccessConfig = types.AccessTypeOnlyAddress.With(myAddress) ) nobodyJson, err := json.Marshal(types.AccessTypeNobody) require.NoError(t, err) specs := map[string]struct { src proposal.ParamChange expUploadConfig types.AccessConfig expInstantiateType types.AccessType }{ "update upload permission param": { src: proposal.ParamChange{ Subspace: types.DefaultParamspace, Key: string(types.ParamStoreKeyUploadAccess), Value: string(cdc.MustMarshalJSON(&types.AllowNobody)), }, expUploadConfig: types.AllowNobody, expInstantiateType: types.AccessTypeEverybody, }, "update upload permission param with address": { src: proposal.ParamChange{ Subspace: types.DefaultParamspace, Key: string(types.ParamStoreKeyUploadAccess), Value: string(cdc.MustMarshalJSON(&oneAddressAccessConfig)), }, expUploadConfig: oneAddressAccessConfig, expInstantiateType: types.AccessTypeEverybody, }, "update instantiate param": { src: proposal.ParamChange{ Subspace: types.DefaultParamspace, Key: string(types.ParamStoreKeyInstantiateAccess), Value: string(nobodyJson), }, expUploadConfig: types.AllowEverybody, expInstantiateType: types.AccessTypeNobody, }, } for msg, spec := range specs { t.Run(msg, func(t *testing.T) { wasmKeeper.setParams(ctx, types.DefaultParams()) proposal := proposal.ParameterChangeProposal{ Title: "Foo", Description: "Bar", Changes: []proposal.ParamChange{spec.src}, } // when stored storedProposal, err := govKeeper.SubmitProposal(ctx, &proposal) require.NoError(t, err) // and proposal execute handler := govKeeper.Router().GetRoute(storedProposal.ProposalRoute()) err = handler(ctx, storedProposal.GetContent()) require.NoError(t, err) // then assert.True(t, spec.expUploadConfig.Equals(wasmKeeper.getUploadAccessConfig(ctx)), "got %#v not %#v", wasmKeeper.getUploadAccessConfig(ctx), spec.expUploadConfig) assert.Equal(t, spec.expInstantiateType, wasmKeeper.getInstantiateAccessConfig(ctx)) }) } }