1
1
use std:: {
2
- sync:: {
3
- atomic:: { AtomicBool , Ordering } ,
4
- Arc ,
5
- } ,
2
+ sync:: { atomic:: AtomicBool , Arc } ,
6
3
time:: { Duration , Instant } ,
7
4
} ;
8
5
9
6
use kaspa_consensus_core:: {
10
7
api:: counters:: ProcessingCounters ,
11
- config:: { params :: NEW_DIFFICULTY_WINDOW_DURATION , Config } ,
8
+ config:: Config ,
12
9
daa_score_timestamp:: DaaScoreTimestamp ,
13
10
mining_rules:: MiningRules ,
14
11
network:: NetworkType :: { Mainnet , Testnet } ,
@@ -20,14 +17,14 @@ use kaspa_core::{
20
17
tick:: { TickReason , TickService } ,
21
18
} ,
22
19
time:: unix_now,
23
- trace, warn ,
20
+ trace,
24
21
} ;
25
22
use kaspa_p2p_lib:: Hub ;
26
23
27
- use crate :: rules:: mining_rule:: MiningRule ;
24
+ use crate :: rules:: { mining_rule:: MiningRule , sync_rate_rule :: SyncRateRule , ExtraData } ;
28
25
29
26
const RULE_ENGINE : & str = "mining-rule-engine" ;
30
- const SYNC_RATE_THRESHOLD : f64 = 0. 10;
27
+ pub const SNAPSHOT_INTERVAL : u64 = 10 ;
31
28
32
29
#[ derive( Clone ) ]
33
30
pub struct MiningRuleEngine {
@@ -44,13 +41,11 @@ pub struct MiningRuleEngine {
44
41
45
42
impl MiningRuleEngine {
46
43
pub async fn worker ( self : & Arc < MiningRuleEngine > ) {
47
- println ! ( module_path!( ) ) ;
48
- let snapshot_interval = 10 ;
49
44
let mut last_snapshot = self . processing_counters . snapshot ( ) ;
50
45
let mut last_log_time = Instant :: now ( ) ;
51
46
loop {
52
47
// START: Sync monitor
53
- if let TickReason :: Shutdown = self . tick_service . tick ( Duration :: from_secs ( snapshot_interval ) ) . await {
48
+ if let TickReason :: Shutdown = self . tick_service . tick ( Duration :: from_secs ( SNAPSHOT_INTERVAL ) ) . await {
54
49
// Let the system print final logs before exiting
55
50
tokio:: time:: sleep ( Duration :: from_millis ( 500 ) ) . await ;
56
51
break ;
@@ -70,60 +65,24 @@ impl MiningRuleEngine {
70
65
if elapsed_time. as_secs ( ) > 0 {
71
66
let session = self . consensus_manager . consensus ( ) . unguarded_session ( ) ;
72
67
let sink_daa_timestamp = session. async_get_sink_daa_score_timestamp ( ) . await ;
73
- let expected_blocks =
74
- ( elapsed_time. as_millis ( ) as u64 ) / self . config . target_time_per_block ( ) . get ( sink_daa_timestamp. daa_score ) ;
75
- let received_blocks = delta. body_counts . max ( delta. header_counts ) ;
76
- let rate: f64 = ( received_blocks as f64 ) / ( expected_blocks as f64 ) ;
77
68
78
69
let finality_point = session. async_finality_point ( ) . await ;
79
70
let finality_point_timestamp = session. async_get_header ( finality_point) . await . unwrap ( ) . timestamp ;
80
- // Finality point is considered "recent" if it is within 3 finality durations from the current time
81
- let is_finality_recent = finality_point_timestamp
82
- >= unix_now ( )
83
- . saturating_sub ( self . config . finality_duration_in_milliseconds ( ) . get ( sink_daa_timestamp. daa_score ) * 3 ) ;
84
-
85
- trace ! (
86
- "Sync rate: {:.2} | Finality point recent: {} | Elapsed time: {}s | Connected: {} | Found/Expected blocks: {}/{}" ,
87
- rate,
88
- is_finality_recent,
89
- elapsed_time. as_secs( ) ,
90
- delta. body_counts,
91
- self . has_sufficient_peer_connectivity( ) ,
92
- expected_blocks,
93
- ) ;
94
-
95
- if is_finality_recent && rate < SYNC_RATE_THRESHOLD {
96
- // if sync rate rule conditions are met:
97
- if let Ok ( false ) = self . use_sync_rate_rule . compare_exchange ( false , true , Ordering :: Relaxed , Ordering :: Relaxed ) {
98
- warn ! ( "Sync rate {:.2} is below threshold: {}" , rate, SYNC_RATE_THRESHOLD ) ;
99
- }
100
- } else {
101
- // else when sync rate conditions are not met:
102
- if let Ok ( true ) = self . use_sync_rate_rule . compare_exchange ( true , false , Ordering :: Relaxed , Ordering :: Relaxed ) {
103
- if !is_finality_recent {
104
- warn ! ( "Sync rate {:.2} recovered: {} by entering IBD" , rate, SYNC_RATE_THRESHOLD ) ;
105
- } else {
106
- warn ! ( "Sync rate {:.2} recovered: {}" , rate, SYNC_RATE_THRESHOLD ) ;
107
- }
108
- } else if !is_finality_recent {
109
- trace ! ( "Finality period is old. Timestamp: {}. Sync rate: {:.2}" , finality_point_timestamp, rate) ;
110
- }
111
- }
112
71
113
- // END - Sync monitor
72
+ let extra_data = ExtraData {
73
+ finality_point_timestamp,
74
+ target_time_per_block : self . config . target_time_per_block ( ) . get ( sink_daa_timestamp. daa_score ) ,
75
+ has_sufficient_peer_connectivity : self . has_sufficient_peer_connectivity ( ) ,
76
+ finality_duration : self . config . finality_duration_in_milliseconds ( ) . get ( sink_daa_timestamp. daa_score ) ,
77
+ elapsed_time,
78
+ } ;
114
79
115
- // START - Rule Engine
116
80
trace ! ( "Current Mining Rule: {:?}" , self . mining_rules) ;
117
81
118
- // Blue Parents Only Check:
82
+ // Check for all the rules
119
83
for rule in & self . rules {
120
- rule. check_rule ( & snapshot ) ;
84
+ rule. check_rule ( & delta , & extra_data ) ;
121
85
}
122
-
123
- // No Transactions Check:
124
- // TODO: implement this part
125
-
126
- // End - Rule Engine
127
86
}
128
87
129
88
last_snapshot = snapshot;
@@ -139,18 +98,10 @@ impl MiningRuleEngine {
139
98
hub : Hub ,
140
99
mining_rules : Arc < MiningRules > ,
141
100
) -> Self {
142
- let rules: Vec < Arc < ( dyn MiningRule + ' static ) > > = vec ! [ ] ;
143
-
144
- Self {
145
- consensus_manager,
146
- config,
147
- processing_counters,
148
- tick_service,
149
- hub,
150
- use_sync_rate_rule : Arc :: new ( AtomicBool :: new ( false ) ) ,
151
- mining_rules,
152
- rules,
153
- }
101
+ let use_sync_rate_rule = Arc :: new ( AtomicBool :: new ( false ) ) ;
102
+ let rules: Vec < Arc < ( dyn MiningRule + ' static ) > > = vec ! [ Arc :: new( SyncRateRule :: new( use_sync_rate_rule. clone( ) ) ) ] ;
103
+
104
+ Self { consensus_manager, config, processing_counters, tick_service, hub, use_sync_rate_rule, mining_rules, rules }
154
105
}
155
106
156
107
pub fn should_mine ( & self , sink_daa_score_timestamp : DaaScoreTimestamp ) -> bool {
@@ -169,27 +120,16 @@ impl MiningRuleEngine {
169
120
pub fn is_nearly_synced ( & self , sink_daa_score_timestamp : DaaScoreTimestamp ) -> bool {
170
121
let sink_timestamp = sink_daa_score_timestamp. timestamp ;
171
122
172
- if self . config . net . is_mainnet ( ) {
173
- // We consider the node close to being synced if the sink (virtual selected parent) block
174
- // timestamp is within DAA window duration far in the past. Blocks mined over such DAG state would
175
- // enter the DAA window of fully-synced nodes and thus contribute to overall network difficulty
176
- //
177
- // [Crescendo]: both durations are nearly equal so this decision is negligible
178
- unix_now ( )
179
- < sink_timestamp
180
- + self . config . expected_difficulty_window_duration_in_milliseconds ( ) . get ( sink_daa_score_timestamp. daa_score )
181
- } else {
182
- // For testnets we consider the node to be synced if the sink timestamp is within a time range which
183
- // is overwhelmingly unlikely to pass without mined blocks even if net hashrate decreased dramatically.
184
- //
185
- // This period is smaller than the above mainnet calculation in order to ensure that an IBDing miner
186
- // with significant testnet hashrate does not overwhelm the network with deep side-DAGs.
187
- //
188
- // We use DAA duration as baseline and scale it down with BPS (and divide by 3 for mining only when very close to current time on 10BPS testnets)
189
- let max_expected_duration_without_blocks_in_milliseconds =
190
- self . config . prior_target_time_per_block * NEW_DIFFICULTY_WINDOW_DURATION / 3 ; // = DAA duration in milliseconds / bps / 3
191
- unix_now ( ) < sink_timestamp + max_expected_duration_without_blocks_in_milliseconds
192
- }
123
+ // We consider the node close to being synced if the sink (virtual selected parent) block
124
+ // timestamp is within a quarter of the DAA window duration far in the past. Blocks mined over such DAG state would
125
+ // enter the DAA window of fully-synced nodes and thus contribute to overall network difficulty
126
+ //
127
+ // [Crescendo]: both durations are nearly equal so this decision is negligible
128
+ let synced_threshold =
129
+ self . config . expected_difficulty_window_duration_in_milliseconds ( ) . get ( sink_daa_score_timestamp. daa_score ) / 4 ;
130
+
131
+ // Roughly 10mins in all networks
132
+ unix_now ( ) < sink_timestamp + synced_threshold
193
133
}
194
134
195
135
fn has_sufficient_peer_connectivity ( & self ) -> bool {
0 commit comments