|
|
- package state
-
- import (
- "bytes"
- "io/ioutil"
- "sync"
- "time"
-
- . "github.com/tendermint/go-common"
- dbm "github.com/tendermint/go-db"
- "github.com/tendermint/go-wire"
- "github.com/tendermint/tendermint/events"
- "github.com/tendermint/tendermint/types"
- )
-
- var (
- stateKey = []byte("stateKey")
- )
-
- //-----------------------------------------------------------------------------
-
- // NOTE: not goroutine-safe.
- type State struct {
- mtx sync.Mutex
- db dbm.DB
- GenesisDoc *types.GenesisDoc
- ChainID string
- LastBlockHeight int
- LastBlockHash []byte
- LastBlockParts types.PartSetHeader
- LastBlockTime time.Time
- Validators *types.ValidatorSet
- LastValidators *types.ValidatorSet
- LastAppHash []byte
-
- evc events.Fireable // typically an events.EventCache
- }
-
- func LoadState(db dbm.DB) *State {
- s := &State{db: db}
- buf := db.Get(stateKey)
- if len(buf) == 0 {
- return nil
- } else {
- r, n, err := bytes.NewReader(buf), new(int), new(error)
- wire.ReadBinaryPtr(&s, r, 0, n, err)
- if *err != nil {
- // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
- Exit(Fmt("Data has been corrupted or its spec has changed: %v\n", *err))
- }
- // TODO: ensure that buf is completely read.
- }
- return s
- }
-
- func (s *State) Copy() *State {
- return &State{
- db: s.db,
- GenesisDoc: s.GenesisDoc,
- ChainID: s.ChainID,
- LastBlockHeight: s.LastBlockHeight,
- LastBlockHash: s.LastBlockHash,
- LastBlockParts: s.LastBlockParts,
- LastBlockTime: s.LastBlockTime,
- Validators: s.Validators.Copy(),
- LastValidators: s.LastValidators.Copy(),
- LastAppHash: s.LastAppHash,
- evc: nil,
- }
- }
-
- func (s *State) Save() {
- s.mtx.Lock()
- defer s.mtx.Unlock()
-
- buf, n, err := new(bytes.Buffer), new(int), new(error)
- wire.WriteBinary(s, buf, n, err)
- if *err != nil {
- PanicCrisis(*err)
- }
- s.db.Set(stateKey, buf.Bytes())
- }
-
- // Implements events.Eventable. Typically uses events.EventCache
- func (s *State) SetFireable(evc events.Fireable) {
- s.mtx.Lock()
- defer s.mtx.Unlock()
-
- s.evc = evc
- }
-
- //-----------------------------------------------------------------------------
- // Genesis
-
- 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))
- }
- genDoc := types.GenesisDocFromJSON(genDocJSON)
- return MakeGenesisState(db, genDoc)
- }
-
- 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()
- }
-
- // 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{
- db: db,
- GenesisDoc: genDoc,
- ChainID: genDoc.ChainID,
- LastBlockHeight: 0,
- LastBlockHash: nil,
- LastBlockParts: types.PartSetHeader{},
- LastBlockTime: genDoc.GenesisTime,
- Validators: types.NewValidatorSet(validators),
- LastValidators: types.NewValidatorSet(nil),
- LastAppHash: genDoc.AppHash,
- }
- }
|