Skip to content

Commit 0367fc0

Browse files
authored
Merge pull request #17874 from MinaProtocol/cjjdespres/rework-genesis-population
Rework, speed up root ledger population from genesis
2 parents f7cc8f9 + af98edb commit 0367fc0

File tree

14 files changed

+123
-71
lines changed

14 files changed

+123
-71
lines changed

changes/17874.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
This PR eliminates unnecessary genesis ledger rehashing when bootstrapping from
2+
genesis, speeding up that process by about 1.5 minutes directly, depending on
3+
hardware.
4+
5+
This PR also fixes a related bug: the initial best tip network would formerly
6+
always fail on mainnet when bootstrapping from genesis, due to the daemon
7+
becoming unresponsive while rehashing the genesis ledger. This would delay
8+
startup by an additional number of minutes, cause the daemon to report itself as
9+
synced while its best tip was still at genesis until the next best tip query
10+
succeeded, and cause confusing behaviour in rosetta. This initial query should
11+
now only fail under very specific poor network conditions.

src/app/dump_blocks/dump_blocks.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,11 @@ let output_block : type a. a -> a codec io -> unit =
8282
*)
8383
let f (type a) ?parent (outputs : a codec io list) make_breadcrumb =
8484
Async.Thread_safe.block_on_async_exn (fun () ->
85-
let frontier = create_frontier ~epoch_ledger_backing_type:Stable_db () in
86-
let root = Full_frontier.root frontier in
8785
let open Async_kernel.Deferred.Let_syntax in
86+
let%bind frontier =
87+
create_frontier ~epoch_ledger_backing_type:Stable_db ()
88+
in
89+
let root = Full_frontier.root frontier in
8890
let%map breadcrumb = make_breadcrumb root in
8991
List.iter outputs ~f:(fun output ->
9092
let module Enc = (val output.encoding) in

src/lib/consensus/proof_of_stake.ml

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2666,14 +2666,9 @@ module Make_str (A : Wire_types.Concrete) = struct
26662666
| Ledger_snapshot.Ledger_root ledger ->
26672667
Ok ledger
26682668
| Ledger_snapshot.Genesis_epoch_ledger packed ->
2669-
let fresh_root_ledger =
2670-
Mina_ledger.Ledger.Root.create ~logger
2671-
~config:snapshot_config
2672-
~depth:Context.constraint_constants.ledger_depth
2673-
()
2674-
in
2675-
Genesis_ledger.Packed.populate_root packed
2676-
fresh_root_ledger )
2669+
Genesis_ledger.Packed.create_root packed
2670+
~config:snapshot_config
2671+
~depth:Context.constraint_constants.ledger_depth () )
26772672
in
26782673
match snapshot_id with
26792674
| Staking_epoch_snapshot ->

src/lib/genesis_ledger/genesis_ledger.ml

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,19 @@ module Balances (Balances : Intf.Named_balances_intf) = struct
6666
end
6767

6868
module Utils = struct
69-
let populate_root_with_backing_root genesis_mask ~src ~dest =
70-
let open Or_error.Let_syntax in
69+
(* Create a new [Ledger.Root.t] ledger with the components of a root
70+
backing_ledger for a genesis ledger. These components are the underlying
71+
root ledger and the stored mask on top of that root that is presented to
72+
users of the genesis root. The mask is passed in to this function so we can
73+
assert that there are no uncommitted changes to it, so we can simply
74+
checkpoint the root instead of performing a much slower account transfer. *)
75+
let create_root_from_backing_root genesis_mask root ~config ~depth () =
7176
assert (
7277
Ledger_hash.equal
7378
(Ledger.merkle_root genesis_mask)
74-
(Ledger.Root.merkle_root src) ) ;
75-
let%map _root =
76-
Ledger_transfer_any.transfer_accounts
77-
~src:(Ledger.Root.as_unmasked src)
78-
~dest:(Ledger.Root.as_unmasked dest)
79-
in
80-
dest
79+
(Ledger.Root.merkle_root root) ) ;
80+
assert (Ledger.Root.depth root = depth) ;
81+
Ledger.Root.create_checkpoint ~config root () |> Or_error.return
8182

