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 }