@@ -4,6 +4,7 @@ mod gloas_payload;
44mod no_votes;
55mod votes;
66
7+ use crate :: error:: Error ;
78use crate :: proto_array_fork_choice:: { Block , ExecutionStatus , PayloadStatus , ProtoArrayForkChoice } ;
89use crate :: { InvalidationOperation , JustifiedBalances } ;
910use fixed_bytes:: FixedBytesExtended ;
@@ -30,6 +31,8 @@ pub enum Operation {
3031 justified_state_balances : Vec < u64 > ,
3132 expected_head : Hash256 ,
3233 current_slot : Slot ,
34+ // TODO(gloas): Make this non-optional. `find_head` always returns a `PayloadStatus`
35+ // (Empty for pre-GLOAS), so every test should assert on it explicitly.
3336 #[ serde( default ) ]
3437 expected_payload_status : Option < PayloadStatus > ,
3538 } ,
@@ -61,6 +64,12 @@ pub enum Operation {
6164 block_root : Hash256 ,
6265 attestation_slot : Slot ,
6366 } ,
67+ ProcessGloasAttestation {
68+ validator_index : usize ,
69+ block_root : Hash256 ,
70+ attestation_slot : Slot ,
71+ payload_present : bool ,
72+ } ,
6473 ProcessPayloadAttestation {
6574 validator_index : usize ,
6675 block_root : Hash256 ,
@@ -105,6 +114,16 @@ pub enum Operation {
105114 block_root : Hash256 ,
106115 expected : bool ,
107116 } ,
117+ AssertPayloadStatusByWeight {
118+ block_root : Hash256 ,
119+ expected_status : PayloadStatus ,
120+ /// Override `current_slot`. Defaults to the `current_slot` of the last `FindHead`.
121+ #[ serde( default ) ]
122+ current_slot : Option < Slot > ,
123+ /// Override the proposer boost root. Defaults to `Hash256::zero()`.
124+ #[ serde( default ) ]
125+ proposer_boost_root : Option < Hash256 > ,
126+ } ,
108127}
109128
110129#[ derive( Debug , Clone , Serialize , Deserialize ) ]
@@ -149,6 +168,7 @@ impl ForkChoiceTestDefinition {
149168 )
150169 . expect ( "should create fork choice struct" ) ;
151170 let equivocating_indices = BTreeSet :: new ( ) ;
171+ let mut last_current_slot = Slot :: new ( 0 ) ;
152172
153173 for ( op_index, op) in self . operations . into_iter ( ) . enumerate ( ) {
154174 match op. clone ( ) {
@@ -189,6 +209,16 @@ impl ForkChoiceTestDefinition {
189209 op_index, op
190210 ) ;
191211 }
212+ assert_canonical_payload_status_matches_find_head (
213+ & fork_choice,
214+ & head,
215+ current_slot,
216+ Hash256 :: zero ( ) ,
217+ & spec,
218+ payload_status,
219+ op_index,
220+ ) ;
221+ last_current_slot = current_slot;
192222 check_bytes_round_trip ( & fork_choice) ;
193223 }
194224 Operation :: ProposerBoostFindHead {
@@ -201,7 +231,7 @@ impl ForkChoiceTestDefinition {
201231 let justified_balances =
202232 JustifiedBalances :: from_effective_balances ( justified_state_balances)
203233 . unwrap ( ) ;
204- let ( head, _payload_status ) = fork_choice
234+ let ( head, payload_status ) = fork_choice
205235 . find_head :: < MainnetEthSpec > (
206236 justified_checkpoint,
207237 finalized_checkpoint,
@@ -220,6 +250,15 @@ impl ForkChoiceTestDefinition {
220250 "Operation at index {} failed head check. Operation: {:?}" ,
221251 op_index, op
222252 ) ;
253+ assert_canonical_payload_status_matches_find_head (
254+ & fork_choice,
255+ & head,
256+ Slot :: new ( 0 ) ,
257+ proposer_boost_root,
258+ & spec,
259+ payload_status,
260+ op_index,
261+ ) ;
223262 check_bytes_round_trip ( & fork_choice) ;
224263 }
225264 Operation :: InvalidFindHead {
@@ -308,6 +347,27 @@ impl ForkChoiceTestDefinition {
308347 } ) ;
309348 check_bytes_round_trip ( & fork_choice) ;
310349 }
350+ Operation :: ProcessGloasAttestation {
351+ validator_index,
352+ block_root,
353+ attestation_slot,
354+ payload_present,
355+ } => {
356+ fork_choice
357+ . process_attestation (
358+ validator_index,
359+ block_root,
360+ attestation_slot,
361+ payload_present,
362+ )
363+ . unwrap_or_else ( |_| {
364+ panic ! (
365+ "process_attestation op at index {} returned error" ,
366+ op_index
367+ )
368+ } ) ;
369+ check_bytes_round_trip ( & fork_choice) ;
370+ }
311371 Operation :: ProcessPayloadAttestation {
312372 validator_index,
313373 block_root,
@@ -522,6 +582,26 @@ impl ForkChoiceTestDefinition {
522582 op_index
523583 ) ;
524584 }
585+ Operation :: AssertPayloadStatusByWeight {
586+ block_root,
587+ expected_status,
588+ current_slot,
589+ proposer_boost_root,
590+ } => {
591+ let actual = fork_choice
592+ . get_canonical_payload_status :: < MainnetEthSpec > (
593+ & block_root,
594+ current_slot. unwrap_or ( last_current_slot) ,
595+ proposer_boost_root. unwrap_or_else ( Hash256 :: zero) ,
596+ & spec,
597+ )
598+ . unwrap ( ) ;
599+ assert_eq ! (
600+ actual, expected_status,
601+ "canonical payload status mismatch at op index {}" ,
602+ op_index
603+ ) ;
604+ }
525605 }
526606 }
527607 }
@@ -546,6 +626,37 @@ fn get_checkpoint(i: u64) -> Checkpoint {
546626 }
547627}
548628
629+ /// Checks that `get_canonical_payload_status` agrees with the `payload_status`
630+ /// returned by `find_head` for the head block.
631+ fn assert_canonical_payload_status_matches_find_head (
632+ fork_choice : & ProtoArrayForkChoice ,
633+ head : & Hash256 ,
634+ current_slot : Slot ,
635+ proposer_boost_root : Hash256 ,
636+ spec : & ChainSpec ,
637+ expected : PayloadStatus ,
638+ op_index : usize ,
639+ ) {
640+ match fork_choice. get_canonical_payload_status :: < MainnetEthSpec > (
641+ head,
642+ current_slot,
643+ proposer_boost_root,
644+ spec,
645+ ) {
646+ Ok ( actual) => assert_eq ! (
647+ actual, expected,
648+ "get_canonical_payload_status disagreed with find_head for head {:?} at op index {}" ,
649+ head, op_index
650+ ) ,
651+ // Skip the check for pre-gloas nodes
652+ Err ( Error :: InvalidNodeVariant { .. } ) => { }
653+ Err ( e) => panic ! (
654+ "get_canonical_payload_status failed at op index {}: {:?}" ,
655+ op_index, e
656+ ) ,
657+ }
658+ }
659+
549660fn check_bytes_round_trip ( original : & ProtoArrayForkChoice ) {
550661 let bytes = original. as_bytes ( ) ;
551662 let decoded = ProtoArrayForkChoice :: from_bytes ( & bytes, original. balances . clone ( ) )
0 commit comments