tendermint/state/state.go

176 lines
4.9 KiB
Go
Raw Normal View History

package state
import (
"bytes"
"io/ioutil"
"time"
. "github.com/tendermint/go-common"
dbm "github.com/tendermint/go-db"
"github.com/tendermint/go-merkle"
"github.com/tendermint/go-wire"
2015-11-01 11:34:08 -08:00
"github.com/tendermint/tendermint/events"
"github.com/tendermint/tendermint/types"
)
var (
2015-11-01 11:34:08 -08:00
stateKey = []byte("stateKey")
)
2014-10-06 21:28:49 -07:00
//-----------------------------------------------------------------------------
2014-10-07 01:05:54 -07:00
// NOTE: not goroutine-safe.
type State struct {
2015-11-01 11:34:08 -08:00
DB dbm.DB
ChainID string
LastBlockHeight int
LastBlockHash []byte
LastBlockParts types.PartSetHeader
LastBlockTime time.Time
Validators *types.ValidatorSet
LastValidators *types.ValidatorSet
2015-04-13 18:26:41 -07:00
2015-04-15 23:40:27 -07:00
evc events.Fireable // typically an events.EventCache
}
func LoadState(db dbm.DB) *State {
2014-10-07 01:05:54 -07:00
s := &State{DB: db}
buf := db.Get(stateKey)
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)
s.ChainID = wire.ReadString(r, 0, n, err)
2015-07-25 15:45:45 -07:00
s.LastBlockHeight = wire.ReadVarint(r, n, err)
2015-11-10 13:10:43 -08:00
s.LastBlockHash = wire.ReadByteSlice(r, 0, n, err)
s.LastBlockParts = wire.ReadBinary(types.PartSetHeader{}, r, 0, n, err).(types.PartSetHeader)
2015-07-25 15:45:45 -07:00
s.LastBlockTime = wire.ReadTime(r, n, err)
2015-11-10 13:10:43 -08:00
s.Validators = wire.ReadBinary(&types.ValidatorSet{}, r, 0, n, err).(*types.ValidatorSet)
s.LastValidators = wire.ReadBinary(&types.ValidatorSet{}, r, 0, n, err).(*types.ValidatorSet)
if *err != nil {
2015-06-16 21:16:58 -07:00
// DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
Exit(Fmt("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) Save() {
2015-11-10 13:10:43 -08:00
buf, n, err := new(bytes.Buffer), new(int), new(error)
2015-07-25 15:45:45 -07:00
wire.WriteString(s.ChainID, buf, n, err)
wire.WriteVarint(s.LastBlockHeight, buf, n, err)
wire.WriteByteSlice(s.LastBlockHash, buf, n, err)
wire.WriteBinary(s.LastBlockParts, buf, n, err)
wire.WriteTime(s.LastBlockTime, buf, n, err)
2015-11-01 11:34:08 -08:00
wire.WriteBinary(s.Validators, buf, n, err)
wire.WriteBinary(s.LastValidators, buf, n, err)
if *err != nil {
2015-07-19 16:42:52 -07:00
PanicCrisis(*err)
}
2014-10-07 01:05:54 -07:00
s.DB.Set(stateKey, buf.Bytes())
}
// CONTRACT:
// Copy() is a cheap way to take a snapshot,
// as if State were copied by value.
func (s *State) Copy() *State {
return &State{
2015-11-01 11:34:08 -08:00
DB: s.DB,
ChainID: s.ChainID,
LastBlockHeight: s.LastBlockHeight,
LastBlockHash: s.LastBlockHash,
LastBlockParts: s.LastBlockParts,
LastBlockTime: s.LastBlockTime,
Validators: s.Validators.Copy(), // TODO remove need for Copy() here.
LastValidators: s.LastValidators.Copy(), // That is, make updates to the validator set
evc: nil,
}
}
// Returns a hash that represents the state data, excluding Last*
func (s *State) Hash() []byte {
2015-08-07 10:43:24 -07:00
return merkle.SimpleHashFromMap(map[string]interface{}{
2015-11-01 11:34:08 -08:00
"Validators": s.Validators,
2015-08-07 10:43:24 -07:00
})
}
// Mutates the block in place and updates it with new state hash.
2015-06-05 14:15:40 -07:00
func (s *State) ComputeBlockStateHash(block *types.Block) error {
sCopy := s.Copy()
2015-04-15 23:40:27 -07:00
// sCopy has no event cache in it, so this won't fire events
err := execBlock(sCopy, block, types.PartSetHeader{})
if err != nil {
return err
2015-03-18 01:27:16 -07:00
}
// Set block.StateHash
block.StateHash = sCopy.Hash()
2015-03-18 01:27:16 -07:00
return nil
}
2015-06-19 08:36:20 -07:00
func (s *State) SetDB(db dbm.DB) {
s.DB = db
}
2015-04-15 23:40:27 -07:00
// Implements events.Eventable. Typically uses events.EventCache
func (s *State) SetFireable(evc events.Fireable) {
s.evc = evc
2015-04-13 18:26:41 -07:00
}
//-----------------------------------------------------------------------------
// Genesis
2014-10-07 23:11:04 -07:00
2015-11-01 11:34:08 -08:00
func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) (*types.GenesisDoc, *State) {
jsonBlob, err := ioutil.ReadFile(genDocFile)
if err != nil {
Exit(Fmt("Couldn't read GenesisDoc file: %v", err))
}
2015-11-01 11:34:08 -08:00
genDoc := types.GenesisDocFromJSON(jsonBlob)
return genDoc, MakeGenesisState(db, genDoc)
}
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
// XXX Speak to application, ensure genesis state.
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-11-01 11:34:08 -08:00
DB: db,
ChainID: genDoc.ChainID,
LastBlockHeight: 0,
LastBlockHash: nil,
LastBlockParts: types.PartSetHeader{},
LastBlockTime: genDoc.GenesisTime,
Validators: types.NewValidatorSet(validators),
LastValidators: types.NewValidatorSet(nil),
}
}
2015-11-01 11:34:08 -08:00
func RandGenesisState(numValidators int, randPower bool, minPower int64) (*State, []*types.PrivValidator) {
db := dbm.NewMemDB()
2015-11-01 11:34:08 -08:00
genDoc, privValidators := types.RandGenesisDoc(numValidators, randPower, minPower)
s0 := MakeGenesisState(db, genDoc)
s0.Save()
2015-11-01 11:34:08 -08:00
return s0, privValidators
}