package lite
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
// FullCommit is a signed header (the block header and a commit that signs it),
|
|
// the validator set which signed the commit, and the next validator set. The
|
|
// next validator set (which is proven from the block header) allows us to
|
|
// revert to block-by-block updating of lite certifier's latest validator set,
|
|
// even in the face of arbitrarily large power changes.
|
|
type FullCommit struct {
|
|
SignedHeader types.SignedHeader `json:"signed_header"`
|
|
Validators *types.ValidatorSet `json:"validator_set"`
|
|
NextValidators *types.ValidatorSet `json:"next_validator_set"`
|
|
}
|
|
|
|
// NewFullCommit returns a new FullCommit.
|
|
func NewFullCommit(signedHeader types.SignedHeader, valset, nextValset *types.ValidatorSet) FullCommit {
|
|
return FullCommit{
|
|
SignedHeader: signedHeader,
|
|
Validators: valset,
|
|
NextValidators: nextValset,
|
|
}
|
|
}
|
|
|
|
// Validate the components and check for consistency.
|
|
// This also checks to make sure that Validators actually
|
|
// signed the SignedHeader.Commit.
|
|
// If > 2/3 did not sign the Commit from fc.Validators, it
|
|
// is not a valid commit!
|
|
func (fc FullCommit) ValidateFull(chainID string) error {
|
|
// Ensure that Validators exists and matches the header.
|
|
if fc.Validators.Size() == 0 {
|
|
return errors.New("need FullCommit.Validators")
|
|
}
|
|
if !bytes.Equal(
|
|
fc.SignedHeader.ValidatorsHash,
|
|
fc.Validators.Hash()) {
|
|
return fmt.Errorf("header has vhash %X but valset hash is %X",
|
|
fc.SignedHeader.ValidatorsHash,
|
|
fc.Validators.Hash(),
|
|
)
|
|
}
|
|
// Ensure that NextValidators exists and matches the header.
|
|
if fc.NextValidators.Size() == 0 {
|
|
return errors.New("need FullCommit.NextValidators")
|
|
}
|
|
if !bytes.Equal(
|
|
fc.SignedHeader.NextValidatorsHash,
|
|
fc.NextValidators.Hash()) {
|
|
return fmt.Errorf("header has next vhash %X but next valset hash is %X",
|
|
fc.SignedHeader.NextValidatorsHash,
|
|
fc.NextValidators.Hash(),
|
|
)
|
|
}
|
|
// Validate the header.
|
|
err := fc.SignedHeader.ValidateBasic(chainID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// Validate the signatures on the commit.
|
|
hdr, cmt := fc.SignedHeader.Header, fc.SignedHeader.Commit
|
|
err = fc.Validators.VerifyCommit(
|
|
hdr.ChainID, cmt.BlockID,
|
|
hdr.Height, cmt)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// All good!
|
|
return nil
|
|
}
|
|
|
|
// Height returns the height of the header.
|
|
func (fc FullCommit) Height() int64 {
|
|
if fc.SignedHeader.Header == nil {
|
|
panic("should not happen")
|
|
}
|
|
return fc.SignedHeader.Height
|
|
}
|
|
|
|
// ChainID returns the chainID of the header.
|
|
func (fc FullCommit) ChainID() string {
|
|
if fc.SignedHeader.Header == nil {
|
|
panic("should not happen")
|
|
}
|
|
return fc.SignedHeader.ChainID
|
|
}
|