remove privValIndex; Stale->AppHashIsStale

This commit is contained in:
Ethan Buchman
2016-12-02 00:12:06 -05:00
parent 3e7c7f51fa
commit 0fe53dc5cf
4 changed files with 24 additions and 48 deletions

View File

@ -111,7 +111,6 @@ func (conR *ConsensusReactor) GetChannels() []*p2p.ChannelDescriptor {
// Implements Reactor // Implements Reactor
func (conR *ConsensusReactor) AddPeer(peer *p2p.Peer) { func (conR *ConsensusReactor) AddPeer(peer *p2p.Peer) {
log.Info("ADDING PEER")
if !conR.IsRunning() { if !conR.IsRunning() {
return return
} }

View File

@ -226,8 +226,7 @@ type ConsensusState struct {
blockStore *bc.BlockStore blockStore *bc.BlockStore
mempool *mempl.Mempool mempool *mempl.Mempool
privValidator PrivValidator // for signing votes privValidator PrivValidator // for signing votes
privValidatorIndex int // cached index; updated if validators added/removed to validator set
mtx sync.Mutex mtx sync.Mutex
RoundState RoundState
@ -320,7 +319,6 @@ func (cs *ConsensusState) SetPrivValidator(priv PrivValidator) {
cs.mtx.Lock() cs.mtx.Lock()
defer cs.mtx.Unlock() defer cs.mtx.Unlock()
cs.privValidator = priv cs.privValidator = priv
cs.setPrivValidatorIndex()
} }
func (cs *ConsensusState) LoadCommit(height int) *types.Commit { func (cs *ConsensusState) LoadCommit(height int) *types.Commit {
@ -579,26 +577,10 @@ func (cs *ConsensusState) updateToState(state *sm.State) {
cs.state = state cs.state = state
if cs.state.ValidatorAddedOrRemoved() {
cs.setPrivValidatorIndex()
}
// Finally, broadcast RoundState // Finally, broadcast RoundState
cs.newStep() cs.newStep()
} }
func (cs *ConsensusState) setPrivValidatorIndex() {
if cs.privValidator != nil {
// TODO: just return -1 for not found
valIdx, val := cs.state.Validators.GetByAddress(cs.privValidator.GetAddress())
if val == nil {
cs.privValidatorIndex = -1
} else {
cs.privValidatorIndex = valIdx
}
}
}
func (cs *ConsensusState) newStep() { func (cs *ConsensusState) newStep() {
rs := cs.RoundStateEvent() rs := cs.RoundStateEvent()
cs.wal.Save(rs) cs.wal.Save(rs)
@ -1520,9 +1502,11 @@ func (cs *ConsensusState) addVote(vote *types.Vote, peerKey string) (added bool,
} }
func (cs *ConsensusState) signVote(type_ byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) { func (cs *ConsensusState) signVote(type_ byte, hash []byte, header types.PartSetHeader) (*types.Vote, error) {
addr := cs.privValidator.GetAddress()
valIndex, _ := cs.Validators.GetByAddress(addr)
vote := &types.Vote{ vote := &types.Vote{
ValidatorAddress: cs.privValidator.GetAddress(), ValidatorAddress: addr,
ValidatorIndex: cs.privValidatorIndex, ValidatorIndex: valIndex,
Height: cs.Height, Height: cs.Height,
Round: cs.Round, Round: cs.Round,
Type: type_, Type: type_,
@ -1535,7 +1519,7 @@ func (cs *ConsensusState) signVote(type_ byte, hash []byte, header types.PartSet
// sign the vote and publish on internalMsgQueue // sign the vote and publish on internalMsgQueue
func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.PartSetHeader) *types.Vote { func (cs *ConsensusState) signAddVote(type_ byte, hash []byte, header types.PartSetHeader) *types.Vote {
// if we don't have a key or we're not in the validator set, do nothing // if we don't have a key or we're not in the validator set, do nothing
if cs.privValidator == nil || cs.privValidatorIndex < 0 { if cs.privValidator == nil || !cs.Validators.HasAddress(cs.privValidator.GetAddress()) {
return nil return nil
} }
vote, err := cs.signVote(type_, hash, header) vote, err := cs.signVote(type_, hash, header)

View File

@ -43,7 +43,7 @@ func (s *State) ExecBlock(eventCache types.Fireable, proxyAppConn proxy.AppConnC
} }
// update the validator set // update the validator set
s.valAddedOrRemoved, err = updateValidators(nextValSet, changedValidators) err = updateValidators(nextValSet, changedValidators)
if err != nil { if err != nil {
log.Warn("Error changing validator set", "error", err) log.Warn("Error changing validator set", "error", err)
// TODO: err or carry on? // TODO: err or carry on?
@ -135,22 +135,20 @@ func execBlockOnProxyApp(eventCache types.Fireable, proxyAppConn proxy.AppConnCo
return changedValidators, nil return changedValidators, nil
} }
func updateValidators(validators *types.ValidatorSet, changedValidators []*tmsp.Validator) (bool, error) { func updateValidators(validators *types.ValidatorSet, changedValidators []*tmsp.Validator) error {
// TODO: prevent change of 1/3+ at once // TODO: prevent change of 1/3+ at once
var addedOrRemoved bool
for _, v := range changedValidators { for _, v := range changedValidators {
pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-wire encoded pubkey pubkey, err := crypto.PubKeyFromBytes(v.PubKey) // NOTE: expects go-wire encoded pubkey
if err != nil { if err != nil {
return false, err return err
} }
address := pubkey.Address() address := pubkey.Address()
power := int64(v.Power) power := int64(v.Power)
// mind the overflow from uint64 // mind the overflow from uint64
if power < 0 { if power < 0 {
return false, errors.New(Fmt("Power (%d) overflows int64", v.Power)) return errors.New(Fmt("Power (%d) overflows int64", v.Power))
} }
_, val := validators.GetByAddress(address) _, val := validators.GetByAddress(address)
@ -158,26 +156,24 @@ func updateValidators(validators *types.ValidatorSet, changedValidators []*tmsp.
// add val // add val
added := validators.Add(types.NewValidator(pubkey, power)) added := validators.Add(types.NewValidator(pubkey, power))
if !added { if !added {
return false, errors.New(Fmt("Failed to add new validator %X with voting power %d", address, power)) return errors.New(Fmt("Failed to add new validator %X with voting power %d", address, power))
} }
addedOrRemoved = true
} else if v.Power == 0 { } else if v.Power == 0 {
// remove val // remove val
_, removed := validators.Remove(address) _, removed := validators.Remove(address)
if !removed { if !removed {
return false, errors.New(Fmt("Failed to remove validator %X)")) return errors.New(Fmt("Failed to remove validator %X)"))
} }
addedOrRemoved = true
} else { } else {
// update val // update val
val.VotingPower = power val.VotingPower = power
updated := validators.Update(val) updated := validators.Update(val)
if !updated { if !updated {
return false, errors.New(Fmt("Failed to update validator %X with voting power %d", address, power)) return errors.New(Fmt("Failed to update validator %X with voting power %d", address, power))
} }
} }
} }
return addedOrRemoved, nil return nil
} }
// return a bit array of validators that signed the last commit // return a bit array of validators that signed the last commit
@ -363,8 +359,8 @@ func (h *Handshaker) ReplayBlocks(appHash []byte, appBlockHeight int, appConnCon
// if we crashed between Commit and SaveState, // if we crashed between Commit and SaveState,
// the state's app hash is stale // the state's app hash is stale
// otherwise we're synced // otherwise we're synced
if h.state.Stale { if h.state.AppHashIsStale {
h.state.Stale = false h.state.AppHashIsStale = false
h.state.AppHash = appHash h.state.AppHash = appHash
} }
return nil return nil

View File

@ -38,10 +38,8 @@ type State struct {
// AppHash is updated after Commit; // AppHash is updated after Commit;
// it's stale after ExecBlock and before Commit // it's stale after ExecBlock and before Commit
Stale bool AppHashIsStale bool
AppHash []byte AppHash []byte
valAddedOrRemoved bool // true if a validator was added or removed
} }
func LoadState(db dbm.DB) *State { func LoadState(db dbm.DB) *State {
@ -62,6 +60,9 @@ func LoadState(db dbm.DB) *State {
} }
func (s *State) Copy() *State { func (s *State) Copy() *State {
if s.AppHashIsStale {
PanicSanity(Fmt("App hash is stale: %v", s))
}
return &State{ return &State{
db: s.db, db: s.db,
GenesisDoc: s.GenesisDoc, GenesisDoc: s.GenesisDoc,
@ -71,7 +72,7 @@ func (s *State) Copy() *State {
LastBlockTime: s.LastBlockTime, LastBlockTime: s.LastBlockTime,
Validators: s.Validators.Copy(), Validators: s.Validators.Copy(),
LastValidators: s.LastValidators.Copy(), LastValidators: s.LastValidators.Copy(),
Stale: s.Stale, // XXX: but really state shouldnt be copied while its stale AppHashIsStale: false,
AppHash: s.AppHash, AppHash: s.AppHash,
} }
} }
@ -96,7 +97,7 @@ func (s *State) Bytes() []byte {
} }
// Mutate state variables to match block and validators // Mutate state variables to match block and validators
// Since we don't have the new AppHash yet, we set s.Stale=true // Since we don't have the new AppHash yet, we set s.AppHashIsStale=true
func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader types.PartSetHeader, prevValSet, nextValSet *types.ValidatorSet) { func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader types.PartSetHeader, prevValSet, nextValSet *types.ValidatorSet) {
s.LastBlockHeight = header.Height s.LastBlockHeight = header.Height
s.LastBlockID = types.BlockID{header.Hash(), blockPartsHeader} s.LastBlockID = types.BlockID{header.Hash(), blockPartsHeader}
@ -104,11 +105,7 @@ func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader typ
s.Validators = nextValSet s.Validators = nextValSet
s.LastValidators = prevValSet s.LastValidators = prevValSet
s.Stale = true s.AppHashIsStale = true
}
func (s *State) ValidatorAddedOrRemoved() bool {
return s.valAddedOrRemoved
} }
func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) { func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) {