@@ -262,12 +262,10 @@ fn pick_best_candidate(
262262 if processed_data_roots. contains ( data_root) {
263263 continue ;
264264 }
265- if let Err ( reason) = entry_passes_filters (
265+ if let Err ( reason) = projected . entry_passes_filters (
266266 att_data,
267267 chain. known_block_roots ,
268268 chain. extended_historical_block_hashes ,
269- & projected. justified_slots ,
270- projected. finalized_slot ,
271269 ) {
272270 trace_skipped_attestation ( reason, att_data, data_root) ;
273271 continue ;
@@ -437,57 +435,58 @@ impl ProjectedState {
437435 } ;
438436 Some ( ( score, new_voters) )
439437 }
440- }
441438
442- /// Validate a candidate entry against the projected chain view.
443- ///
444- /// Mirrors `state_transition::is_valid_vote`: the entry's head must be known,
445- /// its source must be justified, its (source, target) must match the
446- /// candidate-block chain view, `target.slot > source.slot`, target must not
447- /// already be justified, and target must be a justifiable slot relative to
448- /// the projected finalized slot. The genesis self-vote (source == target ==
449- /// slot 0) is exempt from the `target.slot > source.slot` and
450- /// `target_already_justified` checks since fork-choice bootstrapping needs
451- /// it; STF will silently drop it, but it carries fork-choice signal.
452- pub ( crate ) fn entry_passes_filters (
453- att_data : & AttestationData ,
454- known_block_roots : & HashSet < H256 > ,
455- extended_historical_block_hashes : & [ H256 ] ,
456- projected_justified_slots : & JustifiedSlots ,
457- projected_finalized_slot : u64 ,
458- ) -> Result < ( ) , & ' static str > {
459- if !known_block_roots. contains ( & att_data. head . root ) {
460- return Err ( "head_root_unknown" ) ;
461- }
462- if !justified_slots_ops:: is_slot_justified (
463- projected_justified_slots,
464- projected_finalized_slot,
465- att_data. source . slot ,
466- ) {
467- return Err ( "source_not_justified" ) ;
468- }
469- if !attestation_data_matches_chain ( extended_historical_block_hashes, att_data) {
470- return Err ( "chain_mismatch" ) ;
471- }
472- let is_genesis_self_vote = is_genesis_self_vote ( att_data) ;
473- if !is_genesis_self_vote && att_data. target . slot <= att_data. source . slot {
474- return Err ( "target_not_after_source" ) ;
475- }
476- if !is_genesis_self_vote
477- && justified_slots_ops:: is_slot_justified (
478- projected_justified_slots,
479- projected_finalized_slot,
480- att_data. target . slot ,
481- )
482- {
483- return Err ( "target_already_justified" ) ;
484- }
485- if !is_genesis_self_vote
486- && !slot_is_justifiable_after ( att_data. target . slot , projected_finalized_slot)
487- {
488- return Err ( "target_not_justifiable" ) ;
439+ /// Validate a candidate entry against the projection and the given chain
440+ /// view.
441+ ///
442+ /// Mirrors `state_transition::is_valid_vote`: the entry's head must be
443+ /// known, its source must be justified, its (source, target) must match
444+ /// the candidate-block chain view, `target.slot > source.slot`, target
445+ /// must not already be justified, and target must be a justifiable slot
446+ /// relative to the projected finalized slot. The genesis self-vote
447+ /// (source == target == slot 0) is exempt from the `target.slot >
448+ /// source.slot` and `target_already_justified` checks since fork-choice
449+ /// bootstrapping needs it; STF will silently drop it, but it carries
450+ /// fork-choice signal.
451+ pub ( crate ) fn entry_passes_filters (
452+ & self ,
453+ att_data : & AttestationData ,
454+ known_block_roots : & HashSet < H256 > ,
455+ extended_historical_block_hashes : & [ H256 ] ,
456+ ) -> Result < ( ) , & ' static str > {
457+ if !known_block_roots. contains ( & att_data. head . root ) {
458+ return Err ( "head_root_unknown" ) ;
459+ }
460+ if !justified_slots_ops:: is_slot_justified (
461+ & self . justified_slots ,
462+ self . finalized_slot ,
463+ att_data. source . slot ,
464+ ) {
465+ return Err ( "source_not_justified" ) ;
466+ }
467+ if !attestation_data_matches_chain ( extended_historical_block_hashes, att_data) {
468+ return Err ( "chain_mismatch" ) ;
469+ }
470+ let is_genesis_self_vote = is_genesis_self_vote ( att_data) ;
471+ if !is_genesis_self_vote && att_data. target . slot <= att_data. source . slot {
472+ return Err ( "target_not_after_source" ) ;
473+ }
474+ if !is_genesis_self_vote
475+ && justified_slots_ops:: is_slot_justified (
476+ & self . justified_slots ,
477+ self . finalized_slot ,
478+ att_data. target . slot ,
479+ )
480+ {
481+ return Err ( "target_already_justified" ) ;
482+ }
483+ if !is_genesis_self_vote
484+ && !slot_is_justifiable_after ( att_data. target . slot , self . finalized_slot )
485+ {
486+ return Err ( "target_not_justifiable" ) ;
487+ }
488+ Ok ( ( ) )
489489 }
490- Ok ( ( ) )
491490}
492491
493492/// Selection tier for a candidate `AttestationData` entry.
0 commit comments