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