2014-09-03 20:41:57 -07:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2017-09-05 18:57:36 -07:00
|
|
|
"fmt"
|
2015-08-10 20:38:45 -07:00
|
|
|
"io/ioutil"
|
2014-09-03 20:41:57 -07:00
|
|
|
"time"
|
|
|
|
|
2017-04-25 11:50:20 -07:00
|
|
|
cmn "github.com/tendermint/tmlibs/common"
|
2017-04-21 15:12:54 -07:00
|
|
|
dbm "github.com/tendermint/tmlibs/db"
|
2017-04-08 19:04:06 -07:00
|
|
|
|
2017-05-02 00:53:32 -07:00
|
|
|
wire "github.com/tendermint/go-wire"
|
2017-10-16 07:01:32 -07:00
|
|
|
|
2015-11-01 11:34:08 -08:00
|
|
|
"github.com/tendermint/tendermint/types"
|
2014-09-03 20:41:57 -07:00
|
|
|
)
|
|
|
|
|
2017-12-20 20:53:15 -08:00
|
|
|
// database keys
|
2014-09-03 20:41:57 -07:00
|
|
|
var (
|
2017-12-25 10:47:16 -08:00
|
|
|
stateKey = []byte("stateKey")
|
2014-09-03 20:41:57 -07:00
|
|
|
)
|
|
|
|
|
2017-12-01 17:04:53 -08:00
|
|
|
func calcValidatorsKey(height int64) []byte {
|
2017-08-21 13:31:54 -07:00
|
|
|
return []byte(cmn.Fmt("validatorsKey:%v", height))
|
|
|
|
}
|
|
|
|
|
2017-12-21 14:46:25 -08:00
|
|
|
func calcConsensusParamsKey(height int64) []byte {
|
2017-12-20 20:53:15 -08:00
|
|
|
return []byte(cmn.Fmt("consensusParamsKey:%v", height))
|
2017-12-21 14:46:25 -08:00
|
|
|
}
|
2017-12-20 20:53:15 -08:00
|
|
|
|
2017-12-25 10:47:16 -08:00
|
|
|
func calcABCIResponsesKey(height int64) []byte {
|
|
|
|
return []byte(cmn.Fmt("abciResponsesKey:%v", height))
|
2017-12-22 07:04:29 -08:00
|
|
|
}
|
|
|
|
|
2014-10-06 21:28:49 -07:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
2017-12-20 20:53:15 -08:00
|
|
|
// State is a short description of the latest committed block of the Tendermint consensus.
|
|
|
|
// It keeps all information necessary to validate new blocks,
|
|
|
|
// including the last validator set and the consensus params.
|
|
|
|
// All fields are exposed so the struct can be easily serialized,
|
2017-12-27 14:50:16 -08:00
|
|
|
// but none of them should be mutated directly.
|
|
|
|
// Instead, use state.Copy() ro state.NextState(...).
|
2014-10-07 01:05:54 -07:00
|
|
|
// NOTE: not goroutine-safe.
|
2014-09-03 20:41:57 -07:00
|
|
|
type State struct {
|
2017-12-20 20:53:15 -08:00
|
|
|
// Immutable
|
2017-10-12 03:50:09 -07:00
|
|
|
ChainID string
|
2016-09-11 10:16:23 -07:00
|
|
|
|
2017-09-12 11:37:32 -07:00
|
|
|
// LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
|
2017-12-12 04:16:03 -08:00
|
|
|
LastBlockHeight int64
|
|
|
|
LastBlockTotalTx int64
|
|
|
|
LastBlockID types.BlockID
|
|
|
|
LastBlockTime time.Time
|
2017-12-20 20:53:15 -08:00
|
|
|
|
|
|
|
// LastValidators is used to validate block.LastCommit.
|
|
|
|
// Validators are persisted to the database separately every time they change,
|
|
|
|
// so we can query for historical validator sets.
|
|
|
|
// Note that if s.LastBlockHeight causes a valset change,
|
2017-09-05 18:57:36 -07:00
|
|
|
// we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1
|
2017-12-20 20:53:15 -08:00
|
|
|
Validators *types.ValidatorSet
|
|
|
|
LastValidators *types.ValidatorSet
|
2017-12-01 17:04:53 -08:00
|
|
|
LastHeightValidatorsChanged int64
|
2017-08-21 13:31:54 -07:00
|
|
|
|
2017-12-20 20:53:15 -08:00
|
|
|
// Consensus parameters used for validating blocks.
|
|
|
|
// Changes returned by EndBlock and updated after Commit.
|
|
|
|
ConsensusParams types.ConsensusParams
|
|
|
|
LastHeightConsensusParamsChanged int64
|
|
|
|
|
2017-12-25 10:47:16 -08:00
|
|
|
// Merkle root of the results from executing prev block
|
2017-12-26 16:53:26 -08:00
|
|
|
LastResultsHash []byte
|
2017-12-22 06:21:02 -08:00
|
|
|
|
2017-12-20 20:53:15 -08:00
|
|
|
// The latest AppHash we've received from calling abci.Commit()
|
2017-10-16 07:01:32 -07:00
|
|
|
AppHash []byte
|
2017-05-02 00:53:32 -07:00
|
|
|
}
|
|
|
|
|
2017-08-21 13:12:07 -07:00
|
|
|
// Copy makes a copy of the State for mutating.
|
2017-12-27 14:50:16 -08:00
|
|
|
func (s State) Copy() State {
|
2017-12-27 16:21:16 -08:00
|
|
|
return State{
|
2017-12-20 20:53:15 -08:00
|
|
|
ChainID: s.ChainID,
|
|
|
|
|
|
|
|
LastBlockHeight: s.LastBlockHeight,
|
|
|
|
LastBlockTotalTx: s.LastBlockTotalTx,
|
|
|
|
LastBlockID: s.LastBlockID,
|
|
|
|
LastBlockTime: s.LastBlockTime,
|
|
|
|
|
2017-09-04 15:27:04 -07:00
|
|
|
Validators: s.Validators.Copy(),
|
|
|
|
LastValidators: s.LastValidators.Copy(),
|
|
|
|
LastHeightValidatorsChanged: s.LastHeightValidatorsChanged,
|
2017-12-20 20:53:15 -08:00
|
|
|
|
|
|
|
ConsensusParams: s.ConsensusParams,
|
|
|
|
LastHeightConsensusParamsChanged: s.LastHeightConsensusParamsChanged,
|
|
|
|
|
|
|
|
AppHash: s.AppHash,
|
|
|
|
|
2017-12-26 16:53:26 -08:00
|
|
|
LastResultsHash: s.LastResultsHash,
|
2017-09-22 17:17:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-27 14:50:16 -08:00
|
|
|
// Save persists the State, the ValidatorsInfo, and the ConsensusParamsInfo to the database.
|
2017-12-27 16:21:16 -08:00
|
|
|
// It sets the given appHash on the state before persisting.
|
|
|
|
func (s State) Save(db dbm.DB, appHash []byte) {
|
|
|
|
s.AppHash = appHash
|
2017-09-04 15:27:04 -07:00
|
|
|
nextHeight := s.LastBlockHeight + 1
|
2017-12-27 11:27:37 -08:00
|
|
|
saveValidatorsInfo(db, nextHeight, s.LastHeightValidatorsChanged, s.Validators)
|
|
|
|
saveConsensusParamsInfo(db, nextHeight, s.LastHeightConsensusParamsChanged, s.ConsensusParams)
|
|
|
|
db.SetSync(stateKey, s.Bytes())
|
2017-12-21 14:46:25 -08:00
|
|
|
}
|
|
|
|
|
2017-08-21 13:12:07 -07:00
|
|
|
// Equals returns true if the States are identical.
|
2017-12-27 14:50:16 -08:00
|
|
|
func (s State) Equals(s2 State) bool {
|
2016-08-23 18:44:07 -07:00
|
|
|
return bytes.Equal(s.Bytes(), s2.Bytes())
|
|
|
|
}
|
2014-12-09 18:49:04 -08:00
|
|
|
|
2017-08-21 13:12:07 -07:00
|
|
|
// Bytes serializes the State using go-wire.
|
2017-12-27 14:50:16 -08:00
|
|
|
func (s State) Bytes() []byte {
|
2017-08-21 13:12:07 -07:00
|
|
|
return wire.BinaryBytes(s)
|
2016-08-23 18:44:07 -07:00
|
|
|
}
|
|
|
|
|
2017-12-27 14:50:16 -08:00
|
|
|
// NextState returns a new State updated according to the header and responses.
|
2017-12-27 16:21:16 -08:00
|
|
|
func (s State) NextState(blockID types.BlockID, header *types.Header,
|
2017-12-27 14:50:16 -08:00
|
|
|
abciResponses *ABCIResponses) (State, error) {
|
2017-04-14 12:33:19 -07:00
|
|
|
|
2017-04-18 07:44:13 -07:00
|
|
|
// copy the valset so we can apply changes from EndBlock
|
|
|
|
// and update s.LastValidators and s.Validators
|
2017-04-14 12:33:19 -07:00
|
|
|
prevValSet := s.Validators.Copy()
|
|
|
|
nextValSet := prevValSet.Copy()
|
|
|
|
|
2017-08-21 13:31:54 -07:00
|
|
|
// update the validator set with the latest abciResponses
|
2017-12-27 14:50:16 -08:00
|
|
|
lastHeightValsChanged := s.LastHeightValidatorsChanged
|
2017-12-21 09:52:26 -08:00
|
|
|
if len(abciResponses.EndBlock.ValidatorUpdates) > 0 {
|
|
|
|
err := updateValidators(nextValSet, abciResponses.EndBlock.ValidatorUpdates)
|
2017-08-21 13:31:54 -07:00
|
|
|
if err != nil {
|
2017-12-27 16:21:16 -08:00
|
|
|
return s, fmt.Errorf("Error changing validator set: %v", err)
|
2017-08-21 13:31:54 -07:00
|
|
|
}
|
|
|
|
// change results from this height but only applies to the next height
|
2017-12-27 14:50:16 -08:00
|
|
|
lastHeightValsChanged = header.Height + 1
|
2017-04-14 12:33:19 -07:00
|
|
|
}
|
2017-05-15 02:02:40 -07:00
|
|
|
|
2017-04-14 12:33:19 -07:00
|
|
|
// Update validator accums and set state variables
|
|
|
|
nextValSet.IncrementAccum(1)
|
|
|
|
|
2017-12-21 14:46:25 -08:00
|
|
|
// update the params with the latest abciResponses
|
|
|
|
nextParams := s.ConsensusParams
|
2017-12-27 14:50:16 -08:00
|
|
|
lastHeightParamsChanged := s.LastHeightConsensusParamsChanged
|
2017-12-21 14:46:25 -08:00
|
|
|
if abciResponses.EndBlock.ConsensusParamUpdates != nil {
|
|
|
|
// NOTE: must not mutate s.ConsensusParams
|
|
|
|
nextParams = s.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates)
|
|
|
|
err := nextParams.Validate()
|
|
|
|
if err != nil {
|
2017-12-27 16:21:16 -08:00
|
|
|
return s, fmt.Errorf("Error updating consensus params: %v", err)
|
2017-12-21 14:46:25 -08:00
|
|
|
}
|
|
|
|
// change results from this height but only applies to the next height
|
2017-12-27 14:50:16 -08:00
|
|
|
lastHeightParamsChanged = header.Height + 1
|
2017-12-14 01:14:01 -08:00
|
|
|
}
|
2017-12-13 09:34:17 -08:00
|
|
|
|
2017-12-27 16:21:16 -08:00
|
|
|
// NOTE: the AppHash has not been populated.
|
|
|
|
// It will be filled on state.Save.
|
2017-12-27 14:50:16 -08:00
|
|
|
return State{
|
|
|
|
ChainID: s.ChainID,
|
|
|
|
LastBlockHeight: header.Height,
|
|
|
|
LastBlockTotalTx: s.LastBlockTotalTx + header.NumTxs,
|
2017-12-27 16:21:16 -08:00
|
|
|
LastBlockID: blockID,
|
2017-12-27 14:50:16 -08:00
|
|
|
LastBlockTime: header.Time,
|
|
|
|
Validators: nextValSet,
|
|
|
|
LastValidators: s.Validators.Copy(),
|
|
|
|
LastHeightValidatorsChanged: lastHeightValsChanged,
|
|
|
|
ConsensusParams: nextParams,
|
|
|
|
LastHeightConsensusParamsChanged: lastHeightParamsChanged,
|
|
|
|
LastResultsHash: abciResponses.ResultsHash(),
|
|
|
|
AppHash: nil,
|
2017-12-27 16:21:16 -08:00
|
|
|
}, nil
|
2016-11-19 17:29:07 -08:00
|
|
|
}
|
|
|
|
|
2017-08-21 13:12:07 -07:00
|
|
|
// GetValidators returns the last and current validator sets.
|
2017-12-27 14:50:16 -08:00
|
|
|
func (s State) GetValidators() (last *types.ValidatorSet, current *types.ValidatorSet) {
|
2016-08-23 18:44:07 -07:00
|
|
|
return s.LastValidators, s.Validators
|
2015-06-19 08:36:20 -07:00
|
|
|
}
|
|
|
|
|
2017-08-31 04:54:08 -07:00
|
|
|
//------------------------------------------------------------------------
|
2015-08-10 20:38:45 -07:00
|
|
|
// Genesis
|
2014-10-07 23:11:04 -07:00
|
|
|
|
2017-08-31 04:54:08 -07:00
|
|
|
// MakeGenesisStateFromFile reads and unmarshals state from the given
|
|
|
|
// file.
|
2017-01-19 01:33:58 -08:00
|
|
|
//
|
|
|
|
// Used during replay and in tests.
|
2017-12-27 14:50:16 -08:00
|
|
|
func MakeGenesisStateFromFile(genDocFile string) (*State, error) {
|
2017-09-20 15:29:36 -07:00
|
|
|
genDoc, err := MakeGenesisDocFromFile(genDocFile)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2017-12-27 14:50:16 -08:00
|
|
|
return MakeGenesisState(genDoc)
|
2017-09-20 15:29:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// MakeGenesisDocFromFile reads and unmarshals genesis doc from the given file.
|
|
|
|
func MakeGenesisDocFromFile(genDocFile string) (*types.GenesisDoc, error) {
|
2015-12-01 20:12:01 -08:00
|
|
|
genDocJSON, err := ioutil.ReadFile(genDocFile)
|
2015-08-10 20:38:45 -07:00
|
|
|
if err != nil {
|
2017-09-20 15:29:36 -07:00
|
|
|
return nil, fmt.Errorf("Couldn't read GenesisDoc file: %v", err)
|
2015-08-10 20:38:45 -07:00
|
|
|
}
|
2017-01-29 13:50:04 -08:00
|
|
|
genDoc, err := types.GenesisDocFromJSON(genDocJSON)
|
|
|
|
if err != nil {
|
2017-09-20 15:29:36 -07:00
|
|
|
return nil, fmt.Errorf("Error reading GenesisDoc: %v", err)
|
2017-01-29 13:50:04 -08:00
|
|
|
}
|
2017-09-20 15:29:36 -07:00
|
|
|
return genDoc, nil
|
2014-09-03 20:41:57 -07:00
|
|
|
}
|
2014-10-13 20:07:26 -07:00
|
|
|
|
2017-01-19 01:33:58 -08:00
|
|
|
// MakeGenesisState creates state from types.GenesisDoc.
|
2017-12-27 14:50:16 -08:00
|
|
|
func MakeGenesisState(genDoc *types.GenesisDoc) (*State, error) {
|
2017-09-11 13:48:41 -07:00
|
|
|
err := genDoc.ValidateAndComplete()
|
|
|
|
if err != nil {
|
2017-09-20 15:29:36 -07:00
|
|
|
return nil, fmt.Errorf("Error in genesis file: %v", err)
|
2015-08-10 20:38:45 -07:00
|
|
|
}
|
|
|
|
|
2015-11-01 11:34:08 -08:00
|
|
|
// Make validators slice
|
2015-08-10 20:38:45 -07:00
|
|
|
validators := make([]*types.Validator, len(genDoc.Validators))
|
|
|
|
for i, val := range genDoc.Validators {
|
|
|
|
pubKey := val.PubKey
|
|
|
|
address := pubKey.Address()
|
|
|
|
|
|
|
|
// Make validator
|
|
|
|
validators[i] = &types.Validator{
|
|
|
|
Address: address,
|
|
|
|
PubKey: pubKey,
|
2017-09-21 11:37:34 -07:00
|
|
|
VotingPower: val.Power,
|
2015-08-10 20:38:45 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &State{
|
2017-09-22 17:17:21 -07:00
|
|
|
|
2017-10-12 03:50:09 -07:00
|
|
|
ChainID: genDoc.ChainID,
|
2017-10-05 05:50:05 -07:00
|
|
|
|
2017-12-20 20:53:15 -08:00
|
|
|
LastBlockHeight: 0,
|
|
|
|
LastBlockID: types.BlockID{},
|
|
|
|
LastBlockTime: genDoc.GenesisTime,
|
|
|
|
|
2017-08-21 13:31:54 -07:00
|
|
|
Validators: types.NewValidatorSet(validators),
|
|
|
|
LastValidators: types.NewValidatorSet(nil),
|
2017-09-04 15:27:04 -07:00
|
|
|
LastHeightValidatorsChanged: 1,
|
2017-12-20 20:53:15 -08:00
|
|
|
|
|
|
|
ConsensusParams: *genDoc.ConsensusParams,
|
|
|
|
LastHeightConsensusParamsChanged: 1,
|
|
|
|
|
|
|
|
AppHash: genDoc.AppHash,
|
2017-09-20 15:29:36 -07:00
|
|
|
}, nil
|
2014-10-13 20:07:26 -07:00
|
|
|
}
|