@@ -8,6 +8,7 @@ use beacon_chain::chain_config::{
8
8
DisallowedReOrgOffsets , DEFAULT_RE_ORG_HEAD_THRESHOLD ,
9
9
DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION , DEFAULT_RE_ORG_PARENT_THRESHOLD ,
10
10
} ;
11
+ use beacon_chain:: data_column_verification:: GossipVerifiedDataColumn ;
11
12
use beacon_chain:: slot_clock:: SlotClock ;
12
13
use beacon_chain:: {
13
14
attestation_verification:: {
@@ -26,8 +27,9 @@ use std::sync::Arc;
26
27
use std:: time:: Duration ;
27
28
use types:: {
28
29
Attestation , AttestationRef , AttesterSlashing , AttesterSlashingRef , BeaconBlock , BeaconState ,
29
- BlobSidecar , BlobsList , BlockImportSource , Checkpoint , ExecutionBlockHash , Hash256 ,
30
- IndexedAttestation , KzgProof , ProposerPreparationData , SignedBeaconBlock , Slot , Uint256 ,
30
+ BlobSidecar , BlobsList , BlockImportSource , Checkpoint , DataColumnSidecarList ,
31
+ ExecutionBlockHash , Hash256 , IndexedAttestation , KzgProof , ProposerPreparationData ,
32
+ SignedBeaconBlock , Slot , Uint256 ,
31
33
} ;
32
34
33
35
// When set to true, cache any states fetched from the db.
@@ -91,14 +93,14 @@ impl From<PayloadStatus> for PayloadStatusV1 {
91
93
92
94
#[ derive( Debug , Clone , Deserialize ) ]
93
95
#[ serde( untagged, deny_unknown_fields) ]
94
- pub enum Step < TBlock , TBlobs , TAttestation , TAttesterSlashing , TPowBlock > {
96
+ pub enum Step < TBlock , TBlobs , TColumns , TAttestation , TAttesterSlashing , TPowBlock > {
95
97
Tick {
96
98
tick : u64 ,
97
99
} ,
98
100
ValidBlock {
99
101
block : TBlock ,
100
102
} ,
101
- MaybeValidBlock {
103
+ MaybeValidBlockAndBlobs {
102
104
block : TBlock ,
103
105
blobs : Option < TBlobs > ,
104
106
proofs : Option < Vec < KzgProof > > ,
@@ -120,6 +122,11 @@ pub enum Step<TBlock, TBlobs, TAttestation, TAttesterSlashing, TPowBlock> {
120
122
Checks {
121
123
checks : Box < Checks > ,
122
124
} ,
125
+ MaybeValidBlockAndColumns {
126
+ block : TBlock ,
127
+ columns : Option < TColumns > ,
128
+ valid : bool ,
129
+ } ,
123
130
}
124
131
125
132
#[ derive( Debug , Clone , Deserialize ) ]
@@ -136,7 +143,14 @@ pub struct ForkChoiceTest<E: EthSpec> {
136
143
pub anchor_block : BeaconBlock < E > ,
137
144
#[ allow( clippy:: type_complexity) ]
138
145
pub steps : Vec <
139
- Step < SignedBeaconBlock < E > , BlobsList < E > , Attestation < E > , AttesterSlashing < E > , PowBlock > ,
146
+ Step <
147
+ SignedBeaconBlock < E > ,
148
+ BlobsList < E > ,
149
+ DataColumnSidecarList < E > ,
150
+ Attestation < E > ,
151
+ AttesterSlashing < E > ,
152
+ PowBlock ,
153
+ > ,
140
154
> ,
141
155
}
142
156
@@ -150,7 +164,7 @@ impl<E: EthSpec> LoadCase for ForkChoiceTest<E> {
150
164
. expect ( "path must be valid OsStr" )
151
165
. to_string ( ) ;
152
166
let spec = & testing_spec :: < E > ( fork_name) ;
153
- let steps: Vec < Step < String , String , String , String , String > > =
167
+ let steps: Vec < Step < String , String , Vec < String > , String , String , String > > =
154
168
yaml_decode_file ( & path. join ( "steps.yaml" ) ) ?;
155
169
// Resolve the object names in `steps.yaml` into actual decoded block/attestation objects.
156
170
let steps = steps
@@ -163,7 +177,7 @@ impl<E: EthSpec> LoadCase for ForkChoiceTest<E> {
163
177
} )
164
178
. map ( |block| Step :: ValidBlock { block } )
165
179
}
166
- Step :: MaybeValidBlock {
180
+ Step :: MaybeValidBlockAndBlobs {
167
181
block,
168
182
blobs,
169
183
proofs,
@@ -176,7 +190,7 @@ impl<E: EthSpec> LoadCase for ForkChoiceTest<E> {
176
190
let blobs = blobs
177
191
. map ( |blobs| ssz_decode_file ( & path. join ( format ! ( "{blobs}.ssz_snappy" ) ) ) )
178
192
. transpose ( ) ?;
179
- Ok ( Step :: MaybeValidBlock {
193
+ Ok ( Step :: MaybeValidBlockAndBlobs {
180
194
block,
181
195
blobs,
182
196
proofs,
@@ -223,6 +237,31 @@ impl<E: EthSpec> LoadCase for ForkChoiceTest<E> {
223
237
payload_status,
224
238
} ) ,
225
239
Step :: Checks { checks } => Ok ( Step :: Checks { checks } ) ,
240
+ Step :: MaybeValidBlockAndColumns {
241
+ block,
242
+ columns,
243
+ valid,
244
+ } => {
245
+ let block =
246
+ ssz_decode_file_with ( & path. join ( format ! ( "{block}.ssz_snappy" ) ) , |bytes| {
247
+ SignedBeaconBlock :: from_ssz_bytes ( bytes, spec)
248
+ } ) ?;
249
+ let columns = columns
250
+ . map ( |columns_vec| {
251
+ columns_vec
252
+ . into_iter ( )
253
+ . map ( |column| {
254
+ ssz_decode_file ( & path. join ( format ! ( "{column}.ssz_snappy" ) ) )
255
+ } )
256
+ . collect :: < Result < Vec < _ > , _ > > ( )
257
+ } )
258
+ . transpose ( ) ?;
259
+ Ok ( Step :: MaybeValidBlockAndColumns {
260
+ block,
261
+ columns,
262
+ valid,
263
+ } )
264
+ }
226
265
} )
227
266
. collect :: < Result < _ , _ > > ( ) ?;
228
267
let anchor_state = ssz_decode_state ( & path. join ( "anchor_state.ssz_snappy" ) , spec) ?;
@@ -263,14 +302,19 @@ impl<E: EthSpec> Case for ForkChoiceTest<E> {
263
302
match step {
264
303
Step :: Tick { tick } => tester. set_tick ( * tick) ,
265
304
Step :: ValidBlock { block } => {
266
- tester. process_block ( block. clone ( ) , None , None , true ) ?
305
+ tester. process_block_and_blobs ( block. clone ( ) , None , None , true ) ?
267
306
}
268
- Step :: MaybeValidBlock {
307
+ Step :: MaybeValidBlockAndBlobs {
269
308
block,
270
309
blobs,
271
310
proofs,
272
311
valid,
273
- } => tester. process_block ( block. clone ( ) , blobs. clone ( ) , proofs. clone ( ) , * valid) ?,
312
+ } => tester. process_block_and_blobs (
313
+ block. clone ( ) ,
314
+ blobs. clone ( ) ,
315
+ proofs. clone ( ) ,
316
+ * valid,
317
+ ) ?,
274
318
Step :: Attestation { attestation } => tester. process_attestation ( attestation) ?,
275
319
Step :: AttesterSlashing { attester_slashing } => {
276
320
tester. process_attester_slashing ( attester_slashing. to_ref ( ) )
@@ -344,6 +388,14 @@ impl<E: EthSpec> Case for ForkChoiceTest<E> {
344
388
tester. check_expected_proposer_head ( * expected_proposer_head) ?;
345
389
}
346
390
}
391
+
392
+ Step :: MaybeValidBlockAndColumns {
393
+ block,
394
+ columns,
395
+ valid,
396
+ } => {
397
+ tester. process_block_and_columns ( block. clone ( ) , columns. clone ( ) , * valid) ?;
398
+ }
347
399
}
348
400
}
349
401
@@ -384,6 +436,7 @@ impl<E: EthSpec> Tester<E> {
384
436
. genesis_state_ephemeral_store ( case. anchor_state . clone ( ) )
385
437
. mock_execution_layer ( )
386
438
. recalculate_fork_times_with_genesis ( 0 )
439
+ . import_all_data_columns ( true )
387
440
. mock_execution_layer_all_payloads_valid ( )
388
441
. build ( ) ;
389
442
@@ -454,7 +507,66 @@ impl<E: EthSpec> Tester<E> {
454
507
. unwrap ( ) ;
455
508
}
456
509
457
- pub fn process_block (
510
+ pub fn process_block_and_columns (
511
+ & self ,
512
+ block : SignedBeaconBlock < E > ,
513
+ columns : Option < DataColumnSidecarList < E > > ,
514
+ valid : bool ,
515
+ ) -> Result < ( ) , Error > {
516
+ let block_root = block. canonical_root ( ) ;
517
+ let mut data_column_success = true ;
518
+
519
+ if let Some ( columns) = columns. clone ( ) {
520
+ let gossip_verified_data_columns = columns
521
+ . into_iter ( )
522
+ . map ( |column| {
523
+ GossipVerifiedDataColumn :: new ( column. clone ( ) , column. index , & self . harness . chain )
524
+ . unwrap_or_else ( |_| {
525
+ data_column_success = false ;
526
+ GossipVerifiedDataColumn :: __new_for_testing ( column)
527
+ } )
528
+ } )
529
+ . collect ( ) ;
530
+
531
+ let result = self . block_on_dangerous (
532
+ self . harness
533
+ . chain
534
+ . process_gossip_data_columns ( gossip_verified_data_columns, || Ok ( ( ) ) ) ,
535
+ ) ?;
536
+ if valid {
537
+ assert ! ( result. is_ok( ) ) ;
538
+ }
539
+ } ;
540
+
541
+ let block = Arc :: new ( block) ;
542
+ let result: Result < Result < Hash256 , ( ) > , _ > = self
543
+ . block_on_dangerous ( self . harness . chain . process_block (
544
+ block_root,
545
+ RpcBlock :: new_without_blobs ( Some ( block_root) , block. clone ( ) ) ,
546
+ NotifyExecutionLayer :: Yes ,
547
+ BlockImportSource :: Lookup ,
548
+ || Ok ( ( ) ) ,
549
+ ) ) ?
550
+ . map ( |avail : AvailabilityProcessingStatus | avail. try_into ( ) ) ;
551
+ let success = data_column_success && result. as_ref ( ) . is_ok_and ( |inner| inner. is_ok ( ) ) ;
552
+ if success != valid {
553
+ return Err ( Error :: DidntFail ( format ! (
554
+ "block with root {} was valid={} whilst test expects valid={}. result: {:?}" ,
555
+ block_root,
556
+ result. is_ok( ) ,
557
+ valid,
558
+ result
559
+ ) ) ) ;
560
+ }
561
+
562
+ if !valid && columns. is_none ( ) {
563
+ self . apply_invalid_block ( & block) ?;
564
+ }
565
+
566
+ Ok ( ( ) )
567
+ }
568
+
569
+ pub fn process_block_and_blobs (
458
570
& self ,
459
571
block : SignedBeaconBlock < E > ,
460
572
blobs : Option < BlobsList < E > > ,
@@ -537,66 +649,73 @@ impl<E: EthSpec> Tester<E> {
537
649
) ) ) ;
538
650
}
539
651
540
- // Apply invalid blocks directly against the fork choice `on_block` function. This ensures
541
- // that the block is being rejected by `on_block`, not just some upstream block processing
542
- // function. When blobs exist, we don't do this.
543
652
if !valid && blobs. is_none ( ) {
544
- // A missing parent block whilst `valid == false` means the test should pass.
545
- if let Some ( parent_block) = self
653
+ self . apply_invalid_block ( & block) ?;
654
+ }
655
+
656
+ Ok ( ( ) )
657
+ }
658
+
659
+ // Apply invalid blocks directly against the fork choice `on_block` function. This ensures
660
+ // that the block is being rejected by `on_block`, not just some upstream block processing
661
+ // function. When data columns or blobs exist, we don't do this.
662
+ fn apply_invalid_block ( & self , block : & Arc < SignedBeaconBlock < E > > ) -> Result < ( ) , Error > {
663
+ let block_root = block. canonical_root ( ) ;
664
+ // A missing parent block whilst `valid == false` means the test should pass.
665
+ if let Some ( parent_block) = self
666
+ . harness
667
+ . chain
668
+ . get_blinded_block ( & block. parent_root ( ) )
669
+ . unwrap ( )
670
+ {
671
+ let parent_state_root = parent_block. state_root ( ) ;
672
+
673
+ let mut state = self
546
674
. harness
547
675
. chain
548
- . get_blinded_block ( & block. parent_root ( ) )
676
+ . get_state (
677
+ & parent_state_root,
678
+ Some ( parent_block. slot ( ) ) ,
679
+ CACHE_STATE_IN_TESTS ,
680
+ )
549
681
. unwrap ( )
550
- {
551
- let parent_state_root = parent_block. state_root ( ) ;
682
+ . unwrap ( ) ;
552
683
553
- let mut state = self
554
- . harness
555
- . chain
556
- . get_state (
557
- & parent_state_root,
558
- Some ( parent_block. slot ( ) ) ,
559
- CACHE_STATE_IN_TESTS ,
560
- )
561
- . unwrap ( )
562
- . unwrap ( ) ;
563
-
564
- complete_state_advance (
565
- & mut state,
566
- Some ( parent_state_root) ,
567
- block. slot ( ) ,
568
- & self . harness . chain . spec ,
569
- )
684
+ complete_state_advance (
685
+ & mut state,
686
+ Some ( parent_state_root) ,
687
+ block. slot ( ) ,
688
+ & self . harness . chain . spec ,
689
+ )
690
+ . unwrap ( ) ;
691
+
692
+ let block_delay = self
693
+ . harness
694
+ . chain
695
+ . slot_clock
696
+ . seconds_from_current_slot_start ( )
570
697
. unwrap ( ) ;
571
698
572
- let block_delay = self
573
- . harness
574
- . chain
575
- . slot_clock
576
- . seconds_from_current_slot_start ( )
577
- . unwrap ( ) ;
699
+ let result = self
700
+ . harness
701
+ . chain
702
+ . canonical_head
703
+ . fork_choice_write_lock ( )
704
+ . on_block (
705
+ self . harness . chain . slot ( ) . unwrap ( ) ,
706
+ block. message ( ) ,
707
+ block_root,
708
+ block_delay,
709
+ & state,
710
+ PayloadVerificationStatus :: Irrelevant ,
711
+ & self . harness . chain . spec ,
712
+ ) ;
578
713
579
- let result = self
580
- . harness
581
- . chain
582
- . canonical_head
583
- . fork_choice_write_lock ( )
584
- . on_block (
585
- self . harness . chain . slot ( ) . unwrap ( ) ,
586
- block. message ( ) ,
587
- block_root,
588
- block_delay,
589
- & state,
590
- PayloadVerificationStatus :: Irrelevant ,
591
- & self . harness . chain . spec ,
592
- ) ;
593
-
594
- if result. is_ok ( ) {
595
- return Err ( Error :: DidntFail ( format ! (
596
- "block with root {} should fail on_block" ,
597
- block_root,
598
- ) ) ) ;
599
- }
714
+ if result. is_ok ( ) {
715
+ return Err ( Error :: DidntFail ( format ! (
716
+ "block with root {} should fail on_block" ,
717
+ block_root,
718
+ ) ) ) ;
600
719
}
601
720
}
602
721
0 commit comments