diff --git a/consensus/state.go b/consensus/state.go index b5d1461f..748c05cc 100644 --- a/consensus/state.go +++ b/consensus/state.go @@ -71,8 +71,8 @@ import ( ) const ( - roundDuration0 = 60 * time.Second // The first round is 60 seconds long. - roundDurationDelta = 15 * time.Second // Each successive round lasts 15 seconds longer. + roundDuration0 = 30 * time.Second // The first round is 60 seconds long. + roundDurationDelta = 10 * time.Second // Each successive round lasts 15 seconds longer. roundDeadlinePrevote = float64(1.0 / 3.0) // When the prevote 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. diff --git a/state/genesis.go b/state/genesis.go index b712ad38..d5590c40 100644 --- a/state/genesis.go +++ b/state/genesis.go @@ -104,14 +104,15 @@ func MakeGenesisState(db dbm.DB, genDoc *GenesisDoc) *State { validatorInfos.Save() return &State{ - DB: db, - LastBlockHeight: 0, - LastBlockHash: nil, - LastBlockParts: blk.PartSetHeader{}, - LastBlockTime: genDoc.GenesisTime, - BondedValidators: NewValidatorSet(validators), - UnbondingValidators: NewValidatorSet(nil), - accounts: accounts, - validatorInfos: validatorInfos, + DB: db, + LastBlockHeight: 0, + LastBlockHash: nil, + LastBlockParts: blk.PartSetHeader{}, + LastBlockTime: genDoc.GenesisTime, + BondedValidators: NewValidatorSet(validators), + LastBondedValidators: NewValidatorSet(nil), + UnbondingValidators: NewValidatorSet(nil), + accounts: accounts, + validatorInfos: validatorInfos, } } diff --git a/state/state.go b/state/state.go index eaba95bf..fa9cef87 100644 --- a/state/state.go +++ b/state/state.go @@ -37,15 +37,16 @@ func (txErr InvalidTxError) Error() string { // NOTE: not goroutine-safe. type State struct { - DB dbm.DB - LastBlockHeight uint - LastBlockHash []byte - LastBlockParts blk.PartSetHeader - LastBlockTime time.Time - BondedValidators *ValidatorSet - UnbondingValidators *ValidatorSet - accounts merkle.Tree // Shouldn't be accessed directly. - validatorInfos merkle.Tree // Shouldn't be accessed directly. + DB dbm.DB + LastBlockHeight uint + LastBlockHash []byte + LastBlockParts blk.PartSetHeader + LastBlockTime time.Time + BondedValidators *ValidatorSet + LastBondedValidators *ValidatorSet + UnbondingValidators *ValidatorSet + accounts merkle.Tree // Shouldn't be accessed directly. + validatorInfos merkle.Tree // Shouldn't be accessed directly. } 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.LastBlockTime = binary.ReadTime(r, n, err) 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) accountsHash := binary.ReadByteSlice(r, n, err) 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.WriteTime(s.LastBlockTime, 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.WriteByteSlice(s.accounts.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 { return &State{ - DB: s.DB, - LastBlockHeight: s.LastBlockHeight, - LastBlockHash: s.LastBlockHash, - LastBlockParts: s.LastBlockParts, - LastBlockTime: s.LastBlockTime, - BondedValidators: s.BondedValidators.Copy(), - UnbondingValidators: s.UnbondingValidators.Copy(), - accounts: s.accounts.Copy(), - validatorInfos: s.validatorInfos.Copy(), + DB: s.DB, + LastBlockHeight: s.LastBlockHeight, + LastBlockHash: s.LastBlockHash, + LastBlockParts: s.LastBlockParts, + LastBlockTime: s.LastBlockTime, + BondedValidators: s.BondedValidators.Copy(), + LastBondedValidators: s.LastBondedValidators.Copy(), + UnbondingValidators: s.UnbondingValidators.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 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! @@ -364,6 +368,12 @@ func (s *State) ExecTx(tx_ blk.Tx) error { // Verify the signatures _, 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) voteBSignBytes := account.SignBytes(&tx.VoteB) 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") } } else { - if uint(len(block.Validation.Commits)) != s.BondedValidators.Size() { - return errors.New("Invalid block validation size") + if uint(len(block.Validation.Commits)) != s.LastBondedValidators.Size() { + return errors.New(Fmt("Invalid block validation size. Expected %v, got %v", + s.LastBondedValidators.Size(), len(block.Validation.Commits))) } 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] if commit.IsZero() { return false @@ -519,32 +530,45 @@ func (s *State) AppendBlock(block *blk.Block, blockPartsHeader blk.PartSetHeader if err != nil { return err } - if sumVotingPower <= s.BondedValidators.TotalVotingPower()*2/3 { + if sumVotingPower <= s.LastBondedValidators.TotalVotingPower()*2/3 { 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. for i, commit := range block.Validation.Commits { if commit.IsZero() { continue } - _, val := s.BondedValidators.GetByIndex(uint(i)) + _, val := s.LastBondedValidators.GetByIndex(uint(i)) if val == nil { panic(Fmt("Failed to fetch validator at index %v", i)) } - val.LastCommitHeight = block.Height - 1 - updated := s.BondedValidators.Update(val) - if !updated { - panic("Failed to update validator LastCommitHeight") + if _, val_ := s.BondedValidators.GetByAddress(val.Address); val_ != nil { + val_.LastCommitHeight = block.Height - 1 + updated := s.BondedValidators.Update(val_) + 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} } }