-
Notifications
You must be signed in to change notification settings - Fork 670
/
height_indexed_vm.go
138 lines (114 loc) · 3.62 KB
/
height_indexed_vm.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
// Copyright (C) 2019-2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package proposervm
import (
"fmt"
"go.uber.org/zap"
"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/snow/engine/snowman/block"
)
// shouldHeightIndexBeRepaired checks if index needs repairing and stores a
// checkpoint if repairing is needed.
//
// vm.ctx.Lock should be held
func (vm *VM) shouldHeightIndexBeRepaired() (bool, error) {
_, err := vm.State.GetCheckpoint()
if err != database.ErrNotFound {
return true, err
}
// no checkpoint. Either index is complete or repair was never attempted.
// index is complete iff lastAcceptedBlock is indexed
latestProBlkID, err := vm.State.GetLastAccepted()
if err == database.ErrNotFound {
return false, nil
}
if err != nil {
return false, err
}
lastAcceptedBlk, err := vm.getPostForkBlock(latestProBlkID)
if err != nil {
// Could not retrieve last accepted block.
return false, err
}
_, err = vm.State.GetBlockIDAtHeight(lastAcceptedBlk.Height())
if err != database.ErrNotFound {
return false, err
}
// Index needs repairing. Mark the checkpoint so that, in case new blocks
// are accepted after the lock is released here but before indexing has
// started, we do not miss rebuilding the full index.
return true, vm.State.SetCheckpoint(latestProBlkID)
}
// vm.ctx.Lock should be held
func (vm *VM) VerifyHeightIndex() error {
if vm.hVM == nil {
return block.ErrHeightIndexedVMNotImplemented
}
if !vm.hIndexer.IsRepaired() {
return block.ErrIndexIncomplete
}
return nil
}
// vm.ctx.Lock should be held
func (vm *VM) GetBlockIDAtHeight(height uint64) (ids.ID, error) {
if !vm.hIndexer.IsRepaired() {
return ids.Empty, block.ErrIndexIncomplete
}
// The indexer will only report that the index has been repaired if the
// underlying VM supports indexing.
switch forkHeight, err := vm.State.GetForkHeight(); err {
case nil:
if height < forkHeight {
return vm.hVM.GetBlockIDAtHeight(height)
}
return vm.State.GetBlockIDAtHeight(height)
case database.ErrNotFound:
// fork not reached yet. Block must be pre-fork
return vm.hVM.GetBlockIDAtHeight(height)
default:
return ids.Empty, err
}
}
// As postFork blocks/options are accepted, height index is updated even if its
// repairing is ongoing. vm.ctx.Lock should be held
func (vm *VM) updateHeightIndex(height uint64, blkID ids.ID) error {
if vm.resetHeightIndexOngoing.GetValue() {
return nil
}
_, err := vm.State.GetCheckpoint()
switch err {
case nil:
// Index rebuilding is ongoing. We can update the index with the current
// block.
case database.ErrNotFound:
// No checkpoint means indexing has either not started or is already
// done.
if !vm.hIndexer.IsRepaired() {
return nil
}
// Indexing must have finished. We can update the index with the current
// block.
default:
return fmt.Errorf("failed to load index checkpoint: %w", err)
}
return vm.storeHeightEntry(height, blkID)
}
func (vm *VM) storeHeightEntry(height uint64, blkID ids.ID) error {
switch _, err := vm.State.GetForkHeight(); err {
case nil:
// The fork was already reached. Just update the index.
case database.ErrNotFound:
// This is the first post fork block, store the fork height.
if err := vm.State.SetForkHeight(height); err != nil {
return fmt.Errorf("failed storing fork height: %w", err)
}
default:
return fmt.Errorf("failed to load fork height: %w", err)
}
vm.ctx.Log.Debug("indexed block",
zap.Stringer("blkID", blkID),
zap.Uint64("height", height),
)
return vm.State.SetBlockIDAtHeight(height, blkID)
}