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

     1  package keeper
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"testing"
    10  
    11  	"google.golang.org/grpc/codes"
    12  	"google.golang.org/grpc/status"
    13  
    14  	wasmvm "github.com/CosmWasm/wasmvm"
    15  	wasmvmtypes "github.com/CosmWasm/wasmvm/types"
    16  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    17  	sdkErrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    18  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/query"
    19  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  
    23  	"github.com/fibonacci-chain/fbc/x/wasm/keeper/wasmtesting"
    24  	"github.com/fibonacci-chain/fbc/x/wasm/types"
    25  )
    26  
    27  func TestQueryAllContractState(t *testing.T) {
    28  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
    29  	keeper := keepers.WasmKeeper
    30  
    31  	exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers)
    32  	contractAddr := exampleContract.Contract
    33  	contractModel := []types.Model{
    34  		{Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)},
    35  		{Key: []byte("foo"), Value: []byte(`"bar"`)},
    36  	}
    37  	require.NoError(t, keeper.importContractState(ctx, contractAddr, contractModel))
    38  
    39  	q := Querier(keeper)
    40  	specs := map[string]struct {
    41  		srcQuery            *types.QueryAllContractStateRequest
    42  		expModelContains    []types.Model
    43  		expModelContainsNot []types.Model
    44  		expErr              *sdkErrors.Error
    45  	}{
    46  		"query all": {
    47  			srcQuery:         &types.QueryAllContractStateRequest{Address: contractAddr.String()},
    48  			expModelContains: contractModel,
    49  		},
    50  		"query all with unknown address": {
    51  			srcQuery: &types.QueryAllContractStateRequest{Address: RandomBech32AccountAddress(t)},
    52  			expErr:   types.ErrNotFound,
    53  		},
    54  		"with pagination offset": {
    55  			srcQuery: &types.QueryAllContractStateRequest{
    56  				Address: contractAddr.String(),
    57  				Pagination: &query.PageRequest{
    58  					Offset: 1,
    59  				},
    60  			},
    61  			expModelContains: []types.Model{
    62  				{Key: []byte("foo"), Value: []byte(`"bar"`)},
    63  			},
    64  			expModelContainsNot: []types.Model{
    65  				{Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)},
    66  			},
    67  		},
    68  		"with pagination limit": {
    69  			srcQuery: &types.QueryAllContractStateRequest{
    70  				Address: contractAddr.String(),
    71  				Pagination: &query.PageRequest{
    72  					Limit: 1,
    73  				},
    74  			},
    75  			expModelContains: []types.Model{
    76  				{Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)},
    77  			},
    78  			expModelContainsNot: []types.Model{
    79  				{Key: []byte("foo"), Value: []byte(`"bar"`)},
    80  			},
    81  		},
    82  		"with pagination next key": {
    83  			srcQuery: &types.QueryAllContractStateRequest{
    84  				Address: contractAddr.String(),
    85  				Pagination: &query.PageRequest{
    86  					Key: fromBase64("Y29uZmln"),
    87  				},
    88  			},
    89  			expModelContains: []types.Model{
    90  				{Key: []byte("foo"), Value: []byte(`"bar"`)},
    91  			},
    92  			expModelContainsNot: []types.Model{
    93  				{Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)},
    94  			},
    95  		},
    96  	}
    97  	for msg, spec := range specs {
    98  		t.Run(msg, func(t *testing.T) {
    99  			got, err := q.AllContractState(sdk.WrapSDKContext(ctx), spec.srcQuery)
   100  			require.True(t, spec.expErr.Is(err), err)
   101  			if spec.expErr != nil {
   102  				return
   103  			}
   104  			for _, exp := range spec.expModelContains {
   105  				assert.Contains(t, got.Models, exp)
   106  			}
   107  			for _, exp := range spec.expModelContainsNot {
   108  				assert.NotContains(t, got.Models, exp)
   109  			}
   110  		})
   111  	}
   112  }
   113  
   114  func TestQuerySmartContractState(t *testing.T) {
   115  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   116  	keeper := keepers.WasmKeeper
   117  
   118  	exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers)
   119  	contractAddr := exampleContract.Contract.String()
   120  
   121  	q := Querier(keeper)
   122  	specs := map[string]struct {
   123  		srcAddr  sdk.AccAddress
   124  		srcQuery *types.QuerySmartContractStateRequest
   125  		expResp  string
   126  		expErr   error
   127  	}{
   128  		"query smart": {
   129  			srcQuery: &types.QuerySmartContractStateRequest{Address: contractAddr, QueryData: []byte(`{"verifier":{}}`)},
   130  			expResp:  fmt.Sprintf(`{"verifier":"%s"}`, exampleContract.VerifierAddr.String()),
   131  		},
   132  		"query smart invalid request": {
   133  			srcQuery: &types.QuerySmartContractStateRequest{Address: contractAddr, QueryData: []byte(`{"raw":{"key":"config"}}`)},
   134  			expErr:   types.ErrQueryFailed,
   135  		},
   136  		"query smart with invalid json": {
   137  			srcQuery: &types.QuerySmartContractStateRequest{Address: contractAddr, QueryData: []byte(`not a json string`)},
   138  			expErr:   status.Error(codes.InvalidArgument, "invalid query data"),
   139  		},
   140  		"query smart with unknown address": {
   141  			srcQuery: &types.QuerySmartContractStateRequest{Address: RandomBech32AccountAddress(t), QueryData: []byte(`{"verifier":{}}`)},
   142  			expErr:   types.ErrNotFound,
   143  		},
   144  	}
   145  	for msg, spec := range specs {
   146  		t.Run(msg, func(t *testing.T) {
   147  			got, err := q.SmartContractState(sdk.WrapSDKContext(ctx), spec.srcQuery)
   148  			require.True(t, errors.Is(err, spec.expErr), "but got %+v", err)
   149  			if spec.expErr != nil {
   150  				return
   151  			}
   152  			assert.JSONEq(t, string(got.Data), spec.expResp)
   153  		})
   154  	}
   155  }
   156  
   157  func TestQuerySmartContractPanics(t *testing.T) {
   158  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   159  	contractAddr := BuildContractAddress(1, 1)
   160  	keepers.WasmKeeper.storeCodeInfo(ctx, 1, types.CodeInfo{})
   161  	keepers.WasmKeeper.storeContractInfo(ctx, contractAddr, &types.ContractInfo{
   162  		CodeID:  1,
   163  		Created: types.NewAbsoluteTxPosition(ctx),
   164  	})
   165  	ctx.SetGasMeter(sdk.NewGasMeter(DefaultInstanceCost))
   166  	ctx.SetLogger(log.TestingLogger())
   167  
   168  	specs := map[string]struct {
   169  		doInContract func()
   170  		expErr       *sdkErrors.Error
   171  	}{
   172  		"out of gas": {
   173  			doInContract: func() {
   174  				ctx.GasMeter().ConsumeGas(ctx.GasMeter().Limit()+1, "test - consume more than limit")
   175  			},
   176  			expErr: sdkErrors.ErrOutOfGas,
   177  		},
   178  		"other panic": {
   179  			doInContract: func() {
   180  				panic("my panic")
   181  			},
   182  			expErr: sdkErrors.ErrPanic,
   183  		},
   184  	}
   185  	for msg, spec := range specs {
   186  		t.Run(msg, func(t *testing.T) {
   187  			keepers.WasmKeeper.wasmVM = &wasmtesting.MockWasmer{QueryFn: func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) {
   188  				spec.doInContract()
   189  				return nil, 0, nil
   190  			}}
   191  			// when
   192  			q := Querier(keepers.WasmKeeper)
   193  			got, err := q.SmartContractState(sdk.WrapSDKContext(ctx), &types.QuerySmartContractStateRequest{
   194  				Address:   contractAddr.String(),
   195  				QueryData: types.RawContractMessage("{}"),
   196  			})
   197  			require.True(t, spec.expErr.Is(err), "got error: %+v", err)
   198  			assert.Nil(t, got)
   199  		})
   200  	}
   201  }
   202  
   203  func TestQueryRawContractState(t *testing.T) {
   204  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   205  	keeper := keepers.WasmKeeper
   206  
   207  	exampleContract := InstantiateHackatomExampleContract(t, ctx, keepers)
   208  	contractAddr := exampleContract.Contract.String()
   209  	contractModel := []types.Model{
   210  		{Key: []byte("foo"), Value: []byte(`"bar"`)},
   211  		{Key: []byte{0x0, 0x1}, Value: []byte(`{"count":8}`)},
   212  	}
   213  	require.NoError(t, keeper.importContractState(ctx, exampleContract.Contract, contractModel))
   214  
   215  	q := Querier(keeper)
   216  	specs := map[string]struct {
   217  		srcQuery *types.QueryRawContractStateRequest
   218  		expData  []byte
   219  		expErr   *sdkErrors.Error
   220  	}{
   221  		"query raw key": {
   222  			srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr, QueryData: []byte("foo")},
   223  			expData:  []byte(`"bar"`),
   224  		},
   225  		"query raw contract binary key": {
   226  			srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr, QueryData: []byte{0x0, 0x1}},
   227  			expData:  []byte(`{"count":8}`),
   228  		},
   229  		"query non-existent raw key": {
   230  			srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr, QueryData: []byte("not existing key")},
   231  			expData:  nil,
   232  		},
   233  		"query empty raw key": {
   234  			srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr, QueryData: []byte("")},
   235  			expData:  nil,
   236  		},
   237  		"query nil raw key": {
   238  			srcQuery: &types.QueryRawContractStateRequest{Address: contractAddr},
   239  			expData:  nil,
   240  		},
   241  		"query raw with unknown address": {
   242  			srcQuery: &types.QueryRawContractStateRequest{Address: RandomBech32AccountAddress(t), QueryData: []byte("foo")},
   243  			expErr:   types.ErrNotFound,
   244  		},
   245  	}
   246  	for msg, spec := range specs {
   247  		t.Run(msg, func(t *testing.T) {
   248  			got, err := q.RawContractState(sdk.WrapSDKContext(ctx), spec.srcQuery)
   249  			require.True(t, spec.expErr.Is(err), err)
   250  			if spec.expErr != nil {
   251  				return
   252  			}
   253  			assert.Equal(t, spec.expData, got.Data)
   254  		})
   255  	}
   256  }
   257  
   258  func TestQueryContractListByCodeOrdering(t *testing.T) {
   259  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   260  	keeper := keepers.WasmKeeper
   261  
   262  	deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 1000000))
   263  	topUp := sdk.NewCoins(sdk.NewInt64Coin("denom", 500))
   264  	creator := keepers.Faucet.NewFundedAccount(ctx, deposit...)
   265  	anyAddr := keepers.Faucet.NewFundedAccount(ctx, topUp...)
   266  
   267  	wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm")
   268  	require.NoError(t, err)
   269  
   270  	codeID, err := keepers.ContractKeeper.Create(ctx, creator, wasmCode, nil)
   271  	require.NoError(t, err)
   272  
   273  	_, _, bob := keyPubAddr()
   274  	initMsg := HackatomExampleInitMsg{
   275  		Verifier:    anyAddr,
   276  		Beneficiary: bob,
   277  	}
   278  	initMsgBz, err := json.Marshal(initMsg)
   279  	require.NoError(t, err)
   280  
   281  	// manage some realistic block settings
   282  	var h int64 = 10
   283  	setBlock := func(ctx sdk.Context, height int64) sdk.Context {
   284  		ctx = ctx.WithBlockHeight(height)
   285  		meter := sdk.NewGasMeter(1000000)
   286  		ctx.SetGasMeter(meter)
   287  		ctx.SetBlockGasMeter(meter)
   288  		return ctx
   289  	}
   290  
   291  	// create 10 contracts with real block/gas setup
   292  	for i := 0; i < 10; i++ {
   293  		// 3 tx per block, so we ensure both comparisons work
   294  		if i%3 == 0 {
   295  			ctx = setBlock(ctx, h)
   296  			h++
   297  		}
   298  		_, _, err = keepers.ContractKeeper.Instantiate(ctx, codeID, creator, nil, initMsgBz, fmt.Sprintf("contract %d", i), topUp)
   299  		require.NoError(t, err)
   300  	}
   301  
   302  	// query and check the results are properly sorted
   303  	q := Querier(keeper)
   304  	res, err := q.ContractsByCode(sdk.WrapSDKContext(ctx), &types.QueryContractsByCodeRequest{CodeId: codeID})
   305  	require.NoError(t, err)
   306  
   307  	require.Equal(t, 10, len(res.Contracts))
   308  
   309  	for _, contractAddr := range res.Contracts {
   310  		assert.NotEmpty(t, contractAddr)
   311  	}
   312  }
   313  
   314  func TestQueryContractHistory(t *testing.T) {
   315  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   316  	keeper := keepers.WasmKeeper
   317  
   318  	var (
   319  		myContractBech32Addr = RandomBech32AccountAddress(t)
   320  		otherBech32Addr      = RandomBech32AccountAddress(t)
   321  	)
   322  
   323  	specs := map[string]struct {
   324  		srcHistory []types.ContractCodeHistoryEntry
   325  		req        types.QueryContractHistoryRequest
   326  		expContent []types.ContractCodeHistoryEntry
   327  	}{
   328  		"response with internal fields cleared": {
   329  			srcHistory: []types.ContractCodeHistoryEntry{{
   330  				Operation: types.ContractCodeHistoryOperationTypeGenesis,
   331  				CodeID:    firstCodeID,
   332  				Updated:   types.NewAbsoluteTxPosition(ctx),
   333  				Msg:       []byte(`"init message"`),
   334  			}},
   335  			req: types.QueryContractHistoryRequest{Address: myContractBech32Addr},
   336  			expContent: []types.ContractCodeHistoryEntry{{
   337  				Operation: types.ContractCodeHistoryOperationTypeGenesis,
   338  				CodeID:    firstCodeID,
   339  				Msg:       []byte(`"init message"`),
   340  			}},
   341  		},
   342  		"response with multiple entries": {
   343  			srcHistory: []types.ContractCodeHistoryEntry{{
   344  				Operation: types.ContractCodeHistoryOperationTypeInit,
   345  				CodeID:    firstCodeID,
   346  				Updated:   types.NewAbsoluteTxPosition(ctx),
   347  				Msg:       []byte(`"init message"`),
   348  			}, {
   349  				Operation: types.ContractCodeHistoryOperationTypeMigrate,
   350  				CodeID:    2,
   351  				Updated:   types.NewAbsoluteTxPosition(ctx),
   352  				Msg:       []byte(`"migrate message 1"`),
   353  			}, {
   354  				Operation: types.ContractCodeHistoryOperationTypeMigrate,
   355  				CodeID:    3,
   356  				Updated:   types.NewAbsoluteTxPosition(ctx),
   357  				Msg:       []byte(`"migrate message 2"`),
   358  			}},
   359  			req: types.QueryContractHistoryRequest{Address: myContractBech32Addr},
   360  			expContent: []types.ContractCodeHistoryEntry{{
   361  				Operation: types.ContractCodeHistoryOperationTypeInit,
   362  				CodeID:    firstCodeID,
   363  				Msg:       []byte(`"init message"`),
   364  			}, {
   365  				Operation: types.ContractCodeHistoryOperationTypeMigrate,
   366  				CodeID:    2,
   367  				Msg:       []byte(`"migrate message 1"`),
   368  			}, {
   369  				Operation: types.ContractCodeHistoryOperationTypeMigrate,
   370  				CodeID:    3,
   371  				Msg:       []byte(`"migrate message 2"`),
   372  			}},
   373  		},
   374  		"with pagination offset": {
   375  			srcHistory: []types.ContractCodeHistoryEntry{{
   376  				Operation: types.ContractCodeHistoryOperationTypeInit,
   377  				CodeID:    firstCodeID,
   378  				Updated:   types.NewAbsoluteTxPosition(ctx),
   379  				Msg:       []byte(`"init message"`),
   380  			}, {
   381  				Operation: types.ContractCodeHistoryOperationTypeMigrate,
   382  				CodeID:    2,
   383  				Updated:   types.NewAbsoluteTxPosition(ctx),
   384  				Msg:       []byte(`"migrate message 1"`),
   385  			}},
   386  			req: types.QueryContractHistoryRequest{
   387  				Address: myContractBech32Addr,
   388  				Pagination: &query.PageRequest{
   389  					Offset: 1,
   390  				},
   391  			},
   392  			expContent: []types.ContractCodeHistoryEntry{{
   393  				Operation: types.ContractCodeHistoryOperationTypeMigrate,
   394  				CodeID:    2,
   395  				Msg:       []byte(`"migrate message 1"`),
   396  			}},
   397  		},
   398  		"with pagination limit": {
   399  			srcHistory: []types.ContractCodeHistoryEntry{{
   400  				Operation: types.ContractCodeHistoryOperationTypeInit,
   401  				CodeID:    firstCodeID,
   402  				Updated:   types.NewAbsoluteTxPosition(ctx),
   403  				Msg:       []byte(`"init message"`),
   404  			}, {
   405  				Operation: types.ContractCodeHistoryOperationTypeMigrate,
   406  				CodeID:    2,
   407  				Updated:   types.NewAbsoluteTxPosition(ctx),
   408  				Msg:       []byte(`"migrate message 1"`),
   409  			}},
   410  			req: types.QueryContractHistoryRequest{
   411  				Address: myContractBech32Addr,
   412  				Pagination: &query.PageRequest{
   413  					Limit: 1,
   414  				},
   415  			},
   416  			expContent: []types.ContractCodeHistoryEntry{{
   417  				Operation: types.ContractCodeHistoryOperationTypeInit,
   418  				CodeID:    firstCodeID,
   419  				Msg:       []byte(`"init message"`),
   420  			}},
   421  		},
   422  		"unknown contract address": {
   423  			req: types.QueryContractHistoryRequest{Address: otherBech32Addr},
   424  			srcHistory: []types.ContractCodeHistoryEntry{{
   425  				Operation: types.ContractCodeHistoryOperationTypeGenesis,
   426  				CodeID:    firstCodeID,
   427  				Updated:   types.NewAbsoluteTxPosition(ctx),
   428  				Msg:       []byte(`"init message"`),
   429  			}},
   430  			expContent: nil,
   431  		},
   432  	}
   433  	for msg, spec := range specs {
   434  		t.Run(msg, func(t *testing.T) {
   435  			xCtx, _ := ctx.CacheContext()
   436  
   437  			cAddr, _ := sdk.AccAddressFromBech32(myContractBech32Addr)
   438  			keeper.appendToContractHistory(xCtx, cAddr, spec.srcHistory...)
   439  
   440  			// when
   441  			q := Querier(keeper)
   442  			got, err := q.ContractHistory(sdk.WrapSDKContext(xCtx), &spec.req)
   443  
   444  			// then
   445  			if spec.expContent == nil {
   446  				require.Error(t, types.ErrEmpty)
   447  				return
   448  			}
   449  			require.NoError(t, err)
   450  			assert.Equal(t, spec.expContent, got.Entries)
   451  		})
   452  	}
   453  }
   454  
   455  func TestQueryCodeList(t *testing.T) {
   456  	wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm")
   457  	require.NoError(t, err)
   458  
   459  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   460  	keeper := keepers.WasmKeeper
   461  
   462  	specs := map[string]struct {
   463  		storedCodeIDs []uint64
   464  		req           types.QueryCodesRequest
   465  		expCodeIDs    []uint64
   466  	}{
   467  		"none": {},
   468  		"no gaps": {
   469  			storedCodeIDs: []uint64{1, 2, 3},
   470  			expCodeIDs:    []uint64{1, 2, 3},
   471  		},
   472  		"with gaps": {
   473  			storedCodeIDs: []uint64{2, 4, 6},
   474  			expCodeIDs:    []uint64{2, 4, 6},
   475  		},
   476  		"with pagination offset": {
   477  			storedCodeIDs: []uint64{1, 2, 3},
   478  			req: types.QueryCodesRequest{
   479  				Pagination: &query.PageRequest{
   480  					Offset: 1,
   481  				},
   482  			},
   483  			expCodeIDs: []uint64{2, 3},
   484  		},
   485  		"with pagination limit": {
   486  			storedCodeIDs: []uint64{1, 2, 3},
   487  			req: types.QueryCodesRequest{
   488  				Pagination: &query.PageRequest{
   489  					Limit: 2,
   490  				},
   491  			},
   492  			expCodeIDs: []uint64{1, 2},
   493  		},
   494  		"with pagination next key": {
   495  			storedCodeIDs: []uint64{1, 2, 3},
   496  			req: types.QueryCodesRequest{
   497  				Pagination: &query.PageRequest{
   498  					Key: fromBase64("AAAAAAAAAAI="),
   499  				},
   500  			},
   501  			expCodeIDs: []uint64{2, 3},
   502  		},
   503  	}
   504  
   505  	for msg, spec := range specs {
   506  		t.Run(msg, func(t *testing.T) {
   507  			xCtx, _ := ctx.CacheContext()
   508  
   509  			for _, codeID := range spec.storedCodeIDs {
   510  				require.NoError(t, keeper.importCode(xCtx, codeID,
   511  					types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode)),
   512  					wasmCode),
   513  				)
   514  			}
   515  			// when
   516  			q := Querier(keeper)
   517  			got, err := q.Codes(sdk.WrapSDKContext(xCtx), &spec.req)
   518  
   519  			// then
   520  			require.NoError(t, err)
   521  			require.NotNil(t, got.CodeInfos)
   522  			require.Len(t, got.CodeInfos, len(spec.expCodeIDs))
   523  			for i, exp := range spec.expCodeIDs {
   524  				assert.EqualValues(t, exp, got.CodeInfos[i].CodeID)
   525  			}
   526  		})
   527  	}
   528  }
   529  
   530  func TestQueryContractInfo(t *testing.T) {
   531  	var (
   532  		contractAddr = RandomAccountAddress(t)
   533  		//anyDate      = time.Now().UTC()
   534  	)
   535  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   536  	// register an example extension. must be protobuf
   537  	keepers.EncodingConfig.InterfaceRegistry.RegisterImplementations(
   538  		(*types.ContractInfoExtension)(nil),
   539  	)
   540  
   541  	k := keepers.WasmKeeper
   542  	querier := NewGrpcQuerier(*k.cdc, k.storeKey, k, k.queryGasLimit)
   543  	myExtension := func(info *types.ContractInfo) {
   544  		//TODO proposal need not support
   545  		//// abuse gov proposal as a random protobuf extension with an Any type
   546  		//myExt, err := govtypes.NewProposal(&govtypes.TextProposal{Title: "foo", Description: "bar"}, 1, anyDate, anyDate)
   547  		//require.NoError(t, err)
   548  		//myExt.TotalDeposit = nil
   549  		//info.SetExtension(&myExt)
   550  	}
   551  	specs := map[string]struct {
   552  		src    *types.QueryContractInfoRequest
   553  		stored types.ContractInfo
   554  		expRsp *types.QueryContractInfoResponse
   555  		expErr bool
   556  	}{
   557  		"found": {
   558  			src:    &types.QueryContractInfoRequest{Address: contractAddr.String()},
   559  			stored: types.ContractInfoFixture(),
   560  			expRsp: &types.QueryContractInfoResponse{
   561  				Address: contractAddr.String(),
   562  				ContractInfo: types.ContractInfoFixture(func(info *types.ContractInfo) {
   563  					info.Created = nil // not returned on queries
   564  				}),
   565  			},
   566  		},
   567  		"with extension": {
   568  			src:    &types.QueryContractInfoRequest{Address: contractAddr.String()},
   569  			stored: types.ContractInfoFixture(myExtension),
   570  			expRsp: &types.QueryContractInfoResponse{
   571  				Address: contractAddr.String(),
   572  				ContractInfo: types.ContractInfoFixture(myExtension, func(info *types.ContractInfo) {
   573  					info.Created = nil // not returned on queries
   574  				}),
   575  			},
   576  		},
   577  		"not found": {
   578  			src:    &types.QueryContractInfoRequest{Address: RandomBech32AccountAddress(t)},
   579  			stored: types.ContractInfoFixture(),
   580  			expErr: true,
   581  		},
   582  	}
   583  	for name, spec := range specs {
   584  		t.Run(name, func(t *testing.T) {
   585  			xCtx, _ := ctx.CacheContext()
   586  			k.storeContractInfo(xCtx, contractAddr, &spec.stored)
   587  			// when
   588  			gotRsp, gotErr := querier.ContractInfo(sdk.WrapSDKContext(xCtx), spec.src)
   589  			if spec.expErr {
   590  				require.Error(t, gotErr)
   591  				return
   592  			}
   593  			require.NoError(t, gotErr)
   594  			assert.Equal(t, spec.expRsp, gotRsp)
   595  		})
   596  	}
   597  }
   598  
   599  func TestQueryPinnedCodes(t *testing.T) {
   600  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   601  	keeper := keepers.WasmKeeper
   602  
   603  	exampleContract1 := InstantiateHackatomExampleContract(t, ctx, keepers)
   604  	exampleContract2 := InstantiateIBCReflectContract(t, ctx, keepers)
   605  	require.NoError(t, keeper.pinCode(ctx, exampleContract1.CodeID))
   606  	require.NoError(t, keeper.pinCode(ctx, exampleContract2.CodeID))
   607  
   608  	q := Querier(keeper)
   609  	specs := map[string]struct {
   610  		srcQuery   *types.QueryPinnedCodesRequest
   611  		expCodeIDs []uint64
   612  		expErr     *sdkErrors.Error
   613  	}{
   614  		"query all": {
   615  			srcQuery:   &types.QueryPinnedCodesRequest{},
   616  			expCodeIDs: []uint64{exampleContract1.CodeID, exampleContract2.CodeID},
   617  		},
   618  		"with pagination offset": {
   619  			srcQuery: &types.QueryPinnedCodesRequest{
   620  				Pagination: &query.PageRequest{
   621  					Offset: 1,
   622  				},
   623  			},
   624  			expCodeIDs: []uint64{exampleContract2.CodeID},
   625  		},
   626  		"with pagination limit": {
   627  			srcQuery: &types.QueryPinnedCodesRequest{
   628  				Pagination: &query.PageRequest{
   629  					Limit: 1,
   630  				},
   631  			},
   632  			expCodeIDs: []uint64{exampleContract1.CodeID},
   633  		},
   634  		"with pagination next key": {
   635  			srcQuery: &types.QueryPinnedCodesRequest{
   636  				Pagination: &query.PageRequest{
   637  					Key: fromBase64("AAAAAAAAAAM="),
   638  				},
   639  			},
   640  			expCodeIDs: []uint64{exampleContract2.CodeID},
   641  		},
   642  	}
   643  	for msg, spec := range specs {
   644  		t.Run(msg, func(t *testing.T) {
   645  			got, err := q.PinnedCodes(sdk.WrapSDKContext(ctx), spec.srcQuery)
   646  			require.True(t, spec.expErr.Is(err), err)
   647  			if spec.expErr != nil {
   648  				return
   649  			}
   650  			require.NotNil(t, got)
   651  			assert.Equal(t, spec.expCodeIDs, got.CodeIDs)
   652  		})
   653  	}
   654  }
   655  
   656  func TestQueryCodeInfo(t *testing.T) {
   657  	wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm")
   658  	require.NoError(t, err)
   659  
   660  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   661  	keeper := keepers.WasmKeeper
   662  
   663  	anyAddress, err := sdk.AccAddressFromBech32("cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz")
   664  	require.NoError(t, err)
   665  	specs := map[string]struct {
   666  		codeId       uint64
   667  		accessConfig types.AccessConfig
   668  	}{
   669  		"everybody": {
   670  			codeId:       1,
   671  			accessConfig: types.AllowEverybody,
   672  		},
   673  		"nobody": {
   674  			codeId:       10,
   675  			accessConfig: types.AllowNobody,
   676  		},
   677  		"with_address": {
   678  			codeId:       20,
   679  			accessConfig: types.AccessTypeOnlyAddress.With(anyAddress),
   680  		},
   681  	}
   682  	for msg, spec := range specs {
   683  		t.Run(msg, func(t *testing.T) {
   684  			codeInfo := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode))
   685  			codeInfo.InstantiateConfig = spec.accessConfig
   686  			require.NoError(t, keeper.importCode(ctx, spec.codeId,
   687  				codeInfo,
   688  				wasmCode),
   689  			)
   690  
   691  			q := Querier(keeper)
   692  			got, err := q.Code(sdk.WrapSDKContext(ctx), &types.QueryCodeRequest{
   693  				CodeId: spec.codeId,
   694  			})
   695  			require.NoError(t, err)
   696  			expectedResponse := &types.QueryCodeResponse{
   697  				CodeInfoResponse: &types.CodeInfoResponse{
   698  					CodeID:                spec.codeId,
   699  					Creator:               codeInfo.Creator,
   700  					DataHash:              codeInfo.CodeHash,
   701  					InstantiatePermission: spec.accessConfig,
   702  				},
   703  				Data: wasmCode,
   704  			}
   705  			require.NotNil(t, got.CodeInfoResponse)
   706  			require.EqualValues(t, expectedResponse, got)
   707  		})
   708  	}
   709  }
   710  
   711  func TestQueryCodeInfoList(t *testing.T) {
   712  	wasmCode, err := ioutil.ReadFile("./testdata/hackatom.wasm")
   713  	require.NoError(t, err)
   714  
   715  	ctx, keepers := CreateTestInput(t, false, SupportedFeatures)
   716  	keeper := keepers.WasmKeeper
   717  
   718  	anyAddress, err := sdk.AccAddressFromBech32("cosmos100dejzacpanrldpjjwksjm62shqhyss44jf5xz")
   719  	require.NoError(t, err)
   720  	codeInfoWithConfig := func(accessConfig types.AccessConfig) types.CodeInfo {
   721  		codeInfo := types.CodeInfoFixture(types.WithSHA256CodeHash(wasmCode))
   722  		codeInfo.InstantiateConfig = accessConfig
   723  		return codeInfo
   724  	}
   725  
   726  	codes := []struct {
   727  		name     string
   728  		codeId   uint64
   729  		codeInfo types.CodeInfo
   730  	}{
   731  		{
   732  			name:     "everybody",
   733  			codeId:   1,
   734  			codeInfo: codeInfoWithConfig(types.AllowEverybody),
   735  		},
   736  		{
   737  			codeId:   10,
   738  			name:     "nobody",
   739  			codeInfo: codeInfoWithConfig(types.AllowNobody),
   740  		},
   741  		{
   742  			name:     "with_address",
   743  			codeId:   20,
   744  			codeInfo: codeInfoWithConfig(types.AccessTypeOnlyAddress.With(anyAddress)),
   745  		},
   746  	}
   747  
   748  	allCodesResponse := make([]types.CodeInfoResponse, 0)
   749  	for _, code := range codes {
   750  		t.Run(fmt.Sprintf("import_%s", code.name), func(t *testing.T) {
   751  			require.NoError(t, keeper.importCode(ctx, code.codeId,
   752  				code.codeInfo,
   753  				wasmCode),
   754  			)
   755  		})
   756  
   757  		allCodesResponse = append(allCodesResponse, types.CodeInfoResponse{
   758  			CodeID:                code.codeId,
   759  			Creator:               code.codeInfo.Creator,
   760  			DataHash:              code.codeInfo.CodeHash,
   761  			InstantiatePermission: code.codeInfo.InstantiateConfig,
   762  		})
   763  	}
   764  	q := Querier(keeper)
   765  	got, err := q.Codes(sdk.WrapSDKContext(ctx), &types.QueryCodesRequest{
   766  		Pagination: &query.PageRequest{
   767  			Limit: 3,
   768  		},
   769  	})
   770  	require.NoError(t, err)
   771  	require.Len(t, got.CodeInfos, 3)
   772  	require.EqualValues(t, allCodesResponse, got.CodeInfos)
   773  }
   774  
   775  func fromBase64(s string) []byte {
   776  	r, err := base64.StdEncoding.DecodeString(s)
   777  	if err != nil {
   778  		panic(err)
   779  	}
   780  	return r
   781  }