Retrieve Epoch from ChainID (#7280)
* add functions to parse epoch from height * remove 0 epoch hardcoding * fix tendermint tests * fix tests * start update docs * progress * better parsing of chainID * fix update and misbehaviour logic and add tests * update docs * docfix * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * Update x/ibc/07-tendermint/types/misbehaviour_handle_test.go * change self checks to use epochs * address rest of reviews * rename epoch number to version in docs * wrap up rest of TODOs * Update x/ibc/02-client/genesis.go * add self validate test * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * fix godoc Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com>
This commit is contained in:
parent
5dc434fbca
commit
984c2d4179
|
@ -115,7 +115,6 @@ func QueryConsensusStateABCI(
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// TODO: retrieve epoch-number from chain-id
|
||||
return types.NewQueryConsensusStateResponse(clientID, anyConsensusState, proofBz, proofHeight), nil
|
||||
}
|
||||
|
||||
|
|
|
@ -45,10 +45,9 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) {
|
|||
}
|
||||
|
||||
// client id is always "localhost"
|
||||
// Hardcode 0 as epoch number for now
|
||||
// TODO: Retrieve epoch from chain-id
|
||||
epoch := types.ParseChainID(ctx.ChainID())
|
||||
clientState := localhosttypes.NewClientState(
|
||||
ctx.ChainID(), types.NewHeight(0, uint64(ctx.BlockHeight())),
|
||||
ctx.ChainID(), types.NewHeight(epoch, uint64(ctx.BlockHeight())),
|
||||
)
|
||||
|
||||
_, err := k.CreateClient(ctx, exported.ClientTypeLocalHost, clientState, nil)
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
clienttypes "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"
|
||||
|
@ -60,11 +61,17 @@ func (suite *KeeperTestSuite) TestCreateClient() {
|
|||
func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
|
||||
// Must create header creation functions since suite.header gets recreated on each test case
|
||||
createFutureUpdateFn := func(s *KeeperTestSuite) *ibctmtypes.Header {
|
||||
return ibctmtypes.CreateTestHeader(testChainID, int64(suite.header.GetHeight().GetEpochHeight()+3), int64(suite.header.GetHeight().GetEpochHeight()), suite.header.Header.Time.Add(time.Hour),
|
||||
heightPlus3 := clienttypes.NewHeight(suite.header.GetHeight().GetEpochNumber(), suite.header.GetHeight().GetEpochHeight()+3)
|
||||
height := suite.header.GetHeight().(clienttypes.Height)
|
||||
|
||||
return ibctmtypes.CreateTestHeader(testChainID, heightPlus3, height, suite.header.Header.Time.Add(time.Hour),
|
||||
suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||
}
|
||||
createPastUpdateFn := func(s *KeeperTestSuite) *ibctmtypes.Header {
|
||||
return ibctmtypes.CreateTestHeader(testChainID, int64(suite.header.GetHeight().GetEpochHeight()-2), int64(suite.header.GetHeight().GetEpochHeight())-4, suite.header.Header.Time,
|
||||
heightMinus2 := clienttypes.NewHeight(suite.header.GetHeight().GetEpochNumber(), suite.header.GetHeight().GetEpochHeight()-2)
|
||||
heightMinus4 := clienttypes.NewHeight(suite.header.GetHeight().GetEpochNumber(), suite.header.GetHeight().GetEpochHeight()-4)
|
||||
|
||||
return ibctmtypes.CreateTestHeader(testChainID, heightMinus2, heightMinus4, suite.header.Header.Time,
|
||||
suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||
}
|
||||
var (
|
||||
|
@ -270,6 +277,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
altTime := suite.ctx.BlockTime().Add(time.Minute)
|
||||
|
||||
heightPlus3 := types.NewHeight(0, height+3)
|
||||
heightPlus5 := types.NewHeight(0, height+5)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
@ -280,8 +288,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
{
|
||||
"trusting period misbehavior should pass",
|
||||
&ibctmtypes.Misbehaviour{
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, height, height, altTime, bothValSet, bothValSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, height, height, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: testChainID,
|
||||
ClientId: testClientID,
|
||||
},
|
||||
|
@ -297,8 +305,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
{
|
||||
"misbehavior at later height should pass",
|
||||
&ibctmtypes.Misbehaviour{
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, height+5, height, altTime, bothValSet, valSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, height+5, height, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, heightPlus5, testClientHeight, altTime, bothValSet, valSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, heightPlus5, testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
|
||||
ChainId: testChainID,
|
||||
ClientId: testClientID,
|
||||
},
|
||||
|
@ -324,8 +332,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
{
|
||||
"misbehavior at later height with different trusted heights should pass",
|
||||
&ibctmtypes.Misbehaviour{
|
||||
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),
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, heightPlus5, testClientHeight, altTime, bothValSet, valSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, heightPlus5, heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: testChainID,
|
||||
ClientId: testClientID,
|
||||
},
|
||||
|
@ -351,8 +359,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
{
|
||||
"trusted ConsensusState1 not found",
|
||||
&ibctmtypes.Misbehaviour{
|
||||
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),
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, heightPlus5, heightPlus3, altTime, bothValSet, bothValSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, heightPlus5, testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
|
||||
ChainId: testChainID,
|
||||
ClientId: testClientID,
|
||||
},
|
||||
|
@ -368,8 +376,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
{
|
||||
"trusted ConsensusState2 not found",
|
||||
&ibctmtypes.Misbehaviour{
|
||||
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),
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, heightPlus5, testClientHeight, altTime, bothValSet, valSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, heightPlus5, heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: testChainID,
|
||||
ClientId: testClientID,
|
||||
},
|
||||
|
@ -391,8 +399,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
{
|
||||
"client already frozen at earlier height",
|
||||
&ibctmtypes.Misbehaviour{
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, height, height, altTime, bothValSet, bothValSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, height, height, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: testChainID,
|
||||
ClientId: testClientID,
|
||||
},
|
||||
|
@ -411,8 +419,8 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
{
|
||||
"misbehaviour check failed",
|
||||
&ibctmtypes.Misbehaviour{
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, height, height, altTime, bothValSet, bothValSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, height, height, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners),
|
||||
Header1: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
|
||||
Header2: ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners),
|
||||
ChainId: testChainID,
|
||||
ClientId: testClientID,
|
||||
},
|
||||
|
|
|
@ -189,14 +189,15 @@ func (k Keeper) GetClientConsensusStateLTE(ctx sdk.Context, clientID string, max
|
|||
|
||||
// GetSelfConsensusState introspects the (self) past historical info at a given height
|
||||
// and returns the expected consensus state at that height.
|
||||
// TODO: Replace height with *clienttypes.Height once interfaces change
|
||||
// For now, can only retrieve self consensus states for the current epoch
|
||||
func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height exported.Height) (exported.ConsensusState, bool) {
|
||||
// TODO: check self chain-id against epoch number
|
||||
selfHeight, ok := height.(types.Height)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
if selfHeight.EpochNumber != 0 {
|
||||
// check that height epoch matches chainID epoch
|
||||
epoch := types.ParseChainID(ctx.ChainID())
|
||||
if epoch != height.GetEpochNumber() {
|
||||
return nil, false
|
||||
}
|
||||
histInfo, found := k.stakingKeeper.GetHistoricalInfo(ctx, int64(selfHeight.EpochHeight))
|
||||
|
@ -214,6 +215,7 @@ func (k Keeper) GetSelfConsensusState(ctx sdk.Context, height exported.Height) (
|
|||
|
||||
// ValidateSelfClient validates the client parameters for a client of the running chain
|
||||
// This function is only used to validate the client state the counterparty stores for this chain
|
||||
// Client must be in same epoch as the executing chain
|
||||
func (k Keeper) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientState) error {
|
||||
tmClient, ok := clientState.(*ibctmtypes.ClientState)
|
||||
if !ok {
|
||||
|
@ -230,9 +232,15 @@ func (k Keeper) ValidateSelfClient(ctx sdk.Context, clientState exported.ClientS
|
|||
ctx.ChainID(), tmClient.ChainId)
|
||||
}
|
||||
|
||||
// For now, assume epoch number is zero
|
||||
// TODO: Retrieve epoch number from chain-id
|
||||
selfHeight := types.NewHeight(0, uint64(ctx.BlockHeight()))
|
||||
epoch := types.ParseChainID(ctx.ChainID())
|
||||
|
||||
// client must be in the same epoch as executing chain
|
||||
if tmClient.LatestHeight.EpochNumber != epoch {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidClient, "client is not in the same epoch as the chain. expected epoch: %d, got: %d",
|
||||
tmClient.LatestHeight.EpochNumber, epoch)
|
||||
}
|
||||
|
||||
selfHeight := types.NewHeight(epoch, uint64(ctx.BlockHeight()))
|
||||
if tmClient.LatestHeight.GT(selfHeight) {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidClient, "client has LatestHeight %d greater than chain height %d",
|
||||
tmClient.LatestHeight, ctx.BlockHeight())
|
||||
|
|
|
@ -26,7 +26,8 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
testChainID = "gaiahub"
|
||||
testChainID = "gaiahub-0"
|
||||
testChainIDEpoch1 = "gaiahub-1"
|
||||
|
||||
testClientID = "gaiachain"
|
||||
testClientID2 = "ethbridge"
|
||||
|
@ -40,6 +41,7 @@ const (
|
|||
)
|
||||
|
||||
var testClientHeight = types.NewHeight(0, 5)
|
||||
var testClientHeightEpoch1 = types.NewHeight(1, 5)
|
||||
|
||||
type KeeperTestSuite struct {
|
||||
suite.Suite
|
||||
|
@ -83,10 +85,12 @@ func (suite *KeeperTestSuite) SetupTest() {
|
|||
pubKey, err := suite.privVal.GetPubKey()
|
||||
suite.Require().NoError(err)
|
||||
|
||||
testClientHeightMinus1 := types.NewHeight(0, height-1)
|
||||
|
||||
validator := tmtypes.NewValidator(pubKey, 1)
|
||||
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator})
|
||||
suite.valSetHash = suite.valSet.Hash()
|
||||
suite.header = ibctmtypes.CreateTestHeader(testChainID, height, height-1, now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||
suite.header = ibctmtypes.CreateTestHeader(testChainID, testClientHeight, testClientHeightMinus1, now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||
suite.consensusState = ibctmtypes.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot([]byte("hash")), suite.valSetHash)
|
||||
|
||||
var validators stakingtypes.Validators
|
||||
|
@ -170,6 +174,11 @@ func (suite *KeeperTestSuite) TestValidateSelfClient() {
|
|||
ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.NewHeight(0, testClientHeight.EpochHeight+10), commitmenttypes.GetSDKSpecs(), false, false),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid client epoch",
|
||||
ibctmtypes.NewClientState(testChainIDEpoch1, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeightEpoch1, commitmenttypes.GetSDKSpecs(), false, false),
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid proof specs",
|
||||
ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, nil, false, false),
|
||||
|
@ -291,7 +300,9 @@ func (suite KeeperTestSuite) TestConsensusStateHelpers() {
|
|||
|
||||
nextState := ibctmtypes.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot([]byte("next")), suite.valSetHash)
|
||||
|
||||
header := ibctmtypes.CreateTestHeader(testClientID, height+5, height, suite.header.Header.Time.Add(time.Minute),
|
||||
testClientHeightPlus5 := types.NewHeight(0, height+5)
|
||||
|
||||
header := ibctmtypes.CreateTestHeader(testClientID, testClientHeightPlus5, testClientHeight, suite.header.Header.Time.Add(time.Minute),
|
||||
suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||
|
||||
// mock update functionality
|
||||
|
|
|
@ -53,7 +53,8 @@ func TestValidateGenesis(t *testing.T) {
|
|||
val := tmtypes.NewValidator(pubKey, 10)
|
||||
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
||||
|
||||
header := ibctmtypes.CreateTestHeader(chainID, height, height-1, now, valSet, valSet, []tmtypes.PrivValidator{privVal})
|
||||
heightMinus1 := types.NewHeight(0, height-1)
|
||||
header := ibctmtypes.CreateTestHeader(chainID, clientHeight, heightMinus1, now, valSet, valSet, []tmtypes.PrivValidator{privVal})
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
|
|
|
@ -2,6 +2,7 @@ package types
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
|
@ -12,6 +13,11 @@ import (
|
|||
|
||||
var _ exported.Height = (*Height)(nil)
|
||||
|
||||
// IsEpochFormat checks if a chainID is in the format required for parsing epochs
|
||||
// The chainID must be in the form: `{chainID}-{version}
|
||||
// 24-host may enforce stricter checks on chainID
|
||||
var IsEpochFormat = regexp.MustCompile(`^.+[^-]-{1}[1-9][0-9]*$`).MatchString
|
||||
|
||||
// ZeroHeight is a helper function which returns an uninitialized height.
|
||||
func ZeroHeight() Height {
|
||||
return Height{}
|
||||
|
@ -35,7 +41,7 @@ func (h Height) GetEpochHeight() uint64 {
|
|||
return h.EpochHeight
|
||||
}
|
||||
|
||||
/// Compare implements a method to compare two heights. When comparing two heights a, b
|
||||
// Compare implements a method to compare two heights. When comparing two heights a, b
|
||||
// we can call a.Compare(b) which will return
|
||||
// -1 if a < b
|
||||
// 0 if a = b
|
||||
|
@ -143,8 +149,42 @@ func ParseHeight(heightStr string) (Height, error) {
|
|||
return NewHeight(epochNumber, epochHeight), nil
|
||||
}
|
||||
|
||||
// GetSelfHeight is a utility function that returns self height given context
|
||||
// TODO: Retrieve epoch-number from chain-id
|
||||
func GetSelfHeight(ctx sdk.Context) Height {
|
||||
return NewHeight(0, uint64(ctx.BlockHeight()))
|
||||
// SetEpochNumber takes a chainID in valid epoch format and swaps the epoch number
|
||||
// in the chainID with the given epoch number.
|
||||
func SetEpochNumber(chainID string, epoch uint64) (string, error) {
|
||||
if !IsEpochFormat(chainID) {
|
||||
return "", sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInvalidChainID, "chainID is not in epoch format: %s", chainID,
|
||||
)
|
||||
}
|
||||
|
||||
splitStr := strings.Split(chainID, "-")
|
||||
// swap out epoch number with given epoch
|
||||
splitStr[len(splitStr)-1] = strconv.Itoa(int(epoch))
|
||||
return strings.Join(splitStr, "-"), nil
|
||||
}
|
||||
|
||||
// ParseChainID is a utility function that returns an epoch number from the given ChainID.
|
||||
// ParseChainID attempts to parse a chain id in the format: `{chainID}-{version}`
|
||||
// and return the epochnumber as a uint64.
|
||||
// If the chainID is not in the expected format, a default epoch value of 0 is returned.
|
||||
func ParseChainID(chainID string) uint64 {
|
||||
if !IsEpochFormat(chainID) {
|
||||
// chainID is not in epoch format, return 0 as default
|
||||
return 0
|
||||
}
|
||||
splitStr := strings.Split(chainID, "-")
|
||||
epoch, err := strconv.ParseUint(splitStr[len(splitStr)-1], 10, 64)
|
||||
// sanity check: error should always be nil since regex only allows numbers in last element
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("regex allowed non-number value as last split element for chainID: %s", chainID))
|
||||
}
|
||||
return epoch
|
||||
}
|
||||
|
||||
// GetSelfHeight is a utility function that returns self height given context
|
||||
// Epoch number is retrieved from ctx.ChainID()
|
||||
func GetSelfHeight(ctx sdk.Context) Height {
|
||||
epoch := ParseChainID(ctx.ChainID())
|
||||
return NewHeight(epoch, uint64(ctx.BlockHeight()))
|
||||
}
|
||||
|
|
|
@ -93,3 +93,56 @@ func (suite *TypesTestSuite) TestMustParseHeight() {
|
|||
types.MustParseHeight("0-0")
|
||||
})
|
||||
}
|
||||
|
||||
func TestParseChainID(t *testing.T) {
|
||||
cases := []struct {
|
||||
chainID string
|
||||
epoch uint64
|
||||
formatted bool
|
||||
}{
|
||||
{"gaiamainnet-3", 3, true},
|
||||
{"gaia-mainnet-40", 40, true},
|
||||
{"gaiamainnet-3-39", 39, true},
|
||||
{"gaiamainnet--", 0, false},
|
||||
{"gaiamainnet-03", 0, false},
|
||||
{"gaiamainnet--4", 0, false},
|
||||
{"gaiamainnet-3.4", 0, false},
|
||||
{"gaiamainnet", 0, false},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
require.Equal(t, tc.formatted, types.IsEpochFormat(tc.chainID), "case %d does not match expected format", i)
|
||||
|
||||
epoch := types.ParseChainID(tc.chainID)
|
||||
require.Equal(t, tc.epoch, epoch, "case %d returns incorrect epoch", i)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSetEpochNumber(t *testing.T) {
|
||||
// Test SetEpochNumber
|
||||
chainID, err := types.SetEpochNumber("gaiamainnet", 3)
|
||||
require.Error(t, err, "invalid epoch format passed SetEpochNumber")
|
||||
require.Equal(t, "", chainID, "invalid epoch format returned non-empty string on SetEpochNumber")
|
||||
chainID = "gaiamainnet-3"
|
||||
|
||||
chainID, err = types.SetEpochNumber(chainID, 4)
|
||||
require.NoError(t, err, "valid epoch format failed SetEpochNumber")
|
||||
require.Equal(t, "gaiamainnet-4", chainID, "valid epoch format returned incorrect string on SetEpochNumber")
|
||||
}
|
||||
|
||||
func (suite *TypesTestSuite) TestSelfHeight() {
|
||||
ctx := suite.chainA.GetContext()
|
||||
|
||||
// Test default epoch
|
||||
ctx = ctx.WithChainID("gaiamainnet")
|
||||
ctx = ctx.WithBlockHeight(10)
|
||||
height := types.GetSelfHeight(ctx)
|
||||
suite.Require().Equal(types.NewHeight(0, 10), height, "default self height failed")
|
||||
|
||||
// Test successful epoch format
|
||||
ctx = ctx.WithChainID("gaiamainnet-3")
|
||||
ctx = ctx.WithBlockHeight(18)
|
||||
height = types.GetSelfHeight(ctx)
|
||||
suite.Require().Equal(types.NewHeight(3, 18), height, "valid self height failed")
|
||||
}
|
||||
|
|
|
@ -354,8 +354,10 @@ func (suite *TypesTestSuite) TestMarshalMsgSubmitMisbehaviour() {
|
|||
},
|
||||
{
|
||||
"tendermint client", func() {
|
||||
header1 := ibctmtypes.CreateTestHeader(suite.chainA.ChainID, suite.chainA.CurrentHeader.Height, suite.chainA.CurrentHeader.Height-1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers)
|
||||
header2 := ibctmtypes.CreateTestHeader(suite.chainA.ChainID, suite.chainA.CurrentHeader.Height, suite.chainA.CurrentHeader.Height-1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers)
|
||||
height := types.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height))
|
||||
heightMinus1 := types.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height)-1)
|
||||
header1 := ibctmtypes.CreateTestHeader(suite.chainA.ChainID, height, heightMinus1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers)
|
||||
header2 := ibctmtypes.CreateTestHeader(suite.chainA.ChainID, height, heightMinus1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers)
|
||||
|
||||
misbehaviour := ibctmtypes.NewMisbehaviour("tendermint", suite.chainA.ChainID, header1, header2)
|
||||
msg, err = types.NewMsgSubmitMisbehaviour("tendermint", misbehaviour, suite.chainA.SenderAccount.GetAddress())
|
||||
|
@ -410,8 +412,10 @@ func (suite *TypesTestSuite) TestMsgSubmitMisbehaviour_ValidateBasic() {
|
|||
{
|
||||
"valid - tendermint misbehaviour",
|
||||
func() {
|
||||
header1 := ibctmtypes.CreateTestHeader(suite.chainA.ChainID, suite.chainA.CurrentHeader.Height, suite.chainA.CurrentHeader.Height-1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers)
|
||||
header2 := ibctmtypes.CreateTestHeader(suite.chainA.ChainID, suite.chainA.CurrentHeader.Height, suite.chainA.CurrentHeader.Height-1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers)
|
||||
height := types.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height))
|
||||
heightMinus1 := types.NewHeight(0, uint64(suite.chainA.CurrentHeader.Height)-1)
|
||||
header1 := ibctmtypes.CreateTestHeader(suite.chainA.ChainID, height, heightMinus1, suite.chainA.CurrentHeader.Time, suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers)
|
||||
header2 := ibctmtypes.CreateTestHeader(suite.chainA.ChainID, height, heightMinus1, suite.chainA.CurrentHeader.Time.Add(time.Minute), suite.chainA.Vals, suite.chainA.Vals, suite.chainA.Signers)
|
||||
|
||||
misbehaviour := ibctmtypes.NewMisbehaviour("tendermint", suite.chainA.ChainID, header1, header2)
|
||||
msg, err = types.NewMsgSubmitMisbehaviour("tendermint", misbehaviour, suite.chainA.SenderAccount.GetAddress())
|
||||
|
|
|
@ -51,7 +51,6 @@ func queryPacketCommitmentABCI(
|
|||
return nil, sdkerrors.Wrapf(types.ErrPacketCommitmentNotFound, "portID (%s), channelID (%s), sequence (%d)", portID, channelID, sequence)
|
||||
}
|
||||
|
||||
// TODO: retrieve epoch number from chain-id
|
||||
return types.NewQueryPacketCommitmentResponse(portID, channelID, sequence, value, proofBz, proofHeight), nil
|
||||
}
|
||||
|
||||
|
@ -230,6 +229,5 @@ func queryNextSequenceRecvABCI(clientCtx client.Context, portID, channelID strin
|
|||
|
||||
sequence := binary.BigEndian.Uint64(value)
|
||||
|
||||
// TODO: retrieve epoch number from chain-id
|
||||
return types.NewQueryNextSequenceReceiveResponse(portID, channelID, sequence, proofBz, proofHeight), nil
|
||||
}
|
||||
|
|
|
@ -30,16 +30,12 @@ func (h Header) ConsensusState() *ConsensusState {
|
|||
|
||||
// GetHeight returns the current height. It returns 0 if the tendermint
|
||||
// header is nil.
|
||||
//
|
||||
// TODO: return clienttypes.Height once interface changes
|
||||
func (h Header) GetHeight() exported.Height {
|
||||
if h.Header == nil {
|
||||
return clienttypes.ZeroHeight()
|
||||
}
|
||||
|
||||
// Enforce clienttypes.Height to use 0 epoch number
|
||||
// TODO: Retrieve epoch number from chain-id
|
||||
return clienttypes.NewHeight(0, uint64(h.Header.Height))
|
||||
epoch := clienttypes.ParseChainID(h.Header.ChainID)
|
||||
return clienttypes.NewHeight(epoch, uint64(h.Header.Height))
|
||||
}
|
||||
|
||||
// GetTime returns the current block timestamp. It returns a zero time if
|
||||
|
|
|
@ -62,7 +62,7 @@ func (cs ClientState) CheckMisbehaviourAndUpdateState(
|
|||
infractionHeight := tmMisbehaviour.GetHeight().GetEpochHeight()
|
||||
ageBlocks = int64(cs.LatestHeight.EpochHeight - infractionHeight)
|
||||
} else {
|
||||
// if the misbehaviour is from a previous epoch, then the epoch-height
|
||||
// if the misbehaviour is from a different epoch, then the epoch-height
|
||||
// of misbehaviour has no correlation with the current epoch-height
|
||||
// so we disable the block check by setting ageBlocks to 0 and only
|
||||
// rely on the time expiry check with ageDuration
|
||||
|
@ -136,15 +136,22 @@ func checkMisbehaviourHeader(
|
|||
if currentTimestamp.Sub(consState.Timestamp) >= clientState.UnbondingPeriod {
|
||||
return sdkerrors.Wrapf(
|
||||
ErrUnbondingPeriodExpired,
|
||||
"current timestamp minus the latest consensus state timestamp is greater than or equal to the unbonding period (%s >= %s)",
|
||||
"current timestamp minus the latest consensus state timestamp is greater than or equal to the unbonding period (%d >= %d)",
|
||||
currentTimestamp.Sub(consState.Timestamp), clientState.UnbondingPeriod,
|
||||
)
|
||||
}
|
||||
|
||||
chainID := clientState.GetChainID()
|
||||
// If chainID is in epoch format, then set epoch number of chainID with the epoch number
|
||||
// of the misbehaviour header
|
||||
if clienttypes.IsEpochFormat(chainID) {
|
||||
chainID, _ = clienttypes.SetEpochNumber(chainID, header.GetHeight().GetEpochNumber())
|
||||
}
|
||||
|
||||
// - ValidatorSet must have 2/3 similarity with trusted FromValidatorSet
|
||||
// - ValidatorSets on both headers are valid given the last trusted ValidatorSet
|
||||
if err := tmTrustedValset.VerifyCommitLightTrusting(
|
||||
clientState.GetChainID(), tmCommit, clientState.TrustLevel.ToTendermint(),
|
||||
chainID, tmCommit, clientState.TrustLevel.ToTendermint(),
|
||||
); err != nil {
|
||||
return sdkerrors.Wrapf(clienttypes.ErrInvalidMisbehaviour, "validator set in header has too much change from trusted validator set: %v", err)
|
||||
}
|
||||
|
|
|
@ -58,8 +58,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -74,8 +74,88 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
heightMinus1,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
suite.now,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"valid misbehaviour with different trusted heights",
|
||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false),
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
heightMinus1,
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
heightMinus3,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
suite.now,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"valid misbehaviour at a previous epoch",
|
||||
types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), false, false),
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
heightMinus1,
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
heightMinus3,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainIDEpoch0, height, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainIDEpoch0, height, heightMinus3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainIDEpoch0,
|
||||
ClientId: chainID,
|
||||
},
|
||||
suite.now,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"valid misbehaviour at a future epoch",
|
||||
types.NewClientState(chainIDEpoch0, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false),
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
heightMinus1,
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
heightMinus3,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainIDEpoch0, clienttypes.NewHeight(1, 3), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainIDEpoch0, clienttypes.NewHeight(1, 3), heightMinus3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainIDEpoch0,
|
||||
ClientId: chainID,
|
||||
},
|
||||
suite.now,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"valid misbehaviour with trusted heights at a previous epoch",
|
||||
types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), false, false),
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
heightMinus1,
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
heightMinus3,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainIDEpoch1, clienttypes.NewHeight(1, 1), heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainIDEpoch1, clienttypes.NewHeight(1, 1), heightMinus3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainIDEpoch1,
|
||||
ClientId: chainID,
|
||||
},
|
||||
suite.now,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"consensus state's valset hash different from misbehaviour should still pass",
|
||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false),
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
height,
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -90,46 +170,14 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader("ethermint", int64(height.EpochHeight), int64(height.EpochHeight), suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader("ethermint", int64(height.EpochHeight), int64(height.EpochHeight), suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader("ethermint", height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader("ethermint", height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: "ethermint",
|
||||
ClientId: chainID,
|
||||
},
|
||||
suite.now,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid misbehavior misbehaviour with different trusted heights",
|
||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false),
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
heightMinus1,
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
heightMinus3,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-3, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
suite.now,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"consensus state's valset hash different from misbehaviour should still pass",
|
||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false),
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
height,
|
||||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
suite.now,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid misbehavior misbehaviour with trusted height different from trusted consensus state",
|
||||
types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false),
|
||||
|
@ -138,8 +186,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
heightMinus3,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -154,8 +202,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), suite.valsHash),
|
||||
heightMinus3,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-3, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus3, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -170,8 +218,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -186,8 +234,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -213,8 +261,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -229,8 +277,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -245,8 +293,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus1, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -261,8 +309,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -277,8 +325,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -293,8 +341,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now, altValSet, bothValSet, altSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, height, suite.now, altValSet, bothValSet, altSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), bothValSet, bothValSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -309,8 +357,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, height, suite.now, bothValSet, bothValSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
@ -325,8 +373,8 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviourAndUpdateState() {
|
|||
types.NewConsensusState(suite.now, commitmenttypes.NewMerkleRoot(tmhash.Sum([]byte("app_hash"))), bothValsHash),
|
||||
height,
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now, altValSet, bothValSet, altSigners),
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, height, suite.now, altValSet, bothValSet, altSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, height, suite.now.Add(time.Minute), altValSet, bothValSet, altSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: chainID,
|
||||
},
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/ibc/exported"
|
||||
ibctestingmock "github.com/cosmos/cosmos-sdk/x/ibc/testing/mock"
|
||||
|
@ -14,11 +15,11 @@ import (
|
|||
|
||||
func (suite *TendermintTestSuite) TestMisbehaviour() {
|
||||
signers := []tmtypes.PrivValidator{suite.privVal}
|
||||
epochHeight := int64(height.EpochHeight)
|
||||
heightMinus1 := clienttypes.NewHeight(0, height.EpochHeight-1)
|
||||
|
||||
misbehaviour := &types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, suite.valSet, suite.valSet, signers),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, suite.valSet, suite.valSet, signers),
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
}
|
||||
|
@ -50,6 +51,8 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
|
||||
altSigners := []tmtypes.PrivValidator{altPrivVal}
|
||||
|
||||
heightMinus1 := clienttypes.NewHeight(0, height.EpochHeight-1)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
misbehaviour *types.Misbehaviour
|
||||
|
@ -60,7 +63,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"valid misbehaviour",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
@ -83,7 +86,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"valid misbehaviour with different trusted headers",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-3, suite.now.Add(time.Minute), suite.valSet, bothValSet, signers),
|
||||
Header2: types.CreateTestHeader(chainID, height, clienttypes.NewHeight(0, height.EpochHeight-3), suite.now.Add(time.Minute), suite.valSet, bothValSet, signers),
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
@ -93,7 +96,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
{
|
||||
"trusted height is 0 in Header1",
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, 0, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||
Header1: types.CreateTestHeader(chainID, height, clienttypes.ZeroHeight(), suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||
Header2: suite.header,
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
|
@ -105,7 +108,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"trusted height is 0 in Header2",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, 0, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||
Header2: types.CreateTestHeader(chainID, height, clienttypes.ZeroHeight(), suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
@ -115,7 +118,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
{
|
||||
"trusted valset is nil in Header1",
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now.Add(time.Minute), suite.valSet, nil, signers),
|
||||
Header1: types.CreateTestHeader(chainID, height, heightMinus1, suite.now.Add(time.Minute), suite.valSet, nil, signers),
|
||||
Header2: suite.header,
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
|
@ -127,7 +130,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"trusted valset is nil in Header2",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now.Add(time.Minute), suite.valSet, nil, signers),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus1, suite.now.Add(time.Minute), suite.valSet, nil, signers),
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
@ -138,7 +141,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"invalid client ID ",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, suite.valSet, suite.valSet, signers),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, suite.valSet, suite.valSet, signers),
|
||||
ChainId: chainID,
|
||||
ClientId: "GAIA",
|
||||
},
|
||||
|
@ -149,7 +152,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"wrong chainID on header1",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader("ethermint", epochHeight, epochHeight-1, suite.now, suite.valSet, suite.valSet, signers),
|
||||
Header2: types.CreateTestHeader("ethermint", height, heightMinus1, suite.now, suite.valSet, suite.valSet, signers),
|
||||
ChainId: "ethermint",
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
@ -160,7 +163,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"wrong chainID on header2",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader("ethermint", epochHeight, epochHeight-1, suite.now, suite.valSet, suite.valSet, signers),
|
||||
Header2: types.CreateTestHeader("ethermint", height, heightMinus1, suite.now, suite.valSet, suite.valSet, signers),
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
@ -171,7 +174,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"wrong chainID in misbehaviour",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, int64(height.EpochHeight), int64(height.EpochHeight-1), suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers),
|
||||
ChainId: "ethermint",
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
@ -182,7 +185,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"mismatched heights",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, 6, 4, suite.now, suite.valSet, suite.valSet, signers),
|
||||
Header2: types.CreateTestHeader(chainID, clienttypes.NewHeight(0, 6), clienttypes.NewHeight(0, 4), suite.now, suite.valSet, suite.valSet, signers),
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
@ -203,7 +206,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
{
|
||||
"header 1 doesn't have 2/3 majority",
|
||||
&types.Misbehaviour{
|
||||
Header1: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
Header1: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
Header2: suite.header,
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
|
@ -226,7 +229,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"header 2 doesn't have 2/3 majority",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
@ -248,7 +251,7 @@ func (suite *TendermintTestSuite) TestMisbehaviourValidateBasic() {
|
|||
"validators sign off on wrong commit",
|
||||
&types.Misbehaviour{
|
||||
Header1: suite.header,
|
||||
Header2: types.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
Header2: types.CreateTestHeader(chainID, height, heightMinus1, suite.now, bothValSet, suite.valSet, bothSigners),
|
||||
ChainId: chainID,
|
||||
ClientId: clientID,
|
||||
},
|
||||
|
|
|
@ -20,6 +20,8 @@ import (
|
|||
|
||||
const (
|
||||
chainID = "gaia"
|
||||
chainIDEpoch0 = "gaia-epoch-0"
|
||||
chainIDEpoch1 = "gaia-epoch-1"
|
||||
clientID = "gaiamainnet"
|
||||
trustingPeriod time.Duration = time.Hour * 24 * 7 * 2
|
||||
ubdPeriod time.Duration = time.Hour * 24 * 7 * 3
|
||||
|
@ -72,12 +74,12 @@ func (suite *TendermintTestSuite) SetupTest() {
|
|||
pubKey, err := suite.privVal.GetPubKey()
|
||||
suite.Require().NoError(err)
|
||||
|
||||
epochHeight := int64(height.EpochHeight)
|
||||
heightMinus1 := clienttypes.NewHeight(0, height.EpochHeight-1)
|
||||
|
||||
val := tmtypes.NewValidator(pubKey, 10)
|
||||
suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
||||
suite.valsHash = suite.valSet.Hash()
|
||||
suite.header = ibctmtypes.CreateTestHeader(chainID, epochHeight, epochHeight-1, suite.now, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||
suite.header = ibctmtypes.CreateTestHeader(chainID, height, heightMinus1, suite.now, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal})
|
||||
suite.ctx = app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, Time: suite.now})
|
||||
}
|
||||
|
||||
|
|
|
@ -24,16 +24,17 @@ func MakeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) tmtypes.Bl
|
|||
}
|
||||
|
||||
// CreateTestHeader creates a mock header for testing only.
|
||||
func CreateTestHeader(chainID string, height, trustedHeight int64, timestamp time.Time, tmValSet, tmTrustedVals *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) *Header {
|
||||
func CreateTestHeader(chainID string, height, trustedHeight clienttypes.Height, timestamp time.Time, tmValSet, tmTrustedVals *tmtypes.ValidatorSet, signers []tmtypes.PrivValidator) *Header {
|
||||
var (
|
||||
valSet *tmproto.ValidatorSet
|
||||
trustedVals *tmproto.ValidatorSet
|
||||
)
|
||||
vsetHash := tmValSet.Hash()
|
||||
blockHeight := int64(height.EpochHeight)
|
||||
tmHeader := tmtypes.Header{
|
||||
Version: version.Consensus{Block: 2, App: 2},
|
||||
ChainID: chainID,
|
||||
Height: height,
|
||||
Height: blockHeight,
|
||||
Time: timestamp,
|
||||
LastBlockID: MakeBlockID(make([]byte, tmhash.Size), 10_000, make([]byte, tmhash.Size)),
|
||||
LastCommitHash: tmhash.Sum([]byte("last_commit_hash")),
|
||||
|
@ -49,8 +50,8 @@ func CreateTestHeader(chainID string, height, trustedHeight int64, timestamp tim
|
|||
|
||||
hhash := tmHeader.Hash()
|
||||
blockID := MakeBlockID(hhash, 3, tmhash.Sum([]byte("part_set")))
|
||||
voteSet := tmtypes.NewVoteSet(chainID, height, 1, tmproto.PrecommitType, tmValSet)
|
||||
commit, err := tmtypes.MakeCommit(blockID, height, 1, voteSet, signers, timestamp)
|
||||
voteSet := tmtypes.NewVoteSet(chainID, blockHeight, 1, tmproto.PrecommitType, tmValSet)
|
||||
commit, err := tmtypes.MakeCommit(blockID, blockHeight, 1, voteSet, signers, timestamp)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -77,7 +78,7 @@ func CreateTestHeader(chainID string, height, trustedHeight int64, timestamp tim
|
|||
return &Header{
|
||||
SignedHeader: &signedHeader,
|
||||
ValidatorSet: valSet,
|
||||
TrustedHeight: clienttypes.NewHeight(0, uint64(trustedHeight)),
|
||||
TrustedHeight: trustedHeight,
|
||||
TrustedValidators: trustedVals,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ import (
|
|||
// It returns an error if:
|
||||
// - the client or header provided are not parseable to tendermint types
|
||||
// - the header is invalid
|
||||
// - header height is less than or equal to the consensus state height
|
||||
// - header height is less than or equal to the trusted header height
|
||||
// - header epoch is not equal to trusted header epoch
|
||||
// - header valset commit verification fails
|
||||
// - header timestamp is past the trusting period in relation to the consensus state
|
||||
// - header timestamp is less than or equal to the consensus state timestamp
|
||||
|
@ -32,6 +33,8 @@ import (
|
|||
// If we are updating to a past height, a consensus state is created for that height to be persisted in client store
|
||||
// If we are updating to a future height, the consensus state is created and the client state is updated to reflect
|
||||
// the new latest height
|
||||
// UpdateClient must only be used to update within a single epoch, thus header epoch number and trusted height's epoch
|
||||
// number must be the same. To update to a new epoch, use a separate upgrade path
|
||||
// Tendermint client validity checking uses the bisection algorithm described
|
||||
// in the [Tendermint spec](https://github.com/tendermint/spec/blob/master/spec/consensus/light-client.md).
|
||||
func (cs ClientState) CheckHeaderAndUpdateState(
|
||||
|
@ -91,6 +94,16 @@ func checkValidity(
|
|||
return err
|
||||
}
|
||||
|
||||
// UpdateClient only accepts updates with a header at the same epoch
|
||||
// as the trusted consensus state
|
||||
if header.GetHeight().GetEpochNumber() != header.TrustedHeight.EpochNumber {
|
||||
return sdkerrors.Wrapf(
|
||||
ErrInvalidHeaderHeight,
|
||||
"header height epoch %d does not match trusted header epoch %d",
|
||||
header.GetHeight().GetEpochNumber(), header.TrustedHeight.EpochNumber,
|
||||
)
|
||||
}
|
||||
|
||||
tmTrustedValidators, err := tmtypes.ValidatorSetFromProto(header.TrustedValidators)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "trusted validator set in not tendermint validator set type")
|
||||
|
@ -110,7 +123,7 @@ func checkValidity(
|
|||
if header.GetHeight().LTE(header.TrustedHeight) {
|
||||
return sdkerrors.Wrapf(
|
||||
clienttypes.ErrInvalidHeader,
|
||||
"header height ≤ consensus state height (%d ≤ %d)", header.GetHeight(), header.TrustedHeight,
|
||||
"header height ≤ consensus state height (%s ≤ %s)", header.GetHeight(), header.TrustedHeight,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -125,13 +138,24 @@ func checkValidity(
|
|||
Header: &trustedHeader,
|
||||
}
|
||||
|
||||
chainID := clientState.GetChainID()
|
||||
// If chainID is in epoch format, then set epoch number of chainID with the epoch number
|
||||
// of the header we are verifying
|
||||
// This is useful if the update is at a previous epoch rather than an update to the latest epoch
|
||||
// of the client.
|
||||
// The chainID must be set correctly for the previous epoch before attempting verification.
|
||||
// Updates for previous epochs are not supported if the chainID is not in epoch format.
|
||||
if clienttypes.IsEpochFormat(chainID) {
|
||||
chainID, _ = clienttypes.SetEpochNumber(chainID, header.GetHeight().GetEpochNumber())
|
||||
}
|
||||
|
||||
// Verify next header with the passed-in trustedVals
|
||||
// - asserts trusting period not passed
|
||||
// - assert header timestamp is not past the trusting period
|
||||
// - assert header timestamp is past latest stored consensus state timestamp
|
||||
// - assert that a TrustLevel proportion of TrustedValidators signed new Commit
|
||||
err = light.Verify(
|
||||
clientState.GetChainID(), &signedHeader,
|
||||
chainID, &signedHeader,
|
||||
tmTrustedValidators, tmSignedHeader, tmValidatorSet,
|
||||
clientState.TrustingPeriod, currentTimestamp, clientState.MaxClockDrift, clientState.TrustLevel.ToTendermint(),
|
||||
)
|
||||
|
|
|
@ -26,6 +26,10 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
suite.Require().NoError(err)
|
||||
|
||||
epochHeight := int64(height.EpochHeight)
|
||||
|
||||
// create modified heights to use for test-cases
|
||||
heightPlus1 := clienttypes.NewHeight(height.EpochNumber, height.EpochHeight+1)
|
||||
heightMinus1 := clienttypes.NewHeight(height.EpochNumber, height.EpochHeight-1)
|
||||
heightMinus3 := clienttypes.NewHeight(height.EpochNumber, height.EpochHeight-3)
|
||||
heightPlus5 := clienttypes.NewHeight(height.EpochNumber, height.EpochHeight+5)
|
||||
|
||||
|
@ -54,7 +58,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+1, epochHeight, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: true,
|
||||
|
@ -64,7 +68,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+5, epochHeight, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus5, height, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: true,
|
||||
|
@ -74,7 +78,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), bothValSet.Hash())
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+1, epochHeight, suite.headerTime, bothValSet, bothValSet, bothSigners)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, bothValSet, bothValSet, bothSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: true,
|
||||
|
@ -85,7 +89,17 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
consStateHeight = heightMinus3
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight-1, epochHeight-3, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||
newHeader = types.CreateTestHeader(chainID, heightMinus1, heightMinus3, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: true,
|
||||
},
|
||||
{
|
||||
name: "successful update for a previous epoch",
|
||||
setup: func() {
|
||||
clientState = types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainIDEpoch0, height, heightMinus3, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: true,
|
||||
|
@ -95,7 +109,27 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader("ethermint", int64(height.EpochHeight+1), int64(height.EpochHeight), suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
newHeader = types.CreateTestHeader("ethermint", heightPlus1, height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "unsuccessful update to a future epoch",
|
||||
setup: func() {
|
||||
clientState = types.NewClientState(chainIDEpoch0, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainIDEpoch1, clienttypes.NewHeight(1, 1), height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
},
|
||||
{
|
||||
name: "unsuccessful update: header height epoch and trusted height epoch mismatch",
|
||||
setup: func() {
|
||||
clientState = types.NewClientState(chainIDEpoch1, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, clienttypes.NewHeight(1, 1), commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainIDEpoch1, clienttypes.NewHeight(1, 3), height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
|
@ -105,7 +139,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+1, epochHeight, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, bothValSet, suite.valSet, bothSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
|
@ -115,7 +149,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), bothValSet.Hash())
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+1, epochHeight, suite.headerTime, suite.valSet, bothValSet, signers)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, suite.valSet, bothValSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
|
@ -125,7 +159,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+5, epochHeight, suite.headerTime, altValSet, suite.valSet, altSigners)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus5, height, suite.headerTime, altValSet, suite.valSet, altSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
|
@ -135,7 +169,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+5, epochHeight, suite.headerTime, bothValSet, bothValSet, bothSigners)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus5, height, suite.headerTime, bothValSet, bothValSet, bothSigners)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
|
@ -145,7 +179,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+1, epochHeight, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
// make current time pass trusting period from last timestamp on clientstate
|
||||
currentTime = suite.now.Add(trustingPeriod)
|
||||
},
|
||||
|
@ -156,7 +190,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+1, epochHeight, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
|
@ -166,7 +200,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+1, epochHeight, suite.clientTime, suite.valSet, suite.valSet, signers)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.clientTime, suite.valSet, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
|
@ -176,7 +210,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
setup: func() {
|
||||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, height, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight+1, epochHeight, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
newHeader = types.CreateTestHeader(chainID, heightPlus1, height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
// cause new header to fail validatebasic by changing commit height to mismatch header height
|
||||
newHeader.SignedHeader.Commit.Height = epochHeight - 1
|
||||
currentTime = suite.now
|
||||
|
@ -189,7 +223,7 @@ func (suite *TendermintTestSuite) TestCheckHeaderAndUpdateState() {
|
|||
clientState = types.NewClientState(chainID, types.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, heightPlus5, commitmenttypes.GetSDKSpecs(), false, false)
|
||||
consensusState = types.NewConsensusState(suite.clientTime, commitmenttypes.NewMerkleRoot(suite.header.Header.GetAppHash()), suite.valsHash)
|
||||
// Make new header at height less than latest client state
|
||||
newHeader = types.CreateTestHeader(chainID, epochHeight-1, epochHeight, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
newHeader = types.CreateTestHeader(chainID, heightMinus1, height, suite.headerTime, suite.valSet, suite.valSet, signers)
|
||||
currentTime = suite.now
|
||||
},
|
||||
expPass: false,
|
||||
|
|
|
@ -75,9 +75,8 @@ func (cs *ClientState) CheckHeaderAndUpdateState(
|
|||
) (exported.ClientState, exported.ConsensusState, error) {
|
||||
// use the chain ID from context since the localhost client is from the running chain (i.e self).
|
||||
cs.ChainId = ctx.ChainID()
|
||||
// Hardcode 0 for epoch number for now
|
||||
// TODO: Retrieve epoch number from chain-id
|
||||
cs.Height = clienttypes.NewHeight(0, uint64(ctx.BlockHeight()))
|
||||
epoch := clienttypes.ParseChainID(cs.ChainId)
|
||||
cs.Height = clienttypes.NewHeight(epoch, uint64(ctx.BlockHeight()))
|
||||
return cs, nil, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,6 @@ func QueryTendermintProof(clientCtx client.Context, key []byte) ([]byte, []byte,
|
|||
return nil, nil, clienttypes.Height{}, err
|
||||
}
|
||||
|
||||
// TODO: retrieve epoch number from chain-id
|
||||
return res.Value, proofBz, clienttypes.NewHeight(0, uint64(res.Height)+1), nil
|
||||
epoch := clienttypes.ParseChainID(clientCtx.ChainID)
|
||||
return res.Value, proofBz, clienttypes.NewHeight(epoch, uint64(res.Height)+1), nil
|
||||
}
|
||||
|
|
|
@ -63,7 +63,9 @@ func (suite *IBCTestSuite) SetupTest() {
|
|||
val := tmtypes.NewValidator(pubKey, 10)
|
||||
valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{val})
|
||||
|
||||
suite.header = ibctmtypes.CreateTestHeader(chainID, height, height-1, now, valSet, valSet, []tmtypes.PrivValidator{privVal})
|
||||
clientHeightMinus1 := clienttypes.NewHeight(0, height-1)
|
||||
|
||||
suite.header = ibctmtypes.CreateTestHeader(chainID, clientHeight, clientHeightMinus1, now, valSet, valSet, []tmtypes.PrivValidator{privVal})
|
||||
|
||||
suite.ctx = suite.app.BaseApp.NewContext(isCheckTx, tmproto.Header{})
|
||||
}
|
||||
|
|
|
@ -38,7 +38,13 @@ given by the chain's chainID, and the epoch height given by the Tendermint block
|
|||
and resets its block-height, it is responsible for updating its chain-id to increment the epoch number.
|
||||
IBC Tendermint clients then verifies the epoch number against their `ChainId` and treat the `EpochHeight` as the Tendermint block-height.
|
||||
|
||||
TODO: Explain how to structure chain-id to make epoch-number parsable
|
||||
Tendermint chains wishing to use epochs to maintain persistent IBC connections even across height-resetting upgrades must format their chain-ids
|
||||
in the following manner: `{chainID}-{version}`. On any height-resetting upgrade, the chainID **MUST** be updated with a higher epoch number
|
||||
than the previous value.
|
||||
|
||||
Ex:
|
||||
Before upgrade ChainID: `gaiamainnet-3`
|
||||
After upgrade ChainID: `gaiamainnet-4`
|
||||
|
||||
Clients that do not require epochs, such as the solo-machine client, simply hardcode `0` into the epoch number whenever they
|
||||
need to return an IBC height when implementing IBC interfaces and use the `EpochHeight` exclusively.
|
||||
|
|
|
@ -181,10 +181,12 @@ func (chain *TestChain) QueryProof(key []byte) ([]byte, clienttypes.Height) {
|
|||
proof, err := chain.App.AppCodec().MarshalBinaryBare(&merkleProof)
|
||||
require.NoError(chain.t, err)
|
||||
|
||||
epoch := clienttypes.ParseChainID(chain.ChainID)
|
||||
|
||||
// proof height + 1 is returned as the proof created corresponds to the height the proof
|
||||
// was created in the IAVL tree. Tendermint and subsequently the clients that rely on it
|
||||
// have heights 1 above the IAVL tree. Thus we return proof height + 1
|
||||
return proof, clienttypes.NewHeight(0, uint64(res.Height)+1)
|
||||
return proof, clienttypes.NewHeight(epoch, uint64(res.Height)+1)
|
||||
}
|
||||
|
||||
// QueryClientStateProof performs and abci query for a client state
|
||||
|
|
Loading…
Reference in New Issue