@@ -166,17 +166,67 @@ pub fn upgrade_to_v24<T: BeaconChainTypes>(
166166 //
167167 // If the node has been running for a while the `anchor_slot` might be less than the finalized
168168 // checkpoint. This upgrade constructs a grid only with unfinalized states, rooted in the
169- // current finalize state. So we set the `anchor_slot` to `split.slot` to root the grid in the
169+ // current finalized state. So we set the `anchor_slot` to `split.slot` to root the grid in the
170170 // current finalized state. Each migration sets the split to
171171 // ```
172172 // Split { slot: finalized_state.slot(), state_root: finalized_state_root }
173173 // ```
174174 {
175175 let anchor_info = db. get_anchor_info ( ) ;
176- let mut new_anchor_info = anchor_info. clone ( ) ;
177- new_anchor_info. anchor_slot = hot_hdiff_start_slot;
178- // Update the anchor in disk atomically if migration is successful
179- migrate_ops. push ( db. compare_and_set_anchor_info ( anchor_info, new_anchor_info) ?) ;
176+
177+ // If the node is already an archive node, we can set the anchor slot to 0 and copy
178+ // snapshots and diffs from the freezer DB to the hot DB in order to establish an initial
179+ // hot grid that is aligned/"perfect" (no `start_slot`/`anchor_slot` to worry about).
180+ let dummy_start_slot = Slot :: new ( 0 ) ;
181+ let closest_layer_points = db
182+ . hierarchy
183+ . closest_layer_points ( split. slot , dummy_start_slot) ;
184+
185+ let previous_snapshot_slot =
186+ closest_layer_points
187+ . iter ( )
188+ . copied ( )
189+ . min ( )
190+ . ok_or ( Error :: MigrationError (
191+ "closest_layer_points must not be empty" . to_string ( ) ,
192+ ) ) ?;
193+
194+ // If we have the previous snapshot stored in the freezer DB, then we can use this
195+ // optimisation.
196+ if previous_snapshot_slot >= anchor_info. state_upper_limit {
197+ info ! (
198+ %previous_snapshot_slot,
199+ split_slot = %split. slot,
200+ "Aligning hot diff grid to freezer"
201+ ) ;
202+
203+ // Set anchor slot to 0 in case it was set to something else by a previous checkpoint
204+ // sync.
205+ let mut new_anchor_info = anchor_info. clone ( ) ;
206+ new_anchor_info. anchor_slot = Slot :: new ( 0 ) ;
207+
208+ // Update the anchor on disk atomically if migration is successful
209+ migrate_ops. push ( db. compare_and_set_anchor_info ( anchor_info, new_anchor_info) ?) ;
210+
211+ // Copy each of the freezer layers to the hot DB in slot ascending order.
212+ for layer_slot in closest_layer_points. into_iter ( ) . rev ( ) {
213+ let mut freezer_state = db. load_cold_state_by_slot ( layer_slot) ?;
214+
215+ let state_root = freezer_state. canonical_root ( ) ?;
216+
217+ let mut state_ops = vec ! [ ] ;
218+ db. store_hot_state ( & state_root, & freezer_state, & mut state_ops) ?;
219+ db. hot_db . do_atomically ( state_ops) ?;
220+ }
221+ } else {
222+ // Otherwise for non-archive nodes, set the anchor slot for the hot grid to the current
223+ // split slot (the oldest slot available).
224+ let mut new_anchor_info = anchor_info. clone ( ) ;
225+ new_anchor_info. anchor_slot = hot_hdiff_start_slot;
226+
227+ // Update the anchor in disk atomically if migration is successful
228+ migrate_ops. push ( db. compare_and_set_anchor_info ( anchor_info, new_anchor_info) ?) ;
229+ }
180230 }
181231
182232 let state_summaries_dag = new_dag :: < T > ( & db) ?;
0 commit comments