Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make clients use proto Height #7184

Merged
merged 14 commits into from
Aug 31, 2020
17 changes: 17 additions & 0 deletions proto/ibc/client/client.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,20 @@ message ClientConsensusStates {
// consensus states associated with the client
repeated google.protobuf.Any consensus_states = 2 [(gogoproto.moretags) = "yaml:\"consensus_states\""];
}

// Height is a monotonically increasing data type
// that can be compared against another Height for the purposes of updating and freezing clients
//
// Normally the EpochHeight is incremented at each height while keeping epoch number the same
// However some consensus algorithms may choose to reset the height in certain conditions
// e.g. hard forks, state-machine breaking changes
// In these cases, the epoch number is incremented so that height continues to be monitonically increasing
// even as the EpochHeight gets reset
message Height {
option (gogoproto.goproto_stringer) = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this option?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to be able to define my own String() method on Height, especially since it will eventually go into host.ConsensusStatePath


// the epoch that the client is currently on
uint64 epoch_number = 1 [(gogoproto.moretags) = "yaml:\"epoch_number\""];
// the height within the given epoch
uint64 epoch_height = 2 [(gogoproto.moretags) = "yaml:\"epoch_height\""];
}
6 changes: 5 additions & 1 deletion proto/ibc/localhost/localhost.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ syntax = "proto3";
package ibc.localhost;

import "gogoproto/gogo.proto";
import "ibc/client/client.proto";

option go_package = "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types";

Expand All @@ -24,5 +25,8 @@ message ClientState {
(gogoproto.moretags) = "yaml:\"chain_id\""
];
// self latest block height
uint64 height = 3;
ibc.client.Height height = 3 [
(gogoproto.moretags) = "yaml:\"height\"",
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
(gogoproto.nullable) = false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does this need to be a pointer for proto?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this be a problem for proto encoding/decoding? Given the choice, i prefer it to not be a pointer since there's no reason to have a nil Height for ClientState/ConsensusState and not having nil checks everywhere is simpler

];
}
21 changes: 17 additions & 4 deletions proto/ibc/tendermint/tendermint.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import "tendermint/types/types.proto";
import "confio/proofs.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "ibc/client/client.proto";
import "ibc/commitment/commitment.proto";
import "gogoproto/gogo.proto";

Expand Down Expand Up @@ -41,9 +42,15 @@ message ClientState {
(gogoproto.moretags) = "yaml:\"max_clock_drift\""
];
// Block height when the client was frozen due to a misbehaviour
uint64 frozen_height = 6 [(gogoproto.moretags) = "yaml:\"frozen_height\""];
ibc.client.Height frozen_height = 6 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"frozen_height\""
];
// Latest height the client was updated to
uint64 latest_height = 7 [(gogoproto.moretags) = "yaml:\"latest_height\""];
ibc.client.Height latest_height = 7 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"latest_height\""
];
// Proof specifications used in verifying counterparty state
repeated ics23.ProofSpec proof_specs = 8
[(gogoproto.moretags) = "yaml:\"proof_specs\""];
Expand All @@ -60,7 +67,10 @@ message ConsensusState {
// commitment root (i.e app hash)
ibc.commitment.MerkleRoot root = 2 [(gogoproto.nullable) = false];
// height at which the consensus state was stored.
uint64 height = 3;
ibc.client.Height height = 3 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"height\""
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
];
bytes next_validators_hash = 4 [
(gogoproto.casttype) =
"github.com/tendermint/tendermint/libs/bytes.HexBytes",
Expand Down Expand Up @@ -106,7 +116,10 @@ message Header {

.tendermint.types.ValidatorSet validator_set = 2
[(gogoproto.moretags) = "yaml:\"validator_set\""];
uint64 trusted_height = 3 [(gogoproto.moretags) = "yaml:\"trusted_height\""];
ibc.client.Height trusted_height = 3 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"trusted_height\""
];
.tendermint.types.ValidatorSet trusted_validators = 4
[(gogoproto.moretags) = "yaml:\"trusted_validators\""];
}
Expand Down
10 changes: 10 additions & 0 deletions x/ibc/02-client/exported/exported.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,16 @@ type MsgUpdateClient interface {
GetHeader() Header
}

// Height is a wrapper interface over clienttypes.Height
// all clients must use the concrete implementation in types
type Height interface {
IsZero() bool
LT(Height) bool
EQ(Height) bool
GT(Height) bool
IsValid() bool
}

// ClientType defines the type of the consensus algorithm
type ClientType byte

