Validation validation bug fix --> keep track of LastBondedValidators

This commit is contained in:
Jae Kwon 2015-01-16 02:18:49 -08:00
parent b3b6a24317
commit d1a36d2ac2
3 changed files with 72 additions and 47 deletions

View File

@ -71,8 +71,8 @@ import (
) )
const ( const (
roundDuration0 = 60 * time.Second // The first round is 60 seconds long. roundDuration0 = 30 * time.Second // The first round is 60 seconds long.
roundDurationDelta = 15 * time.Second // Each successive round lasts 15 seconds longer. roundDurationDelta = 10 * time.Second // Each successive round lasts 15 seconds longer.
roundDeadlinePrevote = float64(1.0 / 3.0) // When the prevote is due. roundDeadlinePrevote = float64(1.0 / 3.0) // When the prevote is due.
roundDeadlinePrecommit = float64(2.0 / 3.0) // When the precommit vote is due. roundDeadlinePrecommit = float64(2.0 / 3.0) // When the precommit vote is due.
newHeightDelta = roundDuration0 / 3 // The time to wait between commitTime and startTime of next consensus rounds. newHeightDelta = roundDuration0 / 3 // The time to wait between commitTime and startTime of next consensus rounds.

View File

@ -104,14 +104,15 @@ func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State {
validatorInfos.Save() validatorInfos.Save()
return &State{ return &State{
DB: db, DB: db,
LastBlockHeight: 0, LastBlockHeight: 0,
LastBlockHash: nil, LastBlockHash: nil,
LastBlockParts: blk.PartSetHeader{}, LastBlockParts: blk.PartSetHeader{},
LastBlockTime: genDoc.GenesisTime, LastBlockTime: genDoc.GenesisTime,
BondedValidators: NewValidatorSet(validators), BondedValidators: NewValidatorSet(validators),
UnbondingValidators: NewValidatorSet(nil), LastBondedValidators: NewValidatorSet(nil),
accounts: accounts, UnbondingValidators: NewValidatorSet(nil),
validatorInfos: validatorInfos, accounts: accounts,
validatorInfos: validatorInfos,
} }
} }

View File

@ -37,15 +37,16 @@ func (txErr InvalidTxError) Error() string {
// NOTE: not goroutine-safe. // NOTE: not goroutine-safe.
type State struct { type State struct {
DB dbm.DB DB dbm.DB
LastBlockHeight uint LastBlockHeight uint
LastBlockHash []byte LastBlockHash []byte
LastBlockParts blk.PartSetHeader LastBlockParts blk.PartSetHeader
LastBlockTime time.Time LastBlockTime time.Time
BondedValidators *ValidatorSet BondedValidators *ValidatorSet
UnbondingValidators *ValidatorSet LastBondedValidators *ValidatorSet
accounts merkle.Tree // Shouldn't be accessed directly. UnbondingValidators *ValidatorSet
validatorInfos merkle.Tree // Shouldn't be accessed directly. accounts merkle.Tree // Shouldn't be accessed directly.
validatorInfos merkle.Tree // Shouldn't be accessed directly.
} }
func LoadState(db dbm.DB) *State { func LoadState(db dbm.DB) *State {
@ -60,6 +61,7 @@ func LoadState(db dbm.DB) *State {
s.LastBlockParts = binary.ReadBinary(blk.PartSetHeader{}, r, n, err).(blk.PartSetHeader) s.LastBlockParts = binary.ReadBinary(blk.PartSetHeader{}, r, n, err).(blk.PartSetHeader)
s.LastBlockTime = binary.ReadTime(r, n, err) s.LastBlockTime = binary.ReadTime(r, n, err)
s.BondedValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet) s.BondedValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet)
s.LastBondedValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet)
s.UnbondingValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet) s.UnbondingValidators = binary.ReadBinary(&ValidatorSet{}, r, n, err).(*ValidatorSet)
accountsHash := binary.ReadByteSlice(r, n, err) accountsHash := binary.ReadByteSlice(r, n, err)
s.accounts = merkle.NewIAVLTree(binary.BasicCodec, account.AccountCodec, defaultAccountsCacheCapacity, db) s.accounts = merkle.NewIAVLTree(binary.BasicCodec, account.AccountCodec, defaultAccountsCacheCapacity, db)
@ -85,6 +87,7 @@ func (s *State) Save() {
binary.WriteBinary(s.LastBlockParts, buf, n, err) binary.WriteBinary(s.LastBlockParts, buf, n, err)
binary.WriteTime(s.LastBlockTime, buf, n, err) binary.WriteTime(s.LastBlockTime, buf, n, err)
binary.WriteBinary(s.BondedValidators, buf, n, err) binary.WriteBinary(s.BondedValidators, buf, n, err)
binary.WriteBinary(s.LastBondedValidators, buf, n, err)
binary.WriteBinary(s.UnbondingValidators, buf, n, err) binary.WriteBinary(s.UnbondingValidators, buf, n, err)
binary.WriteByteSlice(s.accounts.Hash(), buf, n, err) binary.WriteByteSlice(s.accounts.Hash(), buf, n, err)
binary.WriteByteSlice(s.validatorInfos.Hash(), buf, n, err) binary.WriteByteSlice(s.validatorInfos.Hash(), buf, n, err)
@ -96,15 +99,16 @@ func (s *State) Save() {
func (s *State) Copy() *State { func (s *State) Copy() *State {
return &State{ return &State{
DB: s.DB, DB: s.DB,
LastBlockHeight: s.LastBlockHeight, LastBlockHeight: s.LastBlockHeight,
LastBlockHash: s.LastBlockHash, LastBlockHash: s.LastBlockHash,
LastBlockParts: s.LastBlockParts, LastBlockParts: s.LastBlockParts,
LastBlockTime: s.LastBlockTime, LastBlockTime: s.LastBlockTime,
BondedValidators: s.BondedValidators.Copy(), BondedValidators: s.BondedValidators.Copy(),
UnbondingValidators: s.UnbondingValidators.Copy(), LastBondedValidators: s.LastBondedValidators.Copy(),
accounts: s.accounts.Copy(), UnbondingValidators: s.UnbondingValidators.Copy(),
validatorInfos: s.validatorInfos.Copy(), accounts: s.accounts.Copy(),
validatorInfos: s.validatorInfos.Copy(),
} }
} }
@ -352,7 +356,7 @@ func (s *State) ExecTx(tx_ blk.Tx) error {
// tx.Height must be equal to the next height // tx.Height must be equal to the next height
if tx.Height != s.LastBlockHeight+1 { if tx.Height != s.LastBlockHeight+1 {
return errors.New("Invalid rebond height") return errors.New(Fmt("Invalid rebond height. Expected %v, got %v", s.LastBlockHeight+1, tx.Height))
} }
// Good! // Good!
@ -364,6 +368,12 @@ func (s *State) ExecTx(tx_ blk.Tx) error {
// Verify the signatures // Verify the signatures
_, accused := s.BondedValidators.GetByAddress(tx.Address) _, accused := s.BondedValidators.GetByAddress(tx.Address)
if accused == nil {
_, accused = s.UnbondingValidators.GetByAddress(tx.Address)
if accused == nil {
return blk.ErrTxInvalidAddress
}
}
voteASignBytes := account.SignBytes(&tx.VoteA) voteASignBytes := account.SignBytes(&tx.VoteA)
voteBSignBytes := account.SignBytes(&tx.VoteB) voteBSignBytes := account.SignBytes(&tx.VoteB)
if !accused.PubKey.VerifyBytes(voteASignBytes, tx.VoteA.Signature) || if !accused.PubKey.VerifyBytes(voteASignBytes, tx.VoteA.Signature) ||
@ -490,11 +500,12 @@ func (s *State) AppendBlock(block *blk.Block, blockPartsHeader blk.PartSetHeader
return errors.New("Block at height 1 (first block) should have no Validation commits") return errors.New("Block at height 1 (first block) should have no Validation commits")
} }
} else { } else {
if uint(len(block.Validation.Commits)) != s.BondedValidators.Size() { if uint(len(block.Validation.Commits)) != s.LastBondedValidators.Size() {
return errors.New("Invalid block validation size") return errors.New(Fmt("Invalid block validation size. Expected %v, got %v",
s.LastBondedValidators.Size(), len(block.Validation.Commits)))
} }
var sumVotingPower uint64 var sumVotingPower uint64
s.BondedValidators.Iterate(func(index uint, val *Validator) bool { s.LastBondedValidators.Iterate(func(index uint, val *Validator) bool {
commit := block.Validation.Commits[index] commit := block.Validation.Commits[index]
if commit.IsZero() { if commit.IsZero() {
return false return false
@ -519,32 +530,45 @@ func (s *State) AppendBlock(block *blk.Block, blockPartsHeader blk.PartSetHeader
if err != nil { if err != nil {
return err return err
} }
if sumVotingPower <= s.BondedValidators.TotalVotingPower()*2/3 { if sumVotingPower <= s.LastBondedValidators.TotalVotingPower()*2/3 {
return errors.New("Insufficient validation voting power") return errors.New("Insufficient validation voting power")
} }
} }
// Commit each tx
for _, tx := range block.Data.Txs {
err := s.ExecTx(tx)
if err != nil {
return InvalidTxError{tx, err}
}
}
// Update Validator.LastCommitHeight as necessary. // Update Validator.LastCommitHeight as necessary.
for i, commit := range block.Validation.Commits { for i, commit := range block.Validation.Commits {
if commit.IsZero() { if commit.IsZero() {
continue continue
} }
_, val := s.BondedValidators.GetByIndex(uint(i)) _, val := s.LastBondedValidators.GetByIndex(uint(i))
if val == nil { if val == nil {
panic(Fmt("Failed to fetch validator at index %v", i)) panic(Fmt("Failed to fetch validator at index %v", i))
} }
val.LastCommitHeight = block.Height - 1 if _, val_ := s.BondedValidators.GetByAddress(val.Address); val_ != nil {
updated := s.BondedValidators.Update(val) val_.LastCommitHeight = block.Height - 1
if !updated { updated := s.BondedValidators.Update(val_)
panic("Failed to update validator LastCommitHeight") if !updated {
panic("Failed to update bonded validator LastCommitHeight")
}
} else if _, val_ := s.UnbondingValidators.GetByAddress(val.Address); val_ != nil {
val_.LastCommitHeight = block.Height - 1
updated := s.UnbondingValidators.Update(val_)
if !updated {
panic("Failed to update unbonding validator LastCommitHeight")
}
} else {
panic("Could not find validator")
}
}
// Remember LastBondedValidators
s.LastBondedValidators = s.BondedValidators.Copy()
// Commit each tx
for _, tx := range block.Data.Txs {
err := s.ExecTx(tx)
if err != nil {
return InvalidTxError{tx, err}
} }
} }