mirror of
https://github.com/fluencelabs/tendermint
synced 2025-05-13 15:21:20 +00:00
NewProvider function complete
This commit is contained in:
parent
88b69a956f
commit
236cdf87aa
@ -56,19 +56,26 @@ func (p *provider) StatusClient() rpcclient.StatusClient {
|
|||||||
|
|
||||||
// LatestFullCommit implements Provider.
|
// LatestFullCommit implements Provider.
|
||||||
func (p *provider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (fc lite.FullCommit, err error) {
|
func (p *provider) LatestFullCommit(chainID string, minHeight, maxHeight int64) (fc lite.FullCommit, err error) {
|
||||||
|
// If the chain-id is wrong, error
|
||||||
if chainID != p.chainID {
|
if chainID != p.chainID {
|
||||||
err = fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID)
|
err = fmt.Errorf("expected chainID %s, got %s", p.chainID, chainID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the heights are incorrect error
|
||||||
if maxHeight != 0 && maxHeight < minHeight {
|
if maxHeight != 0 && maxHeight < minHeight {
|
||||||
err = fmt.Errorf("need maxHeight == 0 or minHeight <= maxHeight, got min %v and max %v",
|
err = fmt.Errorf("need maxHeight == 0 or minHeight <= maxHeight, got min %v and max %v",
|
||||||
minHeight, maxHeight)
|
minHeight, maxHeight)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch the latest block
|
||||||
commit, err := p.fetchLatestCommit(minHeight, maxHeight)
|
commit, err := p.fetchLatestCommit(minHeight, maxHeight)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make a lite.FullCommit out of the signed header
|
||||||
fc, err = p.fillFullCommit(commit.SignedHeader)
|
fc, err = p.fillFullCommit(commit.SignedHeader)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -38,36 +38,37 @@ func (fc FullCommit) ValidateFull(chainID string) error {
|
|||||||
if fc.Validators.Size() == 0 {
|
if fc.Validators.Size() == 0 {
|
||||||
return errors.New("need FullCommit.Validators")
|
return errors.New("need FullCommit.Validators")
|
||||||
}
|
}
|
||||||
if !bytes.Equal(
|
|
||||||
fc.SignedHeader.ValidatorsHash,
|
// If the commit ValidatorHash doesn't match the block ValidatorHash return an error
|
||||||
fc.Validators.Hash()) {
|
if !bytes.Equal(fc.SignedHeader.ValidatorsHash, fc.Validators.Hash()) {
|
||||||
return fmt.Errorf("header has vhash %X but valset hash is %X",
|
return fmt.Errorf("header has vhash %X but valset hash is %X",
|
||||||
fc.SignedHeader.ValidatorsHash,
|
fc.SignedHeader.ValidatorsHash,
|
||||||
fc.Validators.Hash(),
|
fc.Validators.Hash(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that NextValidators exists and matches the header.
|
// Ensure that NextValidators exists and matches the header.
|
||||||
if fc.NextValidators.Size() == 0 {
|
if fc.NextValidators.Size() == 0 {
|
||||||
return errors.New("need FullCommit.NextValidators")
|
return errors.New("need FullCommit.NextValidators")
|
||||||
}
|
}
|
||||||
if !bytes.Equal(
|
|
||||||
fc.SignedHeader.NextValidatorsHash,
|
// If the commit ValidatorHash doesn't match the block ValidatorHash return an error
|
||||||
fc.NextValidators.Hash()) {
|
if !bytes.Equal(fc.SignedHeader.NextValidatorsHash, fc.NextValidators.Hash()) {
|
||||||
return fmt.Errorf("header has next vhash %X but next valset hash is %X",
|
return fmt.Errorf("header has next vhash %X but next valset hash is %X",
|
||||||
fc.SignedHeader.NextValidatorsHash,
|
fc.SignedHeader.NextValidatorsHash,
|
||||||
fc.NextValidators.Hash(),
|
fc.NextValidators.Hash(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the header.
|
// Validate the header.
|
||||||
err := fc.SignedHeader.ValidateBasic(chainID)
|
err := fc.SignedHeader.ValidateBasic(chainID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the signatures on the commit.
|
// Validate the signatures on the commit.
|
||||||
hdr, cmt := fc.SignedHeader.Header, fc.SignedHeader.Commit
|
hdr, cmt := fc.SignedHeader.Header, fc.SignedHeader.Commit
|
||||||
return fc.Validators.VerifyCommit(
|
return fc.Validators.VerifyCommit(hdr.ChainID, cmt.BlockID, hdr.Height, cmt)
|
||||||
hdr.ChainID, cmt.BlockID,
|
|
||||||
hdr.Height, cmt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Height returns the height of the header.
|
// Height returns the height of the header.
|
||||||
|
@ -49,40 +49,21 @@ func NewProvider(chainID, rootDir string, client lclient.SignStatusClient, logge
|
|||||||
source := lclient.NewProvider(chainID, client)
|
source := lclient.NewProvider(chainID, client)
|
||||||
vp := makeProvider(chainID, options.TrustPeriod, trust, source)
|
vp := makeProvider(chainID, options.TrustPeriod, trust, source)
|
||||||
vp.SetLogger(logger)
|
vp.SetLogger(logger)
|
||||||
trustPeriod := options.TrustPeriod
|
|
||||||
|
|
||||||
// Get the latest trusted FC.
|
// Get the latest source commit, or the one provided in options.
|
||||||
tlfc, err := trust.LatestFullCommit(chainID, 1, 1<<63-1)
|
trustCommit, err := getTrustCommit(client, options)
|
||||||
//If there is no prior state or last state is older than the Trust Period fetch the last state.
|
if err != nil {
|
||||||
if err != nil || time.Now().Sub(tlfc.SignedHeader.Time) > options.TrustPeriod {
|
return nil, err
|
||||||
// Get the latest source commit, or the one provided in options.
|
}
|
||||||
targetCommit, err := getTargetCommit(client, options)
|
|
||||||
if err != nil {
|
err = vp.fillValidateAndSaveToTrust(trustCommit, nil, nil)
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
err = vp.fillValidateAndSaveToTrust(targetCommit, nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return vp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
if time.Now().Sub(tlfc.SignedHeader.Time) <= 0 {
|
if time.Now().Sub(trustCommit.Time) <= 0 {
|
||||||
panic(fmt.Sprintf("impossible time %v vs %v", time.Now(), tlfc.SignedHeader.Time))
|
panic(fmt.Sprintf("impossible time %v vs %v", time.Now(), trustCommit.Time))
|
||||||
}
|
|
||||||
|
|
||||||
if time.Now().Sub(tlfc.SignedHeader.Time) > trustPeriod {
|
|
||||||
// Get the latest source commit, or the one provided in options.
|
|
||||||
targetCommit, err := getTargetCommit(client, options)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = vp.fillValidateAndSaveToTrust(targetCommit, nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return vp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise we're syncing within the unbonding period.
|
// Otherwise we're syncing within the unbonding period.
|
||||||
@ -90,22 +71,26 @@ func NewProvider(chainID, rootDir string, client lclient.SignStatusClient, logge
|
|||||||
// UpdateToHeight() will fetch it again, and latestCommit isn't used), but
|
// UpdateToHeight() will fetch it again, and latestCommit isn't used), but
|
||||||
// it's only once upon initialization of a validator so it's not a big
|
// it's only once upon initialization of a validator so it's not a big
|
||||||
// deal.
|
// deal.
|
||||||
latestCommit, err := client.Commit(nil)
|
if options.TrustHeight > 0 {
|
||||||
if err != nil {
|
latestCommit, err := client.Commit(nil)
|
||||||
return nil, err
|
if err != nil {
|
||||||
}
|
return nil, err
|
||||||
err = vp.UpdateToHeight(chainID, latestCommit.SignedHeader.Height)
|
}
|
||||||
if err != nil {
|
err = vp.UpdateToHeight(chainID, latestCommit.SignedHeader.Height)
|
||||||
return nil, err
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return vp, nil
|
return vp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTragetCommit returns a commit trusted with weak subjectivity. It either:
|
// getTragetCommit returns a commit trusted with weak subjectivity. It either:
|
||||||
// 1. Fetches a commit at height provide in options and ensure the specified is within the trust period of latest
|
// 1. Fetches a commit at height provided in options and ensures the specified commit
|
||||||
|
// is within the trust period of latest block
|
||||||
// 2. Trusts the remote node and gets the latest commit
|
// 2. Trusts the remote node and gets the latest commit
|
||||||
// 3. Returns an error if the height provided in trust option is too old to sync to latest.
|
// 3. Returns an error if the height provided in trust option is too old to sync to latest.
|
||||||
func getTargetCommit(client lclient.SignStatusClient, options TrustOptions) (types.SignedHeader, error) {
|
func getTrustCommit(client lclient.SignStatusClient, options TrustOptions) (types.SignedHeader, error) {
|
||||||
|
|
||||||
// Get the lastest commit always
|
// Get the lastest commit always
|
||||||
latestBlock, err := client.Commit(nil)
|
latestBlock, err := client.Commit(nil)
|
||||||
@ -132,11 +117,11 @@ func getTargetCommit(client lclient.SignStatusClient, options TrustOptions) (typ
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
latestCommit := latestBlock.SignedHeader
|
latestCommit := latestBlock.SignedHeader
|
||||||
|
|
||||||
// NOTE: This should really belong in the callback.
|
// NOTE: This should really belong in the callback.
|
||||||
// WARN THE USER IN ALL CAPS THAT THE LITE CLIENT IS NEW,
|
// WARN THE USER IN ALL CAPS THAT THE LITE CLIENT IS NEW,
|
||||||
// AND THAT WE WILL SYNC TO AND VERIFY LATEST COMMIT.
|
// AND THAT WE WILL SYNC TO AND VERIFY LATEST COMMIT.
|
||||||
fmt.Printf("trusting source at height %v and hash %X...\n",
|
fmt.Printf("trusting source at height %v and hash %X...\n", latestCommit.Height, latestCommit.Hash())
|
||||||
latestCommit.Height, latestCommit.Hash())
|
|
||||||
if options.Callback != nil {
|
if options.Callback != nil {
|
||||||
err := options.Callback(latestCommit.Height, latestCommit.Hash())
|
err := options.Callback(latestCommit.Height, latestCommit.Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -212,12 +197,11 @@ func (vp *provider) ChainID() string {
|
|||||||
|
|
||||||
// Implements UpdatingProvider
|
// Implements UpdatingProvider
|
||||||
//
|
//
|
||||||
// On success, it will store the full commit (SignedHeader + Validators) in
|
// On success, it will store the full commit (SignedHeader + Validators) in vp.trusted
|
||||||
// vp.trusted.
|
// NOTE: For concurreent usage, use concurrentProvider
|
||||||
// NOTE: For concurreent usage, use concurrentProvider.
|
|
||||||
func (vp *provider) UpdateToHeight(chainID string, height int64) error {
|
func (vp *provider) UpdateToHeight(chainID string, height int64) error {
|
||||||
|
|
||||||
// If we alreeady have the commit, just return nil.
|
// If we alreedy have the commit, just return nil
|
||||||
_, err := vp.trusted.LatestFullCommit(vp.chainID, height, height)
|
_, err := vp.trusted.LatestFullCommit(vp.chainID, height, height)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
@ -238,28 +222,31 @@ func (vp *provider) UpdateToHeight(chainID string, height int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If valset or nextValset are nil, fetches them.
|
// If valset or nextValset are nil, fetches them.
|
||||||
// Then, validatees the full commit, then savees it.
|
// Then, validatees the full commit, then saves it.
|
||||||
func (vp *provider) fillValidateAndSaveToTrust(signedHeader types.SignedHeader, valset, nextValset *types.ValidatorSet) (err error) {
|
func (vp *provider) fillValidateAndSaveToTrust(signedHeader types.SignedHeader, valset, nextValset *types.ValidatorSet) (err error) {
|
||||||
|
|
||||||
// Get the valset.
|
// If there is no valset passed, fetch it
|
||||||
if valset != nil {
|
if valset == nil {
|
||||||
valset, err = vp.source.ValidatorSet(vp.chainID, signedHeader.Height)
|
valset, err = vp.source.ValidatorSet(vp.chainID, signedHeader.Height)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmn.ErrorWrap(err, "fetching the valset")
|
return cmn.ErrorWrap(err, "fetching the valset")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the next validator set.
|
// If there is no nextvalset passed, fetch it
|
||||||
if nextValset != nil {
|
if nextValset == nil {
|
||||||
|
// TODO: Don't loop forever, just do it 10 times
|
||||||
for {
|
for {
|
||||||
|
// fetch block at signedHeader.Height+1
|
||||||
nextValset, err = vp.source.ValidatorSet(vp.chainID, signedHeader.Height+1)
|
nextValset, err = vp.source.ValidatorSet(vp.chainID, signedHeader.Height+1)
|
||||||
if lerr.IsErrUnknownValidators(err) {
|
if lerr.IsErrUnknownValidators(err) {
|
||||||
// try again until we get it.
|
// try again until we get it.
|
||||||
fmt.Printf("fetching validatorset for height %v...\n",
|
fmt.Printf("fetching validatorset for height %v...\n", signedHeader.Height+1)
|
||||||
signedHeader.Height+1)
|
|
||||||
continue
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return cmn.ErrorWrap(err, "fetching the next valset")
|
return cmn.ErrorWrap(err, "fetching the next valset")
|
||||||
|
} else if nextValset != nil {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,16 +257,19 @@ func (vp *provider) fillValidateAndSaveToTrust(signedHeader types.SignedHeader,
|
|||||||
Validators: valset,
|
Validators: valset,
|
||||||
NextValidators: nextValset,
|
NextValidators: nextValset,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the full commit. This checks the cryptographic
|
// Validate the full commit. This checks the cryptographic
|
||||||
// signatures of Commit against Validators.
|
// signatures of Commit against Validators.
|
||||||
if err := fc.ValidateFull(vp.chainID); err != nil {
|
if err := fc.ValidateFull(vp.chainID); err != nil {
|
||||||
return cmn.ErrorWrap(err, "verifying validators from source")
|
return cmn.ErrorWrap(err, "verifying validators from source")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trust it.
|
// Trust it.
|
||||||
err = vp.trusted.SaveFullCommit(fc)
|
err = vp.trusted.SaveFullCommit(fc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cmn.ErrorWrap(err, "saving full commit")
|
return cmn.ErrorWrap(err, "saving full commit")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -290,35 +280,20 @@ func (vp *provider) fillValidateAndSaveToTrust(signedHeader types.SignedHeader,
|
|||||||
// Returns ErrCommitExpired when trustedFC is too old.
|
// Returns ErrCommitExpired when trustedFC is too old.
|
||||||
// Panics if trustedFC.Height() >= newFC.Height().
|
// Panics if trustedFC.Height() >= newFC.Height().
|
||||||
func (vp *provider) verifyAndSave(trustedFC, newFC lite.FullCommit) error {
|
func (vp *provider) verifyAndSave(trustedFC, newFC lite.FullCommit) error {
|
||||||
|
|
||||||
|
// Shouldn't have trusted commits before the new commit height
|
||||||
if trustedFC.Height() >= newFC.Height() {
|
if trustedFC.Height() >= newFC.Height() {
|
||||||
panic("should not happen")
|
panic("should not happen")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check that the latest commit isn't beyond the vp.trustPeriod
|
||||||
if vp.now().Sub(trustedFC.SignedHeader.Time) > vp.trustPeriod {
|
if vp.now().Sub(trustedFC.SignedHeader.Time) > vp.trustPeriod {
|
||||||
return lerr.ErrCommitExpired()
|
return lerr.ErrCommitExpired()
|
||||||
}
|
}
|
||||||
if trustedFC.Height() == newFC.Height()-1 {
|
|
||||||
err := trustedFC.NextValidators.VerifyCommit(
|
|
||||||
vp.chainID, newFC.SignedHeader.Commit.BlockID,
|
|
||||||
newFC.SignedHeader.Height, newFC.SignedHeader.Commit,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err := trustedFC.NextValidators.VerifyFutureCommit(
|
|
||||||
newFC.Validators,
|
|
||||||
vp.chainID, newFC.SignedHeader.Commit.BlockID,
|
|
||||||
newFC.SignedHeader.Height, newFC.SignedHeader.Commit,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if vp.now().Before(newFC.SignedHeader.Time) {
|
// If the new full commit is the next block, verify it. Otherwise use the verify future commit function
|
||||||
// TODO print warning
|
if err := trustedFC.NextValidators.VerifyCommit(vp.chainID, newFC.SignedHeader.Commit.BlockID, newFC.SignedHeader.Height, newFC.SignedHeader.Commit); err != nil {
|
||||||
// TODO if too egregious, return error.
|
return err
|
||||||
// return FullCommit{}, errors.New("now should not be before source time")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vp.trusted.SaveFullCommit(newFC)
|
return vp.trusted.SaveFullCommit(newFC)
|
||||||
@ -352,13 +327,13 @@ func (vp *provider) fetchAndVerifyToHeight(h int64) (lite.FullCommit, error) {
|
|||||||
|
|
||||||
// Verify latest FullCommit against trusted FullCommits
|
// Verify latest FullCommit against trusted FullCommits
|
||||||
// Use a loop rather than recursion to avoid stack overflows.
|
// Use a loop rather than recursion to avoid stack overflows.
|
||||||
FOR_LOOP:
|
|
||||||
for {
|
for {
|
||||||
// Fetch latest full commit from trusted.
|
// Fetch latest full commit from trusted.
|
||||||
trustedFC, err := vp.trusted.LatestFullCommit(vp.chainID, 1, h)
|
trustedFC, err := vp.trusted.LatestFullCommit(vp.chainID, 1, h)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lite.FullCommit{}, err
|
return lite.FullCommit{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have nothing to do.
|
// We have nothing to do.
|
||||||
if trustedFC.Height() == h {
|
if trustedFC.Height() == h {
|
||||||
return trustedFC, nil
|
return trustedFC, nil
|
||||||
@ -366,6 +341,7 @@ FOR_LOOP:
|
|||||||
|
|
||||||
// Update to full commit with checks.
|
// Update to full commit with checks.
|
||||||
err = vp.verifyAndSave(trustedFC, sourceFC)
|
err = vp.verifyAndSave(trustedFC, sourceFC)
|
||||||
|
|
||||||
// Handle special case when err is ErrTooMuchChange.
|
// Handle special case when err is ErrTooMuchChange.
|
||||||
if types.IsErrTooMuchChange(err) {
|
if types.IsErrTooMuchChange(err) {
|
||||||
// Divide and conquer.
|
// Divide and conquer.
|
||||||
@ -374,12 +350,15 @@ FOR_LOOP:
|
|||||||
panic("should not happen")
|
panic("should not happen")
|
||||||
}
|
}
|
||||||
mid := (start + end) / 2
|
mid := (start + end) / 2
|
||||||
|
|
||||||
|
// Recursive call back into fetchAndVerifyToHeight. Once you get to an inner
|
||||||
|
// call that succeeeds, the outer calls will succeed.
|
||||||
_, err = vp.fetchAndVerifyToHeight(mid)
|
_, err = vp.fetchAndVerifyToHeight(mid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lite.FullCommit{}, err
|
return lite.FullCommit{}, err
|
||||||
}
|
}
|
||||||
// If we made it to mid, we retry.
|
// If we made it to mid, we retry.
|
||||||
continue FOR_LOOP
|
continue
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return lite.FullCommit{}, err
|
return lite.FullCommit{}, err
|
||||||
}
|
}
|
||||||
|
@ -368,51 +368,71 @@ func (vals *ValidatorSet) Iterate(fn func(index int, val *Validator) bool) {
|
|||||||
|
|
||||||
// Verify that +2/3 of the set had signed the given signBytes.
|
// Verify that +2/3 of the set had signed the given signBytes.
|
||||||
func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height int64, commit *Commit) error {
|
func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height int64, commit *Commit) error {
|
||||||
|
|
||||||
|
// If the ValidatorSet size is different than the commit.Precommits size somthing is wrong
|
||||||
if vals.Size() != len(commit.Precommits) {
|
if vals.Size() != len(commit.Precommits) {
|
||||||
return fmt.Errorf("Invalid commit -- wrong set size: %v vs %v", vals.Size(), len(commit.Precommits))
|
return fmt.Errorf("Invalid commit -- wrong set size: %v vs %v", vals.Size(), len(commit.Precommits))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the height to check is different than the commit height return an error
|
||||||
if height != commit.Height() {
|
if height != commit.Height() {
|
||||||
return fmt.Errorf("Invalid commit -- wrong height: %v vs %v", height, commit.Height())
|
return fmt.Errorf("Invalid commit -- wrong height: %v vs %v", height, commit.Height())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the blockHash is not equal to the commit block hash return an error
|
||||||
if !blockID.Equals(commit.BlockID) {
|
if !blockID.Equals(commit.BlockID) {
|
||||||
return fmt.Errorf("Invalid commit -- wrong block id: want %v got %v",
|
return fmt.Errorf("Invalid commit -- wrong block id: want %v got %v",
|
||||||
blockID, commit.BlockID)
|
blockID, commit.BlockID)
|
||||||
}
|
}
|
||||||
|
|
||||||
talliedVotingPower := int64(0)
|
var talliedVotingPower int64
|
||||||
round := commit.Round()
|
round := commit.Round()
|
||||||
|
|
||||||
for idx, precommit := range commit.Precommits {
|
for idx, precommit := range commit.Precommits {
|
||||||
|
// Some precommits will likely be missing, skip those
|
||||||
if precommit == nil {
|
if precommit == nil {
|
||||||
continue // OK, some precommits can be missing.
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Malicous data checking for height
|
||||||
if precommit.Height != height {
|
if precommit.Height != height {
|
||||||
return fmt.Errorf("Invalid commit -- wrong height: want %v got %v", height, precommit.Height)
|
return fmt.Errorf("Invalid commit -- wrong height: want %v got %v", height, precommit.Height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Malicous data checking for round
|
||||||
if precommit.Round != round {
|
if precommit.Round != round {
|
||||||
return fmt.Errorf("Invalid commit -- wrong round: want %v got %v", round, precommit.Round)
|
return fmt.Errorf("Invalid commit -- wrong round: want %v got %v", round, precommit.Round)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Malicous data checking for precommit
|
||||||
if precommit.Type != PrecommitType {
|
if precommit.Type != PrecommitType {
|
||||||
return fmt.Errorf("Invalid commit -- not precommit @ index %v", idx)
|
return fmt.Errorf("Invalid commit -- not precommit @ index %v", idx)
|
||||||
}
|
}
|
||||||
_, val := vals.GetByIndex(idx)
|
|
||||||
// Validate signature.
|
// Validate signature.
|
||||||
precommitSignBytes := precommit.SignBytes(chainID)
|
_, val := vals.GetByAddress(precommit.ValidatorAddress)
|
||||||
if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
|
if val == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify that the valiator signed the precommit
|
||||||
|
if !val.PubKey.VerifyBytes(precommit.SignBytes(chainID), precommit.Signature) {
|
||||||
return fmt.Errorf("Invalid commit -- invalid signature: %v", precommit)
|
return fmt.Errorf("Invalid commit -- invalid signature: %v", precommit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Good precommit!
|
// Good precommit!
|
||||||
if blockID.Equals(precommit.BlockID) {
|
if blockID.Equals(precommit.BlockID) {
|
||||||
talliedVotingPower += val.VotingPower
|
talliedVotingPower += val.VotingPower
|
||||||
} else {
|
|
||||||
// It's OK that the BlockID doesn't match. We include stray
|
|
||||||
// precommits to measure validator availability.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// It's OK that the BlockID doesn't match. We include stray
|
||||||
|
// precommits to measure validator availability.
|
||||||
}
|
}
|
||||||
|
|
||||||
if talliedVotingPower > vals.TotalVotingPower()*2/3 {
|
if talliedVotingPower > vals.TotalVotingPower()*2/3 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return errTooMuchChange{talliedVotingPower, vals.TotalVotingPower()*2/3 + 1}
|
return errTooMuchChange{talliedVotingPower, vals.TotalVotingPower()*2/3 + 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,7 +454,7 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height i
|
|||||||
// > 2/3. Otherwise, the lite client isn't providing the same security
|
// > 2/3. Otherwise, the lite client isn't providing the same security
|
||||||
// guarantees.
|
// guarantees.
|
||||||
//
|
//
|
||||||
// newSet is the validator set that signed this block. Only votes from new are
|
// newVals is the validator set that signed this block. Only votes from new are
|
||||||
// sufficient for 2/3 majority in the new set as well, for it to be a valid
|
// sufficient for 2/3 majority in the new set as well, for it to be a valid
|
||||||
// commit.
|
// commit.
|
||||||
//
|
//
|
||||||
@ -444,13 +464,13 @@ func (vals *ValidatorSet) VerifyCommit(chainID string, blockID BlockID, height i
|
|||||||
// set.
|
// set.
|
||||||
//
|
//
|
||||||
// NOTE: This function is strictly more restrictive than merely checking
|
// NOTE: This function is strictly more restrictive than merely checking
|
||||||
// whether newSet.VerifyCommit(...), in fact it calls exactly that.
|
// whether newVals.VerifyCommit(...), in fact it calls exactly that.
|
||||||
func (vals *ValidatorSet) VerifyFutureCommit(newSet *ValidatorSet, chainID string,
|
func (vals *ValidatorSet) VerifyFutureCommit(newVals *ValidatorSet, chainID string,
|
||||||
blockID BlockID, height int64, commit *Commit) error {
|
blockID BlockID, height int64, commit *Commit) error {
|
||||||
oldVals := vals
|
oldVals := vals
|
||||||
|
|
||||||
// Commit must be a valid commit for newSet.
|
// Commit must be a valid commit for newVals.
|
||||||
err := newSet.VerifyCommit(chainID, blockID, height, commit)
|
err := newVals.VerifyCommit(chainID, blockID, height, commit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user