github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/wasm/keeper/query_plugins_test.go (about) 1 package keeper 2 3 import ( 4 "encoding/json" 5 "testing" 6 7 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/store" 8 dbm "github.com/fibonacci-chain/fbc/libs/tm-db" 9 10 wasmvmtypes "github.com/CosmWasm/wasmvm/types" 11 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 12 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 13 channeltypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/04-channel/types" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 "github.com/fibonacci-chain/fbc/x/wasm/keeper/wasmtesting" 18 "github.com/fibonacci-chain/fbc/x/wasm/types" 19 ) 20 21 func TestIBCQuerier(t *testing.T) { 22 myExampleChannels := []channeltypes.IdentifiedChannel{ 23 // this is returned 24 { 25 State: channeltypes.OPEN, 26 Ordering: channeltypes.ORDERED, 27 Counterparty: channeltypes.Counterparty{ 28 PortId: "counterPartyPortID", 29 ChannelId: "counterPartyChannelID", 30 }, 31 ConnectionHops: []string{"one"}, 32 Version: "v1", 33 PortId: "myPortID", 34 ChannelId: "myChannelID", 35 }, 36 // this is filtered out 37 { 38 State: channeltypes.INIT, 39 Ordering: channeltypes.UNORDERED, 40 Counterparty: channeltypes.Counterparty{ 41 PortId: "foobar", 42 }, 43 ConnectionHops: []string{"one"}, 44 Version: "initversion", 45 PortId: "initPortID", 46 ChannelId: "initChannelID", 47 }, 48 // this is returned 49 { 50 State: channeltypes.OPEN, 51 Ordering: channeltypes.UNORDERED, 52 Counterparty: channeltypes.Counterparty{ 53 PortId: "otherCounterPartyPortID", 54 ChannelId: "otherCounterPartyChannelID", 55 }, 56 ConnectionHops: []string{"other", "second"}, 57 Version: "otherVersion", 58 PortId: "otherPortID", 59 ChannelId: "otherChannelID", 60 }, 61 // this is filtered out 62 { 63 State: channeltypes.CLOSED, 64 Ordering: channeltypes.ORDERED, 65 Counterparty: channeltypes.Counterparty{ 66 PortId: "super", 67 ChannelId: "duper", 68 }, 69 ConnectionHops: []string{"no-more"}, 70 Version: "closedVersion", 71 PortId: "closedPortID", 72 ChannelId: "closedChannelID", 73 }, 74 } 75 specs := map[string]struct { 76 srcQuery *wasmvmtypes.IBCQuery 77 wasmKeeper *mockWasmQueryKeeper 78 channelKeeper *wasmtesting.MockChannelKeeper 79 expJsonResult string 80 expErr *sdkerrors.Error 81 }{ 82 "query port id": { 83 srcQuery: &wasmvmtypes.IBCQuery{ 84 PortID: &wasmvmtypes.PortIDQuery{}, 85 }, 86 wasmKeeper: &mockWasmQueryKeeper{ 87 GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { 88 return &types.ContractInfo{IBCPortID: "myIBCPortID"} 89 }, 90 }, 91 channelKeeper: &wasmtesting.MockChannelKeeper{}, 92 expJsonResult: `{"port_id":"myIBCPortID"}`, 93 }, 94 "query list channels - all": { 95 srcQuery: &wasmvmtypes.IBCQuery{ 96 ListChannels: &wasmvmtypes.ListChannelsQuery{}, 97 }, 98 channelKeeper: &wasmtesting.MockChannelKeeper{ 99 IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels), 100 }, 101 expJsonResult: `{ 102 "channels": [ 103 { 104 "endpoint": { 105 "port_id": "myPortID", 106 "channel_id": "myChannelID" 107 }, 108 "counterparty_endpoint": { 109 "port_id": "counterPartyPortID", 110 "channel_id": "counterPartyChannelID" 111 }, 112 "order": "ORDER_ORDERED", 113 "version": "v1", 114 "connection_id": "one" 115 }, 116 { 117 "endpoint": { 118 "port_id": "otherPortID", 119 "channel_id": "otherChannelID" 120 }, 121 "counterparty_endpoint": { 122 "port_id": "otherCounterPartyPortID", 123 "channel_id": "otherCounterPartyChannelID" 124 }, 125 "order": "ORDER_UNORDERED", 126 "version": "otherVersion", 127 "connection_id": "other" 128 } 129 ] 130 }`, 131 }, 132 "query list channels - filtered": { 133 srcQuery: &wasmvmtypes.IBCQuery{ 134 ListChannels: &wasmvmtypes.ListChannelsQuery{ 135 PortID: "otherPortID", 136 }, 137 }, 138 channelKeeper: &wasmtesting.MockChannelKeeper{ 139 IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels), 140 }, 141 expJsonResult: `{ 142 "channels": [ 143 { 144 "endpoint": { 145 "port_id": "otherPortID", 146 "channel_id": "otherChannelID" 147 }, 148 "counterparty_endpoint": { 149 "port_id": "otherCounterPartyPortID", 150 "channel_id": "otherCounterPartyChannelID" 151 }, 152 "order": "ORDER_UNORDERED", 153 "version": "otherVersion", 154 "connection_id": "other" 155 } 156 ] 157 }`, 158 }, 159 "query list channels - filtered empty": { 160 srcQuery: &wasmvmtypes.IBCQuery{ 161 ListChannels: &wasmvmtypes.ListChannelsQuery{ 162 PortID: "none-existing", 163 }, 164 }, 165 channelKeeper: &wasmtesting.MockChannelKeeper{ 166 IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels), 167 }, 168 expJsonResult: `{"channels": []}`, 169 }, 170 "query channel": { 171 srcQuery: &wasmvmtypes.IBCQuery{ 172 Channel: &wasmvmtypes.ChannelQuery{ 173 PortID: "myQueryPortID", 174 ChannelID: "myQueryChannelID", 175 }, 176 }, 177 channelKeeper: &wasmtesting.MockChannelKeeper{ 178 GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { 179 return channeltypes.Channel{ 180 State: channeltypes.OPEN, 181 Ordering: channeltypes.UNORDERED, 182 Counterparty: channeltypes.Counterparty{ 183 PortId: "counterPartyPortID", 184 ChannelId: "otherCounterPartyChannelID", 185 }, 186 ConnectionHops: []string{"one"}, 187 Version: "version", 188 }, true 189 }, 190 }, 191 expJsonResult: `{ 192 "channel": { 193 "endpoint": { 194 "port_id": "myQueryPortID", 195 "channel_id": "myQueryChannelID" 196 }, 197 "counterparty_endpoint": { 198 "port_id": "counterPartyPortID", 199 "channel_id": "otherCounterPartyChannelID" 200 }, 201 "order": "ORDER_UNORDERED", 202 "version": "version", 203 "connection_id": "one" 204 } 205 }`, 206 }, 207 "query channel - without port set": { 208 srcQuery: &wasmvmtypes.IBCQuery{ 209 Channel: &wasmvmtypes.ChannelQuery{ 210 ChannelID: "myQueryChannelID", 211 }, 212 }, 213 wasmKeeper: &mockWasmQueryKeeper{ 214 GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { 215 return &types.ContractInfo{IBCPortID: "myLoadedPortID"} 216 }, 217 }, 218 channelKeeper: &wasmtesting.MockChannelKeeper{ 219 GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { 220 return channeltypes.Channel{ 221 State: channeltypes.OPEN, 222 Ordering: channeltypes.UNORDERED, 223 Counterparty: channeltypes.Counterparty{ 224 PortId: "counterPartyPortID", 225 ChannelId: "otherCounterPartyChannelID", 226 }, 227 ConnectionHops: []string{"one"}, 228 Version: "version", 229 }, true 230 }, 231 }, 232 expJsonResult: `{ 233 "channel": { 234 "endpoint": { 235 "port_id": "myLoadedPortID", 236 "channel_id": "myQueryChannelID" 237 }, 238 "counterparty_endpoint": { 239 "port_id": "counterPartyPortID", 240 "channel_id": "otherCounterPartyChannelID" 241 }, 242 "order": "ORDER_UNORDERED", 243 "version": "version", 244 "connection_id": "one" 245 } 246 }`, 247 }, 248 "query channel in init state": { 249 srcQuery: &wasmvmtypes.IBCQuery{ 250 Channel: &wasmvmtypes.ChannelQuery{ 251 PortID: "myQueryPortID", 252 ChannelID: "myQueryChannelID", 253 }, 254 }, 255 channelKeeper: &wasmtesting.MockChannelKeeper{ 256 GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { 257 return channeltypes.Channel{ 258 State: channeltypes.INIT, 259 Ordering: channeltypes.UNORDERED, 260 Counterparty: channeltypes.Counterparty{ 261 PortId: "foobar", 262 }, 263 ConnectionHops: []string{"one"}, 264 Version: "initversion", 265 }, true 266 }, 267 }, 268 expJsonResult: "{}", 269 }, 270 "query channel in closed state": { 271 srcQuery: &wasmvmtypes.IBCQuery{ 272 Channel: &wasmvmtypes.ChannelQuery{ 273 PortID: "myQueryPortID", 274 ChannelID: "myQueryChannelID", 275 }, 276 }, 277 channelKeeper: &wasmtesting.MockChannelKeeper{ 278 GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { 279 return channeltypes.Channel{ 280 State: channeltypes.CLOSED, 281 Ordering: channeltypes.ORDERED, 282 Counterparty: channeltypes.Counterparty{ 283 PortId: "super", 284 ChannelId: "duper", 285 }, 286 ConnectionHops: []string{"no-more"}, 287 Version: "closedVersion", 288 }, true 289 }, 290 }, 291 expJsonResult: "{}", 292 }, 293 "query channel - empty result": { 294 srcQuery: &wasmvmtypes.IBCQuery{ 295 Channel: &wasmvmtypes.ChannelQuery{ 296 PortID: "myQueryPortID", 297 ChannelID: "myQueryChannelID", 298 }, 299 }, 300 channelKeeper: &wasmtesting.MockChannelKeeper{ 301 GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) { 302 return channeltypes.Channel{}, false 303 }, 304 }, 305 expJsonResult: "{}", 306 }, 307 } 308 for name, spec := range specs { 309 t.Run(name, func(t *testing.T) { 310 h := IBCQuerier(spec.wasmKeeper, spec.channelKeeper) 311 gotResult, gotErr := h(sdk.Context{}, RandomAccountAddress(t), spec.srcQuery) 312 require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr) 313 if spec.expErr != nil { 314 return 315 } 316 assert.JSONEq(t, spec.expJsonResult, string(gotResult), string(gotResult)) 317 }) 318 } 319 } 320 321 func TestBankQuerierBalance(t *testing.T) { 322 mock := bankKeeperMock{GetBalanceFn: func(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { 323 return sdk.NewCoin(denom, sdk.NewInt(1)) 324 }} 325 326 ctx := sdk.Context{} 327 q := BankQuerier(mock) 328 gotBz, gotErr := q(ctx, &wasmvmtypes.BankQuery{ 329 Balance: &wasmvmtypes.BalanceQuery{ 330 Address: RandomBech32AccountAddress(t), 331 Denom: "alx", 332 }, 333 }) 334 require.NoError(t, gotErr) 335 var got wasmvmtypes.BalanceResponse 336 require.NoError(t, json.Unmarshal(gotBz, &got)) 337 exp := wasmvmtypes.BalanceResponse{ 338 Amount: wasmvmtypes.Coin{ 339 Denom: "alx", 340 Amount: "1000000000000000000", 341 }, 342 } 343 assert.Equal(t, exp, got) 344 } 345 346 func TestContractInfoWasmQuerier(t *testing.T) { 347 myValidContractAddr := RandomBech32AccountAddress(t) 348 myCreatorAddr := RandomBech32AccountAddress(t) 349 myAdminAddr := RandomBech32AccountAddress(t) 350 var ctx sdk.Context 351 352 specs := map[string]struct { 353 req *wasmvmtypes.WasmQuery 354 mock mockWasmQueryKeeper 355 expRes wasmvmtypes.ContractInfoResponse 356 expErr bool 357 }{ 358 "all good": { 359 req: &wasmvmtypes.WasmQuery{ 360 ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr}, 361 }, 362 mock: mockWasmQueryKeeper{ 363 GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { 364 val := types.ContractInfoFixture(func(i *types.ContractInfo) { 365 i.Admin, i.Creator, i.IBCPortID = myAdminAddr, myCreatorAddr, "myIBCPort" 366 }) 367 return &val 368 }, 369 IsPinnedCodeFn: func(ctx sdk.Context, codeID uint64) bool { return true }, 370 }, 371 expRes: wasmvmtypes.ContractInfoResponse{ 372 CodeID: 1, 373 Creator: myCreatorAddr, 374 Admin: myAdminAddr, 375 Pinned: true, 376 IBCPort: "myIBCPort", 377 }, 378 }, 379 "invalid addr": { 380 req: &wasmvmtypes.WasmQuery{ 381 ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: "not a valid addr"}, 382 }, 383 expErr: true, 384 }, 385 "unknown addr": { 386 req: &wasmvmtypes.WasmQuery{ 387 ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr}, 388 }, 389 mock: mockWasmQueryKeeper{GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { 390 return nil 391 }}, 392 expErr: true, 393 }, 394 "not pinned": { 395 req: &wasmvmtypes.WasmQuery{ 396 ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr}, 397 }, 398 mock: mockWasmQueryKeeper{ 399 GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { 400 val := types.ContractInfoFixture(func(i *types.ContractInfo) { 401 i.Admin, i.Creator = myAdminAddr, myCreatorAddr 402 }) 403 return &val 404 }, 405 IsPinnedCodeFn: func(ctx sdk.Context, codeID uint64) bool { return false }, 406 }, 407 expRes: wasmvmtypes.ContractInfoResponse{ 408 CodeID: 1, 409 Creator: myCreatorAddr, 410 Admin: myAdminAddr, 411 Pinned: false, 412 }, 413 }, 414 "without admin": { 415 req: &wasmvmtypes.WasmQuery{ 416 ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr}, 417 }, 418 mock: mockWasmQueryKeeper{ 419 GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { 420 val := types.ContractInfoFixture(func(i *types.ContractInfo) { 421 i.Creator = myCreatorAddr 422 }) 423 return &val 424 }, 425 IsPinnedCodeFn: func(ctx sdk.Context, codeID uint64) bool { return true }, 426 }, 427 expRes: wasmvmtypes.ContractInfoResponse{ 428 CodeID: 1, 429 Creator: myCreatorAddr, 430 Pinned: true, 431 }, 432 }, 433 } 434 for name, spec := range specs { 435 t.Run(name, func(t *testing.T) { 436 q := WasmQuerier(spec.mock) 437 gotBz, gotErr := q(ctx, spec.req) 438 if spec.expErr { 439 require.Error(t, gotErr) 440 return 441 } 442 require.NoError(t, gotErr) 443 var gotRes wasmvmtypes.ContractInfoResponse 444 require.NoError(t, json.Unmarshal(gotBz, &gotRes)) 445 assert.Equal(t, spec.expRes, gotRes) 446 }) 447 } 448 } 449 450 func TestQueryErrors(t *testing.T) { 451 specs := map[string]struct { 452 src error 453 expErr error 454 }{ 455 "no error": {}, 456 "no such contract": { 457 src: &types.ErrNoSuchContract{Addr: "contract-addr"}, 458 expErr: wasmvmtypes.NoSuchContract{Addr: "contract-addr"}, 459 }, 460 "no such contract - wrapped": { 461 src: sdkerrors.Wrap(&types.ErrNoSuchContract{Addr: "contract-addr"}, "my additional data"), 462 expErr: wasmvmtypes.NoSuchContract{Addr: "contract-addr"}, 463 }, 464 } 465 for name, spec := range specs { 466 t.Run(name, func(t *testing.T) { 467 mock := WasmVMQueryHandlerFn(func(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) { 468 return nil, spec.src 469 }) 470 ctx := sdk.Context{} 471 ctx.SetGasMeter(sdk.NewInfiniteGasMeter()) 472 ctx.SetMultiStore(store.NewCommitMultiStore(dbm.NewMemDB())) 473 q := NewQueryHandler(ctx, mock, sdk.AccAddress{}, NewDefaultWasmGasRegister()) 474 _, gotErr := q.Query(wasmvmtypes.QueryRequest{}, 1) 475 assert.Equal(t, spec.expErr, gotErr) 476 }) 477 } 478 } 479 480 type mockWasmQueryKeeper struct { 481 GetContractInfoFn func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo 482 QueryRawFn func(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte 483 QuerySmartFn func(ctx sdk.Context, contractAddr sdk.AccAddress, req types.RawContractMessage) ([]byte, error) 484 IsPinnedCodeFn func(ctx sdk.Context, codeID uint64) bool 485 } 486 487 func (m mockWasmQueryKeeper) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo { 488 if m.GetContractInfoFn == nil { 489 panic("not expected to be called") 490 } 491 return m.GetContractInfoFn(ctx, contractAddress) 492 } 493 494 func (m mockWasmQueryKeeper) QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte { 495 if m.QueryRawFn == nil { 496 panic("not expected to be called") 497 } 498 return m.QueryRawFn(ctx, contractAddress, key) 499 } 500 501 func (m mockWasmQueryKeeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error) { 502 if m.QuerySmartFn == nil { 503 panic("not expected to be called") 504 } 505 return m.QuerySmartFn(ctx, contractAddr, req) 506 } 507 508 func (m mockWasmQueryKeeper) IsPinnedCode(ctx sdk.Context, codeID uint64) bool { 509 if m.IsPinnedCodeFn == nil { 510 panic("not expected to be called") 511 } 512 return m.IsPinnedCodeFn(ctx, codeID) 513 } 514 515 type bankKeeperMock struct { 516 GetBalanceFn func(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin 517 GetAllBalancesFn func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins 518 } 519 520 func (m bankKeeperMock) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin { 521 if m.GetBalanceFn == nil { 522 panic("not expected to be called") 523 } 524 return m.GetBalanceFn(ctx, addr, denom) 525 } 526 527 func (m bankKeeperMock) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins { 528 if m.GetAllBalancesFn == nil { 529 panic("not expected to be called") 530 } 531 return m.GetAllBalancesFn(ctx, addr) 532 }