github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/internal/state/execution.go (about)

     1  package state
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"errors"
     7  	"fmt"
     8  	"math"
     9  	"time"
    10  
    11  	abciclient "github.com/ari-anchor/sei-tendermint/abci/client"
    12  	abci "github.com/ari-anchor/sei-tendermint/abci/types"
    13  	"github.com/ari-anchor/sei-tendermint/crypto/encoding"
    14  	"github.com/ari-anchor/sei-tendermint/crypto/merkle"
    15  	"github.com/ari-anchor/sei-tendermint/internal/eventbus"
    16  	"github.com/ari-anchor/sei-tendermint/internal/mempool"
    17  	"github.com/ari-anchor/sei-tendermint/libs/log"
    18  	tmtypes "github.com/ari-anchor/sei-tendermint/proto/tendermint/types"
    19  	"github.com/ari-anchor/sei-tendermint/types"
    20  	otrace "go.opentelemetry.io/otel/trace"
    21  )
    22  
    23  //-----------------------------------------------------------------------------
    24  // BlockExecutor handles block execution and state updates.
    25  // It exposes ApplyBlock(), which validates & executes the block, updates state w/ ABCI responses,
    26  // then commits and updates the mempool atomically, then saves state.
    27  
    28  // BlockExecutor provides the context and accessories for properly executing a block.
    29  type BlockExecutor struct {
    30  	// save state, validators, consensus params, abci responses here
    31  	store Store
    32  
    33  	// use blockstore for the pruning functions.
    34  	blockStore BlockStore
    35  
    36  	// execute the app against this
    37  	appClient abciclient.Client
    38  
    39  	// events
    40  	eventBus types.BlockEventPublisher
    41  
    42  	// manage the mempool lock during commit
    43  	// and update both with block results after commit.
    44  	mempool mempool.Mempool
    45  	evpool  EvidencePool
    46  
    47  	logger  log.Logger
    48  	metrics *Metrics
    49  
    50  	// cache the verification results over a single height
    51  	cache map[string]struct{}
    52  }
    53  
    54  // NewBlockExecutor returns a new BlockExecutor with the passed-in EventBus.
    55  func NewBlockExecutor(
    56  	stateStore Store,
    57  	logger log.Logger,
    58  	appClient abciclient.Client,
    59  	pool mempool.Mempool,
    60  	evpool EvidencePool,
    61  	blockStore BlockStore,
    62  	eventBus *eventbus.EventBus,
    63  	metrics *Metrics,
    64  ) *BlockExecutor {
    65  	return &BlockExecutor{
    66  		eventBus:   eventBus,
    67  		store:      stateStore,
    68  		appClient:  appClient,
    69  		mempool:    pool,
    70  		evpool:     evpool,
    71  		logger:     logger,
    72  		metrics:    metrics,
    73  		cache:      make(map[string]struct{}),
    74  		blockStore: blockStore,
    75  	}
    76  }
    77  
    78  func (blockExec *BlockExecutor) Store() Store {
    79  	return blockExec.store
    80  }
    81  
    82  // CreateProposalBlock calls state.MakeBlock with evidence from the evpool
    83  // and txs from the mempool. The max bytes must be big enough to fit the commit.
    84  // Up to 1/10th of the block space is allcoated for maximum sized evidence.
    85  // The rest is given to txs, up to the max gas.
    86  //
    87  // Contract: application will not return more bytes than are sent over the wire.
    88  func (blockExec *BlockExecutor) CreateProposalBlock(
    89  	ctx context.Context,
    90  	height int64,
    91  	state State,
    92  	lastExtCommit *types.ExtendedCommit,
    93  	proposerAddr []byte,
    94  ) (*types.Block, error) {
    95  
    96  	maxBytes := state.ConsensusParams.Block.MaxBytes
    97  	maxGas := state.ConsensusParams.Block.MaxGas
    98  
    99  	evidence, evSize := blockExec.evpool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
   100  
   101  	// Fetch a limited amount of valid txs
   102  	maxDataBytes := types.MaxDataBytes(maxBytes, evSize, state.Validators.Size())
   103  
   104  	txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas)
   105  	commit := lastExtCommit.ToCommit()
   106  	block := state.MakeBlock(height, txs, commit, evidence, proposerAddr)
   107  	rpp, err := blockExec.appClient.PrepareProposal(
   108  		ctx,
   109  		&abci.RequestPrepareProposal{
   110  			MaxTxBytes:            maxDataBytes,
   111  			Txs:                   block.Txs.ToSliceOfBytes(),
   112  			LocalLastCommit:       buildExtendedCommitInfo(lastExtCommit, blockExec.store, state.InitialHeight, state.ConsensusParams.ABCI),
   113  			ByzantineValidators:   block.Evidence.ToABCI(),
   114  			Height:                block.Height,
   115  			Time:                  block.Time,
   116  			NextValidatorsHash:    block.NextValidatorsHash,
   117  			ProposerAddress:       block.ProposerAddress,
   118  			AppHash:               block.AppHash,
   119  			ValidatorsHash:        block.ValidatorsHash,
   120  			ConsensusHash:         block.ConsensusHash,
   121  			DataHash:              block.DataHash,
   122  			EvidenceHash:          block.EvidenceHash,
   123  			LastBlockHash:         block.LastBlockID.Hash,
   124  			LastBlockPartSetTotal: int64(block.LastBlockID.PartSetHeader.Total),
   125  			LastBlockPartSetHash:  block.LastBlockID.Hash,
   126  			LastCommitHash:        block.LastCommitHash,
   127  			LastResultsHash:       block.LastResultsHash,
   128  		},
   129  	)
   130  	if err != nil {
   131  		// The App MUST ensure that only valid (and hence 'processable') transactions
   132  		// enter the mempool. Hence, at this point, we can't have any non-processable
   133  		// transaction causing an error.
   134  		//
   135  		// Also, the App can simply skip any transaction that could cause any kind of trouble.
   136  		// Either way, we cannot recover in a meaningful way, unless we skip proposing
   137  		// this block, repair what caused the error and try again. Hence, we return an
   138  		// error for now (the production code calling this function is expected to panic).
   139  		return nil, err
   140  	}
   141  	txrSet := types.NewTxRecordSet(rpp.TxRecords)
   142  
   143  	if err := txrSet.Validate(maxDataBytes, block.Txs); err != nil {
   144  		return nil, err
   145  	}
   146  
   147  	for _, rtx := range txrSet.RemovedTxs() {
   148  		if err := blockExec.mempool.RemoveTxByKey(rtx.Key()); err != nil {
   149  			blockExec.logger.Debug("error removing transaction from the mempool", "error", err, "tx hash", rtx.Hash())
   150  		}
   151  	}
   152  	itxs := txrSet.IncludedTxs()
   153  	return state.MakeBlock(height, itxs, commit, evidence, proposerAddr), nil
   154  }
   155  
   156  func (blockExec *BlockExecutor) GetTxsForKeys(txKeys []types.TxKey) types.Txs {
   157  	return blockExec.mempool.GetTxsForKeys(txKeys)
   158  }
   159  
   160  func (blockExec *BlockExecutor) ProcessProposal(
   161  	ctx context.Context,
   162  	block *types.Block,
   163  	state State,
   164  ) (bool, error) {
   165  	txs := block.Data.Txs.ToSliceOfBytes()
   166  	resp, err := blockExec.appClient.ProcessProposal(ctx, &abci.RequestProcessProposal{
   167  		Hash:                  block.Header.Hash(),
   168  		Height:                block.Header.Height,
   169  		Time:                  block.Header.Time,
   170  		Txs:                   txs,
   171  		ProposedLastCommit:    buildLastCommitInfo(block, blockExec.store, state.InitialHeight),
   172  		ByzantineValidators:   block.Evidence.ToABCI(),
   173  		ProposerAddress:       block.ProposerAddress,
   174  		NextValidatorsHash:    block.NextValidatorsHash,
   175  		AppHash:               block.AppHash,
   176  		ValidatorsHash:        block.ValidatorsHash,
   177  		ConsensusHash:         block.ConsensusHash,
   178  		DataHash:              block.DataHash,
   179  		EvidenceHash:          block.EvidenceHash,
   180  		LastBlockHash:         block.LastBlockID.Hash,
   181  		LastBlockPartSetTotal: int64(block.LastBlockID.PartSetHeader.Total),
   182  		LastBlockPartSetHash:  block.LastBlockID.Hash,
   183  		LastCommitHash:        block.LastCommitHash,
   184  		LastResultsHash:       block.LastResultsHash,
   185  	})
   186  	if err != nil {
   187  		return false, ErrInvalidBlock(err)
   188  	}
   189  	if resp.IsStatusUnknown() {
   190  		panic(fmt.Sprintf("ProcessProposal responded with status %s", resp.Status.String()))
   191  	}
   192  
   193  	return resp.IsAccepted(), nil
   194  }
   195  
   196  // ValidateBlock validates the given block against the given state.
   197  // If the block is invalid, it returns an error.
   198  // Validation does not mutate state, but does require historical information from the stateDB,
   199  // ie. to verify evidence from a validator at an old height.
   200  func (blockExec *BlockExecutor) ValidateBlock(ctx context.Context, state State, block *types.Block) error {
   201  	hash := block.Hash()
   202  	if _, ok := blockExec.cache[hash.String()]; ok {
   203  		return nil
   204  	}
   205  
   206  	err := validateBlock(state, block)
   207  	if err != nil {
   208  		return err
   209  	}
   210  
   211  	err = blockExec.evpool.CheckEvidence(ctx, block.Evidence)
   212  	if err != nil {
   213  		return err
   214  	}
   215  
   216  	blockExec.cache[hash.String()] = struct{}{}
   217  	return nil
   218  }
   219  
   220  // ApplyBlock validates the block against the state, executes it against the app,
   221  // fires the relevant events, commits the app, and saves the new state and responses.
   222  // It returns the new state.
   223  // It's the only function that needs to be called
   224  // from outside this package to process and commit an entire block.
   225  // It takes a blockID to avoid recomputing the parts hash.
   226  func (blockExec *BlockExecutor) ApplyBlock(
   227  	ctx context.Context,
   228  	state State,
   229  	blockID types.BlockID, block *types.Block, tracer otrace.Tracer) (State, error) {
   230  	if tracer != nil {
   231  		spanCtx, span := tracer.Start(ctx, "cs.state.ApplyBlock")
   232  		ctx = spanCtx
   233  		defer span.End()
   234  	}
   235  	// validate the block if we haven't already
   236  	if err := blockExec.ValidateBlock(ctx, state, block); err != nil {
   237  		return state, ErrInvalidBlock(err)
   238  	}
   239  	startTime := time.Now()
   240  	defer func() {
   241  		blockExec.metrics.BlockProcessingTime.Observe(time.Since(startTime).Seconds())
   242  	}()
   243  	var finalizeBlockSpan otrace.Span = nil
   244  	if tracer != nil {
   245  		_, finalizeBlockSpan = tracer.Start(ctx, "cs.state.ApplyBlock.FinalizeBlock")
   246  		defer finalizeBlockSpan.End()
   247  	}
   248  	txs := block.Data.Txs.ToSliceOfBytes()
   249  	fBlockRes, err := blockExec.appClient.FinalizeBlock(
   250  		ctx,
   251  		&abci.RequestFinalizeBlock{
   252  			Hash:                  block.Hash(),
   253  			Height:                block.Header.Height,
   254  			Time:                  block.Header.Time,
   255  			Txs:                   txs,
   256  			DecidedLastCommit:     buildLastCommitInfo(block, blockExec.store, state.InitialHeight),
   257  			ByzantineValidators:   block.Evidence.ToABCI(),
   258  			ProposerAddress:       block.ProposerAddress,
   259  			NextValidatorsHash:    block.NextValidatorsHash,
   260  			AppHash:               block.AppHash,
   261  			ValidatorsHash:        block.ValidatorsHash,
   262  			ConsensusHash:         block.ConsensusHash,
   263  			DataHash:              block.DataHash,
   264  			EvidenceHash:          block.EvidenceHash,
   265  			LastBlockHash:         block.LastBlockID.Hash,
   266  			LastBlockPartSetTotal: int64(block.LastBlockID.PartSetHeader.Total),
   267  			LastBlockPartSetHash:  block.LastBlockID.Hash,
   268  			LastCommitHash:        block.LastCommitHash,
   269  			LastResultsHash:       block.LastResultsHash,
   270  		},
   271  	)
   272  	if finalizeBlockSpan != nil {
   273  		finalizeBlockSpan.End()
   274  	}
   275  	if err != nil {
   276  		return state, ErrProxyAppConn(err)
   277  	}
   278  
   279  	blockExec.logger.Info(
   280  		"finalized block",
   281  		"height", block.Height,
   282  		"latency_ms", time.Now().Sub(startTime).Milliseconds(),
   283  		"num_txs_res", len(fBlockRes.TxResults),
   284  		"num_val_updates", len(fBlockRes.ValidatorUpdates),
   285  		"block_app_hash", fmt.Sprintf("%X", fBlockRes.AppHash),
   286  	)
   287  
   288  	// Save the results before we commit.
   289  	err = blockExec.store.SaveFinalizeBlockResponses(block.Height, fBlockRes)
   290  	if err != nil && !errors.Is(err, ErrNoFinalizeBlockResponsesForHeight{block.Height}) {
   291  		// It is correct to have an empty ResponseFinalizeBlock for ApplyBlock,
   292  		// but not for saving it to the state store
   293  		return state, err
   294  	}
   295  
   296  	// validate the validator updates and convert to tendermint types
   297  	err = validateValidatorUpdates(fBlockRes.ValidatorUpdates, state.ConsensusParams.Validator)
   298  	if err != nil {
   299  		return state, fmt.Errorf("error in validator updates: %w", err)
   300  	}
   301  
   302  	validatorUpdates, err := types.PB2TM.ValidatorUpdates(fBlockRes.ValidatorUpdates)
   303  	if err != nil {
   304  		return state, err
   305  	}
   306  	if len(validatorUpdates) > 0 {
   307  		blockExec.logger.Debug("updates to validators", "updates", types.ValidatorListString(validatorUpdates))
   308  		blockExec.metrics.ValidatorSetUpdates.Add(1)
   309  	}
   310  	if fBlockRes.ConsensusParamUpdates != nil {
   311  		blockExec.metrics.ConsensusParamUpdates.Add(1)
   312  	}
   313  
   314  	// Update the state with the block and responses.
   315  	rs, err := abci.MarshalTxResults(fBlockRes.TxResults)
   316  	if err != nil {
   317  		return state, fmt.Errorf("marshaling TxResults: %w", err)
   318  	}
   319  	h := merkle.HashFromByteSlices(rs)
   320  	state, err = state.Update(blockID, &block.Header, h, fBlockRes.ConsensusParamUpdates, validatorUpdates)
   321  	if err != nil {
   322  		return state, fmt.Errorf("commit failed for application: %w", err)
   323  	}
   324  
   325  	var commitSpan otrace.Span = nil
   326  	if tracer != nil {
   327  		_, commitSpan = tracer.Start(ctx, "cs.state.ApplyBlock.Commit")
   328  		defer commitSpan.End()
   329  	}
   330  	// Lock mempool, commit app state, update mempoool.
   331  	retainHeight, err := blockExec.Commit(ctx, state, block, fBlockRes.TxResults)
   332  	if err != nil {
   333  		return state, fmt.Errorf("commit failed for application: %w", err)
   334  	}
   335  	if commitSpan != nil {
   336  		commitSpan.End()
   337  	}
   338  
   339  	// Update evpool with the latest state.
   340  	blockExec.evpool.Update(ctx, state, block.Evidence)
   341  
   342  	// Update the app hash and save the state.
   343  	state.AppHash = fBlockRes.AppHash
   344  	if err := blockExec.store.Save(state); err != nil {
   345  		return state, err
   346  	}
   347  
   348  	// Prune old heights, if requested by ABCI app.
   349  	if retainHeight > 0 {
   350  		pruned, err := blockExec.pruneBlocks(retainHeight)
   351  		if err != nil {
   352  			blockExec.logger.Error("failed to prune blocks", "retain_height", retainHeight, "err", err)
   353  		} else {
   354  			blockExec.logger.Debug("pruned blocks", "pruned", pruned, "retain_height", retainHeight)
   355  		}
   356  	}
   357  
   358  	// reset the verification cache
   359  	blockExec.cache = make(map[string]struct{})
   360  
   361  	// Events are fired after everything else.
   362  	// NOTE: if we crash between Commit and Save, events wont be fired during replay
   363  	fireEvents(blockExec.logger, blockExec.eventBus, block, blockID, fBlockRes, validatorUpdates)
   364  
   365  	return state, nil
   366  }
   367  
   368  func (blockExec *BlockExecutor) ExtendVote(ctx context.Context, vote *types.Vote) ([]byte, error) {
   369  	resp, err := blockExec.appClient.ExtendVote(ctx, &abci.RequestExtendVote{
   370  		Hash:   vote.BlockID.Hash,
   371  		Height: vote.Height,
   372  	})
   373  	if err != nil {
   374  		panic(fmt.Errorf("ExtendVote call failed: %w", err))
   375  	}
   376  	return resp.VoteExtension, nil
   377  }
   378  
   379  func (blockExec *BlockExecutor) VerifyVoteExtension(ctx context.Context, vote *types.Vote) error {
   380  	resp, err := blockExec.appClient.VerifyVoteExtension(ctx, &abci.RequestVerifyVoteExtension{
   381  		Hash:             vote.BlockID.Hash,
   382  		ValidatorAddress: vote.ValidatorAddress,
   383  		Height:           vote.Height,
   384  		VoteExtension:    vote.Extension,
   385  	})
   386  	if err != nil {
   387  		panic(fmt.Errorf("VerifyVoteExtension call failed: %w", err))
   388  	}
   389  
   390  	if !resp.IsOK() {
   391  		return errors.New("invalid vote extension")
   392  	}
   393  
   394  	return nil
   395  }
   396  
   397  // Commit locks the mempool, runs the ABCI Commit message, and updates the
   398  // mempool.
   399  // It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any).
   400  // The Mempool must be locked during commit and update because state is
   401  // typically reset on Commit and old txs must be replayed against committed
   402  // state before new txs are run in the mempool, lest they be invalid.
   403  func (blockExec *BlockExecutor) Commit(
   404  	ctx context.Context,
   405  	state State,
   406  	block *types.Block,
   407  	txResults []*abci.ExecTxResult,
   408  ) (int64, error) {
   409  	blockExec.mempool.Lock()
   410  	defer blockExec.mempool.Unlock()
   411  
   412  	// while mempool is Locked, flush to ensure all async requests have completed
   413  	// in the ABCI app before Commit.
   414  	start := time.Now()
   415  	err := blockExec.mempool.FlushAppConn(ctx)
   416  	if err != nil {
   417  		blockExec.logger.Error("client error during mempool.FlushAppConn", "err", err)
   418  		return 0, err
   419  	}
   420  	blockExec.metrics.FlushAppConnectionTime.Observe(float64(time.Since(start)))
   421  
   422  	// Commit block, get hash back
   423  	start = time.Now()
   424  	res, err := blockExec.appClient.Commit(ctx)
   425  	if err != nil {
   426  		blockExec.logger.Error("client error during proxyAppConn.Commit", "err", err)
   427  		return 0, err
   428  	}
   429  	blockExec.metrics.ApplicationCommitTime.Observe(float64(time.Since(start)))
   430  
   431  	// ResponseCommit has no error code - just data
   432  	blockExec.logger.Info(
   433  		"committed state",
   434  		"height", block.Height,
   435  		"num_txs", len(block.Txs),
   436  		"block_app_hash", fmt.Sprintf("%X", block.AppHash),
   437  		"time", time.Now().UnixMilli(),
   438  	)
   439  
   440  	// Update mempool.
   441  	start = time.Now()
   442  	err = blockExec.mempool.Update(
   443  		ctx,
   444  		block.Height,
   445  		block.Txs,
   446  		txResults,
   447  		TxPreCheckForState(state),
   448  		TxPostCheckForState(state),
   449  		state.ConsensusParams.ABCI.RecheckTx,
   450  	)
   451  	blockExec.metrics.UpdateMempoolTime.Observe(float64(time.Since(start)))
   452  
   453  	return res.RetainHeight, err
   454  }
   455  
   456  func (blockExec *BlockExecutor) GetMissingTxs(txKeys []types.TxKey) []types.TxKey {
   457  	var missingTxKeys []types.TxKey
   458  	for _, txKey := range txKeys {
   459  		if !blockExec.mempool.HasTx(txKey) {
   460  			missingTxKeys = append(missingTxKeys, txKey)
   461  		}
   462  	}
   463  	return missingTxKeys
   464  }
   465  
   466  func (blockExec *BlockExecutor) CheckTxFromPeerProposal(ctx context.Context, tx types.Tx) {
   467  	// Ignore errors from CheckTx because there could be benign errors due to the same tx being
   468  	// inserted into the mempool from gossiping. Since such simultaneous insertion could result in
   469  	// multiple different kinds of errors, we will ignore them all here, and verify in the consensus
   470  	// state machine whether all txs in the proposal are present in the mempool at a later time.
   471  	if err := blockExec.mempool.CheckTx(ctx, tx, func(rct *abci.ResponseCheckTx) {}, mempool.TxInfo{
   472  		SenderID: math.MaxUint16,
   473  	}); err != nil {
   474  		blockExec.logger.Info(fmt.Sprintf("CheckTx for proposal tx from peer raised error %s. This could be ignored if the error is because the tx is added to the mempool while this check was happening", err))
   475  	}
   476  }
   477  
   478  func buildLastCommitInfo(block *types.Block, store Store, initialHeight int64) abci.CommitInfo {
   479  	if block.Height == initialHeight {
   480  		// there is no last commit for the initial height.
   481  		// return an empty value.
   482  		return abci.CommitInfo{}
   483  	}
   484  
   485  	lastValSet, err := store.LoadValidators(block.Height - 1)
   486  	if err != nil {
   487  		panic(fmt.Errorf("failed to load validator set at height %d: %w", block.Height-1, err))
   488  	}
   489  
   490  	var (
   491  		commitSize = block.LastCommit.Size()
   492  		valSetLen  = len(lastValSet.Validators)
   493  	)
   494  
   495  	// ensure that the size of the validator set in the last commit matches
   496  	// the size of the validator set in the state store.
   497  	if commitSize != valSetLen {
   498  		panic(fmt.Sprintf(
   499  			"commit size (%d) doesn't match validator set length (%d) at height %d\n\n%v\n\n%v",
   500  			commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators,
   501  		))
   502  	}
   503  
   504  	votes := make([]abci.VoteInfo, block.LastCommit.Size())
   505  	for i, val := range lastValSet.Validators {
   506  		commitSig := block.LastCommit.Signatures[i]
   507  		votes[i] = abci.VoteInfo{
   508  			Validator:       types.TM2PB.Validator(val),
   509  			SignedLastBlock: commitSig.BlockIDFlag != types.BlockIDFlagAbsent,
   510  		}
   511  	}
   512  
   513  	return abci.CommitInfo{
   514  		Round: block.LastCommit.Round,
   515  		Votes: votes,
   516  	}
   517  }
   518  
   519  // buildExtendedCommitInfo populates an ABCI extended commit from the
   520  // corresponding Tendermint extended commit ec, using the stored validator set
   521  // from ec.  It requires ec to include the original precommit votes along with
   522  // the vote extensions from the last commit.
   523  //
   524  // For heights below the initial height, for which we do not have the required
   525  // data, it returns an empty record.
   526  //
   527  // Assumes that the commit signatures are sorted according to validator index.
   528  func buildExtendedCommitInfo(ec *types.ExtendedCommit, store Store, initialHeight int64, ap types.ABCIParams) abci.ExtendedCommitInfo {
   529  	if ec.Height < initialHeight {
   530  		// There are no extended commits for heights below the initial height.
   531  		return abci.ExtendedCommitInfo{}
   532  	}
   533  
   534  	valSet, err := store.LoadValidators(ec.Height)
   535  	if err != nil {
   536  		panic(fmt.Errorf("failed to load validator set at height %d, initial height %d: %w", ec.Height, initialHeight, err))
   537  	}
   538  
   539  	var (
   540  		ecSize    = ec.Size()
   541  		valSetLen = len(valSet.Validators)
   542  	)
   543  
   544  	// Ensure that the size of the validator set in the extended commit matches
   545  	// the size of the validator set in the state store.
   546  	if ecSize != valSetLen {
   547  		panic(fmt.Errorf(
   548  			"extended commit size (%d) does not match validator set length (%d) at height %d\n\n%v\n\n%v",
   549  			ecSize, valSetLen, ec.Height, ec.ExtendedSignatures, valSet.Validators,
   550  		))
   551  	}
   552  
   553  	votes := make([]abci.ExtendedVoteInfo, ecSize)
   554  	for i, val := range valSet.Validators {
   555  		ecs := ec.ExtendedSignatures[i]
   556  
   557  		// Absent signatures have empty validator addresses, but otherwise we
   558  		// expect the validator addresses to be the same.
   559  		if ecs.BlockIDFlag != types.BlockIDFlagAbsent && !bytes.Equal(ecs.ValidatorAddress, val.Address) {
   560  			panic(fmt.Errorf("validator address of extended commit signature in position %d (%s) does not match the corresponding validator's at height %d (%s)",
   561  				i, ecs.ValidatorAddress, ec.Height, val.Address,
   562  			))
   563  		}
   564  
   565  		var ext []byte
   566  		// Check if vote extensions were enabled during the commit's height: ec.Height.
   567  		// ec is the commit from the previous height, so if extensions were enabled
   568  		// during that height, we ensure they are present and deliver the data to
   569  		// the proposer. If they were not enabled during this previous height, we
   570  		// will not deliver extension data.
   571  		if ap.VoteExtensionsEnabled(ec.Height) && ecs.BlockIDFlag == types.BlockIDFlagCommit {
   572  			if err := ecs.EnsureExtension(); err != nil {
   573  				panic(fmt.Errorf("commit at height %d received with missing vote extensions data", ec.Height))
   574  			}
   575  			ext = ecs.Extension
   576  		}
   577  
   578  		votes[i] = abci.ExtendedVoteInfo{
   579  			Validator:       types.TM2PB.Validator(val),
   580  			SignedLastBlock: ecs.BlockIDFlag != types.BlockIDFlagAbsent,
   581  			VoteExtension:   ext,
   582  		}
   583  	}
   584  
   585  	return abci.ExtendedCommitInfo{
   586  		Round: ec.Round,
   587  		Votes: votes,
   588  	}
   589  }
   590  
   591  func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate,
   592  	params types.ValidatorParams) error {
   593  	for _, valUpdate := range abciUpdates {
   594  		if valUpdate.GetPower() < 0 {
   595  			return fmt.Errorf("voting power can't be negative %v", valUpdate)
   596  		} else if valUpdate.GetPower() == 0 {
   597  			// continue, since this is deleting the validator, and thus there is no
   598  			// pubkey to check
   599  			continue
   600  		}
   601  
   602  		// Check if validator's pubkey matches an ABCI type in the consensus params
   603  		pk, err := encoding.PubKeyFromProto(valUpdate.PubKey)
   604  		if err != nil {
   605  			return err
   606  		}
   607  
   608  		if !params.IsValidPubkeyType(pk.Type()) {
   609  			return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus",
   610  				valUpdate, pk.Type())
   611  		}
   612  	}
   613  	return nil
   614  }
   615  
   616  // Update returns a copy of state with the fields set using the arguments passed in.
   617  func (state State) Update(
   618  	blockID types.BlockID,
   619  	header *types.Header,
   620  	resultsHash []byte,
   621  	consensusParamUpdates *tmtypes.ConsensusParams,
   622  	validatorUpdates []*types.Validator,
   623  ) (State, error) {
   624  
   625  	// Copy the valset so we can apply changes from FinalizeBlock
   626  	// and update s.LastValidators and s.Validators.
   627  	nValSet := state.NextValidators.Copy()
   628  
   629  	// Update the validator set with the latest responses to FinalizeBlock.
   630  	lastHeightValsChanged := state.LastHeightValidatorsChanged
   631  	if len(validatorUpdates) > 0 {
   632  		err := nValSet.UpdateWithChangeSet(validatorUpdates)
   633  		if err != nil {
   634  			return state, fmt.Errorf("changing validator set: %w", err)
   635  		}
   636  		// Change results from this height but only applies to the next next height.
   637  		lastHeightValsChanged = header.Height + 1 + 1
   638  	}
   639  
   640  	// Update validator proposer priority and set state variables.
   641  	nValSet.IncrementProposerPriority(1)
   642  
   643  	// Update the params with the latest responses to FinalizeBlock.
   644  	nextParams := state.ConsensusParams
   645  	lastHeightParamsChanged := state.LastHeightConsensusParamsChanged
   646  	if consensusParamUpdates != nil {
   647  		// NOTE: must not mutate state.ConsensusParams
   648  		nextParams = state.ConsensusParams.UpdateConsensusParams(consensusParamUpdates)
   649  		err := nextParams.ValidateConsensusParams()
   650  		if err != nil {
   651  			return state, fmt.Errorf("updating consensus params: %w", err)
   652  		}
   653  
   654  		err = state.ConsensusParams.ValidateUpdate(consensusParamUpdates, header.Height)
   655  		if err != nil {
   656  			return state, fmt.Errorf("updating consensus params: %w", err)
   657  		}
   658  
   659  		state.Version.Consensus.App = nextParams.Version.AppVersion
   660  
   661  		// Change results from this height but only applies to the next height.
   662  		lastHeightParamsChanged = header.Height + 1
   663  	}
   664  
   665  	nextVersion := state.Version
   666  
   667  	// NOTE: the AppHash and the VoteExtension has not been populated.
   668  	// It will be filled on state.Save.
   669  	return State{
   670  		Version:                          nextVersion,
   671  		ChainID:                          state.ChainID,
   672  		InitialHeight:                    state.InitialHeight,
   673  		LastBlockHeight:                  header.Height,
   674  		LastBlockID:                      blockID,
   675  		LastBlockTime:                    header.Time,
   676  		NextValidators:                   nValSet,
   677  		Validators:                       state.NextValidators.Copy(),
   678  		LastValidators:                   state.Validators.Copy(),
   679  		LastHeightValidatorsChanged:      lastHeightValsChanged,
   680  		ConsensusParams:                  nextParams,
   681  		LastHeightConsensusParamsChanged: lastHeightParamsChanged,
   682  		LastResultsHash:                  resultsHash,
   683  		AppHash:                          nil,
   684  	}, nil
   685  }
   686  
   687  // Fire NewBlock, NewBlockHeader.
   688  // Fire TxEvent for every tx.
   689  // NOTE: if Tendermint crashes before commit, some or all of these events may be published again.
   690  func fireEvents(
   691  	logger log.Logger,
   692  	eventBus types.BlockEventPublisher,
   693  	block *types.Block,
   694  	blockID types.BlockID,
   695  	finalizeBlockResponse *abci.ResponseFinalizeBlock,
   696  	validatorUpdates []*types.Validator,
   697  ) {
   698  	if err := eventBus.PublishEventNewBlock(types.EventDataNewBlock{
   699  		Block:               block,
   700  		BlockID:             blockID,
   701  		ResultFinalizeBlock: *finalizeBlockResponse,
   702  	}); err != nil {
   703  		logger.Error("failed publishing new block", "err", err)
   704  	}
   705  
   706  	if err := eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{
   707  		Header:              block.Header,
   708  		NumTxs:              int64(len(block.Txs)),
   709  		ResultFinalizeBlock: *finalizeBlockResponse,
   710  	}); err != nil {
   711  		logger.Error("failed publishing new block header", "err", err)
   712  	}
   713  
   714  	if len(block.Evidence) != 0 {
   715  		for _, ev := range block.Evidence {
   716  			if err := eventBus.PublishEventNewEvidence(types.EventDataNewEvidence{
   717  				Evidence: ev,
   718  				Height:   block.Height,
   719  			}); err != nil {
   720  				logger.Error("failed publishing new evidence", "err", err)
   721  			}
   722  		}
   723  	}
   724  
   725  	// sanity check
   726  	if len(finalizeBlockResponse.TxResults) != len(block.Data.Txs) {
   727  		panic(fmt.Sprintf("number of TXs (%d) and ABCI TX responses (%d) do not match",
   728  			len(block.Data.Txs), len(finalizeBlockResponse.TxResults)))
   729  	}
   730  
   731  	for i, tx := range block.Data.Txs {
   732  		if err := eventBus.PublishEventTx(types.EventDataTx{
   733  			TxResult: abci.TxResult{
   734  				Height: block.Height,
   735  				Index:  uint32(i),
   736  				Tx:     tx,
   737  				Result: *(finalizeBlockResponse.TxResults[i]),
   738  			},
   739  		}); err != nil {
   740  			logger.Error("failed publishing event TX", "err", err)
   741  		}
   742  	}
   743  
   744  	if len(finalizeBlockResponse.ValidatorUpdates) > 0 {
   745  		if err := eventBus.PublishEventValidatorSetUpdates(
   746  			types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates}); err != nil {
   747  			logger.Error("failed publishing event", "err", err)
   748  		}
   749  	}
   750  }
   751  
   752  //----------------------------------------------------------------------------------------------------
   753  // Execute block without state. TODO: eliminate
   754  
   755  // ExecCommitBlock executes and commits a block on the proxyApp without validating or mutating the state.
   756  // It returns the application root hash (result of abci.Commit).
   757  func ExecCommitBlock(
   758  	ctx context.Context,
   759  	be *BlockExecutor,
   760  	appConn abciclient.Client,
   761  	block *types.Block,
   762  	logger log.Logger,
   763  	store Store,
   764  	initialHeight int64,
   765  	s State,
   766  ) ([]byte, error) {
   767  	finalizeBlockResponse, err := appConn.FinalizeBlock(
   768  		ctx,
   769  		&abci.RequestFinalizeBlock{
   770  			Hash:                  block.Hash(),
   771  			Height:                block.Height,
   772  			Time:                  block.Time,
   773  			Txs:                   block.Txs.ToSliceOfBytes(),
   774  			DecidedLastCommit:     buildLastCommitInfo(block, store, initialHeight),
   775  			ByzantineValidators:   block.Evidence.ToABCI(),
   776  			AppHash:               block.AppHash,
   777  			ValidatorsHash:        block.ValidatorsHash,
   778  			ConsensusHash:         block.ConsensusHash,
   779  			DataHash:              block.DataHash,
   780  			EvidenceHash:          block.EvidenceHash,
   781  			LastBlockHash:         block.LastBlockID.Hash,
   782  			LastBlockPartSetTotal: int64(block.LastBlockID.PartSetHeader.Total),
   783  			LastBlockPartSetHash:  block.LastBlockID.Hash,
   784  			LastCommitHash:        block.LastCommitHash,
   785  			LastResultsHash:       block.LastResultsHash,
   786  		},
   787  	)
   788  
   789  	if err != nil {
   790  		logger.Error("executing block", "err", err)
   791  		return nil, err
   792  	}
   793  	logger.Info("executed block", "height", block.Height)
   794  
   795  	// the BlockExecutor condition is using for the final block replay process.
   796  	if be != nil {
   797  		err = validateValidatorUpdates(finalizeBlockResponse.ValidatorUpdates, s.ConsensusParams.Validator)
   798  		if err != nil {
   799  			logger.Error("validating validator updates", "err", err)
   800  			return nil, err
   801  		}
   802  		validatorUpdates, err := types.PB2TM.ValidatorUpdates(finalizeBlockResponse.ValidatorUpdates)
   803  		if err != nil {
   804  			logger.Error("converting validator updates to native types", "err", err)
   805  			return nil, err
   806  		}
   807  
   808  		bps, err := block.MakePartSet(types.BlockPartSizeBytes)
   809  		if err != nil {
   810  			return nil, err
   811  		}
   812  
   813  		blockID := types.BlockID{Hash: block.Hash(), PartSetHeader: bps.Header()}
   814  		fireEvents(be.logger, be.eventBus, block, blockID, finalizeBlockResponse, validatorUpdates)
   815  	}
   816  
   817  	// Commit block
   818  	_, err = appConn.Commit(ctx)
   819  	if err != nil {
   820  		logger.Error("client error during proxyAppConn.Commit", "err", err)
   821  		return nil, err
   822  	}
   823  
   824  	// ResponseCommit has no error or log
   825  	return finalizeBlockResponse.AppHash, nil
   826  }
   827  
   828  func (blockExec *BlockExecutor) pruneBlocks(retainHeight int64) (uint64, error) {
   829  	base := blockExec.blockStore.Base()
   830  	if retainHeight <= base {
   831  		return 0, nil
   832  	}
   833  	pruned, err := blockExec.blockStore.PruneBlocks(retainHeight)
   834  	if err != nil {
   835  		return 0, fmt.Errorf("failed to prune block store: %w", err)
   836  	}
   837  
   838  	err = blockExec.Store().PruneStates(retainHeight)
   839  	if err != nil {
   840  		return 0, fmt.Errorf("failed to prune state store: %w", err)
   841  	}
   842  	return pruned, nil
   843  }