Expand Down
6 changes: 5 additions & 1 deletion x/ibc/02-client/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) {
}

// client id is always "localhost"
clientState := localhosttypes.NewClientState(ctx.ChainID(), ctx.BlockHeight())
// Hardcode 0 as epoch number for now
// TODO: Retrieve epoch from chain-id
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

track issue?

clientState := localhosttypes.NewClientState(
ctx.ChainID(), types.NewHeight(0, uint64(ctx.BlockHeight())),
)

_, err := k.CreateClient(ctx, exported.ClientTypeLocalHost, clientState, nil)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion x/ibc/02-client/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ func HandleMsgCreateClient(ctx sdk.Context, k keeper.Keeper, msg exported.MsgCre
// localhost is a special case that must initialize client state
// from context and not from msg
case *localhosttypes.MsgCreateClient:
clientState = localhosttypes.NewClientState(ctx.ChainID(), ctx.BlockHeight())
selfHeight := types.NewHeight(0, uint64(ctx.BlockHeight()))
clientState = localhosttypes.NewClientState(ctx.ChainID(), selfHeight)
// Localhost consensus height is chain's blockheight
consensusHeight = uint64(ctx.BlockHeight())
default:
Expand Down
68 changes: 35 additions & 33 deletions x/ibc/02-client/keeper/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
tmtypes "github.com/tendermint/tendermint/types"

"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"
localhosttypes "github.com/cosmos/cosmos-sdk/x/ibc/09-localhost/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
Expand Down Expand Up @@ -80,14 +81,15 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)

// store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height
incrementedClientHeight := testClientHeight.Increment()
intermediateConsState := &ibctmtypes.ConsensusState{
Height: testClientHeight + 1,
Height: incrementedClientHeight,
Timestamp: suite.now.Add(time.Minute),
NextValidatorsHash: suite.valSetHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+1, intermediateConsState)
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, incrementedClientHeight.EpochHeight, intermediateConsState)

clientState.LatestHeight = testClientHeight + 1
clientState.LatestHeight = incrementedClientHeight
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)

updateHeader = createFutureUpdateFn(suite)
Expand All @@ -100,15 +102,15 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {

// store previous consensus state
prevConsState := &ibctmtypes.ConsensusState{
Height: 1,
Height: types.NewHeight(0, 1),
Timestamp: suite.past,
NextValidatorsHash: suite.valSetHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, 1, prevConsState)

// store intermediate consensus state to check that trustedHeight does not need to be hightest consensus state before header height
intermediateConsState := &ibctmtypes.ConsensusState{
Height: 2,
Height: types.NewHeight(0, 2),
Timestamp: suite.past.Add(time.Minute),
NextValidatorsHash: suite.valSetHash,
}
Expand Down Expand Up @@ -145,7 +147,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
return nil
}, false},
{"frozen client before update", func() error {
clientState = &ibctmtypes.ClientState{FrozenHeight: 1, LatestHeight: testClientHeight}
clientState = &ibctmtypes.ClientState{FrozenHeight: types.NewHeight(0, 1), LatestHeight: testClientHeight}
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)
suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint)
updateHeader = createFutureUpdateFn(suite)
Expand All @@ -154,13 +156,13 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
}, false},
{"valid past update before client was frozen", func() error {
clientState = ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs())
clientState.FrozenHeight = testClientHeight - 1
clientState.FrozenHeight = types.NewHeight(0, testClientHeight.EpochHeight-1)
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)
suite.Require().NoError(err)

// store previous consensus state
prevConsState := &ibctmtypes.ConsensusState{
Height: 1,
Height: types.NewHeight(0, 1),
Timestamp: suite.past,
NextValidatorsHash: suite.valSetHash,
}
Expand Down Expand Up @@ -198,7 +200,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
suite.Require().NoError(err, err)

expConsensusState := &ibctmtypes.ConsensusState{
Height: updateHeader.GetHeight(),
Height: types.NewHeight(0, updateHeader.GetHeight()),
Timestamp: updateHeader.GetTime(),
Root: commitmenttypes.NewMerkleRoot(updateHeader.Header.GetAppHash()),
NextValidatorsHash: updateHeader.Header.NextValidatorsHash,
Expand Down Expand Up @@ -231,7 +233,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
}

func (suite *KeeperTestSuite) TestUpdateClientLocalhost() {
var localhostClient exported.ClientState = localhosttypes.NewClientState(suite.header.Header.GetChainID(), suite.ctx.BlockHeight())
var localhostClient exported.ClientState = localhosttypes.NewClientState(suite.header.Header.GetChainID(), types.NewHeight(0, uint64(suite.ctx.BlockHeight())))

suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1)

