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.

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