Browse Source

light: ensure required header fields are present for verification (#5677)

pull/5689/head
Callum Waters 4 years ago
committed by GitHub
parent
commit
68dc751a8c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 66 additions and 41 deletions
  1. +66
    -41
      light/verifier.go

+ 66
- 41
light/verifier.go View File

@ -29,6 +29,7 @@ var (
// //
// maxClockDrift defines how much untrustedHeader.Time can drift into the // maxClockDrift defines how much untrustedHeader.Time can drift into the
// future. // future.
// trustedHeader must have a ChainID, Height and Time
func VerifyNonAdjacent( func VerifyNonAdjacent(
trustedHeader *types.SignedHeader, // height=X trustedHeader *types.SignedHeader, // height=X
trustedVals *types.ValidatorSet, // height=X or height=X+1 trustedVals *types.ValidatorSet, // height=X or height=X+1
@ -39,6 +40,8 @@ func VerifyNonAdjacent(
maxClockDrift time.Duration, maxClockDrift time.Duration,
trustLevel tmmath.Fraction) error { trustLevel tmmath.Fraction) error {
checkRequiredHeaderFields(trustedHeader)
if untrustedHeader.Height == trustedHeader.Height+1 { if untrustedHeader.Height == trustedHeader.Height+1 {
return errors.New("headers must be non adjacent in height") return errors.New("headers must be non adjacent in height")
} }
@ -90,6 +93,7 @@ func VerifyNonAdjacent(
// //
// maxClockDrift defines how much untrustedHeader.Time can drift into the // maxClockDrift defines how much untrustedHeader.Time can drift into the
// future. // future.
// trustedHeader must have a ChainID, Height, Time and NextValidatorsHash
func VerifyAdjacent( func VerifyAdjacent(
trustedHeader *types.SignedHeader, // height=X trustedHeader *types.SignedHeader, // height=X
untrustedHeader *types.SignedHeader, // height=X+1 untrustedHeader *types.SignedHeader, // height=X+1
@ -98,6 +102,12 @@ func VerifyAdjacent(
now time.Time, now time.Time,
maxClockDrift time.Duration) error { maxClockDrift time.Duration) error {
checkRequiredHeaderFields(trustedHeader)
if len(trustedHeader.NextValidatorsHash) == 0 {
panic("next validators hash in trusted header is empty")
}
if untrustedHeader.Height != trustedHeader.Height+1 { if untrustedHeader.Height != trustedHeader.Height+1 {
return errors.New("headers must be adjacent in height") return errors.New("headers must be adjacent in height")
} }
@ -150,47 +160,6 @@ func Verify(
return VerifyAdjacent(trustedHeader, untrustedHeader, untrustedVals, trustingPeriod, now, maxClockDrift) return VerifyAdjacent(trustedHeader, untrustedHeader, untrustedVals, trustingPeriod, now, maxClockDrift)
} }
func verifyNewHeaderAndVals(
untrustedHeader *types.SignedHeader,
untrustedVals *types.ValidatorSet,
trustedHeader *types.SignedHeader,
now time.Time,
maxClockDrift time.Duration) error {
if err := untrustedHeader.ValidateBasic(trustedHeader.ChainID); err != nil {
return fmt.Errorf("untrustedHeader.ValidateBasic failed: %w", err)
}
if untrustedHeader.Height <= trustedHeader.Height {
return fmt.Errorf("expected new header height %d to be greater than one of old header %d",
untrustedHeader.Height,
trustedHeader.Height)
}
if !untrustedHeader.Time.After(trustedHeader.Time) {
return fmt.Errorf("expected new header time %v to be after old header time %v",
untrustedHeader.Time,
trustedHeader.Time)
}
if !untrustedHeader.Time.Before(now.Add(maxClockDrift)) {
return fmt.Errorf("new header has a time from the future %v (now: %v; max clock drift: %v)",
untrustedHeader.Time,
now,
maxClockDrift)
}
if !bytes.Equal(untrustedHeader.ValidatorsHash, untrustedVals.Hash()) {
return fmt.Errorf("expected new header validators (%X) to match those that were supplied (%X) at height %d",
untrustedHeader.ValidatorsHash,
untrustedVals.Hash(),
untrustedHeader.Height,
)
}
return nil
}
// ValidateTrustLevel checks that trustLevel is within the allowed range [1/3, // ValidateTrustLevel checks that trustLevel is within the allowed range [1/3,
// 1]. If not, it returns an error. 1/3 is the minimum amount of trust needed // 1]. If not, it returns an error. 1/3 is the minimum amount of trust needed
// which does not break the security model. // which does not break the security model.
@ -243,3 +212,59 @@ func VerifyBackwards(untrustedHeader, trustedHeader *types.Header) error {
return nil return nil
} }
func verifyNewHeaderAndVals(
untrustedHeader *types.SignedHeader,
untrustedVals *types.ValidatorSet,
trustedHeader *types.SignedHeader,
now time.Time,
maxClockDrift time.Duration) error {
if err := untrustedHeader.ValidateBasic(trustedHeader.ChainID); err != nil {
return fmt.Errorf("untrustedHeader.ValidateBasic failed: %w", err)
}
if untrustedHeader.Height <= trustedHeader.Height {
return fmt.Errorf("expected new header height %d to be greater than one of old header %d",
untrustedHeader.Height,
trustedHeader.Height)
}
if !untrustedHeader.Time.After(trustedHeader.Time) {
return fmt.Errorf("expected new header time %v to be after old header time %v",
untrustedHeader.Time,
trustedHeader.Time)
}
if !untrustedHeader.Time.Before(now.Add(maxClockDrift)) {
return fmt.Errorf("new header has a time from the future %v (now: %v; max clock drift: %v)",
untrustedHeader.Time,
now,
maxClockDrift)
}
if !bytes.Equal(untrustedHeader.ValidatorsHash, untrustedVals.Hash()) {
return fmt.Errorf("expected new header validators (%X) to match those that were supplied (%X) at height %d",
untrustedHeader.ValidatorsHash,
untrustedVals.Hash(),
untrustedHeader.Height,
)
}
return nil
}
func checkRequiredHeaderFields(h *types.SignedHeader) {
if h.Height == 0 {
panic("height in trusted header must be set (non zero")
}
zeroTime := time.Time{}
if h.Time == zeroTime {
panic("time in trusted header must be set")
}
if h.ChainID == "" {
panic("chain ID in trusted header must be set")
}
}

Loading…
Cancel
Save