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.

248 lines
7.7 KiB

10 years ago
8 years ago
7 years ago
8 years ago
7 years ago
8 years ago
  1. package state
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "time"
  7. "github.com/tendermint/tendermint/types"
  8. tmtime "github.com/tendermint/tendermint/types/time"
  9. "github.com/tendermint/tendermint/version"
  10. )
  11. // database keys
  12. var (
  13. stateKey = []byte("stateKey")
  14. )
  15. //-----------------------------------------------------------------------------
  16. // Version is for versioning the State.
  17. // It holds the Block and App version needed for making blocks,
  18. // and the software version to support upgrades to the format of
  19. // the State as stored on disk.
  20. type Version struct {
  21. Consensus version.Consensus
  22. Software string
  23. }
  24. // initStateVersion sets the Consensus.Block and Software versions,
  25. // but leaves the Consensus.App version blank.
  26. // The Consensus.App version will be set during the Handshake, once
  27. // we hear from the app what protocol version it is running.
  28. var initStateVersion = Version{
  29. Consensus: version.Consensus{
  30. Block: version.BlockProtocol,
  31. App: 0,
  32. },
  33. Software: version.TMCoreSemVer,
  34. }
  35. //-----------------------------------------------------------------------------
  36. // State is a short description of the latest committed block of the Tendermint consensus.
  37. // It keeps all information necessary to validate new blocks,
  38. // including the last validator set and the consensus params.
  39. // All fields are exposed so the struct can be easily serialized,
  40. // but none of them should be mutated directly.
  41. // Instead, use state.Copy() or state.NextState(...).
  42. // NOTE: not goroutine-safe.
  43. type State struct {
  44. Version Version
  45. // immutable
  46. ChainID string
  47. // LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
  48. LastBlockHeight int64
  49. LastBlockID types.BlockID
  50. LastBlockTime time.Time
  51. // LastValidators is used to validate block.LastCommit.
  52. // Validators are persisted to the database separately every time they change,
  53. // so we can query for historical validator sets.
  54. // Note that if s.LastBlockHeight causes a valset change,
  55. // we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1 + 1
  56. // Extra +1 due to nextValSet delay.
  57. NextValidators *types.ValidatorSet
  58. Validators *types.ValidatorSet
  59. LastValidators *types.ValidatorSet
  60. LastHeightValidatorsChanged int64
  61. // Consensus parameters used for validating blocks.
  62. // Changes returned by EndBlock and updated after Commit.
  63. ConsensusParams types.ConsensusParams
  64. LastHeightConsensusParamsChanged int64
  65. // Merkle root of the results from executing prev block
  66. LastResultsHash []byte
  67. // the latest AppHash we've received from calling abci.Commit()
  68. AppHash []byte
  69. }
  70. // Copy makes a copy of the State for mutating.
  71. func (state State) Copy() State {
  72. return State{
  73. Version: state.Version,
  74. ChainID: state.ChainID,
  75. LastBlockHeight: state.LastBlockHeight,
  76. LastBlockID: state.LastBlockID,
  77. LastBlockTime: state.LastBlockTime,
  78. NextValidators: state.NextValidators.Copy(),
  79. Validators: state.Validators.Copy(),
  80. LastValidators: state.LastValidators.Copy(),
  81. LastHeightValidatorsChanged: state.LastHeightValidatorsChanged,
  82. ConsensusParams: state.ConsensusParams,
  83. LastHeightConsensusParamsChanged: state.LastHeightConsensusParamsChanged,
  84. AppHash: state.AppHash,
  85. LastResultsHash: state.LastResultsHash,
  86. }
  87. }
  88. // Equals returns true if the States are identical.
  89. func (state State) Equals(state2 State) bool {
  90. sbz, s2bz := state.Bytes(), state2.Bytes()
  91. return bytes.Equal(sbz, s2bz)
  92. }
  93. // Bytes serializes the State using go-amino.
  94. func (state State) Bytes() []byte {
  95. return cdc.MustMarshalBinaryBare(state)
  96. }
  97. // IsEmpty returns true if the State is equal to the empty State.
  98. func (state State) IsEmpty() bool {
  99. return state.Validators == nil // XXX can't compare to Empty
  100. }
  101. //------------------------------------------------------------------------
  102. // Create a block from the latest state
  103. // MakeBlock builds a block from the current state with the given txs, commit,
  104. // and evidence. Note it also takes a proposerAddress because the state does not
  105. // track rounds, and hence does not know the correct proposer. TODO: fix this!
  106. func (state State) MakeBlock(
  107. height int64,
  108. txs []types.Tx,
  109. commit *types.Commit,
  110. evidence []types.Evidence,
  111. proposerAddress []byte,
  112. ) (*types.Block, *types.PartSet) {
  113. // Build base block with block data.
  114. block := types.MakeBlock(height, txs, commit, evidence)
  115. // Set time.
  116. var timestamp time.Time
  117. if height == 1 {
  118. timestamp = state.LastBlockTime // genesis time
  119. } else {
  120. timestamp = MedianTime(commit, state.LastValidators)
  121. }
  122. // Fill rest of header with state data.
  123. block.Header.Populate(
  124. state.Version.Consensus, state.ChainID,
  125. timestamp, state.LastBlockID,
  126. state.Validators.Hash(), state.NextValidators.Hash(),
  127. state.ConsensusParams.Hash(), state.AppHash, state.LastResultsHash,
  128. proposerAddress,
  129. )
  130. return block, block.MakePartSet(types.BlockPartSizeBytes)
  131. }
  132. // MedianTime computes a median time for a given Commit (based on Timestamp field of votes messages) and the
  133. // corresponding validator set. The computed time is always between timestamps of
  134. // the votes sent by honest processes, i.e., a faulty processes can not arbitrarily increase or decrease the
  135. // computed value.
  136. func MedianTime(commit *types.Commit, validators *types.ValidatorSet) time.Time {
  137. weightedTimes := make([]*tmtime.WeightedTime, len(commit.Precommits))
  138. totalVotingPower := int64(0)
  139. for i, vote := range commit.Precommits {
  140. if vote != nil {
  141. _, validator := validators.GetByIndex(vote.ValidatorIndex)
  142. totalVotingPower += validator.VotingPower
  143. weightedTimes[i] = tmtime.NewWeightedTime(vote.Timestamp, validator.VotingPower)
  144. }
  145. }
  146. return tmtime.WeightedMedian(weightedTimes, totalVotingPower)
  147. }
  148. //------------------------------------------------------------------------
  149. // Genesis
  150. // MakeGenesisStateFromFile reads and unmarshals state from the given
  151. // file.
  152. //
  153. // Used during replay and in tests.
  154. func MakeGenesisStateFromFile(genDocFile string) (State, error) {
  155. genDoc, err := MakeGenesisDocFromFile(genDocFile)
  156. if err != nil {
  157. return State{}, err
  158. }
  159. return MakeGenesisState(genDoc)
  160. }
  161. // MakeGenesisDocFromFile reads and unmarshals genesis doc from the given file.
  162. func MakeGenesisDocFromFile(genDocFile string) (*types.GenesisDoc, error) {
  163. genDocJSON, err := ioutil.ReadFile(genDocFile)
  164. if err != nil {
  165. return nil, fmt.Errorf("couldn't read GenesisDoc file: %v", err)
  166. }
  167. genDoc, err := types.GenesisDocFromJSON(genDocJSON)
  168. if err != nil {
  169. return nil, fmt.Errorf("error reading GenesisDoc: %v", err)
  170. }
  171. return genDoc, nil
  172. }
  173. // MakeGenesisState creates state from types.GenesisDoc.
  174. func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
  175. err := genDoc.ValidateAndComplete()
  176. if err != nil {
  177. return State{}, fmt.Errorf("error in genesis file: %v", err)
  178. }
  179. var validatorSet, nextValidatorSet *types.ValidatorSet
  180. if genDoc.Validators == nil {
  181. validatorSet = types.NewValidatorSet(nil)
  182. nextValidatorSet = types.NewValidatorSet(nil)
  183. } else {
  184. validators := make([]*types.Validator, len(genDoc.Validators))
  185. for i, val := range genDoc.Validators {
  186. validators[i] = types.NewValidator(val.PubKey, val.Power)
  187. }
  188. validatorSet = types.NewValidatorSet(validators)
  189. nextValidatorSet = types.NewValidatorSet(validators).CopyIncrementProposerPriority(1)
  190. }
  191. return State{
  192. Version: initStateVersion,
  193. ChainID: genDoc.ChainID,
  194. LastBlockHeight: 0,
  195. LastBlockID: types.BlockID{},
  196. LastBlockTime: genDoc.GenesisTime,
  197. NextValidators: nextValidatorSet,
  198. Validators: validatorSet,
  199. LastValidators: types.NewValidatorSet(nil),
  200. LastHeightValidatorsChanged: 1,
  201. ConsensusParams: *genDoc.ConsensusParams,
  202. LastHeightConsensusParamsChanged: 1,
  203. AppHash: genDoc.AppHash,
  204. }, nil
  205. }