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.

315 lines
8.6 KiB

8 years ago
8 years ago
8 years ago
10 years ago
8 years ago
10 years ago
8 years ago
8 years ago
8 years ago
8 years ago
7 years ago
8 years ago
8 years ago
  1. package state
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "time"
  7. cmn "github.com/tendermint/tmlibs/common"
  8. dbm "github.com/tendermint/tmlibs/db"
  9. "github.com/tendermint/tmlibs/log"
  10. wire "github.com/tendermint/go-wire"
  11. "github.com/tendermint/tendermint/types"
  12. )
  13. // database keys
  14. var (
  15. stateKey = []byte("stateKey")
  16. )
  17. func calcValidatorsKey(height int64) []byte {
  18. return []byte(cmn.Fmt("validatorsKey:%v", height))
  19. }
  20. func calcConsensusParamsKey(height int64) []byte {
  21. return []byte(cmn.Fmt("consensusParamsKey:%v", height))
  22. }
  23. func calcABCIResponsesKey(height int64) []byte {
  24. return []byte(cmn.Fmt("abciResponsesKey:%v", height))
  25. }
  26. //-----------------------------------------------------------------------------
  27. // State is a short description of the latest committed block of the Tendermint consensus.
  28. // It keeps all information necessary to validate new blocks,
  29. // including the last validator set and the consensus params.
  30. // All fields are exposed so the struct can be easily serialized,
  31. // but the fields should only be changed by calling state.SetBlockAndValidators.
  32. // NOTE: not goroutine-safe.
  33. type State struct {
  34. db dbm.DB
  35. // Immutable
  36. ChainID string
  37. // Exposed fields are updated by SetBlockAndValidators.
  38. // LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
  39. LastBlockHeight int64
  40. LastBlockTotalTx int64
  41. LastBlockID types.BlockID
  42. LastBlockTime time.Time
  43. // LastValidators is used to validate block.LastCommit.
  44. // Validators are persisted to the database separately every time they change,
  45. // so we can query for historical validator sets.
  46. // Note that if s.LastBlockHeight causes a valset change,
  47. // we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1
  48. Validators *types.ValidatorSet
  49. LastValidators *types.ValidatorSet
  50. LastHeightValidatorsChanged int64
  51. // Consensus parameters used for validating blocks.
  52. // Changes returned by EndBlock and updated after Commit.
  53. ConsensusParams types.ConsensusParams
  54. LastHeightConsensusParamsChanged int64
  55. // Merkle root of the results from executing prev block
  56. LastResultsHash []byte
  57. // The latest AppHash we've received from calling abci.Commit()
  58. AppHash []byte
  59. logger log.Logger
  60. }
  61. func (s *State) DB() dbm.DB {
  62. return s.db
  63. }
  64. // GetState loads the most recent state from the database,
  65. // or creates a new one from the given genesisFile and persists the result
  66. // to the database.
  67. func GetState(stateDB dbm.DB, genesisFile string) (*State, error) {
  68. state := LoadState(stateDB)
  69. if state == nil {
  70. var err error
  71. state, err = MakeGenesisStateFromFile(stateDB, genesisFile)
  72. if err != nil {
  73. return nil, err
  74. }
  75. state.Save()
  76. }
  77. return state, nil
  78. }
  79. // LoadState loads the State from the database.
  80. func LoadState(db dbm.DB) *State {
  81. return loadState(db, stateKey)
  82. }
  83. func loadState(db dbm.DB, key []byte) *State {
  84. buf := db.Get(key)
  85. if len(buf) == 0 {
  86. return nil
  87. }
  88. s := &State{db: db}
  89. r, n, err := bytes.NewReader(buf), new(int), new(error)
  90. wire.ReadBinaryPtr(&s, r, 0, n, err)
  91. if *err != nil {
  92. // DATA HAS BEEN CORRUPTED OR THE SPEC HAS CHANGED
  93. cmn.Exit(cmn.Fmt(`LoadState: Data has been corrupted or its spec has changed:
  94. %v\n`, *err))
  95. }
  96. // TODO: ensure that buf is completely read.
  97. return s
  98. }
  99. // SetLogger sets the logger on the State.
  100. func (s *State) SetLogger(l log.Logger) {
  101. s.logger = l
  102. }
  103. // Copy makes a copy of the State for mutating.
  104. func (s *State) Copy() *State {
  105. return &State{
  106. db: s.db,
  107. ChainID: s.ChainID,
  108. LastBlockHeight: s.LastBlockHeight,
  109. LastBlockTotalTx: s.LastBlockTotalTx,
  110. LastBlockID: s.LastBlockID,
  111. LastBlockTime: s.LastBlockTime,
  112. Validators: s.Validators.Copy(),
  113. LastValidators: s.LastValidators.Copy(),
  114. LastHeightValidatorsChanged: s.LastHeightValidatorsChanged,
  115. ConsensusParams: s.ConsensusParams,
  116. LastHeightConsensusParamsChanged: s.LastHeightConsensusParamsChanged,
  117. AppHash: s.AppHash,
  118. LastResultsHash: s.LastResultsHash,
  119. logger: s.logger,
  120. }
  121. }
  122. // Save persists the State to the database.
  123. func (s *State) Save() {
  124. nextHeight := s.LastBlockHeight + 1
  125. // persist everything to db
  126. db := s.db
  127. saveValidatorsInfo(db, nextHeight, s.LastHeightValidatorsChanged, s.Validators)
  128. saveConsensusParamsInfo(db, nextHeight, s.LastHeightConsensusParamsChanged, s.ConsensusParams)
  129. db.SetSync(stateKey, s.Bytes())
  130. }
  131. // Equals returns true if the States are identical.
  132. func (s *State) Equals(s2 *State) bool {
  133. return bytes.Equal(s.Bytes(), s2.Bytes())
  134. }
  135. // Bytes serializes the State using go-wire.
  136. func (s *State) Bytes() []byte {
  137. return wire.BinaryBytes(s)
  138. }
  139. // SetBlockAndValidators mutates State variables
  140. // to update block and validators after running EndBlock.
  141. func (s *State) SetBlockAndValidators(header *types.Header, blockPartsHeader types.PartSetHeader,
  142. abciResponses *ABCIResponses) error {
  143. // copy the valset so we can apply changes from EndBlock
  144. // and update s.LastValidators and s.Validators
  145. prevValSet := s.Validators.Copy()
  146. nextValSet := prevValSet.Copy()
  147. // update the validator set with the latest abciResponses
  148. if len(abciResponses.EndBlock.ValidatorUpdates) > 0 {
  149. err := updateValidators(nextValSet, abciResponses.EndBlock.ValidatorUpdates)
  150. if err != nil {
  151. return fmt.Errorf("Error changing validator set: %v", err)
  152. }
  153. // change results from this height but only applies to the next height
  154. s.LastHeightValidatorsChanged = header.Height + 1
  155. }
  156. // Update validator accums and set state variables
  157. nextValSet.IncrementAccum(1)
  158. // update the params with the latest abciResponses
  159. nextParams := s.ConsensusParams
  160. if abciResponses.EndBlock.ConsensusParamUpdates != nil {
  161. // NOTE: must not mutate s.ConsensusParams
  162. nextParams = s.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates)
  163. err := nextParams.Validate()
  164. if err != nil {
  165. return fmt.Errorf("Error updating consensus params: %v", err)
  166. }
  167. // change results from this height but only applies to the next height
  168. s.LastHeightConsensusParamsChanged = header.Height + 1
  169. }
  170. s.setBlockAndValidators(header.Height,
  171. header.NumTxs,
  172. types.BlockID{header.Hash(), blockPartsHeader},
  173. header.Time,
  174. nextValSet,
  175. nextParams,
  176. abciResponses.ResultsHash())
  177. return nil
  178. }
  179. func (s *State) setBlockAndValidators(height int64,
  180. newTxs int64, blockID types.BlockID, blockTime time.Time,
  181. valSet *types.ValidatorSet,
  182. params types.ConsensusParams,
  183. resultsHash []byte) {
  184. s.LastBlockHeight = height
  185. s.LastBlockTotalTx += newTxs
  186. s.LastBlockID = blockID
  187. s.LastBlockTime = blockTime
  188. s.LastValidators = s.Validators.Copy()
  189. s.Validators = valSet
  190. s.ConsensusParams = params
  191. s.LastResultsHash = resultsHash
  192. }
  193. // GetValidators returns the last and current validator sets.
  194. func (s *State) GetValidators() (last *types.ValidatorSet, current *types.ValidatorSet) {
  195. return s.LastValidators, s.Validators
  196. }
  197. //------------------------------------------------------------------------
  198. // Genesis
  199. // MakeGenesisStateFromFile reads and unmarshals state from the given
  200. // file.
  201. //
  202. // Used during replay and in tests.
  203. func MakeGenesisStateFromFile(db dbm.DB, genDocFile string) (*State, error) {
  204. genDoc, err := MakeGenesisDocFromFile(genDocFile)
  205. if err != nil {
  206. return nil, err
  207. }
  208. return MakeGenesisState(db, genDoc)
  209. }
  210. // MakeGenesisDocFromFile reads and unmarshals genesis doc from the given file.
  211. func MakeGenesisDocFromFile(genDocFile string) (*types.GenesisDoc, error) {
  212. genDocJSON, err := ioutil.ReadFile(genDocFile)
  213. if err != nil {
  214. return nil, fmt.Errorf("Couldn't read GenesisDoc file: %v", err)
  215. }
  216. genDoc, err := types.GenesisDocFromJSON(genDocJSON)
  217. if err != nil {
  218. return nil, fmt.Errorf("Error reading GenesisDoc: %v", err)
  219. }
  220. return genDoc, nil
  221. }
  222. // MakeGenesisState creates state from types.GenesisDoc.
  223. func MakeGenesisState(db dbm.DB, genDoc *types.GenesisDoc) (*State, error) {
  224. err := genDoc.ValidateAndComplete()
  225. if err != nil {
  226. return nil, fmt.Errorf("Error in genesis file: %v", err)
  227. }
  228. // Make validators slice
  229. validators := make([]*types.Validator, len(genDoc.Validators))
  230. for i, val := range genDoc.Validators {
  231. pubKey := val.PubKey
  232. address := pubKey.Address()
  233. // Make validator
  234. validators[i] = &types.Validator{
  235. Address: address,
  236. PubKey: pubKey,
  237. VotingPower: val.Power,
  238. }
  239. }
  240. return &State{
  241. db: db,
  242. ChainID: genDoc.ChainID,
  243. LastBlockHeight: 0,
  244. LastBlockID: types.BlockID{},
  245. LastBlockTime: genDoc.GenesisTime,
  246. Validators: types.NewValidatorSet(validators),
  247. LastValidators: types.NewValidatorSet(nil),
  248. LastHeightValidatorsChanged: 1,
  249. ConsensusParams: *genDoc.ConsensusParams,
  250. LastHeightConsensusParamsChanged: 1,
  251. AppHash: genDoc.AppHash,
  252. }, nil
  253. }