8283
let keypair_of_account_record_exn (private_key, account) =
8384
let open Account in
@@ -163,11 +164,12 @@ module Make (Inputs : Intf.Ledger_input_intf) : Intf.S = struct
163164

164165
let t = Lazy.map ~f:snd backing_ledger
165166

166-
let populate_root root =
167+
let create_root ~config ~depth () =
167168
let backing_ledger, mask = Lazy.force backing_ledger in
168169
match backing_ledger with
169170
| `Ephemeral ledger ->
170171
let open Or_error.Let_syntax in
172+
let root = Ledger.Root.create ~logger ~config ~depth () in
171173
(* We are transferring to an unmasked view of the root, so this is
172174
used solely for the transfer side effect *)
173175
let%map _dest =
@@ -176,7 +178,7 @@ module Make (Inputs : Intf.Ledger_input_intf) : Intf.S = struct
176178
in
177179
root
178180
| `Root ledger ->
179-
populate_root_with_backing_root mask ~src:ledger ~dest:root
181+
create_root_from_backing_root mask ledger ~config ~depth ()
180182

181183
include Utils
182184

@@ -214,7 +216,7 @@ module Packed = struct
214216

215217
let t ((module L) : t) = L.t
216218

217-
let populate_root ((module L) : t) ledger = L.populate_root ledger
219+
let create_root ((module L) : t) = L.create_root
218220

219221
let depth ((module L) : t) = L.depth
220222

@@ -258,9 +260,9 @@ end) : Intf.S = struct
258260

259261
include Utils
260262

261-
let populate_root dest =
263+
let create_root ~config ~depth () =
262264
let genesis_root, mask = Lazy.force backing_ledger in
263-
populate_root_with_backing_root mask ~src:genesis_root ~dest
265+
create_root_from_backing_root mask genesis_root ~config ~depth ()
264266

265267
let find_account_record_exn ~f =
266268
find_account_record_exn ~f (Lazy.force accounts)

src/lib/genesis_ledger/intf.ml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,12 @@ end
7474
module type S = sig
7575
val t : Mina_ledger.Ledger.t Lazy.t
7676

77-
(** Populate a root ledger with the content of the genesis ledger *)
78-
val populate_root :
79-
Mina_ledger.Ledger.Root.t -> Mina_ledger.Ledger.Root.t Or_error.t
77+
(** Create a new root ledger that is equal in state to the genesis ledger *)
78+
val create_root :
79+
config:Mina_ledger.Ledger.Root.Config.t
80+
-> depth:int
81+
-> unit
82+
-> Mina_ledger.Ledger.Root.t Or_error.t
8083

8184
val depth : int
8285

src/lib/genesis_proof/genesis_proof.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ module T = struct
115115
let genesis_ledger { genesis_ledger; _ } =
116116
Genesis_ledger.Packed.t genesis_ledger
117117

118-
let populate_root { genesis_ledger; _ } =
119-
Genesis_ledger.Packed.populate_root genesis_ledger
118+
let create_root { genesis_ledger; _ } =
119+
Genesis_ledger.Packed.create_root genesis_ledger
120120

121121
let genesis_epoch_data { genesis_epoch_data; _ } = genesis_epoch_data
122122

