github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/keeper/keeper_test.go (about)

     1  package keeper
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"math"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
    14  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    15  
    16  	wasmvm "github.com/CosmWasm/wasmvm"
    17  	wasmvmtypes "github.com/CosmWasm/wasmvm/types"
    18  
    19  	stypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store/types"
    20  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    21  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    22  	authtypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/types"
    23  	"github.com/stretchr/testify/assert"
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"github.com/fibonacci-chain/fbc/x/wasm/keeper/wasmtesting"
    27  	"github.com/fibonacci-chain/fbc/x/wasm/types"
    28  )
    29  
    30  // When migrated to go 1.16, embed package should be used instead.
    31  func init() {
    32  	b, err := ioutil.ReadFile("./testdata/hackatom.wasm")
    33  	if err != nil {
    34  		panic(err)
    35  	}
    36  	hackatomWasm = b
    37  }
    38  
    39  var hackatomWasm []byte
    40  
    41  func TestNewKeeper(t *testing.T) {
    42  	_, keepers := CreateTestInput(t, false, SupportedFeatures)
    43  	require.NotNil(t, keepers.ContractKeeper)
    44  }
    45  
    46  func TestCreateSuccess(t *testing.T) {
    47  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
    48  	keeper := keepers.ContractKeeper
    49  
    50  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
    51  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
    52  
    53  	em := sdk.NewEventManager()
    54  	newCtx := ctx
    55  	ctx.SetEventManager(em)
    56  	contractID, err := keeper.Create(newCtx, creator, hackatomWasm, nil)
    57  	require.NoError(t, err)
    58  	require.Equal(t, uint64(1), contractID)
    59  	// and verify content
    60  	storedCode, err := keepers.WasmKeeper.GetByteCode(ctx, contractID)
    61  	require.NoError(t, err)
    62  	require.Equal(t, hackatomWasm, storedCode)
    63  	// and events emitted
    64  	exp := sdk.Events{sdk.NewEvent("store_code", sdk.NewAttribute("code_id", "1"))}
    65  	assert.Equal(t, exp, newCtx.EventManager().Events())
    66  }
    67  
    68  func TestCreateNilCreatorAddress(t *testing.T) {
    69  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
    70  
    71  	_, err := keepers.ContractKeeper.Create(ctx, nil, hackatomWasm, nil)
    72  	require.Error(t, err, "nil creator is not allowed")
    73  }
    74  
    75  func TestCreateNilWasmCode(t *testing.T) {
    76  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
    77  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
    78  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
    79  
    80  	_, err := keepers.ContractKeeper.Create(ctx, creator, nil, nil)
    81  	require.Error(t, err, "nil WASM code is not allowed")
    82  }
    83  
    84  func TestCreateInvalidWasmCode(t *testing.T) {
    85  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
    86  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
    87  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
    88  
    89  	_, err := keepers.ContractKeeper.Create(ctx, creator, []byte("potatoes"), nil)
    90  	require.Error(t, err, "potatoes are not valid WASM code")
    91  }
    92  
    93  func TestCreateStoresInstantiatePermission(t *testing.T) {
    94  	var (
    95  		deposit                = sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
    96  		myAddr  sdk.AccAddress = bytes.Repeat([]byte{1}, types.SDKAddrLen)
    97  	)
    98  
    99  	specs := map[string]struct {
   100  		srcPermission types.AccessType
   101  		expInstConf   types.AccessConfig
   102  	}{
   103  		"default": {
   104  			srcPermission: types.DefaultParams().InstantiateDefaultPermission,
   105  			expInstConf:   types.AllowEverybody,
   106  		},
   107  		"everybody": {
   108  			srcPermission: types.AccessTypeEverybody,
   109  			expInstConf:   types.AllowEverybody,
   110  		},
   111  		"nobody": {
   112  			srcPermission: types.AccessTypeNobody,
   113  			expInstConf:   types.AllowNobody,
   114  		},
   115  		"onlyAddress with matching address": {
   116  			srcPermission: types.AccessTypeOnlyAddress,
   117  			expInstConf:   types.AccessConfig{Permission: types.AccessTypeOnlyAddress, Address: myAddr.String()},
   118  		},
   119  	}
   120  	for msg, spec := range specs {
   121  		t.Run(msg, func(t *testing.T) {
   122  			ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   123  			accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.ContractKeeper, keepers.BankKeeper
   124  			keepers.WasmKeeper.SetParams(ctx, types.Params{
   125  				CodeUploadAccess:             types.AllowEverybody,
   126  				InstantiateDefaultPermission: spec.srcPermission,
   127  			})
   128  			fundAccounts(t, ctx, accKeeper, bankKeeper, keepers.supplyKeepr, myAddr, deposit)
   129  
   130  			codeID, err := keeper.Create(ctx, myAddr, hackatomWasm, nil)
   131  			require.NoError(t, err)
   132  
   133  			codeInfo := keepers.WasmKeeper.GetCodeInfo(ctx, codeID)
   134  			require.NotNil(t, codeInfo)
   135  			assert.True(t, spec.expInstConf.Equals(codeInfo.InstantiateConfig), "got %#v", codeInfo.InstantiateConfig)
   136  		})
   137  	}
   138  }
   139  
   140  func TestCreateWithParamPermissions(t *testing.T) {
   141  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   142  	keeper := keepers.ContractKeeper
   143  
   144  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   145  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   146  	otherAddr := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   147  
   148  	specs := map[string]struct {
   149  		srcPermission types.AccessConfig
   150  		expError      *sdkerrors.Error
   151  	}{
   152  		"default": {
   153  			srcPermission: types.DefaultUploadAccess,
   154  			expError:      sdkerrors.ErrUnauthorized,
   155  		},
   156  		"everybody": {
   157  			srcPermission: types.AllowEverybody,
   158  		},
   159  		"nobody": {
   160  			srcPermission: types.AllowNobody,
   161  			expError:      sdkerrors.ErrUnauthorized,
   162  		},
   163  		"onlyAddress with matching address": {
   164  			srcPermission: types.AccessTypeOnlyAddress.With(creator),
   165  		},
   166  		"onlyAddress with non matching address": {
   167  			srcPermission: types.AccessTypeOnlyAddress.With(otherAddr),
   168  			expError:      sdkerrors.ErrUnauthorized,
   169  		},
   170  	}
   171  	for msg, spec := range specs {
   172  		t.Run(msg, func(t *testing.T) {
   173  			params := types.TestParams()
   174  			params.CodeUploadAccess = spec.srcPermission
   175  			keepers.WasmKeeper.SetParams(ctx, params)
   176  			_, err := keeper.Create(ctx, creator, hackatomWasm, nil)
   177  			require.True(t, spec.expError.Is(err), err)
   178  			if spec.expError != nil {
   179  				return
   180  			}
   181  		})
   182  	}
   183  }
   184  
   185  // ensure that the user cannot set the code instantiate permission to something more permissive
   186  // than the default
   187  func TestEnforceValidPermissionsOnCreate(t *testing.T) {
   188  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   189  	keeper := keepers.WasmKeeper
   190  	contractKeeper := keepers.ContractKeeper
   191  
   192  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   193  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   194  	other := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   195  
   196  	onlyCreator := types.AccessTypeOnlyAddress.With(creator)
   197  	onlyOther := types.AccessTypeOnlyAddress.With(other)
   198  
   199  	specs := map[string]struct {
   200  		defaultPermssion    types.AccessType
   201  		requestedPermission *types.AccessConfig
   202  		// grantedPermission is set iff no error
   203  		grantedPermission types.AccessConfig
   204  		// expError is nil iff the request is allowed
   205  		expError *sdkerrors.Error
   206  	}{
   207  		"override everybody": {
   208  			defaultPermssion:    types.AccessTypeEverybody,
   209  			requestedPermission: &onlyCreator,
   210  			grantedPermission:   onlyCreator,
   211  		},
   212  		"default to everybody": {
   213  			defaultPermssion:    types.AccessTypeEverybody,
   214  			requestedPermission: nil,
   215  			grantedPermission:   types.AccessConfig{Permission: types.AccessTypeEverybody},
   216  		},
   217  		"explicitly set everybody": {
   218  			defaultPermssion:    types.AccessTypeEverybody,
   219  			requestedPermission: &types.AccessConfig{Permission: types.AccessTypeEverybody},
   220  			grantedPermission:   types.AccessConfig{Permission: types.AccessTypeEverybody},
   221  		},
   222  		"cannot override nobody": {
   223  			defaultPermssion:    types.AccessTypeNobody,
   224  			requestedPermission: &onlyCreator,
   225  			expError:            sdkerrors.ErrUnauthorized,
   226  		},
   227  		"default to nobody": {
   228  			defaultPermssion:    types.AccessTypeNobody,
   229  			requestedPermission: nil,
   230  			grantedPermission:   types.AccessConfig{Permission: types.AccessTypeNobody},
   231  		},
   232  		"only defaults to code creator": {
   233  			defaultPermssion:    types.AccessTypeOnlyAddress,
   234  			requestedPermission: nil,
   235  			grantedPermission:   onlyCreator,
   236  		},
   237  		"can explicitly set to code creator": {
   238  			defaultPermssion:    types.AccessTypeOnlyAddress,
   239  			requestedPermission: &onlyCreator,
   240  			grantedPermission:   onlyCreator,
   241  		},
   242  		"cannot override which address in only": {
   243  			defaultPermssion:    types.AccessTypeOnlyAddress,
   244  			requestedPermission: &onlyOther,
   245  			expError:            sdkerrors.ErrUnauthorized,
   246  		},
   247  	}
   248  	for msg, spec := range specs {
   249  		t.Run(msg, func(t *testing.T) {
   250  			params := types.TestParams()
   251  			params.InstantiateDefaultPermission = spec.defaultPermssion
   252  			keeper.SetParams(ctx, params)
   253  			codeID, err := contractKeeper.Create(ctx, creator, hackatomWasm, spec.requestedPermission)
   254  			require.True(t, spec.expError.Is(err), err)
   255  			if spec.expError == nil {
   256  				codeInfo := keeper.GetCodeInfo(ctx, codeID)
   257  				require.Equal(t, codeInfo.InstantiateConfig, spec.grantedPermission)
   258  			}
   259  		})
   260  	}
   261  }
   262  
   263  func TestCreateDuplicate(t *testing.T) {
   264  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   265  	keeper := keepers.ContractKeeper
   266  
   267  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   268  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   269  
   270  	// create one copy
   271  	contractID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
   272  	require.NoError(t, err)
   273  	require.Equal(t, uint64(1), contractID)
   274  
   275  	// create second copy
   276  	duplicateID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
   277  	require.NoError(t, err)
   278  	require.Equal(t, uint64(2), duplicateID)
   279  
   280  	// and verify both content is proper
   281  	storedCode, err := keepers.WasmKeeper.GetByteCode(ctx, contractID)
   282  	require.NoError(t, err)
   283  	require.Equal(t, hackatomWasm, storedCode)
   284  	storedCode, err = keepers.WasmKeeper.GetByteCode(ctx, duplicateID)
   285  	require.NoError(t, err)
   286  	require.Equal(t, hackatomWasm, storedCode)
   287  }
   288  
   289  func TestCreateWithSimulation(t *testing.T) {
   290  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   291  	ctx.SetBlockHeader(abci.Header{Height: 1})
   292  	ctx.SetGasMeter(stypes.NewInfiniteGasMeter())
   293  
   294  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   295  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   296  
   297  	// create this once in simulation mode
   298  	contractID, err := keepers.ContractKeeper.Create(ctx, creator, hackatomWasm, nil)
   299  	require.NoError(t, err)
   300  	require.Equal(t, uint64(1), contractID)
   301  
   302  	// then try to create it in non-simulation mode (should not fail)
   303  	ctx, keepers = CreateTestInput(t, false, SupportedFeatures)
   304  	ctx.SetGasMeter(sdk.NewGasMeter(10_000_000))
   305  	creator = keepers.Faucet.NewFundedAccount(ctx, deposit...)
   306  	contractID, err = keepers.ContractKeeper.Create(ctx, creator, hackatomWasm, nil)
   307  
   308  	require.NoError(t, err)
   309  	require.Equal(t, uint64(1), contractID)
   310  
   311  	// and verify content
   312  	code, err := keepers.WasmKeeper.GetByteCode(ctx, contractID)
   313  	require.NoError(t, err)
   314  	require.Equal(t, code, hackatomWasm)
   315  }
   316  
   317  func TestIsSimulationMode(t *testing.T) {
   318  	genesisCtx := sdk.Context{}
   319  	genesisCtx.SetBlockHeader(abci.Header{})
   320  	genesisCtx.SetGasMeter(stypes.NewInfiniteGasMeter())
   321  
   322  	regularBlockCtx := sdk.Context{}
   323  	regularBlockCtx.SetBlockHeader(abci.Header{Height: 1})
   324  	regularBlockCtx.SetGasMeter(stypes.NewGasMeter(10000000))
   325  
   326  	simulationCtx := sdk.Context{}
   327  	simulationCtx.SetBlockHeader(abci.Header{Height: 1})
   328  	simulationCtx.SetGasMeter(stypes.NewInfiniteGasMeter())
   329  	specs := map[string]struct {
   330  		ctx sdk.Context
   331  		exp bool
   332  	}{
   333  		"genesis block": {
   334  			ctx: genesisCtx,
   335  			exp: false,
   336  		},
   337  		"any regular block": {
   338  			ctx: regularBlockCtx,
   339  			exp: false,
   340  		},
   341  		"simulation": {
   342  			ctx: simulationCtx,
   343  			exp: true,
   344  		},
   345  	}
   346  	for msg := range specs {
   347  		t.Run(msg, func(t *testing.T) {
   348  			// assert.Equal(t, spec.exp, isSimulationMode(spec.ctx))
   349  		})
   350  	}
   351  }
   352  
   353  func TestCreateWithGzippedPayload(t *testing.T) {
   354  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   355  	keeper := keepers.ContractKeeper
   356  
   357  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   358  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   359  
   360  	wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm.gzip")
   361  	require.NoError(t, err, "reading gzipped WASM code")
   362  
   363  	contractID, err := keeper.Create(ctx, creator, wasmCode, nil)
   364  	require.NoError(t, err)
   365  	require.Equal(t, uint64(1), contractID)
   366  	// and verify content
   367  	storedCode, err := keepers.WasmKeeper.GetByteCode(ctx, contractID)
   368  	require.NoError(t, err)
   369  	require.Equal(t, hackatomWasm, storedCode)
   370  }
   371  
   372  func TestInstantiate(t *testing.T) {
   373  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   374  	keeper := keepers.ContractKeeper
   375  
   376  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   377  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   378  
   379  	codeID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
   380  	require.NoError(t, err)
   381  
   382  	_, _, bob := keyPubAddr()
   383  	_, _, fred := keyPubAddr()
   384  
   385  	initMsg := HackatomExampleInitMsg{
   386  		Verifier:    fred,
   387  		Beneficiary: bob,
   388  	}
   389  	initMsgBz, err := json.Marshal(initMsg)
   390  	require.NoError(t, err)
   391  
   392  	gasBefore := ctx.GasMeter().GasConsumed()
   393  
   394  	em := sdk.NewEventManager()
   395  	// create with no balance is also legal
   396  	ctx.SetEventManager(em)
   397  	gotContractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, initMsgBz, "demo contract 1", nil)
   398  	require.NoError(t, err)
   399  	require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", gotContractAddr.String())
   400  
   401  	gasAfter := ctx.GasMeter().GasConsumed()
   402  	if types.EnableGasVerification {
   403  		require.Equal(t, uint64(0x16d87), gasAfter-gasBefore)
   404  	}
   405  
   406  	// ensure it is stored properly
   407  	info := keepers.WasmKeeper.GetContractInfo(ctx, gotContractAddr)
   408  	require.NotNil(t, info)
   409  	assert.Equal(t, creator.String(), info.Creator)
   410  	assert.Equal(t, codeID, info.CodeID)
   411  	assert.Equal(t, "demo contract 1", info.Label)
   412  
   413  	exp := []types.ContractCodeHistoryEntry{{
   414  		Operation: types.ContractCodeHistoryOperationTypeInit,
   415  		CodeID:    codeID,
   416  		Updated:   types.NewAbsoluteTxPosition(ctx),
   417  		Msg:       initMsgBz,
   418  	}}
   419  	assert.Equal(t, exp, keepers.WasmKeeper.GetContractHistory(ctx, gotContractAddr))
   420  
   421  	// and events emitted
   422  	expEvt := sdk.Events{
   423  		sdk.NewEvent("instantiate",
   424  			sdk.NewAttribute("_contract_address", gotContractAddr.String()), sdk.NewAttribute("code_id", "1")),
   425  		sdk.NewEvent("wasm",
   426  			sdk.NewAttribute("_contract_address", gotContractAddr.String()), sdk.NewAttribute("Let the", "hacking begin")),
   427  	}
   428  	assert.Equal(t, expEvt, em.Events())
   429  }
   430  
   431  func TestInstantiateWithDeposit(t *testing.T) {
   432  	var (
   433  		bob  = bytes.Repeat([]byte{1}, types.SDKAddrLen)
   434  		fred = bytes.Repeat([]byte{2}, types.SDKAddrLen)
   435  
   436  		deposit = sdk.NewCoins(sdk.NewInt64Coin("denom", 100))
   437  		initMsg = HackatomExampleInitMsg{Verifier: fred, Beneficiary: bob}
   438  	)
   439  
   440  	initMsgBz, err := json.Marshal(initMsg)
   441  	require.NoError(t, err)
   442  
   443  	specs := map[string]struct {
   444  		srcActor sdk.AccAddress
   445  		expError bool
   446  		fundAddr bool
   447  	}{
   448  		"address with funds": {
   449  			srcActor: bob,
   450  			fundAddr: true,
   451  		},
   452  		"address without funds": {
   453  			srcActor: bob,
   454  			expError: true,
   455  		},
   456  		"blocked address": {
   457  			srcActor: authtypes.NewModuleAddress(authtypes.FeeCollectorName),
   458  			fundAddr: true,
   459  			expError: false,
   460  		},
   461  	}
   462  	for msg, spec := range specs {
   463  		t.Run(msg, func(t *testing.T) {
   464  			ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   465  			accKeeper, bankKeeper, keeper := keepers.AccountKeeper, keepers.BankKeeper, keepers.ContractKeeper
   466  
   467  			if spec.fundAddr {
   468  				fundAccounts(t, ctx, accKeeper, bankKeeper, keepers.supplyKeepr, spec.srcActor, sdk.NewCoins(sdk.NewInt64Coin("denom", 200)))
   469  			}
   470  			contractID, err := keeper.Create(ctx, spec.srcActor, hackatomWasm, nil)
   471  			require.NoError(t, err)
   472  
   473  			// when
   474  			addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, spec.srcActor, nil, initMsgBz, "my label", deposit)
   475  			// then
   476  			if spec.expError {
   477  				require.Error(t, err)
   478  				return
   479  			}
   480  			require.NoError(t, err)
   481  			balances := bankKeeper.GetCoins(ctx, addr)
   482  			assert.Equal(t, deposit, balances)
   483  		})
   484  	}
   485  }
   486  
   487  func TestInstantiateWithPermissions(t *testing.T) {
   488  	var (
   489  		deposit   = sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   490  		myAddr    = bytes.Repeat([]byte{1}, types.SDKAddrLen)
   491  		otherAddr = bytes.Repeat([]byte{2}, types.SDKAddrLen)
   492  		anyAddr   = bytes.Repeat([]byte{3}, types.SDKAddrLen)
   493  	)
   494  
   495  	initMsg := HackatomExampleInitMsg{
   496  		Verifier:    anyAddr,
   497  		Beneficiary: anyAddr,
   498  	}
   499  	initMsgBz, err := json.Marshal(initMsg)
   500  	require.NoError(t, err)
   501  
   502  	specs := map[string]struct {
   503  		srcPermission types.AccessConfig
   504  		srcActor      sdk.AccAddress
   505  		expError      *sdkerrors.Error
   506  	}{
   507  		"default": {
   508  			srcPermission: types.DefaultUploadAccess,
   509  			srcActor:      anyAddr,
   510  			expError:      sdkerrors.ErrUnauthorized,
   511  		},
   512  		"everybody": {
   513  			srcPermission: types.AllowEverybody,
   514  			srcActor:      anyAddr,
   515  		},
   516  		"nobody": {
   517  			srcPermission: types.AllowNobody,
   518  			srcActor:      myAddr,
   519  			expError:      sdkerrors.ErrUnauthorized,
   520  		},
   521  		"onlyAddress with matching address": {
   522  			srcPermission: types.AccessTypeOnlyAddress.With(myAddr),
   523  			srcActor:      myAddr,
   524  		},
   525  		"onlyAddress with non matching address": {
   526  			srcPermission: types.AccessTypeOnlyAddress.With(otherAddr),
   527  			expError:      sdkerrors.ErrUnauthorized,
   528  		},
   529  	}
   530  	for msg, spec := range specs {
   531  		t.Run(msg, func(t *testing.T) {
   532  			ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   533  			accKeeper, bankKeeper, keeper := keepers.AccountKeeper, keepers.BankKeeper, keepers.ContractKeeper
   534  			fundAccounts(t, ctx, accKeeper, bankKeeper, keepers.supplyKeepr, spec.srcActor, deposit)
   535  
   536  			contractID, err := keeper.Create(ctx, myAddr, hackatomWasm, &spec.srcPermission)
   537  			require.NoError(t, err)
   538  
   539  			_, _, err = keepers.ContractKeeper.Instantiate(ctx, contractID, spec.srcActor, nil, initMsgBz, "demo contract 1", nil)
   540  			fmt.Printf("case: %s result: %v \n", msg, err)
   541  			assert.True(t, spec.expError.Is(err), "got %+v", err)
   542  		})
   543  	}
   544  }
   545  
   546  func TestInstantiateWithNonExistingCodeID(t *testing.T) {
   547  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   548  
   549  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   550  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   551  
   552  	initMsg := HackatomExampleInitMsg{}
   553  	initMsgBz, err := json.Marshal(initMsg)
   554  	require.NoError(t, err)
   555  
   556  	const nonExistingCodeID = 9999
   557  	addr, _, err := keepers.ContractKeeper.Instantiate(ctx, nonExistingCodeID, creator, nil, initMsgBz, "demo contract 2", nil)
   558  	require.True(t, types.ErrNotFound.Is(err), err)
   559  	require.Nil(t, addr)
   560  }
   561  
   562  func TestInstantiateWithContractDataResponse(t *testing.T) {
   563  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   564  
   565  	wasmerMock := &wasmtesting.MockWasmer{
   566  		InstantiateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
   567  			return &wasmvmtypes.Response{Data: []byte("my-response-data")}, 0, nil
   568  		},
   569  		AnalyzeCodeFn: wasmtesting.WithoutIBCAnalyzeFn,
   570  		CreateFn:      wasmtesting.NoOpCreateFn,
   571  	}
   572  
   573  	example := StoreRandomContract(t, ctx, keepers, wasmerMock)
   574  	_, data, err := keepers.ContractKeeper.Instantiate(ctx, example.CodeID, example.CreatorAddr, nil, nil, "test", nil)
   575  	require.NoError(t, err)
   576  	assert.Equal(t, []byte("my-response-data"), data)
   577  }
   578  
   579  func TestExecute(t *testing.T) {
   580  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   581  	accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.ContractKeeper, keepers.BankKeeper
   582  
   583  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   584  	topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
   585  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
   586  	fred := keepers.Faucet.NewFundedAccount(ctx, topUp...)
   587  
   588  	contractID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
   589  	require.NoError(t, err)
   590  
   591  	_, _, bob := keyPubAddr()
   592  	initMsg := HackatomExampleInitMsg{
   593  		Verifier:    fred,
   594  		Beneficiary: bob,
   595  	}
   596  	initMsgBz, err := json.Marshal(initMsg)
   597  	require.NoError(t, err)
   598  
   599  	addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit)
   600  	require.NoError(t, err)
   601  	require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", addr.String())
   602  
   603  	// ensure bob doesn't exist
   604  	bobAcct := accKeeper.GetAccount(ctx, bob)
   605  	require.Nil(t, bobAcct)
   606  
   607  	// ensure funder has reduced balance
   608  	creatorAcct := accKeeper.GetAccount(ctx, creator)
   609  	require.NotNil(t, creatorAcct)
   610  	// we started at 2*deposit, should have spent one above
   611  	assert.Equal(t, deposit, bankKeeper.GetCoins(ctx, creatorAcct.GetAddress()))
   612  
   613  	// ensure contract has updated balance
   614  	contractAcct := accKeeper.GetAccount(ctx, addr)
   615  	require.NotNil(t, contractAcct)
   616  	assert.Equal(t, deposit, bankKeeper.GetCoins(ctx, contractAcct.GetAddress()))
   617  
   618  	// unauthorized - trialCtx so we don't change state
   619  	trialCtx := ctx
   620  	trialCtx.SetMultiStore(ctx.MultiStore().CacheWrap().(sdk.MultiStore))
   621  	res, err := keepers.ContractKeeper.Execute(trialCtx, addr, creator, []byte(`{"release":{}}`), nil)
   622  	require.Error(t, err)
   623  	require.True(t, errors.Is(err, types.ErrExecuteFailed))
   624  	require.Equal(t, "execute wasm contract failed: Unauthorized", err.Error())
   625  
   626  	// verifier can execute, and get proper gas amount
   627  	start := time.Now()
   628  	gasBefore := ctx.GasMeter().GasConsumed()
   629  	em := sdk.NewEventManager()
   630  	// when
   631  	ctx.SetEventManager(em)
   632  	res, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"release":{}}`), topUp)
   633  	diff := time.Now().Sub(start)
   634  	require.NoError(t, err)
   635  	require.NotNil(t, res)
   636  
   637  	// make sure gas is properly deducted from ctx
   638  	gasAfter := ctx.GasMeter().GasConsumed()
   639  	if types.EnableGasVerification {
   640  		require.Equal(t, uint64(0x19c71), gasAfter-gasBefore)
   641  	}
   642  	// ensure bob now exists and got both payments released
   643  	bobAcct = accKeeper.GetAccount(ctx, bob)
   644  	require.NotNil(t, bobAcct)
   645  	balance := bankKeeper.GetCoins(ctx, bobAcct.GetAddress())
   646  	assert.Equal(t, deposit.Add(topUp...), balance)
   647  
   648  	// ensure contract has updated balance
   649  	contractAcct = accKeeper.GetAccount(ctx, addr)
   650  	require.NotNil(t, contractAcct)
   651  	assert.Equal(t, sdk.Coins{}.String(), bankKeeper.GetCoins(ctx, contractAcct.GetAddress()).String())
   652  
   653  	// and events emitted
   654  	require.Len(t, em.Events(), 4)
   655  	expEvt := sdk.NewEvent("execute",
   656  		sdk.NewAttribute("_contract_address", addr.String()))
   657  	assert.Equal(t, expEvt, em.Events()[0], prettyEvents(t, em.Events()))
   658  
   659  	t.Logf("Duration: %v (%d gas)\n", diff, gasAfter-gasBefore)
   660  }
   661  
   662  func TestExecuteWithDeposit(t *testing.T) {
   663  	var (
   664  		bob         = bytes.Repeat([]byte{1}, types.SDKAddrLen)
   665  		fred        = bytes.Repeat([]byte{2}, types.SDKAddrLen)
   666  		blockedAddr = authtypes.NewModuleAddress(auth.FeeCollectorName)
   667  		deposit     = sdk.NewCoins(sdk.NewInt64Coin("denom", 100))
   668  	)
   669  
   670  	type bankParams struct {
   671  		DefaultSendEnabled bool
   672  	}
   673  
   674  	specs := map[string]struct {
   675  		srcActor      sdk.AccAddress
   676  		beneficiary   sdk.AccAddress
   677  		newBankParams *bankParams
   678  		expError      bool
   679  		fundAddr      bool
   680  	}{
   681  		"actor with funds": {
   682  			srcActor:    bob,
   683  			fundAddr:    true,
   684  			beneficiary: fred,
   685  		},
   686  		"actor without funds": {
   687  			srcActor:    bob,
   688  			beneficiary: fred,
   689  			expError:    true,
   690  		},
   691  		"blocked address as actor": {
   692  			srcActor:    blockedAddr,
   693  			fundAddr:    true,
   694  			beneficiary: fred,
   695  			expError:    false,
   696  		},
   697  		"coin transfer with all transfers disabled": {
   698  			srcActor:      bob,
   699  			fundAddr:      true,
   700  			beneficiary:   fred,
   701  			newBankParams: &bankParams{DefaultSendEnabled: false},
   702  			expError:      true,
   703  		},
   704  		"blocked address as beneficiary": {
   705  			srcActor:    bob,
   706  			fundAddr:    true,
   707  			beneficiary: blockedAddr,
   708  			expError:    true,
   709  		},
   710  	}
   711  	for msg, spec := range specs {
   712  		t.Run(msg, func(t *testing.T) {
   713  			ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   714  			accKeeper, bankKeeper, keeper := keepers.AccountKeeper, keepers.BankKeeper, keepers.ContractKeeper
   715  			if spec.newBankParams != nil {
   716  				bankKeeper.SetSendEnabled(ctx, spec.newBankParams.DefaultSendEnabled)
   717  			}
   718  			if spec.fundAddr {
   719  				fundAccounts(t, ctx, accKeeper, bankKeeper, keepers.supplyKeepr, spec.srcActor, sdk.NewCoins(sdk.NewInt64Coin("denom", 200)))
   720  			}
   721  			codeID, err := keeper.Create(ctx, spec.srcActor, hackatomWasm, nil)
   722  			require.NoError(t, err)
   723  
   724  			initMsg := HackatomExampleInitMsg{Verifier: spec.srcActor, Beneficiary: spec.beneficiary}
   725  			initMsgBz, err := json.Marshal(initMsg)
   726  			require.NoError(t, err)
   727  
   728  			contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, codeID, spec.srcActor, nil, initMsgBz, "my label", nil)
   729  			require.NoError(t, err)
   730  
   731  			// when
   732  			_, err = keepers.ContractKeeper.Execute(ctx, contractAddr, spec.srcActor, []byte(`{"release":{}}`), deposit)
   733  
   734  			// then
   735  			if spec.expError {
   736  				require.Error(t, err)
   737  				return
   738  			}
   739  			require.NoError(t, err)
   740  			balances := bankKeeper.GetCoins(ctx, spec.beneficiary)
   741  			assert.Equal(t, deposit, balances)
   742  		})
   743  	}
   744  }
   745  
   746  func TestExecuteWithNonExistingAddress(t *testing.T) {
   747  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   748  	keeper := keepers.ContractKeeper
   749  
   750  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   751  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
   752  
   753  	// unauthorized - trialCtx so we don't change state
   754  	nonExistingAddress := RandomAccountAddress(t)
   755  	_, err := keeper.Execute(ctx, nonExistingAddress, creator, []byte(`{}`), nil)
   756  	require.True(t, types.ErrNotFound.Is(err), err)
   757  }
   758  
   759  func TestExecuteWithPanic(t *testing.T) {
   760  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   761  	keeper := keepers.ContractKeeper
   762  
   763  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   764  	topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
   765  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
   766  	fred := keepers.Faucet.NewFundedAccount(ctx, topUp...)
   767  
   768  	contractID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
   769  	require.NoError(t, err)
   770  
   771  	_, _, bob := keyPubAddr()
   772  	initMsg := HackatomExampleInitMsg{
   773  		Verifier:    fred,
   774  		Beneficiary: bob,
   775  	}
   776  	initMsgBz, err := json.Marshal(initMsg)
   777  	require.NoError(t, err)
   778  
   779  	addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 4", deposit)
   780  	require.NoError(t, err)
   781  
   782  	// let's make sure we get a reasonable error, no panic/crash
   783  	_, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"panic":{}}`), topUp)
   784  	require.Error(t, err)
   785  	require.True(t, errors.Is(err, types.ErrExecuteFailed))
   786  	// test with contains as "Display" implementation of the Wasmer "RuntimeError" is different for Mac and Linux
   787  	assert.Contains(t, err.Error(), "Error calling the VM: Error executing Wasm: Wasmer runtime error: RuntimeError: unreachable")
   788  }
   789  
   790  func TestExecuteWithCpuLoop(t *testing.T) {
   791  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   792  	keeper := keepers.ContractKeeper
   793  
   794  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   795  	topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
   796  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
   797  	fred := keepers.Faucet.NewFundedAccount(ctx, topUp...)
   798  
   799  	contractID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
   800  	require.NoError(t, err)
   801  
   802  	_, _, bob := keyPubAddr()
   803  	initMsg := HackatomExampleInitMsg{
   804  		Verifier:    fred,
   805  		Beneficiary: bob,
   806  	}
   807  	initMsgBz, err := json.Marshal(initMsg)
   808  	require.NoError(t, err)
   809  
   810  	addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 5", deposit)
   811  	require.NoError(t, err)
   812  
   813  	// make sure we set a limit before calling
   814  	var gasLimit uint64 = 400_000
   815  	ctx.SetGasMeter(sdk.NewGasMeter(gasLimit))
   816  	require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed())
   817  
   818  	// ensure we get an out of gas panic
   819  	defer func() {
   820  		r := recover()
   821  		require.NotNil(t, r)
   822  		_, ok := r.(sdk.ErrorOutOfGas)
   823  		require.True(t, ok, "%v", r)
   824  	}()
   825  
   826  	// this should throw out of gas exception (panic)
   827  	_, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"cpu_loop":{}}`), nil)
   828  	require.True(t, false, "We must panic before this line")
   829  }
   830  
   831  func TestExecuteWithStorageLoop(t *testing.T) {
   832  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   833  	keeper := keepers.ContractKeeper
   834  
   835  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   836  	topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
   837  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
   838  	fred := keepers.Faucet.NewFundedAccount(ctx, topUp...)
   839  
   840  	contractID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
   841  	require.NoError(t, err)
   842  
   843  	_, _, bob := keyPubAddr()
   844  	initMsg := HackatomExampleInitMsg{
   845  		Verifier:    fred,
   846  		Beneficiary: bob,
   847  	}
   848  	initMsgBz, err := json.Marshal(initMsg)
   849  	require.NoError(t, err)
   850  
   851  	addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 6", deposit)
   852  	require.NoError(t, err)
   853  
   854  	// make sure we set a limit before calling
   855  	var gasLimit uint64 = 400_002
   856  	ctx.SetGasMeter(sdk.NewGasMeter(gasLimit))
   857  	require.Equal(t, uint64(0), ctx.GasMeter().GasConsumed())
   858  
   859  	// ensure we get an out of gas panic
   860  	defer func() {
   861  		r := recover()
   862  		require.NotNil(t, r)
   863  		_, ok := r.(sdk.ErrorOutOfGas)
   864  		require.True(t, ok, "%v", r)
   865  	}()
   866  
   867  	// this should throw out of gas exception (panic)
   868  	_, err = keepers.ContractKeeper.Execute(ctx, addr, fred, []byte(`{"storage_loop":{}}`), nil)
   869  	require.True(t, false, "We must panic before this line")
   870  }
   871  
   872  func TestMigrate(t *testing.T) {
   873  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   874  	keeper := keepers.ContractKeeper
   875  
   876  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
   877  	topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
   878  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
   879  	fred := keepers.Faucet.NewFundedAccount(ctx, topUp...)
   880  
   881  	originalCodeID := StoreHackatomExampleContract(t, ctx, keepers).CodeID
   882  	newCodeID := StoreHackatomExampleContract(t, ctx, keepers).CodeID
   883  	ibcCodeID := StoreIBCReflectContract(t, ctx, keepers).CodeID
   884  	require.NotEqual(t, originalCodeID, newCodeID)
   885  
   886  	anyAddr := RandomAccountAddress(t)
   887  	newVerifierAddr := RandomAccountAddress(t)
   888  	initMsgBz := HackatomExampleInitMsg{
   889  		Verifier:    fred,
   890  		Beneficiary: anyAddr,
   891  	}.GetBytes(t)
   892  
   893  	migMsg := struct {
   894  		Verifier sdk.AccAddress `json:"verifier"`
   895  	}{Verifier: newVerifierAddr}
   896  	migMsgBz, err := json.Marshal(migMsg)
   897  	require.NoError(t, err)
   898  
   899  	specs := map[string]struct {
   900  		admin                sdk.AccAddress
   901  		overrideContractAddr sdk.AccAddress
   902  		caller               sdk.AccAddress
   903  		fromCodeID           uint64
   904  		toCodeID             uint64
   905  		migrateMsg           []byte
   906  		expErr               *sdkerrors.Error
   907  		expVerifier          sdk.AccAddress
   908  		expIBCPort           bool
   909  		initMsg              []byte
   910  	}{
   911  		"all good with same code id": {
   912  			admin:       creator,
   913  			caller:      creator,
   914  			initMsg:     initMsgBz,
   915  			fromCodeID:  originalCodeID,
   916  			toCodeID:    originalCodeID,
   917  			migrateMsg:  migMsgBz,
   918  			expVerifier: newVerifierAddr,
   919  		},
   920  		"all good with different code id": {
   921  			admin:       creator,
   922  			caller:      creator,
   923  			initMsg:     initMsgBz,
   924  			fromCodeID:  originalCodeID,
   925  			toCodeID:    newCodeID,
   926  			migrateMsg:  migMsgBz,
   927  			expVerifier: newVerifierAddr,
   928  		},
   929  		"all good with admin set": {
   930  			admin:       fred,
   931  			caller:      fred,
   932  			initMsg:     initMsgBz,
   933  			fromCodeID:  originalCodeID,
   934  			toCodeID:    newCodeID,
   935  			migrateMsg:  migMsgBz,
   936  			expVerifier: newVerifierAddr,
   937  		},
   938  		"adds IBC port for IBC enabled contracts": {
   939  			admin:       fred,
   940  			caller:      fred,
   941  			initMsg:     initMsgBz,
   942  			fromCodeID:  originalCodeID,
   943  			toCodeID:    ibcCodeID,
   944  			migrateMsg:  []byte(`{}`),
   945  			expIBCPort:  true,
   946  			expVerifier: fred, // not updated
   947  		},
   948  		"prevent migration when admin was not set on instantiate": {
   949  			caller:     creator,
   950  			initMsg:    initMsgBz,
   951  			fromCodeID: originalCodeID,
   952  			toCodeID:   originalCodeID,
   953  			expErr:     sdkerrors.ErrUnauthorized,
   954  		},
   955  		"prevent migration when not sent by admin": {
   956  			caller:     creator,
   957  			admin:      fred,
   958  			initMsg:    initMsgBz,
   959  			fromCodeID: originalCodeID,
   960  			toCodeID:   originalCodeID,
   961  			expErr:     sdkerrors.ErrUnauthorized,
   962  		},
   963  		"fail with non existing code id": {
   964  			admin:      creator,
   965  			caller:     creator,
   966  			initMsg:    initMsgBz,
   967  			fromCodeID: originalCodeID,
   968  			toCodeID:   99999,
   969  			expErr:     sdkerrors.ErrInvalidRequest,
   970  		},
   971  		"fail with non existing contract addr": {
   972  			admin:                creator,
   973  			caller:               creator,
   974  			initMsg:              initMsgBz,
   975  			overrideContractAddr: anyAddr,
   976  			fromCodeID:           originalCodeID,
   977  			toCodeID:             originalCodeID,
   978  			expErr:               sdkerrors.ErrInvalidRequest,
   979  		},
   980  		"fail in contract with invalid migrate msg": {
   981  			admin:      creator,
   982  			caller:     creator,
   983  			initMsg:    initMsgBz,
   984  			fromCodeID: originalCodeID,
   985  			toCodeID:   originalCodeID,
   986  			migrateMsg: bytes.Repeat([]byte{0x1}, 7),
   987  			expErr:     types.ErrMigrationFailed,
   988  		},
   989  		"fail in contract without migrate msg": {
   990  			admin:      creator,
   991  			caller:     creator,
   992  			initMsg:    initMsgBz,
   993  			fromCodeID: originalCodeID,
   994  			toCodeID:   originalCodeID,
   995  			expErr:     types.ErrMigrationFailed,
   996  		},
   997  		"fail when no IBC callbacks": {
   998  			admin:      fred,
   999  			caller:     fred,
  1000  			initMsg:    IBCReflectInitMsg{ReflectCodeID: StoreReflectContract(t, ctx, keepers)}.GetBytes(t),
  1001  			fromCodeID: ibcCodeID,
  1002  			toCodeID:   newCodeID,
  1003  			migrateMsg: migMsgBz,
  1004  			expErr:     types.ErrMigrationFailed,
  1005  		},
  1006  	}
  1007  
  1008  	for msg, spec := range specs {
  1009  		t.Run(msg, func(t *testing.T) {
  1010  			// given a contract instance
  1011  			ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
  1012  			contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, spec.fromCodeID, creator, spec.admin, spec.initMsg, "demo contract", nil)
  1013  			require.NoError(t, err)
  1014  			if spec.overrideContractAddr != nil {
  1015  				contractAddr = spec.overrideContractAddr
  1016  			}
  1017  			// when
  1018  			_, err = keeper.Migrate(ctx, contractAddr, spec.caller, spec.toCodeID, spec.migrateMsg)
  1019  
  1020  			// then
  1021  			require.True(t, spec.expErr.Is(err), "expected %v but got %+v", spec.expErr, err)
  1022  			if spec.expErr != nil {
  1023  				return
  1024  			}
  1025  			cInfo := keepers.WasmKeeper.GetContractInfo(ctx, contractAddr)
  1026  			assert.Equal(t, spec.toCodeID, cInfo.CodeID)
  1027  			assert.Equal(t, spec.expIBCPort, cInfo.IBCPortID != "", cInfo.IBCPortID)
  1028  
  1029  			expHistory := []types.ContractCodeHistoryEntry{{
  1030  				Operation: types.ContractCodeHistoryOperationTypeInit,
  1031  				CodeID:    spec.fromCodeID,
  1032  				Updated:   types.NewAbsoluteTxPosition(ctx),
  1033  				Msg:       initMsgBz,
  1034  			}, {
  1035  				Operation: types.ContractCodeHistoryOperationTypeMigrate,
  1036  				CodeID:    spec.toCodeID,
  1037  				Updated:   types.NewAbsoluteTxPosition(ctx),
  1038  				Msg:       spec.migrateMsg,
  1039  			}}
  1040  			assert.Equal(t, expHistory, keepers.WasmKeeper.GetContractHistory(ctx, contractAddr))
  1041  
  1042  			// and verify contract state
  1043  			raw := keepers.WasmKeeper.QueryRaw(ctx, contractAddr, []byte("config"))
  1044  			var stored map[string]string
  1045  			require.NoError(t, json.Unmarshal(raw, &stored))
  1046  			require.Contains(t, stored, "verifier")
  1047  			require.NoError(t, err)
  1048  			assert.Equal(t, spec.expVerifier.String(), stored["verifier"])
  1049  		})
  1050  	}
  1051  }
  1052  
  1053  func TestMigrateReplacesTheSecondIndex(t *testing.T) {
  1054  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1055  	example := InstantiateHackatomExampleContract(t, ctx, keepers)
  1056  
  1057  	// then assert a second index exists
  1058  	store := ctx.KVStore(keepers.WasmKeeper.storeKey)
  1059  	oldContractInfo := keepers.WasmKeeper.GetContractInfo(ctx, example.Contract)
  1060  	require.NotNil(t, oldContractInfo)
  1061  	createHistoryEntry := types.ContractCodeHistoryEntry{
  1062  		CodeID:  example.CodeID,
  1063  		Updated: types.NewAbsoluteTxPosition(ctx),
  1064  	}
  1065  	exists := store.Has(types.GetContractByCreatedSecondaryIndexKey(example.Contract, createHistoryEntry))
  1066  	require.True(t, exists)
  1067  
  1068  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) // increment for different block
  1069  	// when do migrate
  1070  	newCodeExample := StoreBurnerExampleContract(t, ctx, keepers)
  1071  	migMsgBz := BurnerExampleInitMsg{Payout: example.CreatorAddr}.GetBytes(t)
  1072  	_, err := keepers.ContractKeeper.Migrate(ctx, example.Contract, example.CreatorAddr, newCodeExample.CodeID, migMsgBz)
  1073  	require.NoError(t, err)
  1074  
  1075  	// then the new index exists
  1076  	migrateHistoryEntry := types.ContractCodeHistoryEntry{
  1077  		CodeID:  newCodeExample.CodeID,
  1078  		Updated: types.NewAbsoluteTxPosition(ctx),
  1079  	}
  1080  	exists = store.Has(types.GetContractByCreatedSecondaryIndexKey(example.Contract, migrateHistoryEntry))
  1081  	require.True(t, exists)
  1082  	// and the old index was removed
  1083  	exists = store.Has(types.GetContractByCreatedSecondaryIndexKey(example.Contract, createHistoryEntry))
  1084  	require.False(t, exists)
  1085  }
  1086  
  1087  func TestMigrateWithDispatchedMessage(t *testing.T) {
  1088  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1089  	keeper := keepers.ContractKeeper
  1090  
  1091  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
  1092  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
  1093  	fred := keepers.Faucet.NewFundedAccount(ctx, sdk.NewInt64Coin("denom", 5000))
  1094  
  1095  	burnerCode, err := ioutil.ReadFile("./testdata/burner.wasm")
  1096  	require.NoError(t, err)
  1097  
  1098  	originalContractID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
  1099  	require.NoError(t, err)
  1100  	burnerContractID, err := keeper.Create(ctx, creator, burnerCode, nil)
  1101  	require.NoError(t, err)
  1102  	require.NotEqual(t, originalContractID, burnerContractID)
  1103  
  1104  	_, _, myPayoutAddr := keyPubAddr()
  1105  	initMsg := HackatomExampleInitMsg{
  1106  		Verifier:    fred,
  1107  		Beneficiary: fred,
  1108  	}
  1109  	initMsgBz := initMsg.GetBytes(t)
  1110  
  1111  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
  1112  	contractAddr, _, err := keepers.ContractKeeper.Instantiate(ctx, originalContractID, creator, fred, initMsgBz, "demo contract", deposit)
  1113  	require.NoError(t, err)
  1114  
  1115  	migMsgBz := BurnerExampleInitMsg{Payout: myPayoutAddr}.GetBytes(t)
  1116  	ctx.SetEventManager(sdk.NewEventManager())
  1117  	ctx.SetBlockHeight((ctx.BlockHeight() + 1))
  1118  	data, err := keeper.Migrate(ctx, contractAddr, fred, burnerContractID, migMsgBz)
  1119  	require.NoError(t, err)
  1120  	assert.Equal(t, "burnt 1 keys", string(data))
  1121  	type dict map[string]interface{}
  1122  	expEvents := []dict{
  1123  		{
  1124  			"Type": "migrate",
  1125  			"Attr": []dict{
  1126  				{"code_id": "2"},
  1127  				{"_contract_address": contractAddr},
  1128  			},
  1129  		},
  1130  		{
  1131  			"Type": "wasm",
  1132  			"Attr": []dict{
  1133  				{"_contract_address": contractAddr},
  1134  				{"action": "burn"},
  1135  				{"payout": myPayoutAddr},
  1136  			},
  1137  		},
  1138  		{
  1139  			"Type": "transfer",
  1140  			"Attr": []dict{
  1141  				{"recipient": myPayoutAddr},
  1142  				{"sender": contractAddr},
  1143  				{"amount": "100000.000000000000000000denom"},
  1144  			},
  1145  		},
  1146  	}
  1147  	expJSONEvts := string(mustMarshal(t, expEvents))
  1148  	assert.JSONEq(t, expJSONEvts, prettyEvents(t, ctx.EventManager().Events()), prettyEvents(t, ctx.EventManager().Events()))
  1149  
  1150  	// all persistent data cleared
  1151  	m := keepers.WasmKeeper.QueryRaw(ctx, contractAddr, []byte("config"))
  1152  	require.Len(t, m, 0)
  1153  
  1154  	// and all deposit tokens sent to myPayoutAddr
  1155  	balance := keepers.BankKeeper.GetCoins(ctx, myPayoutAddr)
  1156  	assert.Equal(t, deposit, balance)
  1157  }
  1158  
  1159  func TestIterateContractsByCode(t *testing.T) {
  1160  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1161  	k, c := keepers.WasmKeeper, keepers.ContractKeeper
  1162  	example1 := InstantiateHackatomExampleContract(t, ctx, keepers)
  1163  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
  1164  	example2 := InstantiateIBCReflectContract(t, ctx, keepers)
  1165  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
  1166  	initMsg := HackatomExampleInitMsg{
  1167  		Verifier:    RandomAccountAddress(t),
  1168  		Beneficiary: RandomAccountAddress(t),
  1169  	}.GetBytes(t)
  1170  	contractAddr3, _, err := c.Instantiate(ctx, example1.CodeID, example1.CreatorAddr, nil, initMsg, "foo", nil)
  1171  	require.NoError(t, err)
  1172  	specs := map[string]struct {
  1173  		codeID uint64
  1174  		exp    []sdk.AccAddress
  1175  	}{
  1176  		"multiple results": {
  1177  			codeID: example1.CodeID,
  1178  			exp:    []sdk.AccAddress{example1.Contract, contractAddr3},
  1179  		},
  1180  		"single results": {
  1181  			codeID: example2.CodeID,
  1182  			exp:    []sdk.AccAddress{example2.Contract},
  1183  		},
  1184  		"empty results": {
  1185  			codeID: 99999,
  1186  		},
  1187  	}
  1188  	for name, spec := range specs {
  1189  		t.Run(name, func(t *testing.T) {
  1190  			var gotAddr []sdk.AccAddress
  1191  			k.IterateContractsByCode(ctx, spec.codeID, func(address sdk.AccAddress) bool {
  1192  				gotAddr = append(gotAddr, address)
  1193  				return false
  1194  			})
  1195  			assert.Equal(t, spec.exp, gotAddr)
  1196  		})
  1197  	}
  1198  }
  1199  
  1200  func TestIterateContractsByCodeWithMigration(t *testing.T) {
  1201  	// mock migration so that it does not fail when migrate example1 to example2.codeID
  1202  	mockWasmVM := wasmtesting.MockWasmer{MigrateFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, migrateMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
  1203  		return &wasmvmtypes.Response{}, 1, nil
  1204  	}}
  1205  	wasmtesting.MakeInstantiable(&mockWasmVM)
  1206  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures, WithWasmEngine(&mockWasmVM))
  1207  	k, c := keepers.WasmKeeper, keepers.ContractKeeper
  1208  	example1 := InstantiateHackatomExampleContract(t, ctx, keepers)
  1209  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
  1210  	example2 := InstantiateIBCReflectContract(t, ctx, keepers)
  1211  	ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1)
  1212  	_, err := c.Migrate(ctx, example1.Contract, example1.CreatorAddr, example2.CodeID, []byte("{}"))
  1213  	require.NoError(t, err)
  1214  
  1215  	// when
  1216  	var gotAddr []sdk.AccAddress
  1217  	k.IterateContractsByCode(ctx, example2.CodeID, func(address sdk.AccAddress) bool {
  1218  		gotAddr = append(gotAddr, address)
  1219  		return false
  1220  	})
  1221  
  1222  	// then
  1223  	exp := []sdk.AccAddress{example2.Contract, example1.Contract}
  1224  	assert.Equal(t, exp, gotAddr)
  1225  }
  1226  
  1227  type sudoMsg struct {
  1228  	// This is a tongue-in-check demo command. This is not the intended purpose of Sudo.
  1229  	// Here we show that some priviledged Go module can make a call that should never be exposed
  1230  	// to end users (via Tx/Execute).
  1231  	//
  1232  	// The contract developer can choose to expose anything to sudo. This functionality is not a true
  1233  	// backdoor (it can never be called by end users), but allows the developers of the native blockchain
  1234  	// code to make special calls. This can also be used as an authentication mechanism, if you want to expose
  1235  	// some callback that only can be triggered by some system module and not faked by external users.
  1236  	StealFunds stealFundsMsg `json:"steal_funds"`
  1237  }
  1238  
  1239  type stealFundsMsg struct {
  1240  	Recipient string            `json:"recipient"`
  1241  	Amount    wasmvmtypes.Coins `json:"amount"`
  1242  }
  1243  
  1244  func TestSudo(t *testing.T) {
  1245  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1246  	accKeeper, keeper, bankKeeper := keepers.AccountKeeper, keepers.ContractKeeper, keepers.BankKeeper
  1247  
  1248  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
  1249  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
  1250  
  1251  	contractID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
  1252  	require.NoError(t, err)
  1253  
  1254  	_, _, bob := keyPubAddr()
  1255  	_, _, fred := keyPubAddr()
  1256  	initMsg := HackatomExampleInitMsg{
  1257  		Verifier:    fred,
  1258  		Beneficiary: bob,
  1259  	}
  1260  	initMsgBz, err := json.Marshal(initMsg)
  1261  	require.NoError(t, err)
  1262  	addr, _, err := keepers.ContractKeeper.Instantiate(ctx, contractID, creator, nil, initMsgBz, "demo contract 3", deposit)
  1263  	require.NoError(t, err)
  1264  	require.Equal(t, "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr", addr.String())
  1265  
  1266  	// the community is broke
  1267  	_, _, community := keyPubAddr()
  1268  	comAcct := accKeeper.GetAccount(ctx, community)
  1269  	require.Nil(t, comAcct)
  1270  
  1271  	// now the community wants to get paid via sudo
  1272  	msg := sudoMsg{
  1273  		// This is a tongue-in-check demo command. This is not the intended purpose of Sudo.
  1274  		// Here we show that some priviledged Go module can make a call that should never be exposed
  1275  		// to end users (via Tx/Execute).
  1276  		StealFunds: stealFundsMsg{
  1277  			Recipient: community.String(),
  1278  			Amount:    wasmvmtypes.Coins{wasmvmtypes.Coin{"denom", "76543000000000000000000"}},
  1279  		},
  1280  	}
  1281  	sudoMsg, err := json.Marshal(msg)
  1282  	require.NoError(t, err)
  1283  
  1284  	em := sdk.NewEventManager()
  1285  
  1286  	// when
  1287  	newCtx := ctx
  1288  	newCtx.SetEventManager(em)
  1289  	_, err = keepers.WasmKeeper.Sudo(newCtx, addr, sudoMsg)
  1290  	require.NoError(t, err)
  1291  
  1292  	// ensure community now exists and got paid
  1293  	comAcct = accKeeper.GetAccount(ctx, community)
  1294  	require.NotNil(t, comAcct)
  1295  	balance := bankKeeper.GetCoins(ctx, comAcct.GetAddress())
  1296  	assert.Equal(t, sdk.Coins{sdk.NewInt64Coin("denom", 76543)}, balance)
  1297  	// and events emitted
  1298  	require.Len(t, em.Events(), 2, prettyEvents(t, em.Events()))
  1299  	expEvt := sdk.NewEvent("sudo",
  1300  		sdk.NewAttribute("_contract_address", addr.String()))
  1301  	assert.Equal(t, expEvt, em.Events()[0])
  1302  }
  1303  
  1304  func prettyEvents(t *testing.T, events sdk.Events) string {
  1305  	t.Helper()
  1306  	type prettyEvent struct {
  1307  		Type string
  1308  		Attr []map[string]string
  1309  	}
  1310  
  1311  	r := make([]prettyEvent, len(events))
  1312  	for i, e := range events {
  1313  		attr := make([]map[string]string, len(e.Attributes))
  1314  		for j, a := range e.Attributes {
  1315  			attr[j] = map[string]string{string(a.Key): string(a.Value)}
  1316  		}
  1317  		r[i] = prettyEvent{Type: e.Type, Attr: attr}
  1318  	}
  1319  	return string(mustMarshal(t, r))
  1320  }
  1321  
  1322  func mustMarshal(t *testing.T, r interface{}) []byte {
  1323  	t.Helper()
  1324  	bz, err := json.Marshal(r)
  1325  	require.NoError(t, err)
  1326  	return bz
  1327  }
  1328  
  1329  func TestUpdateContractAdmin(t *testing.T) {
  1330  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1331  	keeper := keepers.ContractKeeper
  1332  
  1333  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
  1334  	topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
  1335  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
  1336  	fred := keepers.Faucet.NewFundedAccount(ctx, topUp...)
  1337  
  1338  	originalContractID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
  1339  	require.NoError(t, err)
  1340  
  1341  	_, _, anyAddr := keyPubAddr()
  1342  	initMsg := HackatomExampleInitMsg{
  1343  		Verifier:    fred,
  1344  		Beneficiary: anyAddr,
  1345  	}
  1346  	initMsgBz, err := json.Marshal(initMsg)
  1347  	require.NoError(t, err)
  1348  	specs := map[string]struct {
  1349  		instAdmin            sdk.AccAddress
  1350  		newAdmin             sdk.AccAddress
  1351  		overrideContractAddr sdk.AccAddress
  1352  		caller               sdk.AccAddress
  1353  		expErr               *sdkerrors.Error
  1354  	}{
  1355  		"all good with admin set": {
  1356  			instAdmin: fred,
  1357  			newAdmin:  anyAddr,
  1358  			caller:    fred,
  1359  		},
  1360  		"prevent update when admin was not set on instantiate": {
  1361  			caller:   creator,
  1362  			newAdmin: fred,
  1363  			expErr:   sdkerrors.ErrUnauthorized,
  1364  		},
  1365  		"prevent updates from non admin address": {
  1366  			instAdmin: creator,
  1367  			newAdmin:  fred,
  1368  			caller:    fred,
  1369  			expErr:    sdkerrors.ErrUnauthorized,
  1370  		},
  1371  		"fail with non existing contract addr": {
  1372  			instAdmin:            creator,
  1373  			newAdmin:             anyAddr,
  1374  			caller:               creator,
  1375  			overrideContractAddr: anyAddr,
  1376  			expErr:               sdkerrors.ErrInvalidRequest,
  1377  		},
  1378  	}
  1379  	for msg, spec := range specs {
  1380  		t.Run(msg, func(t *testing.T) {
  1381  			addr, _, err := keepers.ContractKeeper.Instantiate(ctx, originalContractID, creator, spec.instAdmin, initMsgBz, "demo contract", nil)
  1382  			require.NoError(t, err)
  1383  			if spec.overrideContractAddr != nil {
  1384  				addr = spec.overrideContractAddr
  1385  			}
  1386  			err = keeper.UpdateContractAdmin(ctx, addr, spec.caller, spec.newAdmin)
  1387  			require.True(t, spec.expErr.Is(err), "expected %v but got %+v", spec.expErr, err)
  1388  			if spec.expErr != nil {
  1389  				return
  1390  			}
  1391  			cInfo := keepers.WasmKeeper.GetContractInfo(ctx, addr)
  1392  			assert.Equal(t, spec.newAdmin.String(), cInfo.Admin)
  1393  		})
  1394  	}
  1395  }
  1396  
  1397  func TestClearContractAdmin(t *testing.T) {
  1398  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1399  	keeper := keepers.ContractKeeper
  1400  
  1401  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
  1402  	topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 5000))
  1403  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit.Add(deposit...)...)
  1404  	fred := keepers.Faucet.NewFundedAccount(ctx, topUp...)
  1405  
  1406  	originalContractID, err := keeper.Create(ctx, creator, hackatomWasm, nil)
  1407  	require.NoError(t, err)
  1408  
  1409  	_, _, anyAddr := keyPubAddr()
  1410  	initMsg := HackatomExampleInitMsg{
  1411  		Verifier:    fred,
  1412  		Beneficiary: anyAddr,
  1413  	}
  1414  	initMsgBz, err := json.Marshal(initMsg)
  1415  	require.NoError(t, err)
  1416  	specs := map[string]struct {
  1417  		instAdmin            sdk.AccAddress
  1418  		overrideContractAddr sdk.AccAddress
  1419  		caller               sdk.AccAddress
  1420  		expErr               *sdkerrors.Error
  1421  	}{
  1422  		"all good when called by proper admin": {
  1423  			instAdmin: fred,
  1424  			caller:    fred,
  1425  		},
  1426  		"prevent update when admin was not set on instantiate": {
  1427  			caller: creator,
  1428  			expErr: sdkerrors.ErrUnauthorized,
  1429  		},
  1430  		"prevent updates from non admin address": {
  1431  			instAdmin: creator,
  1432  			caller:    fred,
  1433  			expErr:    sdkerrors.ErrUnauthorized,
  1434  		},
  1435  		"fail with non existing contract addr": {
  1436  			instAdmin:            creator,
  1437  			caller:               creator,
  1438  			overrideContractAddr: anyAddr,
  1439  			expErr:               sdkerrors.ErrInvalidRequest,
  1440  		},
  1441  	}
  1442  	for msg, spec := range specs {
  1443  		t.Run(msg, func(t *testing.T) {
  1444  			addr, _, err := keepers.ContractKeeper.Instantiate(ctx, originalContractID, creator, spec.instAdmin, initMsgBz, "demo contract", nil)
  1445  			require.NoError(t, err)
  1446  			if spec.overrideContractAddr != nil {
  1447  				addr = spec.overrideContractAddr
  1448  			}
  1449  			err = keeper.ClearContractAdmin(ctx, addr, spec.caller)
  1450  			require.True(t, spec.expErr.Is(err), "expected %v but got %+v", spec.expErr, err)
  1451  			if spec.expErr != nil {
  1452  				return
  1453  			}
  1454  			cInfo := keepers.WasmKeeper.GetContractInfo(ctx, addr)
  1455  			assert.Empty(t, cInfo.Admin)
  1456  		})
  1457  	}
  1458  }
  1459  
  1460  func TestPinCode(t *testing.T) {
  1461  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1462  	k := keepers.WasmKeeper
  1463  
  1464  	var capturedChecksums []wasmvm.Checksum
  1465  	mock := wasmtesting.MockWasmer{PinFn: func(checksum wasmvm.Checksum) error {
  1466  		capturedChecksums = append(capturedChecksums, checksum)
  1467  		return nil
  1468  	}}
  1469  	wasmtesting.MakeInstantiable(&mock)
  1470  	myCodeID := StoreRandomContract(t, ctx, keepers, &mock).CodeID
  1471  	require.Equal(t, uint64(1), myCodeID)
  1472  	em := sdk.NewEventManager()
  1473  
  1474  	// when
  1475  	newCtx := ctx
  1476  	newCtx.SetEventManager(em)
  1477  	gotErr := k.pinCode(newCtx, myCodeID)
  1478  
  1479  	// then
  1480  	require.NoError(t, gotErr)
  1481  	assert.NotEmpty(t, capturedChecksums)
  1482  	assert.True(t, k.IsPinnedCode(ctx, myCodeID))
  1483  
  1484  	// and events
  1485  	exp := sdk.Events{sdk.NewEvent("pin_code", sdk.NewAttribute("code_id", "1"))}
  1486  	assert.Equal(t, exp, em.Events())
  1487  }
  1488  
  1489  func TestUnpinCode(t *testing.T) {
  1490  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1491  	k := keepers.WasmKeeper
  1492  
  1493  	var capturedChecksums []wasmvm.Checksum
  1494  	mock := wasmtesting.MockWasmer{
  1495  		PinFn: func(checksum wasmvm.Checksum) error {
  1496  			return nil
  1497  		},
  1498  		UnpinFn: func(checksum wasmvm.Checksum) error {
  1499  			capturedChecksums = append(capturedChecksums, checksum)
  1500  			return nil
  1501  		},
  1502  	}
  1503  	wasmtesting.MakeInstantiable(&mock)
  1504  	myCodeID := StoreRandomContract(t, ctx, keepers, &mock).CodeID
  1505  	require.Equal(t, uint64(1), myCodeID)
  1506  	err := k.pinCode(ctx, myCodeID)
  1507  	require.NoError(t, err)
  1508  	em := sdk.NewEventManager()
  1509  
  1510  	// when
  1511  	newCtx := ctx
  1512  	newCtx.SetEventManager(em)
  1513  	gotErr := k.unpinCode(newCtx, myCodeID)
  1514  
  1515  	// then
  1516  	require.NoError(t, gotErr)
  1517  	assert.NotEmpty(t, capturedChecksums)
  1518  	assert.False(t, k.IsPinnedCode(ctx, myCodeID))
  1519  
  1520  	// and events
  1521  	exp := sdk.Events{sdk.NewEvent("unpin_code", sdk.NewAttribute("code_id", "1"))}
  1522  	assert.Equal(t, exp, em.Events())
  1523  }
  1524  
  1525  func TestInitializePinnedCodes(t *testing.T) {
  1526  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1527  	k := keepers.WasmKeeper
  1528  
  1529  	var capturedChecksums []wasmvm.Checksum
  1530  	mock := wasmtesting.MockWasmer{PinFn: func(checksum wasmvm.Checksum) error {
  1531  		capturedChecksums = append(capturedChecksums, checksum)
  1532  		return nil
  1533  	}}
  1534  	wasmtesting.MakeInstantiable(&mock)
  1535  
  1536  	const testItems = 3
  1537  	myCodeIDs := make([]uint64, testItems)
  1538  	for i := 0; i < testItems; i++ {
  1539  		myCodeIDs[i] = StoreRandomContract(t, ctx, keepers, &mock).CodeID
  1540  		require.NoError(t, k.pinCode(ctx, myCodeIDs[i]))
  1541  	}
  1542  	capturedChecksums = nil
  1543  
  1544  	// when
  1545  	gotErr := k.InitializePinnedCodes(ctx)
  1546  
  1547  	// then
  1548  	require.NoError(t, gotErr)
  1549  	require.Len(t, capturedChecksums, testItems)
  1550  	for i, c := range myCodeIDs {
  1551  		var exp wasmvm.Checksum = k.GetCodeInfo(ctx, c).CodeHash
  1552  		assert.Equal(t, exp, capturedChecksums[i])
  1553  	}
  1554  }
  1555  
  1556  func TestPinnedContractLoops(t *testing.T) {
  1557  	var capturedChecksums []wasmvm.Checksum
  1558  	mock := wasmtesting.MockWasmer{PinFn: func(checksum wasmvm.Checksum) error {
  1559  		capturedChecksums = append(capturedChecksums, checksum)
  1560  		return nil
  1561  	}}
  1562  	wasmtesting.MakeInstantiable(&mock)
  1563  
  1564  	// a pinned contract that calls itself via submessages should terminate with an
  1565  	// error at some point
  1566  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures, WithWasmEngine(&mock))
  1567  	k := keepers.WasmKeeper
  1568  
  1569  	example := SeedNewContractInstance(t, ctx, keepers, &mock)
  1570  	require.NoError(t, k.pinCode(ctx, example.CodeID))
  1571  	var loops int
  1572  	anyMsg := []byte(`{}`)
  1573  	mock.ExecuteFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, executeMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
  1574  		loops++
  1575  		return &wasmvmtypes.Response{
  1576  			Messages: []wasmvmtypes.SubMsg{
  1577  				{
  1578  					ID:      1,
  1579  					ReplyOn: wasmvmtypes.ReplyNever,
  1580  					Msg: wasmvmtypes.CosmosMsg{
  1581  						Wasm: &wasmvmtypes.WasmMsg{
  1582  							Execute: &wasmvmtypes.ExecuteMsg{
  1583  								ContractAddr: example.Contract.String(),
  1584  								Msg:          anyMsg,
  1585  							},
  1586  						},
  1587  					},
  1588  				},
  1589  			},
  1590  		}, 0, nil
  1591  	}
  1592  
  1593  	ctx.SetGasMeter(sdk.NewGasMeter(24000))
  1594  	require.PanicsWithValue(t, sdk.ErrorOutOfGas{Descriptor: "ReadFlat"}, func() {
  1595  		_, err := k.execute(ctx, example.Contract, RandomAccountAddress(t), anyMsg, nil)
  1596  		require.NoError(t, err)
  1597  	})
  1598  	assert.True(t, ctx.GasMeter().IsOutOfGas())
  1599  	assert.Greater(t, loops, 2)
  1600  }
  1601  
  1602  func TestNewDefaultWasmVMContractResponseHandler(t *testing.T) {
  1603  	specs := map[string]struct {
  1604  		srcData []byte
  1605  		setup   func(m *wasmtesting.MockMsgDispatcher)
  1606  		expErr  bool
  1607  		expData []byte
  1608  		expEvts sdk.Events
  1609  	}{
  1610  		"submessage overwrites result when set": {
  1611  			srcData: []byte("otherData"),
  1612  			setup: func(m *wasmtesting.MockMsgDispatcher) {
  1613  				m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) {
  1614  					return []byte("mySubMsgData"), nil
  1615  				}
  1616  			},
  1617  			expErr:  false,
  1618  			expData: []byte("mySubMsgData"),
  1619  			expEvts: sdk.Events{},
  1620  		},
  1621  		"submessage overwrites result when empty": {
  1622  			srcData: []byte("otherData"),
  1623  			setup: func(m *wasmtesting.MockMsgDispatcher) {
  1624  				m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) {
  1625  					return []byte(""), nil
  1626  				}
  1627  			},
  1628  			expErr:  false,
  1629  			expData: []byte(""),
  1630  			expEvts: sdk.Events{},
  1631  		},
  1632  		"submessage do not overwrite result when nil": {
  1633  			srcData: []byte("otherData"),
  1634  			setup: func(m *wasmtesting.MockMsgDispatcher) {
  1635  				m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) {
  1636  					return nil, nil
  1637  				}
  1638  			},
  1639  			expErr:  false,
  1640  			expData: []byte("otherData"),
  1641  			expEvts: sdk.Events{},
  1642  		},
  1643  		"submessage error aborts process": {
  1644  			setup: func(m *wasmtesting.MockMsgDispatcher) {
  1645  				m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) {
  1646  					return nil, errors.New("test - ignore")
  1647  				}
  1648  			},
  1649  			expErr: true,
  1650  		},
  1651  		"message emit non message events": {
  1652  			setup: func(m *wasmtesting.MockMsgDispatcher) {
  1653  				m.DispatchSubmessagesFn = func(ctx sdk.Context, contractAddr sdk.AccAddress, ibcPort string, msgs []wasmvmtypes.SubMsg) ([]byte, error) {
  1654  					ctx.EventManager().EmitEvent(sdk.NewEvent("myEvent"))
  1655  					return nil, nil
  1656  				}
  1657  			},
  1658  			expEvts: sdk.Events{sdk.NewEvent("myEvent")},
  1659  		},
  1660  	}
  1661  	for name, spec := range specs {
  1662  		t.Run(name, func(t *testing.T) {
  1663  			var msgs []wasmvmtypes.SubMsg
  1664  			var mock wasmtesting.MockMsgDispatcher
  1665  			spec.setup(&mock)
  1666  			d := NewDefaultWasmVMContractResponseHandler(&mock)
  1667  			em := sdk.NewEventManager()
  1668  
  1669  			// when
  1670  			newCtx := sdk.Context{}
  1671  			newCtx.SetEventManager(em)
  1672  			gotData, gotErr := d.Handle(newCtx, RandomAccountAddress(t), "ibc-port", msgs, spec.srcData)
  1673  			if spec.expErr {
  1674  				require.Error(t, gotErr)
  1675  				return
  1676  			}
  1677  			require.NoError(t, gotErr)
  1678  			assert.Equal(t, spec.expData, gotData)
  1679  			assert.Equal(t, spec.expEvts, em.Events())
  1680  		})
  1681  	}
  1682  }
  1683  
  1684  func TestReply(t *testing.T) {
  1685  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1686  	k := keepers.WasmKeeper
  1687  	var mock wasmtesting.MockWasmer
  1688  	wasmtesting.MakeInstantiable(&mock)
  1689  	example := SeedNewContractInstance(t, ctx, keepers, &mock)
  1690  
  1691  	specs := map[string]struct {
  1692  		replyFn func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error)
  1693  		expData []byte
  1694  		expErr  bool
  1695  		expEvt  sdk.Events
  1696  	}{
  1697  		"all good": {
  1698  			replyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
  1699  				return &wasmvmtypes.Response{Data: []byte("foo")}, 1, nil
  1700  			},
  1701  			expData: []byte("foo"),
  1702  			expEvt:  sdk.Events{sdk.NewEvent("reply", sdk.NewAttribute("_contract_address", example.Contract.String()))},
  1703  		},
  1704  		"with query": {
  1705  			replyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
  1706  				bzRsp, err := querier.Query(wasmvmtypes.QueryRequest{
  1707  					Bank: &wasmvmtypes.BankQuery{
  1708  						Balance: &wasmvmtypes.BalanceQuery{Address: env.Contract.Address, Denom: "stake"},
  1709  					},
  1710  				}, 10_000*DefaultGasMultiplier)
  1711  				require.NoError(t, err)
  1712  				var gotBankRsp wasmvmtypes.BalanceResponse
  1713  				require.NoError(t, json.Unmarshal(bzRsp, &gotBankRsp))
  1714  				assert.Equal(t, wasmvmtypes.BalanceResponse{Amount: wasmvmtypes.NewCoin(0, "stake")}, gotBankRsp)
  1715  				return &wasmvmtypes.Response{Data: []byte("foo")}, 1, nil
  1716  			},
  1717  			expData: []byte("foo"),
  1718  			expEvt:  sdk.Events{sdk.NewEvent("reply", sdk.NewAttribute("_contract_address", example.Contract.String()))},
  1719  		},
  1720  		"with query error handled": {
  1721  			replyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
  1722  				bzRsp, err := querier.Query(wasmvmtypes.QueryRequest{}, 0)
  1723  				require.Error(t, err)
  1724  				assert.Nil(t, bzRsp)
  1725  				return &wasmvmtypes.Response{Data: []byte("foo")}, 1, nil
  1726  			},
  1727  			expData: []byte("foo"),
  1728  			expEvt:  sdk.Events{sdk.NewEvent("reply", sdk.NewAttribute("_contract_address", example.Contract.String()))},
  1729  		},
  1730  		"error": {
  1731  			replyFn: func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
  1732  				return nil, 1, errors.New("testing")
  1733  			},
  1734  			expErr: true,
  1735  		},
  1736  	}
  1737  	for name, spec := range specs {
  1738  		t.Run(name, func(t *testing.T) {
  1739  			mock.ReplyFn = spec.replyFn
  1740  			em := sdk.NewEventManager()
  1741  
  1742  			ctx.SetEventManager(em)
  1743  			gotData, gotErr := k.reply(ctx, example.Contract, wasmvmtypes.Reply{})
  1744  			if spec.expErr {
  1745  				require.Error(t, gotErr)
  1746  				return
  1747  			}
  1748  			require.NoError(t, gotErr)
  1749  			assert.Equal(t, spec.expData, gotData)
  1750  			assert.Equal(t, spec.expEvt, ctx.EventManager().Events())
  1751  		})
  1752  	}
  1753  }
  1754  
  1755  func TestQueryIsolation(t *testing.T) {
  1756  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
  1757  	k := keepers.WasmKeeper
  1758  	var mock wasmtesting.MockWasmer
  1759  	wasmtesting.MakeInstantiable(&mock)
  1760  	example := SeedNewContractInstance(t, ctx, keepers, &mock)
  1761  	WithQueryHandlerDecorator(func(other WasmVMQueryHandler) WasmVMQueryHandler {
  1762  		return WasmVMQueryHandlerFn(func(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) {
  1763  			if request.Custom == nil {
  1764  				return other.HandleQuery(ctx, caller, request)
  1765  			}
  1766  			// here we write to DB which should not be persisted
  1767  			ctx.KVStore(k.storeKey).Set([]byte(`set_in_query`), []byte(`this_is_allowed`))
  1768  			return nil, nil
  1769  		})
  1770  	}).apply(k)
  1771  
  1772  	// when
  1773  	mock.ReplyFn = func(codeID wasmvm.Checksum, env wasmvmtypes.Env, reply wasmvmtypes.Reply, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) {
  1774  		_, err := querier.Query(wasmvmtypes.QueryRequest{
  1775  			Custom: []byte(`{}`),
  1776  		}, 10000*DefaultGasMultiplier)
  1777  		require.NoError(t, err)
  1778  		return &wasmvmtypes.Response{}, 0, nil
  1779  	}
  1780  	em := sdk.NewEventManager()
  1781  	//newCtx := ctx
  1782  	ctx.SetEventManager(em)
  1783  	assert.Nil(t, ctx.KVStore(k.storeKey).Get([]byte(`set_in_query`)))
  1784  	_, gotErr := k.reply(ctx, example.Contract, wasmvmtypes.Reply{})
  1785  	require.NoError(t, gotErr)
  1786  	assert.Nil(t, ctx.KVStore(k.storeKey).Get([]byte(`set_in_query`)))
  1787  }
  1788  
  1789  func TestBuildContractAddress(t *testing.T) {
  1790  	specs := map[string]struct {
  1791  		srcCodeID     uint64
  1792  		srcInstanceID uint64
  1793  		expectedAddr  string
  1794  	}{
  1795  		"initial contract": {
  1796  			srcCodeID:     1,
  1797  			srcInstanceID: 1,
  1798  			expectedAddr:  "cosmos14hj2tavq8fpesdwxxcu44rty3hh90vhujrvcmstl4zr3txmfvw9s4hmalr",
  1799  		},
  1800  		"demo value": {
  1801  			srcCodeID:     1,
  1802  			srcInstanceID: 100,
  1803  			expectedAddr:  "cosmos1mujpjkwhut9yjw4xueyugc02evfv46y0dtmnz4lh8xxkkdapym9stu5qm8",
  1804  		},
  1805  		"both below max": {
  1806  			srcCodeID:     math.MaxUint32 - 1,
  1807  			srcInstanceID: math.MaxUint32 - 1,
  1808  		},
  1809  		"both at max": {
  1810  			srcCodeID:     math.MaxUint32,
  1811  			srcInstanceID: math.MaxUint32,
  1812  		},
  1813  		"codeID > max u32": {
  1814  			srcCodeID:     math.MaxUint32 + 1,
  1815  			srcInstanceID: 17,
  1816  			expectedAddr:  "cosmos1673hrexz4h6s0ft04l96ygq667djzh2nsr335kstjp49x5dk6rpsf5t0le",
  1817  		},
  1818  		"instanceID > max u32": {
  1819  			srcCodeID:     22,
  1820  			srcInstanceID: math.MaxUint32 + 1,
  1821  			expectedAddr:  "cosmos10q3pgfvmeyy0veekgtqhxujxkhz0vm9zmalqgc7evrhj68q3l62qrdfg4m",
  1822  		},
  1823  	}
  1824  	for name, spec := range specs {
  1825  		t.Run(name, func(t *testing.T) {
  1826  			gotAddr := BuildContractAddress(spec.srcCodeID, spec.srcInstanceID)
  1827  			require.NotNil(t, gotAddr)
  1828  			assert.Nil(t, sdk.VerifyAddressFormat(gotAddr))
  1829  			if len(spec.expectedAddr) > 0 {
  1830  				require.Equal(t, spec.expectedAddr, gotAddr.String())
  1831  			}
  1832  		})
  1833  	}
  1834  }