mirror of https://github.com/certusone/wasmd.git
529 lines
16 KiB
Go
529 lines
16 KiB
Go
package keeper
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/cosmos/cosmos-sdk/store"
|
|
dbm "github.com/tendermint/tm-db"
|
|
|
|
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
|
channeltypes "github.com/cosmos/ibc-go/v2/modules/core/04-channel/types"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/CosmWasm/wasmd/x/wasm/keeper/wasmtesting"
|
|
"github.com/CosmWasm/wasmd/x/wasm/types"
|
|
)
|
|
|
|
func TestIBCQuerier(t *testing.T) {
|
|
myExampleChannels := []channeltypes.IdentifiedChannel{
|
|
// this is returned
|
|
{
|
|
State: channeltypes.OPEN,
|
|
Ordering: channeltypes.ORDERED,
|
|
Counterparty: channeltypes.Counterparty{
|
|
PortId: "counterPartyPortID",
|
|
ChannelId: "counterPartyChannelID",
|
|
},
|
|
ConnectionHops: []string{"one"},
|
|
Version: "v1",
|
|
PortId: "myPortID",
|
|
ChannelId: "myChannelID",
|
|
},
|
|
// this is filtered out
|
|
{
|
|
State: channeltypes.INIT,
|
|
Ordering: channeltypes.UNORDERED,
|
|
Counterparty: channeltypes.Counterparty{
|
|
PortId: "foobar",
|
|
},
|
|
ConnectionHops: []string{"one"},
|
|
Version: "initversion",
|
|
PortId: "initPortID",
|
|
ChannelId: "initChannelID",
|
|
},
|
|
// this is returned
|
|
{
|
|
State: channeltypes.OPEN,
|
|
Ordering: channeltypes.UNORDERED,
|
|
Counterparty: channeltypes.Counterparty{
|
|
PortId: "otherCounterPartyPortID",
|
|
ChannelId: "otherCounterPartyChannelID",
|
|
},
|
|
ConnectionHops: []string{"other", "second"},
|
|
Version: "otherVersion",
|
|
PortId: "otherPortID",
|
|
ChannelId: "otherChannelID",
|
|
},
|
|
// this is filtered out
|
|
{
|
|
State: channeltypes.CLOSED,
|
|
Ordering: channeltypes.ORDERED,
|
|
Counterparty: channeltypes.Counterparty{
|
|
PortId: "super",
|
|
ChannelId: "duper",
|
|
},
|
|
ConnectionHops: []string{"no-more"},
|
|
Version: "closedVersion",
|
|
PortId: "closedPortID",
|
|
ChannelId: "closedChannelID",
|
|
},
|
|
}
|
|
specs := map[string]struct {
|
|
srcQuery *wasmvmtypes.IBCQuery
|
|
wasmKeeper *mockWasmQueryKeeper
|
|
channelKeeper *wasmtesting.MockChannelKeeper
|
|
expJsonResult string
|
|
expErr *sdkerrors.Error
|
|
}{
|
|
"query port id": {
|
|
srcQuery: &wasmvmtypes.IBCQuery{
|
|
PortID: &wasmvmtypes.PortIDQuery{},
|
|
},
|
|
wasmKeeper: &mockWasmQueryKeeper{
|
|
GetContractInfoFn: func(ctx sdk.Context, contractAddress sdk.AccAddress) *types.ContractInfo {
|
|
return &types.ContractInfo{IBCPortID: "myIBCPortID"}
|
|
},
|
|
},
|
|
channelKeeper: &wasmtesting.MockChannelKeeper{},
|
|
expJsonResult: `{"port_id":"myIBCPortID"}`,
|
|
},
|
|
"query list channels - all": {
|
|
srcQuery: &wasmvmtypes.IBCQuery{
|
|
ListChannels: &wasmvmtypes.ListChannelsQuery{},
|
|
},
|
|
channelKeeper: &wasmtesting.MockChannelKeeper{
|
|
IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels),
|
|
},
|
|
expJsonResult: `{
|
|
"channels": [
|
|
{
|
|
"endpoint": {
|
|
"port_id": "myPortID",
|
|
"channel_id": "myChannelID"
|
|
},
|
|
"counterparty_endpoint": {
|
|
"port_id": "counterPartyPortID",
|
|
"channel_id": "counterPartyChannelID"
|
|
},
|
|
"order": "ORDER_ORDERED",
|
|
"version": "v1",
|
|
"connection_id": "one"
|
|
},
|
|
{
|
|
"endpoint": {
|
|
"port_id": "otherPortID",
|
|
"channel_id": "otherChannelID"
|
|
},
|
|
"counterparty_endpoint": {
|
|
"port_id": "otherCounterPartyPortID",
|
|
"channel_id": "otherCounterPartyChannelID"
|
|
},
|
|
"order": "ORDER_UNORDERED",
|
|
"version": "otherVersion",
|
|
"connection_id": "other"
|
|
}
|
|
]
|
|
}`,
|
|
},
|
|
"query list channels - filtered": {
|
|
srcQuery: &wasmvmtypes.IBCQuery{
|
|
ListChannels: &wasmvmtypes.ListChannelsQuery{
|
|
PortID: "otherPortID",
|
|
},
|
|
},
|
|
channelKeeper: &wasmtesting.MockChannelKeeper{
|
|
IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels),
|
|
},
|
|
expJsonResult: `{
|
|
"channels": [
|
|
{
|
|
"endpoint": {
|
|
"port_id": "otherPortID",
|
|
"channel_id": "otherChannelID"
|
|
},
|
|
"counterparty_endpoint": {
|
|
"port_id": "otherCounterPartyPortID",
|
|
"channel_id": "otherCounterPartyChannelID"
|
|
},
|
|
"order": "ORDER_UNORDERED",
|
|
"version": "otherVersion",
|
|
"connection_id": "other"
|
|
}
|
|
]
|
|
}`,
|
|
},
|
|
"query list channels - filtered empty": {
|
|
srcQuery: &wasmvmtypes.IBCQuery{
|
|
ListChannels: &wasmvmtypes.ListChannelsQuery{
|
|
PortID: "none-existing",
|
|
},
|
|
},
|
|
channelKeeper: &wasmtesting.MockChannelKeeper{
|
|
IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels),
|
|
},
|
|
expJsonResult: `{"channels": []}`,
|
|
},
|
|
"query channel": {
|
|
srcQuery: &wasmvmtypes.IBCQuery{
|
|
Channel: &wasmvmtypes.ChannelQuery{
|
|
PortID: "myQueryPortID",
|
|
ChannelID: "myQueryChannelID",
|
|
},
|
|
},
|
|
channelKeeper: &wasmtesting.MockChannelKeeper{
|
|
GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) {
|
|
return channeltypes.Channel{
|
|
State: channeltypes.OPEN,
|
|
Ordering: channeltypes.UNORDERED,
|
|
Counterparty: channeltypes.Counterparty{
|
|
PortId: "counterPartyPortID",
|
|
ChannelId: "otherCounterPartyChannelID",
|
|
},
|
|
ConnectionHops: []string{"one"},
|
|
Version: "version",
|
|
}, true
|
|
},
|
|
},
|
|
expJsonResult: `{
|
|
"channel": {
|
|
"endpoint": {
|
|
"port_id": "myQueryPortID",
|
|
"channel_id": "myQueryChannelID"
|
|
},
|
|
"counterparty_endpoint": {
|
|
"port_id": "counterPartyPortID",
|
|
"channel_id": "otherCounterPartyChannelID"
|
|
},
|
|
"order": "ORDER_UNORDERED",
|
|
"version": "version",
|
|
"connection_id": "one"
|
|
}
|
|
}`,
|
|
},
|
|
"query channel - without port set": {
|
|
srcQuery: &wasmvmtypes.IBCQuery{
|
|
Channel: &wasmvmtypes.ChannelQuery{
|
|
ChannelID: "myQueryChannelID",
|
|
},
|
|
},
|
|
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{
|
|
State: channeltypes.OPEN,
|
|
Ordering: channeltypes.UNORDERED,
|
|
Counterparty: channeltypes.Counterparty{
|
|
PortId: "counterPartyPortID",
|
|
ChannelId: "otherCounterPartyChannelID",
|
|
},
|
|
ConnectionHops: []string{"one"},
|
|
Version: "version",
|
|
}, true
|
|
},
|
|
},
|
|
expJsonResult: `{
|
|
"channel": {
|
|
"endpoint": {
|
|
"port_id": "myLoadedPortID",
|
|
"channel_id": "myQueryChannelID"
|
|
},
|
|
"counterparty_endpoint": {
|
|
"port_id": "counterPartyPortID",
|
|
"channel_id": "otherCounterPartyChannelID"
|
|
},
|
|
"order": "ORDER_UNORDERED",
|
|
"version": "version",
|
|
"connection_id": "one"
|
|
}
|
|
}`,
|
|
},
|
|
"query channel in init state": {
|
|
srcQuery: &wasmvmtypes.IBCQuery{
|
|
Channel: &wasmvmtypes.ChannelQuery{
|
|
PortID: "myQueryPortID",
|
|
ChannelID: "myQueryChannelID",
|
|
},
|
|
},
|
|
channelKeeper: &wasmtesting.MockChannelKeeper{
|
|
GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) {
|
|
return channeltypes.Channel{
|
|
State: channeltypes.INIT,
|
|
Ordering: channeltypes.UNORDERED,
|
|
Counterparty: channeltypes.Counterparty{
|
|
PortId: "foobar",
|
|
},
|
|
ConnectionHops: []string{"one"},
|
|
Version: "initversion",
|
|
}, true
|
|
},
|
|
},
|
|
expJsonResult: "{}",
|
|
},
|
|
"query channel in closed state": {
|
|
srcQuery: &wasmvmtypes.IBCQuery{
|
|
Channel: &wasmvmtypes.ChannelQuery{
|
|
PortID: "myQueryPortID",
|
|
ChannelID: "myQueryChannelID",
|
|
},
|
|
},
|
|
channelKeeper: &wasmtesting.MockChannelKeeper{
|
|
GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) {
|
|
return channeltypes.Channel{
|
|
State: channeltypes.CLOSED,
|
|
Ordering: channeltypes.ORDERED,
|
|
Counterparty: channeltypes.Counterparty{
|
|
PortId: "super",
|
|
ChannelId: "duper",
|
|
},
|
|
ConnectionHops: []string{"no-more"},
|
|
Version: "closedVersion",
|
|
}, true
|
|
},
|
|
},
|
|
expJsonResult: "{}",
|
|
},
|
|
"query channel - empty result": {
|
|
srcQuery: &wasmvmtypes.IBCQuery{
|
|
Channel: &wasmvmtypes.ChannelQuery{
|
|
PortID: "myQueryPortID",
|
|
ChannelID: "myQueryChannelID",
|
|
},
|
|
},
|
|
channelKeeper: &wasmtesting.MockChannelKeeper{
|
|
GetChannelFn: func(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) {
|
|
return channeltypes.Channel{}, false
|
|
},
|
|
},
|
|
expJsonResult: "{}",
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
h := IBCQuerier(spec.wasmKeeper, spec.channelKeeper)
|
|
gotResult, gotErr := h(sdk.Context{}, RandomAccountAddress(t), spec.srcQuery)
|
|
require.True(t, spec.expErr.Is(gotErr), "exp %v but got %#+v", spec.expErr, gotErr)
|
|
if spec.expErr != nil {
|
|
return
|
|
}
|
|
assert.JSONEq(t, spec.expJsonResult, string(gotResult), string(gotResult))
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
func TestBankQuerierBalance(t *testing.T) {
|
|
mock := bankKeeperMock{GetBalanceFn: func(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin {
|
|
return sdk.NewCoin(denom, sdk.NewInt(1))
|
|
}}
|
|
|
|
ctx := sdk.Context{}
|
|
q := BankQuerier(mock)
|
|
gotBz, gotErr := q(ctx, &wasmvmtypes.BankQuery{
|
|
Balance: &wasmvmtypes.BalanceQuery{
|
|
Address: RandomBech32AccountAddress(t),
|
|
Denom: "ALX",
|
|
},
|
|
})
|
|
require.NoError(t, gotErr)
|
|
var got wasmvmtypes.BalanceResponse
|
|
require.NoError(t, json.Unmarshal(gotBz, &got))
|
|
exp := wasmvmtypes.BalanceResponse{
|
|
Amount: wasmvmtypes.Coin{
|
|
Denom: "ALX",
|
|
Amount: "1",
|
|
},
|
|
}
|
|
assert.Equal(t, exp, got)
|
|
}
|
|
|
|
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 TestQueryErrors(t *testing.T) {
|
|
specs := map[string]struct {
|
|
src error
|
|
expErr error
|
|
}{
|
|
"no error": {},
|
|
"no such contract": {
|
|
src: &types.ErrNoSuchContract{Addr: "contract-addr"},
|
|
expErr: wasmvmtypes.NoSuchContract{Addr: "contract-addr"},
|
|
},
|
|
"no such contract - wrapped": {
|
|
src: sdkerrors.Wrap(&types.ErrNoSuchContract{Addr: "contract-addr"}, "my additional data"),
|
|
expErr: wasmvmtypes.NoSuchContract{Addr: "contract-addr"},
|
|
},
|
|
}
|
|
for name, spec := range specs {
|
|
t.Run(name, func(t *testing.T) {
|
|
mock := WasmVMQueryHandlerFn(func(ctx sdk.Context, caller sdk.AccAddress, request wasmvmtypes.QueryRequest) ([]byte, error) {
|
|
return nil, spec.src
|
|
})
|
|
ctx := sdk.Context{}.WithGasMeter(sdk.NewInfiniteGasMeter()).WithMultiStore(store.NewCommitMultiStore(dbm.NewMemDB()))
|
|
q := NewQueryHandler(ctx, mock, sdk.AccAddress{}, NewDefaultWasmGasRegister())
|
|
_, gotErr := q.Query(wasmvmtypes.QueryRequest{}, 1)
|
|
assert.Equal(t, spec.expErr, gotErr)
|
|
})
|
|
}
|
|
}
|
|
|
|
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 types.RawContractMessage) ([]byte, error)
|
|
IsPinnedCodeFn func(ctx sdk.Context, codeID uint64) bool
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (m bankKeeperMock) GetBalance(ctx sdk.Context, addr sdk.AccAddress, denom string) sdk.Coin {
|
|
if m.GetBalanceFn == nil {
|
|
panic("not expected to be called")
|
|
}
|
|
return m.GetBalanceFn(ctx, addr, denom)
|
|
}
|
|
|
|
func (m bankKeeperMock) GetAllBalances(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins {
|
|
if m.GetAllBalancesFn == nil {
|
|
panic("not expected to be called")
|
|
}
|
|
return m.GetAllBalancesFn(ctx, addr)
|
|
}
|