From 02245b27cc2be178bcc62c3898fc3096652835cc Mon Sep 17 00:00:00 2001 From: Valentin Chaboche Date: Tue, 6 May 2025 10:53:11 +0200 Subject: [PATCH] Baker: move partially [per_block_vote_file] logic in agnostic library --- src/lib_agnostic_baker/configuration.ml | 34 ++-- src/lib_agnostic_baker/configuration.mli | 18 +- src/lib_agnostic_baker/errors.ml | 111 ++++++++++++- src/lib_agnostic_baker/events.ml | 37 +++++ .../per_block_vote_file.ml | 45 +++-- .../per_block_vote_file.mli | 7 +- src/lib_agnostic_baker/per_block_votes.ml | 55 +++++++ .../lib_agnostic_baker/baker_args_parser.ml | 22 ++- .../lib_delegate/baking_actions.ml | 40 ++++- .../lib_delegate/baking_commands.ml | 40 ++++- .../lib_agnostic_baker/baker_args_parser.ml | 22 ++- .../lib_delegate/baking_actions.ml | 40 ++++- .../lib_delegate/baking_commands.ml | 55 ++++--- .../lib_delegate/per_block_vote_file.ml | 154 ------------------ .../lib_delegate/per_block_vote_file.mli | 77 --------- .../tests/liquidity_baking_per_block_votes.ml | 4 +- 16 files changed, 421 insertions(+), 340 deletions(-) rename src/{proto_022_PsRiotum/lib_delegate => lib_agnostic_baker}/per_block_vote_file.ml (82%) rename src/{proto_022_PsRiotum/lib_delegate => lib_agnostic_baker}/per_block_vote_file.mli (96%) create mode 100644 src/lib_agnostic_baker/per_block_votes.ml delete mode 100644 src/proto_alpha/lib_delegate/per_block_vote_file.ml delete mode 100644 src/proto_alpha/lib_delegate/per_block_vote_file.mli diff --git a/src/lib_agnostic_baker/configuration.ml b/src/lib_agnostic_baker/configuration.ml index adc26a3b35fd..6cdb3b8090d7 100644 --- a/src/lib_agnostic_baker/configuration.ml +++ b/src/lib_agnostic_baker/configuration.ml @@ -9,31 +9,13 @@ created. An argument of this type will be passed to the main running function of the agnostic baker. *) -type error += Block_vote_file_not_found of string +open Errors type error += Bad_minimal_fees of string type error += Bad_preserved_levels of string let () = - register_error_kind - `Permanent - ~id:"agnostic_baker.configuration.block_vote_file_not_found" - ~title: - "The provided block vote file path does not point to an existing file." - ~description: - "A block vote file path was provided on the command line but the path \ - does not point to an existing file." - ~pp:(fun ppf file_path -> - Format.fprintf - ppf - "@[The provided block vote file path \"%s\" does not point to an \ - existing file.@]" - file_path) - Data_encoding.(obj1 (req "file_path" string)) - (function - | Block_vote_file_not_found file_path -> Some file_path | _ -> None) - (fun file_path -> Block_vote_file_not_found file_path) ; register_error_kind `Permanent ~id:"agnostic_baker.configuration.badMinimalFeesArg" @@ -80,7 +62,9 @@ let per_block_vote_parameter = Tezos_clic.parameter ~autocomplete:(fun _ctxt -> return ["on"; "off"; "pass"]) (fun (_cctxt : Tezos_client_base.Client_context.full) -> function - | ("on" | "off" | "pass") as s -> return s + | "on" -> return Per_block_votes.Per_block_vote_on + | "off" -> return Per_block_votes.Per_block_vote_off + | "pass" -> return Per_block_votes.Per_block_vote_pass | s -> failwith "unexpected vote: %s, expected either \"on\", \"off\", or \"pass\"." @@ -395,8 +379,8 @@ type t = { minimal_nanotez_per_byte : Q.t; force_apply_from_round : int option; keep_alive : bool; - liquidity_baking_vote : string option; - adaptive_issuance_vote : string option; + liquidity_baking_vote : Per_block_votes.per_block_vote option; + adaptive_issuance_vote : Per_block_votes.per_block_vote option; per_block_vote_file : string option; extra_operations : Uri.t option; dal_node_endpoint : Uri.t option; @@ -444,3 +428,9 @@ let create_config pre_emptive_forge_time; remote_calls_timeout; } + +type per_block_votes_config = { + vote_file : string option; + liquidity_baking_vote : Per_block_votes.per_block_vote; + adaptive_issuance_vote : Per_block_votes.per_block_vote; +} diff --git a/src/lib_agnostic_baker/configuration.mli b/src/lib_agnostic_baker/configuration.mli index 609288c4e306..eeafba27930d 100644 --- a/src/lib_agnostic_baker/configuration.mli +++ b/src/lib_agnostic_baker/configuration.mli @@ -24,8 +24,8 @@ val baker_args : * Q.t * int option * bool - * string option - * string option + * Per_block_votes.per_block_vote option + * Per_block_votes.per_block_vote option * string option * Uri.t option * Uri.t option @@ -58,8 +58,8 @@ type t = { minimal_nanotez_per_byte : Q.t; force_apply_from_round : int option; keep_alive : bool; - liquidity_baking_vote : string option; - adaptive_issuance_vote : string option; + liquidity_baking_vote : Per_block_votes.per_block_vote option; + adaptive_issuance_vote : Per_block_votes.per_block_vote option; per_block_vote_file : string option; extra_operations : Uri.t option; dal_node_endpoint : Uri.t option; @@ -78,8 +78,8 @@ val create_config : * Q.t * int option * bool - * string option - * string option + * Per_block_votes.per_block_vote option + * Per_block_votes.per_block_vote option * string option * Uri.t option * Uri.t option @@ -88,3 +88,9 @@ val create_config : * Q.t option * Q.t option -> t + +type per_block_votes_config = { + vote_file : string option; + liquidity_baking_vote : Per_block_votes.per_block_vote; + adaptive_issuance_vote : Per_block_votes.per_block_vote; +} diff --git a/src/lib_agnostic_baker/errors.ml b/src/lib_agnostic_baker/errors.ml index d13f5d0ec2eb..af4b8b99e1ab 100644 --- a/src/lib_agnostic_baker/errors.ml +++ b/src/lib_agnostic_baker/errors.ml @@ -19,6 +19,11 @@ type error += baker_commit_info : Tezos_version.Octez_node_version.commit_info option; } | Node_version_malformatted of string + | Block_vote_file_not_found of string + | Block_vote_file_invalid of string + | Block_vote_file_wrong_content of string + | Block_vote_file_missing_liquidity_baking_toggle_vote of string + | Missing_vote_on_startup let () = Error_monad.register_error_kind @@ -143,4 +148,108 @@ let () = version) Data_encoding.(obj1 (req "provided_version" string)) (function Node_version_malformatted v -> Some v | _ -> None) - (fun v -> Node_version_malformatted v) + (fun v -> Node_version_malformatted v) ; + register_error_kind + `Permanent + ~id:"Per_block_vote_file.block_vote_file_not_found" + ~title: + "The provided block vote file path does not point to an existing file." + ~description: + "A block vote file path was provided on the command line but the path \ + does not point to an existing file." + ~pp:(fun ppf file_path -> + Format.fprintf + ppf + "@[The provided block vote file path \"%s\" does not point to an \ + existing file.@]" + file_path) + Data_encoding.(obj1 (req "file_path" string)) + (function + | Block_vote_file_not_found file_path -> Some file_path | _ -> None) + (fun file_path -> Block_vote_file_not_found file_path) ; + register_error_kind + `Permanent + ~id:"Per_block_vote_file.block_vote_file_invalid" + ~title: + "The provided block vote file path does not point to a valid JSON file." + ~description: + "A block vote file path was provided on the command line but the path \ + does not point to a valid JSON file." + ~pp:(fun ppf file_path -> + Format.fprintf + ppf + "@[The provided block vote file path \"%s\" does not point to a valid \ + JSON file. The file exists but its content is not valid JSON.@]" + file_path) + Data_encoding.(obj1 (req "file_path" string)) + (function Block_vote_file_invalid file_path -> Some file_path | _ -> None) + (fun file_path -> Block_vote_file_invalid file_path) ; + register_error_kind + `Permanent + ~id:"Per_block_vote_file.block_vote_file_wrong_content" + ~title:"The content of the provided block vote file is unexpected." + ~description: + "The block vote file is valid JSON but its content is not the expected \ + one." + ~pp:(fun ppf file_path -> + Format.fprintf + ppf + "@[The provided block vote file \"%s\" is a valid JSON file but its \ + content is unexpected. Expecting a JSON file containing \ + '{\"liquidity_baking_toggle_vote\": value1, \ + \"adaptive_issuance_vote\": value2}' or '{\"adaptive_issuance_vote\": \ + value1, \"liquidity_baking_toggle_vote\": value2}', where value1 is \ + one of \"on\", \"off\", or \"pass\" and value2 is one of \"on\", \ + \"off\", or \"pass\", or '{\"liquidity_baking_toggle_vote\": value}' \ + where value is one of \"on\", \"off\", or \"pass\".@]" + file_path) + Data_encoding.(obj1 (req "file_path" string)) + (function + | Block_vote_file_wrong_content file_path -> Some file_path | _ -> None) + (fun file_path -> Block_vote_file_wrong_content file_path) ; + register_error_kind + `Permanent + ~id: + "Per_block_vote_file.block_vote_file_missing_liquidity_baking_toggle_vote" + ~title: + "In the provided block vote file, no entry for liquidity baking toggle \ + vote was found" + ~description: + "In the provided block vote file, no entry for liquidity baking toggle \ + vote was found." + ~pp:(fun ppf file_path -> + Format.fprintf + ppf + "@[In the provided block vote file \"%s\", the \ + \"liquidity_baking_toggle_vote\" field is missing. Expecting a JSON \ + file containing '{\"liquidity_baking_toggle_vote\": value1, \ + \"adaptive_issuance_vote\": value2}' or '{\"adaptive_issuance_vote\": \ + value1, \"liquidity_baking_toggle_vote\": value2}', where value1 is \ + one of \"on\", \"off\", or \"pass\" and value2 is one of \"on\", \ + \"off\", or \"pass\", or '{\"liquidity_baking_toggle_vote\": value}' \ + where value is one of \"on\", \"off\", or \"pass\".@]" + file_path) + Data_encoding.(obj1 (req "file_path" string)) + (function + | Block_vote_file_missing_liquidity_baking_toggle_vote file_path -> + Some file_path + | _ -> None) + (fun file_path -> + Block_vote_file_missing_liquidity_baking_toggle_vote file_path) ; + register_error_kind + `Permanent + ~id:"Per_block_vote_file.missing_vote_on_startup" + ~title:"Missing vote on startup" + ~description: + "No CLI flag, file path, or votes file in default location provided on \ + startup" + ~pp:(fun fmt () -> + Format.fprintf + fmt + "Missing liquidity baking toggle vote, please use either the \ + --liquidity-baking-toggle-vote option, or the --votefile option or a \ + votes file in the default location: per_block_votes.json in the \ + current working directory or in the baker directory.") + Data_encoding.empty + (function Missing_vote_on_startup -> Some () | _ -> None) + (fun () -> Missing_vote_on_startup) diff --git a/src/lib_agnostic_baker/events.ml b/src/lib_agnostic_baker/events.ml index 700ee545d8d9..561301f828b6 100644 --- a/src/lib_agnostic_baker/events.ml +++ b/src/lib_agnostic_baker/events.ml @@ -152,3 +152,40 @@ let node_version_check = ( "baker_commit", Data_encoding.option Tezos_version.Octez_node_version.commit_info_encoding ) + +module Per_block_votes = struct + include Internal_event.Simple + + let reading_per_block_votes = + declare_1 + ~section + ~name:"reading_per_block_votes" + ~level:Notice + ~msg:"reading votes file: {path}" + ("path", Data_encoding.string) + + let liquidity_baking_toggle_vote = + declare_1 + ~section + ~name:"read_liquidity_baking_toggle_vote" + ~level:Notice + ~msg:"read liquidity baking toggle vote = {value}" + ("value", Per_block_votes.liquidity_baking_vote_encoding) + + let per_block_vote_file_fail = + declare_1 + ~section + ~name:"per_block_vote_file_error" + ~level:Error + ~msg:"Error reading the block vote file: {errors}" + ~pp1:pp_print_top_error_of_trace + ("errors", Error_monad.(TzTrace.encoding error_encoding)) + + let adaptive_issuance_vote = + declare_1 + ~section + ~name:"read_adaptive_issuance_vote" + ~level:Notice + ~msg:"read adaptive issuance vote = {value}" + ("value", Per_block_votes.adaptive_issuance_vote_encoding) +end diff --git a/src/proto_022_PsRiotum/lib_delegate/per_block_vote_file.ml b/src/lib_agnostic_baker/per_block_vote_file.ml similarity index 82% rename from src/proto_022_PsRiotum/lib_delegate/per_block_vote_file.ml rename to src/lib_agnostic_baker/per_block_vote_file.ml index 0866e45d6dc1..2ced8c993afe 100644 --- a/src/proto_022_PsRiotum/lib_delegate/per_block_vote_file.ml +++ b/src/lib_agnostic_baker/per_block_vote_file.ml @@ -23,21 +23,19 @@ (* *) (*****************************************************************************) -module Events = Baking_events.Per_block_votes -open Baking_errors +module Events = Events.Per_block_votes +open Errors let default_vote_json_filename = "per_block_votes.json" type per_block_votes = { - liquidity_baking_toggle_vote : - Protocol.Alpha_context.Per_block_votes.per_block_vote; - adaptive_issuance_vote_opt : - Protocol.Alpha_context.Per_block_votes.per_block_vote option; + liquidity_baking_toggle_vote : Per_block_votes.per_block_vote; + adaptive_issuance_vote_opt : Per_block_votes.per_block_vote option; } let vote_file_content_encoding = let open Data_encoding in - def (String.concat "." [Protocol.name; "vote_file_content"]) + def "vote_file_content" @@ conv (fun {liquidity_baking_toggle_vote; adaptive_issuance_vote_opt} -> (liquidity_baking_toggle_vote, adaptive_issuance_vote_opt)) @@ -46,12 +44,10 @@ let vote_file_content_encoding = (obj2 (req "liquidity_baking_toggle_vote" - Protocol.Alpha_context.Per_block_votes - .liquidity_baking_vote_encoding) + Per_block_votes.liquidity_baking_vote_encoding) (opt "adaptive_issuance_vote" - Protocol.Alpha_context.Per_block_votes - .adaptive_issuance_vote_encoding)) + Per_block_votes.adaptive_issuance_vote_encoding)) let check_file_exists file = let open Lwt_result_syntax in @@ -91,7 +87,7 @@ let read_per_block_votes_no_fail ~default ~per_block_vote_file = adaptive_issuance_vote_opt = Some adaptive_issuance_vote; } -> return - Protocol.Alpha_context.Per_block_votes. + Per_block_votes. { liquidity_baking_vote = liquidity_baking_toggle_vote; adaptive_issuance_vote; @@ -101,7 +97,7 @@ let read_per_block_votes_no_fail ~default ~per_block_vote_file = let load_per_block_votes_config ~default_liquidity_baking_vote ~default_adaptive_issuance_vote ~per_block_vote_file : - Baking_configuration.per_block_votes_config tzresult Lwt.t = + Configuration.per_block_votes_config tzresult Lwt.t = let open Lwt_result_syntax in (* If a vote file is given, it takes priority. Otherwise, we expect per-block vote arguments to be passed. *) @@ -109,7 +105,7 @@ let load_per_block_votes_config ~default_liquidity_baking_vote (* Unlike the vote for liquidity baking, the vote for adaptive issuance is not mandatory. *) match default_adaptive_issuance_vote with - | None -> Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass + | None -> Per_block_votes.Per_block_vote_pass | Some default_adaptive_issuance_vote -> default_adaptive_issuance_vote in let* config = @@ -118,7 +114,7 @@ let load_per_block_votes_config ~default_liquidity_baking_vote | None, Some liquidity_baking_vote -> return { - Baking_configuration.vote_file = None; + Configuration.vote_file = None; liquidity_baking_vote; adaptive_issuance_vote = default_adaptive_issuance_vote; } @@ -137,7 +133,7 @@ let load_per_block_votes_config ~default_liquidity_baking_vote in return { - Baking_configuration.vote_file = Some per_block_vote_file; + Configuration.vote_file = Some per_block_vote_file; liquidity_baking_vote; adaptive_issuance_vote; } @@ -152,3 +148,20 @@ let load_per_block_votes_config ~default_liquidity_baking_vote Events.(emit adaptive_issuance_vote) config.adaptive_issuance_vote in return config + +let lookup_default_vote_file_path + (cctxt : Tezos_client_base.Client_context.full) = + let open Lwt_syntax in + let default_filename = default_vote_json_filename in + let file_exists path = + Lwt.catch (fun () -> Lwt_unix.file_exists path) (fun _ -> return_false) + in + let when_s pred x g = + let* b = pred x in + if b then return_some x else g () + in + (* Check in current working directory *) + when_s file_exists default_filename @@ fun () -> + (* Check in the baker directory *) + let base_dir_file = Filename.Infix.(cctxt#get_base_dir // default_filename) in + when_s file_exists base_dir_file @@ fun () -> return_none diff --git a/src/proto_022_PsRiotum/lib_delegate/per_block_vote_file.mli b/src/lib_agnostic_baker/per_block_vote_file.mli similarity index 96% rename from src/proto_022_PsRiotum/lib_delegate/per_block_vote_file.mli rename to src/lib_agnostic_baker/per_block_vote_file.mli index 5347f30a6ce8..ad4e871b0445 100644 --- a/src/proto_022_PsRiotum/lib_delegate/per_block_vote_file.mli +++ b/src/lib_agnostic_baker/per_block_vote_file.mli @@ -48,8 +48,6 @@ the config in order to check for updated votes. *) -open Protocol.Alpha_context - (** Default vote file name that should be looked up when the baker starts. *) val default_vote_json_filename : string @@ -74,4 +72,7 @@ val load_per_block_votes_config : default_liquidity_baking_vote:Per_block_votes.per_block_vote option -> default_adaptive_issuance_vote:Per_block_votes.per_block_vote option -> per_block_vote_file:string option -> - Baking_configuration.per_block_votes_config tzresult Lwt.t + Configuration.per_block_votes_config tzresult Lwt.t + +val lookup_default_vote_file_path : + Tezos_client_base.Client_context.full -> string option Lwt.t diff --git a/src/lib_agnostic_baker/per_block_votes.ml b/src/lib_agnostic_baker/per_block_votes.ml new file mode 100644 index 000000000000..ca06559686dc --- /dev/null +++ b/src/lib_agnostic_baker/per_block_votes.ml @@ -0,0 +1,55 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** TODO: This is a copy paste of `src/proto_alpha/lib_protocol/per_block_votes.ml`, + arguably it should be moved to the environment as the agnostic baker needs it. *) + +type per_block_vote = + | Per_block_vote_on + | Per_block_vote_off + | Per_block_vote_pass + +type per_block_votes = { + liquidity_baking_vote : per_block_vote; + adaptive_issuance_vote : per_block_vote; +} + +let per_block_vote_compact_encoding = + let open Data_encoding in + let open Compact in + union + ~union_tag_bits:2 + ~cases_tag_bits:0 + [ + case + ~title:"per_block_vote_on" + (payload (constant "on")) + (function Per_block_vote_on -> Some () | _ -> None) + (fun () -> Per_block_vote_on); + case + ~title:"per_block_vote_off" + (payload (constant "off")) + (function Per_block_vote_off -> Some () | _ -> None) + (fun () -> Per_block_vote_off); + case + ~title:"per_block_vote_pass" + (payload (constant "pass")) + (function Per_block_vote_pass -> Some () | _ -> None) + (fun () -> Per_block_vote_pass); + ] + +let liquidity_baking_vote_encoding = + let open Data_encoding in + def + "liquidity_baking_vote" + (Compact.make ~tag_size:`Uint8 per_block_vote_compact_encoding) + +let adaptive_issuance_vote_encoding = + let open Data_encoding in + def + "adaptive_issuance_vote" + (Compact.make ~tag_size:`Uint8 per_block_vote_compact_encoding) diff --git a/src/proto_022_PsRiotum/lib_agnostic_baker/baker_args_parser.ml b/src/proto_022_PsRiotum/lib_agnostic_baker/baker_args_parser.ml index 764f7803957a..c972c8dd00c8 100644 --- a/src/proto_022_PsRiotum/lib_agnostic_baker/baker_args_parser.ml +++ b/src/proto_022_PsRiotum/lib_agnostic_baker/baker_args_parser.ml @@ -11,16 +11,6 @@ open Protocol.Alpha_context (** [parse_minimal_fees] parses integer valued fees to [Tez] values. *) let parse_minimal_fees = Tez.of_mutez_exn -(** [parse_per_block_vote] parses string valued voting options to protocol - specific [Per_block_votes] values. *) -let parse_per_block_vote = - Option.map (function - | "on" -> Per_block_votes.Per_block_vote_on - | "off" -> Per_block_vote_off - | "pass" -> Per_block_vote_pass - (* This is unreachable because any other value would fail in CLI configuration parsing *) - | _ -> assert false) - (** [parse_operations] parses uri's to either [Remote] or [Local] operations sources. *) let parse_operations = let open Baking_configuration.Operations_source in @@ -56,6 +46,14 @@ let parse_configuration pre_emptive_forge_time; remote_calls_timeout; } = + let to_protocol = function + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_on -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_on + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_off -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_off + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass + in ( pidfile, node_version_check_bypass, node_version_allowed, @@ -64,8 +62,8 @@ let parse_configuration minimal_nanotez_per_byte, force_apply_from_round, keep_alive, - parse_per_block_vote liquidity_baking_vote, - parse_per_block_vote adaptive_issuance_vote, + Option.map to_protocol liquidity_baking_vote, + Option.map to_protocol adaptive_issuance_vote, per_block_vote_file, parse_operations extra_operations, dal_node_endpoint, diff --git a/src/proto_022_PsRiotum/lib_delegate/baking_actions.ml b/src/proto_022_PsRiotum/lib_delegate/baking_actions.ml index 3b1e42ba4313..2f3616efa6f1 100644 --- a/src/proto_022_PsRiotum/lib_delegate/baking_actions.ml +++ b/src/proto_022_PsRiotum/lib_delegate/baking_actions.ml @@ -359,16 +359,48 @@ let prepare_block (global_state : global_state) (block_to_bake : block_to_bake) in (* Prioritize reading from the [vote_file] if it exists. *) let*! {liquidity_baking_vote; adaptive_issuance_vote} = + let of_protocol = function + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_on -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_on + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_off -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_off + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass + in + let to_protocol = function + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_on -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_on + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_off -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_off + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass + in let default = Protocol.Alpha_context.Per_block_votes. {liquidity_baking_vote; adaptive_issuance_vote} in match vote_file with | Some per_block_vote_file -> - Per_block_vote_file.read_per_block_votes_no_fail - ~default - ~per_block_vote_file - [@profiler.record_s {verbosity = Info} "read per block votes file"] + let default = + Octez_agnostic_baker.Per_block_votes. + { + liquidity_baking_vote = of_protocol liquidity_baking_vote; + adaptive_issuance_vote = of_protocol adaptive_issuance_vote; + } + in + let*! Octez_agnostic_baker.Per_block_votes. + {liquidity_baking_vote; adaptive_issuance_vote} = + (Per_block_vote_file.read_per_block_votes_no_fail + ~default + ~per_block_vote_file + [@profiler.record_s {verbosity = Info} "read per block votes file"]) + in + Lwt.return + Protocol.Alpha_context.Per_block_votes. + { + liquidity_baking_vote = to_protocol liquidity_baking_vote; + adaptive_issuance_vote = to_protocol adaptive_issuance_vote; + } | None -> Lwt.return default in let*! () = diff --git a/src/proto_022_PsRiotum/lib_delegate/baking_commands.ml b/src/proto_022_PsRiotum/lib_delegate/baking_commands.ml index bdf596dae1a4..29518f5c568a 100644 --- a/src/proto_022_PsRiotum/lib_delegate/baking_commands.ml +++ b/src/proto_022_PsRiotum/lib_delegate/baking_commands.ml @@ -597,7 +597,9 @@ let remote_calls_timeout_arg = let lookup_default_vote_file_path (cctxt : Protocol_client_context.full) = let open Lwt_syntax in - let default_filename = Per_block_vote_file.default_vote_json_filename in + let default_filename = + Octez_agnostic_baker.Per_block_vote_file.default_vote_json_filename + in let file_exists path = Lwt.catch (fun () -> Lwt_unix.file_exists path) (fun _ -> return_false) in @@ -700,10 +702,38 @@ let run_baker ?(recommend_agnostic_baker = true) option (CLI, file path, or file in default location) for the per-block votes. *) let* votes = - Per_block_vote_file.load_per_block_votes_config - ~default_liquidity_baking_vote:liquidity_baking_vote - ~default_adaptive_issuance_vote:adaptive_issuance_vote - ~per_block_vote_file + let of_protocol = function + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_on -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_on + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_off -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_off + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass + in + let to_protocol = function + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_on -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_on + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_off -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_off + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass + in + let* Octez_agnostic_baker.Configuration. + {vote_file; liquidity_baking_vote; adaptive_issuance_vote} = + Octez_agnostic_baker.Per_block_vote_file.load_per_block_votes_config + ~default_liquidity_baking_vote: + (Option.map of_protocol liquidity_baking_vote) + ~default_adaptive_issuance_vote: + (Option.map of_protocol adaptive_issuance_vote) + ~per_block_vote_file + in + return + Baking_configuration. + { + vote_file; + liquidity_baking_vote = to_protocol liquidity_baking_vote; + adaptive_issuance_vote = to_protocol adaptive_issuance_vote; + } in let dal_node_rpc_ctxt = Option.map create_dal_node_rpc_ctxt dal_node_endpoint diff --git a/src/proto_alpha/lib_agnostic_baker/baker_args_parser.ml b/src/proto_alpha/lib_agnostic_baker/baker_args_parser.ml index 3ea1a51283a9..0764226288f1 100644 --- a/src/proto_alpha/lib_agnostic_baker/baker_args_parser.ml +++ b/src/proto_alpha/lib_agnostic_baker/baker_args_parser.ml @@ -11,16 +11,6 @@ open Protocol.Alpha_context (** [parse_minimal_fees] parses integer valued fees to [Tez] values. *) let parse_minimal_fees = Tez.of_mutez_exn -(** [parse_per_block_vote] parses string valued voting options to protocol - specific [Per_block_votes] values. *) -let parse_per_block_vote = - Option.map (function - | "on" -> Per_block_votes.Per_block_vote_on - | "off" -> Per_block_vote_off - | "pass" -> Per_block_vote_pass - (* This is unreachable because any other value would fail in CLI configuration parsing *) - | _ -> assert false) - (** [parse_operations] parses uri's to either [Remote] or [Local] operations sources. *) let parse_operations = let open Baking_configuration.Operations_source in @@ -56,6 +46,14 @@ let parse_configuration pre_emptive_forge_time; remote_calls_timeout; } = + let to_protocol = function + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_on -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_on + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_off -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_off + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass + in ( pidfile, node_version_check_bypass, node_version_allowed, @@ -64,8 +62,8 @@ let parse_configuration minimal_nanotez_per_byte, force_apply_from_round, keep_alive, - parse_per_block_vote liquidity_baking_vote, - parse_per_block_vote adaptive_issuance_vote, + Option.map to_protocol liquidity_baking_vote, + Option.map to_protocol adaptive_issuance_vote, per_block_vote_file, parse_operations extra_operations, dal_node_endpoint, diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index 7f7cc97609fb..6288dc4f8cd6 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -360,16 +360,48 @@ let prepare_block (global_state : global_state) (block_to_bake : block_to_bake) in (* Prioritize reading from the [vote_file] if it exists. *) let*! {liquidity_baking_vote; adaptive_issuance_vote} = + let of_protocol = function + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_on -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_on + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_off -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_off + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass + in + let to_protocol = function + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_on -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_on + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_off -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_off + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass + in let default = Protocol.Alpha_context.Per_block_votes. {liquidity_baking_vote; adaptive_issuance_vote} in match vote_file with | Some per_block_vote_file -> - Per_block_vote_file.read_per_block_votes_no_fail - ~default - ~per_block_vote_file - [@profiler.record_s {verbosity = Info} "read per block votes file"] + let default = + Octez_agnostic_baker.Per_block_votes. + { + liquidity_baking_vote = of_protocol liquidity_baking_vote; + adaptive_issuance_vote = of_protocol adaptive_issuance_vote; + } + in + let*! Octez_agnostic_baker.Per_block_votes. + {liquidity_baking_vote; adaptive_issuance_vote} = + (Per_block_vote_file.read_per_block_votes_no_fail + ~default + ~per_block_vote_file + [@profiler.record_s {verbosity = Info} "read per block votes file"]) + in + Lwt.return + Protocol.Alpha_context.Per_block_votes. + { + liquidity_baking_vote = to_protocol liquidity_baking_vote; + adaptive_issuance_vote = to_protocol adaptive_issuance_vote; + } | None -> Lwt.return default in let*! () = diff --git a/src/proto_alpha/lib_delegate/baking_commands.ml b/src/proto_alpha/lib_delegate/baking_commands.ml index a468b3b0666e..aeed25332883 100644 --- a/src/proto_alpha/lib_delegate/baking_commands.ml +++ b/src/proto_alpha/lib_delegate/baking_commands.ml @@ -595,22 +595,6 @@ let remote_calls_timeout_arg = try return (Q.of_string s) with _ -> failwith "remote-calls-timeout expected int or float.")) -let lookup_default_vote_file_path (cctxt : Protocol_client_context.full) = - let open Lwt_syntax in - let default_filename = Per_block_vote_file.default_vote_json_filename in - let file_exists path = - Lwt.catch (fun () -> Lwt_unix.file_exists path) (fun _ -> return_false) - in - let when_s pred x g = - let* b = pred x in - if b then return_some x else g () - in - (* Check in current working directory *) - when_s file_exists default_filename @@ fun () -> - (* Check in the baker directory *) - let base_dir_file = Filename.Infix.(cctxt#get_base_dir // default_filename) in - when_s file_exists base_dir_file @@ fun () -> return_none - (* This function checks that a DAL node endpoint was given, and that the specified DAL node is "healthy", (the DAL's nodes 'health' RPC is used for that). *) @@ -703,17 +687,46 @@ let run_baker ?(recommend_agnostic_baker = true) if per_block_vote_file = None then (* If the votes file was not explicitly given, we look into default locations. *) - lookup_default_vote_file_path cctxt + Octez_agnostic_baker.Per_block_vote_file.lookup_default_vote_file_path + (cctxt :> Client_context.full) else Lwt.return per_block_vote_file in (* We don't let the user run the baker without providing some option (CLI, file path, or file in default location) for the per-block votes. *) let* votes = - Per_block_vote_file.load_per_block_votes_config - ~default_liquidity_baking_vote:liquidity_baking_vote - ~default_adaptive_issuance_vote:adaptive_issuance_vote - ~per_block_vote_file + let of_protocol = function + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_on -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_on + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_off -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_off + | Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass -> + Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass + in + let to_protocol = function + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_on -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_on + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_off -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_off + | Octez_agnostic_baker.Per_block_votes.Per_block_vote_pass -> + Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass + in + let* Octez_agnostic_baker.Configuration. + {vote_file; liquidity_baking_vote; adaptive_issuance_vote} = + Octez_agnostic_baker.Per_block_vote_file.load_per_block_votes_config + ~default_liquidity_baking_vote: + (Option.map of_protocol liquidity_baking_vote) + ~default_adaptive_issuance_vote: + (Option.map of_protocol adaptive_issuance_vote) + ~per_block_vote_file + in + return + Baking_configuration. + { + vote_file; + liquidity_baking_vote = to_protocol liquidity_baking_vote; + adaptive_issuance_vote = to_protocol adaptive_issuance_vote; + } in let dal_node_rpc_ctxt = Option.map create_dal_node_rpc_ctxt dal_node_endpoint diff --git a/src/proto_alpha/lib_delegate/per_block_vote_file.ml b/src/proto_alpha/lib_delegate/per_block_vote_file.ml deleted file mode 100644 index 0866e45d6dc1..000000000000 --- a/src/proto_alpha/lib_delegate/per_block_vote_file.ml +++ /dev/null @@ -1,154 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs *) -(* *) -(* Permission is hereby granted, free of charge, to any person obtaining a *) -(* copy of this software and associated documentation files (the "Software"),*) -(* to deal in the Software without restriction, including without limitation *) -(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) -(* and/or sell copies of the Software, and to permit persons to whom the *) -(* Software is furnished to do so, subject to the following conditions: *) -(* *) -(* The above copyright notice and this permission notice shall be included *) -(* in all copies or substantial portions of the Software. *) -(* *) -(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) -(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) -(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) -(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) -(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) -(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) -(* DEALINGS IN THE SOFTWARE. *) -(* *) -(*****************************************************************************) - -module Events = Baking_events.Per_block_votes -open Baking_errors - -let default_vote_json_filename = "per_block_votes.json" - -type per_block_votes = { - liquidity_baking_toggle_vote : - Protocol.Alpha_context.Per_block_votes.per_block_vote; - adaptive_issuance_vote_opt : - Protocol.Alpha_context.Per_block_votes.per_block_vote option; -} - -let vote_file_content_encoding = - let open Data_encoding in - def (String.concat "." [Protocol.name; "vote_file_content"]) - @@ conv - (fun {liquidity_baking_toggle_vote; adaptive_issuance_vote_opt} -> - (liquidity_baking_toggle_vote, adaptive_issuance_vote_opt)) - (fun (liquidity_baking_toggle_vote, adaptive_issuance_vote_opt) -> - {liquidity_baking_toggle_vote; adaptive_issuance_vote_opt}) - (obj2 - (req - "liquidity_baking_toggle_vote" - Protocol.Alpha_context.Per_block_votes - .liquidity_baking_vote_encoding) - (opt - "adaptive_issuance_vote" - Protocol.Alpha_context.Per_block_votes - .adaptive_issuance_vote_encoding)) - -let check_file_exists file = - let open Lwt_result_syntax in - let*! file_exists = - Lwt.catch (fun () -> Lwt_unix.file_exists file) (fun _ -> Lwt.return_false) - in - if file_exists then return_unit else tzfail (Block_vote_file_not_found file) - -let read_per_block_votes ~per_block_vote_file : 'a tzresult Lwt.t = - let open Lwt_result_syntax in - let*! () = Events.(emit reading_per_block_votes) per_block_vote_file in - let* () = check_file_exists per_block_vote_file in - let* votes_json = - trace - (Block_vote_file_invalid per_block_vote_file) - (Lwt_utils_unix.Json.read_file per_block_vote_file) - in - let* votes = - trace - (Block_vote_file_wrong_content per_block_vote_file) - (protect (fun () -> - return - (Data_encoding.Json.destruct vote_file_content_encoding votes_json))) - in - return votes - -let read_per_block_votes_no_fail ~default ~per_block_vote_file = - let open Lwt_syntax in - let* result = read_per_block_votes ~per_block_vote_file in - match result with - | Error errs -> - let* () = Events.(emit per_block_vote_file_fail) errs in - return default - | Ok - { - liquidity_baking_toggle_vote; - adaptive_issuance_vote_opt = Some adaptive_issuance_vote; - } -> - return - Protocol.Alpha_context.Per_block_votes. - { - liquidity_baking_vote = liquidity_baking_toggle_vote; - adaptive_issuance_vote; - } - | Ok {liquidity_baking_toggle_vote; adaptive_issuance_vote_opt = None} -> - return {default with liquidity_baking_vote = liquidity_baking_toggle_vote} - -let load_per_block_votes_config ~default_liquidity_baking_vote - ~default_adaptive_issuance_vote ~per_block_vote_file : - Baking_configuration.per_block_votes_config tzresult Lwt.t = - let open Lwt_result_syntax in - (* If a vote file is given, it takes priority. Otherwise, we expect - per-block vote arguments to be passed. *) - let default_adaptive_issuance_vote = - (* Unlike the vote for liquidity baking, the vote for adaptive - issuance is not mandatory. *) - match default_adaptive_issuance_vote with - | None -> Protocol.Alpha_context.Per_block_votes.Per_block_vote_pass - | Some default_adaptive_issuance_vote -> default_adaptive_issuance_vote - in - let* config = - match (per_block_vote_file, default_liquidity_baking_vote) with - | None, None -> tzfail Missing_vote_on_startup - | None, Some liquidity_baking_vote -> - return - { - Baking_configuration.vote_file = None; - liquidity_baking_vote; - adaptive_issuance_vote = default_adaptive_issuance_vote; - } - | Some per_block_vote_file, _ -> ( - let*! (res : _ tzresult) = read_per_block_votes ~per_block_vote_file in - match res with - | Ok - { - liquidity_baking_toggle_vote = liquidity_baking_vote; - adaptive_issuance_vote_opt; - } -> - let adaptive_issuance_vote = - Option.value - ~default:default_adaptive_issuance_vote - adaptive_issuance_vote_opt - in - return - { - Baking_configuration.vote_file = Some per_block_vote_file; - liquidity_baking_vote; - adaptive_issuance_vote; - } - | Error errs -> - let*! () = Events.(emit per_block_vote_file_fail) errs in - tzfail Missing_vote_on_startup) - in - let*! () = - Events.(emit liquidity_baking_toggle_vote) config.liquidity_baking_vote - in - let*! () = - Events.(emit adaptive_issuance_vote) config.adaptive_issuance_vote - in - return config diff --git a/src/proto_alpha/lib_delegate/per_block_vote_file.mli b/src/proto_alpha/lib_delegate/per_block_vote_file.mli deleted file mode 100644 index 5347f30a6ce8..000000000000 --- a/src/proto_alpha/lib_delegate/per_block_vote_file.mli +++ /dev/null @@ -1,77 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs *) -(* *) -(* Permission is hereby granted, free of charge, to any person obtaining a *) -(* copy of this software and associated documentation files (the "Software"),*) -(* to deal in the Software without restriction, including without limitation *) -(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) -(* and/or sell copies of the Software, and to permit persons to whom the *) -(* Software is furnished to do so, subject to the following conditions: *) -(* *) -(* The above copyright notice and this permission notice shall be included *) -(* in all copies or substantial portions of the Software. *) -(* *) -(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) -(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) -(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) -(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) -(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) -(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) -(* DEALINGS IN THE SOFTWARE. *) -(* *) -(*****************************************************************************) - -(** This module is used to load the baker's per block votes - configurations. When a file is given as configuration, its content - is expected to be a valid JSON matching the following examples: - - {v {"liquidity_baking_toggle_vote": "on"} v} - - {v {"liquidity_baking_toggle_vote": "off"} v} - - {v {"liquidity_baking_toggle_vote": "pass"} v} - - {v {"adaptive_issuance_vote": "on"} v} - - {v {"adaptive_issuance_vote": "off"} v} - - {v {"adaptive_issuance_vote": "pass"} v} - - {v {"liquidity_baking_toggle_vote": "on","adaptive_issuance_vote": "on"} v} - - {v {"liquidity_baking_toggle_vote": "on","adaptive_issuance_vote": "off"} v} - - {v {"liquidity_baking_toggle_vote": "on","adaptive_issuance_vote": "pass"} v} - - {v {"liquidity_baking_toggle_vote": "off","adaptive_issuance_vote": "on"} v} - - {v {"liquidity_baking_toggle_vote": "off","adaptive_issuance_vote": "off"} v} - - {v {"liquidity_baking_toggle_vote": "off","adaptive_issuance_vote": "pass"} v} - - {v {"liquidity_baking_toggle_vote": "pass","adaptive_issuance_vote": "on"} v} - - {v {"liquidity_baking_toggle_vote": "pass","adaptive_issuance_vote": "off"} v} - - {v {"liquidity_baking_toggle_vote": "pass","adaptive_issuance_vote": "pass"} v} - - Moreover, in order to handle dynamic voting (i.e. change the - baker's vote without having to restart it), each time a block is - being built, the baker will try and read the vote file present in - the config in order to check for updated votes. -*) - -open Protocol.Alpha_context - -(** Default vote file name that should be looked up when the baker - starts. *) -val default_vote_json_filename : string - -(** Reads the content of [per_block_vote_file] and returns the votes. If - any error occurs (e.g. Non-existing file, unparsable content, - etc.), given default values will be used to fill the gaps. *) -val read_per_block_votes_no_fail : - default:Per_block_votes.per_block_votes -> - per_block_vote_file:string -> - Per_block_votes.per_block_votes Lwt.t - -(** Load a configuration of per-block votes. Liquidity baking toggle - vote is mandatory, it has to come from either the per-block vote - file [per_block_vote_file] or from - [default_liquidity_baking_vote]. If a vote cannot be determined - from those values, this function fails. Adaptive issuance feature - vote is optional. Priority is given to the values in the - [per_block_vote_file] file for all votes at the time of the block - (the file is freshly read each time). *) -val load_per_block_votes_config : - default_liquidity_baking_vote:Per_block_votes.per_block_vote option -> - default_adaptive_issuance_vote:Per_block_votes.per_block_vote option -> - per_block_vote_file:string option -> - Baking_configuration.per_block_votes_config tzresult Lwt.t diff --git a/tezt/tests/liquidity_baking_per_block_votes.ml b/tezt/tests/liquidity_baking_per_block_votes.ml index 7ea2e79a1671..ebf615d96263 100644 --- a/tezt/tests/liquidity_baking_per_block_votes.ml +++ b/tezt/tests/liquidity_baking_per_block_votes.ml @@ -115,7 +115,6 @@ let test_all_per_block_votes = ~uses:(fun _protocol -> [Constant.octez_agnostic_baker]) @@ fun protocol -> let ( >|= ) = Lwt.( >|= ) in - let error_prefix = "baker." ^ Protocol.encoding_prefix protocol ^ "." in if Sys.file_exists default_votefile then Test.fail @@ -247,8 +246,7 @@ let test_all_per_block_votes = (* Explicitly remove the votefile to check that the baker has retained its value *) let p_error = baker_wait_for_per_block_vote_file_error - ~expected_id: - (error_prefix ^ "Per_block_vote_file.block_vote_file_not_found") + ~expected_id:"Per_block_vote_file.block_vote_file_not_found" ~expected_file_path:default_votefile baker in -- GitLab