github.com/aakash4dev/cometbft@v0.38.2/state/execution.go (about)

     1  package state
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"time"
     8  
     9  	abci "github.com/aakash4dev/cometbft/abci/types"
    10  	cryptoenc "github.com/aakash4dev/cometbft/crypto/encoding"
    11  	"github.com/aakash4dev/cometbft/libs/fail"
    12  	"github.com/aakash4dev/cometbft/libs/log"
    13  	"github.com/aakash4dev/cometbft/mempool"
    14  	cmtproto "github.com/aakash4dev/cometbft/proto/tendermint/types"
    15  	"github.com/aakash4dev/cometbft/proxy"
    16  	"github.com/aakash4dev/cometbft/types"
    17  )
    18  
    19  //-----------------------------------------------------------------------------
    20  // BlockExecutor handles block execution and state updates.
    21  // It exposes ApplyBlock(), which validates & executes the block, updates state w/ ABCI responses,
    22  // then commits and updates the mempool atomically, then saves state.
    23  
    24  // BlockExecutor provides the context and accessories for properly executing a block.
    25  type BlockExecutor struct {
    26  	// save state, validators, consensus params, abci responses here
    27  	store Store
    28  
    29  	// use blockstore for the pruning functions.
    30  	blockStore BlockStore
    31  
    32  	// execute the app against this
    33  	proxyApp proxy.AppConnConsensus
    34  
    35  	// events
    36  	eventBus types.BlockEventPublisher
    37  
    38  	// manage the mempool lock during commit
    39  	// and update both with block results after commit.
    40  	mempool mempool.Mempool
    41  	evpool  EvidencePool
    42  
    43  	logger log.Logger
    44  
    45  	metrics *Metrics
    46  }
    47  
    48  type BlockExecutorOption func(executor *BlockExecutor)
    49  
    50  func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption {
    51  	return func(blockExec *BlockExecutor) {
    52  		blockExec.metrics = metrics
    53  	}
    54  }
    55  
    56  // NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
    57  // Call SetEventBus to provide one.
    58  func NewBlockExecutor(
    59  	stateStore Store,
    60  	logger log.Logger,
    61  	proxyApp proxy.AppConnConsensus,
    62  	mempool mempool.Mempool,
    63  	evpool EvidencePool,
    64  	blockStore BlockStore,
    65  	options ...BlockExecutorOption,
    66  ) *BlockExecutor {
    67  	res := &BlockExecutor{
    68  		store:      stateStore,
    69  		proxyApp:   proxyApp,
    70  		eventBus:   types.NopEventBus{},
    71  		mempool:    mempool,
    72  		evpool:     evpool,
    73  		logger:     logger,
    74  		metrics:    NopMetrics(),
    75  		blockStore: blockStore,
    76  	}
    77  
    78  	for _, option := range options {
    79  		option(res)
    80  	}
    81  
    82  	return res
    83  }
    84  
    85  func (blockExec *BlockExecutor) Store() Store {
    86  	return blockExec.store
    87  }
    88  
    89  // SetEventBus - sets the event bus for publishing block related events.
    90  // If not called, it defaults to types.NopEventBus.
    91  func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) {
    92  	blockExec.eventBus = eventBus
    93  }
    94  
    95  // CreateProposalBlock calls state.MakeBlock with evidence from the evpool
    96  // and txs from the mempool. The max bytes must be big enough to fit the commit.
    97  // The block space is first allocated to outstanding evidence.
    98  // The rest is given to txs, up to the max gas.
    99  //
   100  // Contract: application will not return more bytes than are sent over the wire.
   101  func (blockExec *BlockExecutor) CreateProposalBlock(
   102  	ctx context.Context,
   103  	height int64,
   104  	state State,
   105  	lastExtCommit *types.ExtendedCommit,
   106  	proposerAddr []byte,
   107  ) (*types.Block, error) {
   108  
   109  	maxBytes := state.ConsensusParams.Block.MaxBytes
   110  	emptyMaxBytes := maxBytes == -1
   111  	if emptyMaxBytes {
   112  		maxBytes = int64(types.MaxBlockSizeBytes)
   113  	}
   114  
   115  	maxGas := state.ConsensusParams.Block.MaxGas
   116  
   117  	evidence, evSize := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
   118  
   119  	// Fetch a limited amount of valid txs
   120  	maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size())
   121  	maxReapBytes := maxDataBytes
   122  	if emptyMaxBytes {
   123  		maxReapBytes = -1
   124  	}
   125  
   126  	txs := blockExec.mempool.ReapMaxBytesMaxGas(maxReapBytes, maxGas)
   127  	commit := lastExtCommit.ToCommit()
   128  	block := state.MakeBlock(height, txs, commit, evidence, proposerAddr)
   129  	rpp, err := blockExec.proxyApp.PrepareProposal(
   130  		ctx,
   131  		&abci.RequestPrepareProposal{
   132  			MaxTxBytes:         maxDataBytes,
   133  			Txs:                block.Txs.ToSliceOfBytes(),
   134  			LocalLastCommit:    buildExtendedCommitInfo(lastExtCommit, blockExec.store, state.InitialHeight, state.ConsensusParams.ABCI),
   135  			Misbehavior:        block.Evidence.Evidence.ToABCI(),
   136  			Height:             block.Height,
   137  			Time:               block.Time,
   138  			NextValidatorsHash: block.NextValidatorsHash,
   139  			ProposerAddress:    block.ProposerAddress,
   140  		},
   141  	)
   142  	if err != nil {
   143  		// The App MUST ensure that only valid (and hence 'processable') transactions
   144  		// enter the mempool. Hence, at this point, we can't have any non-processable
   145  		// transaction causing an error.
   146  		//
   147  		// Also, the App can simply skip any transaction that could cause any kind of trouble.
   148  		// Either way, we cannot recover in a meaningful way, unless we skip proposing
   149  		// this block, repair what caused the error and try again. Hence, we return an
   150  		// error for now (the production code calling this function is expected to panic).
   151  		return nil, err
   152  	}
   153  
   154  	txl := types.ToTxs(rpp.Txs)
   155  	if err := txl.Validate(maxDataBytes); err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	return state.MakeBlock(height, txl, commit, evidence, proposerAddr), nil
   160  }
   161  
   162  func (blockExec *BlockExecutor) ProcessProposal(
   163  	block *types.Block,
   164  	state State,
   165  ) (bool, error) {
   166  	resp, err := blockExec.proxyApp.ProcessProposal(context.TODO(), &abci.RequestProcessProposal{
   167  		Hash:               block.Header.Hash(),
   168  		Height:             block.Header.Height,
   169  		Time:               block.Header.Time,
   170  		Txs:                block.Data.Txs.ToSliceOfBytes(),
   171  		ProposedLastCommit: buildLastCommitInfo(block, blockExec.store, state.InitialHeight),
   172  		Misbehavior:        block.Evidence.Evidence.ToABCI(),
   173  		ProposerAddress:    block.ProposerAddress,
   174  		NextValidatorsHash: block.NextValidatorsHash,
   175  	})
   176  	if err != nil {
   177  		return false, err
   178  	}
   179  	if resp.IsStatusUnknown() {
   180  		panic(fmt.Sprintf("ProcessProposal responded with status %s", resp.Status.String()))
   181  	}
   182  
   183  	return resp.IsAccepted(), nil
   184  }
   185  
   186  // ValidateBlock validates the given block against the given state.
   187  // If the block is invalid, it returns an error.
   188  // Validation does not mutate state, but does require historical information from the stateDB,
   189  // ie. to verify evidence from a validator at an old height.
   190  func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) error {
   191  	err := validateBlock(state, block)
   192  	if err != nil {
   193  		return err
   194  	}
   195  	return blockExec.evpool.CheckEvidence(block.Evidence.Evidence)
   196  }
   197  
   198  // ApplyBlock validates the block against the state, executes it against the app,
   199  // fires the relevant events, commits the app, and saves the new state and responses.
   200  // It returns the new state.
   201  // It's the only function that needs to be called
   202  // from outside this package to process and commit an entire block.
   203  // It takes a blockID to avoid recomputing the parts hash.
   204  func (blockExec *BlockExecutor) ApplyBlock(
   205  	state State, blockID types.BlockID, block *types.Block,
   206  ) (State, error) {
   207  
   208  	if err := validateBlock(state, block); err != nil {
   209  		return state, ErrInvalidBlock(err)
   210  	}
   211  
   212  	commitInfo := buildLastCommitInfo(block, blockExec.store, state.InitialHeight)
   213  
   214  	startTime := time.Now().UnixNano()
   215  	abciResponse, err := blockExec.proxyApp.FinalizeBlock(context.TODO(), &abci.RequestFinalizeBlock{
   216  		Hash:               block.Hash(),
   217  		NextValidatorsHash: block.NextValidatorsHash,
   218  		ProposerAddress:    block.ProposerAddress,
   219  		Height:             block.Height,
   220  		Time:               block.Time,
   221  		DecidedLastCommit:  commitInfo,
   222  		Misbehavior:        block.Evidence.Evidence.ToABCI(),
   223  		Txs:                block.Txs.ToSliceOfBytes(),
   224  	})
   225  	endTime := time.Now().UnixNano()
   226  	blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1000000)
   227  	if err != nil {
   228  		blockExec.logger.Error("error in proxyAppConn.FinalizeBlock", "err", err)
   229  		return state, err
   230  	}
   231  
   232  	blockExec.logger.Info(
   233  		"finalized block",
   234  		"height", block.Height,
   235  		"num_txs_res", len(abciResponse.TxResults),
   236  		"num_val_updates", len(abciResponse.ValidatorUpdates),
   237  		"block_app_hash", fmt.Sprintf("%X", abciResponse.AppHash),
   238  	)
   239  
   240  	// Assert that the application correctly returned tx results for each of the transactions provided in the block
   241  	if len(block.Data.Txs) != len(abciResponse.TxResults) {
   242  		return state, fmt.Errorf("expected tx results length to match size of transactions in block. Expected %d, got %d", len(block.Data.Txs), len(abciResponse.TxResults))
   243  	}
   244  
   245  	blockExec.logger.Info("executed block", "height", block.Height, "app_hash", abciResponse.AppHash)
   246  
   247  	fail.Fail() // XXX
   248  
   249  	// Save the results before we commit.
   250  	if err := blockExec.store.SaveFinalizeBlockResponse(block.Height, abciResponse); err != nil {
   251  		return state, err
   252  	}
   253  
   254  	fail.Fail() // XXX
   255  
   256  	// validate the validator updates and convert to CometBFT types
   257  	err = validateValidatorUpdates(abciResponse.ValidatorUpdates, state.ConsensusParams.Validator)
   258  	if err != nil {
   259  		return state, fmt.Errorf("error in validator updates: %v", err)
   260  	}
   261  
   262  	validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciResponse.ValidatorUpdates)
   263  	if err != nil {
   264  		return state, err
   265  	}
   266  	if len(validatorUpdates) > 0 {
   267  		blockExec.logger.Debug("updates to validators", "updates", types.ValidatorListString(validatorUpdates))
   268  		blockExec.metrics.ValidatorSetUpdates.Add(1)
   269  	}
   270  	if abciResponse.ConsensusParamUpdates != nil {
   271  		blockExec.metrics.ConsensusParamUpdates.Add(1)
   272  	}
   273  
   274  	// Update the state with the block and responses.
   275  	state, err = updateState(state, blockID, &block.Header, abciResponse, validatorUpdates)
   276  	if err != nil {
   277  		return state, fmt.Errorf("commit failed for application: %v", err)
   278  	}
   279  
   280  	// Lock mempool, commit app state, update mempoool.
   281  	retainHeight, err := blockExec.Commit(state, block, abciResponse)
   282  	if err != nil {
   283  		return state, fmt.Errorf("commit failed for application: %v", err)
   284  	}
   285  
   286  	// Update evpool with the latest state.
   287  	blockExec.evpool.Update(state, block.Evidence.Evidence)
   288  
   289  	fail.Fail() // XXX
   290  
   291  	// Update the app hash and save the state.
   292  	state.AppHash = abciResponse.AppHash
   293  	if err := blockExec.store.Save(state); err != nil {
   294  		return state, err
   295  	}
   296  
   297  	fail.Fail() // XXX
   298  
   299  	// Prune old heights, if requested by ABCI app.
   300  	if retainHeight > 0 {
   301  		pruned, err := blockExec.pruneBlocks(retainHeight, state)
   302  		if err != nil {
   303  			blockExec.logger.Error("failed to prune blocks", "retain_height", retainHeight, "err", err)
   304  		} else {
   305  			blockExec.logger.Debug("pruned blocks", "pruned", pruned, "retain_height", retainHeight)
   306  		}
   307  	}
   308  
   309  	// Events are fired after everything else.
   310  	// NOTE: if we crash between Commit and Save, events wont be fired during replay
   311  	fireEvents(blockExec.logger, blockExec.eventBus, block, blockID, abciResponse, validatorUpdates)
   312  
   313  	return state, nil
   314  }
   315  
   316  func (blockExec *BlockExecutor) ExtendVote(ctx context.Context, vote *types.Vote) ([]byte, error) {
   317  	req := abci.RequestExtendVote{
   318  		Hash:   vote.BlockID.Hash,
   319  		Height: vote.Height,
   320  	}
   321  
   322  	resp, err := blockExec.proxyApp.ExtendVote(ctx, &req)
   323  	if err != nil {
   324  		panic(fmt.Errorf("ExtendVote call failed: %w", err))
   325  	}
   326  	return resp.VoteExtension, nil
   327  }
   328  
   329  func (blockExec *BlockExecutor) VerifyVoteExtension(ctx context.Context, vote *types.Vote) error {
   330  	req := abci.RequestVerifyVoteExtension{
   331  		Hash:             vote.BlockID.Hash,
   332  		ValidatorAddress: vote.ValidatorAddress,
   333  		Height:           vote.Height,
   334  		VoteExtension:    vote.Extension,
   335  	}
   336  
   337  	resp, err := blockExec.proxyApp.VerifyVoteExtension(ctx, &req)
   338  	if err != nil {
   339  		panic(fmt.Errorf("VerifyVoteExtension call failed: %w", err))
   340  	}
   341  	if resp.IsStatusUnknown() {
   342  		panic(fmt.Sprintf("VerifyVoteExtension responded with status %s", resp.Status.String()))
   343  	}
   344  
   345  	if !resp.IsAccepted() {
   346  		return types.ErrInvalidVoteExtension
   347  	}
   348  	return nil
   349  }
   350  
   351  // Commit locks the mempool, runs the ABCI Commit message, and updates the
   352  // mempool.
   353  // It returns the result of calling abci.Commit which is the height to retain (if any)).
   354  // The application is expected to have persisted its state (if any) before returning
   355  // from the ABCI Commit call. This is the only place where the application should
   356  // persist its state.
   357  // The Mempool must be locked during commit and update because state is
   358  // typically reset on Commit and old txs must be replayed against committed
   359  // state before new txs are run in the mempool, lest they be invalid.
   360  func (blockExec *BlockExecutor) Commit(
   361  	state State,
   362  	block *types.Block,
   363  	abciResponse *abci.ResponseFinalizeBlock,
   364  ) (int64, error) {
   365  	blockExec.mempool.Lock()
   366  	defer blockExec.mempool.Unlock()
   367  
   368  	// while mempool is Locked, flush to ensure all async requests have completed
   369  	// in the ABCI app before Commit.
   370  	err := blockExec.mempool.FlushAppConn()
   371  	if err != nil {
   372  		blockExec.logger.Error("client error during mempool.FlushAppConn", "err", err)
   373  		return 0, err
   374  	}
   375  
   376  	// Commit block, get hash back
   377  	res, err := blockExec.proxyApp.Commit(context.TODO())
   378  	if err != nil {
   379  		blockExec.logger.Error("client error during proxyAppConn.CommitSync", "err", err)
   380  		return 0, err
   381  	}
   382  
   383  	// ResponseCommit has no error code - just data
   384  	blockExec.logger.Info(
   385  		"committed state",
   386  		"height", block.Height,
   387  		"block_app_hash", fmt.Sprintf("%X", block.AppHash),
   388  	)
   389  
   390  	// Update mempool.
   391  	err = blockExec.mempool.Update(
   392  		block.Height,
   393  		block.Txs,
   394  		abciResponse.TxResults,
   395  		TxPreCheck(state),
   396  		TxPostCheck(state),
   397  	)
   398  
   399  	return res.RetainHeight, err
   400  }
   401  
   402  //---------------------------------------------------------
   403  // Helper functions for executing blocks and updating state
   404  
   405  func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) abci.CommitInfo {
   406  	if block.Height == initialHeight {
   407  		// there is no last commit for the initial height.
   408  		// return an empty value.
   409  		return abci.CommitInfo{}
   410  	}
   411  
   412  	lastValSet, err := store.LoadValidators(block.Height - 1)
   413  	if err != nil {
   414  		panic(fmt.Errorf("failed to load validator set at height %d: %w", block.Height-1, err))
   415  	}
   416  
   417  	var (
   418  		commitSize = block.LastCommit.Size()
   419  		valSetLen  = len(lastValSet.Validators)
   420  	)
   421  
   422  	// ensure that the size of the validator set in the last commit matches
   423  	// the size of the validator set in the state store.
   424  	if commitSize != valSetLen {
   425  		panic(fmt.Sprintf(
   426  			"commit size (%d) doesn't match validator set length (%d) at height %d\n\n%v\n\n%v",
   427  			commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators,
   428  		))
   429  	}
   430  
   431  	votes := make([]abci.VoteInfo, block.LastCommit.Size())
   432  	for i, val := range lastValSet.Validators {
   433  		commitSig := block.LastCommit.Signatures[i]
   434  		votes[i] = abci.VoteInfo{
   435  			Validator:   types.TM2PB.Validator(val),
   436  			BlockIdFlag: cmtproto.BlockIDFlag(commitSig.BlockIDFlag),
   437  		}
   438  	}
   439  
   440  	return abci.CommitInfo{
   441  		Round: block.LastCommit.Round,
   442  		Votes: votes,
   443  	}
   444  }
   445  
   446  // buildExtendedCommitInfo populates an ABCI extended commit from the
   447  // corresponding CometBFT extended commit ec, using the stored validator set
   448  // from ec.  It requires ec to include the original precommit votes along with
   449  // the vote extensions from the last commit.
   450  //
   451  // For heights below the initial height, for which we do not have the required
   452  // data, it returns an empty record.
   453  //
   454  // Assumes that the commit signatures are sorted according to validator index.
   455  func buildExtendedCommitInfo(ec *types.ExtendedCommit, store Store, initialHeight int64, ap types.ABCIParams) abci.ExtendedCommitInfo {
   456  	if ec.Height < initialHeight {
   457  		// There are no extended commits for heights below the initial height.
   458  		return abci.ExtendedCommitInfo{}
   459  	}
   460  
   461  	valSet, err := store.LoadValidators(ec.Height)
   462  	if err != nil {
   463  		panic(fmt.Errorf("failed to load validator set at height %d, initial height %d: %w", ec.Height, initialHeight, err))
   464  	}
   465  
   466  	var (
   467  		ecSize    = ec.Size()
   468  		valSetLen = len(valSet.Validators)
   469  	)
   470  
   471  	// Ensure that the size of the validator set in the extended commit matches
   472  	// the size of the validator set in the state store.
   473  	if ecSize != valSetLen {
   474  		panic(fmt.Errorf(
   475  			"extended commit size (%d) does not match validator set length (%d) at height %d\n\n%v\n\n%v",
   476  			ecSize, valSetLen, ec.Height, ec.ExtendedSignatures, valSet.Validators,
   477  		))
   478  	}
   479  
   480  	votes := make([]abci.ExtendedVoteInfo, ecSize)
   481  	for i, val := range valSet.Validators {
   482  		ecs := ec.ExtendedSignatures[i]
   483  
   484  		// Absent signatures have empty validator addresses, but otherwise we
   485  		// expect the validator addresses to be the same.
   486  		if ecs.BlockIDFlag != types.BlockIDFlagAbsent && !bytes.Equal(ecs.ValidatorAddress, val.Address) {
   487  			panic(fmt.Errorf("validator address of extended commit signature in position %d (%s) does not match the corresponding validator's at height %d (%s)",
   488  				i, ecs.ValidatorAddress, ec.Height, val.Address,
   489  			))
   490  		}
   491  
   492  		// Check if vote extensions were enabled during the commit's height: ec.Height.
   493  		// ec is the commit from the previous height, so if extensions were enabled
   494  		// during that height, we ensure they are present and deliver the data to
   495  		// the proposer. If they were not enabled during this previous height, we
   496  		// will not deliver extension data.
   497  		if err := ecs.EnsureExtension(ap.VoteExtensionsEnabled(ec.Height)); err != nil {
   498  			panic(fmt.Errorf("commit at height %d has problems with vote extension data; err %w", ec.Height, err))
   499  		}
   500  
   501  		votes[i] = abci.ExtendedVoteInfo{
   502  			Validator:          types.TM2PB.Validator(val),
   503  			BlockIdFlag:        cmtproto.BlockIDFlag(ecs.BlockIDFlag),
   504  			VoteExtension:      ecs.Extension,
   505  			ExtensionSignature: ecs.ExtensionSignature,
   506  		}
   507  	}
   508  
   509  	return abci.ExtendedCommitInfo{
   510  		Round: ec.Round,
   511  		Votes: votes,
   512  	}
   513  }
   514  
   515  func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate,
   516  	params types.ValidatorParams) error {
   517  	for _, valUpdate := range abciUpdates {
   518  		if valUpdate.GetPower() < 0 {
   519  			return fmt.Errorf("voting power can't be negative %v", valUpdate)
   520  		} else if valUpdate.GetPower() == 0 {
   521  			// continue, since this is deleting the validator, and thus there is no
   522  			// pubkey to check
   523  			continue
   524  		}
   525  
   526  		// Check if validator's pubkey matches an ABCI type in the consensus params
   527  		pk, err := cryptoenc.PubKeyFromProto(valUpdate.PubKey)
   528  		if err != nil {
   529  			return err
   530  		}
   531  
   532  		if !types.IsValidPubkeyType(params, pk.Type()) {
   533  			return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus",
   534  				valUpdate, pk.Type())
   535  		}
   536  	}
   537  	return nil
   538  }
   539  
   540  // updateState returns a new State updated according to the header and responses.
   541  func updateState(
   542  	state State,
   543  	blockID types.BlockID,
   544  	header *types.Header,
   545  	abciResponse *abci.ResponseFinalizeBlock,
   546  	validatorUpdates []*types.Validator,
   547  ) (State, error) {
   548  
   549  	// Copy the valset so we can apply changes from EndBlock
   550  	// and update s.LastValidators and s.Validators.
   551  	nValSet := state.NextValidators.Copy()
   552  
   553  	// Update the validator set with the latest abciResponse.
   554  	lastHeightValsChanged := state.LastHeightValidatorsChanged
   555  	if len(validatorUpdates) > 0 {
   556  		err := nValSet.UpdateWithChangeSet(validatorUpdates)
   557  		if err != nil {
   558  			return state, fmt.Errorf("changing validator set: %w", err)
   559  		}
   560  		// Change results from this height but only applies to the next next height.
   561  		lastHeightValsChanged = header.Height + 1 + 1
   562  	}
   563  
   564  	// Update validator proposer priority and set state variables.
   565  	nValSet.IncrementProposerPriority(1)
   566  
   567  	// Update the params with the latest abciResponse.
   568  	nextParams := state.ConsensusParams
   569  	lastHeightParamsChanged := state.LastHeightConsensusParamsChanged
   570  	if abciResponse.ConsensusParamUpdates != nil {
   571  		// NOTE: must not mutate state.ConsensusParams
   572  		nextParams = state.ConsensusParams.Update(abciResponse.ConsensusParamUpdates)
   573  		err := nextParams.ValidateBasic()
   574  		if err != nil {
   575  			return state, fmt.Errorf("validating new consensus params: %w", err)
   576  		}
   577  
   578  		err = state.ConsensusParams.ValidateUpdate(abciResponse.ConsensusParamUpdates, header.Height)
   579  		if err != nil {
   580  			return state, fmt.Errorf("updating consensus params: %w", err)
   581  		}
   582  
   583  		state.Version.Consensus.App = nextParams.Version.App
   584  
   585  		// Change results from this height but only applies to the next height.
   586  		lastHeightParamsChanged = header.Height + 1
   587  	}
   588  
   589  	nextVersion := state.Version
   590  
   591  	// NOTE: the AppHash and the VoteExtension has not been populated.
   592  	// It will be filled on state.Save.
   593  	return State{
   594  		Version:                          nextVersion,
   595  		ChainID:                          state.ChainID,
   596  		InitialHeight:                    state.InitialHeight,
   597  		LastBlockHeight:                  header.Height,
   598  		LastBlockID:                      blockID,
   599  		LastBlockTime:                    header.Time,
   600  		NextValidators:                   nValSet,
   601  		Validators:                       state.NextValidators.Copy(),
   602  		LastValidators:                   state.Validators.Copy(),
   603  		LastHeightValidatorsChanged:      lastHeightValsChanged,
   604  		ConsensusParams:                  nextParams,
   605  		LastHeightConsensusParamsChanged: lastHeightParamsChanged,
   606  		LastResultsHash:                  TxResultsHash(abciResponse.TxResults),
   607  		AppHash:                          nil,
   608  	}, nil
   609  }
   610  
   611  // Fire NewBlock, NewBlockHeader.
   612  // Fire TxEvent for every tx.
   613  // NOTE: if CometBFT crashes before commit, some or all of these events may be published again.
   614  func fireEvents(
   615  	logger log.Logger,
   616  	eventBus types.BlockEventPublisher,
   617  	block *types.Block,
   618  	blockID types.BlockID,
   619  	abciResponse *abci.ResponseFinalizeBlock,
   620  	validatorUpdates []*types.Validator,
   621  ) {
   622  	if err := eventBus.PublishEventNewBlock(types.EventDataNewBlock{
   623  		Block:               block,
   624  		BlockID:             blockID,
   625  		ResultFinalizeBlock: *abciResponse,
   626  	}); err != nil {
   627  		logger.Error("failed publishing new block", "err", err)
   628  	}
   629  
   630  	if err := eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{
   631  		Header: block.Header,
   632  	}); err != nil {
   633  		logger.Error("failed publishing new block header", "err", err)
   634  	}
   635  
   636  	if err := eventBus.PublishEventNewBlockEvents(types.EventDataNewBlockEvents{
   637  		Height: block.Height,
   638  		Events: abciResponse.Events,
   639  		NumTxs: int64(len(block.Txs)),
   640  	}); err != nil {
   641  		logger.Error("failed publishing new block events", "err", err)
   642  	}
   643  
   644  	if len(block.Evidence.Evidence) != 0 {
   645  		for _, ev := range block.Evidence.Evidence {
   646  			if err := eventBus.PublishEventNewEvidence(types.EventDataNewEvidence{
   647  				Evidence: ev,
   648  				Height:   block.Height,
   649  			}); err != nil {
   650  				logger.Error("failed publishing new evidence", "err", err)
   651  			}
   652  		}
   653  	}
   654  
   655  	for i, tx := range block.Data.Txs {
   656  		if err := eventBus.PublishEventTx(types.EventDataTx{TxResult: abci.TxResult{
   657  			Height: block.Height,
   658  			Index:  uint32(i),
   659  			Tx:     tx,
   660  			Result: *(abciResponse.TxResults[i]),
   661  		}}); err != nil {
   662  			logger.Error("failed publishing event TX", "err", err)
   663  		}
   664  	}
   665  
   666  	if len(validatorUpdates) > 0 {
   667  		if err := eventBus.PublishEventValidatorSetUpdates(
   668  			types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}); err != nil {
   669  			logger.Error("failed publishing event", "err", err)
   670  		}
   671  	}
   672  }
   673  
   674  //----------------------------------------------------------------------------------------------------
   675  // Execute block without state. TODO: eliminate
   676  
   677  // ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
   678  // It returns the application root hash (result of abci.Commit).
   679  func ExecCommitBlock(
   680  	appConnConsensus proxy.AppConnConsensus,
   681  	block *types.Block,
   682  	logger log.Logger,
   683  	store Store,
   684  	initialHeight int64,
   685  ) ([]byte, error) {
   686  	commitInfo := buildLastCommitInfo(block, store, initialHeight)
   687  
   688  	resp, err := appConnConsensus.FinalizeBlock(context.TODO(), &abci.RequestFinalizeBlock{
   689  		Hash:               block.Hash(),
   690  		NextValidatorsHash: block.NextValidatorsHash,
   691  		ProposerAddress:    block.ProposerAddress,
   692  		Height:             block.Height,
   693  		Time:               block.Time,
   694  		DecidedLastCommit:  commitInfo,
   695  		Misbehavior:        block.Evidence.Evidence.ToABCI(),
   696  		Txs:                block.Txs.ToSliceOfBytes(),
   697  	})
   698  	if err != nil {
   699  		logger.Error("error in proxyAppConn.FinalizeBlock", "err", err)
   700  		return nil, err
   701  	}
   702  
   703  	// Assert that the application correctly returned tx results for each of the transactions provided in the block
   704  	if len(block.Data.Txs) != len(resp.TxResults) {
   705  		return nil, fmt.Errorf("expected tx results length to match size of transactions in block. Expected %d, got %d", len(block.Data.Txs), len(resp.TxResults))
   706  	}
   707  
   708  	logger.Info("executed block", "height", block.Height, "app_hash", resp.AppHash)
   709  
   710  	// Commit block
   711  	_, err = appConnConsensus.Commit(context.TODO())
   712  	if err != nil {
   713  		logger.Error("client error during proxyAppConn.Commit", "err", err)
   714  		return nil, err
   715  	}
   716  
   717  	// ResponseCommit has no error or log
   718  	return resp.AppHash, nil
   719  }
   720  
   721  func (blockExec *BlockExecutor) pruneBlocks(retainHeight int64, state State) (uint64, error) {
   722  	base := blockExec.blockStore.Base()
   723  	if retainHeight <= base {
   724  		return 0, nil
   725  	}
   726  
   727  	amountPruned, prunedHeaderHeight, err := blockExec.blockStore.PruneBlocks(retainHeight, state)
   728  	if err != nil {
   729  		return 0, fmt.Errorf("failed to prune block store: %w", err)
   730  	}
   731  
   732  	err = blockExec.Store().PruneStates(base, retainHeight, prunedHeaderHeight)
   733  	if err != nil {
   734  		return 0, fmt.Errorf("failed to prune state store: %w", err)
   735  	}
   736  	return amountPruned, nil
   737  }