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.

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