@@ -1003,6 +1003,61 @@ pub fn get_gloas_should_build_on_full_test_definition() -> ForkChoiceTestDefinit
10031003 }
10041004}
10051005
1006+ /// When the justified checkpoint has no viable descendants, `get_head` must still
1007+ /// resolve the PENDING seed to EMPTY or FULL.
1008+ pub fn get_pending_head_resolves_when_justified_subtree_non_viable_test_definition ( )
1009+ -> ForkChoiceTestDefinition {
1010+ let ops = vec ! [
1011+ // Justified block at slot 32.
1012+ Operation :: ProcessBlock {
1013+ slot: Slot :: new( 32 ) ,
1014+ root: get_root( 2 ) ,
1015+ parent_root: get_root( 0 ) ,
1016+ justified_checkpoint: get_checkpoint( 0 ) ,
1017+ finalized_checkpoint: get_checkpoint( 0 ) ,
1018+ execution_payload_parent_hash: Some ( get_hash( 0 ) ) ,
1019+ execution_payload_block_hash: Some ( get_hash( 2 ) ) ,
1020+ } ,
1021+ // Child with stale voting source (below viability horizon).
1022+ Operation :: ProcessBlock {
1023+ slot: Slot :: new( 64 ) ,
1024+ root: get_root( 3 ) ,
1025+ parent_root: get_root( 2 ) ,
1026+ justified_checkpoint: get_checkpoint( 0 ) ,
1027+ finalized_checkpoint: get_checkpoint( 0 ) ,
1028+ execution_payload_parent_hash: Some ( get_hash( 99 ) ) ,
1029+ execution_payload_block_hash: Some ( get_hash( 3 ) ) ,
1030+ } ,
1031+ Operation :: FindHead {
1032+ justified_checkpoint: Checkpoint {
1033+ epoch: Epoch :: new( 1 ) ,
1034+ root: get_root( 2 ) ,
1035+ } ,
1036+ finalized_checkpoint: get_checkpoint( 0 ) ,
1037+ justified_state_balances: vec![ 1 ] ,
1038+ expected_head: get_root( 2 ) ,
1039+ current_slot: Slot :: new( 128 ) ,
1040+ expected_payload_status: Some ( PayloadStatus :: Empty ) ,
1041+ } ,
1042+ Operation :: AssertShouldBuildOnFull {
1043+ block_root: get_root( 2 ) ,
1044+ parent_payload_status: PayloadStatus :: Empty ,
1045+ proposal_slot: Slot :: new( 129 ) ,
1046+ expected: false ,
1047+ } ,
1048+ ] ;
1049+
1050+ ForkChoiceTestDefinition {
1051+ finalized_block_slot : Slot :: new ( 0 ) ,
1052+ justified_checkpoint : get_checkpoint ( 0 ) ,
1053+ finalized_checkpoint : get_checkpoint ( 0 ) ,
1054+ operations : ops,
1055+ execution_payload_parent_hash : Some ( get_hash ( 42 ) ) ,
1056+ execution_payload_block_hash : Some ( get_hash ( 0 ) ) ,
1057+ spec : Some ( gloas_spec ( ) ) ,
1058+ }
1059+ }
1060+
10061061#[ cfg( test) ]
10071062mod tests {
10081063 use super :: * ;
@@ -1198,6 +1253,11 @@ mod tests {
11981253 test. run ( ) ;
11991254 }
12001255
1256+ #[ test]
1257+ fn pending_head_resolves_when_justified_subtree_non_viable ( ) {
1258+ get_pending_head_resolves_when_justified_subtree_non_viable_test_definition ( ) . run ( ) ;
1259+ }
1260+
12011261 /// Test that execution payload invalidation propagates across the V17→V29 fork
12021262 /// boundary: after invalidating a V17 parent, head must not select any descendant.
12031263 ///
0 commit comments