func (store dbStore) SaveValidatorSets(lowerHeight, upperHeight int64, vals *types.ValidatorSet) error {
	batch := store.db.NewBatch()
	defer batch.Close()
	for height := lowerHeight; height <= upperHeight; height++ {
		if err := store.saveValidatorsInfo(height, lowerHeight, vals, batch); err != nil {
			return err
		}
	}
	return batch.WriteSync()
}
SaveValidatorSets is used to save the validator set over multiple heights.
It is exposed so that a backfill operation during state sync can populate
the store with the necessary amount of validator sets to verify any evidence
it may encounter.
package state
import (
	"bytes"
	"errors"
	"fmt"
	"github.com/gogo/protobuf/proto"
	"github.com/google/orderedcode"
	dbm "github.com/tendermint/tm-db"
	abci "github.com/tendermint/tendermint/abci/types"
	tmmath "github.com/tendermint/tendermint/libs/math"
	tmos "github.com/tendermint/tendermint/libs/os"
	tmstate "github.com/tendermint/tendermint/proto/tendermint/state"
	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
	"github.com/tendermint/tendermint/types"
)
const (
	valSetCheckpointInterval = 100000
)
const (
	prefixValidators      = int64(5)
	prefixConsensusParams = int64(6)
	prefixABCIResponses   = int64(7)
	prefixState           = int64(8)
)
func encodeKey(prefix int64, height int64) []byte {
	res, err := orderedcode.Append(nil, prefix, height)
	if err != nil {
		panic(err)
	}
	return res
}
func validatorsKey(height int64) []byte {
	return encodeKey(prefixValidators, height)
}
func consensusParamsKey(height int64) []byte {
	return encodeKey(prefixConsensusParams, height)
}
func abciResponsesKey(height int64) []byte {
	return encodeKey(prefixABCIResponses, height)
}
var stateKey []byte
func init() {
	var err error
	stateKey, err = orderedcode.Append(nil, prefixState)
	if err != nil {
		panic(err)
	}
}
type Store interface {
	Load() (State, error)
	LoadValidators(int64) (*types.ValidatorSet, error)
	LoadABCIResponses(int64) (*tmstate.ABCIResponses, error)
	LoadConsensusParams(int64) (types.ConsensusParams, error)
	Save(State) error
	SaveABCIResponses(int64, *tmstate.ABCIResponses) error
	SaveValidatorSets(int64, int64, *types.ValidatorSet) error
	Bootstrap(State) error
	PruneStates(int64) error
}
type dbStore struct {
	db dbm.DB
}
var _ Store = (*dbStore)(nil)
func NewStore(db dbm.DB) Store {
	return dbStore{db}
}
func (store dbStore) Load() (State, error) {
	return store.loadState(stateKey)
}
func (store dbStore) loadState(key []byte) (state State, err error) {
	buf, err := store.db.Get(key)
	if err != nil {
		return state, err
	}
	if len(buf) == 0 {
		return state, nil
	}
	sp := new(tmstate.State)
	err = proto.Unmarshal(buf, sp)
	if err != nil {
		tmos.Exit(fmt.Sprintf(`LoadState: Data has been corrupted or its spec has changed:
		%v\n`, err))
	}
	sm, err := FromProto(sp)
	if err != nil {
		return state, err
	}
	return *sm, nil
}
func (store dbStore) Save(state State) error {
	return store.save(state, stateKey)
}
func (store dbStore) save(state State, key []byte) error {
	batch := store.db.NewBatch()
	defer batch.Close()
	nextHeight := state.LastBlockHeight + 1
	if nextHeight == 1 {
		nextHeight = state.InitialHeight
		if err := store.saveValidatorsInfo(nextHeight, nextHeight, state.Validators, batch); err != nil {
			return err
		}
	}
	err := store.saveValidatorsInfo(nextHeight+1, state.LastHeightValidatorsChanged, state.NextValidators, batch)
	if err != nil {
		return err
	}
	if err := store.saveConsensusParamsInfo(nextHeight,
		state.LastHeightConsensusParamsChanged, state.ConsensusParams, batch); err != nil {
		return err
	}
	if err := batch.Set(key, state.Bytes()); err != nil {
		return err
	}
	return batch.WriteSync()
}
func (store dbStore) Bootstrap(state State) error {
	height := state.LastBlockHeight + 1
	if height == 1 {
		height = state.InitialHeight
	}
	batch := store.db.NewBatch()
	defer batch.Close()
	if height > 1 && !state.LastValidators.IsNilOrEmpty() {
		if err := store.saveValidatorsInfo(height-1, height-1, state.LastValidators, batch); err != nil {
			return err
		}
	}
	if err := store.saveValidatorsInfo(height, height, state.Validators, batch); err != nil {
		return err
	}
	if err := store.saveValidatorsInfo(height+1, height+1, state.NextValidators, batch); err != nil {
		return err
	}
	if err := store.saveConsensusParamsInfo(height,
		state.LastHeightConsensusParamsChanged, state.ConsensusParams, batch); err != nil {
		return err
	}
	if err := batch.Set(stateKey, state.Bytes()); err != nil {
		return err
	}
	return batch.WriteSync()
}
func (store dbStore) PruneStates(retainHeight int64) error {
	if retainHeight <= 0 {
		return fmt.Errorf("height %v must be greater than 0", retainHeight)
	}
	if err := store.pruneConsensusParams(retainHeight); err != nil {
		return err
	}
	if err := store.pruneValidatorSets(retainHeight); err != nil {
		return err
	}
	if err := store.pruneABCIResponses(retainHeight); err != nil {
		return err
	}
	return nil
}
func (store dbStore) pruneValidatorSets(retainHeight int64) error {
	valInfo, err := loadValidatorsInfo(store.db, retainHeight)
	if err != nil {
		return fmt.Errorf("validators at height %v not found: %w", retainHeight, err)
	}
	lastRecordedValSetHeight := lastStoredHeightFor(retainHeight, valInfo.LastHeightChanged)
	lastRecordedValSet, err := loadValidatorsInfo(store.db, lastRecordedValSetHeight)
	if err != nil || lastRecordedValSet.ValidatorSet == nil {
		return fmt.Errorf("couldn't find validators at height %d (height %d was originally requested): %w",
			lastStoredHeightFor(retainHeight, valInfo.LastHeightChanged),
			retainHeight,
			err,
		)
	}
	if lastRecordedValSetHeight < retainHeight {
		err := store.pruneRange(
			validatorsKey(lastRecordedValSetHeight+1),
			validatorsKey(retainHeight),
		)
		if err != nil {
			return err
		}
	}
	return store.pruneRange(
		validatorsKey(1),
		validatorsKey(lastRecordedValSetHeight),
	)
}
func (store dbStore) pruneConsensusParams(retainHeight int64) error {
	paramsInfo, err := store.loadConsensusParamsInfo(retainHeight)
	if err != nil {
		return fmt.Errorf("consensus params at height %v not found: %w", retainHeight, err)
	}
	if paramsInfo.ConsensusParams.Equal(&tmproto.ConsensusParams{}) {
		lastRecordedConsensusParams, err := store.loadConsensusParamsInfo(paramsInfo.LastHeightChanged)
		if err != nil || lastRecordedConsensusParams.ConsensusParams.Equal(&tmproto.ConsensusParams{}) {
			return fmt.Errorf(
				"couldn't find consensus params at height %d (height %d was originally requested): %w",
				paramsInfo.LastHeightChanged,
				retainHeight,
				err,
			)
		}
		err = store.pruneRange(
			consensusParamsKey(paramsInfo.LastHeightChanged+1),
			consensusParamsKey(retainHeight),
		)
		if err != nil {
			return err
		}
	}
	return store.pruneRange(
		consensusParamsKey(1),
		consensusParamsKey(paramsInfo.LastHeightChanged),
	)
}
func (store dbStore) pruneABCIResponses(height int64) error {
	return store.pruneRange(abciResponsesKey(1), abciResponsesKey(height))
}
func (store dbStore) pruneRange(start []byte, end []byte) error {
	var err error
	batch := store.db.NewBatch()
	defer batch.Close()
	end, err = store.reverseBatchDelete(batch, start, end)
	if err != nil {
		return err
	}
	for !bytes.Equal(start, end) {
		if err := batch.Write(); err != nil {
			return err
		}
		if err := batch.Close(); err != nil {
			return err
		}
		batch = store.db.NewBatch()
		end, err = store.reverseBatchDelete(batch, start, end)
		if err != nil {
			return err
		}
	}
	return batch.WriteSync()
}
func (store dbStore) reverseBatchDelete(batch dbm.Batch, start, end []byte) ([]byte, error) {
	iter, err := store.db.ReverseIterator(start, end)
	if err != nil {
		return end, fmt.Errorf("iterator error: %w", err)
	}
	defer iter.Close()
	size := 0
	for ; iter.Valid(); iter.Next() {
		if err := batch.Delete(iter.Key()); err != nil {
			return end, fmt.Errorf("pruning error at key %X: %w", iter.Key(), err)
		}
		size++
		if size == 1000 {
			return iter.Key(), iter.Error()
		}
	}
	return start, iter.Error()
}
func ABCIResponsesResultsHash(ar *tmstate.ABCIResponses) []byte {
	return types.NewResults(ar.DeliverTxs).Hash()
}
func (store dbStore) LoadABCIResponses(height int64) (*tmstate.ABCIResponses, error) {
	buf, err := store.db.Get(abciResponsesKey(height))
	if err != nil {
		return nil, err
	}
	if len(buf) == 0 {
		return nil, ErrNoABCIResponsesForHeight{height}
	}
	abciResponses := new(tmstate.ABCIResponses)
	err = abciResponses.Unmarshal(buf)
	if err != nil {
		tmos.Exit(fmt.Sprintf(`LoadABCIResponses: Data has been corrupted or its spec has
                changed: %v\n`, err))
	}
	return abciResponses, nil
}
func (store dbStore) SaveABCIResponses(height int64, abciResponses *tmstate.ABCIResponses) error {
	return store.saveABCIResponses(height, abciResponses)
}
func (store dbStore) saveABCIResponses(height int64, abciResponses *tmstate.ABCIResponses) error {
	var dtxs []*abci.ResponseDeliverTx
	for _, tx := range abciResponses.DeliverTxs {
		if tx != nil {
			dtxs = append(dtxs, tx)
		}
	}
	abciResponses.DeliverTxs = dtxs
	bz, err := abciResponses.Marshal()
	if err != nil {
		return err
	}
	return store.db.SetSync(abciResponsesKey(height), bz)
}