Skip to content

Commit

Permalink
Handle contract info query
Browse files Browse the repository at this point in the history
  • Loading branch information
alpe committed Sep 27, 2021
1 parent fc8d33e commit bc785a4
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 18 deletions.
31 changes: 25 additions & 6 deletions x/wasm/keeper/query_plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ type wasmQueryKeeper interface {
contractMetaDataSource
QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte
QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error)
IsPinnedCode(ctx sdk.Context, codeID uint64) bool
}

func DefaultQueryPlugins(
Expand Down Expand Up @@ -459,21 +460,39 @@ func getAccumulatedRewards(ctx sdk.Context, distKeeper types.DistributionKeeper,
return rewards, nil
}

func WasmQuerier(wasm wasmQueryKeeper) func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error) {
func WasmQuerier(k wasmQueryKeeper) func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error) {
return func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error) {
if request.Smart != nil {
switch {
case request.Smart != nil:
addr, err := sdk.AccAddressFromBech32(request.Smart.ContractAddr)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.Smart.ContractAddr)
}
return wasm.QuerySmart(ctx, addr, request.Smart.Msg)
}
if request.Raw != nil {
return k.QuerySmart(ctx, addr, request.Smart.Msg)
case request.Raw != nil:
addr, err := sdk.AccAddressFromBech32(request.Raw.ContractAddr)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.Raw.ContractAddr)
}
return wasm.QueryRaw(ctx, addr, request.Raw.Key), nil
return k.QueryRaw(ctx, addr, request.Raw.Key), nil
case request.ContractInfo != nil:
addr, err := sdk.AccAddressFromBech32(request.ContractInfo.ContractAddr)
if err != nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, request.ContractInfo.ContractAddr)
}
info := k.GetContractInfo(ctx, addr)
if info == nil {
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownAddress, request.ContractInfo.ContractAddr)
}

