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:
parent
54f8666044
commit
397ffbe119
@ -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
|
||||
|
||||
|
||||
@ -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
21
x/ibc/02-client/abci.go
Normal 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)
|
||||
}
|
||||
}
|
||||
60
x/ibc/02-client/abci_test.go
Normal file
60
x/ibc/02-client/abci_test.go
Normal 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())
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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), '/')
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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{
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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}) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
25
x/ibc/09-localhost/client/cli/cli.go
Normal file
25
x/ibc/09-localhost/client/cli/cli.go
Normal 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
|
||||
}
|
||||
47
x/ibc/09-localhost/client/cli/tx.go
Normal file
47
x/ibc/09-localhost/client/cli/tx.go
Normal 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
|
||||
}
|
||||
18
x/ibc/09-localhost/client/rest/rest.go
Normal file
18
x/ibc/09-localhost/client/rest/rest.go
Normal 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"`
|
||||
}
|
||||
56
x/ibc/09-localhost/client/rest/tx.go
Normal file
56
x/ibc/09-localhost/client/rest/tx.go
Normal 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})
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
29
x/ibc/09-localhost/module.go
Normal file
29
x/ibc/09-localhost/module.go
Normal 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))
|
||||
}
|
||||
@ -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
|
||||
343
x/ibc/09-localhost/types/client_state_test.go
Normal file
343
x/ibc/09-localhost/types/client_state_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
package localhost_test
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
72
x/ibc/09-localhost/types/msgs.go
Normal file
72
x/ibc/09-localhost/types/msgs.go
Normal 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
|
||||
}
|
||||
@ -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{}
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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),
|
||||
)...)
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user