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.

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