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.

249 lines
7.8 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. LastBlockTotalTx int64
  50. LastBlockID types.BlockID
  51. LastBlockTime time.Time
  52. // LastValidators is used to validate block.LastCommit.
  53. // Validators are persisted to the database separately every time they change,
  54. // so we can query for historical validator sets.
  55. // Note that if s.LastBlockHeight causes a valset change,
  56. // we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1
  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. LastBlockTotalTx: state.LastBlockTotalTx,
  77. LastBlockID: state.LastBlockID,
  78. LastBlockTime: state.LastBlockTime,
  79. NextValidators: state.NextValidators.Copy(),
  80. Validators: state.Validators.Copy(),
  81. LastValidators: state.LastValidators.Copy(),
  82. LastHeightValidatorsChanged: state.LastHeightValidatorsChanged,
  83. ConsensusParams: state.ConsensusParams,
  84. LastHeightConsensusParamsChanged: state.LastHeightConsensusParamsChanged,
  85. AppHash: state.AppHash,
  86. LastResultsHash: state.LastResultsHash,
  87. }
  88. }
  89. // Equals returns true if the States are identical.
  90. func (state State) Equals(state2 State) bool {
  91. sbz, s2bz := state.Bytes(), state2.Bytes()
  92. return bytes.Equal(sbz, s2bz)
  93. }
  94. // Bytes serializes the State using go-amino.
  95. func (state State) Bytes() []byte {
  96. return cdc.MustMarshalBinaryBare(state)
  97. }
  98. // IsEmpty returns true if the State is equal to the empty State.
  99. func (state State) IsEmpty() bool {
  100. return state.Validators == nil // XXX can't compare to Empty
  101. }
  102. //------------------------------------------------------------------------
  103. // Create a block from the latest state
  104. // MakeBlock builds a block from the current state with the given txs, commit,
  105. // and evidence. Note it also takes a proposerAddress because the state does not
  106. // track rounds, and hence does not know the correct proposer. TODO: fix this!
  107. func (state State) MakeBlock(
  108. height int64,
  109. txs []types.Tx,
  110. commit *types.Commit,
  111. evidence []types.Evidence,
  112. proposerAddress []byte,
  113. ) (*types.Block, *types.PartSet) {
  114. // Build base block with block data.
  115. block := types.MakeBlock(height, txs, commit, evidence)
  116. // Set time.
  117. var timestamp time.Time
  118. if height == 1 {
  119. timestamp = state.LastBlockTime // genesis time
  120. } else {
  121. timestamp = MedianTime(commit, state.LastValidators)
  122. }
  123. // Fill rest of header with state data.
  124. block.Header.Populate(
  125. state.Version.Consensus, state.ChainID,
  126. timestamp, state.LastBlockID, state.LastBlockTotalTx+block.NumTxs,
  127. state.Validators.Hash(), state.NextValidators.Hash(),
  128. state.ConsensusParams.Hash(), state.AppHash, state.LastResultsHash,
  129. proposerAddress,
  130. )
  131. return block, block.MakePartSet(types.BlockPartSizeBytes)
  132. }
  133. // MedianTime computes a median time for a given Commit (based on Timestamp field of votes messages) and the
  134. // corresponding validator set. The computed time is always between timestamps of
  135. // the votes sent by honest processes, i.e., a faulty processes can not arbitrarily increase or decrease the
  136. // computed value.
  137. func MedianTime(commit *types.Commit, validators *types.ValidatorSet) time.Time {
  138. weightedTimes := make([]*tmtime.WeightedTime, len(commit.Precommits))
  139. totalVotingPower := int64(0)
  140. for i, vote := range commit.Precommits {
  141. if vote != nil {
  142. _, validator := validators.GetByIndex(vote.ValidatorIndex)
  143. totalVotingPower += validator.VotingPower
  144. weightedTimes[i] = tmtime.NewWeightedTime(vote.Timestamp, validator.VotingPower)
  145. }
  146. }
  147. return tmtime.WeightedMedian(weightedTimes, totalVotingPower)
  148. }
  149. //------------------------------------------------------------------------
  150. // Genesis
  151. // MakeGenesisStateFromFile reads and unmarshals state from the given
  152. // file.
  153. //
  154. // Used during replay and in tests.
  155. func MakeGenesisStateFromFile(genDocFile string) (State, error) {
  156. genDoc, err := MakeGenesisDocFromFile(genDocFile)
  157. if err != nil {
  158. return State{}, err
  159. }
  160. return MakeGenesisState(genDoc)
  161. }
  162. // MakeGenesisDocFromFile reads and unmarshals genesis doc from the given file.
  163. func MakeGenesisDocFromFile(genDocFile string) (*types.GenesisDoc, error) {
  164. genDocJSON, err := ioutil.ReadFile(genDocFile)
  165. if err != nil {
  166. return nil, fmt.Errorf("Couldn't read GenesisDoc file: %v", err)
  167. }
  168. genDoc, err := types.GenesisDocFromJSON(genDocJSON)
  169. if err != nil {
  170. return nil, fmt.Errorf("Error reading GenesisDoc: %v", err)
  171. }
  172. return genDoc, nil
  173. }
  174. // MakeGenesisState creates state from types.GenesisDoc.
  175. func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
  176. err := genDoc.ValidateAndComplete()
  177. if err != nil {
  178. return State{}, fmt.Errorf("Error in genesis file: %v", err)
  179. }
  180. var validatorSet, nextValidatorSet *types.ValidatorSet
  181. if genDoc.Validators == nil {
  182. validatorSet = types.NewValidatorSet(nil)
  183. nextValidatorSet = types.NewValidatorSet(nil)
  184. } else {
  185. validators := make([]*types.Validator, len(genDoc.Validators))
  186. for i, val := range genDoc.Validators {
  187. validators[i] = types.NewValidator(val.PubKey, val.Power)
  188. }
  189. validatorSet = types.NewValidatorSet(validators)
  190. nextValidatorSet = types.NewValidatorSet(validators).CopyIncrementAccum(1)
  191. }
  192. return State{
  193. Version: initStateVersion,
  194. ChainID: genDoc.ChainID,
  195. LastBlockHeight: 0,
  196. LastBlockID: types.BlockID{},
  197. LastBlockTime: genDoc.GenesisTime,
  198. NextValidators: nextValidatorSet,
  199. Validators: validatorSet,
  200. LastValidators: types.NewValidatorSet(nil),
  201. LastHeightValidatorsChanged: 1,
  202. ConsensusParams: *genDoc.ConsensusParams,
  203. LastHeightConsensusParamsChanged: 1,
  204. AppHash: genDoc.AppHash,
  205. }, nil
  206. }