github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/tendermint/state/execution.go (about)

     1  package state
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"time"
     7  
     8  	"github.com/fibonacci-chain/fbc/libs/system/trace"
     9  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    10  	cfg "github.com/fibonacci-chain/fbc/libs/tendermint/config"
    11  	"github.com/fibonacci-chain/fbc/libs/tendermint/global"
    12  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/automation"
    13  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/fail"
    14  	"github.com/fibonacci-chain/fbc/libs/tendermint/libs/log"
    15  	mempl "github.com/fibonacci-chain/fbc/libs/tendermint/mempool"
    16  	"github.com/fibonacci-chain/fbc/libs/tendermint/proxy"
    17  	"github.com/fibonacci-chain/fbc/libs/tendermint/types"
    18  	tmtime "github.com/fibonacci-chain/fbc/libs/tendermint/types/time"
    19  	dbm "github.com/fibonacci-chain/fbc/libs/tm-db"
    20  	"github.com/tendermint/go-amino"
    21  )
    22  
    23  // -----------------------------------------------------------------------------
    24  type (
    25  	// Enum mode for executing [deliverTx, ...]
    26  	DeliverTxsExecMode int
    27  )
    28  
    29  const (
    30  	DeliverTxsExecModeSerial   DeliverTxsExecMode = iota // execute [deliverTx,...] sequentially
    31  	DeliverTxsExecModeParallel                    = 2    // execute [deliverTx,...] parallel
    32  
    33  	// There are two modes.
    34  	// 0: execute [deliverTx,...] sequentially (default)
    35  	// 1: execute [deliverTx,...] deprecated
    36  	// 2: execute [deliverTx,...] parallel
    37  	FlagDeliverTxsExecMode = "deliver-txs-mode"
    38  	FlagEnableConcurrency  = "enable-concurrency"
    39  )
    40  
    41  // BlockExecutor handles block execution and state updates.
    42  // It exposes ApplyBlock(), which validates & executes the block, updates state w/ ABCI responses,
    43  // then commits and updates the mempool atomically, then saves state.
    44  
    45  // BlockExecutor provides the context and accessories for properly executing a block.
    46  type BlockExecutor struct {
    47  	// save state, validators, consensus params, abci responses here
    48  	db dbm.DB
    49  
    50  	// execute the app against this
    51  	proxyApp proxy.AppConnConsensus
    52  
    53  	// events
    54  	eventBus types.BlockEventPublisher
    55  
    56  	// manage the mempool lock during commit
    57  	// and update both with block results after commit.
    58  	mempool mempl.Mempool
    59  	evpool  EvidencePool
    60  
    61  	logger  log.Logger
    62  	metrics *Metrics
    63  
    64  	// download or upload data to dds
    65  	deltaContext *DeltaContext
    66  
    67  	prerunCtx *prerunContext
    68  
    69  	isFastSync bool
    70  
    71  	// async save state, validators, consensus params, abci responses here
    72  	asyncDBContext
    73  
    74  	// the owner is validator
    75  	isNullIndexer bool
    76  	eventsChan    chan event
    77  }
    78  
    79  type event struct {
    80  	block   *types.Block
    81  	abciRsp *ABCIResponses
    82  	vals    []*types.Validator
    83  }
    84  
    85  type BlockExecutorOption func(executor *BlockExecutor)
    86  
    87  func BlockExecutorWithMetrics(metrics *Metrics) BlockExecutorOption {
    88  	return func(blockExec *BlockExecutor) {
    89  		blockExec.metrics = metrics
    90  	}
    91  }
    92  
    93  // NewBlockExecutor returns a new BlockExecutor with a NopEventBus.
    94  // Call SetEventBus to provide one.
    95  func NewBlockExecutor(
    96  	db dbm.DB,
    97  	logger log.Logger,
    98  	proxyApp proxy.AppConnConsensus,
    99  	mempool mempl.Mempool,
   100  	evpool EvidencePool,
   101  	options ...BlockExecutorOption,
   102  ) *BlockExecutor {
   103  	res := &BlockExecutor{
   104  		db:           db,
   105  		proxyApp:     proxyApp,
   106  		eventBus:     types.NopEventBus{},
   107  		mempool:      mempool,
   108  		evpool:       evpool,
   109  		logger:       logger,
   110  		metrics:      NopMetrics(),
   111  		prerunCtx:    newPrerunContex(logger),
   112  		deltaContext: newDeltaContext(logger),
   113  		eventsChan:   make(chan event, 5),
   114  	}
   115  
   116  	for _, option := range options {
   117  		option(res)
   118  	}
   119  	automation.LoadTestCase(logger)
   120  	res.deltaContext.init()
   121  
   122  	res.initAsyncDBContext()
   123  
   124  	return res
   125  }
   126  
   127  func (blockExec *BlockExecutor) fireEventsRountine() {
   128  	for et := range blockExec.eventsChan {
   129  		if et.block == nil {
   130  			break
   131  		}
   132  		fireEvents(blockExec.logger, blockExec.eventBus, et.block, et.abciRsp, et.vals)
   133  	}
   134  	blockExec.wg.Done()
   135  }
   136  
   137  func (blockExec *BlockExecutor) DB() dbm.DB {
   138  	return blockExec.db
   139  }
   140  
   141  func (blockExec *BlockExecutor) SetIsFastSyncing(isSyncing bool) {
   142  	blockExec.isFastSync = isSyncing
   143  }
   144  
   145  func (blockExec *BlockExecutor) SetIsNullIndexer(isNullIndexer bool) {
   146  	blockExec.isNullIndexer = isNullIndexer
   147  }
   148  
   149  func (blockExec *BlockExecutor) Stop() {
   150  	blockExec.stopAsyncDBContext()
   151  }
   152  
   153  // SetEventBus - sets the event bus for publishing block related events.
   154  // If not called, it defaults to types.NopEventBus.
   155  func (blockExec *BlockExecutor) SetEventBus(eventBus types.BlockEventPublisher) {
   156  	blockExec.eventBus = eventBus
   157  	blockExec.mempool.SetEventBus(eventBus)
   158  }
   159  
   160  // CreateProposalBlock calls state.MakeBlock with evidence from the evpool
   161  // and txs from the mempool. The max bytes must be big enough to fit the commit.
   162  // Up to 1/10th of the block space is allcoated for maximum sized evidence.
   163  // The rest is given to txs, up to the max gas.
   164  func (blockExec *BlockExecutor) CreateProposalBlock(
   165  	height int64,
   166  	state State, commit *types.Commit,
   167  	proposerAddr []byte,
   168  ) (*types.Block, *types.PartSet) {
   169  
   170  	maxBytes := state.ConsensusParams.Block.MaxBytes
   171  	maxGas := state.ConsensusParams.Block.MaxGas
   172  
   173  	// Fetch a limited amount of valid evidence
   174  	maxNumEvidence, _ := types.MaxEvidencePerBlock(maxBytes)
   175  	evidence := blockExec.evpool.PendingEvidence(maxNumEvidence)
   176  
   177  	// Fetch a limited amount of valid txs
   178  	maxDataBytes := types.MaxDataBytes(maxBytes, state.Validators.Size(), len(evidence))
   179  	if cfg.DynamicConfig.GetMaxGasUsedPerBlock() > -1 {
   180  		maxGas = cfg.DynamicConfig.GetMaxGasUsedPerBlock()
   181  	}
   182  	txs := blockExec.mempool.ReapMaxBytesMaxGas(maxDataBytes, maxGas)
   183  
   184  	return state.MakeBlock(height, txs, commit, evidence, proposerAddr)
   185  }
   186  
   187  // ValidateBlock validates the given block against the given state.
   188  // If the block is invalid, it returns an error.
   189  // Validation does not mutate state, but does require historical information from the stateDB,
   190  // ie. to verify evidence from a validator at an old height.
   191  func (blockExec *BlockExecutor) ValidateBlock(state State, block *types.Block) error {
   192  	if IgnoreSmbCheck {
   193  		// debug only
   194  		return nil
   195  	}
   196  	return validateBlock(blockExec.evpool, blockExec.db, state, block)
   197  }
   198  
   199  // ApplyBlock validates the block against the state, executes it against the app,
   200  // fires the relevant events, commits the app, and saves the new state and responses.
   201  // It returns the new state and the block height to retain (pruning older blocks).
   202  // It's the only function that needs to be called
   203  // from outside this package to process and commit an entire block.
   204  // It takes a blockID to avoid recomputing the parts hash.
   205  func (blockExec *BlockExecutor) ApplyBlock(
   206  	state State, blockID types.BlockID, block *types.Block) (State, int64, error) {
   207  	if ApplyBlockPprofTime >= 0 {
   208  		f, t := PprofStart()
   209  		defer PprofEnd(int(block.Height), f, t)
   210  	}
   211  	trc := trace.NewTracer(trace.ApplyBlock)
   212  	trc.EnableSummary()
   213  	trc.SetWorkloadStatistic(trace.GetApplyBlockWorkloadSttistic())
   214  	dc := blockExec.deltaContext
   215  
   216  	defer func() {
   217  		trace.GetElapsedInfo().AddInfo(trace.Height, strconv.FormatInt(block.Height, 10))
   218  		trace.GetElapsedInfo().AddInfo(trace.Tx, strconv.Itoa(len(block.Data.Txs)))
   219  		trace.GetElapsedInfo().AddInfo(trace.BlockSize, strconv.Itoa(block.FastSize()))
   220  		trace.GetElapsedInfo().AddInfo(trace.ApplyBlock, trc.Format())
   221  		trace.GetElapsedInfo().AddInfo(trace.Workload, trace.GetApplyBlockWorkloadSttistic().Format())
   222  		trace.GetElapsedInfo().SetElapsedTime(trc.GetElapsedTime())
   223  
   224  		now := time.Now().UnixNano()
   225  		blockExec.metrics.IntervalTime.Set(float64(now-blockExec.metrics.lastBlockTime) / 1e6)
   226  		blockExec.metrics.lastBlockTime = now
   227  	}()
   228  
   229  	if err := blockExec.ValidateBlock(state, block); err != nil {
   230  		return state, 0, ErrInvalidBlock(err)
   231  	}
   232  
   233  	deltaInfo := dc.prepareStateDelta(block.Height)
   234  
   235  	trc.Pin(trace.Abci)
   236  
   237  	startTime := time.Now().UnixNano()
   238  
   239  	//wait till the last block async write be saved
   240  	blockExec.tryWaitLastBlockSave(block.Height - 1)
   241  
   242  	abciResponses, duration, err := blockExec.runAbci(block, deltaInfo)
   243  
   244  	// publish event
   245  	if types.EnableEventBlockTime {
   246  
   247  		blockExec.FireBlockTimeEvents(block.Height, len(block.Txs), true)
   248  
   249  		if !blockExec.isNullIndexer {
   250  			blockExec.eventsChan <- event{
   251  				block:   block,
   252  				abciRsp: abciResponses,
   253  			}
   254  		}
   255  	}
   256  
   257  	trace.GetElapsedInfo().AddInfo(trace.LastRun, fmt.Sprintf("%dms", duration.Milliseconds()))
   258  	trace.GetApplyBlockWorkloadSttistic().Add(trace.LastRun, time.Now(), duration)
   259  
   260  	if err != nil {
   261  		return state, 0, ErrProxyAppConn(err)
   262  	}
   263  
   264  	fail.Fail() // XXX
   265  
   266  	// Save the results before we commit.
   267  	blockExec.trySaveABCIResponsesAsync(block.Height, abciResponses)
   268  
   269  	fail.Fail() // XXX
   270  	endTime := time.Now().UnixNano()
   271  	blockExec.metrics.BlockProcessingTime.Observe(float64(endTime-startTime) / 1e6)
   272  	blockExec.metrics.AbciTime.Set(float64(endTime-startTime) / 1e6)
   273  
   274  	// validate the validator updates and convert to tendermint types
   275  	abciValUpdates := abciResponses.EndBlock.ValidatorUpdates
   276  	err = validateValidatorUpdates(abciValUpdates, state.ConsensusParams.Validator)
   277  	if err != nil {
   278  		return state, 0, fmt.Errorf("error in validator updates: %v", err)
   279  	}
   280  	validatorUpdates, err := types.PB2TM.ValidatorUpdates(abciValUpdates)
   281  	if err != nil {
   282  		return state, 0, err
   283  	}
   284  	if len(validatorUpdates) > 0 {
   285  		blockExec.logger.Info("Updates to validators", "updates", types.ValidatorListString(validatorUpdates))
   286  	}
   287  
   288  	// Update the state with the block and responses.
   289  	state, err = updateState(state, blockID, &block.Header, abciResponses, validatorUpdates)
   290  	if err != nil {
   291  		return state, 0, fmt.Errorf("commit failed for application: %v", err)
   292  	}
   293  
   294  	trc.Pin(trace.Persist)
   295  	startTime = time.Now().UnixNano()
   296  
   297  	// Lock mempool, commit app state, update mempoool.
   298  	commitResp, retainHeight, err := blockExec.commit(state, block, deltaInfo, abciResponses.DeliverTxs, trc)
   299  	endTime = time.Now().UnixNano()
   300  	blockExec.metrics.CommitTime.Set(float64(endTime-startTime) / 1e6)
   301  	if err != nil {
   302  		return state, 0, fmt.Errorf("commit failed for application: %v", err)
   303  	}
   304  	global.SetGlobalHeight(block.Height)
   305  
   306  	// Update evpool with the block and state.
   307  	blockExec.evpool.Update(block, state)
   308  
   309  	fail.Fail() // XXX
   310  
   311  	trc.Pin("SaveState")
   312  
   313  	// Update the app hash and save the state.
   314  	state.AppHash = commitResp.Data
   315  	blockExec.trySaveStateAsync(state)
   316  
   317  	blockExec.logger.Debug("SaveState", "state", &state)
   318  	fail.Fail() // XXX
   319  
   320  	dc.postApplyBlock(block.Height, deltaInfo, abciResponses, commitResp.DeltaMap, blockExec.isFastSync)
   321  
   322  	// Events are fired after everything else.
   323  	// NOTE: if we crash between Commit and Save, events wont be fired during replay
   324  	if !types.EnableEventBlockTime {
   325  		if !blockExec.isNullIndexer {
   326  			blockExec.eventsChan <- event{
   327  				block:   block,
   328  				abciRsp: abciResponses,
   329  			}
   330  		}
   331  	}
   332  
   333  	return state, retainHeight, nil
   334  }
   335  
   336  func (blockExec *BlockExecutor) ApplyBlockWithTrace(
   337  	state State, blockID types.BlockID, block *types.Block) (State, int64, error) {
   338  	s, id, err := blockExec.ApplyBlock(state, blockID, block)
   339  	trace.GetElapsedInfo().Dump(blockExec.logger.With("module", "main"))
   340  	return s, id, err
   341  }
   342  
   343  func (blockExec *BlockExecutor) runAbci(block *types.Block, deltaInfo *DeltaInfo) (*ABCIResponses, time.Duration, error) {
   344  	var abciResponses *ABCIResponses
   345  	var err error
   346  	var duration time.Duration
   347  
   348  	if deltaInfo != nil {
   349  		blockExec.logger.Info("Apply delta", "height", block.Height, "deltas-length", deltaInfo.deltaLen)
   350  		t0 := time.Now()
   351  		execBlockOnProxyAppWithDeltas(blockExec.proxyApp, block, blockExec.db)
   352  		abciResponses = deltaInfo.abciResponses
   353  		duration = time.Now().Sub(t0)
   354  	} else {
   355  		pc := blockExec.prerunCtx
   356  		if pc.prerunTx {
   357  			abciResponses, duration, err = pc.getPrerunResult(block)
   358  		}
   359  
   360  		if abciResponses == nil {
   361  			t0 := time.Now()
   362  			ctx := &executionTask{
   363  				logger:   blockExec.logger,
   364  				block:    block,
   365  				db:       blockExec.db,
   366  				proxyApp: blockExec.proxyApp,
   367  			}
   368  			mode := DeliverTxsExecMode(cfg.DynamicConfig.GetDeliverTxsExecuteMode())
   369  			switch mode {
   370  			case DeliverTxsExecModeSerial:
   371  				abciResponses, err = execBlockOnProxyApp(ctx)
   372  			case DeliverTxsExecModeParallel:
   373  				abciResponses, err = execBlockOnProxyAppAsync(blockExec.logger, blockExec.proxyApp, block, blockExec.db)
   374  			default:
   375  				abciResponses, err = execBlockOnProxyApp(ctx)
   376  			}
   377  			duration = time.Now().Sub(t0)
   378  		}
   379  	}
   380  
   381  	return abciResponses, duration, err
   382  }
   383  
   384  // Commit locks the mempool, runs the ABCI Commit message, and updates the
   385  // mempool.
   386  // It returns the result of calling abci.Commit (the AppHash) and the height to retain (if any).
   387  // The Mempool must be locked during commit and update because state is
   388  // typically reset on Commit and old txs must be replayed against committed
   389  // state before new txs are run in the mempool, lest they be invalid.
   390  func (blockExec *BlockExecutor) commit(
   391  	state State,
   392  	block *types.Block,
   393  	deltaInfo *DeltaInfo,
   394  	deliverTxResponses []*abci.ResponseDeliverTx,
   395  	trc *trace.Tracer,
   396  ) (*abci.ResponseCommit, int64, error) {
   397  	blockExec.mempool.Lock()
   398  	defer func() {
   399  		blockExec.mempool.Unlock()
   400  		// Forced flushing mempool
   401  		if cfg.DynamicConfig.GetMempoolFlush() {
   402  			blockExec.mempool.Flush()
   403  		}
   404  	}()
   405  
   406  	// while mempool is Locked, flush to ensure all async requests have completed
   407  	// in the ABCI app before Commit.
   408  	err := blockExec.mempool.FlushAppConn()
   409  	if err != nil {
   410  		blockExec.logger.Error("Client error during mempool.FlushAppConn", "err", err)
   411  		return nil, 0, err
   412  	}
   413  
   414  	// Commit block, get hash back
   415  	var treeDeltaMap interface{}
   416  	if deltaInfo != nil {
   417  		treeDeltaMap = deltaInfo.treeDeltaMap
   418  	}
   419  	res, err := blockExec.proxyApp.CommitSync(abci.RequestCommit{DeltaMap: treeDeltaMap})
   420  	if err != nil {
   421  		blockExec.logger.Error(
   422  			"Client error during proxyAppConn.CommitSync",
   423  			"err", err,
   424  		)
   425  		return nil, 0, err
   426  	}
   427  
   428  	// ResponseCommit has no error code - just data
   429  	blockExec.logger.Debug(
   430  		"Committed state",
   431  		"height", block.Height,
   432  		"txs", len(block.Txs),
   433  		"appHash", amino.BytesHexStringer(res.Data),
   434  		"blockLen", amino.FuncStringer(func() string { return strconv.Itoa(block.FastSize()) }),
   435  	)
   436  
   437  	trc.Pin("mpUpdate")
   438  	// Update mempool.
   439  	err = blockExec.mempool.Update(
   440  		block.Height,
   441  		block.Txs,
   442  		deliverTxResponses,
   443  		TxPreCheck(state),
   444  		TxPostCheck(state),
   445  	)
   446  
   447  	if !cfg.DynamicConfig.GetMempoolRecheck() && block.Height%cfg.DynamicConfig.GetMempoolForceRecheckGap() == 0 {
   448  		proxyCb := func(req *abci.Request, res *abci.Response) {
   449  
   450  		}
   451  		blockExec.proxyApp.SetResponseCallback(proxyCb)
   452  		// reset checkState
   453  		blockExec.proxyApp.SetOptionAsync(abci.RequestSetOption{
   454  			Key: "ResetCheckState",
   455  		})
   456  	}
   457  
   458  	return res, res.RetainHeight, err
   459  }
   460  
   461  func transTxsToBytes(txs types.Txs) [][]byte {
   462  	ret := make([][]byte, 0)
   463  	for _, v := range txs {
   464  		ret = append(ret, v)
   465  	}
   466  	return ret
   467  }
   468  
   469  //---------------------------------------------------------
   470  // Helper functions for executing blocks and updating state
   471  
   472  // Executes block's transactions on proxyAppConn.
   473  // Returns a list of transaction results and updates to the validator set
   474  func execBlockOnProxyApp(context *executionTask) (*ABCIResponses, error) {
   475  	block := context.block
   476  	proxyAppConn := context.proxyApp
   477  	stateDB := context.db
   478  	logger := context.logger
   479  
   480  	var validTxs, invalidTxs = 0, 0
   481  
   482  	txIndex := 0
   483  	abciResponses := NewABCIResponses(block)
   484  
   485  	// Execute transactions and get hash.
   486  	proxyCb := func(req *abci.Request, res *abci.Response) {
   487  		if r, ok := res.Value.(*abci.Response_DeliverTx); ok {
   488  			// TODO: make use of res.Log
   489  			// TODO: make use of this info
   490  			// Blocks may include invalid txs.
   491  			txRes := r.DeliverTx
   492  			if txRes.Code == abci.CodeTypeOK {
   493  				validTxs++
   494  			} else {
   495  				logger.Debug("Invalid tx", "code", txRes.Code, "log", txRes.Log, "index", txIndex)
   496  				invalidTxs++
   497  			}
   498  			abciResponses.DeliverTxs[txIndex] = txRes
   499  			txIndex++
   500  		}
   501  	}
   502  	proxyAppConn.SetResponseCallback(proxyCb)
   503  
   504  	// proxyAppConn.ParallelTxs(transTxsToBytes(block.Txs), true)
   505  	commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB)
   506  
   507  	// Begin block
   508  	var err error
   509  	abciResponses.BeginBlock, err = proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
   510  		Hash:                block.Hash(),
   511  		Header:              types.TM2PB.Header(&block.Header),
   512  		LastCommitInfo:      commitInfo,
   513  		ByzantineValidators: byzVals,
   514  	})
   515  	if err != nil {
   516  		logger.Error("Error in proxyAppConn.BeginBlock", "err", err)
   517  		return nil, err
   518  	}
   519  
   520  	realTxCh := make(chan abci.TxEssentials, len(block.Txs))
   521  	stopedCh := make(chan struct{}, 1)
   522  
   523  	go preDeliverRoutine(proxyAppConn, block.Txs, realTxCh, stopedCh)
   524  
   525  	count := 0
   526  	for realTx := range realTxCh {
   527  		if realTx != nil {
   528  			proxyAppConn.DeliverRealTxAsync(realTx)
   529  		} else {
   530  			proxyAppConn.DeliverTxAsync(abci.RequestDeliverTx{Tx: block.Txs[count]})
   531  		}
   532  
   533  		if err = proxyAppConn.Error(); err != nil {
   534  			return nil, err
   535  		}
   536  		if context != nil && context.stopped {
   537  			stopedCh <- struct{}{}
   538  			close(stopedCh)
   539  			context.dump(fmt.Sprintf("Prerun stopped, %d/%d tx executed", count+1, len(block.Txs)))
   540  			return nil, fmt.Errorf("Prerun stopped")
   541  		}
   542  		count += 1
   543  	}
   544  	close(stopedCh)
   545  
   546  	// End block.
   547  	abciResponses.EndBlock, err = proxyAppConn.EndBlockSync(abci.RequestEndBlock{Height: block.Height})
   548  	if err != nil {
   549  		logger.Error("Error in proxyAppConn.EndBlock", "err", err)
   550  		return nil, err
   551  	}
   552  
   553  	trace.GetElapsedInfo().AddInfo(trace.InvalidTxs, fmt.Sprintf("%d", invalidTxs))
   554  
   555  	return abciResponses, nil
   556  }
   557  
   558  func preDeliverRoutine(proxyAppConn proxy.AppConnConsensus, txs types.Txs, realTxCh chan<- abci.TxEssentials, stopedCh <-chan struct{}) {
   559  	for _, tx := range txs {
   560  		realTx := proxyAppConn.PreDeliverRealTxAsync(tx)
   561  		select {
   562  		case realTxCh <- realTx:
   563  		case <-stopedCh:
   564  			close(realTxCh)
   565  			return
   566  		}
   567  	}
   568  	close(realTxCh)
   569  }
   570  
   571  func execBlockOnProxyAppWithDeltas(
   572  	proxyAppConn proxy.AppConnConsensus,
   573  	block *types.Block,
   574  	stateDB dbm.DB,
   575  ) {
   576  	proxyCb := func(req *abci.Request, res *abci.Response) {
   577  	}
   578  	proxyAppConn.SetResponseCallback(proxyCb)
   579  
   580  	commitInfo, byzVals := getBeginBlockValidatorInfo(block, stateDB)
   581  	_, _ = proxyAppConn.BeginBlockSync(abci.RequestBeginBlock{
   582  		Hash:                block.Hash(),
   583  		Header:              types.TM2PB.Header(&block.Header),
   584  		LastCommitInfo:      commitInfo,
   585  		ByzantineValidators: byzVals,
   586  	})
   587  }
   588  
   589  func getBeginBlockValidatorInfo(block *types.Block, stateDB dbm.DB) (abci.LastCommitInfo, []abci.Evidence) {
   590  	voteInfos := make([]abci.VoteInfo, block.LastCommit.Size())
   591  	// block.Height=1 -> LastCommitInfo.Votes are empty.
   592  	// Remember that the first LastCommit is intentionally empty, so it makes
   593  	// sense for LastCommitInfo.Votes to also be empty.
   594  	if block.Height > types.GetStartBlockHeight()+1 {
   595  		lastValSet, err := LoadValidators(stateDB, block.Height-1)
   596  		if err != nil {
   597  			panic(err)
   598  		}
   599  
   600  		// Sanity check that commit size matches validator set size - only applies
   601  		// after first block.
   602  		var (
   603  			commitSize = block.LastCommit.Size()
   604  			valSetLen  = len(lastValSet.Validators)
   605  		)
   606  		if commitSize != valSetLen {
   607  			panic(fmt.Sprintf("commit size (%d) doesn't match valset length (%d) at height %d\n\n%v\n\n%v",
   608  				commitSize, valSetLen, block.Height, block.LastCommit.Signatures, lastValSet.Validators))
   609  		}
   610  
   611  		for i, val := range lastValSet.Validators {
   612  			commitSig := block.LastCommit.Signatures[i]
   613  			voteInfos[i] = abci.VoteInfo{
   614  				Validator:       types.TM2PB.Validator(val),
   615  				SignedLastBlock: !commitSig.Absent(),
   616  			}
   617  		}
   618  	}
   619  
   620  	byzVals := make([]abci.Evidence, len(block.Evidence.Evidence))
   621  	for i, ev := range block.Evidence.Evidence {
   622  		// We need the validator set. We already did this in validateBlock.
   623  		// TODO: Should we instead cache the valset in the evidence itself and add
   624  		// `SetValidatorSet()` and `ToABCI` methods ?
   625  		valset, err := LoadValidators(stateDB, ev.Height())
   626  		if err != nil {
   627  			panic(err)
   628  		}
   629  		byzVals[i] = types.TM2PB.Evidence(ev, valset, block.Time)
   630  	}
   631  
   632  	return abci.LastCommitInfo{
   633  		Round: int32(block.LastCommit.Round),
   634  		Votes: voteInfos,
   635  	}, byzVals
   636  }
   637  
   638  func validateValidatorUpdates(abciUpdates []abci.ValidatorUpdate,
   639  	params types.ValidatorParams) error {
   640  	for _, valUpdate := range abciUpdates {
   641  		if valUpdate.GetPower() < 0 {
   642  			return fmt.Errorf("voting power can't be negative %v", valUpdate)
   643  		} else if valUpdate.GetPower() == 0 {
   644  			// continue, since this is deleting the validator, and thus there is no
   645  			// pubkey to check
   646  			continue
   647  		}
   648  
   649  		// Check if validator's pubkey matches an ABCI type in the consensus params
   650  		thisKeyType := valUpdate.PubKey.Type
   651  		if !params.IsValidPubkeyType(thisKeyType) {
   652  			return fmt.Errorf("validator %v is using pubkey %s, which is unsupported for consensus",
   653  				valUpdate, thisKeyType)
   654  		}
   655  	}
   656  	return nil
   657  }
   658  
   659  // updateState returns a new State updated according to the header and responses.
   660  func updateState(
   661  	state State,
   662  	blockID types.BlockID,
   663  	header *types.Header,
   664  	abciResponses *ABCIResponses,
   665  	validatorUpdates []*types.Validator,
   666  ) (State, error) {
   667  
   668  	// Copy the valset so we can apply changes from EndBlock
   669  	// and update s.LastValidators and s.Validators.
   670  	nValSet := state.NextValidators.Copy()
   671  
   672  	// Update the validator set with the latest abciResponses.
   673  	lastHeightValsChanged := state.LastHeightValidatorsChanged
   674  	if len(validatorUpdates) > 0 {
   675  		err := nValSet.UpdateWithChangeSet(validatorUpdates)
   676  		if err != nil {
   677  			return state, fmt.Errorf("error changing validator set: %v", err)
   678  		}
   679  		// Change results from this height but only applies to the next next height.
   680  		lastHeightValsChanged = header.Height + 1 + 1
   681  	}
   682  
   683  	// Update validator proposer priority and set state variables.
   684  	nValSet.IncrementProposerPriority(1)
   685  
   686  	// Update the params with the latest abciResponses.
   687  	nextParams := state.ConsensusParams
   688  	lastHeightParamsChanged := state.LastHeightConsensusParamsChanged
   689  	if abciResponses.EndBlock.ConsensusParamUpdates != nil {
   690  		// NOTE: must not mutate s.ConsensusParams
   691  		nextParams = state.ConsensusParams.Update(abciResponses.EndBlock.ConsensusParamUpdates)
   692  		err := nextParams.Validate()
   693  		if err != nil {
   694  			return state, fmt.Errorf("error updating consensus params: %v", err)
   695  		}
   696  		// Change results from this height but only applies to the next height.
   697  		lastHeightParamsChanged = header.Height + 1
   698  	}
   699  
   700  	// TODO: allow app to upgrade version
   701  	nextVersion := state.Version
   702  	if types.HigherThanVenus1(header.Height) && !state.Version.IsUpgraded() {
   703  		nextVersion = state.Version.UpgradeToIBCVersion()
   704  	}
   705  
   706  	// NOTE: the AppHash has not been populated.
   707  	// It will be filled on state.Save.
   708  	return State{
   709  		Version:                          nextVersion,
   710  		ChainID:                          state.ChainID,
   711  		LastBlockHeight:                  header.Height,
   712  		LastBlockID:                      blockID,
   713  		LastBlockTime:                    header.Time,
   714  		NextValidators:                   nValSet,
   715  		Validators:                       state.NextValidators.Copy(),
   716  		LastValidators:                   state.Validators.Copy(),
   717  		LastHeightValidatorsChanged:      lastHeightValsChanged,
   718  		ConsensusParams:                  nextParams,
   719  		LastHeightConsensusParamsChanged: lastHeightParamsChanged,
   720  		LastResultsHash:                  abciResponses.ResultsHash(),
   721  		AppHash:                          nil,
   722  	}, nil
   723  }
   724  
   725  // Fire NewBlock, NewBlockHeader.
   726  // Fire TxEvent for every tx.
   727  // NOTE: if Tendermint crashes before commit, some or all of these events may be published again.
   728  func fireEvents(
   729  	logger log.Logger,
   730  	eventBus types.BlockEventPublisher,
   731  	block *types.Block,
   732  	abciResponses *ABCIResponses,
   733  	validatorUpdates []*types.Validator,
   734  ) {
   735  	eventBus.PublishEventNewBlock(types.EventDataNewBlock{
   736  		Block:            block,
   737  		ResultBeginBlock: *abciResponses.BeginBlock,
   738  		ResultEndBlock:   *abciResponses.EndBlock,
   739  	})
   740  	eventBus.PublishEventNewBlockHeader(types.EventDataNewBlockHeader{
   741  		Header:           block.Header,
   742  		NumTxs:           int64(len(block.Txs)),
   743  		ResultBeginBlock: *abciResponses.BeginBlock,
   744  		ResultEndBlock:   *abciResponses.EndBlock,
   745  	})
   746  
   747  	//publish tx event 1by1
   748  	for i, tx := range block.Data.Txs {
   749  		eventBus.PublishEventTx(types.EventDataTx{TxResult: types.TxResult{
   750  			Height: block.Height,
   751  			Index:  uint32(i),
   752  			Tx:     tx,
   753  			Result: *(abciResponses.DeliverTxs[i]),
   754  		}})
   755  	}
   756  
   757  	//publish batch txs event
   758  	if len(block.Data.Txs) > 0 {
   759  		eventBus.PublishEventTxs(types.EventDataTxs{
   760  			Height:  block.Height,
   761  			Results: abciResponses.DeliverTxs,
   762  		})
   763  	}
   764  
   765  	//if len(validatorUpdates) > 0 {
   766  	//	eventBus.PublishEventValidatorSetUpdates(
   767  	//		types.EventDataValidatorSetUpdates{ValidatorUpdates: validatorUpdates})
   768  	//}
   769  }
   770  
   771  func (blockExec *BlockExecutor) FireBlockTimeEvents(height int64, txNum int, available bool) {
   772  	blockExec.eventBus.PublishEventLatestBlockTime(
   773  		types.EventDataBlockTime{Height: height, TimeNow: tmtime.Now().UnixMilli(), TxNum: txNum, Available: available})
   774  }