github.com/iotexproject/iotex-core@v1.14.1-rc1/blockchain/blockdao/blockindexer.go (about) 1 // Copyright (c) 2019 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package blockdao 7 8 import ( 9 "context" 10 "time" 11 12 "github.com/pkg/errors" 13 "go.uber.org/zap" 14 15 "github.com/iotexproject/iotex-core/action/protocol" 16 "github.com/iotexproject/iotex-core/blockchain/block" 17 "github.com/iotexproject/iotex-core/blockchain/genesis" 18 "github.com/iotexproject/iotex-core/pkg/log" 19 ) 20 21 type ( 22 // BlockIndexer defines an interface to accept block to build index 23 BlockIndexer interface { 24 Start(ctx context.Context) error 25 Stop(ctx context.Context) error 26 Height() (uint64, error) 27 PutBlock(context.Context, *block.Block) error 28 DeleteTipBlock(context.Context, *block.Block) error 29 } 30 31 // BlockIndexerWithStart defines an interface to accept block to build index from a start height 32 BlockIndexerWithStart interface { 33 BlockIndexer 34 // StartHeight returns the start height of the indexer 35 StartHeight() uint64 36 } 37 38 // BlockIndexerChecker defines a checker of block indexer 39 BlockIndexerChecker struct { 40 dao BlockDAO 41 } 42 ) 43 44 // NewBlockIndexerChecker creates a new block indexer checker 45 func NewBlockIndexerChecker(dao BlockDAO) *BlockIndexerChecker { 46 return &BlockIndexerChecker{dao: dao} 47 } 48 49 // CheckIndexer checks a block indexer against block dao 50 func (bic *BlockIndexerChecker) CheckIndexer(ctx context.Context, indexer BlockIndexer, targetHeight uint64, progressReporter func(uint64)) error { 51 bcCtx, ok := protocol.GetBlockchainCtx(ctx) 52 if !ok { 53 return errors.New("failed to find blockchain ctx") 54 } 55 g, ok := genesis.ExtractGenesisContext(ctx) 56 if !ok { 57 return errors.New("failed to find genesis ctx") 58 } 59 tipHeight, err := indexer.Height() 60 if err != nil { 61 return err 62 } 63 daoTip, err := bic.dao.Height() 64 if err != nil { 65 return err 66 } 67 if tipHeight > daoTip { 68 return errors.New("indexer tip height cannot by higher than dao tip height") 69 } 70 tipBlk, err := bic.dao.GetBlockByHeight(tipHeight) 71 if err != nil { 72 return err 73 } 74 if targetHeight == 0 || targetHeight > daoTip { 75 targetHeight = daoTip 76 } 77 startHeight := tipHeight + 1 78 if indexerWS, ok := indexer.(BlockIndexerWithStart); ok { 79 indexStartHeight := indexerWS.StartHeight() 80 if indexStartHeight > startHeight { 81 startHeight = indexStartHeight 82 } 83 } 84 for i := startHeight; i <= targetHeight; i++ { 85 // ternimate if context is done 86 if err := ctx.Err(); err != nil { 87 return errors.Wrap(err, "terminate the indexer checking") 88 } 89 blk, err := bic.dao.GetBlockByHeight(i) 90 if err != nil { 91 return err 92 } 93 if blk.Receipts == nil { 94 blk.Receipts, err = bic.dao.GetReceipts(i) 95 if err != nil { 96 return err 97 } 98 } 99 producer := blk.PublicKey().Address() 100 if producer == nil { 101 return errors.New("failed to get address") 102 } 103 bcCtx.Tip.Height = tipBlk.Height() 104 if bcCtx.Tip.Height > 0 { 105 bcCtx.Tip.Hash = tipBlk.HashHeader() 106 bcCtx.Tip.Timestamp = tipBlk.Timestamp() 107 } else { 108 bcCtx.Tip.Hash = g.Hash() 109 bcCtx.Tip.Timestamp = time.Unix(g.Timestamp, 0) 110 } 111 for { 112 if err = indexer.PutBlock(protocol.WithBlockCtx( 113 protocol.WithBlockchainCtx(ctx, bcCtx), 114 protocol.BlockCtx{ 115 BlockHeight: i, 116 BlockTimeStamp: blk.Timestamp(), 117 Producer: producer, 118 GasLimit: g.BlockGasLimitByHeight(i), 119 }, 120 ), blk); err == nil { 121 break 122 } 123 if i < g.HawaiiBlockHeight && errors.Cause(err) == block.ErrDeltaStateMismatch { 124 log.L().Info("delta state mismatch", zap.Uint64("block", i)) 125 continue 126 } 127 return err 128 } 129 if progressReporter != nil { 130 progressReporter(i) 131 } 132 tipBlk = blk 133 } 134 return nil 135 }