/
check.go
250 lines (201 loc) · 8.06 KB
/
check.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
package chain
import (
"fmt"
"github.com/koinotice/vite/chain/state"
"github.com/koinotice/vite/chain/utils"
"github.com/koinotice/vite/common/db/xleveldb/errors"
"github.com/koinotice/vite/common/db/xleveldb/util"
"github.com/koinotice/vite/common/types"
"github.com/koinotice/vite/ledger"
)
func printSnapshotLog(snapshotLog chain_state.SnapshotLog) string {
str := ""
for addr, logItems := range snapshotLog {
str += fmt.Sprintf("%s: %d, ", addr, len(logItems))
}
return str
}
func (c *chain) CheckRedo() error {
redoStore := c.stateDB.RedoStore()
iter := redoStore.NewIterator(nil)
redo := c.stateDB.StorageRedo()
var prevHeight uint64
for iter.Next() {
key := iter.Key()
snapshotHeight := chain_utils.BytesToUint64(key[1:])
if prevHeight > 0 && prevHeight+1 != snapshotHeight {
return errors.New(fmt.Sprintf("prevHeight + 1 != snapshotHeight, prev height is %d, snapshot height is %d", prevHeight, snapshotHeight))
}
prevHeight = snapshotHeight
chunks, err := c.GetSubLedger(snapshotHeight-1, snapshotHeight)
if err != nil {
return errors.New(fmt.Sprintf("c.GetSubLedger failed, start snapshot height is %d, end snapshot height is %d", snapshotHeight-1, snapshotHeight))
}
snapshotLog, ok, err := redo.QueryLog(snapshotHeight)
if err != nil {
return errors.New(fmt.Sprintf("redo.QueryLog failed, snapshot height is %d", snapshotHeight))
}
if !ok {
return errors.New(fmt.Sprintf("ok is false, snapshot height is %d", snapshotHeight))
}
blockCount := 0
for _, chunk := range chunks {
blockCount += len(chunk.AccountBlocks)
for _, accountBlock := range chunk.AccountBlocks {
if logs, ok := snapshotLog[accountBlock.AccountAddress]; !ok || len(logs) <= 0 {
return errors.New(fmt.Sprintf("!ok || len(logs) <= 0. snapshot log is %s. accountBlock is %+v, snapshot height is %d",
printSnapshotLog(snapshotLog), accountBlock, snapshotHeight))
}
}
}
logLength := 0
for _, logItems := range snapshotLog {
logLength += len(logItems)
}
if blockCount != logLength {
return errors.New(fmt.Sprintf("blockCount != logLength, blockCount is %d, logLength is %d, snapshot log is %s", blockCount, logLength, printSnapshotLog(snapshotLog)))
}
c.log.Info(fmt.Sprintf("snapshot height: %d. %d logs, %d blocks", snapshotHeight, logLength, blockCount), "method", "checkRedo")
}
err := iter.Error()
iter.Release()
return err
}
func (c *chain) CheckRecentBlocks() error {
latestSb := c.GetLatestSnapshotBlock()
c.log.Info(fmt.Sprintf("latest snapshot block is %d, %s", latestSb.Height, latestSb.Hash), "method", "checkRecentBlocks")
sbList, err := c.GetSnapshotBlocks(latestSb.Hash, false, 100)
if err != nil {
cErr := errors.New(fmt.Sprintf("c.GetSnapshotBlocks failed. Error: %s", err))
return cErr
}
var prevSb *ledger.SnapshotBlock
accountLatestBlockMap := make(map[types.Address]*ledger.AccountBlock)
for _, sb := range sbList {
if prevSb != nil && (prevSb.PrevHash != sb.Hash || prevSb.Height != sb.Height+1) {
return errors.New(fmt.Sprintf("prevSb is %+v, sb is %+v", prevSb, sb))
}
prevSb = sb
c.log.Info(fmt.Sprintf("check snapshot block %d, %s", sb.Height, sb.Hash), "method", "checkRecentBlocks")
for addr, hashHeight := range sb.SnapshotContent {
block, err := c.GetAccountBlockByHash(hashHeight.Hash)
if err != nil {
return errors.New(fmt.Sprintf("c.GetAccountBlockByHash failed, addr is %s, hash is %s. Error: %s", addr, hashHeight.Hash, err))
}
for {
if block == nil {
return errors.New(fmt.Sprintf("c.GetAccountBlockByHash(), block is nil, addr is %s, hash is %s", addr, hashHeight.Hash))
}
c.log.Info(fmt.Sprintf("check account block %s %d %s %s", block.AccountAddress, block.Height, block.Hash, block.FromBlockHash))
cacheLatestBlock, ok := accountLatestBlockMap[addr]
if !ok {
latestBlock, err := c.GetLatestAccountBlock(addr)
if err != nil {
return errors.New(fmt.Sprintf("c.GetLatestAccountBlock failed, addr is %s. Error: %s", addr, err))
}
if latestBlock == nil {
return errors.New(fmt.Sprintf("c.GetAccountBlockByHash(), latest account block is nil, addr is %s", addr))
}
if latestBlock.Hash != block.Hash {
return errors.New(fmt.Sprintf("latest account block is %+v, block is %+v", latestBlock, block))
}
} else if cacheLatestBlock.Height <= block.Height {
return errors.New(fmt.Sprintf("cacheLatestBlock.Height <= block.Height, cacheLatestBlock is %+v, block is %+v", cacheLatestBlock, block))
}
// set latest
accountLatestBlockMap[addr] = block
// get prev block
if block.Height <= 1 {
break
}
confirmedSb, err := c.GetConfirmSnapshotBlockByAbHash(block.PrevHash)
if err != nil {
return errors.New(fmt.Sprintf("GetConfirmSnapshotBlockByAbHash failed, addr is %s, prevHash is %s. Error: %s", addr, block.PrevHash, err))
}
if confirmedSb == nil {
return errors.New(fmt.Sprintf("confirmd sb is nil, account block hash is %s", block.PrevHash))
}
if confirmedSb.Hash != sb.Hash {
break
}
prevBlock, err := c.GetAccountBlockByHash(block.PrevHash)
if err != nil {
return errors.New(fmt.Sprintf("get prev account block failed, addr is %s, prevHash is %s. Error: %s", addr, block.PrevHash, err))
}
if prevBlock == nil {
return errors.New(fmt.Sprintf("get prev account block is nil, addr is %s, prevHash is %s. Error: %s", addr, block.PrevHash, err))
}
block = prevBlock
}
}
}
return nil
}
func (c *chain) CheckOnRoad() error {
indexStore := c.indexDB.Store()
iter := indexStore.NewIterator(util.BytesPrefix([]byte{chain_utils.OnRoadKeyPrefix}))
onRoadCount := 0
for iter.Next() {
onRoadCount++
key := iter.Key()
toAddrBytes := key[1 : 1+types.AddressSize]
sendBlockHashBytes := key[1+types.AddressSize:]
toAddr, err := types.BytesToAddress(toAddrBytes)
if err != nil {
return errors.New(fmt.Sprintf("types.BytesToAddress failed, toAddrBytes is %d", toAddrBytes))
}
sendBlockHash, err := types.BytesToHash(sendBlockHashBytes)
if err != nil {
return errors.New(fmt.Sprintf("types.HexToHash failed, sendBlockHashBytes is %d", sendBlockHashBytes))
}
existed, err := c.IsAccountBlockExisted(sendBlockHash)
if err != nil {
return errors.New(fmt.Sprintf("c.IsAccountBlockExisted failed, sendBlockHash is %s, toAddr is %s", sendBlockHash, toAddr))
}
if !existed {
return errors.New(fmt.Sprintf("send block is not exsited, sendBlockHash is %s, toAddr is %s", sendBlockHash, toAddr))
}
received, err := c.IsReceived(sendBlockHash)
if err != nil {
return errors.New(fmt.Sprintf("c.IsReceived failed, sendBlockHash is %s", sendBlockHash))
}
if received {
return errors.New(fmt.Sprintf("is received, sendBlockHash is %s", sendBlockHash))
}
c.log.Info(fmt.Sprintf("check on road, to addr is %s, send block hash is %s", toAddr, sendBlockHash), "method", "checkOnRoad")
}
c.log.Info(fmt.Sprintf("total onroad: %d", onRoadCount), "method", "checkOnRoad")
err := iter.Error()
iter.Release()
return err
}
func (c *chain) CheckHash() error {
store := c.indexDB.Store()
iter := store.NewIterator(util.BytesPrefix([]byte{chain_utils.AccountBlockHashKeyPrefix}))
defer iter.Release()
for iter.Next() {
key := iter.Key()
hash, err := types.BytesToHash(key[1:])
if err != nil {
return errors.New(fmt.Sprintf("BytesToHash failed, key is %d. Error: %s", key, err))
}
block, err := c.GetAccountBlockByHash(hash)
if err != nil {
return errors.New(fmt.Sprintf("c.GetAccountBlockByHash failed, hash is %s. Error: %s", hash, err))
}
if block == nil {
return errors.New(fmt.Sprintf("block is nil, hash is %s.", hash))
}
if !(block.IsSendBlock() && block.Height == 0 && block.PrevHash.IsZero()) {
if block.Hash != block.ComputeHash() {
c.log.Error(fmt.Sprintf("error. block.Hash != block.ComputeHash(), block is %+v, computedHash is %s", block, block.ComputeHash()), "method", "CheckHash")
continue
}
}
c.log.Info(fmt.Sprintf("check account block, blockHash: %s", block.Hash), "method", "CheckHash")
}
if err := iter.Error(); err != nil {
return err
}
return nil
}