-
Notifications
You must be signed in to change notification settings - Fork 166
/
finalize_test.go
316 lines (248 loc) · 9.87 KB
/
finalize_test.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
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
package cmd
import (
"encoding/hex"
"os"
"regexp"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
utils "github.com/onflow/flow-go/cmd/bootstrap/utils"
model "github.com/onflow/flow-go/model/bootstrap"
"github.com/onflow/flow-go/utils/unittest"
)
const finalizeHappyPathLogs = "^deterministic bootstrapping random seed" +
"collecting partner network and staking keys" +
`read \d+ partner node configuration files` +
`read \d+ stakes for partner nodes` +
"generating internal private networking and staking keys" +
`read \d+ internal private node-info files` +
`read internal node configurations` +
`read \d+ stakes for internal nodes` +
`checking constraints on consensus/cluster nodes` +
`assembling network and staking keys` +
`reading root block data` +
`reading root block votes` +
`read vote .*` +
`reading dkg data` +
`constructing root QC` +
`computing collection node clusters` +
`constructing root blocks for collection node clusters` +
`constructing root QCs for collection node clusters` +
`constructing root execution result and block seal` +
`constructing root protocol snapshot` +
`wrote file \S+/root-protocol-state-snapshot.json` +
`saved result and seal are matching` +
`saved root snapshot is valid` +
`attempting to copy private key files` +
`skipping copy of private keys to output dir` +
`created keys for \d+ consensus nodes` +
`created keys for \d+ collection nodes` +
`created keys for \d+ verification nodes` +
`created keys for \d+ execution nodes` +
`created keys for \d+ access nodes` +
"🌊 🏄 🤙 Done – ready to flow!"
var finalizeHappyPathRegex = regexp.MustCompile(finalizeHappyPathLogs)
func TestFinalize_HappyPath(t *testing.T) {
deterministicSeed := GenerateRandomSeed()
rootCommit := unittest.StateCommitmentFixture()
rootParent := unittest.StateCommitmentFixture()
chainName := "main"
rootHeight := uint64(12332)
epochCounter := uint64(2)
utils.RunWithSporkBootstrapDir(t, func(bootDir, partnerDir, partnerStakes, internalPrivDir, configPath string) {
flagOutdir = bootDir
flagConfig = configPath
flagPartnerNodeInfoDir = partnerDir
flagPartnerStakes = partnerStakes
flagInternalNodePrivInfoDir = internalPrivDir
flagFastKG = true
flagRootChain = chainName
flagRootParent = hex.EncodeToString(rootParent[:])
flagRootHeight = rootHeight
// set deterministic bootstrapping seed
flagBootstrapRandomSeed = deterministicSeed
// rootBlock will generate DKG and place it into bootDir/public-root-information
rootBlock(nil, nil)
flagRootCommit = hex.EncodeToString(rootCommit[:])
flagEpochCounter = epochCounter
flagRootBlock = filepath.Join(bootDir, model.PathRootBlockData)
flagDKGDataPath = filepath.Join(bootDir, model.PathRootDKGData)
flagRootBlockVotesDir = filepath.Join(bootDir, model.DirnameRootBlockVotes)
hook := zeroLoggerHook{logs: &strings.Builder{}}
log = log.Hook(hook)
finalize(nil, nil)
assert.Regexp(t, finalizeHappyPathRegex, hook.logs.String())
hook.logs.Reset()
// check if root protocol snapshot exists
snapshotPath := filepath.Join(bootDir, model.PathRootProtocolStateSnapshot)
assert.FileExists(t, snapshotPath)
})
}
func TestFinalize_Deterministic(t *testing.T) {
deterministicSeed := GenerateRandomSeed()
rootCommit := unittest.StateCommitmentFixture()
rootParent := unittest.StateCommitmentFixture()
chainName := "main"
rootHeight := uint64(1000)
epochCounter := uint64(0)
utils.RunWithSporkBootstrapDir(t, func(bootDir, partnerDir, partnerStakes, internalPrivDir, configPath string) {
flagOutdir = bootDir
flagConfig = configPath
flagPartnerNodeInfoDir = partnerDir
flagPartnerStakes = partnerStakes
flagInternalNodePrivInfoDir = internalPrivDir
flagFastKG = true
flagRootCommit = hex.EncodeToString(rootCommit[:])
flagRootParent = hex.EncodeToString(rootParent[:])
flagRootChain = chainName
flagRootHeight = rootHeight
flagEpochCounter = epochCounter
// set deterministic bootstrapping seed
flagBootstrapRandomSeed = deterministicSeed
// rootBlock will generate DKG and place it into model.PathRootDKGData
rootBlock(nil, nil)
flagRootBlock = filepath.Join(bootDir, model.PathRootBlockData)
flagDKGDataPath = filepath.Join(bootDir, model.PathRootDKGData)
flagRootBlockVotesDir = filepath.Join(bootDir, model.DirnameRootBlockVotes)
hook := zeroLoggerHook{logs: &strings.Builder{}}
log = log.Hook(hook)
finalize(nil, nil)
require.Regexp(t, finalizeHappyPathRegex, hook.logs.String())
hook.logs.Reset()
// check if root protocol snapshot exists
snapshotPath := filepath.Join(bootDir, model.PathRootProtocolStateSnapshot)
assert.FileExists(t, snapshotPath)
// read snapshot
_, err := utils.ReadRootProtocolSnapshot(bootDir)
require.NoError(t, err)
// delete snapshot file
err = os.Remove(snapshotPath)
require.NoError(t, err)
finalize(nil, nil)
require.Regexp(t, finalizeHappyPathRegex, hook.logs.String())
hook.logs.Reset()
// check if root protocol snapshot exists
assert.FileExists(t, snapshotPath)
// read snapshot
_, err = utils.ReadRootProtocolSnapshot(bootDir)
require.NoError(t, err)
// ATTENTION: we can't use next statement because QC generation is not deterministic
// assert.Equal(t, firstSnapshot, secondSnapshot)
// Meaning we don't have a guarantee that with same input arguments we will get same QC.
// This doesn't mean that QC is invalid, but it will result in different structures,
// different QC => different service events => different result => different seal
// We need to use a different mechanism for comparing.
// ToDo: Revisit if this test case is valid at all.
})
}
func TestFinalize_SameSeedDifferentStateCommits(t *testing.T) {
deterministicSeed := GenerateRandomSeed()
rootCommit := unittest.StateCommitmentFixture()
rootParent := unittest.StateCommitmentFixture()
chainName := "main"
rootHeight := uint64(1000)
epochCounter := uint64(0)
utils.RunWithSporkBootstrapDir(t, func(bootDir, partnerDir, partnerStakes, internalPrivDir, configPath string) {
flagOutdir = bootDir
flagConfig = configPath
flagPartnerNodeInfoDir = partnerDir
flagPartnerStakes = partnerStakes
flagInternalNodePrivInfoDir = internalPrivDir
flagFastKG = true
flagRootCommit = hex.EncodeToString(rootCommit[:])
flagRootParent = hex.EncodeToString(rootParent[:])
flagRootChain = chainName
flagRootHeight = rootHeight
flagEpochCounter = epochCounter
// set deterministic bootstrapping seed
flagBootstrapRandomSeed = deterministicSeed
// rootBlock will generate DKG and place it into bootDir/public-root-information
rootBlock(nil, nil)
flagRootBlock = filepath.Join(bootDir, model.PathRootBlockData)
flagDKGDataPath = filepath.Join(bootDir, model.PathRootDKGData)
flagRootBlockVotesDir = filepath.Join(bootDir, model.DirnameRootBlockVotes)
hook := zeroLoggerHook{logs: &strings.Builder{}}
log = log.Hook(hook)
finalize(nil, nil)
require.Regexp(t, finalizeHappyPathRegex, hook.logs.String())
hook.logs.Reset()
// check if root protocol snapshot exists
snapshotPath := filepath.Join(bootDir, model.PathRootProtocolStateSnapshot)
assert.FileExists(t, snapshotPath)
// read snapshot
snapshot1, err := utils.ReadRootProtocolSnapshot(bootDir)
require.NoError(t, err)
// delete snapshot file
err = os.Remove(snapshotPath)
require.NoError(t, err)
// change input state commitments
rootCommit2 := unittest.StateCommitmentFixture()
rootParent2 := unittest.StateCommitmentFixture()
flagRootCommit = hex.EncodeToString(rootCommit2[:])
flagRootParent = hex.EncodeToString(rootParent2[:])
finalize(nil, nil)
require.Regexp(t, finalizeHappyPathRegex, hook.logs.String())
hook.logs.Reset()
// check if root protocol snapshot exists
assert.FileExists(t, snapshotPath)
// read snapshot
snapshot2, err := utils.ReadRootProtocolSnapshot(bootDir)
require.NoError(t, err)
// current epochs
currentEpoch1 := snapshot1.Epochs().Current()
currentEpoch2 := snapshot2.Epochs().Current()
// check dkg
dkg1, err := currentEpoch1.DKG()
require.NoError(t, err)
dkg2, err := currentEpoch2.DKG()
require.NoError(t, err)
assert.Equal(t, dkg1, dkg2)
// check clustering
clustering1, err := currentEpoch1.Clustering()
require.NoError(t, err)
clustering2, err := currentEpoch2.Clustering()
require.NoError(t, err)
assert.Equal(t, clustering1, clustering2)
// verify random sources are same
randomSource1, err := currentEpoch1.RandomSource()
require.NoError(t, err)
randomSource2, err := currentEpoch2.RandomSource()
require.NoError(t, err)
assert.Equal(t, randomSource1, randomSource2)
assert.Equal(t, randomSource1, getRandomSource(deterministicSeed))
})
}
func TestFinalize_InvalidRandomSeedLength(t *testing.T) {
rootCommit := unittest.StateCommitmentFixture()
rootParent := unittest.StateCommitmentFixture()
chainName := "main"
rootHeight := uint64(12332)
epochCounter := uint64(2)
// set random seed with smaller length
deterministicSeed, err := hex.DecodeString("a12354a343234aa44bbb43")
require.NoError(t, err)
// invalid length execution logs
expectedLogs := regexp.MustCompile("random seed provided length is not valid")
utils.RunWithSporkBootstrapDir(t, func(bootDir, partnerDir, partnerStakes, internalPrivDir, configPath string) {
flagOutdir = bootDir
flagConfig = configPath
flagPartnerNodeInfoDir = partnerDir
flagPartnerStakes = partnerStakes
flagInternalNodePrivInfoDir = internalPrivDir
flagFastKG = true
flagRootCommit = hex.EncodeToString(rootCommit[:])
flagRootParent = hex.EncodeToString(rootParent[:])
flagRootChain = chainName
flagRootHeight = rootHeight
flagEpochCounter = epochCounter
// set deterministic bootstrapping seed
flagBootstrapRandomSeed = deterministicSeed
hook := zeroLoggerHook{logs: &strings.Builder{}}
log = log.Hook(hook)
finalize(nil, nil)
assert.Regexp(t, expectedLogs, hook.logs.String())
hook.logs.Reset()
})
}