diff --git a/x/wasm/internal/keeper/keeper.go b/x/wasm/internal/keeper/keeper.go index 01fe28dc47..64ca395481 100644 --- a/x/wasm/internal/keeper/keeper.go +++ b/x/wasm/internal/keeper/keeper.go @@ -327,6 +327,9 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller if err != nil { return nil, err } + if contractInfo.Status != types.ContractStatusActive { + return nil, sdkerrors.Wrap(types.ErrInvalid, "inactive contract") + } if !k.IsPinnedCode(ctx, contractInfo.CodeID) { ctx.GasMeter().ConsumeGas(InstanceCost, "Loading CosmWasm module: execute") @@ -380,6 +383,9 @@ func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller if contractInfo == nil { return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "unknown contract") } + if contractInfo.Status != types.ContractStatusActive { + return nil, sdkerrors.Wrap(types.ErrInvalid, "inactive contract") + } if !authZ.CanModifyContract(contractInfo.AdminAddr(), caller) { return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not migrate") } @@ -558,6 +564,9 @@ func (k Keeper) setContractAdmin(ctx sdk.Context, contractAddress, caller, newAd if contractInfo == nil { return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "unknown contract") } + if contractInfo.Status != types.ContractStatusActive { + return sdkerrors.Wrap(types.ErrInvalid, "inactive contract") + } if !authZ.CanModifyContract(contractInfo.AdminAddr(), caller) { return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "can not modify contract") } diff --git a/x/wasm/internal/keeper/keeper_test.go b/x/wasm/internal/keeper/keeper_test.go index b5031d4b86..ddc1385b05 100644 --- a/x/wasm/internal/keeper/keeper_test.go +++ b/x/wasm/internal/keeper/keeper_test.go @@ -763,6 +763,43 @@ func TestExecuteWithStorageLoop(t *testing.T) { require.True(t, false, "We must panic before this line") } +func TestExecuteInactiveContract(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, deposit.Add(deposit...)) + fred := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, topUp) + + wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + contractID, err := keeper.Create(ctx, creator, wasmCode, "", "", nil) + require.NoError(t, err) + + _, _, bob := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: bob, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + addr, _, err := keeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit) + require.NoError(t, err) + require.Equal(t, "link18vd8fpwxzck93qlwghaj6arh4p7c5n89fvcmzu", addr.String()) + + // execute inactive contract + params := keeper.GetParams(ctx) + params.ContractStatusAccess = types.AccessTypeOnlyAddress.With(creator) + keeper.setParams(ctx, params) + err = keeper.UpdateContractStatus(ctx, addr, creator, types.ContractStatusInactive) + require.NoError(t, err) + _, err = keeper.Execute(ctx, addr, fred, []byte(`{"release":{}}`), topUp) + require.True(t, types.ErrInvalid.Is(err), "expected %v but got %+v", types.ErrInvalid, err) +} + func TestMigrate(t *testing.T) { ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil) accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper @@ -1048,6 +1085,41 @@ func TestMigrateWithDispatchedMessage(t *testing.T) { assert.Equal(t, deposit, balance) } +func TestMigrateInactiveContract(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, deposit.Add(deposit...)) + fred := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, topUp) + + originalCodeID := StoreHackatomExampleContract(t, ctx, keepers).CodeID + newCodeID := StoreHackatomExampleContract(t, ctx, keepers).CodeID + require.NotEqual(t, originalCodeID, newCodeID) + + anyAddr := RandomAccountAddress(t) + newVerifierAddr := RandomAccountAddress(t) + initMsgBz := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: anyAddr, + }.GetBytes(t) + migMsg := struct { + Verifier sdk.AccAddress `json:"verifier"` + }{Verifier: newVerifierAddr} + migMsgBz, err := json.Marshal(migMsg) + + contractAddr, _, err := keeper.Instantiate(ctx, originalCodeID, creator, creator, initMsgBz, "demo contract", nil) + + params := keeper.GetParams(ctx) + params.ContractStatusAccess = types.AccessTypeOnlyAddress.With(creator) + keeper.setParams(ctx, params) + err = keeper.UpdateContractStatus(ctx, contractAddr, creator, types.ContractStatusInactive) + require.NoError(t, err) + _, err = keeper.Migrate(ctx, contractAddr, creator, newCodeID, migMsgBz) + require.True(t, types.ErrInvalid.Is(err), "expected %v but got %+v", types.ErrInvalid, err) +} + type sudoMsg struct { // This is a tongue-in-check demo command. This is not the intended purpose of Sudo. // Here we show that some priviledged Go module can make a call that should never be exposed @@ -1215,6 +1287,42 @@ func TestUpdateContractAdmin(t *testing.T) { } } +func TestUpdateContractAdminInactiveContract(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, deposit.Add(deposit...)) + fred := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, topUp) + + wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + originalContractID, err := keeper.Create(ctx, creator, wasmCode, "", "", nil) + require.NoError(t, err) + + _, _, anyAddr := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: anyAddr, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + addr, _, err := keeper.Instantiate(ctx, originalContractID, creator, fred, initMsgBz, "demo contract", nil) + require.NoError(t, err) + + params := keeper.GetParams(ctx) + params.ContractStatusAccess = types.AccessTypeOnlyAddress.With(creator) + keeper.setParams(ctx, params) + err = keeper.UpdateContractStatus(ctx, addr, creator, types.ContractStatusInactive) + require.NoError(t, err) + + err = keeper.UpdateContractAdmin(ctx, addr, fred, anyAddr) + require.True(t, types.ErrInvalid.Is(err), "expected %v but got %+v", types.ErrInvalid, err) +} + func TestClearContractAdmin(t *testing.T) { ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil) accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper @@ -1281,6 +1389,42 @@ func TestClearContractAdmin(t *testing.T) { } } +func TestClearContractAdminInactiveContract(t *testing.T) { + ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil) + accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper + + deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000)) + topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000)) + creator := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, deposit.Add(deposit...)) + fred := createFakeFundedAccount(t, ctx, accKeeper, bankKeeper, topUp) + + wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm") + require.NoError(t, err) + + originalContractID, err := keeper.Create(ctx, creator, wasmCode, "", "", nil) + require.NoError(t, err) + + _, _, anyAddr := keyPubAddr() + initMsg := HackatomExampleInitMsg{ + Verifier: fred, + Beneficiary: anyAddr, + } + initMsgBz, err := json.Marshal(initMsg) + require.NoError(t, err) + + addr, _, err := keeper.Instantiate(ctx, originalContractID, creator, fred, initMsgBz, "demo contract", nil) + require.NoError(t, err) + + params := keeper.GetParams(ctx) + params.ContractStatusAccess = types.AccessTypeOnlyAddress.With(creator) + keeper.setParams(ctx, params) + err = keeper.UpdateContractStatus(ctx, addr, creator, types.ContractStatusInactive) + require.NoError(t, err) + + err = keeper.ClearContractAdmin(ctx, addr, fred) + require.True(t, types.ErrInvalid.Is(err), "expected %v but got %+v", types.ErrInvalid, err) +} + func TestUpdateContractStatus(t *testing.T) { ctx, keepers := CreateTestInput(t, false, SupportedFeatures, nil, nil) accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.WasmKeeper, keepers.BankKeeper