You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
5.0 KiB

10 years ago
8 years ago
10 years ago
10 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package state
  2. import (
  3. "bytes"
  4. "io/ioutil"
  5. "sync"
  6. "time"
  7. . "github.com/tendermint/go-common"
  8. cfg "github.com/tendermint/go-config"
  9. dbm "github.com/tendermint/go-db"
  10. "github.com/tendermint/go-wire"
  11. "github.com/tendermint/tendermint/state/tx"
  12. txindexer "github.com/tendermint/tendermint/state/tx/indexer"
  13. "github.com/tendermint/tendermint/types"
  14. )
  15. var (
  16. stateKey = []byte("stateKey")
  17. )
  18. //-----------------------------------------------------------------------------
  19. // NOTE: not goroutine-safe.
  20. type State struct {
  21. // mtx for writing to db
  22. mtx sync.Mutex
  23. db dbm.DB
  24. // should not change
  25. GenesisDoc *types.GenesisDoc
  26. ChainID string
  27. // updated at end of ExecBlock
  28. LastBlockHeight int // Genesis state has this set to 0. So, Block(H=0) does not exist.
  29. LastBlockID types.BlockID
  30. LastBlockTime time.Time
  31. Validators *types.ValidatorSet
  32. LastValidators *types.ValidatorSet // block.LastCommit validated against this
  33. // AppHash is updated after Commit
  34. AppHash []byte
  35. TxIndexer tx.Indexer `json:"-"` // Transaction indexer.
  36. }
  37. func LoadState(db dbm.DB) *State {
  38. return loadState(db, stateKey)
  39. }
  40. func loadState(db dbm.DB, key []byte) *State {
  41. s := &State{db: db, TxIndexer: &txindexer.Null{}}
  42. buf := db.Get(key)
  43. if len(buf) == 0 {
  44. return nil
  45. } else {
  46. r, n, err := bytes.NewReader(buf), new(int), new(error)
  47. wire.ReadBinaryPtr(&s, r, 0, n, err)
  48. if *err != nil {
  49. // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
  50. Exit(Fmt("Data has been corrupted or its spec has changed: %v\n", *err))
  51. }
  52. // TODO: ensure that buf is completely read.
  53. }
  54. return s
  55. }
  56. func (s *State) Copy() *State {
  57. return &State{
  58. db: s.db,
  59. GenesisDoc: s.GenesisDoc,
  60. ChainID: s.ChainID,
  61. LastBlockHeight: s.LastBlockHeight,
  62. LastBlockID: s.LastBlockID,
  63. LastBlockTime: s.LastBlockTime,
  64. Validators: s.Validators.Copy(),
  65. LastValidators: s.LastValidators.Copy(),
  66. AppHash: s.AppHash,
  67. TxIndexer: s.TxIndexer, // pointer here, not value
  68. }
  69. }
  70. func (s *State) Save() {
  71. s.mtx.Lock()
  72. defer s.mtx.Unlock()
  73. s.db.SetSync(stateKey, s.Bytes())
  74. }
  75. func (s *State) Equals(s2 *State) bool {
  76. return bytes.Equal(s.Bytes(), s2.Bytes())
  77. }
  78. func (s *State) Bytes() []byte {
  79. buf, n, err := new(bytes.Buffer), new(int), new(error)
  80. wire.WriteBinary(s, buf, n, err)
  81. if *err != nil {
  82. PanicCrisis(*err)
  83. }
  84. return buf.Bytes()
  85. }
  86. // Mutate state variables to match block and validators
  87. // after running EndBlock
  88. func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader types.PartSetHeader, prevValSet, nextValSet *types.ValidatorSet) {
  89. s.setBlockAndValidators(header.Height,
  90. types.BlockID{header.Hash(), blockPartsHeader}, header.Time,
  91. prevValSet, nextValSet)
  92. }
  93. func (s *State) setBlockAndValidators(
  94. height int, blockID types.BlockID, blockTime time.Time,
  95. prevValSet, nextValSet *types.ValidatorSet) {
  96. s.LastBlockHeight = height
  97. s.LastBlockID = blockID
  98. s.LastBlockTime = blockTime
  99. s.Validators = nextValSet
  100. s.LastValidators = prevValSet
  101. }
  102. func (s *State) GetValidators() (*types.ValidatorSet, *types.ValidatorSet) {
  103. return s.LastValidators, s.Validators
  104. }
  105. // Load the most recent state from "state" db,
  106. // or create a new one (and save) from genesis.
  107. func GetState(config cfg.Config, stateDB dbm.DB) *State {
  108. state := LoadState(stateDB)
  109. if state == nil {
  110. state = MakeGenesisStateFromFile(stateDB, config.GetString("genesis_file"))
  111. state.Save()
  112. }
  113. return state
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Genesis
  117. // MakeGenesisStateFromFile reads and unmarshals state from the given file.
  118. //
  119. // Used during replay and in tests.
  120. func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) *State {
  121. genDocJSON, err := ioutil.ReadFile(genDocFile)
  122. if err != nil {
  123. Exit(Fmt("Couldn't read GenesisDoc file: %v", err))
  124. }
  125. genDoc, err := types.GenesisDocFromJSON(genDocJSON)
  126. if err != nil {
  127. Exit(Fmt("Error reading GenesisDoc: %v", err))
  128. }
  129. return MakeGenesisState(db, genDoc)
  130. }
  131. // MakeGenesisState creates state from types.GenesisDoc.
  132. //
  133. // Used in tests.
  134. func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) *State {
  135. if len(genDoc.Validators) == 0 {
  136. Exit(Fmt("The genesis file has no validators"))
  137. }
  138. if genDoc.GenesisTime.IsZero() {
  139. genDoc.GenesisTime = time.Now()
  140. }
  141. // Make validators slice
  142. validators := make([]*types.Validator, len(genDoc.Validators))
  143. for i, val := range genDoc.Validators {
  144. pubKey := val.PubKey
  145. address := pubKey.Address()
  146. // Make validator
  147. validators[i] = &types.Validator{
  148. Address: address,
  149. PubKey: pubKey,
  150. VotingPower: val.Amount,
  151. }
  152. }
  153. return &State{
  154. db: db,
  155. GenesisDoc: genDoc,
  156. ChainID: genDoc.ChainID,
  157. LastBlockHeight: 0,
  158. LastBlockID: types.BlockID{},
  159. LastBlockTime: genDoc.GenesisTime,
  160. Validators: types.NewValidatorSet(validators),
  161. LastValidators: types.NewValidatorSet(nil),
  162. AppHash: genDoc.AppHash,
  163. TxIndexer: &txindexer.Null{}, // we do not need indexer during replay and in tests
  164. }
  165. }