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.

356 lines
11 KiB

10 years ago
8 years ago
7 years ago
8 years ago
8 years ago
  1. package state
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "io/ioutil"
  7. "time"
  8. "github.com/gogo/protobuf/proto"
  9. tmstate "github.com/tendermint/tendermint/proto/tendermint/state"
  10. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  11. tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
  12. "github.com/tendermint/tendermint/types"
  13. tmtime "github.com/tendermint/tendermint/types/time"
  14. "github.com/tendermint/tendermint/version"
  15. )
  16. // database keys
  17. var (
  18. stateKey = []byte("stateKey")
  19. )
  20. //-----------------------------------------------------------------------------
  21. // InitStateVersion sets the Consensus.Block and Software versions,
  22. // but leaves the Consensus.App version blank.
  23. // The Consensus.App version will be set during the Handshake, once
  24. // we hear from the app what protocol version it is running.
  25. var InitStateVersion = tmstate.Version{
  26. Consensus: tmversion.Consensus{
  27. Block: version.BlockProtocol,
  28. App: 0,
  29. },
  30. Software: version.TMCoreSemVer,
  31. }
  32. //-----------------------------------------------------------------------------
  33. // State is a short description of the latest committed block of the Tendermint consensus.
  34. // It keeps all information necessary to validate new blocks,
  35. // including the last validator set and the consensus params.
  36. // All fields are exposed so the struct can be easily serialized,
  37. // but none of them should be mutated directly.
  38. // Instead, use state.Copy() or state.NextState(...).
  39. // NOTE: not goroutine-safe.
  40. type State struct {
  41. Version tmstate.Version
  42. // immutable
  43. ChainID string
  44. InitialHeight int64 // should be 1, not 0, when starting from height 1
  45. // LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
  46. LastBlockHeight int64
  47. LastBlockID types.BlockID
  48. LastBlockTime time.Time
  49. // LastValidators is used to validate block.LastCommit.
  50. // Validators are persisted to the database separately every time they change,
  51. // so we can query for historical validator sets.
  52. // Note that if s.LastBlockHeight causes a valset change,
  53. // we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1 + 1
  54. // Extra +1 due to nextValSet delay.
  55. NextValidators *types.ValidatorSet
  56. Validators *types.ValidatorSet
  57. LastValidators *types.ValidatorSet
  58. LastHeightValidatorsChanged int64
  59. // Consensus parameters used for validating blocks.
  60. // Changes returned by EndBlock and updated after Commit.
  61. ConsensusParams tmproto.ConsensusParams
  62. LastHeightConsensusParamsChanged int64
  63. // Merkle root of the results from executing prev block
  64. LastResultsHash []byte
  65. // the latest AppHash we've received from calling abci.Commit()
  66. AppHash []byte
  67. }
  68. // Copy makes a copy of the State for mutating.
  69. func (state State) Copy() State {
  70. return State{
  71. Version: state.Version,
  72. ChainID: state.ChainID,
  73. InitialHeight: state.InitialHeight,
  74. LastBlockHeight: state.LastBlockHeight,
  75. LastBlockID: state.LastBlockID,
  76. LastBlockTime: state.LastBlockTime,
  77. NextValidators: state.NextValidators.Copy(),
  78. Validators: state.Validators.Copy(),
  79. LastValidators: state.LastValidators.Copy(),
  80. LastHeightValidatorsChanged: state.LastHeightValidatorsChanged,
  81. ConsensusParams: state.ConsensusParams,
  82. LastHeightConsensusParamsChanged: state.LastHeightConsensusParamsChanged,
  83. AppHash: state.AppHash,
  84. LastResultsHash: state.LastResultsHash,
  85. }
  86. }
  87. // Equals returns true if the States are identical.
  88. func (state State) Equals(state2 State) bool {
  89. sbz, s2bz := state.Bytes(), state2.Bytes()
  90. return bytes.Equal(sbz, s2bz)
  91. }
  92. // Bytes serializes the State using protobuf.
  93. // It panics if either casting to protobuf or serialization fails.
  94. func (state State) Bytes() []byte {
  95. sm, err := state.ToProto()
  96. if err != nil {
  97. panic(err)
  98. }
  99. bz, err := proto.Marshal(sm)
  100. if err != nil {
  101. panic(err)
  102. }
  103. return bz
  104. }
  105. // IsEmpty returns true if the State is equal to the empty State.
  106. func (state State) IsEmpty() bool {
  107. return state.Validators == nil // XXX can't compare to Empty
  108. }
  109. // ToProto takes the local state type and returns the equivalent proto type
  110. func (state *State) ToProto() (*tmstate.State, error) {
  111. if state == nil {
  112. return nil, errors.New("state is nil")
  113. }
  114. sm := new(tmstate.State)
  115. sm.Version = state.Version
  116. sm.ChainID = state.ChainID
  117. sm.InitialHeight = state.InitialHeight
  118. sm.LastBlockHeight = state.LastBlockHeight
  119. sm.LastBlockID = state.LastBlockID.ToProto()
  120. sm.LastBlockTime = state.LastBlockTime
  121. vals, err := state.Validators.ToProto()
  122. if err != nil {
  123. return nil, err
  124. }
  125. sm.Validators = vals
  126. nVals, err := state.NextValidators.ToProto()
  127. if err != nil {
  128. return nil, err
  129. }
  130. sm.NextValidators = nVals
  131. if state.LastBlockHeight >= 1 { // At Block 1 LastValidators is nil
  132. lVals, err := state.LastValidators.ToProto()
  133. if err != nil {
  134. return nil, err
  135. }
  136. sm.LastValidators = lVals
  137. }
  138. sm.LastHeightValidatorsChanged = state.LastHeightValidatorsChanged
  139. sm.ConsensusParams = state.ConsensusParams
  140. sm.LastHeightConsensusParamsChanged = state.LastHeightConsensusParamsChanged
  141. sm.LastResultsHash = state.LastResultsHash
  142. sm.AppHash = state.AppHash
  143. return sm, nil
  144. }
  145. // FromProto takes a state proto message & returns the local state type
  146. func FromProto(pb *tmstate.State) (*State, error) { //nolint:golint
  147. if pb == nil {
  148. return nil, errors.New("nil State")
  149. }
  150. state := new(State)
  151. state.Version = pb.Version
  152. state.ChainID = pb.ChainID
  153. state.InitialHeight = pb.InitialHeight
  154. bi, err := types.BlockIDFromProto(&pb.LastBlockID)
  155. if err != nil {
  156. return nil, err
  157. }
  158. state.LastBlockID = *bi
  159. state.LastBlockHeight = pb.LastBlockHeight
  160. state.LastBlockTime = pb.LastBlockTime
  161. vals, err := types.ValidatorSetFromProto(pb.Validators)
  162. if err != nil {
  163. return nil, err
  164. }
  165. state.Validators = vals
  166. nVals, err := types.ValidatorSetFromProto(pb.NextValidators)
  167. if err != nil {
  168. return nil, err
  169. }
  170. state.NextValidators = nVals
  171. if state.LastBlockHeight >= 1 { // At Block 1 LastValidators is nil
  172. lVals, err := types.ValidatorSetFromProto(pb.LastValidators)
  173. if err != nil {
  174. return nil, err
  175. }
  176. state.LastValidators = lVals
  177. } else {
  178. state.LastValidators = types.NewValidatorSet(nil)
  179. }
  180. state.LastHeightValidatorsChanged = pb.LastHeightValidatorsChanged
  181. state.ConsensusParams = pb.ConsensusParams
  182. state.LastHeightConsensusParamsChanged = pb.LastHeightConsensusParamsChanged
  183. state.LastResultsHash = pb.LastResultsHash
  184. state.AppHash = pb.AppHash
  185. return state, nil
  186. }
  187. //------------------------------------------------------------------------
  188. // Create a block from the latest state
  189. // MakeBlock builds a block from the current state with the given txs, commit,
  190. // and evidence. Note it also takes a proposerAddress because the state does not
  191. // track rounds, and hence does not know the correct proposer. TODO: fix this!
  192. func (state State) MakeBlock(
  193. height int64,
  194. txs []types.Tx,
  195. commit *types.Commit,
  196. evidence []types.Evidence,
  197. proposerAddress []byte,
  198. ) (*types.Block, *types.PartSet) {
  199. // Build base block with block data.
  200. block := types.MakeBlock(height, txs, commit, evidence)
  201. // Set time.
  202. var timestamp time.Time
  203. if height == state.InitialHeight {
  204. timestamp = state.LastBlockTime // genesis time
  205. } else {
  206. timestamp = MedianTime(commit, state.LastValidators)
  207. }
  208. // Fill rest of header with state data.
  209. block.Header.Populate(
  210. state.Version.Consensus, state.ChainID,
  211. timestamp, state.LastBlockID,
  212. state.Validators.Hash(), state.NextValidators.Hash(),
  213. types.HashConsensusParams(state.ConsensusParams), state.AppHash, state.LastResultsHash,
  214. proposerAddress,
  215. )
  216. return block, block.MakePartSet(types.BlockPartSizeBytes)
  217. }
  218. // MedianTime computes a median time for a given Commit (based on Timestamp field of votes messages) and the
  219. // corresponding validator set. The computed time is always between timestamps of
  220. // the votes sent by honest processes, i.e., a faulty processes can not arbitrarily increase or decrease the
  221. // computed value.
  222. func MedianTime(commit *types.Commit, validators *types.ValidatorSet) time.Time {
  223. weightedTimes := make([]*tmtime.WeightedTime, len(commit.Signatures))
  224. totalVotingPower := int64(0)
  225. for i, commitSig := range commit.Signatures {
  226. if commitSig.Absent() {
  227. continue
  228. }
  229. _, validator := validators.GetByAddress(commitSig.ValidatorAddress)
  230. // If there's no condition, TestValidateBlockCommit panics; not needed normally.
  231. if validator != nil {
  232. totalVotingPower += validator.VotingPower
  233. weightedTimes[i] = tmtime.NewWeightedTime(commitSig.Timestamp, validator.VotingPower)
  234. }
  235. }
  236. return tmtime.WeightedMedian(weightedTimes, totalVotingPower)
  237. }
  238. //------------------------------------------------------------------------
  239. // Genesis
  240. // MakeGenesisStateFromFile reads and unmarshals state from the given
  241. // file.
  242. //
  243. // Used during replay and in tests.
  244. func MakeGenesisStateFromFile(genDocFile string) (State, error) {
  245. genDoc, err := MakeGenesisDocFromFile(genDocFile)
  246. if err != nil {
  247. return State{}, err
  248. }
  249. return MakeGenesisState(genDoc)
  250. }
  251. // MakeGenesisDocFromFile reads and unmarshals genesis doc from the given file.
  252. func MakeGenesisDocFromFile(genDocFile string) (*types.GenesisDoc, error) {
  253. genDocJSON, err := ioutil.ReadFile(genDocFile)
  254. if err != nil {
  255. return nil, fmt.Errorf("couldn't read GenesisDoc file: %v", err)
  256. }
  257. genDoc, err := types.GenesisDocFromJSON(genDocJSON)
  258. if err != nil {
  259. return nil, fmt.Errorf("error reading GenesisDoc: %v", err)
  260. }
  261. return genDoc, nil
  262. }
  263. // MakeGenesisState creates state from types.GenesisDoc.
  264. func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
  265. err := genDoc.ValidateAndComplete()
  266. if err != nil {
  267. return State{}, fmt.Errorf("error in genesis file: %v", err)
  268. }
  269. var validatorSet, nextValidatorSet *types.ValidatorSet
  270. if genDoc.Validators == nil {
  271. validatorSet = types.NewValidatorSet(nil)
  272. nextValidatorSet = types.NewValidatorSet(nil)
  273. } else {
  274. validators := make([]*types.Validator, len(genDoc.Validators))
  275. for i, val := range genDoc.Validators {
  276. validators[i] = types.NewValidator(val.PubKey, val.Power)
  277. }
  278. validatorSet = types.NewValidatorSet(validators)
  279. nextValidatorSet = types.NewValidatorSet(validators).CopyIncrementProposerPriority(1)
  280. }
  281. return State{
  282. Version: InitStateVersion,
  283. ChainID: genDoc.ChainID,
  284. InitialHeight: genDoc.InitialHeight,
  285. LastBlockHeight: 0,
  286. LastBlockID: types.BlockID{},
  287. LastBlockTime: genDoc.GenesisTime,
  288. NextValidators: nextValidatorSet,
  289. Validators: validatorSet,
  290. LastValidators: types.NewValidatorSet(nil),
  291. LastHeightValidatorsChanged: genDoc.InitialHeight,
  292. ConsensusParams: *genDoc.ConsensusParams,
  293. LastHeightConsensusParamsChanged: genDoc.InitialHeight,
  294. AppHash: genDoc.AppHash,
  295. }, nil
  296. }