mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
Re-use ValidatorSet.VerifyValidation()
This commit is contained in:
parent
7752405945
commit
829df93577
@ -232,7 +232,7 @@ FOR_LOOP:
|
|||||||
firstPartsHeader := firstParts.Header()
|
firstPartsHeader := firstParts.Header()
|
||||||
// Finally, verify the first block using the second's validation.
|
// Finally, verify the first block using the second's validation.
|
||||||
err := bcR.state.BondedValidators.VerifyValidation(
|
err := bcR.state.BondedValidators.VerifyValidation(
|
||||||
bcR.state.ChainID, first.Hash(), firstPartsHeader, first.Height, second.Validation)
|
bcR.state.ChainID, first.Hash(), firstPartsHeader, first.Height, second.LastValidation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error in validation", "error", err)
|
log.Debug("error in validation", "error", err)
|
||||||
bcR.pool.RedoRequest(first.Height)
|
bcR.pool.RedoRequest(first.Height)
|
||||||
@ -244,7 +244,7 @@ FOR_LOOP:
|
|||||||
// TODO This is bad, are we zombie?
|
// TODO This is bad, are we zombie?
|
||||||
panic(Fmt("Failed to process committed block: %v", err))
|
panic(Fmt("Failed to process committed block: %v", err))
|
||||||
}
|
}
|
||||||
bcR.store.SaveBlock(first, firstParts, second.Validation)
|
bcR.store.SaveBlock(first, firstParts, second.LastValidation)
|
||||||
bcR.state.Save()
|
bcR.state.Save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,50 +38,26 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate block Validation.
|
// Validate block LastValidation.
|
||||||
if block.Height == 1 {
|
if block.Height == 1 {
|
||||||
if len(block.Validation.Precommits) != 0 {
|
if len(block.LastValidation.Precommits) != 0 {
|
||||||
return errors.New("Block at height 1 (first block) should have no Validation precommits")
|
return errors.New("Block at height 1 (first block) should have no LastValidation precommits")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if uint(len(block.Validation.Precommits)) != s.LastBondedValidators.Size() {
|
if uint(len(block.LastValidation.Precommits)) != s.LastBondedValidators.Size() {
|
||||||
return errors.New(Fmt("Invalid block validation size. Expected %v, got %v",
|
return errors.New(Fmt("Invalid block validation size. Expected %v, got %v",
|
||||||
s.LastBondedValidators.Size(), len(block.Validation.Precommits)))
|
s.LastBondedValidators.Size(), len(block.LastValidation.Precommits)))
|
||||||
}
|
}
|
||||||
var sumVotingPower uint64
|
err := s.LastBondedValidators.VerifyValidation(
|
||||||
s.LastBondedValidators.Iterate(func(index uint, val *Validator) bool {
|
s.ChainID, s.LastBlockHash, s.LastBlockParts, block.Height-1, block.LastValidation)
|
||||||
precommit := block.Validation.Precommits[index]
|
|
||||||
if precommit.IsZero() {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
vote := &types.Vote{
|
|
||||||
Height: block.Height - 1,
|
|
||||||
Round: block.Validation.Round,
|
|
||||||
Type: types.VoteTypePrecommit,
|
|
||||||
BlockHash: block.LastBlockHash,
|
|
||||||
BlockParts: block.LastBlockParts,
|
|
||||||
}
|
|
||||||
if val.PubKey.VerifyBytes(account.SignBytes(s.ChainID, vote), precommit.Signature) {
|
|
||||||
sumVotingPower += val.VotingPower
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
log.Warn(Fmt("Invalid validation signature.\nval: %v\nvote: %v", val, vote))
|
|
||||||
err = errors.New("Invalid validation signature")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if sumVotingPower <= s.LastBondedValidators.TotalVotingPower()*2/3 {
|
|
||||||
return errors.New("Insufficient validation voting power")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Validator.LastCommitHeight as necessary.
|
// Update Validator.LastCommitHeight as necessary.
|
||||||
for i, precommit := range block.Validation.Precommits {
|
for i, precommit := range block.LastValidation.Precommits {
|
||||||
if precommit.IsZero() {
|
if precommit == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, val := s.LastBondedValidators.GetByIndex(uint(i))
|
_, val := s.LastBondedValidators.GetByIndex(uint(i))
|
||||||
|
@ -2,7 +2,6 @@ package state
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@ -201,45 +200,52 @@ func (valSet *ValidatorSet) Iterate(fn func(index uint, 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 (valSet *ValidatorSet) VerifyValidation(chainID string, hash []byte, parts types.PartSetHeader, height uint, v *types.Validation) error {
|
func (valSet *ValidatorSet) VerifyValidation(chainID string,
|
||||||
|
hash []byte, parts types.PartSetHeader, height uint, v *types.Validation) error {
|
||||||
if valSet.Size() != uint(len(v.Precommits)) {
|
if valSet.Size() != uint(len(v.Precommits)) {
|
||||||
return errors.New(Fmt("Invalid validation -- wrong set size: %v vs %v",
|
return fmt.Errorf("Invalid validation -- wrong set size: %v vs %v", valSet.Size(), len(v.Precommits))
|
||||||
valSet.Size(), len(v.Precommits)))
|
}
|
||||||
|
if height != v.Height() {
|
||||||
|
return fmt.Errorf("Invalid validation -- wrong height: %v vs %v", height, v.Height())
|
||||||
}
|
}
|
||||||
|
|
||||||
talliedVotingPower := uint64(0)
|
talliedVotingPower := uint64(0)
|
||||||
seenValidators := map[string]struct{}{}
|
round := v.Round()
|
||||||
|
|
||||||
for idx, precommit := range v.Precommits {
|
for idx, precommit := range v.Precommits {
|
||||||
// may be zero, in which case skip.
|
// may be nil if validator skipped.
|
||||||
if precommit.Signature.IsZero() {
|
if precommit == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if precommit.Height != height {
|
||||||
|
return fmt.Errorf("Invalid validation -- wrong height: %v vs %v", height, precommit.Height)
|
||||||
|
}
|
||||||
|
if precommit.Round != round {
|
||||||
|
return fmt.Errorf("Invalid validation -- wrong round: %v vs %v", round, precommit.Round)
|
||||||
|
}
|
||||||
|
if precommit.Type != types.VoteTypePrecommit {
|
||||||
|
return fmt.Errorf("Invalid validation -- not precommit @ index %v", idx)
|
||||||
|
}
|
||||||
_, val := valSet.GetByIndex(uint(idx))
|
_, val := valSet.GetByIndex(uint(idx))
|
||||||
precommitSignBytes := account.SignBytes(chainID, &types.Vote{
|
// Validate signature
|
||||||
Height: height, Round: v.Round, Type: types.VoteTypePrecommit,
|
precommitSignBytes := account.SignBytes(chainID, precommit)
|
||||||
BlockHash: hash,
|
|
||||||
BlockParts: parts,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Validate
|
|
||||||
if _, seen := seenValidators[string(val.Address)]; seen {
|
|
||||||
return fmt.Errorf("Duplicate validator for precommit %v for Validation %v", precommit, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
|
if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
|
||||||
return fmt.Errorf("Invalid signature for precommit %v for Validation %v", precommit, v)
|
return fmt.Errorf("Invalid validation -- invalid signature: %v", precommit)
|
||||||
}
|
}
|
||||||
|
if !bytes.Equal(precommit.BlockHash, hash) {
|
||||||
// Tally
|
continue // Not an error, but doesn't count
|
||||||
seenValidators[string(val.Address)] = struct{}{}
|
}
|
||||||
|
if !parts.Equals(precommit.BlockParts) {
|
||||||
|
continue // Not an error, but doesn't count
|
||||||
|
}
|
||||||
|
// Good precommit!
|
||||||
talliedVotingPower += val.VotingPower
|
talliedVotingPower += val.VotingPower
|
||||||
}
|
}
|
||||||
|
|
||||||
if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
|
if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("insufficient voting power %v, needed %v",
|
return fmt.Errorf("Invalid validation -- insufficient voting power: got %v, needed %v",
|
||||||
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
|
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,24 @@ func (v *Validation) ValidateBasic() error {
|
|||||||
if len(v.Precommits) == 0 {
|
if len(v.Precommits) == 0 {
|
||||||
return errors.New("No precommits in validation")
|
return errors.New("No precommits in validation")
|
||||||
}
|
}
|
||||||
// TODO Additional validation?
|
height, round := v.Height(), v.Round()
|
||||||
|
for _, precommit := range v.Precommits {
|
||||||
|
// Ensure that all votes are precommits
|
||||||
|
if precommit.Type != VoteTypePrecommit {
|
||||||
|
return fmt.Errorf("Invalid validation vote. Expected precommit, got %v",
|
||||||
|
precommit.Type)
|
||||||
|
}
|
||||||
|
// Ensure that all heights are the same
|
||||||
|
if precommit.Height != height {
|
||||||
|
return fmt.Errorf("Invalid validation precommit height. Expected %v, got %v",
|
||||||
|
height, precommit.Height)
|
||||||
|
}
|
||||||
|
// Ensure that all rounds are the same
|
||||||
|
if precommit.Round != round {
|
||||||
|
return fmt.Errorf("Invalid validation precommit round. Expected %v, got %v",
|
||||||
|
round, precommit.Round)
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,7 +258,7 @@ func (v *Validation) BitArray() *BitArray {
|
|||||||
if v.bitArray == nil {
|
if v.bitArray == nil {
|
||||||
v.bitArray = NewBitArray(uint(len(v.Precommits)))
|
v.bitArray = NewBitArray(uint(len(v.Precommits)))
|
||||||
for i, precommit := range v.Precommits {
|
for i, precommit := range v.Precommits {
|
||||||
v.bitArray.SetIndex(uint(i), !precommit.IsZero())
|
v.bitArray.SetIndex(uint(i), precommit != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return v.bitArray
|
return v.bitArray
|
||||||
|
Loading…
x
Reference in New Issue
Block a user