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 }