@@ -22,7 +22,7 @@ use futures::channel::mpsc;
2222use futures:: stream:: FuturesUnordered ;
2323use futures:: { FutureExt , StreamExt } ;
2424use starknet_api:: block:: BlockNumber ;
25- use tracing:: { debug, error, info, instrument, trace} ;
25+ use tracing:: { debug, error, info, instrument, trace, warn } ;
2626
2727use crate :: metrics:: {
2828 register_metrics,
@@ -407,27 +407,36 @@ impl<ContextT: ConsensusContext> MultiHeightManager<ContextT> {
407407
408408 match proposal_init. height . cmp ( & height) {
409409 std:: cmp:: Ordering :: Greater => {
410- debug ! ( "Received a proposal for a future height. {:?}" , proposal_init) ;
411- // Note: new proposals with the same height/round will be ignored.
412- //
413- // TODO(matan): This only work for trusted peers. In the case of possibly malicious
414- // peers this is a possible DoS attack (malicious users can insert
415- // invalid/bad/malicious proposals before "good" nodes can propose).
416- //
417- // When moving to version 1.0 make sure this is addressed.
418- self . cached_proposals
419- . entry ( proposal_init. height . 0 )
420- . or_default ( )
421- . entry ( proposal_init. round )
422- . or_insert ( ( proposal_init, content_receiver) ) ;
410+ if self . should_cache_proposal ( & height, 0 , & proposal_init) {
411+ debug ! ( "Received a proposal for a future height. {:?}" , proposal_init) ;
412+ // Note: new proposals with the same height/round will be ignored.
413+ //
414+ // TODO(matan): This only work for trusted peers. In the case of possibly
415+ // malicious peers this is a possible DoS attack (malicious
416+ // users can insert invalid/bad/malicious proposals before
417+ // "good" nodes can propose).
418+ //
419+ // When moving to version 1.0 make sure this is addressed.
420+ self . cached_proposals
421+ . entry ( proposal_init. height . 0 )
422+ . or_default ( )
423+ . entry ( proposal_init. round )
424+ . or_insert ( ( proposal_init, content_receiver) ) ;
425+ }
423426 Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) )
424427 }
425428 std:: cmp:: Ordering :: Less => {
426429 trace ! ( "Drop proposal from past height. {:?}" , proposal_init) ;
427430 Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) )
428431 }
429432 std:: cmp:: Ordering :: Equal => match shc {
430- Some ( shc) => shc. handle_proposal ( context, proposal_init, content_receiver) . await ,
433+ Some ( shc) => {
434+ if self . should_cache_proposal ( & height, shc. current_round ( ) , & proposal_init) {
435+ shc. handle_proposal ( context, proposal_init, content_receiver) . await
436+ } else {
437+ Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) )
438+ }
439+ }
431440 None => {
432441 trace ! ( "Drop proposal from just completed height. {:?}" , proposal_init) ;
433442 Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) )
@@ -481,16 +490,24 @@ impl<ContextT: ConsensusContext> MultiHeightManager<ContextT> {
481490 // 2. Parallel proposals - we may send/receive a proposal for (H+1, 0).
482491 match message. height . cmp ( & height. 0 ) {
483492 std:: cmp:: Ordering :: Greater => {
484- trace ! ( "Cache message for a future height. {:?}" , message) ;
485- self . future_votes . entry ( message. height ) . or_default ( ) . push ( message) ;
493+ if self . should_cache_vote ( & height, 0 , & message) {
494+ trace ! ( "Cache message for a future height. {:?}" , message) ;
495+ self . future_votes . entry ( message. height ) . or_default ( ) . push ( message) ;
496+ }
486497 Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) )
487498 }
488499 std:: cmp:: Ordering :: Less => {
489500 trace ! ( "Drop message from past height. {:?}" , message) ;
490501 Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) )
491502 }
492503 std:: cmp:: Ordering :: Equal => match shc {
493- Some ( shc) => shc. handle_vote ( context, message) . await ,
504+ Some ( shc) => {
505+ if self . should_cache_vote ( & height, shc. current_round ( ) , & message) {
506+ shc. handle_vote ( context, message) . await
507+ } else {
508+ Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) )
509+ }
510+ }
494511 None => {
495512 trace ! ( "Drop message from just completed height. {:?}" , message) ;
496513 Ok ( ShcReturn :: Tasks ( Vec :: new ( ) ) )
@@ -548,4 +565,76 @@ impl<ContextT: ConsensusContext> MultiHeightManager<ContextT> {
548565 let max_cached_block_number = self . cached_proposals . keys ( ) . max ( ) . unwrap_or ( & height. 0 ) ;
549566 CONSENSUS_MAX_CACHED_BLOCK_NUMBER . set_lossy ( * max_cached_block_number) ;
550567 }
568+
569+ fn should_cache_msg (
570+ & self ,
571+ current_height : & BlockNumber ,
572+ current_round : u32 ,
573+ msg_height : u64 ,
574+ msg_round : u32 ,
575+ msg_description : & str ,
576+ ) -> bool {
577+ let height_diff = msg_height. saturating_sub ( current_height. 0 ) ;
578+ let round_diff = msg_round. saturating_sub ( current_round) ;
579+ let mut should_cache = true ;
580+
581+ // Check height limits first
582+ if height_diff > self . consensus_config . static_config . future_height_limit . into ( ) {
583+ should_cache = false ;
584+ }
585+
586+ // Check round limits based on height
587+ if height_diff == 0 {
588+ // For current height, check against current round + future_round_limit
589+ if round_diff > self . consensus_config . static_config . future_round_limit {
590+ should_cache = false ;
591+ }
592+ } else {
593+ // For future heights, check absolute round limit
594+ if msg_round > self . consensus_config . static_config . future_height_round_limit {
595+ should_cache = false ;
596+ }
597+ }
598+
599+ if !should_cache {
600+ warn ! (
601+ "Dropping {} for height={} round={} when current_height={} current_round={} - \
602+ limits: future_height={}, future_height_round={}, future_round={}",
603+ msg_description,
604+ msg_height,
605+ msg_round,
606+ current_height. 0 ,
607+ current_round,
608+ self . consensus_config. static_config. future_height_limit,
609+ self . consensus_config. static_config. future_height_round_limit,
610+ self . consensus_config. static_config. future_round_limit
611+ ) ;
612+ }
613+
614+ should_cache
615+ }
616+
617+ fn should_cache_proposal (
618+ & self ,
619+ current_height : & BlockNumber ,
620+ current_round : u32 ,
621+ proposal : & ProposalInit ,
622+ ) -> bool {
623+ self . should_cache_msg (
624+ current_height,
625+ current_round,
626+ proposal. height . 0 ,
627+ proposal. round ,
628+ "proposal" ,
629+ )
630+ }
631+
632+ fn should_cache_vote (
633+ & self ,
634+ current_height : & BlockNumber ,
635+ current_round : u32 ,
636+ vote : & Vote ,
637+ ) -> bool {
638+ self . should_cache_msg ( current_height, current_round, vote. height , vote. round , "vote" )
639+ }
551640}
0 commit comments