-
Notifications
You must be signed in to change notification settings - Fork 319
/
blockindexer.go
118 lines (110 loc) · 3.26 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
// Copyright (c) 2019 IoTeX Foundation
// This is an alpha (internal) release and is not suitable for production. 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
}
// 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
}
for i := tipHeight + 1; 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
}