diff --git a/src/node/main/node_config_file.ml b/src/node/main/node_config_file.ml index 4c7f3fe84..e11c8a887 100644 --- a/src/node/main/node_config_file.ml +++ b/src/node/main/node_config_file.ml @@ -257,7 +257,7 @@ let read fp = return default_config let write fp cfg = - Lwt_utils.create_dir ~perm:0o700 (Filename.dirname fp) >>= fun () -> + Node_data_version.ensure_data_dir (Filename.dirname fp) >>=? fun () -> Data_encoding_ezjsonm.write_file fp (Data_encoding.Json.construct encoding cfg) @@ -284,6 +284,8 @@ let update ?rpc_tls ?log_output cfg = + let data_dir = Utils.unopt ~default:cfg.data_dir data_dir in + Node_data_version.ensure_data_dir data_dir >>=? fun () -> let peer_table_size = map_option peer_table_size ~f:(fun i -> i, i / 4 * 3) in let unopt_list ~default = function @@ -343,8 +345,7 @@ let update output = Utils.unopt ~default:cfg.log.output log_output ; } in - { data_dir = Utils.unopt ~default:cfg.data_dir data_dir ; - net ; rpc ; log } + return { data_dir ; net ; rpc ; log } let resolve_addr ?default_port ?(passive = false) peer = let addr, port = Utils.parse_addr_port peer in diff --git a/src/node/main/node_config_file.mli b/src/node/main/node_config_file.mli index 0e391d51a..e84b78f0e 100644 --- a/src/node/main/node_config_file.mli +++ b/src/node/main/node_config_file.mli @@ -67,7 +67,7 @@ val update: ?cors_headers:string list -> ?rpc_tls:tls -> ?log_output:Logging.Output.t -> - t -> t + t -> t tzresult Lwt.t val to_string: t -> string val read: string -> t tzresult Lwt.t diff --git a/src/node/main/node_data_version.ml b/src/node/main/node_data_version.ml new file mode 100644 index 000000000..af58a460e --- /dev/null +++ b/src/node/main/node_data_version.ml @@ -0,0 +1,94 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2016. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +open Error_monad + +type t = string + +let data_version = "0.0.1" + +let version_encoding = Data_encoding.(obj1 (req "version" string)) + +let version_file_name = "version.json" + +let pp ppf version = Format.pp_print_string ppf version + +type error += Invalid_data_dir_version of t * t +type error += No_data_dir_version_file of string +type error += Could_not_read_data_dir_version of string + +let () = + register_error_kind + `Permanent + ~id: "invalidDataDirVersion" + ~title: "Invalid data directory version" + ~description: "The data directory version was not the one that was expected" + Data_encoding.(obj2 + (req "expectedVersion" string) + (req "actualVersion" string)) + (function + | Invalid_data_dir_version (expected, actual) -> + Some (expected, actual) + | _ -> None) + (fun (expected, actual) -> Invalid_data_dir_version (expected, actual)) ; + register_error_kind + `Permanent + ~id: "couldNotReadDataDirVersion" + ~title: "Could not read data directory version file" + ~description: "Data directory version file was invalid." + Data_encoding.(obj1 (req "versionPath" string)) + ~pp:(fun ppf path -> + Format.fprintf ppf + "Tried to read version file at '%s', \ + \ but the file could not be parsed." + path) + (function Could_not_read_data_dir_version path -> Some path | _ -> None) + (fun path -> Could_not_read_data_dir_version path); + register_error_kind + `Permanent + ~id: "noDataDirVersionFile" + ~title: "Data directory version file did not exist" + ~description: "Data directory version file did not exist" + Data_encoding.(obj1 (req "versionPath" string)) + ~pp:(fun ppf path -> + Format.fprintf ppf + "Expected to find data directory version file at '%s', \ + \ but the file did not exist." + path) + (function No_data_dir_version_file path -> Some path | _ -> None) + (fun path -> No_data_dir_version_file path) + +let version_file data_dir = + (Filename.concat data_dir version_file_name) + +let check_data_dir_version data_dir = + let version_file = version_file data_dir in + fail_unless (Sys.file_exists version_file) + (No_data_dir_version_file version_file) >>=? fun () -> + Data_encoding_ezjsonm.read_file version_file + |> trace (Could_not_read_data_dir_version version_file) >>=? fun json -> + begin + try return (Data_encoding.Json.destruct version_encoding json) + with _ -> fail (Could_not_read_data_dir_version version_file) + end >>=? fun version -> + fail_unless + (String.equal data_version version) + (Invalid_data_dir_version (data_version, version)) >>=? fun () -> + return () + +let ensure_data_dir data_dir = + if Sys.file_exists data_dir && + (Array.length (Sys.readdir data_dir)) > 0 + then + check_data_dir_version data_dir + else + Lwt_utils.create_dir ~perm:0o700 data_dir >>= fun () -> + Data_encoding_ezjsonm.write_file + (version_file data_dir) + (Data_encoding.Json.construct version_encoding data_version) diff --git a/src/node/main/node_data_version.mli b/src/node/main/node_data_version.mli new file mode 100644 index 000000000..75bf6ed1c --- /dev/null +++ b/src/node/main/node_data_version.mli @@ -0,0 +1,21 @@ +(**************************************************************************) +(* *) +(* Copyright (c) 2014 - 2016. *) +(* Dynamic Ledger Solutions, Inc. *) +(* *) +(* All rights reserved. No warranty, explicit or implicit, provided. *) +(* *) +(**************************************************************************) + +type t + +type error += Invalid_data_dir_version of t * t +type error += Could_not_read_data_dir_version of string + +val data_version : t + +val pp : Format.formatter -> t -> unit + +val version_encoding : t Data_encoding.encoding + +val ensure_data_dir : string -> unit tzresult Lwt.t diff --git a/src/node/main/node_identity_command.ml b/src/node/main/node_identity_command.ml index 58dafe8ce..e84eb855a 100644 --- a/src/node/main/node_identity_command.ml +++ b/src/node/main/node_identity_command.ml @@ -67,7 +67,7 @@ module Term = struct Node_config_file.read config_file >>=? fun cfg -> return { cfg with data_dir } end >>=? fun cfg -> - let cfg = Node_config_file.update ?expected_pow cfg in + Node_config_file.update ?expected_pow cfg >>=? fun cfg -> match subcommand with | Show -> show cfg | Generate -> generate cfg diff --git a/src/node/main/node_identity_file.ml b/src/node/main/node_identity_file.ml index 71e2c4572..b0723a41c 100644 --- a/src/node/main/node_identity_file.ml +++ b/src/node/main/node_identity_file.ml @@ -81,6 +81,6 @@ let write file identity = if Sys.file_exists file then fail (Existent_identity_file file) else - Lwt_utils.create_dir ~perm:0o700 (Filename.dirname file) >>= fun () -> + Node_data_version.ensure_data_dir (Filename.dirname file) >>=? fun () -> Data_encoding_ezjsonm.write_file file (Data_encoding.Json.construct P2p.Identity.encoding identity) diff --git a/src/node/main/node_run_command.ml b/src/node/main/node_run_command.ml index 550989cfb..8a999ae3b 100644 --- a/src/node/main/node_run_command.ml +++ b/src/node/main/node_run_command.ml @@ -185,7 +185,7 @@ let init_signal () = ignore (Lwt_unix.on_signal Sys.sigterm handler : Lwt_unix.signal_handler_id) let run ?verbosity ?sandbox (config : Node_config_file.t) = - Lwt_utils.create_dir config.data_dir >>= fun () -> + Node_data_version.ensure_data_dir config.data_dir >>=? fun () -> Lwt_utils.Lock_file.create ~unlink_on_exit:true (lock_file config.data_dir) >>=? fun () -> init_signal () ; diff --git a/src/node/main/node_shared_arg.ml b/src/node/main/node_shared_arg.ml index 966f36d79..37811da82 100644 --- a/src/node/main/node_shared_arg.ml +++ b/src/node/main/node_shared_arg.ml @@ -267,7 +267,6 @@ let read_and_patch_config_file ?(ignore_bootstrap_peers=false) args = peers end else cfg.net.bootstrap_peers @ peers in - return @@ Node_config_file.update ?data_dir ?min_connections ?expected_connections ?max_connections ?max_download_speed ?max_upload_speed ?binary_chunks_size