github.com/aergoio/aergo@v1.3.1/chain/chainverifier.go (about) 1 package chain 2 3 import ( 4 "fmt" 5 "github.com/aergoio/aergo-actor/actor" 6 "github.com/aergoio/aergo/message" 7 "github.com/aergoio/aergo/pkg/component" 8 "github.com/aergoio/aergo/types" 9 "reflect" 10 "time" 11 ) 12 13 type ChainVerifier struct { 14 *SubComponent 15 cs *ChainService 16 IChainHandler //to use chain APIs 17 *Core 18 reader *BlockReader 19 err error 20 } 21 22 func newChainVerifier(cs *ChainService, core *Core) *ChainVerifier { 23 chainVerifier := &ChainVerifier{IChainHandler: cs, Core: core, cs: cs} 24 chainVerifier.SubComponent = NewSubComponent(chainVerifier, cs.BaseComponent, chainVerifierName, 1) 25 26 var ( 27 bestBlock *types.Block 28 err error 29 ) 30 31 if bestBlock, err = core.cdb.GetBestBlock(); err != nil { 32 logger.Fatal().Msg("can't get best block in newChainVerifier()") 33 } 34 35 chainVerifier.reader = &BlockReader{cdb: core.cdb, curNo: 0, bestNo: bestBlock.BlockNo()} 36 37 return chainVerifier 38 } 39 40 func (cv *ChainVerifier) Receive(context actor.Context) { 41 defer RecoverExit() 42 43 switch msg := context.Message().(type) { 44 case *message.VerifyStart: 45 46 case *actor.Started: 47 logger.Info().Msg("verify chain service start") 48 49 for !cv.cs.isRecovered() { 50 logger.Debug().Msg("recovery of chain doesn't finished") 51 time.Sleep(time.Second * 5) 52 } 53 54 if err := cv.VerifyChain(); err != nil { 55 logger.Error().Err(err).Msg("failed to verify chain") 56 cv.err = err 57 } 58 59 logger.Info().Msg("verify chain finished") 60 61 case *actor.Stopping, *actor.Stopped, *component.CompStatReq: // donothing 62 default: 63 debug := fmt.Sprintf("[%s] Missed message. (%v) %s", cv.name, reflect.TypeOf(msg), msg) 64 logger.Debug().Msg(debug) 65 } 66 } 67 68 type BlockReader struct { 69 cdb *ChainDB 70 71 genesisBlock *types.Block 72 curNo uint64 73 bestNo uint64 74 } 75 76 func (br *BlockReader) getNext() (*types.Block, error) { 77 if br.genesisBlock == nil { 78 br.curNo = 0 79 } else { 80 if br.curNo+1 > br.bestNo { 81 return nil, nil 82 } 83 br.curNo++ 84 } 85 86 block, err := br.cdb.GetBlockByNo(br.curNo) 87 if err != nil { 88 logger.Error().Err(err).Uint64("no", br.curNo).Msg("failed to get next block") 89 return nil, err 90 } 91 92 if br.curNo == 0 { 93 br.genesisBlock = block 94 } 95 96 return block, nil 97 } 98 99 func (cv *ChainVerifier) VerifyChain() error { 100 var ( 101 err error 102 block *types.Block 103 ) 104 105 logger.Info().Msg("start verifychan") 106 107 // get genesis block 108 if block, err = cv.reader.getNext(); err != nil || block == nil { 109 logger.Error().Err(err).Msg("failed to get genesis block") 110 return err 111 } 112 113 if err = cv.Core.sdb.SetRoot(block.GetHeader().GetBlocksRootHash()); err != nil { 114 logger.Error().Err(err).Msg("failed to set root of sdb to root hash of genesis block") 115 return err 116 } 117 118 for { 119 if block, err = cv.reader.getNext(); err != nil || block == nil { 120 return err 121 } 122 123 if err := cv.verifyBlock(block); err != nil { 124 logger.Error().Err(err).Uint64("no", block.BlockNo()).Str("block", block.ID()).Msg("failed to verify block") 125 return err 126 } 127 } 128 } 129 130 func (cv *ChainVerifier) IsRunning() bool { 131 return cv.reader.bestNo > cv.reader.curNo 132 } 133 134 func (cv *ChainVerifier) Statistics() *map[string]interface{} { 135 var ( 136 state string 137 errStr string 138 ) 139 140 if cv.err != nil { 141 errStr = cv.err.Error() 142 } 143 144 if cv.IsRunning() { 145 state = "running" 146 } else { 147 state = "finished" 148 } 149 150 return &map[string]interface{}{ 151 "verify": state, 152 "verifyBestNo": cv.reader.bestNo, 153 "verifyCurNo": cv.reader.curNo, 154 "verifyErr": errStr, 155 } 156 }