x/ibc: update ICS09 Loopback Client (#6018)

* x/ibc: update ICS09 Loopback Client

* ibc/09-localhost: client state errors

* ibc/09-localhost: add messages for create client

* x/ibc: BeginBlocker for localhost client

* test fixes

* update client REST

* add tests
This commit is contained in:
Federico Kunze 2020-04-17 22:36:12 -04:00 committed by GitHub
parent 54f8666044
commit 397ffbe119
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 856 additions and 646 deletions

View File

@ -105,7 +105,7 @@ information on how to implement the new `Keyring` interface.
* (ibc/ante) Implement IBC `AnteHandler` as per [ADR 15 - IBC Packet Receiver](https://github.com/cosmos/tree/master/docs/architecture/adr-015-ibc-packet-receiver.md).
* (x/capability) [\#5828](https://github.com/cosmos/cosmos-sdk/pull/5828) Capability module integration as outlined in [ADR 3 - Dynamic Capability Store](https://github.com/cosmos/tree/master/docs/architecture/adr-003-dynamic-capability-store.md).
* (x/params) [\#6005](https://github.com/cosmos/cosmos-sdk/pull/6005) Add new CLI command for querying raw x/params parameters by subspace and key.
* (x/ibc) [\#5769] Implementation of localhost client.
* (x/ibc) [\#5769](https://github.com/cosmos/cosmos-sdk/pull/5769) [ICS 009 - Loopback Client](https://github.com/cosmos/ics/tree/master/spec/ics-009-loopback-client) subpackage
### Bug Fixes

View File

@ -288,7 +288,10 @@ func NewSimApp(
// During begin block slashing happens after distr.BeginBlocker so that
// there is nothing left over in the validator fee pool, so as to keep the
// CanWithdrawInvariant invariant.
app.mm.SetOrderBeginBlockers(upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName, evidence.ModuleName, staking.ModuleName)
app.mm.SetOrderBeginBlockers(
upgrade.ModuleName, mint.ModuleName, distr.ModuleName, slashing.ModuleName,
evidence.ModuleName, staking.ModuleName, ibc.ModuleName,
)
app.mm.SetOrderEndBlockers(crisis.ModuleName, gov.ModuleName, staking.ModuleName)
// NOTE: The genutils moodule must occur after staking so that pools are

21
x/ibc/02-client/abci.go Normal file
View File

@ -0,0 +1,21 @@
package client
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/keeper"
)
// BeginBlocker updates an existing localhost client with the latest block height.
func BeginBlocker(ctx sdk.Context, k keeper.Keeper) {
localhostClient, found := k.GetClientState(ctx, exported.ClientTypeLocalHost)
if !found {
return
}
// update the localhost client with the latest block height
_, err := k.UpdateClient(ctx, localhostClient.GetID(), nil)
if err != nil {
panic(err)
}
}

View File

@ -0,0 +1,60 @@
package client_test
import (
"testing"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types"
client "github.com/cosmos/cosmos-sdk/x/ibc/02-client"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
)
type ClientTestSuite struct {
suite.Suite
cdc *codec.Codec
ctx sdk.Context
app *simapp.SimApp
}
func (suite *ClientTestSuite) SetupTest() {
isCheckTx := false
suite.app = simapp.Setup(isCheckTx)
suite.cdc = suite.app.Codec()
suite.ctx = suite.app.BaseApp.NewContext(isCheckTx, abci.Header{Height: 1, ChainID: "localhost_chain"})
}
func TestClientTestSuite(t *testing.T) {
suite.Run(t, new(ClientTestSuite))
}
func (suite *ClientTestSuite) TestBeginBlocker() {
localHostClient := localhosttypes.NewClientState(
suite.app.IBCKeeper.ClientKeeper.ClientStore(suite.ctx, exported.ClientTypeLocalHost),
suite.ctx.ChainID(),
suite.ctx.BlockHeight(),
)
_, err := suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, localHostClient, nil)
suite.Require().NoError(err)
// increase height
suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1)
var prevHeight uint64
for i := 0; i < 10; i++ {
prevHeight = localHostClient.GetLatestHeight()
suite.Require().NotPanics(func() {
client.BeginBlocker(suite.ctx, suite.app.IBCKeeper.ClientKeeper)
}, "BeginBlocker shouldn't panic")
localHostClient, found := suite.app.IBCKeeper.ClientKeeper.GetClientState(suite.ctx, localHostClient.GetID())
suite.Require().True(found)
suite.Require().Equal(prevHeight+1, localHostClient.GetLatestHeight())
}
}

View File

@ -54,7 +54,7 @@ func QueryClientState(
}
var clientState exported.ClientState
if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &clientState); err != nil {
if err := cliCtx.Codec.UnmarshalBinaryBare(res.Value, &clientState); err != nil {
return types.StateResponse{}, err
}
@ -82,7 +82,7 @@ func QueryConsensusState(
}
var cs exported.ConsensusState
if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &cs); err != nil {
if err := cliCtx.Codec.UnmarshalBinaryBare(res.Value, &cs); err != nil {
return conStateRes, err
}

View File

@ -148,12 +148,15 @@ const (
// string representation of the client types
const (
ClientTypeTendermint string = "tendermint"
ClientTypeLocalHost string = "localhost"
)
func (ct ClientType) String() string {
switch ct {
case Tendermint:
return ClientTypeTendermint
case Localhost:
return ClientTypeLocalHost
default:
return ""
}
@ -187,7 +190,8 @@ func ClientTypeFromString(clientType string) ClientType {
switch clientType {
case ClientTypeTendermint:
return Tendermint
case ClientTypeLocalHost:
return Localhost
default:
return 0
}

View File

@ -1,6 +1,8 @@
package client
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/evidence"
@ -8,7 +10,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
localhost "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost"
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
)
// HandleMsgCreateClient defines the sdk.Handler for MsgCreateClient
@ -29,7 +31,12 @@ func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg exported.MsgCreateClie
return nil, err
}
case exported.Localhost:
clientState = localhost.NewClientState(ctx.MultiStore().GetKVStore(k.GetStoreKey()))
// msg client id is always "localhost"
clientState = localhosttypes.NewClientState(
k.ClientStore(ctx, msg.GetClientID()),
ctx.ChainID(),
ctx.BlockHeight(),
)
default:
return nil, sdkerrors.Wrap(ErrInvalidClientType, msg.GetClientType())
}
@ -66,7 +73,8 @@ func HandleMsgCreateClient(ctx sdk.Context, k Keeper, msg exported.MsgCreateClie
// HandleMsgUpdateClient defines the sdk.Handler for MsgUpdateClient
func HandleMsgUpdateClient(ctx sdk.Context, k Keeper, msg exported.MsgUpdateClient) (*sdk.Result, error) {
if err := k.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader()); err != nil {
clientState, err := k.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader())
if err != nil {
return nil, err
}
@ -76,11 +84,13 @@ func HandleMsgUpdateClient(ctx sdk.Context, k Keeper, msg exported.MsgUpdateClie
attributes[i+1] = sdk.NewAttribute(sdk.AttributeKeySender, signer.String())
}
k.Logger(ctx).Info(fmt.Sprintf("client %s updated to height %d", msg.GetClientID(), clientState.GetLatestHeight()))
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
EventTypeUpdateClient,
sdk.NewAttribute(AttributeKeyClientID, msg.GetClientID()),
sdk.NewAttribute(AttrbuteKeyClientType, msg.GetHeader().ClientType().String()),
sdk.NewAttribute(AttrbuteKeyClientType, clientState.ClientType().String()),
),
sdk.NewEvent(
sdk.EventTypeMessage,

View File

@ -9,6 +9,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
)
// CreateClient creates a new client state and populates it with a given consensus
@ -29,9 +30,8 @@ func (k Keeper) CreateClient(
panic(fmt.Sprintf("client type is already defined for client %s", clientID))
}
height := consensusState.GetHeight()
if consensusState != nil {
k.SetClientConsensusState(ctx, clientID, height, consensusState)
k.SetClientConsensusState(ctx, clientID, consensusState.GetHeight(), consensusState)
}
k.SetClientState(ctx, clientState)
@ -53,25 +53,26 @@ func (k Keeper) CreateClient(
}
// UpdateClient updates the consensus state and the state root from a provided header
func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) error {
func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.Header) (exported.ClientState, error) {
clientType, found := k.GetClientType(ctx, clientID)
if !found {
return sdkerrors.Wrapf(types.ErrClientTypeNotFound, "cannot update client with ID %s", clientID)
return nil, sdkerrors.Wrapf(types.ErrClientTypeNotFound, "cannot update client with ID %s", clientID)
}
// check that the header consensus matches the client one
if header.ClientType() != clientType {
return sdkerrors.Wrapf(types.ErrInvalidConsensus, "cannot update client with ID %s", clientID)
// NOTE: not checked for localhost client
if header != nil && clientType != exported.Localhost && header.ClientType() != clientType {
return nil, sdkerrors.Wrapf(types.ErrInvalidConsensus, "cannot update client with ID %s", clientID)
}
clientState, found := k.GetClientState(ctx, clientID)
if !found {
return sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID)
return nil, sdkerrors.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID)
}
// addittion to spec: prevent update if the client is frozen
if clientState.IsFrozen() {
return sdkerrors.Wrapf(types.ErrClientFrozen, "cannot update client with ID %s", clientID)
return nil, sdkerrors.Wrapf(types.ErrClientFrozen, "cannot update client with ID %s", clientID)
}
var (
@ -84,30 +85,29 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, header exported.H
clientState, consensusState, err = tendermint.CheckValidityAndUpdateState(
clientState, header, ctx.BlockTime(),
)
case exported.Localhost:
// override client state and update the block height
clientState = localhosttypes.NewClientState(
k.ClientStore(ctx, clientState.GetID()),
clientState.GetChainID(),
ctx.BlockHeight(),
)
default:
err = types.ErrInvalidClientType
}
if err != nil {
return sdkerrors.Wrapf(err, "cannot update client with ID %s", clientID)
return nil, sdkerrors.Wrapf(err, "cannot update client with ID %s", clientID)
}
k.SetClientState(ctx, clientState)
k.SetClientConsensusState(ctx, clientID, header.GetHeight(), consensusState)
k.Logger(ctx).Info(fmt.Sprintf("client %s updated to height %d", clientID, header.GetHeight()))
ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(
types.EventTypeUpdateClient,
sdk.NewAttribute(types.AttributeKeyClientID, clientID),
),
sdk.NewEvent(
sdk.EventTypeMessage,
sdk.NewAttribute(sdk.AttributeKeyModule, types.AttributeValueCategory),
),
})
// we don't set consensus state for localhost client
if header != nil && clientType != exported.Localhost {
k.SetClientConsensusState(ctx, clientID, header.GetHeight(), consensusState)
}
return nil
return clientState, nil
}
// CheckMisbehaviourAndUpdateState checks for client misbehaviour and freezes the

