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.

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