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.

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