View File

@ -9,6 +9,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
)
@ -60,7 +61,7 @@ func (suite *KeeperTestSuite) TestCreateClient() {
}
}
func (suite *KeeperTestSuite) TestUpdateClient() {
func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
// Must create header creation functions since suite.header gets recreated on each test case
createValidUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header {
return ibctmtypes.CreateTestHeader(testClientID, suite.header.Height+1, suite.header.Time.Add(time.Minute),
@ -137,7 +138,7 @@ func (suite *KeeperTestSuite) TestUpdateClient() {
suite.ctx = suite.ctx.WithBlockTime(updateHeader.Time.Add(time.Minute))
err = suite.keeper.UpdateClient(suite.ctx, testClientID, updateHeader)
updatedClientState, err := suite.keeper.UpdateClient(suite.ctx, testClientID, updateHeader)
if tc.expPass {
suite.Require().NoError(err, err)
@ -159,9 +160,16 @@ func (suite *KeeperTestSuite) TestUpdateClient() {
// recalculate cached totalVotingPower field for equality check
tmConsState.ValidatorSet.TotalVotingPower()
tmClientState, ok := updatedClientState.(ibctmtypes.ClientState)
suite.Require().True(ok, "client state is not a tendermint client state")
// recalculate cached totalVotingPower field for equality check
tmClientState.LastHeader.ValidatorSet.TotalVotingPower()
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
suite.Require().Equal(updateHeader.GetHeight(), clientState.GetLatestHeight(), "client state height not updated correctly on case %s", tc.name)
suite.Require().Equal(expConsensusState, consensusState, "consensus state should have been updated on case %s", tc.name)
suite.Require().Equal(updatedClientState, tmClientState, "client states don't match")
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
@ -169,6 +177,24 @@ func (suite *KeeperTestSuite) TestUpdateClient() {
}
}
func (suite *KeeperTestSuite) TestUpdateClientLocalhost() {
var localhostClient exported.ClientState = localhosttypes.NewClientState(
suite.keeper.ClientStore(suite.ctx, exported.ClientTypeLocalHost),
suite.header.ChainID,
suite.ctx.BlockHeight(),
)
localhostClient, err := suite.keeper.CreateClient(suite.ctx, localhostClient, nil)
suite.Require().NoError(err, err)
suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1)
updatedClientState, err := suite.keeper.UpdateClient(suite.ctx, exported.ClientTypeLocalHost, nil)
suite.Require().NoError(err, err)
suite.Require().Equal(localhostClient.GetID(), updatedClientState.GetID())
suite.Require().Equal(localhostClient.GetLatestHeight()+1, updatedClientState.GetLatestHeight())
}
func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
altPrivVal := tmtypes.NewMockPV()
altVal := tmtypes.NewValidator(altPrivVal.GetPubKey(), 4)

View File

@ -40,33 +40,29 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", ibctypes.ModuleName, types.SubModuleName))
}
func (k Keeper) GetStoreKey() sdk.StoreKey {
return k.storeKey
}
// GetClientState gets a particular client from the store
func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) {
store := k.clientStore(ctx, clientID)
store := k.ClientStore(ctx, clientID)
bz := store.Get(ibctypes.KeyClientState())
if bz == nil {
return nil, false
}
var clientState exported.ClientState
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &clientState)
k.cdc.MustUnmarshalBinaryBare(bz, &clientState)
return clientState, true
}
// SetClientState sets a particular Client to the store
func (k Keeper) SetClientState(ctx sdk.Context, clientState exported.ClientState) {
store := k.clientStore(ctx, clientState.GetID())
bz := k.cdc.MustMarshalBinaryLengthPrefixed(clientState)
store := k.ClientStore(ctx, clientState.GetID())
bz := k.cdc.MustMarshalBinaryBare(clientState)
store.Set(ibctypes.KeyClientState(), bz)
}
// GetClientType gets the consensus type for a specific client
func (k Keeper) GetClientType(ctx sdk.Context, clientID string) (exported.ClientType, bool) {
store := k.clientStore(ctx, clientID)
store := k.ClientStore(ctx, clientID)
bz := store.Get(ibctypes.KeyClientType())
if bz == nil {
return 0, false
@ -77,35 +73,35 @@ func (k Keeper) GetClientType(ctx sdk.Context, clientID string) (exported.Client
// SetClientType sets the specific client consensus type to the provable store
func (k Keeper) SetClientType(ctx sdk.Context, clientID string, clientType exported.ClientType) {
store := k.clientStore(ctx, clientID)
store := k.ClientStore(ctx, clientID)
store.Set(ibctypes.KeyClientType(), []byte{byte(clientType)})
}
// GetClientConsensusState gets the stored consensus state from a client at a given height.
func (k Keeper) GetClientConsensusState(ctx sdk.Context, clientID string, height uint64) (exported.ConsensusState, bool) {
store := k.clientStore(ctx, clientID)
store := k.ClientStore(ctx, clientID)
bz := store.Get(ibctypes.KeyConsensusState(height))
if bz == nil {
return nil, false
}
var consensusState exported.ConsensusState
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &consensusState)
k.cdc.MustUnmarshalBinaryBare(bz, &consensusState)
return consensusState, true
}
// SetClientConsensusState sets a ConsensusState to a particular client at the given
// height
func (k Keeper) SetClientConsensusState(ctx sdk.Context, clientID string, height uint64, consensusState exported.ConsensusState) {
store := k.clientStore(ctx, clientID)
bz := k.cdc.MustMarshalBinaryLengthPrefixed(consensusState)
store := k.ClientStore(ctx, clientID)
bz := k.cdc.MustMarshalBinaryBare(consensusState)
store.Set(ibctypes.KeyConsensusState(height), bz)
}
// HasClientConsensusState returns if keeper has a ConsensusState for a particular
// client at the given height
func (k Keeper) HasClientConsensusState(ctx sdk.Context, clientID string, height uint64) bool {
store := k.clientStore(ctx, clientID)
store := k.ClientStore(ctx, clientID)
return store.Has(ibctypes.KeyConsensusState(height))
}
@ -118,7 +114,7 @@ func (k Keeper) GetLatestClientConsensusState(ctx sdk.Context, clientID string)
return k.GetClientConsensusState(ctx, clientID, clientState.GetLatestHeight())
}
// GetClientConsensusStatelTE will get the latest ConsensusState of a particular client at the latest height
// GetClientConsensusStateLTE will get the latest ConsensusState of a particular client at the latest height
// less than or equal to the given height
func (k Keeper) GetClientConsensusStateLTE(ctx sdk.Context, clientID string, maxHeight uint64) (exported.ConsensusState, bool) {
for i := maxHeight; i > 0; i-- {
@ -163,7 +159,7 @@ func (k Keeper) IterateClients(ctx sdk.Context, cb func(exported.ClientState) bo
continue
}
var clientState exported.ClientState
k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &clientState)
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &clientState)
if cb(clientState) {
break
@ -180,9 +176,9 @@ func (k Keeper) GetAllClients(ctx sdk.Context) (states []exported.ClientState) {
return states
}
// Returns isolated prefix store for each client so they can read/write in separate
// ClientStore returns isolated prefix store for each client so they can read/write in separate
// namespace without being able to read/write other client's data
func (k Keeper) clientStore(ctx sdk.Context, clientID string) sdk.KVStore {
func (k Keeper) ClientStore(ctx sdk.Context, clientID string) sdk.KVStore {
// append here is safe, appends within a function won't cause
// weird side effects when its singlethreaded
clientPrefix := append([]byte("clients/"+clientID), '/')

View File

@ -55,7 +55,7 @@ func QueryConnection(
}
var connection types.ConnectionEnd
if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &connection); err != nil {
if err := cliCtx.Codec.UnmarshalBinaryBare(res.Value, &connection); err != nil {
return types.ConnectionResponse{}, err
}
@ -81,7 +81,7 @@ func QueryClientConnections(
}
var paths []string
if err := cliCtx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &paths); err != nil {
if err := cliCtx.Codec.UnmarshalBinaryBare(res.Value, &paths); err != nil {
return types.ClientConnectionsResponse{}, err
}

View File

@ -52,14 +52,14 @@ func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.Conne
}
var connection types.ConnectionEnd
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &connection)
k.cdc.MustUnmarshalBinaryBare(bz, &connection)
return connection, true
}
// SetConnection sets a connection to the store
func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection types.ConnectionEnd) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryLengthPrefixed(connection)
bz := k.cdc.MustMarshalBinaryBare(connection)
store.Set(ibctypes.KeyConnection(connectionID), bz)
}
@ -73,14 +73,14 @@ func (k Keeper) GetClientConnectionPaths(ctx sdk.Context, clientID string) ([]st
}
var paths []string
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &paths)
k.cdc.MustUnmarshalBinaryBare(bz, &paths)
return paths, true
}
// SetClientConnectionPaths sets the connections paths for client
func (k Keeper) SetClientConnectionPaths(ctx sdk.Context, clientID string, paths []string) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryLengthPrefixed(paths)
bz := k.cdc.MustMarshalBinaryBare(paths)
store.Set(ibctypes.KeyClientConnections(clientID), bz)
}
@ -94,7 +94,7 @@ func (k Keeper) IterateConnections(ctx sdk.Context, cb func(types.IdentifiedConn
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var connection types.ConnectionEnd
k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &connection)
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &connection)
identifier := string(iterator.Key()[len(ibctypes.KeyConnectionPrefix)+1:])
conn := types.IdentifiedConnectionEnd{

View File

@ -62,7 +62,7 @@ func QueryChannel(
}
var channel types.Channel
if err := ctx.Codec.UnmarshalBinaryLengthPrefixed(res.Value, &channel); err != nil {
if err := ctx.Codec.UnmarshalBinaryBare(res.Value, &channel); err != nil {
return types.ChannelResponse{}, err
}
return types.NewChannelResponse(portID, channelID, channel, res.Proof, res.Height), nil

View File

@ -53,14 +53,14 @@ func (k Keeper) GetChannel(ctx sdk.Context, portID, channelID string) (types.Cha
}
var channel types.Channel
k.cdc.MustUnmarshalBinaryLengthPrefixed(bz, &channel)
k.cdc.MustUnmarshalBinaryBare(bz, &channel)
return channel, true
}
// SetChannel sets a channel to the store
func (k Keeper) SetChannel(ctx sdk.Context, portID, channelID string, channel types.Channel) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryLengthPrefixed(channel)
bz := k.cdc.MustMarshalBinaryBare(channel)
store.Set(ibctypes.KeyChannel(portID, channelID), bz)
}
@ -144,7 +144,7 @@ func (k Keeper) IterateChannels(ctx sdk.Context, cb func(types.IdentifiedChannel
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var channel types.Channel
k.cdc.MustUnmarshalBinaryLengthPrefixed(iterator.Value(), &channel)
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &channel)
portID, channelID := ibctypes.MustParseChannelPath(string(iterator.Key()))
if cb(types.IdentifiedChannel{Channel: channel, PortIdentifier: portID, ChannelIdentifier: channelID}) {

View File

@ -15,7 +15,7 @@ import (
// RegisterRoutes - Central function to define routes that get registered by the main application
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/ibc/clients", createClientHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc("/ibc/clients/tendermint", createClientHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc(fmt.Sprintf("/ibc/clients/{%s}/update", RestClientID), updateClientHandlerFn(cliCtx)).Methods("POST")
r.HandleFunc("/ibc/clients/{%s}/misbehaviour", submitMisbehaviourHandlerFn(cliCtx)).Methods("POST")
}
@ -29,7 +29,7 @@ func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
// @Param body body rest.CreateClientReq true "Create client request body"
// @Success 200 {object} PostCreateClient "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/clients [post]
// @Router /ibc/clients/tendermint [post]
func createClientHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req CreateClientReq

View File

@ -32,7 +32,7 @@ type ClientState struct {
// Block height when the client was frozen due to a misbehaviour
FrozenHeight uint64 `json:"frozen_height" yaml:"frozen_height"`
// Last Header that was stored by client
LastHeader Header
LastHeader Header `json:"last_header" yaml:"last_header"`
}
// InitializeFromMsg creates a tendermint client state from a CreateClientMsg
@ -124,7 +124,7 @@ func (cs ClientState) VerifyClientConsensusState(
return err
}
bz, err := cdc.MarshalBinaryLengthPrefixed(consensusState)
bz, err := cdc.MarshalBinaryBare(consensusState)
if err != nil {
return err
}
@ -156,7 +156,7 @@ func (cs ClientState) VerifyConnectionState(
return err
}
bz, err := cdc.MarshalBinaryLengthPrefixed(connectionEnd)
bz, err := cdc.MarshalBinaryBare(connectionEnd)
if err != nil {
return err
}
@ -189,7 +189,7 @@ func (cs ClientState) VerifyChannelState(
return err
}
bz, err := cdc.MarshalBinaryLengthPrefixed(channel)
bz, err := cdc.MarshalBinaryBare(channel)
if err != nil {
return err
}

View File

@ -0,0 +1,25 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
)
// GetTxCmd returns the transaction commands for IBC
func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command {
ics09LocalhostTxCmd := &cobra.Command{
Use: types.SubModuleName,
Short: "Localhost transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
}
ics09LocalhostTxCmd.AddCommand(flags.PostCommands(
GetCmdCreateClient(cdc),
)...)
return ics09LocalhostTxCmd
}

View File

@ -0,0 +1,47 @@
package cli
import (
"bufio"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
)
// GetCmdCreateClient defines the command to create a new IBC Client as defined
// in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create
func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "create",
Short: "create new localhost client",
Long: strings.TrimSpace(fmt.Sprintf(`create new localhost (loopback) client:
Example:
$ %s tx ibc client localhost create --from node0 --home ../node0/<app>cli --chain-id $CID
`, version.ClientName),
),
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock)
msg := types.NewMsgCreateClient(cliCtx.GetFromAddress())
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}
return cmd
}

