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.

681 lines
21 KiB

cleanup: Reduce and normalize import path aliasing. (#6975) The code in the Tendermint repository makes heavy use of import aliasing. This is made necessary by our extensive reuse of common base package names, and by repetition of similar names across different subdirectories. Unfortunately we have not been very consistent about which packages we alias in various circumstances, and the aliases we use vary. In the spirit of the advice in the style guide and https://github.com/golang/go/wiki/CodeReviewComments#imports, his change makes an effort to clean up and normalize import aliasing. This change makes no API or behavioral changes. It is a pure cleanup intended o help make the code more readable to developers (including myself) trying to understand what is being imported where. Only unexported names have been modified, and the changes were generated and applied mechanically with gofmt -r and comby, respecting the lexical and syntactic rules of Go. Even so, I did not fix every inconsistency. Where the changes would be too disruptive, I left it alone. The principles I followed in this cleanup are: - Remove aliases that restate the package name. - Remove aliases where the base package name is unambiguous. - Move overly-terse abbreviations from the import to the usage site. - Fix lexical issues (remove underscores, remove capitalization). - Fix import groupings to more closely match the style guide. - Group blank (side-effecting) imports and ensure they are commented. - Add aliases to multiple imports with the same base package name.
3 years ago
cleanup: Reduce and normalize import path aliasing. (#6975) The code in the Tendermint repository makes heavy use of import aliasing. This is made necessary by our extensive reuse of common base package names, and by repetition of similar names across different subdirectories. Unfortunately we have not been very consistent about which packages we alias in various circumstances, and the aliases we use vary. In the spirit of the advice in the style guide and https://github.com/golang/go/wiki/CodeReviewComments#imports, his change makes an effort to clean up and normalize import aliasing. This change makes no API or behavioral changes. It is a pure cleanup intended o help make the code more readable to developers (including myself) trying to understand what is being imported where. Only unexported names have been modified, and the changes were generated and applied mechanically with gofmt -r and comby, respecting the lexical and syntactic rules of Go. Even so, I did not fix every inconsistency. Where the changes would be too disruptive, I left it alone. The principles I followed in this cleanup are: - Remove aliases that restate the package name. - Remove aliases where the base package name is unambiguous. - Move overly-terse abbreviations from the import to the usage site. - Fix lexical issues (remove underscores, remove capitalization). - Fix import groupings to more closely match the style guide. - Group blank (side-effecting) imports and ensure they are commented. - Add aliases to multiple imports with the same base package name.
3 years ago
cleanup: Reduce and normalize import path aliasing. (#6975) The code in the Tendermint repository makes heavy use of import aliasing. This is made necessary by our extensive reuse of common base package names, and by repetition of similar names across different subdirectories. Unfortunately we have not been very consistent about which packages we alias in various circumstances, and the aliases we use vary. In the spirit of the advice in the style guide and https://github.com/golang/go/wiki/CodeReviewComments#imports, his change makes an effort to clean up and normalize import aliasing. This change makes no API or behavioral changes. It is a pure cleanup intended o help make the code more readable to developers (including myself) trying to understand what is being imported where. Only unexported names have been modified, and the changes were generated and applied mechanically with gofmt -r and comby, respecting the lexical and syntactic rules of Go. Even so, I did not fix every inconsistency. Where the changes would be too disruptive, I left it alone. The principles I followed in this cleanup are: - Remove aliases that restate the package name. - Remove aliases where the base package name is unambiguous. - Move overly-terse abbreviations from the import to the usage site. - Fix lexical issues (remove underscores, remove capitalization). - Fix import groupings to more closely match the style guide. - Group blank (side-effecting) imports and ensure they are commented. - Add aliases to multiple imports with the same base package name.
3 years ago
cleanup: Reduce and normalize import path aliasing. (#6975) The code in the Tendermint repository makes heavy use of import aliasing. This is made necessary by our extensive reuse of common base package names, and by repetition of similar names across different subdirectories. Unfortunately we have not been very consistent about which packages we alias in various circumstances, and the aliases we use vary. In the spirit of the advice in the style guide and https://github.com/golang/go/wiki/CodeReviewComments#imports, his change makes an effort to clean up and normalize import aliasing. This change makes no API or behavioral changes. It is a pure cleanup intended o help make the code more readable to developers (including myself) trying to understand what is being imported where. Only unexported names have been modified, and the changes were generated and applied mechanically with gofmt -r and comby, respecting the lexical and syntactic rules of Go. Even so, I did not fix every inconsistency. Where the changes would be too disruptive, I left it alone. The principles I followed in this cleanup are: - Remove aliases that restate the package name. - Remove aliases where the base package name is unambiguous. - Move overly-terse abbreviations from the import to the usage site. - Fix lexical issues (remove underscores, remove capitalization). - Fix import groupings to more closely match the style guide. - Group blank (side-effecting) imports and ensure they are commented. - Add aliases to multiple imports with the same base package name.
3 years ago
cleanup: Reduce and normalize import path aliasing. (#6975) The code in the Tendermint repository makes heavy use of import aliasing. This is made necessary by our extensive reuse of common base package names, and by repetition of similar names across different subdirectories. Unfortunately we have not been very consistent about which packages we alias in various circumstances, and the aliases we use vary. In the spirit of the advice in the style guide and https://github.com/golang/go/wiki/CodeReviewComments#imports, his change makes an effort to clean up and normalize import aliasing. This change makes no API or behavioral changes. It is a pure cleanup intended o help make the code more readable to developers (including myself) trying to understand what is being imported where. Only unexported names have been modified, and the changes were generated and applied mechanically with gofmt -r and comby, respecting the lexical and syntactic rules of Go. Even so, I did not fix every inconsistency. Where the changes would be too disruptive, I left it alone. The principles I followed in this cleanup are: - Remove aliases that restate the package name. - Remove aliases where the base package name is unambiguous. - Move overly-terse abbreviations from the import to the usage site. - Fix lexical issues (remove underscores, remove capitalization). - Fix import groupings to more closely match the style guide. - Group blank (side-effecting) imports and ensure they are commented. - Add aliases to multiple imports with the same base package name.
3 years ago
cs/replay: execCommitBlock should not read from state.lastValidators (#3067) * execCommitBlock should not read from state.lastValidators * fix height 1 * fix blockchain/reactor_test * fix consensus/mempool_test * fix consensus/reactor_test * fix consensus/replay_test * add CHANGELOG * fix consensus/reactor_test * fix consensus/replay_test * add a test for replay validators change * fix mem_pool test * fix byzantine test * remove a redundant code * reduce validator change blocks to 6 * fix * return peer0 config * seperate testName * seperate testName 1 * seperate testName 2 * seperate app db path * seperate app db path 1 * add a lock before startNet * move the lock to reactor_test * simulate just once * try to find problem * handshake only saveState when app version changed * update gometalinter to 3.0.0 (#3233) in the attempt to fix https://circleci.com/gh/tendermint/tendermint/43165 also code is simplified by running gofmt -s . remove unused vars enable linters we're currently passing remove deprecated linters (cherry picked from commit d47094550315c094512a242445e0dde24b5a03f5) * gofmt code * goimport code * change the bool name to testValidatorsChange * adjust receive kvstore.ProtocolVersion * adjust receive kvstore.ProtocolVersion 1 * adjust receive kvstore.ProtocolVersion 3 * fix merge execution.go * fix merge develop * fix merge develop 1 * fix run cleanupFunc * adjust code according to reviewers' opinion * modify the func name match the convention * simplify simulate a chain containing some validator change txs 1 * test CI error * Merge remote-tracking branch 'upstream/develop' into fixReplay 1 * fix pubsub_test * subscribeUnbuffered vote channel
6 years ago
7 years ago
add support for block pruning via ABCI Commit response (#4588) * Added BlockStore.DeleteBlock() * Added initial block pruner prototype * wip * Added BlockStore.PruneBlocks() * Added consensus setting for block pruning * Added BlockStore base * Error on replay if base does not have blocks * Handle missing blocks when sending VoteSetMaj23Message * Error message tweak * Properly update blockstore state * Error message fix again * blockchain: ignore peer missing blocks * Added FIXME * Added test for block replay with truncated history * Handle peer base in blockchain reactor * Improved replay error handling * Added tests for Store.PruneBlocks() * Fix non-RPC handling of truncated block history * Panic on missing block meta in needProofBlock() * Updated changelog * Handle truncated block history in RPC layer * Added info about earliest block in /status RPC * Reorder height and base in blockchain reactor messages * Updated changelog * Fix tests * Appease linter * Minor review fixes * Non-empty BlockStores should always have base > 0 * Update code to assume base > 0 invariant * Added blockstore tests for pruning to 0 * Make sure we don't prune below the current base * Added BlockStore.Size() * config: added retain_blocks recommendations * Update v1 blockchain reactor to handle blockstore base * Added state database pruning * Propagate errors on missing validator sets * Comment tweaks * Improved error message Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * use ABCI field ResponseCommit.retain_height instead of retain-blocks config option * remove State.RetainHeight, return value instead * fix minor issues * rename pruneHeights() to pruneBlocks() * noop to fix GitHub borkage Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
add support for block pruning via ABCI Commit response (#4588) * Added BlockStore.DeleteBlock() * Added initial block pruner prototype * wip * Added BlockStore.PruneBlocks() * Added consensus setting for block pruning * Added BlockStore base * Error on replay if base does not have blocks * Handle missing blocks when sending VoteSetMaj23Message * Error message tweak * Properly update blockstore state * Error message fix again * blockchain: ignore peer missing blocks * Added FIXME * Added test for block replay with truncated history * Handle peer base in blockchain reactor * Improved replay error handling * Added tests for Store.PruneBlocks() * Fix non-RPC handling of truncated block history * Panic on missing block meta in needProofBlock() * Updated changelog * Handle truncated block history in RPC layer * Added info about earliest block in /status RPC * Reorder height and base in blockchain reactor messages * Updated changelog * Fix tests * Appease linter * Minor review fixes * Non-empty BlockStores should always have base > 0 * Update code to assume base > 0 invariant * Added blockstore tests for pruning to 0 * Make sure we don't prune below the current base * Added BlockStore.Size() * config: added retain_blocks recommendations * Update v1 blockchain reactor to handle blockstore base * Added state database pruning * Propagate errors on missing validator sets * Comment tweaks * Improved error message Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * use ABCI field ResponseCommit.retain_height instead of retain-blocks config option * remove State.RetainHeight, return value instead * fix minor issues * rename pruneHeights() to pruneBlocks() * noop to fix GitHub borkage Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
add support for block pruning via ABCI Commit response (#4588) * Added BlockStore.DeleteBlock() * Added initial block pruner prototype * wip * Added BlockStore.PruneBlocks() * Added consensus setting for block pruning * Added BlockStore base * Error on replay if base does not have blocks * Handle missing blocks when sending VoteSetMaj23Message * Error message tweak * Properly update blockstore state * Error message fix again * blockchain: ignore peer missing blocks * Added FIXME * Added test for block replay with truncated history * Handle peer base in blockchain reactor * Improved replay error handling * Added tests for Store.PruneBlocks() * Fix non-RPC handling of truncated block history * Panic on missing block meta in needProofBlock() * Updated changelog * Handle truncated block history in RPC layer * Added info about earliest block in /status RPC * Reorder height and base in blockchain reactor messages * Updated changelog * Fix tests * Appease linter * Minor review fixes * Non-empty BlockStores should always have base > 0 * Update code to assume base > 0 invariant * Added blockstore tests for pruning to 0 * Make sure we don't prune below the current base * Added BlockStore.Size() * config: added retain_blocks recommendations * Update v1 blockchain reactor to handle blockstore base * Added state database pruning * Propagate errors on missing validator sets * Comment tweaks * Improved error message Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * use ABCI field ResponseCommit.retain_height instead of retain-blocks config option * remove State.RetainHeight, return value instead * fix minor issues * rename pruneHeights() to pruneBlocks() * noop to fix GitHub borkage Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
add support for block pruning via ABCI Commit response (#4588) * Added BlockStore.DeleteBlock() * Added initial block pruner prototype * wip * Added BlockStore.PruneBlocks() * Added consensus setting for block pruning * Added BlockStore base * Error on replay if base does not have blocks * Handle missing blocks when sending VoteSetMaj23Message * Error message tweak * Properly update blockstore state * Error message fix again * blockchain: ignore peer missing blocks * Added FIXME * Added test for block replay with truncated history * Handle peer base in blockchain reactor * Improved replay error handling * Added tests for Store.PruneBlocks() * Fix non-RPC handling of truncated block history * Panic on missing block meta in needProofBlock() * Updated changelog * Handle truncated block history in RPC layer * Added info about earliest block in /status RPC * Reorder height and base in blockchain reactor messages * Updated changelog * Fix tests * Appease linter * Minor review fixes * Non-empty BlockStores should always have base > 0 * Update code to assume base > 0 invariant * Added blockstore tests for pruning to 0 * Make sure we don't prune below the current base * Added BlockStore.Size() * config: added retain_blocks recommendations * Update v1 blockchain reactor to handle blockstore base * Added state database pruning * Propagate errors on missing validator sets * Comment tweaks * Improved error message Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * use ABCI field ResponseCommit.retain_height instead of retain-blocks config option * remove State.RetainHeight, return value instead * fix minor issues * rename pruneHeights() to pruneBlocks() * noop to fix GitHub borkage Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
add support for block pruning via ABCI Commit response (#4588) * Added BlockStore.DeleteBlock() * Added initial block pruner prototype * wip * Added BlockStore.PruneBlocks() * Added consensus setting for block pruning * Added BlockStore base * Error on replay if base does not have blocks * Handle missing blocks when sending VoteSetMaj23Message * Error message tweak * Properly update blockstore state * Error message fix again * blockchain: ignore peer missing blocks * Added FIXME * Added test for block replay with truncated history * Handle peer base in blockchain reactor * Improved replay error handling * Added tests for Store.PruneBlocks() * Fix non-RPC handling of truncated block history * Panic on missing block meta in needProofBlock() * Updated changelog * Handle truncated block history in RPC layer * Added info about earliest block in /status RPC * Reorder height and base in blockchain reactor messages * Updated changelog * Fix tests * Appease linter * Minor review fixes * Non-empty BlockStores should always have base > 0 * Update code to assume base > 0 invariant * Added blockstore tests for pruning to 0 * Make sure we don't prune below the current base * Added BlockStore.Size() * config: added retain_blocks recommendations * Update v1 blockchain reactor to handle blockstore base * Added state database pruning * Propagate errors on missing validator sets * Comment tweaks * Improved error message Co-Authored-By: Anton Kaliaev <anton.kalyaev@gmail.com> * use ABCI field ResponseCommit.retain_height instead of retain-blocks config option * remove State.RetainHeight, return value instead * fix minor issues * rename pruneHeights() to pruneBlocks() * noop to fix GitHub borkage Co-authored-by: Anton Kaliaev <anton.kalyaev@gmail.com>
5 years ago
8 years ago
8 years ago
cs/replay: execCommitBlock should not read from state.lastValidators (#3067) * execCommitBlock should not read from state.lastValidators * fix height 1 * fix blockchain/reactor_test * fix consensus/mempool_test * fix consensus/reactor_test * fix consensus/replay_test * add CHANGELOG * fix consensus/reactor_test * fix consensus/replay_test * add a test for replay validators change * fix mem_pool test * fix byzantine test * remove a redundant code * reduce validator change blocks to 6 * fix * return peer0 config * seperate testName * seperate testName 1 * seperate testName 2 * seperate app db path * seperate app db path 1 * add a lock before startNet * move the lock to reactor_test * simulate just once * try to find problem * handshake only saveState when app version changed * update gometalinter to 3.0.0 (#3233) in the attempt to fix https://circleci.com/gh/tendermint/tendermint/43165 also code is simplified by running gofmt -s . remove unused vars enable linters we're currently passing remove deprecated linters (cherry picked from commit d47094550315c094512a242445e0dde24b5a03f5) * gofmt code * goimport code * change the bool name to testValidatorsChange * adjust receive kvstore.ProtocolVersion * adjust receive kvstore.ProtocolVersion 1 * adjust receive kvstore.ProtocolVersion 3 * fix merge execution.go * fix merge develop * fix merge develop 1 * fix run cleanupFunc * adjust code according to reviewers' opinion * modify the func name match the convention * simplify simulate a chain containing some validator change txs 1 * test CI error * Merge remote-tracking branch 'upstream/develop' into fixReplay 1 * fix pubsub_test * subscribeUnbuffered vote channel
6 years ago
cleanup: Reduce and normalize import path aliasing. (#6975) The code in the Tendermint repository makes heavy use of import aliasing. This is made necessary by our extensive reuse of common base package names, and by repetition of similar names across different subdirectories. Unfortunately we have not been very consistent about which packages we alias in various circumstances, and the aliases we use vary. In the spirit of the advice in the style guide and https://github.com/golang/go/wiki/CodeReviewComments#imports, his change makes an effort to clean up and normalize import aliasing. This change makes no API or behavioral changes. It is a pure cleanup intended o help make the code more readable to developers (including myself) trying to understand what is being imported where. Only unexported names have been modified, and the changes were generated and applied mechanically with gofmt -r and comby, respecting the lexical and syntactic rules of Go. Even so, I did not fix every inconsistency. Where the changes would be too disruptive, I left it alone. The principles I followed in this cleanup are: - Remove aliases that restate the package name. - Remove aliases where the base package name is unambiguous. - Move overly-terse abbreviations from the import to the usage site. - Fix lexical issues (remove underscores, remove capitalization). - Fix import groupings to more closely match the style guide. - Group blank (side-effecting) imports and ensure they are commented. - Add aliases to multiple imports with the same base package name.
3 years ago
8 years ago
7 years ago
8 years ago
  1. package state
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "time"
  7. abci "github.com/tendermint/tendermint/abci/types"
  8. "github.com/tendermint/tendermint/crypto/encoding"
  9. "github.com/tendermint/tendermint/internal/eventbus"
  10. "github.com/tendermint/tendermint/internal/mempool"
  11. "github.com/tendermint/tendermint/internal/proxy"
  12. "github.com/tendermint/tendermint/libs/log"
  13. tmstate "github.com/tendermint/tendermint/proto/tendermint/state"
  14. "github.com/tendermint/tendermint/types"
  15. )
  16. //-----------------------------------------------------------------------------
  17. // BlockExecutor handles block execution and state updates.
  18. // It exposes ApplyBlock(), which validates & executes the block, updates state w/ ABCI responses,
  19. // then commits and updates the mempool atomically, then saves state.
  20. // BlockExecutor provides the context and accessories for properly executing a block.
  21. type BlockExecutor struct {
  22. // save state, validators, consensus params, abci responses here
  23. store Store
  24. // use blockstore for the pruning functions.
  25. blockStore BlockStore
  26. // execute the app against this
  27. proxyApp proxy.AppConnConsensus
  28. // events
  29. eventBus types.BlockEventPublisher
  30. // manage the mempool lock during commit
  31. // and update both with block results after commit.
  32. mempool mempool.Mempool
  33. evpool EvidencePool
  34. logger log.Logger
  35. metrics *Metrics
  36. // cache the verification results over a single height
  37. cache map[string]struct{}
  38. }
  39. type BlockExecutorOption func(executor *BlockExecutor)
  40. func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption {
  41. return func(blockExec *BlockExecutor) {
  42. blockExec.metrics = metrics
  43. }
  44. }
  45. // NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
  46. // Call SetEventBus to provide one.
  47. func NewBlockExecutor(
  48. stateStore Store,
  49. logger log.Logger,
  50. proxyApp proxy.AppConnConsensus,
  51. pool mempool.Mempool,
  52. evpool EvidencePool,
  53. blockStore BlockStore,
  54. options ...BlockExecutorOption,
  55. ) *BlockExecutor {
  56. res := &BlockExecutor{
  57. store: stateStore,
  58. proxyApp: proxyApp,
  59. eventBus: eventbus.NopEventBus{},
  60. mempool: pool,
  61. evpool: evpool,
  62. logger: logger,
  63. metrics: NopMetrics(),
  64. cache: make(map[string]struct{}),
  65. blockStore: blockStore,
  66. }
  67. for _, option := range options {
  68. option(res)
  69. }
  70. return res
  71. }
  72. func (blockExec *BlockExecutor) Store() Store {
  73. return blockExec.store
  74. }
  75. // SetEventBus - sets the event bus for publishing block related events.
  76. // If not called, it defaults to types.NopEventBus.
  77. func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) {
  78. blockExec.eventBus = eventBus
  79. }
  80. // CreateProposalBlock calls state.MakeBlock with evidence from the evpool
  81. // and txs from the mempool. The max bytes must be big enough to fit the commit.
  82. // Up to 1/10th of the block space is allcoated for maximum sized evidence.
  83. // The rest is given to txs, up to the max gas.
  84. //
  85. // Contract: application will not return more bytes than are sent over the wire.
  86. func (blockExec *BlockExecutor) CreateProposalBlock(
  87. ctx context.Context,
  88. height int64,
  89. state State, commit *types.Commit,
  90. proposerAddr []byte,
  91. votes []*types.Vote,
  92. ) (*types.Block, *types.PartSet, error) {
  93. maxBytes := state.ConsensusParams.Block.MaxBytes
  94. maxGas := state.ConsensusParams.Block.MaxGas
  95. evidence, evSize := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
  96. // Fetch a limited amount of valid txs
  97. maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size())
  98. txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas)
  99. preparedProposal, err := blockExec.proxyApp.PrepareProposal(
  100. ctx,
  101. abci.RequestPrepareProposal{
  102. BlockData: txs.ToSliceOfBytes(),
  103. BlockDataSize: maxDataBytes,
  104. Votes: types.VotesToProto(votes),
  105. },
  106. )
  107. if err != nil {
  108. // The App MUST ensure that only valid (and hence 'processable') transactions
  109. // enter the mempool. Hence, at this point, we can't have any non-processable
  110. // transaction causing an error.
  111. //
  112. // Also, the App can simply skip any transaction that could cause any kind of trouble.
  113. // Either way, we can not recover in a meaningful way, unless we skip proposing
  114. // this block, repair what caused the error and try again. Hence, we panic on
  115. // purpose for now.
  116. panic(err)
  117. }
  118. newTxs := preparedProposal.GetBlockData()
  119. var txSize int
  120. for _, tx := range newTxs {
  121. txSize += len(tx)
  122. if maxDataBytes < int64(txSize) {
  123. panic("block data exceeds max amount of allowed bytes")
  124. }
  125. }
  126. modifiedTxs := types.ToTxs(preparedProposal.GetBlockData())
  127. return state.MakeBlock(height, modifiedTxs, commit, evidence, proposerAddr)
  128. }
  129. func (blockExec *BlockExecutor) ProcessProposal(
  130. ctx context.Context,
  131. block *types.Block,
  132. state State,
  133. ) (bool, error) {
  134. req := abci.RequestProcessProposal{
  135. Hash: block.Header.Hash(),
  136. Header: *block.Header.ToProto(),
  137. Txs: block.Data.Txs.ToSliceOfBytes(),
  138. LastCommitInfo: buildLastCommitInfo(block, blockExec.store, state.InitialHeight),
  139. ByzantineValidators: block.Evidence.ToABCI(),
  140. }
  141. resp, err := blockExec.proxyApp.ProcessProposal(ctx, req)
  142. if err != nil {
  143. return false, ErrInvalidBlock(err)
  144. }
  145. return resp.Accept, nil
  146. }
  147. // ValidateBlock validates the given block against the given state.
  148. // If the block is invalid, it returns an error.
  149. // Validation does not mutate state, but does require historical information from the stateDB,
  150. // ie. to verify evidence from a validator at an old height.
  151. func (blockExec *BlockExecutor) ValidateBlock(ctx context.Context, state State, block *types.Block) error {
  152. hash := block.Hash()
  153. if _, ok := blockExec.cache[hash.String()]; ok {
  154. return nil
  155. }
  156. err := validateBlock(state, block)
  157. if err != nil {
  158. return err
  159. }
  160. err = blockExec.evpool.CheckEvidence(ctx, block.Evidence)
  161. if err != nil {
  162. return err
  163. }
  164. blockExec.cache[hash.String()] = struct{}{}
  165. return nil
  166. }
  167. // ApplyBlock validates the block against the state, executes it against the app,
  168. // fires the relevant events, commits the app, and saves the new state and responses.
  169. // It returns the new state.
  170. // It's the only function that needs to be called
  171. // from outside this package to process and commit an entire block.
  172. // It takes a blockID to avoid recomputing the parts hash.
  173. func (blockExec *BlockExecutor) ApplyBlock(
  174. ctx context.Context,
  175. state State,
  176. blockID types.BlockID,
  177. block *types.Block,
  178. ) (State, error) {
  179. // validate the block if we haven't already
  180. if err := blockExec.ValidateBlock(ctx, state, block); err != nil {
  181. return state, ErrInvalidBlock(err)
  182. }
  183. startTime := time.Now().UnixNano()
  184. abciResponses, err := execBlockOnProxyApp(ctx,
  185. blockExec.logger, blockExec.proxyApp, block, blockExec.store, state.InitialHeight,
  186. )
  187. endTime := time.Now().UnixNano()
  188. blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000)
  189. if err != nil {
  190. return state, ErrProxyAppConn(err)
  191. }
  192. // Save the results before we commit.
  193. if err := blockExec.store.SaveABCIResponses(block.Height, abciResponses); err != nil {
  194. return state, err
  195. }
  196. // validate the validator updates and convert to tendermint types
  197. abciValUpdates := abciResponses.FinalizeBlock.ValidatorUpdates
  198. err = validateValidatorUpdates(abciValUpdates, state.ConsensusParams.Validator)
  199. if err != nil {
  200. return state, fmt.Errorf("error in validator updates: %w", err)
  201. }
  202. validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates)
  203. if err != nil {
  204. return state, err
  205. }
  206. if len(validatorUpdates) > 0 {
  207. blockExec.logger.Debug("updates to validators", "updates", types.ValidatorListString(validatorUpdates))
  208. }
  209. // Update the state with the block and responses.
  210. state, err = updateState(state, blockID, &block.Header, abciResponses, validatorUpdates)
  211. if err != nil {
  212. return state, fmt.Errorf("commit failed for application: %w", err)
  213. }
  214. // Lock mempool, commit app state, update mempoool.
  215. appHash, retainHeight, err := blockExec.Commit(ctx, state, block, abciResponses.FinalizeBlock.TxResults)
  216. if err != nil {
  217. return state, fmt.Errorf("commit failed for application: %w", err)
  218. }
  219. // Update evpool with the latest state.
  220. blockExec.evpool.Update(ctx, state, block.Evidence)
  221. // Update the app hash and save the state.
  222. state.AppHash = appHash
  223. if err := blockExec.store.Save(state); err != nil {
  224. return state, err
  225. }
  226. // Prune old heights, if requested by ABCI app.
  227. if retainHeight > 0 {
  228. pruned, err := blockExec.pruneBlocks(retainHeight)
  229. if err != nil {
  230. blockExec.logger.Error("failed to prune blocks", "retain_height", retainHeight, "err", err)
  231. } else {
  232. blockExec.logger.Debug("pruned blocks", "pruned", pruned, "retain_height", retainHeight)
  233. }
  234. }
  235. // reset the verification cache
  236. blockExec.cache = make(map[string]struct{})
  237. // Events are fired after everything else.
  238. // NOTE: if we crash between Commit and Save, events wont be fired during replay
  239. fireEvents(ctx, blockExec.logger, blockExec.eventBus, block, blockID, abciResponses, validatorUpdates)
  240. return state, nil
  241. }
  242. func (blockExec *BlockExecutor) ExtendVote(ctx context.Context, vote *types.Vote) (types.VoteExtension, error) {
  243. req := abci.RequestExtendVote{
  244. Vote: vote.ToProto(),
  245. }
  246. resp, err := blockExec.proxyApp.ExtendVote(ctx, req)
  247. if err != nil {
  248. return types.VoteExtension{}, err
  249. }
  250. return types.VoteExtensionFromProto(resp.VoteExtension), nil
  251. }
  252. func (blockExec *BlockExecutor) VerifyVoteExtension(ctx context.Context, vote *types.Vote) error {
  253. req := abci.RequestVerifyVoteExtension{
  254. Vote: vote.ToProto(),
  255. }
  256. resp, err := blockExec.proxyApp.VerifyVoteExtension(ctx, req)
  257. if err != nil {
  258. return err
  259. }
  260. if resp.IsErr() {
  261. return types.ErrVoteInvalidExtension
  262. }
  263. return nil
  264. }
  265. // Commit locks the mempool, runs the ABCI Commit message, and updates the
  266. // mempool.
  267. // It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any).
  268. // The Mempool must be locked during commit and update because state is
  269. // typically reset on Commit and old txs must be replayed against committed
  270. // state before new txs are run in the mempool, lest they be invalid.
  271. func (blockExec *BlockExecutor) Commit(
  272. ctx context.Context,
  273. state State,
  274. block *types.Block,
  275. txResults []*abci.ExecTxResult,
  276. ) ([]byte, int64, error) {
  277. blockExec.mempool.Lock()
  278. defer blockExec.mempool.Unlock()
  279. // while mempool is Locked, flush to ensure all async requests have completed
  280. // in the ABCI app before Commit.
  281. err := blockExec.mempool.FlushAppConn(ctx)
  282. if err != nil {
  283. blockExec.logger.Error("client error during mempool.FlushAppConn", "err", err)
  284. return nil, 0, err
  285. }
  286. // Commit block, get hash back
  287. res, err := blockExec.proxyApp.Commit(ctx)
  288. if err != nil {
  289. blockExec.logger.Error("client error during proxyAppConn.Commit", "err", err)
  290. return nil, 0, err
  291. }
  292. // ResponseCommit has no error code - just data
  293. blockExec.logger.Info(
  294. "committed state",
  295. "height", block.Height,
  296. "num_txs", len(block.Txs),
  297. "app_hash", fmt.Sprintf("%X", res.Data),
  298. )
  299. // Update mempool.
  300. err = blockExec.mempool.Update(
  301. ctx,
  302. block.Height,
  303. block.Txs,
  304. txResults,
  305. TxPreCheck(state),
  306. TxPostCheck(state),
  307. )
  308. return res.Data, res.RetainHeight, err
  309. }
  310. //---------------------------------------------------------
  311. // Helper functions for executing blocks and updating state
  312. // Executes block's transactions on proxyAppConn.
  313. // Returns a list of transaction results and updates to the validator set
  314. func execBlockOnProxyApp(
  315. ctx context.Context,
  316. logger log.Logger,
  317. proxyAppConn proxy.AppConnConsensus,
  318. block *types.Block,
  319. store Store,
  320. initialHeight int64,
  321. ) (*tmstate.ABCIResponses, error) {
  322. abciResponses := new(tmstate.ABCIResponses)
  323. abciResponses.FinalizeBlock = &abci.ResponseFinalizeBlock{}
  324. dtxs := make([]*abci.ExecTxResult, len(block.Txs))
  325. abciResponses.FinalizeBlock.TxResults = dtxs
  326. // Begin block
  327. var err error
  328. pbh := block.Header.ToProto()
  329. if pbh == nil {
  330. return nil, errors.New("nil header")
  331. }
  332. abciResponses.FinalizeBlock, err = proxyAppConn.FinalizeBlock(
  333. ctx,
  334. abci.RequestFinalizeBlock{
  335. Txs: block.Txs.ToSliceOfBytes(),
  336. Hash: block.Hash(),
  337. Header: *pbh,
  338. LastCommitInfo: buildLastCommitInfo(block, store, initialHeight),
  339. ByzantineValidators: block.Evidence.ToABCI(),
  340. },
  341. )
  342. if err != nil {
  343. logger.Error("error in proxyAppConn.FinalizeBlock", "err", err)
  344. return nil, err
  345. }
  346. logger.Info("executed block", "height", block.Height)
  347. return abciResponses, nil
  348. }
  349. func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) abci.LastCommitInfo {
  350. if block.Height == initialHeight {
  351. // there is no last commmit for the initial height.
  352. // return an empty value.
  353. return abci.LastCommitInfo{}
  354. }
  355. lastValSet, err := store.LoadValidators(block.Height - 1)
  356. if err != nil {
  357. panic(err)
  358. }
  359. var (
  360. commitSize = block.LastCommit.Size()
  361. valSetLen = len(lastValSet.Validators)
  362. )
  363. // ensure that the size of the validator set in the last commit matches
  364. // the size of the validator set in the state store.
  365. if commitSize != valSetLen {
  366. panic(fmt.Sprintf(
  367. "commit size (%d) doesn't match validator set length (%d) at height %d\n\n%v\n\n%v",
  368. commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators,
  369. ))
  370. }
  371. votes := make([]abci.VoteInfo, block.LastCommit.Size())
  372. for i, val := range lastValSet.Validators {
  373. commitSig := block.LastCommit.Signatures[i]
  374. votes[i] = abci.VoteInfo{
  375. Validator: types.TM2PB.Validator(val),
  376. SignedLastBlock: !commitSig.Absent(),
  377. }
  378. }
  379. return abci.LastCommitInfo{
  380. Round: block.LastCommit.Round,
  381. Votes: votes,
  382. }
  383. }
  384. func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate,
  385. params types.ValidatorParams) error {
  386. for _, valUpdate := range abciUpdates {
  387. if valUpdate.GetPower() < 0 {
  388. return fmt.Errorf("voting power can't be negative %v", valUpdate)
  389. } else if valUpdate.GetPower() == 0 {
  390. // continue, since this is deleting the validator, and thus there is no
  391. // pubkey to check
  392. continue
  393. }
  394. // Check if validator's pubkey matches an ABCI type in the consensus params
  395. pk, err := encoding.PubKeyFromProto(valUpdate.PubKey)
  396. if err != nil {
  397. return err
  398. }
  399. if !params.IsValidPubkeyType(pk.Type()) {
  400. return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus",
  401. valUpdate, pk.Type())
  402. }
  403. }
  404. return nil
  405. }
  406. // updateState returns a new State updated according to the header and responses.
  407. func updateState(
  408. state State,
  409. blockID types.BlockID,
  410. header *types.Header,
  411. abciResponses *tmstate.ABCIResponses,
  412. validatorUpdates []*types.Validator,
  413. ) (State, error) {
  414. // Copy the valset so we can apply changes from EndBlock
  415. // and update s.LastValidators and s.Validators.
  416. nValSet := state.NextValidators.Copy()
  417. // Update the validator set with the latest abciResponses.
  418. lastHeightValsChanged := state.LastHeightValidatorsChanged
  419. if len(validatorUpdates) > 0 {
  420. err := nValSet.UpdateWithChangeSet(validatorUpdates)
  421. if err != nil {
  422. return state, fmt.Errorf("error changing validator set: %w", err)
  423. }
  424. // Change results from this height but only applies to the next next height.
  425. lastHeightValsChanged = header.Height + 1 + 1
  426. }
  427. // Update validator proposer priority and set state variables.
  428. nValSet.IncrementProposerPriority(1)
  429. // Update the params with the latest abciResponses.
  430. nextParams := state.ConsensusParams
  431. lastHeightParamsChanged := state.LastHeightConsensusParamsChanged
  432. if abciResponses.FinalizeBlock.ConsensusParamUpdates != nil {
  433. // NOTE: must not mutate s.ConsensusParams
  434. nextParams = state.ConsensusParams.UpdateConsensusParams(abciResponses.FinalizeBlock.ConsensusParamUpdates)
  435. err := nextParams.ValidateConsensusParams()
  436. if err != nil {
  437. return state, fmt.Errorf("error updating consensus params: %w", err)
  438. }
  439. state.Version.Consensus.App = nextParams.Version.AppVersion
  440. // Change results from this height but only applies to the next height.
  441. lastHeightParamsChanged = header.Height + 1
  442. }
  443. nextVersion := state.Version
  444. // NOTE: the AppHash and the VoteExtension has not been populated.
  445. // It will be filled on state.Save.
  446. return State{
  447. Version: nextVersion,
  448. ChainID: state.ChainID,
  449. InitialHeight: state.InitialHeight,
  450. LastBlockHeight: header.Height,
  451. LastBlockID: blockID,
  452. LastBlockTime: header.Time,
  453. NextValidators: nValSet,
  454. Validators: state.NextValidators.Copy(),
  455. LastValidators: state.Validators.Copy(),
  456. LastHeightValidatorsChanged: lastHeightValsChanged,
  457. ConsensusParams: nextParams,
  458. LastHeightConsensusParamsChanged: lastHeightParamsChanged,
  459. LastResultsHash: ABCIResponsesResultsHash(abciResponses),
  460. AppHash: nil,
  461. }, nil
  462. }
  463. // Fire NewBlock, NewBlockHeader.
  464. // Fire TxEvent for every tx.
  465. // NOTE: if Tendermint crashes before commit, some or all of these events may be published again.
  466. func fireEvents(
  467. ctx context.Context,
  468. logger log.Logger,
  469. eventBus types.BlockEventPublisher,
  470. block *types.Block,
  471. blockID types.BlockID,
  472. abciResponses *tmstate.ABCIResponses,
  473. validatorUpdates []*types.Validator,
  474. ) {
  475. if err := eventBus.PublishEventNewBlock(ctx, types.EventDataNewBlock{
  476. Block: block,
  477. BlockID: blockID,
  478. ResultFinalizeBlock: *abciResponses.FinalizeBlock,
  479. }); err != nil {
  480. logger.Error("failed publishing new block", "err", err)
  481. }
  482. if err := eventBus.PublishEventNewBlockHeader(ctx, types.EventDataNewBlockHeader{
  483. Header: block.Header,
  484. NumTxs: int64(len(block.Txs)),
  485. ResultFinalizeBlock: *abciResponses.FinalizeBlock,
  486. }); err != nil {
  487. logger.Error("failed publishing new block header", "err", err)
  488. }
  489. if len(block.Evidence) != 0 {
  490. for _, ev := range block.Evidence {
  491. if err := eventBus.PublishEventNewEvidence(ctx, types.EventDataNewEvidence{
  492. Evidence: ev,
  493. Height: block.Height,
  494. }); err != nil {
  495. logger.Error("failed publishing new evidence", "err", err)
  496. }
  497. }
  498. }
  499. // sanity check
  500. if len(abciResponses.FinalizeBlock.TxResults) != len(block.Data.Txs) {
  501. panic(fmt.Sprintf("number of TXs (%d) and ABCI TX responses (%d) do not match",
  502. len(block.Data.Txs), len(abciResponses.FinalizeBlock.TxResults)))
  503. }
  504. for i, tx := range block.Data.Txs {
  505. if err := eventBus.PublishEventTx(ctx, types.EventDataTx{
  506. TxResult: abci.TxResult{
  507. Height: block.Height,
  508. Index: uint32(i),
  509. Tx: tx,
  510. Result: *(abciResponses.FinalizeBlock.TxResults[i]),
  511. },
  512. }); err != nil {
  513. logger.Error("failed publishing event TX", "err", err)
  514. }
  515. }
  516. if len(validatorUpdates) > 0 {
  517. if err := eventBus.PublishEventValidatorSetUpdates(ctx,
  518. types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}); err != nil {
  519. logger.Error("failed publishing event", "err", err)
  520. }
  521. }
  522. }
  523. //----------------------------------------------------------------------------------------------------
  524. // Execute block without state. TODO: eliminate
  525. // ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
  526. // It returns the application root hash (result of abci.Commit).
  527. func ExecCommitBlock(
  528. ctx context.Context,
  529. be *BlockExecutor,
  530. appConnConsensus proxy.AppConnConsensus,
  531. block *types.Block,
  532. logger log.Logger,
  533. store Store,
  534. initialHeight int64,
  535. s State,
  536. ) ([]byte, error) {
  537. abciResponses, err := execBlockOnProxyApp(ctx, logger, appConnConsensus, block, store, initialHeight)
  538. if err != nil {
  539. logger.Error("failed executing block on proxy app", "height", block.Height, "err", err)
  540. return nil, err
  541. }
  542. // the BlockExecutor condition is using for the final block replay process.
  543. if be != nil {
  544. abciValUpdates := abciResponses.FinalizeBlock.ValidatorUpdates
  545. err = validateValidatorUpdates(abciValUpdates, s.ConsensusParams.Validator)
  546. if err != nil {
  547. logger.Error("err", err)
  548. return nil, err
  549. }
  550. validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates)
  551. if err != nil {
  552. logger.Error("err", err)
  553. return nil, err
  554. }
  555. bps, err := block.MakePartSet(types.BlockPartSizeBytes)
  556. if err != nil {
  557. return nil, err
  558. }
  559. blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
  560. fireEvents(ctx, be.logger, be.eventBus, block, blockID, abciResponses, validatorUpdates)
  561. }
  562. // Commit block, get hash back
  563. res, err := appConnConsensus.Commit(ctx)
  564. if err != nil {
  565. logger.Error("client error during proxyAppConn.Commit", "err", res)
  566. return nil, err
  567. }
  568. // ResponseCommit has no error or log, just data
  569. return res.Data, nil
  570. }
  571. func (blockExec *BlockExecutor) pruneBlocks(retainHeight int64) (uint64, error) {
  572. base := blockExec.blockStore.Base()
  573. if retainHeight <= base {
  574. return 0, nil
  575. }
  576. pruned, err := blockExec.blockStore.PruneBlocks(retainHeight)
  577. if err != nil {
  578. return 0, fmt.Errorf("failed to prune block store: %w", err)
  579. }
  580. err = blockExec.Store().PruneStates(retainHeight)
  581. if err != nil {
  582. return 0, fmt.Errorf("failed to prune state store: %w", err)
  583. }
  584. return pruned, nil
  585. }