Expand Down Expand Up @@ -274,8 +276,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
{
"trusting period misbehavior should pass",
&ibctmtypes.Misbehaviour{
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
Header1: ibctmtypes.CreateTestHeader(testChainID, height, height, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, height, height, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
ChainId: testChainID,
ClientId: testClientID,
},
Expand All @@ -291,8 +293,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
{
"misbehavior at later height should pass",
&ibctmtypes.Misbehaviour{
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, altTime, bothValSet, valSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
Header1: ibctmtypes.CreateTestHeader(testChainID, height+5, height, altTime, bothValSet, valSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, height+5, height, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
ChainId: testChainID,
ClientId: testClientID,
},
Expand All @@ -303,13 +305,13 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {

// store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height
intermediateConsState := &ibctmtypes.ConsensusState{
Height: testClientHeight + 3,
Height: types.NewHeight(0, height+3),
Timestamp: suite.now.Add(time.Minute),
NextValidatorsHash: suite.valSetHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+3, intermediateConsState)
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, height+3, intermediateConsState)

clientState.LatestHeight = testClientHeight + 3
clientState.LatestHeight = types.NewHeight(0, height+3)
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)

return err
Expand All @@ -319,8 +321,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
{
"misbehavior at later height with different trusted heights should pass",
&ibctmtypes.Misbehaviour{
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, altTime, bothValSet, valSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight+3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
Header1: ibctmtypes.CreateTestHeader(testChainID, height+5, height, altTime, bothValSet, valSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, height+5, height+3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
ChainId: testChainID,
ClientId: testClientID,
},
Expand All @@ -331,13 +333,13 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {

// store trusted consensus state for Header2
intermediateConsState := &ibctmtypes.ConsensusState{
Height: testClientHeight + 3,
Height: types.NewHeight(0, height+3),
Timestamp: suite.now.Add(time.Minute),
NextValidatorsHash: bothValsHash,
}
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+3, intermediateConsState)
suite.keeper.SetClientConsensusState(suite.ctx, testClientID, height+3, intermediateConsState)

clientState.LatestHeight = testClientHeight + 3
clientState.LatestHeight = types.NewHeight(0, height+3)
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)

return err
Expand All @@ -347,8 +349,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
{
"misbehaviour fails validatebasic",
&ibctmtypes.Misbehaviour{
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+1, testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
Header1: ibctmtypes.CreateTestHeader(testChainID, height+1, height, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, height, height, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
ChainId: testChainID,
ClientId: testClientID,
},
Expand All @@ -364,8 +366,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
{
"trusted ConsensusState1 not found",
&ibctmtypes.Misbehaviour{
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight+3, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
Header1: ibctmtypes.CreateTestHeader(testChainID, height+5, height+3, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, height+5, height, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
ChainId: testChainID,
ClientId: testClientID,
},
Expand All @@ -381,8 +383,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
{
"trusted ConsensusState2 not found",
&ibctmtypes.Misbehaviour{
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight, altTime, bothValSet, valSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight+5, testClientHeight+3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
Header1: ibctmtypes.CreateTestHeader(testChainID, height+5, height, altTime, bothValSet, valSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, height+5, height+3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
ChainId: testChainID,
ClientId: testClientID,
},
Expand All @@ -405,8 +407,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
{
"client already frozen at earlier height",
&ibctmtypes.Misbehaviour{
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
Header1: ibctmtypes.CreateTestHeader(testChainID, height, height, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, height, height, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
ChainId: testChainID,
ClientId: testClientID,
},
Expand All @@ -415,7 +417,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs())
_, err := suite.keeper.CreateClient(suite.ctx, testClientID, clientState, suite.consensusState)

clientState.FrozenHeight = 1
clientState.FrozenHeight = types.NewHeight(0, 1)
suite.keeper.SetClientState(suite.ctx, testClientID, clientState)

return err
Expand All @@ -426,8 +428,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
{
"misbehaviour check failed",
&ibctmtypes.Misbehaviour{
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners),
Header1: ibctmtypes.CreateTestHeader(testChainID, height, height, altTime, bothValSet, bothValSet, bothSigners),
Header2: ibctmtypes.CreateTestHeader(testChainID, height, height, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners),
ChainId: testChainID,
ClientId: testClientID,
},
Expand Down
Loading