github.com/okex/exchain@v1.8.0/libs/tendermint/state/execution_context.go (about)

     1  package state
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"github.com/okex/exchain/libs/tendermint/libs/log"
     7  	"github.com/okex/exchain/libs/tendermint/types"
     8  	"time"
     9  )
    10  
    11  type prerunContext struct {
    12  	prerunTx       bool
    13  	taskChan       chan *executionTask
    14  	taskResultChan chan *executionTask
    15  	prerunTask     *executionTask
    16  	logger         log.Logger
    17  }
    18  
    19  func newPrerunContex(logger log.Logger) *prerunContext {
    20  	return &prerunContext{
    21  		taskChan:       make(chan *executionTask, 1),
    22  		taskResultChan: make(chan *executionTask, 1),
    23  		logger:         logger,
    24  	}
    25  }
    26  
    27  func (pc *prerunContext) checkIndex(height int64) {
    28  	var index int64
    29  	if pc.prerunTask != nil {
    30  		index = pc.prerunTask.index
    31  	}
    32  	pc.logger.Info("Not apply delta", "height", height, "prerunIndex", index)
    33  
    34  }
    35  
    36  func (pc *prerunContext) flushPrerunResult() {
    37  	for {
    38  		select {
    39  		case task := <-pc.taskResultChan:
    40  			task.dump("Flush prerun result")
    41  		default:
    42  			return
    43  		}
    44  	}
    45  }
    46  
    47  func (pc *prerunContext) prerunRoutine() {
    48  	pc.prerunTx = true
    49  	for task := range pc.taskChan {
    50  		task.run()
    51  	}
    52  }
    53  
    54  func (pc *prerunContext) dequeueResult() (*ABCIResponses, time.Duration, error) {
    55  	expected := pc.prerunTask
    56  	for context := range pc.taskResultChan {
    57  
    58  		context.dump("Got prerun result")
    59  
    60  		if context.stopped {
    61  			continue
    62  		}
    63  
    64  		if context.height != expected.block.Height {
    65  			continue
    66  		}
    67  
    68  		if context.index != expected.index {
    69  			continue
    70  		}
    71  
    72  		if bytes.Equal(context.block.AppHash, expected.block.AppHash) {
    73  			return context.result.res, context.result.duration, context.result.err
    74  		} else {
    75  			// todo
    76  			panic("wrong app hash")
    77  		}
    78  	}
    79  	return nil, 0, nil
    80  }
    81  
    82  func (pc *prerunContext) stopPrerun(height int64) (index int64) {
    83  	task := pc.prerunTask
    84  	// stop the existing prerun if any
    85  	if task != nil {
    86  		if height > 0 && height != task.block.Height {
    87  			task.dump(fmt.Sprintf(
    88  				"Prerun sanity check failed. block.Height=%d, context.block.Height=%d",
    89  				height,
    90  				task.block.Height))
    91  
    92  			// todo
    93  			panic("Prerun sanity check failed")
    94  		}
    95  		task.dump("Stopping prerun")
    96  		task.stop()
    97  
    98  		index = task.index
    99  	}
   100  	pc.flushPrerunResult()
   101  	pc.prerunTask = nil
   102  	return index
   103  }
   104  
   105  func (pc *prerunContext) notifyPrerun(blockExec *BlockExecutor, block *types.Block) {
   106  
   107  	stoppedIndex := pc.stopPrerun(block.Height)
   108  	stoppedIndex++
   109  
   110  	pc.prerunTask = newExecutionTask(blockExec, block, stoppedIndex)
   111  
   112  	pc.prerunTask.dump("Notify prerun")
   113  
   114  	// start a new one
   115  	pc.taskChan <- pc.prerunTask
   116  }
   117  
   118  func (pc *prerunContext) getPrerunResult(block *types.Block) (res *ABCIResponses, duration time.Duration, err error) {
   119  	pc.checkIndex(block.Height)
   120  
   121  	// blockExec.prerunContext == nil means:
   122  	// 1. prerunTx disabled
   123  	// 2. we are in fasy-sync: the block comes from BlockPool.AddBlock not State.addProposalBlockPart and no prerun result expected
   124  	if pc.prerunTask != nil {
   125  		prerunHash := pc.prerunTask.block.Hash()
   126  		res, duration, err = pc.dequeueResult()
   127  		pc.prerunTask = nil
   128  
   129  		//compare block hash equal prerun block hash
   130  		if !bytes.Equal(prerunHash, block.Hash()) {
   131  			res = nil
   132  			pc.logger.Error("unequal block hash between prerun and block",
   133  				"prerun hash", prerunHash,
   134  				"block hash", block.Hash())
   135  		}
   136  
   137  	}
   138  	return
   139  }