github.com/pokt-network/tendermint@v0.32.11-0.20230426215212-59310158d3e9/state/execution.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/tendermint/tendermint/state/txindex"
     6  	"time"
     7  
     8  	dbm "github.com/tendermint/tm-db"
     9  
    10  	abci "github.com/tendermint/tendermint/abci/types"
    11  	"github.com/tendermint/tendermint/libs/fail"
    12  	"github.com/tendermint/tendermint/libs/log"
    13  	mempl "github.com/tendermint/tendermint/mempool"
    14  	"github.com/tendermint/tendermint/proxy"
    15  	"github.com/tendermint/tendermint/types"
    16  )
    17  
    18  //-----------------------------------------------------------------------------
    19  // BlockExecutor handles block execution and state updates.
    20  // It exposes ApplyBlock(), which validates & executes the block, updates state w/ ABCI responses,
    21  // then commits and updates the mempool atomically, then saves state.
    22  
    23  // BlockExecutor provides the context and accessories for properly executing a block.
    24  type BlockExecutor struct {
    25  	// save state, validators, consensus params, abci responses here
    26  	db dbm.DB
    27  
    28  	// execute the app against this
    29  	proxyApp proxy.AppConnConsensus
    30  
    31  	// events
    32  	eventBus types.BlockEventPublisher
    33  
    34  	// manage the mempool lock during commit
    35  	// and update both with block results after commit.
    36  	mempool mempl.Mempool
    37  	evpool  EvidencePool
    38  
    39  	logger log.Logger
    40  
    41  	metrics *Metrics
    42  
    43  	indexer txindex.TxIndexer
    44  }
    45  
    46  type BlockExecutorOption func(executor *BlockExecutor)
    47  
    48  func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption {
    49  	return func(blockExec *BlockExecutor) {
    50  		blockExec.metrics = metrics
    51  	}
    52  }
    53  
    54  // NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
    55  // Call SetEventBus to provide one.
    56  func NewBlockExecutor(
    57  	db dbm.DB,
    58  	logger log.Logger,
    59  	proxyApp proxy.AppConnConsensus,
    60  	mempool mempl.Mempool,
    61  	evpool EvidencePool,
    62  	indexer txindex.TxIndexer,
    63  	options ...BlockExecutorOption,
    64  ) *BlockExecutor {
    65  	res := &BlockExecutor{
    66  		db:       db,
    67  		proxyApp: proxyApp,
    68  		eventBus: types.NopEventBus{},
    69  		mempool:  mempool,
    70  		evpool:   evpool,
    71  		logger:   logger,
    72  		metrics:  NopMetrics(),
    73  		indexer:  indexer,
    74  	}
    75  
    76  	for _, option := range options {
    77  		option(res)
    78  	}
    79  
    80  	return res
    81  }
    82  
    83  func (blockExec *BlockExecutor) DB() dbm.DB {
    84  	return blockExec.db
    85  }
    86  
    87  // SetEventBus - sets the event bus for publishing block related events.
    88  // If not called, it defaults to types.NopEventBus.
    89  func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) {
    90  	blockExec.eventBus = eventBus
    91  }
    92  
    93  // CreateProposalBlock calls state.MakeBlock with evidence from the evpool
    94  // and txs from the mempool. The max bytes must be big enough to fit the commit.
    95  // Up to 1/10th of the block space is allcoated for maximum sized evidence.
    96  // The rest is given to txs, up to the max gas.
    97  func (blockExec *BlockExecutor) CreateProposalBlock(
    98  	height int64,
    99  	state State, commit *types.Commit,
   100  	proposerAddr []byte,
   101  ) (*types.Block, *types.PartSet) {
   102  
   103  	maxBytes := state.ConsensusParams.Block.MaxBytes
   104  	maxGas := state.ConsensusParams.Block.MaxGas
   105  
   106  	// Fetch a limited amount of valid evidence
   107  	maxNumEvidence, _ := types.MaxEvidencePerBlock(maxBytes)
   108  	evidence := blockExec.evpool.PendingEvidence(maxNumEvidence)
   109  
   110  	// Fetch a limited amount of valid txs
   111  	maxDataBytes := types.MaxDataBytes(maxBytes, state.Validators.Size(), len(evidence))
   112  	txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas)
   113  
   114  	return state.MakeBlock(height, txs, commit, evidence, proposerAddr)
   115  }
   116  
   117  // ValidateBlock validates the given block against the given state.
   118  // If the block is invalid, it returns an error.
   119  // Validation does not mutate state, but does require historical information from the stateDB,
   120  // ie. to verify evidence from a validator at an old height.
   121  func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) error {
   122  	defer types.TimeTrack(time.Now(), blockExec.logger)
   123  	return validateBlock(blockExec.evpool, blockExec.db, state, block)
   124  }
   125  
   126  // ApplyBlock validates the block against the state, executes it against the app,
   127  // fires the relevant events, commits the app, and saves the new state and responses.
   128  // It returns the new state and the block height to retain (pruning older blocks).
   129  // It's the only function that needs to be called
   130  // from outside this package to process and commit an entire block.
   131  // It takes a blockID to avoid recomputing the parts hash.
   132  func (blockExec *BlockExecutor) ApplyBlock(
   133  	state State, blockID types.BlockID, block *types.Block,
   134  ) (State, int64, error) {
   135  	defer types.TimeTrack(time.Now(), blockExec.logger)
   136  
   137  	if err := blockExec.ValidateBlock(state, block); err != nil {
   138  		return state, 0, ErrInvalidBlock(err)
   139  	}
   140  
   141  	startTime := time.Now().UnixNano()
   142  	abciResponses, err := execBlockOnProxyApp(blockExec.logger, blockExec.proxyApp, block, blockExec.db)
   143  	endTime := time.Now().UnixNano()
   144  	blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000)
   145  	if err != nil {
   146  		return state, 0, ErrProxyAppConn(err)
   147  	}
   148  
   149  	fail.Fail() // XXX
   150  
   151  	// Save the results before we commit.
   152  	SaveABCIResponses(blockExec.db, block.Height, abciResponses)
   153  
   154  	fail.Fail() // XXX
   155  
   156  	// validate the validator updates and convert to tendermint types
   157  	abciValUpdates := abciResponses.EndBlock.ValidatorUpdates
   158  	err = validateValidatorUpdates(abciValUpdates, state.ConsensusParams.Validator)
   159  	if err != nil {
   160  		return state, 0, fmt.Errorf("error in validator updates: %v", err)
   161  	}
   162  	validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates)
   163  	if err != nil {
   164  		return state, 0, err
   165  	}
   166  	if len(validatorUpdates) > 0 {
   167  		blockExec.logger.Info("Updates to validators", "updates", types.ValidatorListString(validatorUpdates))
   168  	}
   169  
   170  	// Update the state with the block and responses.
   171  	state, err = updateState(state, blockID, &block.Header, abciResponses, validatorUpdates)
   172  	if err != nil {
   173  		return state, 0, fmt.Errorf("commit failed for application: %v", err)
   174  	}
   175  
   176  	// Lock mempool, commit app state, update mempoool.
   177  	appHash, retainHeight, err := blockExec.Commit(state, block, abciResponses.DeliverTx)
   178  	if err != nil {
   179  		return state, 0, fmt.Errorf("commit failed for application: %v", err)
   180  	}
   181  
   182  	// Update evpool with the block and state.
   183  	blockExec.evpool.Update(block, state)
   184  
   185  	fail.Fail() // XXX
   186  
   187  	// Update the app hash and save the state.
   188  	state.AppHash = appHash
   189  	SaveState(blockExec.db, state)
   190  
   191  	fail.Fail() // XXX
   192  
   193  	// Events are fired after everything else.
   194  	// NOTE: if we crash between Commit and Save, events wont be fired during replay
   195  	fireEvents(blockExec.logger, blockExec.eventBus, block, abciResponses, validatorUpdates)
   196  
   197  	return state, retainHeight, nil
   198  }
   199  
   200  // Commit locks the mempool, runs the ABCI Commit message, and updates the
   201  // mempool.
   202  // It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any).
   203  // The Mempool must be locked during commit and update because state is
   204  // typically reset on Commit and old txs must be replayed against committed
   205  // state before new txs are run in the mempool, lest they be invalid.
   206  func (blockExec *BlockExecutor) Commit(
   207  	state State,
   208  	block *types.Block,
   209  	deliverTxResponses []*abci.ResponseDeliverTx,
   210  ) ([]byte, int64, error) {
   211  	defer types.TimeTrack(time.Now(), blockExec.logger)
   212  
   213  	blockExec.mempool.Lock()
   214  	defer blockExec.mempool.Unlock()
   215  
   216  	// while mempool is Locked, flush to ensure all async requests have completed
   217  	// in the ABCI app before Commit.
   218  	err := blockExec.mempool.FlushAppConn()
   219  	if err != nil {
   220  		blockExec.logger.Error("Client error during mempool.FlushAppConn", "err", err)
   221  		return nil, 0, err
   222  	}
   223  
   224  	// Commit block, get hash back
   225  	res, err := blockExec.proxyApp.CommitSync()
   226  	if err != nil {
   227  		blockExec.logger.Error(
   228  			"Client error during proxyAppConn.CommitSync",
   229  			"err", err,
   230  		)
   231  		return nil, 0, err
   232  	}
   233  	// ResponseCommit has no error code - just data
   234  
   235  	blockExec.logger.Info(
   236  		"Committed state",
   237  		"height", block.Height,
   238  		"txs", block.NumTxs,
   239  		"appHash", fmt.Sprintf("%X", res.Data),
   240  	)
   241  
   242  	// Update mempool.
   243  	err = blockExec.mempool.Update(
   244  		block.Height,
   245  		block.Txs,
   246  		deliverTxResponses,
   247  		TxPreCheck(state),
   248  		TxPostCheck(state),
   249  	)
   250  	// create a new batch
   251  	b := txindex.NewBatch(block.NumTxs)
   252  	for i, tx := range block.Txs {
   253  		err := b.Add(&types.TxResult{
   254  			Height: block.Height,
   255  			Index:  uint32(i),
   256  			Tx:     tx,
   257  			Result: *(deliverTxResponses[i]),
   258  		})
   259  		if err != nil {
   260  			return nil, 0, err
   261  		}
   262  	}
   263  	// update txIndexer
   264  	txindex.SyncTxIndexer(blockExec.logger, blockExec.indexer, b, block.Height)
   265  	return res.Data, res.RetainHeight, err
   266  }
   267  
   268  //---------------------------------------------------------
   269  // Helper functions for executing blocks and updating state
   270  
   271  // Executes block's transactions on proxyAppConn.
   272  // Returns a list of transaction results and updates to the validator set
   273  func execBlockOnProxyApp(
   274  	logger log.Logger,
   275  	proxyAppConn proxy.AppConnConsensus,
   276  	block *types.Block,
   277  	stateDB dbm.DB,
   278  ) (*ABCIResponses, error) {
   279  	defer types.TimeTrack(time.Now(), logger)
   280  
   281  	var validTxs, invalidTxs = 0, 0
   282  
   283  	txIndex := 0
   284  	abciResponses := NewABCIResponses(block)
   285  
   286  	// Execute transactions and get hash.
   287  	proxyCb := func(req *abci.Request, res *abci.Response) {
   288  		if r, ok := res.Value.(*abci.Response_DeliverTx); ok {
   289  			// TODO: make use of res.Log
   290  			// TODO: make use of this info
   291  			// Blocks may include invalid txs.
   292  			txRes := r.DeliverTx
   293  			if txRes.Code == abci.CodeTypeOK {
   294  				validTxs++
   295  			} else {
   296  				logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log)
   297  				invalidTxs++
   298  			}
   299  			abciResponses.DeliverTx[txIndex] = txRes
   300  			txIndex++
   301  		}
   302  	}
   303  	proxyAppConn.SetResponseCallback(proxyCb)
   304  
   305  	commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB)
   306  
   307  	// Begin block
   308  	var err error
   309  	abciResponses.BeginBlock, err = proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
   310  		Hash:                block.Hash(),
   311  		Header:              types.TM2PB.Header(&block.Header),
   312  		LastCommitInfo:      commitInfo,
   313  		ByzantineValidators: byzVals,
   314  	})
   315  	if err != nil {
   316  		logger.Error("Error in proxyAppConn.BeginBlock", "err", err)
   317  		return nil, err
   318  	}
   319  
   320  	// Run txs of block.
   321  	for _, tx := range block.Txs {
   322  		proxyAppConn.DeliverTxAsync(abci.RequestDeliverTx{Tx: tx})
   323  		if err := proxyAppConn.Error(); err != nil {
   324  			return nil, err
   325  		}
   326  	}
   327  
   328  	// End block.
   329  	abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{Height: block.Height})
   330  	if err != nil {
   331  		logger.Error("Error in proxyAppConn.EndBlock", "err", err)
   332  		return nil, err
   333  	}
   334  
   335  	logger.Info("Executed block", "height", block.Height, "validTxs", validTxs, "invalidTxs", invalidTxs)
   336  
   337  	return abciResponses, nil
   338  }
   339  
   340  func getBeginBlockValidatorInfo(block *types.Block, stateDB dbm.DB) (abci.LastCommitInfo, []abci.Evidence) {
   341  	defer types.TimeTrack(time.Now(), nil)
   342  
   343  	voteInfos := make([]abci.VoteInfo, block.LastCommit.Size())
   344  	// block.Height=1 -> LastCommitInfo.Votes are empty.
   345  	// Remember that the first LastCommit is intentionally empty, so it makes
   346  	// sense for LastCommitInfo.Votes to also be empty.
   347  	if block.Height > 1 {
   348  		lastValSet, err := LoadValidators(stateDB, block.Height-1)
   349  		if err != nil {
   350  			panic(err)
   351  		}
   352  
   353  		// Sanity check that commit size matches validator set size - only applies
   354  		// after first block.
   355  		var (
   356  			commitSize = block.LastCommit.Size()
   357  			valSetLen  = len(lastValSet.Validators)
   358  		)
   359  		if commitSize != valSetLen {
   360  			panic(fmt.Sprintf("commit size (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v",
   361  				commitSize, valSetLen, block.Height, block.LastCommit.Precommits, lastValSet.Validators))
   362  		}
   363  
   364  		for i, val := range lastValSet.Validators {
   365  			commitSig := block.LastCommit.Precommits[i]
   366  			voteInfos[i] = abci.VoteInfo{
   367  				Validator:       types.TM2PB.Validator(val),
   368  				SignedLastBlock: commitSig != nil,
   369  			}
   370  		}
   371  	}
   372  
   373  	byzVals := make([]abci.Evidence, len(block.Evidence.Evidence))
   374  	for i, ev := range block.Evidence.Evidence {
   375  		// We need the validator set. We already did this in validateBlock.
   376  		// TODO: Should we instead cache the valset in the evidence itself and add
   377  		// `SetValidatorSet()` and `ToABCI` methods ?
   378  		valset, err := LoadValidators(stateDB, ev.Height())
   379  		if err != nil {
   380  			panic(err)
   381  		}
   382  		byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time)
   383  	}
   384  
   385  	return abci.LastCommitInfo{
   386  		Round: int32(block.LastCommit.Round()),
   387  		Votes: voteInfos,
   388  	}, byzVals
   389  }
   390  
   391  func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate,
   392  	params types.ValidatorParams) error {
   393  	defer types.TimeTrack(time.Now(), nil)
   394  
   395  	for _, valUpdate := range abciUpdates {
   396  		if valUpdate.GetPower() < 0 {
   397  			return fmt.Errorf("voting power can't be negative %v", valUpdate)
   398  		} else if valUpdate.GetPower() == 0 {
   399  			// continue, since this is deleting the validator, and thus there is no
   400  			// pubkey to check
   401  			continue
   402  		}
   403  
   404  		// Check if validator's pubkey matches an ABCI type in the consensus params
   405  		thisKeyType := valUpdate.PubKey.Type
   406  		if !params.IsValidPubkeyType(thisKeyType) {
   407  			return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus",
   408  				valUpdate, thisKeyType)
   409  		}
   410  	}
   411  	return nil
   412  }
   413  
   414  // updateState returns a new State updated according to the header and responses.
   415  func updateState(
   416  	state State,
   417  	blockID types.BlockID,
   418  	header *types.Header,
   419  	abciResponses *ABCIResponses,
   420  	validatorUpdates []*types.Validator,
   421  ) (State, error) {
   422  
   423  	defer types.TimeTrack(time.Now(), nil)
   424  
   425  	// Copy the valset so we can apply changes from EndBlock
   426  	// and update s.LastValidators and s.Validators.
   427  	nValSet := state.NextValidators.Copy()
   428  
   429  	// Update the validator set with the latest abciResponses.
   430  	lastHeightValsChanged := state.LastHeightValidatorsChanged
   431  	if len(validatorUpdates) > 0 {
   432  		err := nValSet.UpdateWithChangeSet(validatorUpdates)
   433  		if err != nil {
   434  			return state, fmt.Errorf("error changing validator set: %v", err)
   435  		}
   436  		// Change results from this height but only applies to the next next height.
   437  		lastHeightValsChanged = header.Height + 1 + 1
   438  	}
   439  
   440  	// Update validator proposer priority and set state variables.
   441  	nValSet.IncrementProposerPriority(1)
   442  
   443  	// Update the params with the latest abciResponses.
   444  	nextParams := state.ConsensusParams
   445  	lastHeightParamsChanged := state.LastHeightConsensusParamsChanged
   446  	if abciResponses.EndBlock.ConsensusParamUpdates != nil {
   447  		// NOTE: must not mutate s.ConsensusParams
   448  		nextParams = state.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates)
   449  		err := nextParams.Validate()
   450  		if err != nil {
   451  			return state, fmt.Errorf("error updating consensus params: %v", err)
   452  		}
   453  		// Change results from this height but only applies to the next height.
   454  		lastHeightParamsChanged = header.Height + 1
   455  	}
   456  
   457  	// TODO: allow app to upgrade version
   458  	nextVersion := state.Version
   459  
   460  	// NOTE: the AppHash has not been populated.
   461  	// It will be filled on state.Save.
   462  	return State{
   463  		Version:                          nextVersion,
   464  		ChainID:                          state.ChainID,
   465  		LastBlockHeight:                  header.Height,
   466  		LastBlockTotalTx:                 state.LastBlockTotalTx + header.NumTxs,
   467  		LastBlockID:                      blockID,
   468  		LastBlockTime:                    header.Time,
   469  		NextValidators:                   nValSet,
   470  		Validators:                       state.NextValidators.Copy(),
   471  		LastValidators:                   state.Validators.Copy(),
   472  		LastHeightValidatorsChanged:      lastHeightValsChanged,
   473  		ConsensusParams:                  nextParams,
   474  		LastHeightConsensusParamsChanged: lastHeightParamsChanged,
   475  		LastResultsHash:                  abciResponses.ResultsHash(),
   476  		AppHash:                          nil,
   477  	}, nil
   478  }
   479  
   480  // Fire NewBlock, NewBlockHeader.
   481  // Fire TxEvent for every tx.
   482  // NOTE: if Tendermint crashes before commit, some or all of these events may be published again.
   483  func fireEvents(
   484  	logger log.Logger,
   485  	eventBus types.BlockEventPublisher,
   486  	block *types.Block,
   487  	abciResponses *ABCIResponses,
   488  	validatorUpdates []*types.Validator,
   489  ) {
   490  	eventBus.PublishEventNewBlock(types.EventDataNewBlock{
   491  		Block:            block,
   492  		ResultBeginBlock: *abciResponses.BeginBlock,
   493  		ResultEndBlock:   *abciResponses.EndBlock,
   494  	})
   495  	eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{
   496  		Header:           block.Header,
   497  		NumTxs:           int64(len(block.Txs)),
   498  		ResultBeginBlock: *abciResponses.BeginBlock,
   499  		ResultEndBlock:   *abciResponses.EndBlock,
   500  	})
   501  
   502  	for i, tx := range block.Data.Txs {
   503  		eventBus.PublishEventTx(types.EventDataTx{TxResult: types.TxResult{
   504  			Height: block.Height,
   505  			Index:  uint32(i),
   506  			Tx:     tx,
   507  			Result: *(abciResponses.DeliverTx[i]),
   508  		}})
   509  	}
   510  
   511  	if len(validatorUpdates) > 0 {
   512  		eventBus.PublishEventValidatorSetUpdates(
   513  			types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates})
   514  	}
   515  }
   516  
   517  //----------------------------------------------------------------------------------------------------
   518  // Execute block without state. TODO: eliminate
   519  
   520  // ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
   521  // It returns the application root hash (result of abci.Commit).
   522  func ExecCommitBlock(
   523  	appConnConsensus proxy.AppConnConsensus,
   524  	block *types.Block,
   525  	logger log.Logger,
   526  	stateDB dbm.DB,
   527  	indexer txindex.TxIndexer,
   528  ) ([]byte, error) {
   529  	defer types.TimeTrack(time.Now(), logger)
   530  
   531  	resp, err := execBlockOnProxyApp(logger, appConnConsensus, block, stateDB)
   532  	if err != nil {
   533  		logger.Error("Error executing block on proxy app", "height", block.Height, "err", err)
   534  		return nil, err
   535  	}
   536  	// Commit block, get hash back
   537  	res, err := appConnConsensus.CommitSync()
   538  	if err != nil {
   539  		logger.Error("Client error during proxyAppConn.CommitSync", "err", res)
   540  		return nil, err
   541  	}
   542  	// create a new batch
   543  	b := txindex.NewBatch(block.NumTxs)
   544  	for i, tx := range block.Txs {
   545  		err := b.Add(&types.TxResult{
   546  			Height: block.Height,
   547  			Index:  uint32(i),
   548  			Tx:     tx,
   549  			Result: *(resp.DeliverTx[i]),
   550  		})
   551  		if err != nil {
   552  			return nil, err
   553  		}
   554  	}
   555  	// update txIndexer
   556  	txindex.SyncTxIndexer(logger, indexer, b, block.Height)
   557  	// ResponseCommit has no error or log, just data
   558  	return res.Data, nil
   559  }