7
7
"context"
8
8
"errors"
9
9
"fmt"
10
+ "sync/atomic"
10
11
"time"
11
12
12
13
"github.com/prometheus/client_golang/prometheus"
@@ -42,7 +43,10 @@ const (
42
43
// blocks.
43
44
DefaultNumHistoricalBlocks uint64 = 0
44
45
45
- innerBlkCacheSize = 64 * units .MiB
46
+ checkIndexedFrequency = 10 * time .Second
47
+ innerBlkCacheSize = 64 * units .MiB
48
+
49
+ pChainPostBootstrapSyncPollInterval = time .Millisecond * 100
46
50
)
47
51
48
52
var (
@@ -71,9 +75,10 @@ type VM struct {
71
75
scheduler.Scheduler
72
76
mockable.Clock
73
77
74
- ctx * snow.Context
75
- db * versiondb.Database
76
- toScheduler chan <- common.Message
78
+ ctx * snow.Context
79
+ db * versiondb.Database
80
+ toScheduler chan <- common.Message
81
+ schedulerDispatched atomic.Bool
77
82
78
83
// Block ID --> Block
79
84
// Each element is a block that passed verification but
@@ -161,13 +166,7 @@ func (vm *VM) Initialize(
161
166
}
162
167
vm .innerBlkCache = innerBlkCache
163
168
164
- scheduler , vmToEngine := scheduler .New (vm .ctx .Log , toEngine )
165
- vm .Scheduler = scheduler
166
- vm .toScheduler = vmToEngine
167
-
168
- go chainCtx .Log .RecoverAndPanic (func () {
169
- scheduler .Dispatch (time .Now ())
170
- })
169
+ defer vm .dispatchScheduler (toEngine )
171
170
172
171
vm .verifiedBlocks = make (map [ids.ID ]PostForkBlock )
173
172
detachedCtx := context .WithoutCancel (ctx )
@@ -182,7 +181,7 @@ func (vm *VM) Initialize(
182
181
genesisBytes ,
183
182
upgradeBytes ,
184
183
configBytes ,
185
- vmToEngine ,
184
+ vm . toScheduler ,
186
185
fxs ,
187
186
appSender ,
188
187
)
@@ -249,6 +248,69 @@ func (vm *VM) Initialize(
249
248
)
250
249
}
251
250
251
+ func (vm * VM ) dispatchScheduler (toEngine chan <- common.Message ) {
252
+ scheduler , vmToEngine := scheduler .New (vm .ctx .Log , toEngine )
253
+ vm .Scheduler = scheduler
254
+ vm .toScheduler = vmToEngine
255
+
256
+ platformChain := vm .ctx .ChainID == constants .PlatformChainID
257
+
258
+ go vm .ctx .Log .RecoverAndPanic (func () {
259
+ // Since new blocks built must have a P-chain height that is at least the P-chain height
260
+ // of their ancestors, if our local P-chain height is behind the P-chain height of our inner VM,
261
+ // we cannot build blocks.
262
+ // We therefore wait until the local P-chain has caught up with the P-chain height of the last block
263
+ // of our inner VM.
264
+ for ! vm .isLocalPlatformChainInSync () && ! platformChain {
265
+ time .Sleep (pChainPostBootstrapSyncPollInterval )
266
+ }
267
+ vm .schedulerDispatched .Store (true )
268
+ scheduler .Dispatch (time .Now ())
269
+ })
270
+ }
271
+
272
+ func (vm * VM ) isLocalPlatformChainInSync () bool {
273
+ vm .ctx .Lock .Lock ()
274
+ defer vm .ctx .Lock .Unlock ()
275
+
276
+ if vm .consensusState != snow .NormalOp {
277
+ vm .ctx .Log .Verbo ("not yet in normal operation state" )
278
+ }
279
+
280
+ ctx , cancel := context .WithTimeout (context .Background (), time .Second )
281
+ defer cancel ()
282
+
283
+ lastAcceptedID , err := vm .GetLastAccepted ()
284
+ if err != nil {
285
+ vm .ctx .Log .Debug ("failed getting last accepted block ID" , zap .Error (err ))
286
+ return false
287
+ }
288
+
289
+ lastAccepted , err := vm .getPostForkBlock (ctx , lastAcceptedID )
290
+ if err != nil {
291
+ vm .ctx .Log .Debug ("failed getting block with last accepted ID" ,
292
+ zap .Stringer ("ID" , lastAcceptedID ), zap .Error (err ))
293
+ return false
294
+ }
295
+
296
+ localPchainHeight , err := vm .ctx .ValidatorState .GetCurrentHeight (ctx )
297
+ if err != nil {
298
+ vm .ctx .Log .Debug ("failed getting local P-Chain block height" , zap .Error (err ))
299
+ return false
300
+ }
301
+
302
+ attestedPchainHeight , err := lastAccepted .pChainHeight (ctx )
303
+ if err != nil {
304
+ vm .ctx .Log .Debug ("failed getting P-Chain height of last accepted block" , zap .Uint64 ("block height" , lastAccepted .Height ()), zap .Error (err ))
305
+ return false
306
+ }
307
+
308
+ vm .ctx .Log .Debug ("checking if local platform chain is in sync" ,
309
+ zap .Uint64 ("local P-chain height" , localPchainHeight ), zap .Uint64 ("attested P-chain height" , attestedPchainHeight ))
310
+
311
+ return localPchainHeight >= attestedPchainHeight
312
+ }
313
+
252
314
// shutdown ops then propagate shutdown to innerVM
253
315
func (vm * VM ) Shutdown (ctx context.Context ) error {
254
316
vm .onShutdown ()
@@ -369,13 +431,20 @@ func (vm *VM) SetPreference(ctx context.Context, preferred ids.ID) error {
369
431
// until the P-chain's height has advanced.
370
432
return nil
371
433
}
372
- vm .Scheduler .SetBuildBlockTime (nextStartTime )
373
434
374
435
vm .ctx .Log .Debug ("set preference" ,
375
436
zap .Stringer ("blkID" , blk .ID ()),
376
437
zap .Time ("blockTimestamp" , parentTimestamp ),
377
438
zap .Time ("nextStartTime" , nextStartTime ),
378
439
)
440
+
441
+ if ! vm .schedulerDispatched .Load () {
442
+ vm .ctx .Log .Debug ("Skipping setting block build time because local P-chain has not caught up yet" )
443
+ return nil
444
+ }
445
+
446
+ vm .Scheduler .SetBuildBlockTime (nextStartTime )
447
+
379
448
return nil
380
449
}
381
450
0 commit comments