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.

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