-
Notifications
You must be signed in to change notification settings - Fork 671
/
state_syncable_vm.go
161 lines (136 loc) · 4.44 KB
/
state_syncable_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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright (C) 2019-2022, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package proposervm
import (
"context"
"fmt"
"go.uber.org/zap"
"github.com/ava-labs/avalanchego/database"
"github.com/ava-labs/avalanchego/snow/engine/snowman/block"
"github.com/ava-labs/avalanchego/vms/proposervm/summary"
)
func (vm *VM) StateSyncEnabled(ctx context.Context) (bool, error) {
if vm.ssVM == nil {
return false, nil
}
// if vm implements Snowman++, a block height index must be available
// to support state sync
if vm.VerifyHeightIndex(ctx) != nil {
return false, nil
}
return vm.ssVM.StateSyncEnabled(ctx)
}
func (vm *VM) GetOngoingSyncStateSummary(ctx context.Context) (block.StateSummary, error) {
if vm.ssVM == nil {
return nil, block.ErrStateSyncableVMNotImplemented
}
innerSummary, err := vm.ssVM.GetOngoingSyncStateSummary(ctx)
if err != nil {
return nil, err // includes database.ErrNotFound case
}
return vm.buildStateSummary(ctx, innerSummary)
}
func (vm *VM) GetLastStateSummary(ctx context.Context) (block.StateSummary, error) {
if vm.ssVM == nil {
return nil, block.ErrStateSyncableVMNotImplemented
}
// Extract inner vm's last state summary
innerSummary, err := vm.ssVM.GetLastStateSummary(ctx)
if err != nil {
return nil, err // including database.ErrNotFound case
}
return vm.buildStateSummary(ctx, innerSummary)
}
// Note: it's important that ParseStateSummary do not use any index or state
// to allow summaries being parsed also by freshly started node with no previous state.
func (vm *VM) ParseStateSummary(ctx context.Context, summaryBytes []byte) (block.StateSummary, error) {
if vm.ssVM == nil {
return nil, block.ErrStateSyncableVMNotImplemented
}
statelessSummary, err := summary.Parse(summaryBytes)
if err != nil {
// it may be a preFork summary
return vm.ssVM.ParseStateSummary(ctx, summaryBytes)
}
innerSummary, err := vm.ssVM.ParseStateSummary(ctx, statelessSummary.InnerSummaryBytes())
if err != nil {
return nil, fmt.Errorf("could not parse inner summary due to: %w", err)
}
block, err := vm.parsePostForkBlock(ctx, statelessSummary.BlockBytes())
if err != nil {
return nil, fmt.Errorf("could not parse proposervm block bytes from summary due to: %w", err)
}
return &stateSummary{
StateSummary: statelessSummary,
innerSummary: innerSummary,
block: block,
vm: vm,
}, nil
}
func (vm *VM) GetStateSummary(ctx context.Context, height uint64) (block.StateSummary, error) {
if vm.ssVM == nil {
return nil, block.ErrStateSyncableVMNotImplemented
}
innerSummary, err := vm.ssVM.GetStateSummary(ctx, height)
if err != nil {
return nil, err // including database.ErrNotFound case
}
return vm.buildStateSummary(ctx, innerSummary)
}
// Note: building state summary requires a well formed height index.
func (vm *VM) buildStateSummary(ctx context.Context, innerSummary block.StateSummary) (block.StateSummary, error) {
// if vm implements Snowman++, a block height index must be available
// to support state sync
if err := vm.VerifyHeightIndex(ctx); err != nil {
return nil, fmt.Errorf("could not build state summary: %w", err)
}
forkHeight, err := vm.GetForkHeight()
switch err {
case nil:
if innerSummary.Height() < forkHeight {
return innerSummary, nil
}
case database.ErrNotFound:
// fork has not been reached since there is not fork height
// just return innerSummary
vm.ctx.Log.Debug("built pre-fork summary",
zap.Stringer("summaryID", innerSummary.ID()),
zap.Uint64("summaryHeight", innerSummary.Height()),
)
return innerSummary, nil
default:
return nil, err
}
height := innerSummary.Height()
blkID, err := vm.GetBlockIDAtHeight(ctx, height)
if err != nil {
vm.ctx.Log.Debug("failed to fetch proposervm block ID",
zap.Uint64("height", height),
zap.Error(err),
)
return nil, err
}
block, err := vm.getPostForkBlock(ctx, blkID)
if err != nil {
vm.ctx.Log.Warn("failed to fetch proposervm block",
zap.Stringer("blkID", blkID),
zap.Uint64("height", height),
zap.Error(err),
)
return nil, err
}
statelessSummary, err := summary.Build(forkHeight, block.Bytes(), innerSummary.Bytes())
if err != nil {
return nil, err
}
vm.ctx.Log.Debug("built post-fork summary",
zap.Stringer("summaryID", statelessSummary.ID()),
zap.Uint64("summaryHeight", forkHeight),
)
return &stateSummary{
StateSummary: statelessSummary,
innerSummary: innerSummary,
block: block,
vm: vm,
}, nil
}