src/lib/mina_lmdb_storage/block.ml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,8 @@ let%test_module "Block storage tests" =
182182
Quickcheck.test (gen_breadcrumb ~verifier ()) ~trials:1
183183
~f:(fun make_breadcrumb ->
184184
let frontier =
185-
create_frontier ~epoch_ledger_backing_type:Stable_db ()
185+
Async.Thread_safe.block_on_async_exn (fun () ->
186+
create_frontier ~epoch_ledger_backing_type:Stable_db () )
186187
in
187188
let root = Full_frontier.root frontier in
188189
let reader, writer = Pipe.create () in
@@ -211,7 +212,8 @@ let%test_module "Block storage tests" =
211212
Quickcheck.test (gen_breadcrumb ~verifier ()) ~trials:4
212213
~f:(fun make_breadcrumb ->
213214
let frontier =
214-
create_frontier ~epoch_ledger_backing_type:Stable_db ()
215+
Async.Thread_safe.block_on_async_exn (fun () ->
216+
create_frontier ~epoch_ledger_backing_type:Stable_db () )
215217
in
216218
let root = Full_frontier.root frontier in
217219
let reader, writer = Pipe.create () in

src/lib/transition_frontier/full_frontier/full_frontier.ml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,6 +987,7 @@ module For_tests = struct
987987

988988
let create_frontier ~epoch_ledger_backing_type () =
989989
let open Core in
990+
let open Async.Deferred.Let_syntax in
990991
let epoch_ledger_location =
991992
Filename.temp_dir_name ^/ "epoch_ledger"
992993
^ (Uuid_unix.create () |> Uuid.to_string)
@@ -1025,7 +1026,9 @@ module For_tests = struct
10251026
~directory:(Filename.temp_file "snarked_ledger" "")
10261027
~ledger_depth
10271028
in
1028-
Persistent_root.reset_to_genesis_exn ~precomputed_values persistent_root ;
1029+
let%map () =
1030+
Persistent_root.reset_to_genesis_exn persistent_root ~precomputed_values
1031+
in
10291032
let persistent_root_instance =
10301033
Persistent_root.create_instance_exn persistent_root
10311034
in

src/lib/transition_frontier/full_frontier/full_frontier.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ module For_tests : sig
8989
val create_frontier :
9090
epoch_ledger_backing_type:Mina_ledger.Ledger.Root.Config.backing_type
9191
-> unit
92-
-> t
92+
-> t Async_kernel.Deferred.t
9393

9494
val clean_up_persistent_root : frontier:t -> unit
9595

src/lib/transition_frontier/persistent_root/persistent_root.ml

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -309,17 +309,38 @@ let with_instance_exn t ~f =
309309
let x = f instance in
310310
Instance.close instance ; x
311311

312-
let reset_to_genesis_exn t ~precomputed_values =
312+
(** Clear the factory directory and recreate the snarked ledger instance for
313+
this factory with [create_root] and [setup] *)
314+
let reset_factory_root_exn t ~create_root ~setup =
315+
let open Async.Deferred.Let_syntax in
313316
assert (Option.is_none t.instance) ;
314-
Mina_stdlib_unix.File_system.rmrf t.directory ;
315-
with_instance_exn t ~f:(fun instance ->
316-
ignore
317-
( Precomputed_values.populate_root precomputed_values
318-
(Instance.snarked_ledger instance)
319-
|> Or_error.map ~f:Ledger.Root.as_unmasked
320-
: Ledger.Any_ledger.witness Or_error.t ) ;
321-
Instance.set_root_identifier instance
322-
(genesis_root_identifier
323-
~genesis_state_hash:
324-
(Precomputed_values.genesis_state_hashes precomputed_values)
325-
.state_hash ) )
317+
(* Certain database initialization methods, e.g. creation from a checkpoint,
318+
depend on the parent directory existing and the target directory _not_
319+
existing. *)
320+
let%bind () = Mina_stdlib_unix.File_system.remove_dir t.directory in
321+
let%map () = Mina_stdlib_unix.File_system.create_dir t.directory in
322+
let root =
323+
create_root
324+
~config:(Instance.Config.snarked_ledger t)
325+
~depth:t.ledger_depth ()
326+
|> Or_error.ok_exn
327+
in
328+
Ledger.Root.close root ;
329+
with_instance_exn t ~f:setup
330+
331+
let reset_to_genesis_exn t ~precomputed_values =
332+
let open Async.Deferred.Let_syntax in
333+
let logger = t.logger in
334+
[%log debug] "Resetting snarked_root in $directory to genesis"
335+
~metadata:[ ("directory", `String t.directory) ] ;
336+
let%map () =
337+
reset_factory_root_exn t
338+
~create_root:(Precomputed_values.create_root precomputed_values)
339+
~setup:(fun instance ->
340+
Instance.set_root_identifier instance
341+
(genesis_root_identifier
342+
~genesis_state_hash:
343+
(Precomputed_values.genesis_state_hashes precomputed_values)
344+
.state_hash ) )
345+
in
346+
[%log debug] "Finished resetting snarked_root to genesis"

0 commit comments

Comments
 (0)