View File

@ -0,0 +1,18 @@
package rest
import (
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/types/rest"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) {
registerTxRoutes(cliCtx, r)
}
// CreateClientReq defines the properties of a create client request's body.
type CreateClientReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
}

View File

@ -0,0 +1,56 @@
package rest
import (
"net/http"
"github.com/gorilla/mux"
"github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) {
r.HandleFunc("/ibc/clients/localhost", createClientHandlerFn(cliCtx)).Methods("POST")
}
// createClientHandlerFn implements a create client handler
//
// @Summary Create client
// @Tags IBC
// @Accept json
// @Produce json
// @Param body body rest.CreateClientReq true "Create client request body"
// @Success 200 {object} PostCreateClient "OK"
// @Failure 500 {object} rest.ErrorResponse "Internal Server Error"
// @Router /ibc/clients/localhost [post]
func createClientHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req CreateClientReq
if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
return
}
req.BaseReq = req.BaseReq.Sanitize()
if !req.BaseReq.ValidateBasic(w) {
return
}
fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From)
if err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
msg := types.NewMsgCreateClient(fromAddr)
if err := msg.ValidateBasic(); err != nil {
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
return
}
authclient.WriteGenerateStdTxResponse(w, cliCtx, req.BaseReq, []sdk.Msg{msg})
}
}

