@@ -397,7 +397,6 @@ where
397
397
let remote_state_id = if let Some ( id) = remote_state {
398
398
id
399
399
} else {
400
- // TODO: Check finalized state inside DA boundary
401
400
StateId :: Finalized
402
401
} ;
403
402
@@ -413,15 +412,57 @@ where
413
412
} ;
414
413
debug ! ( context. log( ) , "Downloading {}" , state_string) ;
415
414
416
- let state = remote
415
+ let checkpoint_state = remote
417
416
. get_debug_beacon_states_ssz :: < TEthSpec > ( remote_state_id, & spec)
418
417
. await
419
418
. map_err ( |e| format ! ( "Error loading checkpoint state from remote: {:?}" , e) ) ?
420
419
. ok_or_else ( || "Checkpoint state missing from remote" . to_string ( ) ) ?;
421
420
422
- debug ! ( context. log( ) , "Downloaded {}" , state_string; "slot" => ?state . slot( ) ) ;
421
+ debug ! ( context. log( ) , "Downloaded {}" , state_string; "slot" => ?checkpoint_state . slot( ) ) ;
423
422
424
- let state_block_slot = state. latest_block_header ( ) . slot ;
423
+ let genesis_state = genesis_state ( & runtime_context, & config, log) . await ?;
424
+
425
+ if let Some ( deneb_fork_epoch) = spec. deneb_fork_epoch {
426
+ // Deneb is enabled. We must ensure the checkpoint state is within the data availability boundary.
427
+ let genesis_time = genesis_state. genesis_time ( ) ;
428
+ let slot_clock = SystemTimeSlotClock :: new (
429
+ spec. genesis_slot ,
430
+ Duration :: from_secs ( genesis_time) ,
431
+ Duration :: from_secs ( spec. seconds_per_slot ) ,
432
+ ) ;
433
+ let slot_clock_current_epoch = slot_clock
434
+ . now ( )
435
+ . map ( |slot| slot. epoch ( TEthSpec :: slots_per_epoch ( ) ) )
436
+ . ok_or ( "Unable to determine current slot for DA boundary calculation" ) ?;
437
+
438
+ if slot_clock_current_epoch > deneb_fork_epoch {
439
+ let cutoff_epoch = if checkpoint_state. current_epoch ( ) < deneb_fork_epoch {
440
+ // The chain is past the deneb fork and we are trying to checkpoint sync to a state
441
+ // before the fork. Here we use a modified DA boundary calculation. As long as we can
442
+ // sync up to the deneb fork before the DA boundary advances past it, we are good.
443
+ slot_clock_current_epoch. saturating_sub (
444
+ spec. min_epochs_for_blob_sidecars_requests
445
+ . saturating_sub ( BLOB_AVAILABILITY_REDUCTION_EPOCHS ) ,
446
+ )
447
+ } else {
448
+ std:: cmp:: max (
449
+ deneb_fork_epoch,
450
+ slot_clock_current_epoch
451
+ . saturating_sub ( spec. min_epochs_for_blob_sidecars_requests ) ,
452
+ )
453
+ } ;
454
+
455
+ if checkpoint_state. current_epoch ( ) < cutoff_epoch {
456
+ return Err ( "Requested checkpoint state is outside of the data availability boundary" . to_string ( ) ) ;
457
+ }
458
+ }
459
+ debug ! (
460
+ context. log( ) ,
461
+ "Checkpoint state is within data availability boundary"
462
+ ) ;
463
+ }
464
+
465
+ let state_block_slot = checkpoint_state. latest_block_header ( ) . slot ;
425
466
426
467
debug ! ( context. log( ) , "Downloading corresponding block" ; "block_slot" => ?state_block_slot) ;
427
468
let block = remote
@@ -439,7 +480,7 @@ where
439
480
440
481
debug ! ( context. log( ) , "Downloaded corresponding block" ) ;
441
482
442
- let anchor_state = if matches ! ( remote_state_id, StateId :: Finalized ) {
483
+ let anchor_state = if remote_state_id == StateId :: Finalized {
443
484
AnchorState :: Finalized
444
485
} else {
445
486
debug ! ( context. log( ) , "Downloading finalized block header" ) ;
@@ -459,21 +500,20 @@ where
459
500
. header
460
501
. message ;
461
502
debug ! ( context. log( ) , "Downloaded finalized block header" ; "anchor_slot" => block. slot( ) , "finalized_slot" => finalized_header. slot) ;
462
- if finalized_header. slot < state. slot ( ) {
463
- debug ! ( context. log( ) , "Checkpoint state is newer than remote finalized checkpoint! Treating as non-revertible!" ) ;
503
+ if finalized_header. slot < checkpoint_state. slot ( ) {
504
+ debug ! ( context. log( ) , "Checkpoint state is newer than remote finalized checkpoint. Treating anchor state as non-revertible." ) ;
505
+ // TODO: does this work with checkpointz?
464
506
AnchorState :: NonRevertible
465
507
} else {
466
508
AnchorState :: Finalized
467
509
}
468
510
} ;
469
511
470
- let genesis_state = genesis_state ( & runtime_context, & config, log) . await ?;
471
-
472
512
info ! (
473
513
context. log( ) ,
474
514
"Loaded checkpoint block and state" ;
475
515
"block_slot" => block. slot( ) ,
476
- "state_slot" => state . slot( ) ,
516
+ "state_slot" => checkpoint_state . slot( ) ,
477
517
"block_root" => ?block. canonical_root( ) ,
478
518
) ;
479
519
@@ -502,7 +542,7 @@ where
502
542
} ) ;
503
543
504
544
builder
505
- . weak_subjectivity_state ( state , block, genesis_state, anchor_state)
545
+ . weak_subjectivity_state ( checkpoint_state , block, genesis_state, anchor_state)
506
546
. map ( |v| ( v, service) ) ?
507
547
}
508
548
ClientGenesis :: DepositContract => {
0 commit comments