Browse Source

Re-use ValidatorSet.VerifyValidation()

pull/96/head
Jae Kwon 10 years ago
parent
commit
829df93577
4 changed files with 59 additions and 60 deletions
  1. +2
    -2
      blockchain/reactor.go
  2. +9
    -33
      state/execution.go
  3. +29
    -23
      state/validator_set.go
  4. +19
    -2
      types/block.go

+ 2
- 2
blockchain/reactor.go View File

@ -232,7 +232,7 @@ FOR_LOOP:
firstPartsHeader := firstParts.Header()
// Finally, verify the first block using the second's validation.
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 {
log.Debug("error in validation", "error", err)
bcR.pool.RedoRequest(first.Height)
@ -244,7 +244,7 @@ FOR_LOOP:
// TODO This is bad, are we zombie?
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()
}
}


+ 9
- 33
state/execution.go View File

@ -38,50 +38,26 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade
return err
}
// Validate block Validation.
// Validate block LastValidation.
if block.Height == 1 {
if len(block.Validation.Precommits) != 0 {
return errors.New("Block at height 1 (first block) should have no Validation precommits")
if len(block.LastValidation.Precommits) != 0 {
return errors.New("Block at height 1 (first block) should have no LastValidation precommits")
}
} 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",
s.LastBondedValidators.Size(), len(block.Validation.Precommits)))
s.LastBondedValidators.Size(), len(block.LastValidation.Precommits)))
}
var sumVotingPower uint64
s.LastBondedValidators.Iterate(func(index uint, val *Validator) bool {
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
}
}
})
err := s.LastBondedValidators.VerifyValidation(
s.ChainID, s.LastBlockHash, s.LastBlockParts, block.Height-1, block.LastValidation)
if err != nil {
return err
}
if sumVotingPower <= s.LastBondedValidators.TotalVotingPower()*2/3 {
return errors.New("Insufficient validation voting power")
}
}
// Update Validator.LastCommitHeight as necessary.
for i, precommit := range block.Validation.Precommits {
if precommit.IsZero() {
for i, precommit := range block.LastValidation.Precommits {
if precommit == nil {
continue
}
_, val := s.LastBondedValidators.GetByIndex(uint(i))


+ 29
- 23
state/validator_set.go View File

@ -2,7 +2,6 @@ package state
import (
"bytes"
"errors"
"fmt"
"sort"
"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
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)) {
return errors.New(Fmt("Invalid validation -- wrong set size: %v vs %v",
valSet.Size(), len(v.Precommits)))
return fmt.Errorf("Invalid validation -- wrong set size: %v vs %v", 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)
seenValidators := map[string]struct{}{}
round := v.Round()
for idx, precommit := range v.Precommits {
// may be zero, in which case skip.
if precommit.Signature.IsZero() {
// may be nil if validator skipped.
if precommit == nil {
continue
}
_, val := valSet.GetByIndex(uint(idx))
precommitSignBytes := account.SignBytes(chainID, &types.Vote{
Height: height, Round: v.Round, Type: types.VoteTypePrecommit,
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 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))
// Validate signature
precommitSignBytes := account.SignBytes(chainID, precommit)
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)
}
// Tally
seenValidators[string(val.Address)] = struct{}{}
if !bytes.Equal(precommit.BlockHash, hash) {
continue // Not an error, but doesn't count
}
if !parts.Equals(precommit.BlockParts) {
continue // Not an error, but doesn't count
}
// Good precommit!
talliedVotingPower += val.VotingPower
}
if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
return nil
} 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))
}
}


+ 19
- 2
types/block.go View File

@ -206,7 +206,24 @@ func (v *Validation) ValidateBasic() error {
if len(v.Precommits) == 0 {
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
}
@ -241,7 +258,7 @@ func (v *Validation) BitArray() *BitArray {
if v.bitArray == nil {
v.bitArray = NewBitArray(uint(len(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


Loading…
Cancel
Save