View File

@ -1,410 +0,0 @@
package localhost_test
import (
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
localhost "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
)
const (
testConnectionID = "connectionid"
testPortID = "testportid"
testChannelID = "testchannelid"
testSequence = 1
)
func (suite *LocalhostTestSuite) TestVerifyClientConsensusState() {
testCases := []struct {
name string
clientState localhost.ClientState
consensusState localhost.ConsensusState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: localhost.NewClientState(suite.store),
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "proof verification failed",
clientState: localhost.NewClientState(suite.store),
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyClientConsensusState(
suite.cdc, tc.consensusState.Root, height, "chainA", tc.consensusState.GetHeight(), tc.prefix, tc.proof, tc.consensusState,
// suite.cdc, height, tc.prefix, tc.proof, tc.consensusState,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyConnectionState() {
counterparty := connection.NewCounterparty("clientB", testConnectionID, commitmenttypes.NewMerklePrefix([]byte("ibc")))
conn := connection.NewConnectionEnd(connectionexported.OPEN, "clientA", counterparty, []string{"1.0.0"})
testCases := []struct {
name string
clientState localhost.ClientState
connection connection.ConnectionEnd
consensusState localhost.ConsensusState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: localhost.NewClientState(suite.store),
connection: conn,
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "proof verification failed",
clientState: localhost.NewClientState(suite.store),
connection: conn,
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyConnectionState(
suite.cdc, height, tc.prefix, tc.proof, testConnectionID, tc.connection, tc.consensusState,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyChannelState() {
counterparty := channel.NewCounterparty(testPortID, testChannelID)
ch := channel.NewChannel(channelexported.OPEN, channelexported.ORDERED, counterparty, []string{testConnectionID}, "1.0.0")
testCases := []struct {
name string
clientState localhost.ClientState
channel channel.Channel
consensusState localhost.ConsensusState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: localhost.NewClientState(suite.store),
channel: ch,
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "latest client height < height",
clientState: localhost.NewClientState(suite.store),
channel: ch,
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "proof verification failed",
clientState: localhost.NewClientState(suite.store),
channel: ch,
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyChannelState(
suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, tc.channel, tc.consensusState,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyPacketCommitment() {
testCases := []struct {
name string
clientState localhost.ClientState
commitment []byte
consensusState localhost.ConsensusState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: localhost.NewClientState(suite.store),
commitment: []byte{},
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "latest client height < height",
clientState: localhost.NewClientState(suite.store),
commitment: []byte{},
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "client is frozen",
clientState: localhost.NewClientState(suite.store),
commitment: []byte{},
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "proof verification failed",
clientState: localhost.NewClientState(suite.store),
commitment: []byte{},
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyPacketCommitment(
height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.commitment, tc.consensusState,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyPacketAcknowledgement() {
testCases := []struct {
name string
clientState localhost.ClientState
ack []byte
consensusState localhost.ConsensusState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: localhost.NewClientState(suite.store),
ack: []byte{},
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "latest client height < height",
clientState: localhost.NewClientState(suite.store),
ack: []byte{},
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "client is frozen",
clientState: localhost.NewClientState(suite.store),
ack: []byte{},
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "proof verification failed",
clientState: localhost.NewClientState(suite.store),
ack: []byte{},
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyPacketAcknowledgement(
height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.ack, tc.consensusState,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyPacketAcknowledgementAbsence() {
testCases := []struct {
name string
clientState localhost.ClientState
consensusState localhost.ConsensusState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: localhost.NewClientState(suite.store),
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyPacketAcknowledgementAbsence(
height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.consensusState,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyNextSeqRecv() {
testCases := []struct {
name string
clientState localhost.ClientState
consensusState localhost.ConsensusState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: localhost.NewClientState(suite.store),
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "latest client height < height",
clientState: localhost.NewClientState(suite.store),
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "client is frozen",
clientState: localhost.NewClientState(suite.store),
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "proof verification failed",
clientState: localhost.NewClientState(suite.store),
consensusState: localhost.ConsensusState{
Root: commitmenttypes.NewMerkleRoot([]byte{}),
},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyNextSequenceRecv(
height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.consensusState,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}

View File

@ -1,31 +0,0 @@
package localhost
import (
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
)
// ConsensusState defines a Localhost consensus state
type ConsensusState struct {
Root commitmentexported.Root `json:"root" yaml:"root"`
}
// ClientType returns Localhost
func (ConsensusState) ClientType() clientexported.ClientType {
return clientexported.Localhost
}
// GetRoot returns the commitment Root for the specific
func (cs ConsensusState) GetRoot() commitmentexported.Root {
return cs.Root
}
// GetHeight returns the height for the specific consensus state
func (cs ConsensusState) GetHeight() uint64 {
return 0
}
// ValidateBasic defines a basic validation for the localhost consensus state.
func (cs ConsensusState) ValidateBasic() error {
return nil
}

View File

@ -1,67 +0,0 @@
package localhost
import (
yaml "gopkg.in/yaml.v2"
"github.com/tendermint/tendermint/crypto/tmhash"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
)
var (
_ evidenceexported.Evidence = Evidence{}
_ clientexported.Misbehaviour = Evidence{}
)
// Evidence is not required for a loop-back client
type Evidence struct {
}
// ClientType is Localhost light client
func (ev Evidence) ClientType() clientexported.ClientType {
return clientexported.Localhost
}
// GetClientID returns the ID of the client that committed a misbehaviour.
func (ev Evidence) GetClientID() string {
return clientexported.Localhost.String()
}
// Route implements Evidence interface
func (ev Evidence) Route() string {
return clienttypes.SubModuleName
}
// Type implements Evidence interface
func (ev Evidence) Type() string {
return "client_misbehaviour"
}
// String implements Evidence interface
func (ev Evidence) String() string {
// FIXME: implement custom marshaller
bz, err := yaml.Marshal(ev)
if err != nil {
panic(err)
}
return string(bz)
}
// Hash implements Evidence interface.
func (ev Evidence) Hash() tmbytes.HexBytes {
bz := SubModuleCdc.MustMarshalBinaryBare(ev)
return tmhash.Sum(bz)
}
// GetHeight returns 0.
func (ev Evidence) GetHeight() int64 {
return 0
}
// ValidateBasic implements Evidence interface.
func (ev Evidence) ValidateBasic() error {
return nil
}

View File

@ -1,26 +0,0 @@
package localhost
import (
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
)
var _ clientexported.Header = Header{}
// Header defines the Localhost consensus Header
type Header struct {
}
// ClientType defines that the Header is in loop-back mode.
func (h Header) ClientType() clientexported.ClientType {
return clientexported.Localhost
}
// ConsensusState returns an empty consensus state.
func (h Header) ConsensusState() ConsensusState {
return ConsensusState{}
}
// GetHeight returns 0.
func (h Header) GetHeight() uint64 {
return 0
}

View File

@ -0,0 +1,29 @@
package localhost
import (
"fmt"
"github.com/gorilla/mux"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/client/cli"
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/client/rest"
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
)
// Name returns the IBC client name
func Name() string {
return types.SubModuleName
}
// RegisterRESTRoutes registers the REST routes for the IBC localhost client
func RegisterRESTRoutes(ctx context.CLIContext, rtr *mux.Router, queryRoute string) {
rest.RegisterRoutes(ctx, rtr, fmt.Sprintf("%s/%s", queryRoute, types.SubModuleName))
}
// GetTxCmd returns the root tx command for the IBC localhost client
func GetTxCmd(cdc *codec.Codec, storeKey string) *cobra.Command {
return cli.GetTxCmd(cdc, fmt.Sprintf("%s/%s", storeKey, types.SubModuleName))
}

View File

@ -1,4 +1,4 @@
package localhost
package types
import (
"bytes"
@ -6,7 +6,6 @@ import (
"fmt"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
@ -23,30 +22,30 @@ var _ clientexported.ClientState = ClientState{}
// ClientState requires (read-only) access to keys outside the client prefix.
type ClientState struct {
ctx sdk.Context
store types.KVStore
store sdk.KVStore
ID string `json:"id" yaml:"id"`
ChainID string `json:"chain_id" yaml:"chain_id"`
Height int64 `json:"height" yaml:"height"`
}
// NewClientState creates a new ClientState instance
func NewClientState(store types.KVStore) ClientState {
func NewClientState(store sdk.KVStore, chainID string, height int64) ClientState {
return ClientState{
store: store,
store: store,
ID: clientexported.Localhost.String(),
ChainID: chainID,
Height: height,
}
}
// WithContext updates the client state context to provide the chain ID and latest height
func (cs *ClientState) WithContext(ctx sdk.Context) {
cs.ctx = ctx
}
// GetID returns the loop-back client state identifier.
func (cs ClientState) GetID() string {
return clientexported.Localhost.String()
return cs.ID
}
// GetChainID returns an empty string
func (cs ClientState) GetChainID() string {
return cs.ctx.ChainID()
return cs.ChainID
}
// ClientType is localhost.
@ -54,9 +53,9 @@ func (cs ClientState) ClientType() clientexported.ClientType {
return clientexported.Localhost
}
// GetLatestHeight returns the block height from the stored context.
// GetLatestHeight returns the latest height stored.
func (cs ClientState) GetLatestHeight() uint64 {
return uint64(cs.ctx.BlockHeight())
return uint64(cs.Height)
}
// IsFrozen returns false.
@ -85,13 +84,19 @@ func (cs ClientState) VerifyClientConsensusState(
data := cs.store.Get([]byte(path.String()))
if len(data) == 0 {
return sdkerrors.Wrap(clienttypes.ErrFailedClientConsensusStateVerification, "not found")
return sdkerrors.Wrapf(clienttypes.ErrFailedClientConsensusStateVerification, "not found for path %s", path)
}
var prevConsensusState exported.ConsensusState
cdc.MustUnmarshalBinaryBare(data, &prevConsensusState)
if err := cdc.UnmarshalBinaryBare(data, &prevConsensusState); err != nil {
return err
}
if consensusState != prevConsensusState {
return sdkerrors.Wrap(clienttypes.ErrFailedClientConsensusStateVerification, "not equal")
return sdkerrors.Wrapf(
clienttypes.ErrFailedClientConsensusStateVerification,
"consensus state ≠ previous stored consensus state: \n%v\n≠\n%v", consensusState, prevConsensusState,
)
}
return nil
@ -115,13 +120,19 @@ func (cs ClientState) VerifyConnectionState(
bz := cs.store.Get([]byte(path.String()))
if bz == nil {
return sdkerrors.Wrap(clienttypes.ErrFailedConnectionStateVerification, "not found")
return sdkerrors.Wrapf(clienttypes.ErrFailedConnectionStateVerification, "not found for path %s", path)
}
var prevConnectionState connectionexported.ConnectionI
cdc.MustUnmarshalBinaryBare(bz, &prevConnectionState)
if connectionEnd != prevConnectionState {
return sdkerrors.Wrap(clienttypes.ErrFailedConnectionStateVerification, "not equal")
var prevConnection connectionexported.ConnectionI
if err := cdc.UnmarshalBinaryBare(bz, &prevConnection); err != nil {
return err
}
if connectionEnd != prevConnection {
return sdkerrors.Wrapf(
clienttypes.ErrFailedConnectionStateVerification,
"connection end ≠ previous stored connection: \n%v\n≠\n%v", connectionEnd, prevConnection,
)
}
return nil
@ -146,13 +157,18 @@ func (cs ClientState) VerifyChannelState(
bz := cs.store.Get([]byte(path.String()))
if bz == nil {
return sdkerrors.Wrap(clienttypes.ErrFailedChannelStateVerification, "not found")
return sdkerrors.Wrapf(clienttypes.ErrFailedChannelStateVerification, "not found for path %s", path)
}
var prevChannelState channelexported.ChannelI
cdc.MustUnmarshalBinaryBare(bz, &prevChannelState)
if channel != prevChannelState {
return sdkerrors.Wrap(clienttypes.ErrFailedChannelStateVerification, "not equal")
var prevChannel channelexported.ChannelI
if err := cdc.UnmarshalBinaryBare(bz, &prevChannel); err != nil {
return err
}
if channel != prevChannel {
return sdkerrors.Wrapf(
clienttypes.ErrFailedChannelStateVerification,
"channel end ≠ previous stored channel: \n%v\n≠\n%v", channel, prevChannel,
)
}
return nil
@ -177,11 +193,14 @@ func (cs ClientState) VerifyPacketCommitment(
data := cs.store.Get([]byte(path.String()))
if len(data) == 0 {
return sdkerrors.Wrap(clienttypes.ErrFailedPacketCommitmentVerification, "not found")
return sdkerrors.Wrapf(clienttypes.ErrFailedPacketCommitmentVerification, "not found for path %s", path)
}
if !bytes.Equal(data, commitmentBytes) {
return sdkerrors.Wrap(clienttypes.ErrFailedPacketCommitmentVerification, "not equal")
return sdkerrors.Wrapf(
clienttypes.ErrFailedPacketCommitmentVerification,
"commitment ≠ previous commitment: \n%X\n≠\n%X", commitmentBytes, data,
)
}
return nil
@ -206,11 +225,14 @@ func (cs ClientState) VerifyPacketAcknowledgement(
data := cs.store.Get([]byte(path.String()))
if len(data) == 0 {
return sdkerrors.Wrap(clienttypes.ErrFailedPacketAckVerification, "not found")
return sdkerrors.Wrapf(clienttypes.ErrFailedPacketAckVerification, "not found for path %s", path)
}
if !bytes.Equal(data, acknowledgement) {
return sdkerrors.Wrap(clienttypes.ErrFailedPacketAckVerification, "not equal")
return sdkerrors.Wrapf(
clienttypes.ErrFailedPacketAckVerification,
"ak bytes ≠ previous ack: \n%X\n≠\n%X", acknowledgement, data,
)
}
return nil
@ -259,12 +281,15 @@ func (cs ClientState) VerifyNextSequenceRecv(
data := cs.store.Get([]byte(path.String()))
if len(data) == 0 {
return sdkerrors.Wrap(clienttypes.ErrFailedNextSeqRecvVerification, "not found")
return sdkerrors.Wrapf(clienttypes.ErrFailedNextSeqRecvVerification, "not found for path %s", path)
}
prevSequenceRecv := binary.BigEndian.Uint64(data)
if prevSequenceRecv != nextSequenceRecv {
return sdkerrors.Wrap(clienttypes.ErrFailedNextSeqRecvVerification, "not equal")
return sdkerrors.Wrapf(
clienttypes.ErrFailedNextSeqRecvVerification,
"next sequence receive ≠ previous stored sequence (%d ≠ %d)", nextSequenceRecv, prevSequenceRecv,
)
}
return nil

View File

@ -0,0 +1,343 @@
package types_test
import (
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported"
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported"
"github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
)
const (
testConnectionID = "connectionid"
testPortID = "testportid"
testChannelID = "testchannelid"
testSequence = 1
)
func (suite *LocalhostTestSuite) TestVerifyClientConsensusState() {
testCases := []struct {
name string
clientState types.ClientState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "proof verification failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyClientConsensusState(
suite.cdc, nil, height, "chainA", 0, tc.prefix, tc.proof, nil,
// suite.cdc, height, tc.prefix, tc.proof, nil,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyConnectionState() {
counterparty := connection.NewCounterparty("clientB", testConnectionID, commitmenttypes.NewMerklePrefix([]byte("ibc")))
conn := connection.NewConnectionEnd(connectionexported.OPEN, "clientA", counterparty, []string{"1.0.0"})
testCases := []struct {
name string
clientState types.ClientState
connection connection.ConnectionEnd
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
connection: conn,
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "proof verification failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
connection: conn,
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyConnectionState(
suite.cdc, height, tc.prefix, tc.proof, testConnectionID, tc.connection, nil,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyChannelState() {
counterparty := channel.NewCounterparty(testPortID, testChannelID)
ch := channel.NewChannel(channelexported.OPEN, channelexported.ORDERED, counterparty, []string{testConnectionID}, "1.0.0")
testCases := []struct {
name string
clientState types.ClientState
channel channel.Channel
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
channel: ch,
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "latest client height < height",
clientState: types.NewClientState(suite.store, "chainID", 10),
channel: ch,
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "proof verification failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
channel: ch,
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyChannelState(
suite.cdc, height, tc.prefix, tc.proof, testPortID, testChannelID, tc.channel, nil,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyPacketCommitment() {
testCases := []struct {
name string
clientState types.ClientState
commitment []byte
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
commitment: []byte{},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "latest client height < height",
clientState: types.NewClientState(suite.store, "chainID", 10),
commitment: []byte{},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "client is frozen",
clientState: types.NewClientState(suite.store, "chainID", 10),
commitment: []byte{},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "proof verification failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
commitment: []byte{},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyPacketCommitment(
height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.commitment, nil,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyPacketAcknowledgement() {
testCases := []struct {
name string
clientState types.ClientState
ack []byte
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
ack: []byte{},
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "latest client height < height",
clientState: types.NewClientState(suite.store, "chainID", 10),
ack: []byte{},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "client is frozen",
clientState: types.NewClientState(suite.store, "chainID", 10),
ack: []byte{},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "proof verification failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
ack: []byte{},
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyPacketAcknowledgement(
height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, tc.ack, nil,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyPacketAcknowledgementAbsence() {
testCases := []struct {
name string
clientState types.ClientState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyPacketAcknowledgementAbsence(
height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, nil,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}
func (suite *LocalhostTestSuite) TestVerifyNextSeqRecv() {
testCases := []struct {
name string
clientState types.ClientState
prefix commitmenttypes.MerklePrefix
proof commitmenttypes.MerkleProof
expPass bool
}{
{
name: "ApplyPrefix failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
prefix: commitmenttypes.MerklePrefix{},
expPass: false,
},
{
name: "latest client height < height",
clientState: types.NewClientState(suite.store, "chainID", 10),
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "client is frozen",
clientState: types.NewClientState(suite.store, "chainID", 10),
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
expPass: false,
},
{
name: "proof verification failed",
clientState: types.NewClientState(suite.store, "chainID", 10),
prefix: commitmenttypes.NewMerklePrefix([]byte("ibc")),
proof: commitmenttypes.MerkleProof{},
expPass: false,
},
}
for i, tc := range testCases {
tc := tc
err := tc.clientState.VerifyNextSequenceRecv(
height, tc.prefix, tc.proof, testPortID, testChannelID, testSequence, nil,
)
if tc.expPass {
suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
} else {
suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
}
}
}

View File

@ -1,19 +1,20 @@
package localhost
package types
import (
"github.com/cosmos/cosmos-sdk/codec"
)
const (
// SubModuleName for the localhost (loopback) client
SubModuleName = "localhost"
)
// SubModuleCdc defines the IBC localhost client codec.
var SubModuleCdc *codec.Codec
// RegisterCodec registers the localhost types
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(ClientState{}, "ibc/client/localhost/ClientState", nil)
cdc.RegisterConcrete(ConsensusState{}, "ibc/client/localhost/ConsensusState", nil)
cdc.RegisterConcrete(Header{}, "ibc/client/localhost/Header", nil)
cdc.RegisterConcrete(Evidence{}, "ibc/client/localhost/Evidence", nil)
SetSubModuleCodec(cdc)
}

View File

@ -1,4 +1,4 @@
package localhost_test
package types_test
import (
"testing"

View File

@ -0,0 +1,72 @@
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types"
)
// Message types for the IBC client
const (
TypeMsgCreateClient string = "create_client"
)
var (
_ clientexported.MsgCreateClient = MsgCreateClient{}
)
// MsgCreateClient defines a message to create an IBC client
type MsgCreateClient struct {
Signer sdk.AccAddress `json:"address" yaml:"address"`
}
// NewMsgCreateClient creates a new MsgCreateClient instance
func NewMsgCreateClient(signer sdk.AccAddress) MsgCreateClient {
return MsgCreateClient{
Signer: signer,
}
}
// Route implements sdk.Msg
func (msg MsgCreateClient) Route() string {
return ibctypes.RouterKey
}
// Type implements sdk.Msg
func (msg MsgCreateClient) Type() string {
return TypeMsgCreateClient
}
// ValidateBasic implements sdk.Msg
func (msg MsgCreateClient) ValidateBasic() error {
if msg.Signer.Empty() {
return sdkerrors.ErrInvalidAddress
}
return nil
}
// GetSignBytes implements sdk.Msg
func (msg MsgCreateClient) GetSignBytes() []byte {
return sdk.MustSortJSON(SubModuleCdc.MustMarshalJSON(msg))
}
// GetSigners implements sdk.Msg
func (msg MsgCreateClient) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{msg.Signer}
}
// GetClientID implements clientexported.MsgCreateClient
func (msg MsgCreateClient) GetClientID() string {
return clientexported.ClientTypeLocalHost
}
// GetClientType implements clientexported.MsgCreateClient
func (msg MsgCreateClient) GetClientType() string {
return clientexported.ClientTypeLocalHost
}
// GetConsensusState implements clientexported.MsgCreateClient
func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState {
return nil
}

View File

@ -115,7 +115,7 @@ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data j
var genesisState types.GenesisState
cdc.MustUnmarshalJSON(data, &genesisState)
// check if the IBC transfer module account is set
// TODO: check if the IBC transfer module account is set
InitGenesis(ctx, am.keeper, genesisState)
return []abci.ValidatorUpdate{}
}

View File

@ -30,7 +30,7 @@ func (pvr ProofVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, sim
var err error
switch msg := msg.(type) {
case clientexported.MsgUpdateClient:
err = pvr.clientKeeper.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader())
_, err = pvr.clientKeeper.UpdateClient(ctx, msg.GetClientID(), msg.GetHeader())
case channel.MsgPacket:
_, err = pvr.channelKeeper.RecvPacket(ctx, msg.Packet, msg.Proof, msg.ProofHeight)
case channel.MsgAcknowledgement:

View File

@ -10,6 +10,7 @@ import (
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
tmclient "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/client/cli"
localhostclient "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/client/cli"
"github.com/cosmos/cosmos-sdk/x/ibc/types"
)
@ -25,6 +26,7 @@ func GetTxCmd(storeKey string, cdc *codec.Codec) *cobra.Command {
ibcTxCmd.AddCommand(flags.PostCommands(
tmclient.GetTxCmd(cdc, storeKey),
localhostclient.GetTxCmd(cdc, storeKey),
connection.GetTxCmd(cdc, storeKey),
channel.GetTxCmd(cdc, storeKey),
)...)

View File

@ -7,11 +7,15 @@ import (
client "github.com/cosmos/cosmos-sdk/x/ibc/02-client"
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint"
localhost "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost"
)
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) {
client.RegisterRESTRoutes(cliCtx, r, queryRoute)
tendermint.RegisterRESTRoutes(cliCtx, r, queryRoute)
localhost.RegisterRESTRoutes(cliCtx, r, queryRoute)
connection.RegisterRESTRoutes(cliCtx, r, queryRoute)
channel.RegisterRESTRoutes(cliCtx, r, queryRoute)
}

View File

@ -16,6 +16,7 @@ import (
connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection"
channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel"
ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
"github.com/cosmos/cosmos-sdk/x/ibc/client/cli"
"github.com/cosmos/cosmos-sdk/x/ibc/client/rest"
@ -44,6 +45,7 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
connection.RegisterCodec(cdc)
channel.RegisterCodec(cdc)
ibctmtypes.RegisterCodec(cdc)
localhosttypes.RegisterCodec(cdc)
commitmenttypes.RegisterCodec(cdc)
}
@ -119,7 +121,6 @@ func (am AppModule) NewQuerierHandler() sdk.Querier {
// InitGenesis performs genesis initialization for the ibc module. It returns
// no validator updates.
func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate {
// check if the IBC transfer module account is set
return []abci.ValidatorUpdate{}
}
@ -131,6 +132,7 @@ func (am AppModule) ExportGenesis(_ sdk.Context, _ codec.JSONMarshaler) json.Raw
// BeginBlock returns the begin blocker for the ibc module.
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
client.BeginBlocker(ctx, am.keeper.ClientKeeper)
}
// EndBlock returns the end blocker for the ibc module. It returns no validator