tendermint/state/state.go

270 lines
7.2 KiB
Go
Raw Normal View History

package state
import (
"bytes"
"io/ioutil"
2015-12-01 20:12:01 -08:00
"sync"
"time"
2017-04-08 19:04:06 -07:00
"github.com/spf13/viper"
abci "github.com/tendermint/abci/types"
2016-08-24 21:18:03 -07:00
cfg "github.com/tendermint/go-config"
2017-04-08 19:04:06 -07:00
. "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
"github.com/tendermint/go-wire"
2017-04-18 16:29:02 -07:00
"github.com/tendermint/tendermint/state/txindex"
"github.com/tendermint/tendermint/state/txindex/null"
2015-11-01 11:34:08 -08:00
"github.com/tendermint/tendermint/types"
)
var (
stateKey = []byte("stateKey")
abciResponsesKey = []byte("abciResponsesKey")
)
2014-10-06 21:28:49 -07:00
//-----------------------------------------------------------------------------
2014-10-07 01:05:54 -07:00
// NOTE: not goroutine-safe.
type State struct {
// mtx for writing to db
mtx sync.Mutex
db dbm.DB
// should not change
GenesisDoc *types.GenesisDoc
ChainID string
// updated at end of SetBlockAndValidators
LastBlockHeight int // Genesis state has this set to 0. So, Block(H=0) does not exist.
2016-08-16 14:59:19 -07:00
LastBlockID types.BlockID
2015-11-01 11:34:08 -08:00
LastBlockTime time.Time
Validators *types.ValidatorSet
2016-11-19 16:32:35 -08:00
LastValidators *types.ValidatorSet // block.LastCommit validated against this
// AppHash is updated after Commit
AppHash []byte
2017-04-18 16:29:02 -07:00
TxIndexer txindex.TxIndexer `json:"-"` // Transaction indexer.
// Intermediate results from processing
// Persisted separately from the state
abciResponses *ABCIResponses
}
func LoadState(db dbm.DB) *State {
return loadState(db, stateKey)
}
func loadState(db dbm.DB, key []byte) *State {
2017-04-18 16:29:02 -07:00
s := &State{db: db, TxIndexer: &null.TxIndex{}}
buf := db.Get(key)
if len(buf) == 0 {
2014-10-03 17:59:54 -07:00
return nil
} else {
2015-11-10 13:10:43 -08:00
r, n, err := bytes.NewReader(buf), new(int), new(error)
2015-12-01 20:12:01 -08:00
wire.ReadBinaryPtr(&s, r, 0, n, err)
if *err != nil {
2015-06-16 21:16:58 -07:00
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
Exit(Fmt("LoadState: Data has been corrupted or its spec has changed: %v\n", *err))
}
2014-10-11 21:27:58 -07:00
// TODO: ensure that buf is completely read.
}
return s
}
func (s *State) Copy() *State {
return &State{
2015-12-01 20:12:01 -08:00
db: s.db,
GenesisDoc: s.GenesisDoc,
2015-11-01 11:34:08 -08:00
ChainID: s.ChainID,
LastBlockHeight: s.LastBlockHeight,
2016-08-16 14:59:19 -07:00
LastBlockID: s.LastBlockID,
2015-11-01 11:34:08 -08:00
LastBlockTime: s.LastBlockTime,
2015-12-01 20:12:01 -08:00
Validators: s.Validators.Copy(),
LastValidators: s.LastValidators.Copy(),
AppHash: s.AppHash,
TxIndexer: s.TxIndexer, // pointer here, not value
}
}
2015-12-01 20:12:01 -08:00
func (s *State) Save() {
s.mtx.Lock()
defer s.mtx.Unlock()
2016-12-06 02:52:07 -08:00
s.db.SetSync(stateKey, s.Bytes())
2016-08-23 18:44:07 -07:00
}
// Sets the ABCIResponses in the state and writes them to disk
// in case we crash after app.Commit and before s.Save()
func (s *State) SaveABCIResponses(abciResponses *ABCIResponses) {
// save the validators to the db
s.db.SetSync(abciResponsesKey, abciResponses.Bytes())
}
func (s *State) LoadABCIResponses() *ABCIResponses {
abciResponses := new(ABCIResponses)
buf := s.db.Get(abciResponsesKey)
if len(buf) != 0 {
r, n, err := bytes.NewReader(buf), new(int), new(error)
wire.ReadBinaryPtr(abciResponses, r, 0, n, err)
if *err != nil {
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
Exit(Fmt("LoadABCIResponses: Data has been corrupted or its spec has changed: %v\n", *err))
}
// TODO: ensure that buf is completely read.
}
return abciResponses
}
2016-08-23 18:44:07 -07:00
func (s *State) Equals(s2 *State) bool {
return bytes.Equal(s.Bytes(), s2.Bytes())
}
2016-08-23 18:44:07 -07:00
func (s *State) Bytes() []byte {
2015-12-01 20:12:01 -08:00
buf, n, err := new(bytes.Buffer), new(int), new(error)
wire.WriteBinary(s, buf, n, err)
if *err != nil {
PanicCrisis(*err)
2015-03-18 01:27:16 -07:00
}
2016-08-23 18:44:07 -07:00
return buf.Bytes()
}
// Mutate state variables to match block and validators
// after running EndBlock
func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader types.PartSetHeader, abciResponses *ABCIResponses) {
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
prevValSet := s.Validators.Copy()
nextValSet := prevValSet.Copy()
2017-04-14 14:20:03 -07:00
// update the validator set with the latest abciResponses
err := updateValidators(nextValSet, abciResponses.EndBlock.Diffs)
if err != nil {
log.Warn("Error changing validator set", "error", err)
// TODO: err or carry on?
}
// Update validator accums and set state variables
nextValSet.IncrementAccum(1)
s.setBlockAndValidators(header.Height,
types.BlockID{header.Hash(), blockPartsHeader}, header.Time,
prevValSet, nextValSet)
}
func (s *State) setBlockAndValidators(
height int, blockID types.BlockID, blockTime time.Time,
prevValSet, nextValSet *types.ValidatorSet) {
s.LastBlockHeight = height
s.LastBlockID = blockID
s.LastBlockTime = blockTime
2016-08-23 18:44:07 -07:00
s.Validators = nextValSet
s.LastValidators = prevValSet
}
2016-08-23 18:44:07 -07:00
func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) {
return s.LastValidators, s.Validators
2015-06-19 08:36:20 -07:00
}
2016-08-24 21:18:03 -07:00
// Load the most recent state from "state" db,
// or create a new one (and save) from genesis.
2017-04-08 19:04:06 -07:00
func GetState(config *viper.Viper, stateDB dbm.DB) *State {
2016-08-24 21:18:03 -07:00
state := LoadState(stateDB)
if state == nil {
state = MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
state.Save()
}
2016-08-24 21:18:03 -07:00
return state
}
//--------------------------------------------------
// ABCIResponses holds intermediate state during block processing
type ABCIResponses struct {
Height int
DeliverTx []*abci.ResponseDeliverTx
EndBlock abci.ResponseEndBlock
2017-04-14 22:33:30 -07:00
txs types.Txs // reference for indexing results by hash
}
func NewABCIResponses(block *types.Block) *ABCIResponses {
return &ABCIResponses{
Height: block.Height,
DeliverTx: make([]*abci.ResponseDeliverTx, block.NumTxs),
txs: block.Data.Txs,
}
}
// Serialize the ABCIResponse
func (a *ABCIResponses) Bytes() []byte {
buf, n, err := new(bytes.Buffer), new(int), new(error)
wire.WriteBinary(*a, buf, n, err)
if *err != nil {
PanicCrisis(*err)
}
return buf.Bytes()
}
//-----------------------------------------------------------------------------
// Genesis
2014-10-07 23:11:04 -07:00
// MakeGenesisStateFromFile reads and unmarshals state from the given file.
//
// Used during replay and in tests.
2015-12-01 20:12:01 -08:00
func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) *State {
genDocJSON, err := ioutil.ReadFile(genDocFile)
if err != nil {
Exit(Fmt("Couldn't read GenesisDoc file: %v", err))
}
2017-01-29 13:50:04 -08:00
genDoc, err := types.GenesisDocFromJSON(genDocJSON)
if err != nil {
Exit(Fmt("Error reading GenesisDoc: %v", err))
}
2015-12-01 20:12:01 -08:00
return MakeGenesisState(db, genDoc)
}
// MakeGenesisState creates state from types.GenesisDoc.
//
// Used in tests.
2015-11-01 11:34:08 -08:00
func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State {
if len(genDoc.Validators) == 0 {
Exit(Fmt("The genesis file has no validators"))
}
if genDoc.GenesisTime.IsZero() {
genDoc.GenesisTime = time.Now()
}
2015-11-01 11:34:08 -08:00
// Make validators slice
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,
VotingPower: val.Amount,
}
}
return &State{
2015-12-01 20:12:01 -08:00
db: db,
GenesisDoc: genDoc,
2015-11-01 11:34:08 -08:00
ChainID: genDoc.ChainID,
LastBlockHeight: 0,
2016-08-16 14:59:19 -07:00
LastBlockID: types.BlockID{},
2015-11-01 11:34:08 -08:00
LastBlockTime: genDoc.GenesisTime,
Validators: types.NewValidatorSet(validators),
LastValidators: types.NewValidatorSet(nil),
AppHash: genDoc.AppHash,
2017-04-18 16:29:02 -07:00
TxIndexer: &null.TxIndex{}, // we do not need indexer during replay and in tests
}
}