2015-03-28 23:44:07 -07:00
|
|
|
package state
|
|
|
|
|
|
|
|
import (
|
2017-01-19 13:33:58 +04:00
|
|
|
"fmt"
|
2018-10-10 09:27:43 -07:00
|
|
|
"time"
|
2015-03-28 23:44:07 -07:00
|
|
|
|
2018-06-22 06:59:02 +02:00
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
2018-10-30 10:34:51 -04:00
|
|
|
"github.com/tendermint/tendermint/libs/fail"
|
2018-07-01 22:36:49 -04:00
|
|
|
"github.com/tendermint/tendermint/libs/log"
|
2019-05-04 10:41:31 +04:00
|
|
|
mempl "github.com/tendermint/tendermint/mempool"
|
2018-07-04 12:36:11 +04:00
|
|
|
"github.com/tendermint/tendermint/proxy"
|
|
|
|
"github.com/tendermint/tendermint/types"
|
2019-07-31 11:34:17 +02:00
|
|
|
dbm "github.com/tendermint/tm-db"
|
2015-03-28 23:44:07 -07:00
|
|
|
)
|
|
|
|
|
2017-12-27 20:03:48 -05: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 18:26:13 -05:00
|
|
|
// save state, validators, consensus params, abci responses here
|
|
|
|
db dbm.DB
|
|
|
|
|
|
|
|
// execute the app against this
|
|
|
|
proxyApp proxy.AppConnConsensus
|
2017-04-14 15:33:19 -04:00
|
|
|
|
2017-12-28 18:58:05 -05:00
|
|
|
// events
|
|
|
|
eventBus types.BlockEventPublisher
|
2017-12-27 20:03:48 -05:00
|
|
|
|
2019-01-17 21:46:40 -05:00
|
|
|
// manage the mempool lock during commit
|
|
|
|
// and update both with block results after commit.
|
2019-05-04 10:41:31 +04:00
|
|
|
mempool mempl.Mempool
|
2018-06-04 13:46:34 -07:00
|
|
|
evpool EvidencePool
|
2017-12-27 20:03:48 -05:00
|
|
|
|
2017-12-28 18:26:13 -05:00
|
|
|
logger log.Logger
|
2018-10-10 09:27:43 -07:00
|
|
|
|
|
|
|
metrics *Metrics
|
|
|
|
}
|
|
|
|
|
|
|
|
type BlockExecutorOption func(executor *BlockExecutor)
|
|
|
|
|
|
|
|
func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption {
|
|
|
|
return func(blockExec *BlockExecutor) {
|
|
|
|
blockExec.metrics = metrics
|
|
|
|
}
|
2017-12-27 22:09:48 -05:00
|
|
|
}
|
|
|
|
|
2017-12-28 18:58:05 -05:00
|
|
|
// NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
|
|
|
|
// Call SetEventBus to provide one.
|
2019-05-04 10:41:31 +04:00
|
|
|
func NewBlockExecutor(db dbm.DB, logger log.Logger, proxyApp proxy.AppConnConsensus, mempool mempl.Mempool, evpool EvidencePool, options ...BlockExecutorOption) *BlockExecutor {
|
2018-10-10 09:27:43 -07:00
|
|
|
res := &BlockExecutor{
|
2017-12-28 18:58:05 -05:00
|
|
|
db: db,
|
|
|
|
proxyApp: proxyApp,
|
|
|
|
eventBus: types.NopEventBus{},
|
|
|
|
mempool: mempool,
|
|
|
|
evpool: evpool,
|
|
|
|
logger: logger,
|
2018-10-10 09:27:43 -07:00
|
|
|
metrics: NopMetrics(),
|
2017-12-27 20:03:48 -05:00
|
|
|
}
|
2018-10-10 09:27:43 -07:00
|
|
|
|
|
|
|
for _, option := range options {
|
|
|
|
option(res)
|
|
|
|
}
|
|
|
|
|
|
|
|
return res
|
2017-12-27 20:03:48 -05:00
|
|
|
}
|
|
|
|
|
2019-05-02 05:15:53 +08:00
|
|
|
func (blockExec *BlockExecutor) DB() dbm.DB {
|
|
|
|
return blockExec.db
|
|
|
|
}
|
|
|
|
|
2017-12-28 18:58:05 -05: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 18:26:13 -05:00
|
|
|
}
|
|
|
|
|
2019-01-17 21:46:40 -05:00
|
|
|
// CreateProposalBlock calls state.MakeBlock with evidence from the evpool
|
|
|
|
// and txs from the mempool. The max bytes must be big enough to fit the commit.
|
|
|
|
// Up to 1/10th of the block space is allcoated for maximum sized evidence.
|
|
|
|
// The rest is given to txs, up to the max gas.
|
|
|
|
func (blockExec *BlockExecutor) CreateProposalBlock(
|
|
|
|
height int64,
|
|
|
|
state State, commit *types.Commit,
|
|
|
|
proposerAddr []byte,
|
|
|
|
) (*types.Block, *types.PartSet) {
|
|
|
|
|
2019-03-04 13:24:44 +04:00
|
|
|
maxBytes := state.ConsensusParams.Block.MaxBytes
|
|
|
|
maxGas := state.ConsensusParams.Block.MaxGas
|
2019-01-17 21:46:40 -05:00
|
|
|
|
|
|
|
// Fetch a limited amount of valid evidence
|
|
|
|
maxNumEvidence, _ := types.MaxEvidencePerBlock(maxBytes)
|
|
|
|
evidence := blockExec.evpool.PendingEvidence(maxNumEvidence)
|
|
|
|
|
|
|
|
// Fetch a limited amount of valid txs
|
|
|
|
maxDataBytes := types.MaxDataBytes(maxBytes, state.Validators.Size(), len(evidence))
|
|
|
|
txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas)
|
|
|
|
|
|
|
|
return state.MakeBlock(height, txs, commit, evidence, proposerAddr)
|
|
|
|
}
|
|
|
|
|
2017-12-28 19:35:56 -05: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 {
|
2019-02-09 00:30:45 +01:00
|
|
|
return validateBlock(blockExec.evpool, blockExec.db, state, block)
|
2017-12-28 19:35:56 -05:00
|
|
|
}
|
|
|
|
|
2017-12-27 20:03:48 -05:00
|
|
|
// ApplyBlock validates the block against the state, executes it against the app,
|
2017-12-28 22:10:23 -05:00
|
|
|
// fires the relevant events, commits the app, and saves the new state and responses.
|
2017-12-28 18:58:05 -05:00
|
|
|
// It's the only function that needs to be called
|
2017-12-27 20:03:48 -05: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 20:03:48 -05:00
|
|
|
|
2018-06-04 13:31:57 -07:00
|
|
|
if err := blockExec.ValidateBlock(state, block); err != nil {
|
|
|
|
return state, ErrInvalidBlock(err)
|
2015-03-28 23:44:07 -07:00
|
|
|
}
|
2015-12-01 20:12:01 -08:00
|
|
|
|
2018-10-10 09:27:43 -07:00
|
|
|
startTime := time.Now().UnixNano()
|
2019-05-02 05:15:53 +08:00
|
|
|
abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, blockExec.db)
|
2018-10-10 09:27:43 -07:00
|
|
|
endTime := time.Now().UnixNano()
|
2018-10-12 22:13:01 +02:00
|
|
|
blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000)
|
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 20:03:48 -05:00
|
|
|
fail.Fail() // XXX
|
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// Save the results before we commit.
|
2017-12-27 20:03:48 -05:00
|
|
|
saveABCIResponses(blockExec.db, block.Height, abciResponses)
|
|
|
|
|
|
|
|
fail.Fail() // XXX
|
|
|
|
|
2018-11-28 06:09:27 -08:00
|
|
|
// validate the validator updates and convert to tendermint types
|
|
|
|
abciValUpdates := abciResponses.EndBlock.ValidatorUpdates
|
|
|
|
err = validateValidatorUpdates(abciValUpdates, state.ConsensusParams.Validator)
|
|
|
|
if err != nil {
|
|
|
|
return state, fmt.Errorf("Error in validator updates: %v", err)
|
|
|
|
}
|
|
|
|
validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates)
|
2018-11-28 16:32:16 +03:00
|
|
|
if err != nil {
|
|
|
|
return state, err
|
|
|
|
}
|
|
|
|
if len(validatorUpdates) > 0 {
|
2019-02-08 19:05:09 +01:00
|
|
|
blockExec.logger.Info("Updates to validators", "updates", types.ValidatorListString(validatorUpdates))
|
2018-11-28 16:32:16 +03:00
|
|
|
}
|
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// Update the state with the block and responses.
|
2018-11-28 16:32:16 +03:00
|
|
|
state, err = updateState(state, blockID, &block.Header, abciResponses, validatorUpdates)
|
2017-12-27 20:03:48 -05: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 20:03:48 -05:00
|
|
|
}
|
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// Lock mempool, commit app state, update mempoool.
|
mempool: remove only valid (Code==0) txs on Update (#3625)
* mempool: remove only valid (Code==0) txs on Update
so evil proposers can't drop valid txs in Commit stage.
Also remove invalid (Code!=0) txs from the cache so they can be
resubmitted.
Fixes #3322
@rickyyangz:
In the end of commit stage, we will update mempool to remove all the txs
in current block.
// Update mempool.
err = blockExec.mempool.Update(
block.Height,
block.Txs,
TxPreCheck(state),
TxPostCheck(state),
)
Assum an account has 3 transactions in the mempool, the sequences are
100, 101 and 102 separately, So an evil proposal can only package the
101 and 102 transactions into its proposal block, and leave 100 still in
mempool, then the two txs will be removed from all validators' mempool
when commit. So the account lost the two valid txs.
@ebuchman:
In the longer term we may want to do something like #2639 so we can
validate txs before we commit the block. But even in this case we'd only
want to run the equivalent of CheckTx, which means the DeliverTx could
still fail even if the CheckTx passes depending on how the app handles
the ABCI Code semantics. So more work will be required around the ABCI
code. See also #2185
* add changelog entry and tests
* improve changelog message
* reformat code
2019-05-07 12:25:35 +04:00
|
|
|
appHash, err := blockExec.Commit(state, block, abciResponses.DeliverTx)
|
2017-12-27 20:03:48 -05: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 20:03:48 -05:00
|
|
|
}
|
|
|
|
|
2018-06-04 13:46:34 -07:00
|
|
|
// Update evpool with the block and state.
|
|
|
|
blockExec.evpool.Update(block, state)
|
|
|
|
|
2017-12-27 20:03:48 -05:00
|
|
|
fail.Fail() // XXX
|
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// 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 20:03:48 -05:00
|
|
|
|
2017-12-28 18:58:05 -05:00
|
|
|
fail.Fail() // XXX
|
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// Events are fired after everything else.
|
2017-12-28 18:58:05 -05:00
|
|
|
// NOTE: if we crash between Commit and Save, events wont be fired during replay
|
2018-11-28 16:32:16 +03:00
|
|
|
fireEvents(blockExec.logger, blockExec.eventBus, block, abciResponses, validatorUpdates)
|
2017-12-28 18:58:05 -05:00
|
|
|
|
2018-06-04 13:31:57 -07:00
|
|
|
return state, nil
|
2017-12-27 20:03:48 -05:00
|
|
|
}
|
|
|
|
|
2018-09-21 17:50:06 -07:00
|
|
|
// Commit locks the mempool, runs the ABCI Commit message, and updates the
|
|
|
|
// mempool.
|
2017-12-27 20:03:48 -05:00
|
|
|
// It returns the result of calling abci.Commit (the AppHash), and an error.
|
2018-09-21 17:50:06 -07:00
|
|
|
// 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,
|
mempool: remove only valid (Code==0) txs on Update (#3625)
* mempool: remove only valid (Code==0) txs on Update
so evil proposers can't drop valid txs in Commit stage.
Also remove invalid (Code!=0) txs from the cache so they can be
resubmitted.
Fixes #3322
@rickyyangz:
In the end of commit stage, we will update mempool to remove all the txs
in current block.
// Update mempool.
err = blockExec.mempool.Update(
block.Height,
block.Txs,
TxPreCheck(state),
TxPostCheck(state),
)
Assum an account has 3 transactions in the mempool, the sequences are
100, 101 and 102 separately, So an evil proposal can only package the
101 and 102 transactions into its proposal block, and leave 100 still in
mempool, then the two txs will be removed from all validators' mempool
when commit. So the account lost the two valid txs.
@ebuchman:
In the longer term we may want to do something like #2639 so we can
validate txs before we commit the block. But even in this case we'd only
want to run the equivalent of CheckTx, which means the DeliverTx could
still fail even if the CheckTx passes depending on how the app handles
the ABCI Code semantics. So more work will be required around the ABCI
code. See also #2185
* add changelog entry and tests
* improve changelog message
* reformat code
2019-05-07 12:25:35 +04:00
|
|
|
deliverTxResponses []*abci.ResponseDeliverTx,
|
2018-09-21 17:50:06 -07:00
|
|
|
) ([]byte, error) {
|
2017-12-27 20:03:48 -05:00
|
|
|
blockExec.mempool.Lock()
|
|
|
|
defer blockExec.mempool.Unlock()
|
|
|
|
|
2018-01-23 16:56:14 +04:00
|
|
|
// 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 20:03:48 -05:00
|
|
|
// Commit block, get hash back
|
|
|
|
res, err := blockExec.proxyApp.CommitSync()
|
|
|
|
if err != nil {
|
2018-09-21 17:50:06 -07:00
|
|
|
blockExec.logger.Error(
|
|
|
|
"Client error during proxyAppConn.CommitSync",
|
|
|
|
"err", err,
|
|
|
|
)
|
2017-12-27 20:03:48 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
2018-01-06 01:26:51 -05:00
|
|
|
// ResponseCommit has no error code - just data
|
2017-12-27 20:03:48 -05:00
|
|
|
|
2018-09-21 17:50:06 -07:00
|
|
|
blockExec.logger.Info(
|
|
|
|
"Committed state",
|
2018-02-19 15:32:09 -05:00
|
|
|
"height", block.Height,
|
|
|
|
"txs", block.NumTxs,
|
2018-09-21 17:50:06 -07:00
|
|
|
"appHash", fmt.Sprintf("%X", res.Data),
|
|
|
|
)
|
2017-12-27 20:03:48 -05:00
|
|
|
|
|
|
|
// Update mempool.
|
2018-09-21 17:50:06 -07:00
|
|
|
err = blockExec.mempool.Update(
|
|
|
|
block.Height,
|
|
|
|
block.Txs,
|
mempool: remove only valid (Code==0) txs on Update (#3625)
* mempool: remove only valid (Code==0) txs on Update
so evil proposers can't drop valid txs in Commit stage.
Also remove invalid (Code!=0) txs from the cache so they can be
resubmitted.
Fixes #3322
@rickyyangz:
In the end of commit stage, we will update mempool to remove all the txs
in current block.
// Update mempool.
err = blockExec.mempool.Update(
block.Height,
block.Txs,
TxPreCheck(state),
TxPostCheck(state),
)
Assum an account has 3 transactions in the mempool, the sequences are
100, 101 and 102 separately, So an evil proposal can only package the
101 and 102 transactions into its proposal block, and leave 100 still in
mempool, then the two txs will be removed from all validators' mempool
when commit. So the account lost the two valid txs.
@ebuchman:
In the longer term we may want to do something like #2639 so we can
validate txs before we commit the block. But even in this case we'd only
want to run the equivalent of CheckTx, which means the DeliverTx could
still fail even if the CheckTx passes depending on how the app handles
the ABCI Code semantics. So more work will be required around the ABCI
code. See also #2185
* add changelog entry and tests
* improve changelog message
* reformat code
2019-05-07 12:25:35 +04:00
|
|
|
deliverTxResponses,
|
2018-11-11 16:09:33 +01:00
|
|
|
TxPreCheck(state),
|
|
|
|
TxPostCheck(state),
|
2018-09-21 17:50:06 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
return res.Data, err
|
2015-03-28 23:44:07 -07:00
|
|
|
}
|
|
|
|
|
2017-12-27 20:03:48 -05:00
|
|
|
//---------------------------------------------------------
|
|
|
|
// Helper functions for executing blocks and updating state
|
|
|
|
|
2016-01-06 17:14:20 -08:00
|
|
|
// Executes block's transactions on proxyAppConn.
|
2017-01-19 13:33:58 +04:00
|
|
|
// Returns a list of transaction results and updates to the validator set
|
2018-10-10 09:27:43 -07:00
|
|
|
func execBlockOnProxyApp(
|
2018-10-12 22:13:01 +02:00
|
|
|
logger log.Logger,
|
|
|
|
proxyAppConn proxy.AppConnConsensus,
|
|
|
|
block *types.Block,
|
|
|
|
stateDB dbm.DB,
|
2018-10-10 09:27:43 -07:00
|
|
|
) (*ABCIResponses, error) {
|
2016-01-06 17:14:20 -08:00
|
|
|
var validTxs, invalidTxs = 0, 0
|
2015-12-01 20:12:01 -08:00
|
|
|
|
2017-04-10 22:41:07 +04:00
|
|
|
txIndex := 0
|
2017-04-14 15:33:19 -04:00
|
|
|
abciResponses := NewABCIResponses(block)
|
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// Execute transactions and get hash.
|
2017-01-12 15:53:32 -05:00
|
|
|
proxyCb := func(req *abci.Request, res *abci.Response) {
|
2019-08-02 08:53:52 +02:00
|
|
|
if r, ok := res.Value.(*abci.Response_DeliverTx); ok {
|
2016-01-25 14:34:08 -08:00
|
|
|
// TODO: make use of res.Log
|
2016-01-06 17:14:20 -08:00
|
|
|
// TODO: make use of this info
|
|
|
|
// Blocks may include invalid txs.
|
2017-12-25 13:47:16 -05:00
|
|
|
txRes := r.DeliverTx
|
|
|
|
if txRes.Code == abci.CodeTypeOK {
|
2017-01-19 13:33:58 +04:00
|
|
|
validTxs++
|
2016-01-06 17:14:20 -08:00
|
|
|
} else {
|
2017-12-25 13:47:16 -05:00
|
|
|
logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log)
|
2017-01-19 13:33:58 +04:00
|
|
|
invalidTxs++
|
|
|
|
}
|
2017-12-25 13:47:16 -05:00
|
|
|
abciResponses.DeliverTx[txIndex] = txRes
|
2017-11-15 15:07:08 -06:00
|
|
|
txIndex++
|
2015-12-01 20:12:01 -08:00
|
|
|
}
|
|
|
|
}
|
2016-01-06 17:14:20 -08:00
|
|
|
proxyAppConn.SetResponseCallback(proxyCb)
|
|
|
|
|
2019-05-02 05:15:53 +08:00
|
|
|
commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB)
|
2017-12-25 13:47:16 -05:00
|
|
|
|
2018-11-27 04:21:42 +01:00
|
|
|
// Begin block
|
|
|
|
var err error
|
|
|
|
abciResponses.BeginBlock, err = proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
|
2018-08-16 10:33:53 -04:00
|
|
|
Hash: block.Hash(),
|
|
|
|
Header: types.TM2PB.Header(&block.Header),
|
|
|
|
LastCommitInfo: commitInfo,
|
2018-06-01 15:27:59 -04:00
|
|
|
ByzantineValidators: byzVals,
|
2017-09-22 11:42:40 -04:00
|
|
|
})
|
2016-11-03 19:51:22 -04:00
|
|
|
if err != nil {
|
2017-06-14 12:50:49 +04:00
|
|
|
logger.Error("Error in proxyAppConn.BeginBlock", "err", err)
|
2017-04-14 15:33:19 -04:00
|
|
|
return nil, err
|
2016-11-03 19:51:22 -04:00
|
|
|
}
|
2016-08-06 23:30:46 -04:00
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// Run txs of block.
|
2016-01-06 17:14:20 -08:00
|
|
|
for _, tx := range block.Txs {
|
abci: Refactor CheckTx to notify of recheck (#3744)
As per #2127, this refactors the RequestCheckTx ProtoBuf struct to allow for a flag indicating whether a query is a recheck or not (and allows for possible future, more nuanced states).
In order to pass this extended information through to the ABCI app, the proxy.AppConnMempool (and, for consistency, the proxy.AppConnConsensus) interface seems to need to be refactored along with abcicli.Client.
And, as per this comment, I've made the following modification to the protobuf definition for the RequestCheckTx structure:
enum CheckTxType {
New = 0;
Recheck = 1;
}
message RequestCheckTx {
bytes tx = 1;
CheckTxType type = 2;
}
* Refactor ABCI CheckTx to notify of recheck
As per #2127, this refactors the `RequestCheckTx` ProtoBuf struct to allow for:
1. a flag indicating whether a query is a recheck or not (and allows for
possible future, more nuanced states)
2. an `additional_data` bytes array to provide information for those more
nuanced states.
In order to pass this extended information through to the ABCI app, the
`proxy.AppConnMempool` (and, for consistency, the
`proxy.AppConnConsensus`) interface seems to need to be refactored.
Commits:
* Fix linting issue
* Add CHANGELOG_PENDING entry
* Remove extraneous explicit initialization
* Update ABCI spec doc to include new CheckTx params
* Rename method param for consistency
* Rename CheckTxType enum values and remove additional_data param
2019-07-02 10:14:53 -04:00
|
|
|
proxyAppConn.DeliverTxAsync(abci.RequestDeliverTx{Tx: tx})
|
2016-01-06 17:14:20 -08:00
|
|
|
if err := proxyAppConn.Error(); err != nil {
|
2017-04-14 15:33:19 -04:00
|
|
|
return nil, err
|
2015-12-01 20:12:01 -08:00
|
|
|
}
|
|
|
|
}
|
2016-03-05 20:57:36 -08:00
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// End block.
|
2018-07-27 06:23:19 +04:00
|
|
|
abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{Height: block.Height})
|
2016-03-05 20:57:36 -08:00
|
|
|
if err != nil {
|
2017-06-14 12:50:49 +04:00
|
|
|
logger.Error("Error in proxyAppConn.EndBlock", "err", err)
|
2017-04-14 15:33:19 -04:00
|
|
|
return nil, err
|
2016-03-05 20:57:36 -08:00
|
|
|
}
|
2016-09-11 15:32:33 -04:00
|
|
|
|
2017-06-14 14:41:36 +08:00
|
|
|
logger.Info("Executed block", "height", block.Height, "validTxs", validTxs, "invalidTxs", invalidTxs)
|
2017-12-22 14:07:46 -06:00
|
|
|
|
2017-04-14 15:33:19 -04:00
|
|
|
return abciResponses, nil
|
2016-11-19 19:32:35 -05:00
|
|
|
}
|
|
|
|
|
2019-05-02 05:15:53 +08:00
|
|
|
func getBeginBlockValidatorInfo(block *types.Block, stateDB dbm.DB) (abci.LastCommitInfo, []abci.Evidence) {
|
|
|
|
voteInfos := make([]abci.VoteInfo, block.LastCommit.Size())
|
|
|
|
byzVals := make([]abci.Evidence, len(block.Evidence.Evidence))
|
|
|
|
var lastValSet *types.ValidatorSet
|
|
|
|
var err error
|
2018-06-01 15:27:59 -04:00
|
|
|
if block.Height > 1 {
|
2019-05-02 05:15:53 +08:00
|
|
|
lastValSet, err = LoadValidators(stateDB, block.Height-1)
|
|
|
|
if err != nil {
|
|
|
|
panic(err) // shouldn't happen
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sanity check that commit length matches validator set size -
|
|
|
|
// only applies after first block
|
|
|
|
|
|
|
|
precommitLen := block.LastCommit.Size()
|
2018-06-01 15:27:59 -04:00
|
|
|
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))
|
|
|
|
}
|
2019-05-02 05:15:53 +08:00
|
|
|
} else {
|
|
|
|
lastValSet = types.NewValidatorSet(nil)
|
2018-06-01 15:27:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, val := range lastValSet.Validators {
|
2019-02-04 13:01:59 -05:00
|
|
|
var vote *types.CommitSig
|
2018-06-01 15:27:59 -04:00
|
|
|
if i < len(block.LastCommit.Precommits) {
|
|
|
|
vote = block.LastCommit.Precommits[i]
|
|
|
|
}
|
2018-08-06 00:18:24 -04:00
|
|
|
voteInfo := abci.VoteInfo{
|
|
|
|
Validator: types.TM2PB.Validator(val),
|
2018-08-16 10:33:53 -04:00
|
|
|
SignedLastBlock: vote != nil,
|
2019-09-06 11:20:28 +02:00
|
|
|
// TODO: maybe make it optional, set by config, disabled by default?
|
|
|
|
FullVote: types.TM2PB.Vote(vote),
|
2018-06-01 15:27:59 -04:00
|
|
|
}
|
2018-08-06 00:18:24 -04:00
|
|
|
voteInfos[i] = voteInfo
|
2018-06-01 15:27:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2018-06-01 15:27:59 -04:00
|
|
|
}
|
|
|
|
byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time)
|
|
|
|
}
|
|
|
|
|
2019-05-02 05:15:53 +08:00
|
|
|
commitInfo := abci.LastCommitInfo{
|
|
|
|
Round: int32(block.LastCommit.Round()),
|
|
|
|
Votes: voteInfos,
|
|
|
|
}
|
2018-08-16 10:33:53 -04:00
|
|
|
return commitInfo, byzVals
|
2018-06-01 15:27:59 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-11-28 06:09:27 -08:00
|
|
|
func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate,
|
|
|
|
params types.ValidatorParams) error {
|
|
|
|
for _, valUpdate := range abciUpdates {
|
|
|
|
if valUpdate.GetPower() < 0 {
|
|
|
|
return fmt.Errorf("Voting power can't be negative %v", valUpdate)
|
|
|
|
} else if valUpdate.GetPower() == 0 {
|
|
|
|
// continue, since this is deleting the validator, and thus there is no
|
|
|
|
// pubkey to check
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if validator's pubkey matches an ABCI type in the consensus params
|
|
|
|
thisKeyType := valUpdate.PubKey.Type
|
|
|
|
if !params.IsValidPubkeyType(thisKeyType) {
|
|
|
|
return fmt.Errorf("Validator %v is using pubkey %s, which is unsupported for consensus",
|
|
|
|
valUpdate, thisKeyType)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-12-27 20:03:48 -05:00
|
|
|
// updateState returns a new State updated according to the header and responses.
|
2018-10-10 09:27:43 -07:00
|
|
|
func updateState(
|
2018-10-12 22:13:01 +02:00
|
|
|
state State,
|
|
|
|
blockID types.BlockID,
|
|
|
|
header *types.Header,
|
|
|
|
abciResponses *ABCIResponses,
|
2018-11-28 16:32:16 +03:00
|
|
|
validatorUpdates []*types.Validator,
|
2018-10-10 09:27:43 -07:00
|
|
|
) (State, error) {
|
2017-12-20 23:53:15 -05:00
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// Copy the valset so we can apply changes from EndBlock
|
|
|
|
// and update s.LastValidators and s.Validators.
|
|
|
|
nValSet := state.NextValidators.Copy()
|
2017-12-20 23:53:15 -05:00
|
|
|
|
2018-05-29 01:03:03 -07:00
|
|
|
// Update the validator set with the latest abciResponses.
|
2018-06-04 13:31:57 -07:00
|
|
|
lastHeightValsChanged := state.LastHeightValidatorsChanged
|
2018-11-28 06:09:27 -08:00
|
|
|
if len(validatorUpdates) > 0 {
|
2019-02-08 19:05:09 +01:00
|
|
|
err := nValSet.UpdateWithChangeSet(validatorUpdates)
|
2016-09-11 13:16:23 -04:00
|
|
|
if err != nil {
|
2018-06-04 13:31:57 -07:00
|
|
|
return state, fmt.Errorf("Error changing validator set: %v", err)
|
2016-09-11 13:16:23 -04:00
|
|
|
}
|
2018-05-29 01:03:03 -07:00
|
|
|
// Change results from this height but only applies to the next next height.
|
|
|
|
lastHeightValsChanged = header.Height + 1 + 1
|
2016-09-11 13:16:23 -04:00
|
|
|
}
|
|
|
|
|
2018-11-28 21:35:09 +01:00
|
|
|
// Update validator proposer priority and set state variables.
|
|
|
|
nValSet.IncrementProposerPriority(1)
|
2017-12-27 20:03:48 -05:00
|
|
|
|
2018-05-29 01:03:03 -07: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 20:03:48 -05: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 20:03:48 -05:00
|
|
|
err := nextParams.Validate()
|
2017-12-27 19:21:16 -05: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 12:29:38 -04:00
|
|
|
}
|
2018-05-29 01:03:03 -07:00
|
|
|
// Change results from this height but only applies to the next height.
|
2017-12-27 20:03:48 -05:00
|
|
|
lastHeightParamsChanged = header.Height + 1
|
|
|
|
}
|
|
|
|
|
2018-10-17 15:30:53 -04:00
|
|
|
// TODO: allow app to upgrade version
|
|
|
|
nextVersion := state.Version
|
|
|
|
|
2017-12-27 20:03:48 -05:00
|
|
|
// NOTE: the AppHash has not been populated.
|
|
|
|
// It will be filled on state.Save.
|
|
|
|
return State{
|
2018-10-17 15:30:53 -04:00
|
|
|
Version: nextVersion,
|
2018-06-04 13:31:57 -07:00
|
|
|
ChainID: state.ChainID,
|
2017-12-27 20:03:48 -05:00
|
|
|
LastBlockHeight: header.Height,
|
2018-06-04 13:31:57 -07:00
|
|
|
LastBlockTotalTx: state.LastBlockTotalTx + header.NumTxs,
|
2017-12-27 20:03:48 -05:00
|
|
|
LastBlockID: blockID,
|
|
|
|
LastBlockTime: header.Time,
|
2018-05-29 01:03:03 -07:00
|
|
|
NextValidators: nValSet,
|
|
|
|
Validators: state.NextValidators.Copy(),
|
2018-06-04 13:31:57 -07:00
|
|
|
LastValidators: state.Validators.Copy(),
|
2017-12-27 20:03:48 -05:00
|
|
|
LastHeightValidatorsChanged: lastHeightValsChanged,
|
|
|
|
ConsensusParams: nextParams,
|
|
|
|
LastHeightConsensusParamsChanged: lastHeightParamsChanged,
|
|
|
|
LastResultsHash: abciResponses.ResultsHash(),
|
|
|
|
AppHash: nil,
|
|
|
|
}, nil
|
2015-12-01 20:12:01 -08:00
|
|
|
}
|
2016-08-23 21:44:07 -04:00
|
|
|
|
2017-12-28 18:58:05 -05: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.
|
2018-11-28 16:32:16 +03:00
|
|
|
func fireEvents(logger log.Logger, eventBus types.BlockEventPublisher, block *types.Block, abciResponses *ABCIResponses, validatorUpdates []*types.Validator) {
|
2018-11-27 04:21:42 +01:00
|
|
|
eventBus.PublishEventNewBlock(types.EventDataNewBlock{
|
|
|
|
Block: block,
|
|
|
|
ResultBeginBlock: *abciResponses.BeginBlock,
|
|
|
|
ResultEndBlock: *abciResponses.EndBlock,
|
|
|
|
})
|
|
|
|
eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{
|
|
|
|
Header: block.Header,
|
|
|
|
ResultBeginBlock: *abciResponses.BeginBlock,
|
|
|
|
ResultEndBlock: *abciResponses.EndBlock,
|
|
|
|
})
|
2018-05-11 12:09:41 +04:00
|
|
|
|
2017-12-27 22:09:48 -05:00
|
|
|
for i, tx := range block.Data.Txs {
|
2019-02-11 16:31:34 +04:00
|
|
|
eventBus.PublishEventTx(types.EventDataTx{TxResult: types.TxResult{
|
2017-12-27 19:21:16 -05:00
|
|
|
Height: block.Height,
|
2017-12-27 22:09:48 -05:00
|
|
|
Index: uint32(i),
|
2017-12-27 19:21:16 -05:00
|
|
|
Tx: tx,
|
2017-12-27 22:09:48 -05:00
|
|
|
Result: *(abciResponses.DeliverTx[i]),
|
2017-12-27 19:21:16 -05:00
|
|
|
}})
|
2017-12-27 22:09:48 -05:00
|
|
|
}
|
2018-08-14 19:16:35 +04:00
|
|
|
|
2018-11-28 16:32:16 +03:00
|
|
|
if len(validatorUpdates) > 0 {
|
2018-08-14 19:16:35 +04:00
|
|
|
eventBus.PublishEventValidatorSetUpdates(
|
2018-11-28 16:32:16 +03:00
|
|
|
types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates})
|
2018-08-14 19:16:35 +04:00
|
|
|
}
|
2016-09-11 13:16:23 -04:00
|
|
|
}
|
2016-08-23 21:44:07 -04:00
|
|
|
|
2017-12-27 20:03:48 -05:00
|
|
|
//----------------------------------------------------------------------------------------------------
|
|
|
|
// Execute block without state. TODO: eliminate
|
2016-08-25 00:18:03 -04:00
|
|
|
|
2017-08-21 16:12:07 -04: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-10-10 09:27:43 -07:00
|
|
|
func ExecCommitBlock(
|
2018-10-12 22:13:01 +02:00
|
|
|
appConnConsensus proxy.AppConnConsensus,
|
|
|
|
block *types.Block,
|
|
|
|
logger log.Logger,
|
|
|
|
stateDB dbm.DB,
|
2018-10-10 09:27:43 -07:00
|
|
|
) ([]byte, error) {
|
2019-05-02 05:15:53 +08:00
|
|
|
_, err := execBlockOnProxyApp(logger, appConnConsensus, block, stateDB)
|
2017-02-17 11:32:56 -05:00
|
|
|
if err != nil {
|
2017-05-02 11:53:32 +04:00
|
|
|
logger.Error("Error executing block on proxy app", "height", block.Height, "err", err)
|
2017-02-17 11:32:56 -05:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
// Commit block, get hash back
|
2017-11-22 18:55:09 -06:00
|
|
|
res, err := appConnConsensus.CommitSync()
|
|
|
|
if err != nil {
|
|
|
|
logger.Error("Client error during proxyAppConn.CommitSync", "err", res)
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-01-06 01:26:51 -05:00
|
|
|
// ResponseCommit has no error or log, just data
|
2017-02-17 11:32:56 -05:00
|
|
|
return res.Data, nil
|
|
|
|
}
|