@ -9,6 +9,14 @@ import (
"github.com/tendermint/tendermint/types"
)
const (
// persist validators every valSetCheckpointInterval blocks to avoid
// LoadValidators taking too much time.
// https://github.com/tendermint/tendermint/pull/3438
// 100000 results in ~ 100ms to get 100 validators (see BenchmarkLoadValidators)
valSetCheckpointInterval = 100000
)
//------------------------------------------------------------------------
func calcValidatorsKey ( height int64 ) [ ] byte {
@ -182,25 +190,38 @@ func LoadValidators(db dbm.DB, height int64) (*types.ValidatorSet, error) {
if valInfo == nil {
return nil , ErrNoValSetForHeight { height }
}
if valInfo . ValidatorSet == nil {
valInfo2 := loadValidatorsInfo ( db , valInfo . LastHeightChanged )
lastStoredHeight := lastStoredHeightFor ( height , valInfo . LastHeightChanged )
valInfo2 := loadValidatorsInfo ( db , lastStoredHeight )
if valInfo2 == nil {
panic (
fmt . Sprintf (
"Couldn't find validators at height %d as last changed from height %d" ,
valInfo . LastHeightChanged ,
height ,
) ,
)
// TODO (melekes): remove the below if condition in the 0.33 major
// release and just panic. Old chains might panic otherwise if they
// haven't saved validators at intermediate (%valSetCheckpointInterval)
// height yet.
// https://github.com/tendermint/tendermint/issues/3543
valInfo2 = loadValidatorsInfo ( db , valInfo . LastHeightChanged )
lastStoredHeight = valInfo . LastHeightChanged
if valInfo2 == nil {
panic (
fmt . Sprintf ( "Couldn't find validators at height %d (height %d was originally requested)" ,
lastStoredHeight ,
height ,
) ,
)
}
}
valInfo2 . ValidatorSet . IncrementProposerPriority ( int ( height - valInfo . LastHeightChanged ) ) // mutate
valInfo2 . ValidatorSet . IncrementProposerPriority ( int ( height - lastStoredHeight ) ) // mutate
valInfo = valInfo2
}
return valInfo . ValidatorSet , nil
}
func lastStoredHeightFor ( height , lastHeightChanged int64 ) int64 {
checkpointHeight := height - height % valSetCheckpointInterval
return cmn . MaxInt64 ( checkpointHeight , lastHeightChanged )
}
// CONTRACT: Returned ValidatorsInfo can be mutated.
func loadValidatorsInfo ( db dbm . DB , height int64 ) * ValidatorsInfo {
buf := db . Get ( calcValidatorsKey ( height ) )
@ -221,10 +242,10 @@ func loadValidatorsInfo(db dbm.DB, height int64) *ValidatorsInfo {
}
// saveValidatorsInfo persists the validator set.
// `height` is the effective height for which the validator is responsible for signing.
// It should be called from s.Save(), right before the state itself is persisted.
// If the validator set did not change after processing the latest block,
// only the last height for which the validators changed is persisted.
//
// `height` is the effective height for which the validator is responsible for
// signing. It should be called from s.Save(), right before the state itself is
// persisted.
func saveValidatorsInfo ( db dbm . DB , height , lastHeightChanged int64 , valSet * types . ValidatorSet ) {
if lastHeightChanged > height {
panic ( "LastHeightChanged cannot be greater than ValidatorsInfo height" )
@ -232,7 +253,9 @@ func saveValidatorsInfo(db dbm.DB, height, lastHeightChanged int64, valSet *type
valInfo := & ValidatorsInfo {
LastHeightChanged : lastHeightChanged ,
}
if lastHeightChanged == height {
// Only persist validator set if it was updated or checkpoint height (see
// valSetCheckpointInterval) is reached.
if height == lastHeightChanged || height % valSetCheckpointInterval == 0 {
valInfo . ValidatorSet = valSet
}
db . Set ( calcValidatorsKey ( height ) , valInfo . Bytes ( ) )