From 0e1be5911f88046062e582a4b1ee9b68a806abf1 Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Sun, 25 May 2025 08:36:49 +0200 Subject: [PATCH 1/2] DAL: remove old configuration migration code --- src/lib_dal_node/configuration_file.ml | 263 +------------------------ 1 file changed, 6 insertions(+), 257 deletions(-) diff --git a/src/lib_dal_node/configuration_file.ml b/src/lib_dal_node/configuration_file.ml index 708dcc285ae1..74ef2d0e64bd 100644 --- a/src/lib_dal_node/configuration_file.ml +++ b/src/lib_dal_node/configuration_file.ml @@ -102,8 +102,6 @@ let default_public_addr = let open Gossipsub.Transport_layer.Default_parameters.P2p_config in P2p_point.Id.of_string_exn ~default_port:listening_port "127.0.0.1" -let default_neighbors = [] - let default_peers = [] let default_expected_pow = @@ -116,9 +114,6 @@ let default_endpoint = Uri.of_string "http://localhost:8732" let default_metrics_port = Gossipsub.Transport_layer.Default_parameters.P2p_config.listening_port + 1 -let default_metrics_addr = - P2p_point.Id.of_string_exn ~default_port:default_metrics_port "0.0.0.0" - let default_history_mode = Rolling {blocks = `Auto} let default_experimental_features = () @@ -148,13 +143,6 @@ let default = ignore_l1_config_peers = false; } -let neighbor_encoding : neighbor Data_encoding.t = - let open Data_encoding in - conv - (fun {addr; port} -> (addr, port)) - (fun (addr, port) -> {addr; port}) - (obj2 (req "rpc-addr" string) (req "rpc-port" uint16)) - let uri_encoding : Uri.t Data_encoding.t = let open Data_encoding in conv_with_guard @@ -353,249 +341,6 @@ let encoding : t Data_encoding.t = bool default.ignore_l1_config_peers))) -module V0 = struct - type v0_profile = - | Bootstrap - | Controller of Controller_profiles.t - | Random_observer - - let v0_profile_encoding = - let open Data_encoding in - union - [ - case - ~title:"Bootstrap node" - (Tag 1) - (obj1 (req "kind" (constant "bootstrap"))) - (function Bootstrap -> Some () | _ -> None) - (function () -> Bootstrap); - case - ~title:"Controller" - (Tag 2) - (obj2 - (req "kind" (constant "controller")) - (req "controller_profiles" Controller_profiles.encoding)) - (function - | Controller controller_profiles -> Some ((), controller_profiles) - | _ -> None) - (function (), controller_profiles -> Controller controller_profiles); - case - ~title:"Random_observer" - (Tag 3) - (obj1 (req "kind" (constant "random_observer"))) - (function Random_observer -> Some () | _ -> None) - (function () -> Random_observer); - ] - - let to_latest_profile = function - | Random_observer -> Profile_manager.Random_observer - | Bootstrap -> Profile_manager.bootstrap - | Controller profile -> Profile_manager.controller profile - - (* Legacy V0 configuration type used solely for migration purposes. - - This type represents the legacy (V0) version of the configuration, - originally defined as a record. It is intentionally rewritten as a tuple - for the following reasons: - - - Simplified Encoding/Decoding: Using a tuple allows removing - [Data_encoding.conv] and its field-by-field mapping, significantly reducing - boilerplate in the migration code. - - - Read-Only & Migration-Only: The V0 type is no longer edited or used - beyond JSON decoding and transformation into the current configuration - version. Record semantics (field names, accessors) are unnecessary. - - This design reflects the temporary, transitional nature of the V0 - configuration and isolates legacy logic from the active codebase. *) - type t = tup1 * tup2 - - and tup1 = - string (* data_dir *) - * P2p_point.Id.t (* rpc_addr *) - * P2p_point.Id.t (* listen_addr *) - * P2p_point.Id.t (* public_addr *) - * neighbor list (* neighbors *) - * string list (* peers *) - * float (* expected_pow *) - * string (* network_name *) - * Uri.t (* endpoint *) - * P2p_point.Id.t (* metrics_addr *) - - and tup2 = history_mode (* history_mode *) * v0_profile (* profile *) - - let encoding : t Data_encoding.t = - let open Data_encoding in - merge_objs - (obj10 - (dft "data-dir" string default_data_dir) - (dft "rpc-addr" P2p_point.Id.encoding default_rpc_addr) - (dft "net-addr" P2p_point.Id.encoding default_listen_addr) - (dft "public-addr" P2p_point.Id.encoding default_listen_addr) - (dft "neighbors" (list neighbor_encoding) default_neighbors) - (dft "peers" (list string) default_peers) - (dft "expected-pow" float default_expected_pow) - (dft "network-name" string legacy_network_name) - (dft "endpoint" uri_encoding default_endpoint) - (dft "metrics-addr" P2p_point.Id.encoding default_metrics_addr)) - (obj2 - (dft "history_mode" history_mode_encoding default_history_mode) - (dft - "profiles" - v0_profile_encoding - (Controller Controller_profiles.empty))) - - let to_latest_version - ( ( data_dir, - rpc_addr, - listen_addr, - public_addr, - _neighbors, - peers, - expected_pow, - _network_name, - endpoint, - metrics_addr ), - (history_mode, profile) ) = - { - data_dir; - rpc_addr; - listen_addr; - public_addr; - peers; - expected_pow; - endpoint; - metrics_addr = Some metrics_addr; - history_mode; - profile = to_latest_profile profile; - version = current_version; - service_name = None; - service_namespace = None; - experimental_features = default_experimental_features; - fetch_trusted_setup = true; - verbose = false; - ignore_l1_config_peers = false; - http_backup_uris = []; - trust_http_backup_uris = false; - } -end - -module V1 = struct - (* Legacy V1 configuration type used solely for migration purposes. - - This type represents the legacy (V1) version of the configuration, - originally defined as a record. It is intentionally rewritten as a tuple - for the following reasons: - - - Simplified Encoding/Decoding: Using a tuple allows removing - [Data_encoding.conv] and its field-by-field mapping, significantly reducing - boilerplate in the migration code. - - - Read-Only & Migration-Only: The V1 type is no longer edited or used - beyond JSON decoding and transformation into the current configuration - version. Record semantics (field names, accessors) are unnecessary. - - This design reflects the temporary, transitional nature of the V1 - configuration and isolates legacy logic from the active codebase. *) - type t = tup1 * tup2 - - and tup1 = - string (* data_dir *) - * P2p_point.Id.t (* rpc_addr *) - * P2p_point.Id.t (*listen_addr *) - * P2p_point.Id.t (* public_addr *) - * neighbor list (* neighbors *) - * string list (* peers *) - * float (* expected_pow *) - * string (*network_name *) - * Uri.t (*endpoint *) - * P2p_point.Id.t option (*metrics_addr *) - - and tup2 = - history_mode (* history_mode *) - * V0.v0_profile (* profile *) - * int (*version *) - * string option (* service_name *) - * string option (*service_namespace *) - * experimental_features (* experimental_features *) - * bool (* fetch_trusted_setup *) - * bool (* verbose *) - - let encoding : t Data_encoding.t = - let open Data_encoding in - merge_objs - (obj10 - (dft "data-dir" string default_data_dir) - (dft "rpc-addr" P2p_point.Id.encoding default_rpc_addr) - (dft "net-addr" P2p_point.Id.encoding default_listen_addr) - (dft "public-addr" P2p_point.Id.encoding default_listen_addr) - (dft "neighbors" (list neighbor_encoding) default_neighbors) - (dft "peers" (list string) default_peers) - (dft "expected-pow" float default_expected_pow) - (dft "network-name" string legacy_network_name) - (dft "endpoint" uri_encoding default_endpoint) - (dft "metrics-addr" (Encoding.option P2p_point.Id.encoding) None)) - (obj8 - (dft "history_mode" history_mode_encoding default_history_mode) - (dft - "profiles" - V0.v0_profile_encoding - (V0.Controller Controller_profiles.empty)) - (req "version" int31) - (dft "service_name" (Data_encoding.option Data_encoding.string) None) - (dft - "service_namespace" - (Data_encoding.option Data_encoding.string) - None) - (dft - "experimental_features" - experimental_features_encoding - default_experimental_features) - (dft "fetch_trusted_setup" bool true) - (dft "verbose" bool default.verbose)) - - let to_latest_version - ( ( data_dir, - rpc_addr, - listen_addr, - public_addr, - _neighbors, - peers, - expected_pow, - _network_name, - endpoint, - metrics_addr ), - ( history_mode, - profile, - version, - service_name, - service_namespace, - experimental_features, - fetch_trusted_setup, - verbose ) ) = - { - data_dir; - rpc_addr; - listen_addr; - public_addr; - peers; - expected_pow; - endpoint; - metrics_addr; - history_mode; - profile = V0.to_latest_profile profile; - version; - service_name; - service_namespace; - experimental_features; - fetch_trusted_setup; - verbose; - ignore_l1_config_peers = false; - http_backup_uris = []; - trust_http_backup_uris = false; - } -end - type error += DAL_node_unable_to_write_configuration_file of string let () = @@ -636,8 +381,12 @@ let load = let config_versions = [ (2, destruct encoding); - (1, fun json -> destruct V1.encoding json |> V1.to_latest_version); - (0, fun json -> destruct V0.encoding json |> V0.to_latest_version); + (* We can add cases here of the form: + + , fun json -> destruct Vx.encoding json |> Vx.to_latest_version) + + If we need to migrate the configuration format. See how it was done for previous + migrations for more insight. *) ] in let rec try_decode json = function -- GitLab From 5cb4943f39ee077c4dd872f0a357f896e25d7a79 Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Sun, 25 May 2025 12:46:47 +0200 Subject: [PATCH 2/2] DAL/Node: remove the skip lists KVS store now that we migrated to SQLite --- src/lib_dal_node/store.ml | 259 ++------------------------------------ 1 file changed, 7 insertions(+), 252 deletions(-) diff --git a/src/lib_dal_node/store.ml b/src/lib_dal_node/store.ml index 68a82000d6bc..10a5f219b2e8 100644 --- a/src/lib_dal_node/store.ml +++ b/src/lib_dal_node/store.ml @@ -519,28 +519,21 @@ end) module Storage_backend = struct (** The type [kind] represents the available storage backend types. - [Legacy] refers to the current implementation using KVS. - [SQLite3] corresponds to the new implementation integrating a + [SQLite3] corresponds to the current implementation integrating a [Sqlite.t] database into the DAL node for storing skip list cells and whose purpose is to replace the [Kvs_skip_list_cells_store] module. *) - type kind = Legacy | SQLite3 + type kind = SQLite3 let encoding = let open Data_encoding in union [ - case - ~title:"legacy" - (Tag 0) - (constant "legacy") - (function Legacy -> Some () | _ -> None) - (fun () -> Legacy); case ~title:"sqlite3" (Tag 1) (constant "sqlite3") - (function SQLite3 -> Some () | _ -> None) + (function SQLite3 -> Some ()) (fun () -> SQLite3); ] @@ -581,34 +574,6 @@ module Storage_backend = struct | _ -> None) (fun (current, specified) -> Storage_backend_mismatch {current; specified}) - - (** [set ?force store ~sqlite3_backend] configures the storage - backend based on the value of [sqlite3_backend]. If - [sqlite3_backend] is [true], it sets the [SQLite3] storage - backend; otherwise, it sets the [Legacy] backend. This function - fails with [Storage_backend_mismatch] if the previously used - storage backend does not match the one specified by - [sqlite3_backend] and [force] is false. If [force] is true, then - overwrite the storage backend without taking into account the - previous one. *) - let set ?(force = false) store ~sqlite3_backend = - let open Lwt_result_syntax in - let* current_opt = load store in - let specified = if sqlite3_backend then SQLite3 else Legacy in - (* FIXME: https://gitlab.com/tezos/tezos/-/issues/7528 - Update the following code according to the migration from KVS - to SQLite3 once it is done.*) - if force then - let+ () = save store specified in - specified - else - match current_opt with - | Some current -> - if current = specified then return current - else tzfail (Storage_backend_mismatch {current; specified}) - | None -> - let+ () = save store specified in - specified end (** Store context *) @@ -695,218 +660,12 @@ module Skip_list_cells = struct Dal_store_sqlite3.Skip_list_cells.schemas store end -let init_skip_list_cells_store base_dir = - (* We support at most 64 back-pointers, each of which takes 32 bytes. - The cells content itself takes less than 64 bytes. *) - let padded_encoded_cell_size = 64 * (32 + 1) in - (* A pointer hash is 32 bytes length, but because of the double - encoding in Dal_proto_types and then in skip_list_cells_store, we - have an extra 4 bytes for encoding the size. *) - let encoded_hash_size = 32 + 4 in - Kvs_skip_list_cells_store.init - ~node_store_dir:base_dir - ~skip_list_store_dir:Stores_dirs.skip_list_cells - ~padded_encoded_cell_size - ~encoded_hash_size - let cache_entry node_store commitment slot shares shard_proofs = Commitment_indexed_cache.replace node_store.cache commitment (slot, shares, shard_proofs) -let upgrade_from_v0_to_v1 ~base_dir = - let open Lwt_syntax in - let ( // ) = Filename.Infix.( // ) in - let* () = - Event.emit_store_upgrade_start - ~old_version:(Version.make 0) - ~new_version:(Version.make 1) - in - let rec move_directory_contents src dst = - let stream = Lwt_unix.files_of_directory src in - Lwt_stream.iter_s - (fun name -> - Lwt.catch - (fun () -> - match name with - | "." | ".." -> Lwt.return_unit - | file_name -> ( - let src_path = src // file_name in - let dst_path = dst // file_name in - let* stats = Lwt_unix.lstat src_path in - match stats.st_kind with - | Unix.S_REG | S_LNK -> Lwt_unix.rename src_path dst_path - | S_DIR -> - let* () = Lwt_unix.mkdir dst_path stats.st_perm in - let* () = move_directory_contents src_path dst_path in - Lwt_utils_unix.remove_dir src_path - | _ -> Lwt.return_unit)) - (fun exn -> - let src_path = src // name in - let dst_path = dst // name in - let* () = - Event.emit_store_upgrade_error_moving_directory - ~src:src_path - ~dst:dst_path - ~exn:(Printexc.to_string exn) - in - Lwt.return_unit)) - stream - in - let move_and_rename old_path new_path = - let* () = - Lwt.catch - (fun () -> Lwt_unix.mkdir new_path 0o700) - (fun exn -> - let* () = - Event.emit_store_upgrade_error_creating_directory - ~path:new_path - ~exn:(Printexc.to_string exn) - in - Lwt.return ()) - in - let* () = move_directory_contents old_path new_path in - Lwt_utils_unix.remove_dir old_path - in - (* Remove the Irmin store, that is, delete the "index" directory and all files - that start with "store". *) - let stream = Lwt_unix.files_of_directory base_dir in - let irmin_prefix = "store" in - let* () = - Lwt_stream.iter_p - (fun name -> - let path = Filename.Infix.(base_dir // name) in - if String.equal name "index" then - (* that's Irmin related *) - Lwt_utils_unix.remove_dir path - else if String.starts_with ~prefix:irmin_prefix name then - Lwt_unix.unlink path - else if String.equal name "shard_store" then - (* The V0 shard store uses a different layout. We just delete it, for - simplicity. *) - Lwt_utils_unix.remove_dir path - else if String.equal name "skip_list" then - (* The skip list store is not handled by this module, but we treat this - case here, for simplicity *) - let new_path = Filename.Infix.(base_dir // "skip_list_store") in - move_and_rename path new_path - else Lwt.return ()) - stream - in - Event.emit_store_upgraded - ~old_version:(Version.make 0) - ~new_version:(Version.make 1) - -let upgrade_from_v1_to_v2 ~base_dir = - let open Lwt_result_syntax in - let*! () = - Event.emit_store_upgrade_start - ~old_version:(Version.make 1) - ~new_version:(Version.make 2) - in - (* Initialize both stores and migrate. *) - let* storage_backend_store = Storage_backend.init ~root_dir:base_dir in - let* storage_backend = Storage_backend.load storage_backend_store in - let*! res = - match storage_backend with - | None | Some Storage_backend.Legacy -> - let* kvs_store = init_skip_list_cells_store base_dir in - let* sql_store = init_sqlite_skip_list_cells_store base_dir in - let* () = - Store_migrations.migrate_skip_list_store kvs_store sql_store - in - let* () = Kvs_skip_list_cells_store.close kvs_store in - let*! () = Dal_store_sqlite3.Skip_list_cells.close sql_store in - return_unit - | Some SQLite3 -> - (* If a previous sqlite database has been created using the - `--sqlite3-backend` experimental flag. We simply move it to the - new destination path. *) - let open Filename.Infix in - let mv name = - let previous_path = base_dir // name in - let new_path = base_dir // Stores_dirs.skip_list_cells // name in - if Sys.(file_exists previous_path) then - let*! () = - if not (Sys.file_exists new_path) then - Lwt_utils_unix.copy_file ~src:previous_path ~dst:new_path () - else Lwt.return_unit - in - let*! () = Lwt_unix.unlink previous_path in - return_unit - else return_unit - in - let*! () = - Lwt_utils_unix.create_dir (base_dir // Stores_dirs.skip_list_cells) - in - let* () = mv Dal_store_sqlite3.sqlite_file_name in - let* () = mv (Dal_store_sqlite3.sqlite_file_name ^ "-shm") in - let* () = mv (Dal_store_sqlite3.sqlite_file_name ^ "-wal") in - return_unit - in - match res with - | Ok () -> - (* Set the new storage backend to sqlite3. *) - let* (_ : Storage_backend.kind) = - Storage_backend.set - storage_backend_store - ~sqlite3_backend:true - ~force:true - in - (* Remove the Stores_dirs.skip_list_cells directory. *) - let open Filename.Infix in - let store_dir = base_dir // Stores_dirs.skip_list_cells in - let*! () = Lwt_utils_unix.remove_dir (store_dir // "hashes") in - let*! () = Lwt_utils_unix.remove_dir (store_dir // "cells") in - (* The storage upgrade has been done. *) - let*! () = - Event.emit_store_upgraded - ~old_version:(Version.make 1) - ~new_version:(Version.make 2) - in - return_unit - | Error err -> - (* Clean the sqlite store unless the storage backend was already set to sqlite. *) - let* storage_backend = Storage_backend.load storage_backend_store in - let*! () = - match storage_backend with - | None | Some Legacy -> - let rm name = - let open Filename.Infix in - let path = base_dir // Stores_dirs.skip_list_cells // name in - Lwt_unix.unlink path - in - let*! () = rm Dal_store_sqlite3.sqlite_file_name in - let*! () = rm (Dal_store_sqlite3.sqlite_file_name ^ "-shm") in - rm (Dal_store_sqlite3.sqlite_file_name ^ "-wal") - | Some SQLite3 -> Lwt.return_unit - in - (* The store upgrade failed. *) - let*! () = Event.emit_store_upgrade_error () in - Format.eprintf "%a" Error_monad.pp_print_trace err ; - fail err - -(* Returns [upgradable old_version new_version] returns an upgrade function if - the store is upgradable from [old_version] to [new_version]. Otherwise it - returns [None]. *) -let upgradable old_version new_version : - (base_dir:string -> unit tzresult Lwt.t) option = - let open Lwt_result_syntax in - match (old_version, new_version) with - | 0, 1 -> - Some - (fun ~base_dir -> - let*! () = upgrade_from_v0_to_v1 ~base_dir in - return_unit) - | 0, 2 -> - Some - (fun ~base_dir -> - let*! () = upgrade_from_v0_to_v1 ~base_dir in - upgrade_from_v1_to_v2 ~base_dir) - | 1, 2 -> Some (fun ~base_dir -> upgrade_from_v1_to_v2 ~base_dir) - | _ -> None - (* Checks the version of the store with the respect to the current version. Returns [None] if the store does not need an upgrade and [Some upgrade] if the store is upgradable, where [upgrade] is a function that can @@ -927,14 +686,9 @@ let check_version_and_may_upgrade base_dir = in if Version.(equal version current_version) then return_unit else - match upgradable version Version.current_version with - | Some upgrade -> - let* () = upgrade ~base_dir in - Version.write_version_file ~base_dir - | None -> - tzfail - (Version.Invalid_data_dir_version - {actual = version; expected = Version.current_version}) + tzfail + (Version.Invalid_data_dir_version + {actual = version; expected = Version.current_version}) (** [init config] inits the store on the filesystem using the given [config]. *) @@ -945,6 +699,7 @@ let init config = let* slot_header_statuses = Statuses.init base_dir Stores_dirs.status in let* shards = Shards.init base_dir Stores_dirs.shard in let* slots = Slots.init base_dir Stores_dirs.slot in + let* () = Version.write_version_file ~base_dir in let traps = Traps.create ~capacity:Constants.traps_cache_size in let* last_processed_level = Last_processed_level.init ~root_dir:base_dir in let* first_seen_level = First_seen_level.init ~root_dir:base_dir in -- GitLab