Skip to content

Commit d302519

Browse files
committed
wait until local p-chain has caught up with the p-chain height of inner VM blocks
Signed-off-by: Yacov Manevich <yacov.manevich@avalabs.org>
1 parent 2ef0cbe commit d302519

File tree

1 file changed

+82
-13
lines changed

1 file changed

+82
-13
lines changed

vms/proposervm/vm.go

+82-13
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"errors"
99
"fmt"
10+
"sync/atomic"
1011
"time"
1112

1213
"github.com/prometheus/client_golang/prometheus"
@@ -42,7 +43,10 @@ const (
4243
// blocks.
4344
DefaultNumHistoricalBlocks uint64 = 0
4445

45-
innerBlkCacheSize = 64 * units.MiB
46+
checkIndexedFrequency = 10 * time.Second
47+
innerBlkCacheSize = 64 * units.MiB
48+
49+
pChainPostBootstrapSyncPollInterval = time.Millisecond * 100
4650
)
4751

4852
var (
@@ -71,9 +75,10 @@ type VM struct {
7175
scheduler.Scheduler
7276
mockable.Clock
7377

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
7782

7883
// Block ID --> Block
7984
// Each element is a block that passed verification but
@@ -161,13 +166,7 @@ func (vm *VM) Initialize(
161166
}
162167
vm.innerBlkCache = innerBlkCache
163168

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)
171170

172171
vm.verifiedBlocks = make(map[ids.ID]PostForkBlock)
173172
detachedCtx := context.WithoutCancel(ctx)
@@ -182,7 +181,7 @@ func (vm *VM) Initialize(
182181
genesisBytes,
183182
upgradeBytes,
184183
configBytes,
185-
vmToEngine,
184+
vm.toScheduler,
186185
fxs,
187186
appSender,
188187
)
@@ -249,6 +248,69 @@ func (vm *VM) Initialize(
249248
)
250249
}
251250

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+
252314
// shutdown ops then propagate shutdown to innerVM
253315
func (vm *VM) Shutdown(ctx context.Context) error {
254316
vm.onShutdown()
@@ -369,13 +431,20 @@ func (vm *VM) SetPreference(ctx context.Context, preferred ids.ID) error {
369431
// until the P-chain's height has advanced.
370432
return nil
371433
}
372-
vm.Scheduler.SetBuildBlockTime(nextStartTime)
373434

374435
vm.ctx.Log.Debug("set preference",
375436
zap.Stringer("blkID", blk.ID()),
376437
zap.Time("blockTimestamp", parentTimestamp),
377438
zap.Time("nextStartTime", nextStartTime),
378439
)
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+
379448
return nil
380449
}
381450

0 commit comments

Comments
 (0)