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.

256 lines
8.0 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 doesn't know the correct proposer. TODO: alleviate 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. // Fill rest of header with state data.
  117. block.Version = state.Version.Consensus
  118. block.ChainID = state.ChainID
  119. // Set time
  120. if height == 1 {
  121. block.Time = state.LastBlockTime // genesis time
  122. } else {
  123. block.Time = MedianTime(commit, state.LastValidators)
  124. }
  125. block.LastBlockID = state.LastBlockID
  126. block.TotalTxs = state.LastBlockTotalTx + block.NumTxs
  127. block.ValidatorsHash = state.Validators.Hash()
  128. block.NextValidatorsHash = state.NextValidators.Hash()
  129. block.ConsensusHash = state.ConsensusParams.Hash()
  130. block.AppHash = state.AppHash
  131. block.LastResultsHash = state.LastResultsHash
  132. // NOTE: we can't use the state.Validators because we don't
  133. // IncrementAccum for rounds there.
  134. block.ProposerAddress = proposerAddress
  135. return block, block.MakePartSet(types.BlockPartSizeBytes)
  136. }
  137. // MedianTime computes a median time for a given Commit (based on Timestamp field of votes messages) and the
  138. // corresponding validator set. The computed time is always between timestamps of
  139. // the votes sent by honest processes, i.e., a faulty processes can not arbitrarily increase or decrease the
  140. // computed value.
  141. func MedianTime(commit *types.Commit, validators *types.ValidatorSet) time.Time {
  142. weightedTimes := make([]*tmtime.WeightedTime, len(commit.Precommits))
  143. totalVotingPower := int64(0)
  144. for i, vote := range commit.Precommits {
  145. if vote != nil {
  146. _, validator := validators.GetByIndex(vote.ValidatorIndex)
  147. totalVotingPower += validator.VotingPower
  148. weightedTimes[i] = tmtime.NewWeightedTime(vote.Timestamp, validator.VotingPower)
  149. }
  150. }
  151. return tmtime.WeightedMedian(weightedTimes, totalVotingPower)
  152. }
  153. //------------------------------------------------------------------------
  154. // Genesis
  155. // MakeGenesisStateFromFile reads and unmarshals state from the given
  156. // file.
  157. //
  158. // Used during replay and in tests.
  159. func MakeGenesisStateFromFile(genDocFile string) (State, error) {
  160. genDoc, err := MakeGenesisDocFromFile(genDocFile)
  161. if err != nil {
  162. return State{}, err
  163. }
  164. return MakeGenesisState(genDoc)
  165. }
  166. // MakeGenesisDocFromFile reads and unmarshals genesis doc from the given file.
  167. func MakeGenesisDocFromFile(genDocFile string) (*types.GenesisDoc, error) {
  168. genDocJSON, err := ioutil.ReadFile(genDocFile)
  169. if err != nil {
  170. return nil, fmt.Errorf("Couldn't read GenesisDoc file: %v", err)
  171. }
  172. genDoc, err := types.GenesisDocFromJSON(genDocJSON)
  173. if err != nil {
  174. return nil, fmt.Errorf("Error reading GenesisDoc: %v", err)
  175. }
  176. return genDoc, nil
  177. }
  178. // MakeGenesisState creates state from types.GenesisDoc.
  179. func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
  180. err := genDoc.ValidateAndComplete()
  181. if err != nil {
  182. return State{}, fmt.Errorf("Error in genesis file: %v", err)
  183. }
  184. var validatorSet, nextValidatorSet *types.ValidatorSet
  185. if genDoc.Validators == nil {
  186. validatorSet = types.NewValidatorSet(nil)
  187. nextValidatorSet = types.NewValidatorSet(nil)
  188. } else {
  189. validators := make([]*types.Validator, len(genDoc.Validators))
  190. for i, val := range genDoc.Validators {
  191. validators[i] = types.NewValidator(val.PubKey, val.Power)
  192. }
  193. validatorSet = types.NewValidatorSet(validators)
  194. nextValidatorSet = types.NewValidatorSet(validators).CopyIncrementAccum(1)
  195. }
  196. return State{
  197. Version: initStateVersion,
  198. ChainID: genDoc.ChainID,
  199. LastBlockHeight: 0,
  200. LastBlockID: types.BlockID{},
  201. LastBlockTime: genDoc.GenesisTime,
  202. NextValidators: nextValidatorSet,
  203. Validators: validatorSet,
  204. LastValidators: types.NewValidatorSet(nil),
  205. LastHeightValidatorsChanged: 1,
  206. ConsensusParams: *genDoc.ConsensusParams,
  207. LastHeightConsensusParamsChanged: 1,
  208. AppHash: genDoc.AppHash,
  209. }, nil
  210. }