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.

250 lines
7.8 KiB

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