Skip to content

Commit

Permalink
Merge PR: fix ibc header validate (#2122)
Browse files Browse the repository at this point in the history
* fix ibc hegith by other chain

Co-authored-by: itsfunny <[email protected]>
  • Loading branch information
xiangjianmeng and ItsFunny authored May 30, 2022
1 parent 0ba4f32 commit b7e1868
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 129 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (h Header) ValidateBasic() error {
if err != nil {
return sdkerrors.Wrap(err, "header is not a tendermint header")
}
if err := tmSignedHeader.ValidateBasic(h.Header.GetChainID()); err != nil {
if err := tmSignedHeader.ValidateBasicForIBC(h.Header.GetChainID()); err != nil {
return sdkerrors.Wrap(err, "header failed basic validation")
}

Expand All @@ -75,7 +75,7 @@ func (h Header) ValidateBasic() error {
return sdkerrors.Wrap(err, "validator set is not tendermint validator set")
}
//if !bytes.Equal(h.Header.ValidatorsHash, tmValset.Hash()) {
if !bytes.Equal(h.Header.ValidatorsHash, tmValset.Hash(h.Header.Height)) {
if !bytes.Equal(h.Header.ValidatorsHash, tmValset.IBCHash()) {
return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "validator set does not match hash")
}
return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ func checkTrustedHeader(header *Header, consState *ConsensusState) error {

// assert that trustedVals is NextValidators of last trusted header
// to do this, we check that trustedVals.Hash() == consState.NextValidatorsHash
tvalHash := tmTrustedValidators.Hash(header.Header.Height)
tvalHash := tmTrustedValidators.IBCHash()
if !bytes.Equal(consState.NextValidatorsHash, tvalHash) {
return sdkerrors.Wrapf(
ErrInvalidValidatorSet,
Expand Down
58 changes: 20 additions & 38 deletions libs/tendermint/lite2/ibc_verify.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package lite

import (
"errors"
"time"

tmmath "github.com/okex/exchain/libs/tendermint/libs/math"
Expand All @@ -24,7 +23,7 @@ func IBCVerify(
trustingPeriod, now, maxClockDrift, trustLevel)
}

return VerifyAdjacent(chainID, trustedHeader, untrustedHeader, untrustedVals, trustingPeriod, now, maxClockDrift)
return IBCVerifyAdjacent(chainID, trustedHeader, untrustedHeader, untrustedVals, trustingPeriod, now, maxClockDrift)
}

func IBCVerifyNonAdjacent(
Expand All @@ -38,43 +37,26 @@ func IBCVerifyNonAdjacent(
maxClockDrift time.Duration,
trustLevel tmmath.Fraction) error {

if untrustedHeader.Height == trustedHeader.Height+1 {
return errors.New("headers must be non adjacent in height")
}
return commonVerifyNonAdjacent(
chainID, trustedHeader, trustedVals, untrustedHeader,
untrustedVals, trustingPeriod, now, maxClockDrift, trustLevel, true)
}

if HeaderExpired(trustedHeader, trustingPeriod, now) {
return ErrOldHeaderExpired{trustedHeader.Time.Add(trustingPeriod), now}
}
func IBCVerifyAdjacent(
chainID string,
trustedHeader *types.SignedHeader, // height=X
untrustedHeader *types.SignedHeader, // height=X+1
untrustedVals *types.ValidatorSet, // height=X+1
trustingPeriod time.Duration,
now time.Time,
maxClockDrift time.Duration) error {

if err := verifyNewHeaderAndVals(
return commonVerifyAdjacent(
chainID,
untrustedHeader, untrustedVals,
trustedHeader,
now, maxClockDrift); err != nil {
return ErrInvalidHeader{err}
}

// Ensure that +`trustLevel` (default 1/3) or more of last trusted validators signed correctly.
err := trustedVals.IBCVerifyCommitLightTrusting(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit, trustLevel)
if err != nil {
switch e := err.(type) {
case types.ErrNotEnoughVotingPowerSigned:
return ErrNewValSetCantBeTrusted{e}
default:
return e
}
}

// Ensure that +2/3 of new validators signed correctly.
//
// NOTE: this should always be the last check because untrustedVals can be
// intentionally made very large to DOS the light client. not the case for
// VerifyAdjacent, where validator set is known in advance.
if err := untrustedVals.VerifyCommitLight(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit); err != nil {
return ErrInvalidHeader{err}
}

return nil
trustedHeader, // height=X
untrustedHeader, // height=X+1
untrustedVals, // height=X+1
trustingPeriod,
now,
maxClockDrift, true)
}
90 changes: 78 additions & 12 deletions libs/tendermint/lite2/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,22 @@ func VerifyNonAdjacent(
maxClockDrift time.Duration,
trustLevel tmmath.Fraction) error {

return commonVerifyNonAdjacent(
chainID, trustedHeader, trustedVals, untrustedHeader,
untrustedVals, trustingPeriod, now, maxClockDrift, trustLevel, false)
}

func commonVerifyNonAdjacent(
chainID string,
trustedHeader *types.SignedHeader, // height=X
trustedVals *types.ValidatorSet, // height=X or height=X+1
untrustedHeader *types.SignedHeader, // height=Y
untrustedVals *types.ValidatorSet, // height=Y
trustingPeriod time.Duration,
now time.Time,
maxClockDrift time.Duration,
trustLevel tmmath.Fraction, isIbc bool) error {

if untrustedHeader.Height == trustedHeader.Height+1 {
return errors.New("headers must be non adjacent in height")
}
Expand All @@ -48,17 +64,23 @@ func VerifyNonAdjacent(
return ErrOldHeaderExpired{trustedHeader.Time.Add(trustingPeriod), now}
}

if err := verifyNewHeaderAndVals(
var err error
if err = verifyNewHeaderAndVals(
chainID,
untrustedHeader, untrustedVals,
trustedHeader,
now, maxClockDrift); err != nil {
now, maxClockDrift, isIbc); err != nil {
return ErrInvalidHeader{err}
}

// Ensure that +`trustLevel` (default 1/3) or more of last trusted validators signed correctly.
err := trustedVals.VerifyCommitLightTrusting(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit, trustLevel)
if isIbc {
err = trustedVals.IBCVerifyCommitLightTrusting(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit, trustLevel)
} else {
err = trustedVals.VerifyCommitLightTrusting(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit, trustLevel)
}
if err != nil {
switch e := err.(type) {
case types.ErrNotEnoughVotingPowerSigned:
Expand All @@ -73,8 +95,14 @@ func VerifyNonAdjacent(
// NOTE: this should always be the last check because untrustedVals can be
// intentionally made very large to DOS the light client. not the case for
// VerifyAdjacent, where validator set is known in advance.
if err := untrustedVals.VerifyCommitLight(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit); err != nil {
if isIbc {
err = untrustedVals.IBCVerifyCommitLight(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit)
} else {
err = untrustedVals.VerifyCommitLight(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit)
}
if err != nil {
return ErrInvalidHeader{err}
}

Expand Down Expand Up @@ -102,6 +130,25 @@ func VerifyAdjacent(
now time.Time,
maxClockDrift time.Duration) error {

return commonVerifyAdjacent(
chainID,
trustedHeader, // height=X
untrustedHeader, // height=X+1
untrustedVals, // height=X+1
trustingPeriod,
now,
maxClockDrift, false)
}

func commonVerifyAdjacent(
chainID string,
trustedHeader *types.SignedHeader, // height=X
untrustedHeader *types.SignedHeader, // height=X+1
untrustedVals *types.ValidatorSet, // height=X+1
trustingPeriod time.Duration,
now time.Time,
maxClockDrift time.Duration, isIbc bool) error {

if untrustedHeader.Height != trustedHeader.Height+1 {
return errors.New("headers must be adjacent in height")
}
Expand All @@ -114,7 +161,7 @@ func VerifyAdjacent(
chainID,
untrustedHeader, untrustedVals,
trustedHeader,
now, maxClockDrift); err != nil {
now, maxClockDrift, isIbc); err != nil {
return ErrInvalidHeader{err}
}

Expand All @@ -128,8 +175,15 @@ func VerifyAdjacent(
}

// Ensure that +2/3 of new validators signed correctly.
if err := untrustedVals.VerifyCommitLight(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit); err != nil {
var err error
if isIbc {
err = untrustedVals.IBCVerifyCommitLight(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit)
} else {
err = untrustedVals.VerifyCommitLight(chainID, untrustedHeader.Commit.BlockID, untrustedHeader.Height,
untrustedHeader.Commit)
}
if err != nil {
return ErrInvalidHeader{err}
}

Expand Down Expand Up @@ -162,9 +216,15 @@ func verifyNewHeaderAndVals(
untrustedVals *types.ValidatorSet,
trustedHeader *types.SignedHeader,
now time.Time,
maxClockDrift time.Duration) error {
maxClockDrift time.Duration, isIbc bool) error {

if err := untrustedHeader.ValidateBasic(chainID); err != nil {
var err error
if isIbc {
err = untrustedHeader.ValidateBasicForIBC(chainID)
} else {
err = untrustedHeader.ValidateBasic(chainID)
}
if err != nil {
return errors.Wrap(err, "untrustedHeader.ValidateBasic failed")
}

Expand All @@ -187,7 +247,13 @@ func verifyNewHeaderAndVals(
maxClockDrift)
}

if !bytes.Equal(untrustedHeader.ValidatorsHash, untrustedVals.Hash(untrustedHeader.Height)) {
var hash []byte
if isIbc {
hash = untrustedVals.IBCHash()
} else {
hash = untrustedVals.Hash(untrustedHeader.Height)
}
if !bytes.Equal(untrustedHeader.ValidatorsHash, hash) {
return errors.Errorf("expected new header validators (%X) to match those that were supplied (%X) at height %d",
untrustedHeader.ValidatorsHash,
untrustedVals.Hash(untrustedHeader.Height),
Expand Down
13 changes: 12 additions & 1 deletion libs/tendermint/types/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,10 @@ type SignedHeader struct {
// sure to use a Verifier to validate the signatures actually provide a
// significantly strong proof for this header's validity.
func (sh SignedHeader) ValidateBasic(chainID string) error {
return sh.commonValidateBasic(chainID, false)
}

func (sh SignedHeader) commonValidateBasic(chainID string, isIbc bool) error {
if sh.Header == nil {
return errors.New("missing header")
}
Expand All @@ -1523,7 +1527,14 @@ func (sh SignedHeader) ValidateBasic(chainID string) error {
if sh.Commit.Height != sh.Height {
return fmt.Errorf("header and commit height mismatch: %d vs %d", sh.Height, sh.Commit.Height)
}
if hhash, chash := sh.Hash(), sh.Commit.BlockID.Hash; !bytes.Equal(hhash, chash) {

var hhash tmbytes.HexBytes
if isIbc {
hhash = sh.PureIBCHash()
} else {
hhash = sh.Hash()
}
if chash := sh.Commit.BlockID.Hash; !bytes.Equal(hhash, chash) {
return fmt.Errorf("commit signs block %X, header is block %X", chash, hhash)
}
return nil
Expand Down
20 changes: 20 additions & 0 deletions libs/tendermint/types/block_ibc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package types

import (
tmbytes "github.com/okex/exchain/libs/tendermint/libs/bytes"
)

func (sh SignedHeader) ValidateBasicForIBC(chainID string) error {
return sh.commonValidateBasic(chainID, true)
}

func (h *Header) PureIBCHash() tmbytes.HexBytes {
if h == nil || len(h.ValidatorsHash) == 0 {
return nil
}
return h.IBCHash()
}

func (commit *Commit) IBCVoteSignBytes(chainID string, valIdx int) []byte {
return commit.GetVote(valIdx).ibcSignBytes(chainID)
}
34 changes: 19 additions & 15 deletions libs/tendermint/types/ibc_adapter.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,21 +94,25 @@ func (c *IBCCommit) ToCommit() *Commit {

func (v *Validator) HeightBytes(h int64) []byte {
if HigherThanVenus1(h) {
pk, err := ce.PubKeyToProto(v.PubKey)
if err != nil {
panic(err)
}

pbv := tmproto.SimpleValidator{
PubKey: &pk,
VotingPower: v.VotingPower,
}

bz, err := pbv.Marshal()
if err != nil {
panic(err)
}
return bz
return v.IBCHeightBytes()
}
return v.OriginBytes()
}

func (v *Validator) IBCHeightBytes() []byte {
pk, err := ce.PubKeyToProto(v.PubKey)
if err != nil {
panic(err)
}

pbv := tmproto.SimpleValidator{
PubKey: &pk,
VotingPower: v.VotingPower,
}

bz, err := pbv.Marshal()
if err != nil {
panic(err)
}
return bz
}
Loading

0 comments on commit b7e1868

Please sign in to comment.