@@ -19,6 +19,7 @@ use crate::{
19
19
daa:: DbDaaStore ,
20
20
depth:: { DbDepthStore , DepthStoreReader } ,
21
21
ghostdag:: { DbGhostdagStore , GhostdagData , GhostdagStoreReader } ,
22
+ good_finality_point:: { DbGoodFinalityPointStore , GoodFinalityPointStore , GoodFinalityPointStoreReader } ,
22
23
headers:: { DbHeadersStore , HeaderStoreReader } ,
23
24
past_pruning_points:: DbPastPruningPointsStore ,
24
25
pruning:: { DbPruningStore , PruningStoreReader } ,
@@ -113,6 +114,8 @@ pub struct VirtualStateProcessor {
113
114
pub ( super ) max_block_parents : u8 ,
114
115
pub ( super ) mergeset_size_limit : u64 ,
115
116
pub ( super ) pruning_depth : u64 ,
117
+ consensus_creation_time : u64 ,
118
+ finality_duration : u64 ,
116
119
117
120
// Stores
118
121
pub ( super ) statuses_store : Arc < RwLock < DbStatusesStore > > ,
@@ -133,6 +136,8 @@ pub struct VirtualStateProcessor {
133
136
pub ( super ) virtual_stores : Arc < RwLock < VirtualStores > > ,
134
137
pub ( super ) pruning_utxoset_stores : Arc < RwLock < PruningUtxosetStores > > ,
135
138
139
+ pub ( super ) good_finality_point_store : Arc < RwLock < DbGoodFinalityPointStore > > ,
140
+
136
141
/// The "last known good" virtual state. To be used by any logic which does not want to wait
137
142
/// for a possible virtual state write to complete but can rather settle with the last known state
138
143
pub lkg_virtual_state : LkgVirtualState ,
@@ -176,6 +181,7 @@ impl VirtualStateProcessor {
176
181
pruning_lock : SessionLock ,
177
182
notification_root : Arc < ConsensusNotificationRoot > ,
178
183
counters : Arc < ProcessingCounters > ,
184
+ consensus_creation_time : u64 ,
179
185
) -> Self {
180
186
Self {
181
187
receiver,
@@ -205,6 +211,7 @@ impl VirtualStateProcessor {
205
211
virtual_stores : storage. virtual_stores . clone ( ) ,
206
212
pruning_utxoset_stores : storage. pruning_utxoset_stores . clone ( ) ,
207
213
lkg_virtual_state : storage. lkg_virtual_state . clone ( ) ,
214
+ good_finality_point_store : storage. good_finality_point_store . clone ( ) ,
208
215
209
216
ghostdag_manager : services. ghostdag_primary_manager . clone ( ) ,
210
217
reachability_service : services. reachability_service . clone ( ) ,
@@ -221,6 +228,8 @@ impl VirtualStateProcessor {
221
228
notification_root,
222
229
counters,
223
230
storage_mass_activation_daa_score : params. storage_mass_activation_daa_score ,
231
+ consensus_creation_time,
232
+ finality_duration : params. finality_duration ( ) ,
224
233
}
225
234
}
226
235
@@ -1027,6 +1036,7 @@ impl VirtualStateProcessor {
1027
1036
pruning_point_write. set_history_root ( & mut batch, self . genesis . hash ) . unwrap ( ) ;
1028
1037
pruning_utxoset_write. set_utxoset_position ( & mut batch, self . genesis . hash ) . unwrap ( ) ;
1029
1038
self . db . write ( batch) . unwrap ( ) ;
1039
+ self . good_finality_point_store . write ( ) . set ( self . genesis . hash ) . unwrap ( ) ; // TODO: Wrong lock behavior?
1030
1040
drop ( pruning_point_write) ;
1031
1041
drop ( pruning_utxoset_write) ;
1032
1042
}
@@ -1132,33 +1142,46 @@ impl VirtualStateProcessor {
1132
1142
Ok ( ( ) )
1133
1143
}
1134
1144
1135
- pub fn are_pruning_points_violating_finality ( & self , pp_list : PruningPointsList ) -> bool {
1136
- // Ideally we would want to check if the last known pruning point has the finality point
1137
- // in its chain, but in some cases it's impossible: let `lkp` be the last known pruning
1138
- // point from the list, and `fup` be the first unknown pruning point (the one following `lkp`).
1139
- // fup.blue_score - lkp.blue_score ≈ finality_depth (±k), so it's possible for `lkp` not to
1140
- // have the finality point in its past. So we have no choice but to check if `lkp`
1141
- // has `finality_point.finality_point` in its chain (in the worst case `fup` is one block
1142
- // above the current finality point, and in this case `lkp` will be a few blocks above the
1143
- // finality_point.finality_point), meaning this function can only detect finality violations
1144
- // in depth of 2*finality_depth, and can give false negatives for smaller finality violations.
1145
- let current_pp = self . pruning_point_store . read ( ) . pruning_point ( ) . unwrap ( ) ;
1146
- let vf = self . virtual_finality_point ( & self . lkg_virtual_state . load ( ) . ghostdag_data , current_pp) ;
1147
- let vff = self . depth_manager . calc_finality_point ( & self . ghostdag_primary_store . get_data ( vf) . unwrap ( ) , current_pp) ;
1148
-
1149
- let last_known_pp = pp_list. iter ( ) . rev ( ) . find ( |pp| match self . statuses_store . read ( ) . get ( pp. hash ) . unwrap_option ( ) {
1150
- Some ( status) => status. is_valid ( ) ,
1151
- None => false ,
1152
- } ) ;
1153
-
1154
- if let Some ( last_known_pp) = last_known_pp {
1155
- !self . reachability_service . is_chain_ancestor_of ( vff, last_known_pp. hash )
1145
+ pub fn next_good_finality_point ( & self , pp_list : PruningPointsList ) -> PruningImportResult < Hash > {
1146
+ if self . is_consensus_mature ( ) {
1147
+ // TODO: Fix comment
1148
+ // Ideally we would want to check if the last known pruning point has the finality point
1149
+ // in its chain, but in some cases it's impossible: let `lkp` be the last known pruning
1150
+ // point from the list, and `fup` be the first unknown pruning point (the one following `lkp`).
1151
+ // fup.blue_score - lkp.blue_score ≈ finality_depth (±k), so it's possible for `lkp` not to
1152
+ // have the finality point in its past. So we have no choice but to check if `lkp`
1153
+ // has `finality_point.finality_point` in its chain (in the worst case `fup` is one block
1154
+ // above the current finality point, and in this case `lkp` will be a few blocks above the
1155
+ // finality_point.finality_point), meaning this function can only detect finality violations
1156
+ // in depth of 2*finality_depth, and can give false negatives for smaller finality violations.
1157
+ let current_pp = self . pruning_point_store . read ( ) . pruning_point ( ) . unwrap ( ) ;
1158
+ let vf = self . virtual_finality_point ( & self . lkg_virtual_state . load ( ) . ghostdag_data , current_pp) ;
1159
+ let vff = self . depth_manager . calc_finality_point ( & self . ghostdag_primary_store . get_data ( vf) . unwrap ( ) , current_pp) ;
1160
+
1161
+ let first_pp_in_future_of_vff = pp_list
1162
+ . iter ( )
1163
+ . map ( |pp| pp. hash )
1164
+ . filter ( |pp| match self . statuses_store . read ( ) . get ( * pp) . unwrap_option ( ) {
1165
+ Some ( status) => status. is_valid ( ) ,
1166
+ None => false ,
1167
+ } )
1168
+ . find ( |pp| self . reachability_service . is_chain_ancestor_of ( vff, * pp) ) ;
1169
+
1170
+ first_pp_in_future_of_vff. ok_or ( PruningImportError :: PruningPointListViolatesFinality )
1156
1171
} else {
1157
- // If no pruning point is known, there's definitely a finality violation
1158
- // (normally at least genesis should be known).
1159
- true
1172
+ let good_finality_point = self . good_finality_point_store . read ( ) . get ( ) . unwrap ( ) ;
1173
+ if pp_list. iter ( ) . map ( |h| h. hash ) . contains ( & good_finality_point) {
1174
+ Ok ( good_finality_point)
1175
+ } else {
1176
+ Err ( PruningImportError :: PruningPointListViolatesFinality )
1177
+ }
1160
1178
}
1161
1179
}
1180
+
1181
+ pub fn is_consensus_mature ( & self ) -> bool {
1182
+ // TODO: Maybe we should replace creation time with staging commitment time
1183
+ unix_now ( ) - self . consensus_creation_time > self . finality_duration
1184
+ }
1162
1185
}
1163
1186
1164
1187
enum MergesetIncreaseResult {
0 commit comments