@@ -27,6 +27,7 @@ pub enum Error {
27
27
FailedToReadState ( StoreError ) ,
28
28
MissingState ( Hash256 ) ,
29
29
BeaconStateError ( BeaconStateError ) ,
30
+ UnalignedCheckpoint { block_slot : Slot , state_slot : Slot } ,
30
31
Arith ( ArithError ) ,
31
32
}
32
33
@@ -136,7 +137,9 @@ pub struct BeaconForkChoiceStore<E: EthSpec, Hot: ItemStore<E>, Cold: ItemStore<
136
137
finalized_checkpoint : Checkpoint ,
137
138
justified_checkpoint : Checkpoint ,
138
139
justified_balances : JustifiedBalances ,
140
+ justified_state_root : Hash256 ,
139
141
unrealized_justified_checkpoint : Checkpoint ,
142
+ unrealized_justified_state_root : Hash256 ,
140
143
unrealized_finalized_checkpoint : Checkpoint ,
141
144
proposer_boost_root : Hash256 ,
142
145
equivocating_indices : BTreeSet < u64 > ,
@@ -162,30 +165,48 @@ where
162
165
/// It is assumed that `anchor` is already persisted in `store`.
163
166
pub fn get_forkchoice_store (
164
167
store : Arc < HotColdDB < E , Hot , Cold > > ,
165
- anchor : & BeaconSnapshot < E > ,
168
+ anchor : BeaconSnapshot < E > ,
166
169
) -> Result < Self , Error > {
167
- let anchor_state = & anchor. beacon_state ;
170
+ let unadvanced_state_root = anchor. beacon_state_root ( ) ;
171
+ let mut anchor_state = anchor. beacon_state ;
168
172
let mut anchor_block_header = anchor_state. latest_block_header ( ) . clone ( ) ;
169
- if anchor_block_header. state_root == Hash256 :: zero ( ) {
170
- anchor_block_header. state_root = anchor. beacon_state_root ( ) ;
173
+
174
+ // The anchor state MUST be on an epoch boundary (it should be advanced by the caller).
175
+ if !anchor_state
176
+ . slot ( )
177
+ . as_u64 ( )
178
+ . is_multiple_of ( E :: slots_per_epoch ( ) )
179
+ {
180
+ return Err ( Error :: UnalignedCheckpoint {
181
+ block_slot : anchor_block_header. slot ,
182
+ state_slot : anchor_state. slot ( ) ,
183
+ } ) ;
184
+ }
185
+
186
+ // Compute the accurate block root for the checkpoint block.
187
+ if anchor_block_header. state_root . is_zero ( ) {
188
+ anchor_block_header. state_root = unadvanced_state_root;
171
189
}
172
- let anchor_root = anchor_block_header. canonical_root ( ) ;
190
+ let anchor_block_root = anchor_block_header. canonical_root ( ) ;
173
191
let anchor_epoch = anchor_state. current_epoch ( ) ;
174
192
let justified_checkpoint = Checkpoint {
175
193
epoch : anchor_epoch,
176
- root : anchor_root ,
194
+ root : anchor_block_root ,
177
195
} ;
178
196
let finalized_checkpoint = justified_checkpoint;
179
- let justified_balances = JustifiedBalances :: from_justified_state ( anchor_state) ?;
197
+ let justified_balances = JustifiedBalances :: from_justified_state ( & anchor_state) ?;
198
+ let justified_state_root = anchor_state. canonical_root ( ) ?;
180
199
181
200
Ok ( Self {
182
201
store,
183
202
balances_cache : <_ >:: default ( ) ,
184
203
time : anchor_state. slot ( ) ,
185
204
justified_checkpoint,
186
205
justified_balances,
206
+ justified_state_root,
187
207
finalized_checkpoint,
188
208
unrealized_justified_checkpoint : justified_checkpoint,
209
+ unrealized_justified_state_root : justified_state_root,
189
210
unrealized_finalized_checkpoint : finalized_checkpoint,
190
211
proposer_boost_root : Hash256 :: zero ( ) ,
191
212
equivocating_indices : BTreeSet :: new ( ) ,
@@ -197,33 +218,72 @@ where
197
218
/// on-disk database.
198
219
pub fn to_persisted ( & self ) -> PersistedForkChoiceStore {
199
220
PersistedForkChoiceStore {
200
- balances_cache : self . balances_cache . clone ( ) ,
201
221
time : self . time ,
202
222
finalized_checkpoint : self . finalized_checkpoint ,
203
223
justified_checkpoint : self . justified_checkpoint ,
204
- justified_balances : self . justified_balances . effective_balances . clone ( ) ,
224
+ justified_state_root : self . justified_state_root ,
205
225
unrealized_justified_checkpoint : self . unrealized_justified_checkpoint ,
226
+ unrealized_justified_state_root : self . unrealized_justified_state_root ,
206
227
unrealized_finalized_checkpoint : self . unrealized_finalized_checkpoint ,
207
228
proposer_boost_root : self . proposer_boost_root ,
208
229
equivocating_indices : self . equivocating_indices . clone ( ) ,
209
230
}
210
231
}
211
232
212
233
/// Restore `Self` from a previously-generated `PersistedForkChoiceStore`.
213
- pub fn from_persisted (
214
- persisted : PersistedForkChoiceStore ,
234
+ ///
235
+ /// DEPRECATED. Can be deleted once migrations no longer require it.
236
+ pub fn from_persisted_v17 (
237
+ persisted : PersistedForkChoiceStoreV17 ,
238
+ justified_state_root : Hash256 ,
239
+ unrealized_justified_state_root : Hash256 ,
215
240
store : Arc < HotColdDB < E , Hot , Cold > > ,
216
241
) -> Result < Self , Error > {
217
242
let justified_balances =
218
243
JustifiedBalances :: from_effective_balances ( persisted. justified_balances ) ?;
244
+
219
245
Ok ( Self {
220
246
store,
221
- balances_cache : persisted . balances_cache ,
247
+ balances_cache : < _ > :: default ( ) ,
222
248
time : persisted. time ,
223
249
finalized_checkpoint : persisted. finalized_checkpoint ,
224
250
justified_checkpoint : persisted. justified_checkpoint ,
225
251
justified_balances,
252
+ justified_state_root,
226
253
unrealized_justified_checkpoint : persisted. unrealized_justified_checkpoint ,
254
+ unrealized_justified_state_root,
255
+ unrealized_finalized_checkpoint : persisted. unrealized_finalized_checkpoint ,
256
+ proposer_boost_root : persisted. proposer_boost_root ,
257
+ equivocating_indices : persisted. equivocating_indices ,
258
+ _phantom : PhantomData ,
259
+ } )
260
+ }
261
+
262
+ /// Restore `Self` from a previously-generated `PersistedForkChoiceStore`.
263
+ pub fn from_persisted (
264
+ persisted : PersistedForkChoiceStore ,
265
+ store : Arc < HotColdDB < E , Hot , Cold > > ,
266
+ ) -> Result < Self , Error > {
267
+ let justified_checkpoint = persisted. justified_checkpoint ;
268
+ let justified_state_root = persisted. justified_state_root ;
269
+
270
+ let update_cache = true ;
271
+ let justified_state = store
272
+ . get_hot_state ( & justified_state_root, update_cache)
273
+ . map_err ( Error :: FailedToReadState ) ?
274
+ . ok_or ( Error :: MissingState ( justified_state_root) ) ?;
275
+
276
+ let justified_balances = JustifiedBalances :: from_justified_state ( & justified_state) ?;
277
+ Ok ( Self {
278
+ store,
279
+ balances_cache : <_ >:: default ( ) ,
280
+ time : persisted. time ,
281
+ finalized_checkpoint : persisted. finalized_checkpoint ,
282
+ justified_checkpoint,
283
+ justified_balances,
284
+ justified_state_root,
285
+ unrealized_justified_checkpoint : persisted. unrealized_justified_checkpoint ,
286
+ unrealized_justified_state_root : persisted. unrealized_justified_state_root ,
227
287
unrealized_finalized_checkpoint : persisted. unrealized_finalized_checkpoint ,
228
288
proposer_boost_root : persisted. proposer_boost_root ,
229
289
equivocating_indices : persisted. equivocating_indices ,
@@ -261,6 +321,10 @@ where
261
321
& self . justified_checkpoint
262
322
}
263
323
324
+ fn justified_state_root ( & self ) -> Hash256 {
325
+ self . justified_state_root
326
+ }
327
+
264
328
fn justified_balances ( & self ) -> & JustifiedBalances {
265
329
& self . justified_balances
266
330
}
@@ -273,6 +337,10 @@ where
273
337
& self . unrealized_justified_checkpoint
274
338
}
275
339
340
+ fn unrealized_justified_state_root ( & self ) -> Hash256 {
341
+ self . unrealized_justified_state_root
342
+ }
343
+
276
344
fn unrealized_finalized_checkpoint ( & self ) -> & Checkpoint {
277
345
& self . unrealized_finalized_checkpoint
278
346
}
@@ -285,8 +353,13 @@ where
285
353
self . finalized_checkpoint = checkpoint
286
354
}
287
355
288
- fn set_justified_checkpoint ( & mut self , checkpoint : Checkpoint ) -> Result < ( ) , Error > {
356
+ fn set_justified_checkpoint (
357
+ & mut self ,
358
+ checkpoint : Checkpoint ,
359
+ justified_state_root : Hash256 ,
360
+ ) -> Result < ( ) , Error > {
289
361
self . justified_checkpoint = checkpoint;
362
+ self . justified_state_root = justified_state_root;
290
363
291
364
if let Some ( balances) = self . balances_cache . get (
292
365
self . justified_checkpoint . root ,
@@ -297,36 +370,24 @@ where
297
370
self . justified_balances = JustifiedBalances :: from_effective_balances ( balances) ?;
298
371
} else {
299
372
metrics:: inc_counter ( & metrics:: BALANCES_CACHE_MISSES ) ;
300
- let justified_block = self
301
- . store
302
- . get_blinded_block ( & self . justified_checkpoint . root )
303
- . map_err ( Error :: FailedToReadBlock ) ?
304
- . ok_or ( Error :: MissingBlock ( self . justified_checkpoint . root ) ) ?
305
- . deconstruct ( )
306
- . 0 ;
307
-
308
- let max_slot = self
309
- . justified_checkpoint
310
- . epoch
311
- . start_slot ( E :: slots_per_epoch ( ) ) ;
312
- let ( _, state) = self
373
+
374
+ // Justified state is reasonably useful to cache, it might be finalized soon.
375
+ let update_cache = true ;
376
+ let state = self
313
377
. store
314
- . get_advanced_hot_state (
315
- self . justified_checkpoint . root ,
316
- max_slot,
317
- justified_block. state_root ( ) ,
318
- )
378
+ . get_hot_state ( & self . justified_state_root , update_cache)
319
379
. map_err ( Error :: FailedToReadState ) ?
320
- . ok_or_else ( || Error :: MissingState ( justified_block . state_root ( ) ) ) ?;
380
+ . ok_or_else ( || Error :: MissingState ( self . justified_state_root ) ) ?;
321
381
322
382
self . justified_balances = JustifiedBalances :: from_justified_state ( & state) ?;
323
383
}
324
384
325
385
Ok ( ( ) )
326
386
}
327
387
328
- fn set_unrealized_justified_checkpoint ( & mut self , checkpoint : Checkpoint ) {
388
+ fn set_unrealized_justified_checkpoint ( & mut self , checkpoint : Checkpoint , state_root : Hash256 ) {
329
389
self . unrealized_justified_checkpoint = checkpoint;
390
+ self . unrealized_justified_state_root = state_root;
330
391
}
331
392
332
393
fn set_unrealized_finalized_checkpoint ( & mut self , checkpoint : Checkpoint ) {
@@ -346,18 +407,48 @@ where
346
407
}
347
408
}
348
409
349
- pub type PersistedForkChoiceStore = PersistedForkChoiceStoreV17 ;
410
+ pub type PersistedForkChoiceStore = PersistedForkChoiceStoreV28 ;
350
411
351
412
/// A container which allows persisting the `BeaconForkChoiceStore` to the on-disk database.
352
- #[ superstruct( variants( V17 ) , variant_attributes( derive( Encode , Decode ) ) , no_enum) ]
413
+ #[ superstruct(
414
+ variants( V17 , V28 ) ,
415
+ variant_attributes( derive( Encode , Decode ) ) ,
416
+ no_enum
417
+ ) ]
353
418
pub struct PersistedForkChoiceStore {
419
+ /// The balances cache was removed from disk storage in schema V28.
420
+ #[ superstruct( only( V17 ) ) ]
354
421
pub balances_cache : BalancesCacheV8 ,
355
422
pub time : Slot ,
356
423
pub finalized_checkpoint : Checkpoint ,
357
424
pub justified_checkpoint : Checkpoint ,
425
+ /// The justified balances were removed from disk storage in schema V28.
426
+ #[ superstruct( only( V17 ) ) ]
358
427
pub justified_balances : Vec < u64 > ,
428
+ /// The justified state root is stored so that it can be used to load the justified balances.
429
+ #[ superstruct( only( V28 ) ) ]
430
+ pub justified_state_root : Hash256 ,
359
431
pub unrealized_justified_checkpoint : Checkpoint ,
432
+ #[ superstruct( only( V28 ) ) ]
433
+ pub unrealized_justified_state_root : Hash256 ,
360
434
pub unrealized_finalized_checkpoint : Checkpoint ,
361
435
pub proposer_boost_root : Hash256 ,
362
436
pub equivocating_indices : BTreeSet < u64 > ,
363
437
}
438
+
439
+ // Convert V28 to V17 by adding balances and removing justified state roots.
440
+ impl From < ( PersistedForkChoiceStoreV28 , JustifiedBalances ) > for PersistedForkChoiceStoreV17 {
441
+ fn from ( ( v28, balances) : ( PersistedForkChoiceStoreV28 , JustifiedBalances ) ) -> Self {
442
+ Self {
443
+ balances_cache : Default :: default ( ) ,
444
+ time : v28. time ,
445
+ finalized_checkpoint : v28. finalized_checkpoint ,
446
+ justified_checkpoint : v28. justified_checkpoint ,
447
+ justified_balances : balances. effective_balances ,
448
+ unrealized_justified_checkpoint : v28. unrealized_justified_checkpoint ,
449
+ unrealized_finalized_checkpoint : v28. unrealized_finalized_checkpoint ,
450
+ proposer_boost_root : v28. proposer_boost_root ,
451
+ equivocating_indices : v28. equivocating_indices ,
452
+ }
453
+ }
454
+ }
0 commit comments