tendermint/state/execution.go

422 lines
14 KiB
Go
Raw Normal View History

package state
import (
"fmt"
fail "github.com/ebuchman/fail-test"
2018-06-21 21:59:02 -07:00
abci "github.com/tendermint/tendermint/abci/types"
2018-07-01 19:36:49 -07:00
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/proxy"
"github.com/tendermint/tendermint/types"
)
2017-12-27 17:03:48 -08:00
//-----------------------------------------------------------------------------
// BlockExecutor handles block execution and state updates.
// It exposes ApplyBlock(), which validates & executes the block, updates state w/ ABCI responses,
// then commits and updates the mempool atomically, then saves state.
// BlockExecutor provides the context and accessories for properly executing a block.
type BlockExecutor struct {
2017-12-28 15:26:13 -08:00
// save state, validators, consensus params, abci responses here
db dbm.DB
// execute the app against this
proxyApp proxy.AppConnConsensus
2017-12-28 15:58:05 -08:00
// events
eventBus types.BlockEventPublisher
2017-12-27 17:03:48 -08:00
2017-12-28 15:26:13 -08:00
// update these with block results after commit
mempool Mempool
evpool EvidencePool
2017-12-27 17:03:48 -08:00
2017-12-28 15:26:13 -08:00
logger log.Logger
2017-12-27 19:09:48 -08:00
}
2017-12-28 15:58:05 -08:00
// NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
// Call SetEventBus to provide one.
2017-12-28 15:26:13 -08:00
func NewBlockExecutor(db dbm.DB, logger log.Logger, proxyApp proxy.AppConnConsensus,
mempool Mempool, evpool EvidencePool) *BlockExecutor {
2017-12-27 17:03:48 -08:00
return &BlockExecutor{
2017-12-28 15:58:05 -08:00
db: db,
proxyApp: proxyApp,
eventBus: types.NopEventBus{},
mempool: mempool,
evpool: evpool,
logger: logger,
2017-12-27 17:03:48 -08:00
}
}
2017-12-28 15:58:05 -08:00
// SetEventBus - sets the event bus for publishing block related events.
// If not called, it defaults to types.NopEventBus.
func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) {
blockExec.eventBus = eventBus
2017-12-28 15:26:13 -08:00
}
2017-12-28 16:35:56 -08:00
// ValidateBlock validates the given block against the given state.
// If the block is invalid, it returns an error.
// Validation does not mutate state, but does require historical information from the stateDB,
// ie. to verify evidence from a validator at an old height.
2018-06-04 13:31:57 -07:00
func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) error {
return validateBlock(blockExec.db, state, block)
2017-12-28 16:35:56 -08:00
}
2017-12-27 17:03:48 -08:00
// ApplyBlock validates the block against the state, executes it against the app,
2017-12-28 19:10:23 -08:00
// fires the relevant events, commits the app, and saves the new state and responses.
2017-12-28 15:58:05 -08:00
// It's the only function that needs to be called
2017-12-27 17:03:48 -08:00
// from outside this package to process and commit an entire block.
// It takes a blockID to avoid recomputing the parts hash.
2018-06-04 13:31:57 -07:00
func (blockExec *BlockExecutor) ApplyBlock(state State, blockID types.BlockID, block *types.Block) (State, error) {
2017-12-27 17:03:48 -08:00
2018-06-04 13:31:57 -07:00
if err := blockExec.ValidateBlock(state, block); err != nil {
return state, ErrInvalidBlock(err)
}
2015-12-01 20:12:01 -08:00
2018-06-05 22:14:37 -07:00
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, state.LastValidators, blockExec.db)
2015-12-01 20:12:01 -08:00
if err != nil {
2018-06-04 13:31:57 -07:00
return state, ErrProxyAppConn(err)
2015-12-01 20:12:01 -08:00
}
2017-12-27 17:03:48 -08:00
fail.Fail() // XXX
// Save the results before we commit.
2017-12-27 17:03:48 -08:00
saveABCIResponses(blockExec.db, block.Height, abciResponses)
fail.Fail() // XXX
// Update the state with the block and responses.
state, err = updateState(state, blockID, &block.Header, abciResponses)
2017-12-27 17:03:48 -08:00
if err != nil {
2018-06-04 13:31:57 -07:00
return state, fmt.Errorf("Commit failed for application: %v", err)
2017-12-27 17:03:48 -08:00
}
// Lock mempool, commit app state, update mempoool.
appHash, err := blockExec.Commit(state, block)
2017-12-27 17:03:48 -08:00
if err != nil {
2018-06-04 13:31:57 -07:00
return state, fmt.Errorf("Commit failed for application: %v", err)
2017-12-27 17:03:48 -08:00
}
// Update evpool with the block and state.
blockExec.evpool.Update(block, state)
2017-12-27 17:03:48 -08:00
fail.Fail() // XXX
// Update the app hash and save the state.
2018-06-04 13:31:57 -07:00
state.AppHash = appHash
SaveState(blockExec.db, state)
2017-12-27 17:03:48 -08:00
2017-12-28 15:58:05 -08:00
fail.Fail() // XXX
// Events are fired after everything else.
2017-12-28 15:58:05 -08:00
// NOTE: if we crash between Commit and Save, events wont be fired during replay
fireEvents(blockExec.logger, blockExec.eventBus, block, abciResponses)
2018-06-04 13:31:57 -07:00
return state, nil
2017-12-27 17:03:48 -08:00
}
// Commit locks the mempool, runs the ABCI Commit message, and updates the mempool.
// It returns the result of calling abci.Commit (the AppHash), and an error.
// The Mempool must be locked during commit and update because state is typically reset on Commit and old txs must be replayed
// against committed state before new txs are run in the mempool, lest they be invalid.
func (blockExec *BlockExecutor) Commit(state State, block *types.Block) ([]byte, error) {
2017-12-27 17:03:48 -08:00
blockExec.mempool.Lock()
defer blockExec.mempool.Unlock()
// while mempool is Locked, flush to ensure all async requests have completed
// in the ABCI app before Commit.
err := blockExec.mempool.FlushAppConn()
if err != nil {
blockExec.logger.Error("Client error during mempool.FlushAppConn", "err", err)
return nil, err
}
2017-12-27 17:03:48 -08:00
// Commit block, get hash back
res, err := blockExec.proxyApp.CommitSync()
if err != nil {
blockExec.logger.Error("Client error during proxyAppConn.CommitSync", "err", err)
return nil, err
}
// ResponseCommit has no error code - just data
2017-12-27 17:03:48 -08:00
2018-02-19 12:32:09 -08:00
blockExec.logger.Info("Committed state",
"height", block.Height,
"txs", block.NumTxs,
"appHash", fmt.Sprintf("%X", res.Data))
2017-12-27 17:03:48 -08:00
// Update mempool.
maxDataBytes := types.MaxDataBytesUnknownEvidence(
state.ConsensusParams.BlockSize.MaxBytes,
state.Validators.Size(),
)
filter := func(tx types.Tx) bool { return len(tx) <= maxDataBytes }
if err := blockExec.mempool.Update(block.Height, block.Txs, filter); err != nil {
2017-12-27 17:03:48 -08:00
return nil, err
}
return res.Data, nil
}
2017-12-27 17:03:48 -08:00
//---------------------------------------------------------
// Helper functions for executing blocks and updating state
// Executes block's transactions on proxyAppConn.
// Returns a list of transaction results and updates to the validator set
2018-05-31 20:29:46 -07:00
func execBlockOnProxyApp(logger log.Logger, proxyAppConn proxy.AppConnConsensus,
block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) (*ABCIResponses, error) {
var validTxs, invalidTxs = 0, 0
2015-12-01 20:12:01 -08:00
txIndex := 0
abciResponses := NewABCIResponses(block)
// Execute transactions and get hash.
2017-01-12 12:53:32 -08:00
proxyCb := func(req *abci.Request, res *abci.Response) {
2016-05-14 09:33:27 -07:00
switch r := res.Value.(type) {
2017-01-12 12:55:03 -08:00
case *abci.Response_DeliverTx:
2016-01-25 14:34:08 -08:00
// TODO: make use of res.Log
// TODO: make use of this info
// Blocks may include invalid txs.
txRes := r.DeliverTx
if txRes.Code == abci.CodeTypeOK {
validTxs++
} else {
logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log)
invalidTxs++
}
abciResponses.DeliverTx[txIndex] = txRes
txIndex++
2015-12-01 20:12:01 -08:00
}
}
proxyAppConn.SetResponseCallback(proxyCb)
commitInfo, byzVals := getBeginBlockValidatorInfo(block, lastValSet, stateDB)
// Begin block.
2017-11-29 09:22:52 -08:00
_, err := proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
Hash: block.Hash(),
Header: types.TM2PB.Header(&block.Header),
LastCommitInfo: commitInfo,
ByzantineValidators: byzVals,
})
2016-11-03 16:51:22 -07:00
if err != nil {
logger.Error("Error in proxyAppConn.BeginBlock", "err", err)
return nil, err
2016-11-03 16:51:22 -07:00
}
// Run txs of block.
for _, tx := range block.Txs {
2017-01-12 12:55:03 -08:00
proxyAppConn.DeliverTxAsync(tx)
if err := proxyAppConn.Error(); err != nil {
return nil, err
2015-12-01 20:12:01 -08:00
}
}
2016-03-05 20:57:36 -08:00
// End block.
abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{Height: block.Height})
2016-03-05 20:57:36 -08:00
if err != nil {
logger.Error("Error in proxyAppConn.EndBlock", "err", err)
return nil, err
2016-03-05 20:57:36 -08:00
}
2016-09-11 12:32:33 -07:00
2017-06-13 23:41:36 -07:00
logger.Info("Executed block", "height", block.Height, "validTxs", validTxs, "invalidTxs", invalidTxs)
2018-08-16 07:58:03 -07:00
valUpdates := abciResponses.EndBlock.ValidatorUpdates
if len(valUpdates) > 0 {
// TODO: cleanup the formatting
2018-08-16 07:58:03 -07:00
logger.Info("Updates to validators", "updates", valUpdates)
2016-11-22 15:55:42 -08:00
}
return abciResponses, nil
2016-11-19 16:32:35 -08:00
}
func getBeginBlockValidatorInfo(block *types.Block, lastValSet *types.ValidatorSet, stateDB dbm.DB) (abci.LastCommitInfo, []abci.Evidence) {
// Sanity check that commit length matches validator set size -
// only applies after first block
if block.Height > 1 {
precommitLen := len(block.LastCommit.Precommits)
valSetLen := len(lastValSet.Validators)
if precommitLen != valSetLen {
// sanity check
panic(fmt.Sprintf("precommit length (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v",
precommitLen, valSetLen, block.Height, block.LastCommit.Precommits, lastValSet.Validators))
}
}
// Collect the vote info (list of validators and whether or not they signed).
voteInfos := make([]abci.VoteInfo, len(lastValSet.Validators))
for i, val := range lastValSet.Validators {
var vote *types.Vote
if i < len(block.LastCommit.Precommits) {
vote = block.LastCommit.Precommits[i]
}
voteInfo := abci.VoteInfo{
Validator: types.TM2PB.Validator(val),
SignedLastBlock: vote != nil,
}
voteInfos[i] = voteInfo
}
commitInfo := abci.LastCommitInfo{
Round: int32(block.LastCommit.Round()),
Votes: voteInfos,
}
byzVals := make([]abci.Evidence, len(block.Evidence.Evidence))
for i, ev := range block.Evidence.Evidence {
// We need the validator set. We already did this in validateBlock.
// TODO: Should we instead cache the valset in the evidence itself and add
// `SetValidatorSet()` and `ToABCI` methods ?
valset, err := LoadValidators(stateDB, ev.Height())
if err != nil {
2018-06-05 21:54:59 -07:00
panic(err) // shouldn't happen
}
byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time)
}
return commitInfo, byzVals
}
// If more or equal than 1/3 of total voting power changed in one block, then
// a light client could never prove the transition externally. See
// ./lite/doc.go for details on how a light client tracks validators.
func updateValidators(currentSet *types.ValidatorSet, abciUpdates []abci.ValidatorUpdate) error {
updates, err := types.PB2TM.ValidatorUpdates(abciUpdates)
if err != nil {
return err
}
2016-11-19 16:32:35 -08:00
// these are tendermint types now
for _, valUpdate := range updates {
if valUpdate.VotingPower < 0 {
return fmt.Errorf("Voting power can't be negative %v", valUpdate)
}
address := valUpdate.Address
_, val := currentSet.GetByAddress(address)
2018-07-04 09:50:36 -07:00
if valUpdate.VotingPower == 0 {
2016-11-19 16:32:35 -08:00
// remove val
_, removed := currentSet.Remove(address)
2016-11-19 16:32:35 -08:00
if !removed {
return fmt.Errorf("Failed to remove validator %X", address)
2016-11-19 16:32:35 -08:00
}
2018-07-04 09:50:36 -07:00
} else if val == nil {
// add val
added := currentSet.Add(valUpdate)
if !added {
return fmt.Errorf("Failed to add new validator %v", valUpdate)
}
2016-11-19 16:32:35 -08:00
} else {
// update val
updated := currentSet.Update(valUpdate)
2016-11-19 16:32:35 -08:00
if !updated {
return fmt.Errorf("Failed to update validator %X to %v", address, valUpdate)
2016-11-19 16:32:35 -08:00
}
}
}
return nil
2015-12-01 20:12:01 -08:00
}
2017-12-27 17:03:48 -08:00
// updateState returns a new State updated according to the header and responses.
2018-06-04 13:31:57 -07:00
func updateState(state State, blockID types.BlockID, header *types.Header,
2017-12-27 17:03:48 -08:00
abciResponses *ABCIResponses) (State, error) {
// Copy the valset so we can apply changes from EndBlock
// and update s.LastValidators and s.Validators.
nValSet := state.NextValidators.Copy()
// Update the validator set with the latest abciResponses.
2018-06-04 13:31:57 -07:00
lastHeightValsChanged := state.LastHeightValidatorsChanged
2017-12-27 17:03:48 -08:00
if len(abciResponses.EndBlock.ValidatorUpdates) > 0 {
err := updateValidators(nValSet, abciResponses.EndBlock.ValidatorUpdates)
if err != nil {
2018-06-04 13:31:57 -07:00
return state, fmt.Errorf("Error changing validator set: %v", err)
}
// Change results from this height but only applies to the next next height.
lastHeightValsChanged = header.Height + 1 + 1
}
// Update validator accums and set state variables.
nValSet.IncrementAccum(1)
2017-12-27 17:03:48 -08:00
// Update the params with the latest abciResponses.
2018-06-04 13:31:57 -07:00
nextParams := state.ConsensusParams
lastHeightParamsChanged := state.LastHeightConsensusParamsChanged
2017-12-27 17:03:48 -08:00
if abciResponses.EndBlock.ConsensusParamUpdates != nil {
// NOTE: must not mutate s.ConsensusParams
2018-06-04 13:31:57 -07:00
nextParams = state.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates)
2017-12-27 17:03:48 -08:00
err := nextParams.Validate()
2017-12-27 16:21:16 -08:00
if err != nil {
2018-06-04 13:31:57 -07:00
return state, fmt.Errorf("Error updating consensus params: %v", err)
2017-07-25 09:29:38 -07:00
}
// Change results from this height but only applies to the next height.
2017-12-27 17:03:48 -08:00
lastHeightParamsChanged = header.Height + 1
}
// NOTE: the AppHash has not been populated.
// It will be filled on state.Save.
return State{
2018-06-04 13:31:57 -07:00
ChainID: state.ChainID,
2017-12-27 17:03:48 -08:00
LastBlockHeight: header.Height,
2018-06-04 13:31:57 -07:00
LastBlockTotalTx: state.LastBlockTotalTx + header.NumTxs,
2017-12-27 17:03:48 -08:00
LastBlockID: blockID,
LastBlockTime: header.Time,
NextValidators: nValSet,
Validators: state.NextValidators.Copy(),
2018-06-04 13:31:57 -07:00
LastValidators: state.Validators.Copy(),
2017-12-27 17:03:48 -08:00
LastHeightValidatorsChanged: lastHeightValsChanged,
ConsensusParams: nextParams,
LastHeightConsensusParamsChanged: lastHeightParamsChanged,
LastResultsHash: abciResponses.ResultsHash(),
AppHash: nil,
}, nil
2015-12-01 20:12:01 -08:00
}
2016-08-23 18:44:07 -07:00
2017-12-28 15:58:05 -08:00
// Fire NewBlock, NewBlockHeader.
// Fire TxEvent for every tx.
// NOTE: if Tendermint crashes before commit, some or all of these events may be published again.
func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *types.Block, abciResponses *ABCIResponses) {
2018-05-11 01:09:41 -07:00
eventBus.PublishEventNewBlock(types.EventDataNewBlock{block})
eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{block.Header})
2017-12-27 19:09:48 -08:00
for i, tx := range block.Data.Txs {
2018-05-11 01:09:41 -07:00
eventBus.PublishEventTx(types.EventDataTx{types.TxResult{
2017-12-27 16:21:16 -08:00
Height: block.Height,
2017-12-27 19:09:48 -08:00
Index: uint32(i),
2017-12-27 16:21:16 -08:00
Tx: tx,
2017-12-27 19:09:48 -08:00
Result: *(abciResponses.DeliverTx[i]),
2017-12-27 16:21:16 -08:00
}})
2017-12-27 19:09:48 -08:00
}
2018-08-16 10:22:04 -07:00
abciValUpdates := abciResponses.EndBlock.ValidatorUpdates
if len(abciValUpdates) > 0 {
// if there were an error, we would've stopped in updateValidators
2018-08-16 10:22:04 -07:00
updates, _ := types.PB2TM.ValidatorUpdates(abciValUpdates)
eventBus.PublishEventValidatorSetUpdates(
types.EventDataValidatorSetUpdates{ValidatorUpdates: updates})
}
}
2016-08-23 18:44:07 -07:00
2017-12-27 17:03:48 -08:00
//----------------------------------------------------------------------------------------------------
// Execute block without state. TODO: eliminate
2016-08-24 21:18:03 -07:00
2017-08-21 13:12:07 -07:00
// ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
// It returns the application root hash (result of abci.Commit).
2018-05-31 20:29:46 -07:00
func ExecCommitBlock(appConnConsensus proxy.AppConnConsensus, block *types.Block,
logger log.Logger, lastValSet *types.ValidatorSet, stateDB dbm.DB) ([]byte, error) {
_, err := execBlockOnProxyApp(logger, appConnConsensus, block, lastValSet, stateDB)
if err != nil {
2017-05-02 00:53:32 -07:00
logger.Error("Error executing block on proxy app", "height", block.Height, "err", err)
return nil, err
}
// Commit block, get hash back
res, err := appConnConsensus.CommitSync()
if err != nil {
logger.Error("Client error during proxyAppConn.CommitSync", "err", res)
return nil, err
}
// ResponseCommit has no error or log, just data
return res.Data, nil
}