@@ -77,7 +77,11 @@ use kaspa_consensus_notify::{
77
77
root:: ConsensusNotificationRoot ,
78
78
} ;
79
79
use kaspa_consensusmanager:: SessionLock ;
80
- use kaspa_core:: { debug, info, time:: unix_now, trace, warn} ;
80
+ use kaspa_core:: {
81
+ debug, info,
82
+ time:: { unix_now, Stopwatch } ,
83
+ trace, warn,
84
+ } ;
81
85
use kaspa_database:: prelude:: { StoreError , StoreResultEmptyTuple , StoreResultExtensions } ;
82
86
use kaspa_hashes:: { Hash , ZERO_HASH } ;
83
87
use kaspa_muhash:: MuHash ;
@@ -106,6 +110,10 @@ use std::{
106
110
sync:: { atomic:: Ordering , Arc } ,
107
111
} ;
108
112
113
+ // 100ms - since at 10BPS, average block time is 100ms and so must expect
114
+ // the block template to build faster than that
115
+ pub const BUILD_BLOCK_TEMPLATE_SPEED_THRESHOLD : u128 = 100 ;
116
+
109
117
pub struct VirtualStateProcessor {
110
118
// Channels
111
119
receiver : CrossbeamReceiver < VirtualStateProcessingMessage > ,
@@ -715,7 +723,10 @@ impl VirtualStateProcessor {
715
723
let max_candidates = self . max_virtual_parent_candidates ( max_block_parents) ;
716
724
717
725
// Prioritize half the blocks with highest blue work and pick the rest randomly to ensure diversity between nodes
718
- if candidates. len ( ) > max_candidates {
726
+ if self . mining_rules . blue_only_mergeset . load ( Ordering :: Relaxed ) {
727
+ // pick 100% of the top blue work blocks
728
+ candidates. truncate ( max_candidates) ;
729
+ } else if candidates. len ( ) > max_candidates {
719
730
// make_contiguous should be a no op since the deque was just built
720
731
let slice = candidates. make_contiguous ( ) ;
721
732
@@ -804,25 +815,32 @@ impl VirtualStateProcessor {
804
815
let mut ghostdag_data = self . ghostdag_manager . ghostdag ( & virtual_parents) ;
805
816
let merge_depth_root = self . depth_manager . calc_merge_depth_root ( & ghostdag_data, current_pruning_point) ;
806
817
let mut kosherizing_blues: Option < Vec < Hash > > = None ;
807
- let mut bad_reds = Vec :: new ( ) ;
818
+ let bad_reds = if self . mining_rules . blue_only_mergeset . load ( Ordering :: Relaxed ) {
819
+ // Treat all reds as bad reds when this rule is triggered
820
+ ghostdag_data. mergeset_reds . as_ref ( ) . to_vec ( )
821
+ } else {
822
+ let mut inner_bad_reds = Vec :: new ( ) ;
808
823
809
- //
810
- // Note that the code below optimizes for the usual case where there are no merge-bound-violating blocks.
811
- //
824
+ //
825
+ // Note that the code below optimizes for the usual case where there are no merge-bound-violating blocks.
826
+ //
812
827
813
- // Find red blocks violating the merge bound and which are not kosherized by any blue
814
- for red in ghostdag_data. mergeset_reds . iter ( ) . copied ( ) {
815
- if self . reachability_service . is_dag_ancestor_of ( merge_depth_root, red) {
816
- continue ;
817
- }
818
- // Lazy load the kosherizing blocks since this case is extremely rare
819
- if kosherizing_blues. is_none ( ) {
820
- kosherizing_blues = Some ( self . depth_manager . kosherizing_blues ( & ghostdag_data, merge_depth_root) . collect ( ) ) ;
821
- }
822
- if !self . reachability_service . is_dag_ancestor_of_any ( red, & mut kosherizing_blues. as_ref ( ) . unwrap ( ) . iter ( ) . copied ( ) ) {
823
- bad_reds. push ( red) ;
828
+ // Find red blocks violating the merge bound and which are not kosherized by any blue
829
+ for red in ghostdag_data. mergeset_reds . iter ( ) . copied ( ) {
830
+ if self . reachability_service . is_dag_ancestor_of ( merge_depth_root, red) {
831
+ continue ;
832
+ }
833
+ // Lazy load the kosherizing blocks since this case is extremely rare
834
+ if kosherizing_blues. is_none ( ) {
835
+ kosherizing_blues = Some ( self . depth_manager . kosherizing_blues ( & ghostdag_data, merge_depth_root) . collect ( ) ) ;
836
+ }
837
+ if !self . reachability_service . is_dag_ancestor_of_any ( red, & mut kosherizing_blues. as_ref ( ) . unwrap ( ) . iter ( ) . copied ( ) ) {
838
+ inner_bad_reds. push ( red) ;
839
+ }
824
840
}
825
- }
841
+
842
+ inner_bad_reds
843
+ } ;
826
844
827
845
if !bad_reds. is_empty ( ) {
828
846
// Remove all parents which lead to merging a bad red
@@ -1053,6 +1071,7 @@ impl VirtualStateProcessor {
1053
1071
mut txs : Vec < Transaction > ,
1054
1072
calculated_fees : Vec < u64 > ,
1055
1073
) -> Result < BlockTemplate , RuleError > {
1074
+ let swo = Stopwatch :: new ( "virtual_processor.resolve_virtual" ) ;
1056
1075
// [`calc_block_parents`] can use deep blocks below the pruning point for this calculation, so we
1057
1076
// need to hold the pruning lock.
1058
1077
let _prune_guard = self . pruning_lock . blocking_read ( ) ;
@@ -1102,6 +1121,13 @@ impl VirtualStateProcessor {
1102
1121
let selected_parent_hash = virtual_state. ghostdag_data . selected_parent ;
1103
1122
let selected_parent_timestamp = self . headers_store . get_timestamp ( selected_parent_hash) . unwrap ( ) ;
1104
1123
let selected_parent_daa_score = self . headers_store . get_daa_score ( selected_parent_hash) . unwrap ( ) ;
1124
+
1125
+ if swo. elapsed ( ) . as_millis ( ) <= BUILD_BLOCK_TEMPLATE_SPEED_THRESHOLD {
1126
+ self . counters . build_block_template_within_threshold . fetch_add ( 1 , Ordering :: SeqCst ) ;
1127
+ } else {
1128
+ self . counters . build_block_template_above_threshold . fetch_add ( 1 , Ordering :: SeqCst ) ;
1129
+ }
1130
+
1105
1131
Ok ( BlockTemplate :: new (
1106
1132
MutableBlock :: new ( header, txs) ,
1107
1133
miner_data,
0 commit comments