res := wasmvmtypes.ContractInfoResponse{
CodeID: info.CodeID,
Creator: info.Creator,
Admin: info.Admin,
Pinned: k.IsPinnedCode(ctx, info.CodeID),
IBCPort: info.IBCPortID,
}
return json.Marshal(res)
}
return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown WasmQuery variant"}
}
Expand Down
147 changes: 135 additions & 12 deletions x/wasm/keeper/query_plugins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestIBCQuerier(t *testing.T) {
}
specs := map[string]struct {
srcQuery *wasmvmtypes.IBCQuery
wasmKeeper *wasmKeeperMock
wasmKeeper *mockWasmQueryKeeper
channelKeeper *wasmtesting.MockChannelKeeper
expJsonResult string
expErr *sdkerrors.Error
Expand All @@ -78,11 +78,11 @@ func TestIBCQuerier(t *testing.T) {
srcQuery: &wasmvmtypes.IBCQuery{
PortID: &wasmvmtypes.PortIDQuery{},
},
wasmKeeper: newWasmKeeperMock(
func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
wasmKeeper: &mockWasmQueryKeeper{
GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
return &types.ContractInfo{IBCPortID: "myIBCPortID"}
},
),
},
channelKeeper: &wasmtesting.MockChannelKeeper{},
expJsonResult: `{"port_id":"myIBCPortID"}`,
},
Expand Down Expand Up @@ -205,9 +205,11 @@ func TestIBCQuerier(t *testing.T) {
ChannelID: "myQueryChannelID",
},
},
wasmKeeper: newWasmKeeperMock(func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
return &types.ContractInfo{IBCPortID: "myLoadedPortID"}
}),
wasmKeeper: &mockWasmQueryKeeper{
GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
return &types.ContractInfo{IBCPortID: "myLoadedPortID"}
},
},
channelKeeper: &wasmtesting.MockChannelKeeper{
GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) {
return channeltypes.Channel{
Expand Down Expand Up @@ -337,21 +339,142 @@ func TestBankQuerierBalance(t *testing.T) {
assert.Equal(t, exp, got)
}

type wasmKeeperMock struct {
GetContractInfoFn func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo
func TestContractInfoWasmQuerier(t *testing.T) {
var myValidContractAddr = RandomBech32AccountAddress(t)
var myCreatorAddr = RandomBech32AccountAddress(t)
var myAdminAddr = RandomBech32AccountAddress(t)
var ctx sdk.Context

specs := map[string]struct {
req *wasmvmtypes.WasmQuery
mock mockWasmQueryKeeper
expRes wasmvmtypes.ContractInfoResponse
expErr bool
}{
"all good": {
req: &wasmvmtypes.WasmQuery{
ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr},
},
mock: mockWasmQueryKeeper{GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
val := types.ContractInfoFixture(func(i *types.ContractInfo) {
i.Admin, i.Creator, i.IBCPortID = myAdminAddr, myCreatorAddr, "myIBCPort"
})
return &val
},
IsPinnedCodeFn: func(ctx sdk.Context, codeID uint64) bool { return true },
},
expRes: wasmvmtypes.ContractInfoResponse{
CodeID: 1,
Creator: myCreatorAddr,
Admin: myAdminAddr,
Pinned: true,
IBCPort: "myIBCPort",
},
},
"invalid addr": {
req: &wasmvmtypes.WasmQuery{
ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: "not a valid addr"},
},
expErr: true,
},
"unknown addr": {
req: &wasmvmtypes.WasmQuery{
ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr},
},
mock: mockWasmQueryKeeper{GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
return nil
}},
expErr: true,
},
"not pinned": {
req: &wasmvmtypes.WasmQuery{
ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr},
},
mock: mockWasmQueryKeeper{GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
val := types.ContractInfoFixture(func(i *types.ContractInfo) {
i.Admin, i.Creator = myAdminAddr, myCreatorAddr
})
return &val
},
IsPinnedCodeFn: func(ctx sdk.Context, codeID uint64) bool { return false },
},
expRes: wasmvmtypes.ContractInfoResponse{
CodeID: 1,
Creator: myCreatorAddr,
Admin: myAdminAddr,
Pinned: false,
},
},
"without admin": {
req: &wasmvmtypes.WasmQuery{
ContractInfo: &wasmvmtypes.ContractInfoQuery{ContractAddr: myValidContractAddr},
},
mock: mockWasmQueryKeeper{GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
val := types.ContractInfoFixture(func(i *types.ContractInfo) {
i.Creator = myCreatorAddr
})
return &val
},
IsPinnedCodeFn: func(ctx sdk.Context, codeID uint64) bool { return true },
},
expRes: wasmvmtypes.ContractInfoResponse{
CodeID: 1,
Creator: myCreatorAddr,
Pinned: true,
},
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
q := WasmQuerier(spec.mock)
gotBz, gotErr := q(ctx, spec.req)
if spec.expErr {
require.Error(t, gotErr)
return
}
require.NoError(t, gotErr)
var gotRes wasmvmtypes.ContractInfoResponse
require.NoError(t, json.Unmarshal(gotBz, &gotRes))
assert.Equal(t, spec.expRes, gotRes)
})
}
}

func newWasmKeeperMock(f func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo) *wasmKeeperMock {
return &wasmKeeperMock{GetContractInfoFn: f}
type mockWasmQueryKeeper struct {
GetContractInfoFn func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo
QueryRawFn func(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte
QuerySmartFn func(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error)
IsPinnedCodeFn func(ctx sdk.Context, codeID uint64) bool
}

func (m wasmKeeperMock) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
func (m mockWasmQueryKeeper) GetContractInfo(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
if m.GetContractInfoFn == nil {
panic("not expected to be called")
}
return m.GetContractInfoFn(ctx, contractAddress)
}

func (m mockWasmQueryKeeper) QueryRaw(ctx sdk.Context, contractAddress sdk.AccAddress, key []byte) []byte {
if m.QueryRawFn == nil {
panic("not expected to be called")
}
return m.QueryRawFn(ctx, contractAddress, key)
}

func (m mockWasmQueryKeeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []byte) ([]byte, error) {
if m.QuerySmartFn == nil {
panic("not expected to be called")
}
return m.QuerySmartFn(ctx, contractAddr, req)
}

func (m mockWasmQueryKeeper) IsPinnedCode(ctx sdk.Context, codeID uint64) bool {
if m.IsPinnedCodeFn == nil {
panic("not expected to be called")
}
return m.IsPinnedCodeFn(ctx, codeID)
}

type bankKeeperMock struct {
GetBalanceFn func(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin
GetAllBalancesFn func(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins
Expand Down

0 comments on commit bc785a4

Please sign in to comment.