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.

353 lines
10 KiB

10 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 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. "os"
  7. "time"
  8. "github.com/gogo/protobuf/proto"
  9. abci "github.com/tendermint/tendermint/abci/types"
  10. tmtime "github.com/tendermint/tendermint/libs/time"
  11. tmstate "github.com/tendermint/tendermint/proto/tendermint/state"
  12. tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
  13. "github.com/tendermint/tendermint/types"
  14. "github.com/tendermint/tendermint/version"
  15. )
  16. //-----------------------------------------------------------------------------
  17. type Version struct {
  18. Consensus version.Consensus ` json:"consensus"`
  19. Software string ` json:"software"`
  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 = Version{
  26. Consensus: version.Consensus{
  27. Block: version.BlockProtocol,
  28. App: 0,
  29. },
  30. Software: version.TMVersion,
  31. }
  32. func (v *Version) ToProto() tmstate.Version {
  33. return tmstate.Version{
  34. Consensus: tmversion.Consensus{
  35. Block: v.Consensus.Block,
  36. App: v.Consensus.App,
  37. },
  38. Software: v.Software,
  39. }
  40. }
  41. func VersionFromProto(v tmstate.Version) Version {
  42. return Version{
  43. Consensus: version.Consensus{
  44. Block: v.Consensus.Block,
  45. App: v.Consensus.App,
  46. },
  47. Software: v.Software,
  48. }
  49. }
  50. //-----------------------------------------------------------------------------
  51. // State is a short description of the latest committed block of the Tendermint consensus.
  52. // It keeps all information necessary to validate new blocks,
  53. // including the last validator set and the consensus params.
  54. // All fields are exposed so the struct can be easily serialized,
  55. // but none of them should be mutated directly.
  56. // Instead, use state.Copy() or updateState(...).
  57. // NOTE: not goroutine-safe.
  58. type State struct {
  59. // FIXME: This can be removed as TMVersion is a constant, and version.Consensus should
  60. // eventually be replaced by VersionParams in ConsensusParams
  61. Version Version
  62. // immutable
  63. ChainID string
  64. InitialHeight int64 // should be 1, not 0, when starting from height 1
  65. // LastBlockHeight=0 at genesis (ie. block(H=0) does not exist)
  66. LastBlockHeight int64
  67. LastBlockID types.BlockID
  68. LastBlockTime time.Time
  69. // LastValidators is used to validate block.LastCommit.
  70. // Validators are persisted to the database separately every time they change,
  71. // so we can query for historical validator sets.
  72. // Note that if s.LastBlockHeight causes a valset change,
  73. // we set s.LastHeightValidatorsChanged = s.LastBlockHeight + 1 + 1
  74. // Extra +1 due to nextValSet delay.
  75. NextValidators *types.ValidatorSet
  76. Validators *types.ValidatorSet
  77. LastValidators *types.ValidatorSet
  78. LastHeightValidatorsChanged int64
  79. // Consensus parameters used for validating blocks.
  80. // Changes returned by FinalizeBlock and updated after Commit.
  81. ConsensusParams types.ConsensusParams
  82. LastHeightConsensusParamsChanged int64
  83. // Merkle root of the results from executing prev block
  84. LastResultsHash []byte
  85. // the latest AppHash we've received from calling abci.Commit()
  86. AppHash []byte
  87. }
  88. // Copy makes a copy of the State for mutating.
  89. func (state State) Copy() State {
  90. return State{
  91. Version: state.Version,
  92. ChainID: state.ChainID,
  93. InitialHeight: state.InitialHeight,
  94. LastBlockHeight: state.LastBlockHeight,
  95. LastBlockID: state.LastBlockID,
  96. LastBlockTime: state.LastBlockTime,
  97. NextValidators: state.NextValidators.Copy(),
  98. Validators: state.Validators.Copy(),
  99. LastValidators: state.LastValidators.Copy(),
  100. LastHeightValidatorsChanged: state.LastHeightValidatorsChanged,
  101. ConsensusParams: state.ConsensusParams,
  102. LastHeightConsensusParamsChanged: state.LastHeightConsensusParamsChanged,
  103. AppHash: state.AppHash,
  104. LastResultsHash: state.LastResultsHash,
  105. }
  106. }
  107. // Equals returns true if the States are identical.
  108. func (state State) Equals(state2 State) bool {
  109. sbz, s2bz := state.Bytes(), state2.Bytes()
  110. return bytes.Equal(sbz, s2bz)
  111. }
  112. // Bytes serializes the State using protobuf.
  113. // It panics if either casting to protobuf or serialization fails.
  114. func (state State) Bytes() []byte {
  115. sm, err := state.ToProto()
  116. if err != nil {
  117. panic(err)
  118. }
  119. bz, err := proto.Marshal(sm)
  120. if err != nil {
  121. panic(err)
  122. }
  123. return bz
  124. }
  125. // IsEmpty returns true if the State is equal to the empty State.
  126. func (state State) IsEmpty() bool {
  127. return state.Validators == nil // XXX can't compare to Empty
  128. }
  129. // ToProto takes the local state type and returns the equivalent proto type
  130. func (state *State) ToProto() (*tmstate.State, error) {
  131. if state == nil {
  132. return nil, errors.New("state is nil")
  133. }
  134. sm := new(tmstate.State)
  135. sm.Version = state.Version.ToProto()
  136. sm.ChainID = state.ChainID
  137. sm.InitialHeight = state.InitialHeight
  138. sm.LastBlockHeight = state.LastBlockHeight
  139. sm.LastBlockID = state.LastBlockID.ToProto()
  140. sm.LastBlockTime = state.LastBlockTime
  141. vals, err := state.Validators.ToProto()
  142. if err != nil {
  143. return nil, err
  144. }
  145. sm.Validators = vals
  146. nVals, err := state.NextValidators.ToProto()
  147. if err != nil {
  148. return nil, err
  149. }
  150. sm.NextValidators = nVals
  151. if state.LastBlockHeight >= 1 { // At Block 1 LastValidators is nil
  152. lVals, err := state.LastValidators.ToProto()
  153. if err != nil {
  154. return nil, err
  155. }
  156. sm.LastValidators = lVals
  157. }
  158. sm.LastHeightValidatorsChanged = state.LastHeightValidatorsChanged
  159. sm.ConsensusParams = state.ConsensusParams.ToProto()
  160. sm.LastHeightConsensusParamsChanged = state.LastHeightConsensusParamsChanged
  161. sm.LastResultsHash = state.LastResultsHash
  162. sm.AppHash = state.AppHash
  163. return sm, nil
  164. }
  165. // FromProto takes a state proto message & returns the local state type
  166. func FromProto(pb *tmstate.State) (*State, error) {
  167. if pb == nil {
  168. return nil, errors.New("nil State")
  169. }
  170. state := new(State)
  171. state.Version = VersionFromProto(pb.Version)
  172. state.ChainID = pb.ChainID
  173. state.InitialHeight = pb.InitialHeight
  174. bi, err := types.BlockIDFromProto(&pb.LastBlockID)
  175. if err != nil {
  176. return nil, err
  177. }
  178. state.LastBlockID = *bi
  179. state.LastBlockHeight = pb.LastBlockHeight
  180. state.LastBlockTime = pb.LastBlockTime
  181. vals, err := types.ValidatorSetFromProto(pb.Validators)
  182. if err != nil {
  183. return nil, err
  184. }
  185. state.Validators = vals
  186. nVals, err := types.ValidatorSetFromProto(pb.NextValidators)
  187. if err != nil {
  188. return nil, err
  189. }
  190. state.NextValidators = nVals
  191. if state.LastBlockHeight >= 1 { // At Block 1 LastValidators is nil
  192. lVals, err := types.ValidatorSetFromProto(pb.LastValidators)
  193. if err != nil {
  194. return nil, err
  195. }
  196. state.LastValidators = lVals
  197. } else {
  198. state.LastValidators = types.NewValidatorSet(nil)
  199. }
  200. state.LastHeightValidatorsChanged = pb.LastHeightValidatorsChanged
  201. state.ConsensusParams = types.ConsensusParamsFromProto(pb.ConsensusParams)
  202. state.LastHeightConsensusParamsChanged = pb.LastHeightConsensusParamsChanged
  203. state.LastResultsHash = pb.LastResultsHash
  204. state.AppHash = pb.AppHash
  205. return state, nil
  206. }
  207. //------------------------------------------------------------------------
  208. // Create a block from the latest state
  209. // MakeBlock builds a block from the current state with the given txs, commit,
  210. // and evidence. Note it also takes a proposerAddress because the state does not
  211. // track rounds, and hence does not know the correct proposer. TODO: fix this!
  212. func (state State) MakeBlock(
  213. height int64,
  214. txs []types.Tx,
  215. commit *types.Commit,
  216. evidence []types.Evidence,
  217. proposerAddress []byte,
  218. ) (*types.Block, error) {
  219. // Build base block with block data.
  220. block := types.MakeBlock(height, txs, commit, evidence)
  221. // Fill rest of header with state data.
  222. block.Header.Populate(
  223. state.Version.Consensus, state.ChainID,
  224. tmtime.Now(), state.LastBlockID,
  225. state.Validators.Hash(), state.NextValidators.Hash(),
  226. state.ConsensusParams.HashConsensusParams(), state.AppHash, state.LastResultsHash,
  227. proposerAddress,
  228. )
  229. return block, nil
  230. }
  231. func (state State) BlockFromResponsePrepareProposal(height int64, rpp *abci.ResponsePrepareProposal) (*types.Block, error) {
  232. // TODO: Implement logic create new block.
  233. return &types.Block{}, nil
  234. }
  235. //------------------------------------------------------------------------
  236. // Genesis
  237. // MakeGenesisStateFromFile reads and unmarshals state from the given
  238. // file.
  239. //
  240. // Used during replay and in tests.
  241. func MakeGenesisStateFromFile(genDocFile string) (State, error) {
  242. genDoc, err := MakeGenesisDocFromFile(genDocFile)
  243. if err != nil {
  244. return State{}, err
  245. }
  246. return MakeGenesisState(genDoc)
  247. }
  248. // MakeGenesisDocFromFile reads and unmarshals genesis doc from the given file.
  249. func MakeGenesisDocFromFile(genDocFile string) (*types.GenesisDoc, error) {
  250. genDocJSON, err := os.ReadFile(genDocFile)
  251. if err != nil {
  252. return nil, fmt.Errorf("couldn't read GenesisDoc file: %w", err)
  253. }
  254. genDoc, err := types.GenesisDocFromJSON(genDocJSON)
  255. if err != nil {
  256. return nil, fmt.Errorf("error reading GenesisDoc: %w", err)
  257. }
  258. return genDoc, nil
  259. }
  260. // MakeGenesisState creates state from types.GenesisDoc.
  261. func MakeGenesisState(genDoc *types.GenesisDoc) (State, error) {
  262. err := genDoc.ValidateAndComplete()
  263. if err != nil {
  264. return State{}, fmt.Errorf("error in genesis doc: %w", err)
  265. }
  266. var validatorSet, nextValidatorSet *types.ValidatorSet
  267. if genDoc.Validators == nil || len(genDoc.Validators) == 0 {
  268. validatorSet = types.NewValidatorSet(nil)
  269. nextValidatorSet = types.NewValidatorSet(nil)
  270. } else {
  271. validators := make([]*types.Validator, len(genDoc.Validators))
  272. for i, val := range genDoc.Validators {
  273. validators[i] = types.NewValidator(val.PubKey, val.Power)
  274. }
  275. validatorSet = types.NewValidatorSet(validators)
  276. nextValidatorSet = types.NewValidatorSet(validators).CopyIncrementProposerPriority(1)
  277. }
  278. return State{
  279. Version: InitStateVersion,
  280. ChainID: genDoc.ChainID,
  281. InitialHeight: genDoc.InitialHeight,
  282. LastBlockHeight: 0,
  283. LastBlockID: types.BlockID{},
  284. LastBlockTime: genDoc.GenesisTime,
  285. NextValidators: nextValidatorSet,
  286. Validators: validatorSet,
  287. LastValidators: types.NewValidatorSet(nil),
  288. LastHeightValidatorsChanged: genDoc.InitialHeight,
  289. ConsensusParams: *genDoc.ConsensusParams,
  290. LastHeightConsensusParamsChanged: genDoc.InitialHeight,
  291. AppHash: genDoc.AppHash,
  292. }, nil
  293. }