From 45facc7f359f50df6d71034600589219a71e6bb6 Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 08:46:44 +0200 Subject: [PATCH 01/12] Agnostic_baker: standalone Run_args module --- src/bin_agnostic_baker/main_agnostic_baker.ml | 93 +------------------ src/bin_agnostic_baker/run_args.ml | 91 ++++++++++++++++++ 2 files changed, 92 insertions(+), 92 deletions(-) create mode 100644 src/bin_agnostic_baker/run_args.ml diff --git a/src/bin_agnostic_baker/main_agnostic_baker.ml b/src/bin_agnostic_baker/main_agnostic_baker.ml index 697575c2dc84..f61857f7d44d 100644 --- a/src/bin_agnostic_baker/main_agnostic_baker.ml +++ b/src/bin_agnostic_baker/main_agnostic_baker.ml @@ -450,101 +450,10 @@ module Daemon = struct return_unit end -module Args = struct - let binaries_directory_arg = "--binaries-directory" - - let endpoint_arg = "--endpoint" - - let endpoint_short_arg = "-E" - - let base_dir_arg = "--base-dir" - - let base_dir_short_arg = "--b" - - let help_arg = "--help" - - let print_help () = - Format.printf - "Usage:\n\ - \ octez-agnostic-baker [OCTEZ-AGNOSTIC-BAKER-COMMANDS] -- \ - [OCTEZ-BAKER-COMMANDS]@.@." ; - Format.printf - "OCTEZ-AGNOSTIC-BAKER-COMMANDS:\n\ - \ %s: display help\n\ - \ %s: path to the octez-baker binaries@.@." - help_arg - binaries_directory_arg ; - Format.printf - "OCTEZ-BAKER-COMMANDS:\n Run ./octez-baker- --help@." - - let help_cmd args = - if List.mem ~equal:String.equal help_arg args then ( - print_help () ; - exit 0) - else () - - let version_cmd args = - if List.mem ~equal:String.equal "--version" args then ( - Format.printf "%s@." Tezos_version_value.Bin_version.octez_version_string ; - exit 0) - else () - - let split_args ?(on = "--") = - let rec loop acc = function - | [] -> (List.rev acc, []) - | hd :: tl when hd = on -> (List.rev acc, tl) - | hd :: tl -> loop (hd :: acc) tl - in - loop [] - - let get_arg_value ~arg ?(short_arg = "") = - let rec loop = function - | [] -> None - | x :: y :: _ when x = arg || x = short_arg -> Some y - | _ :: l -> loop l - in - loop - - let get_endpoint = - get_arg_value ~arg:endpoint_arg ~short_arg:endpoint_short_arg - - let get_binaries_directory = get_arg_value ~arg:binaries_directory_arg - - let fail_on_empty_baker_args baker_args = - if List.is_empty baker_args then ( - Format.eprintf - "Cannot run agnostic baker without any baker arguments. Please refer \ - to the following help:@." ; - print_help () ; - exit 1) - - let get_base_dir = - get_arg_value ~arg:base_dir_arg ~short_arg:base_dir_short_arg - - let parse_args all_args = - let all_args = Array.to_list all_args in - (* Specific vesrion case *) - let () = version_cmd all_args in - (* Remove the binary path *) - let all_args = Option.value ~default:[] (List.tl all_args) in - (* Split agnostic baker and baker arguments, that aims to be delimited by -- *) - let agnostic_baker_args, baker_args = split_args all_args in - let () = fail_on_empty_baker_args baker_args in - let () = help_cmd agnostic_baker_args in - let endpoint = - Option.value - ~default:Parameters.default_node_addr - (get_endpoint baker_args) - in - let binaries_directory = get_binaries_directory agnostic_baker_args in - let base_dir = get_base_dir baker_args in - (endpoint, base_dir, binaries_directory, baker_args) -end - let run () = let open Lwt_result_syntax in let node_endpoint, base_dir, binaries_directory, baker_args = - Args.parse_args Sys.argv + Run_args.parse_args Sys.argv in let*! () = Tezos_base_unix.Internal_event_unix.init diff --git a/src/bin_agnostic_baker/run_args.ml b/src/bin_agnostic_baker/run_args.ml new file mode 100644 index 000000000000..a6566e523d36 --- /dev/null +++ b/src/bin_agnostic_baker/run_args.ml @@ -0,0 +1,91 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +let binaries_directory_arg = "--binaries-directory" + +let endpoint_arg = "--endpoint" + +let endpoint_short_arg = "-E" + +let base_dir_arg = "--base-dir" + +let base_dir_short_arg = "--b" + +let help_arg = "--help" + +let print_help () = + Format.printf + "Usage:\n\ + \ octez-agnostic-baker [OCTEZ-AGNOSTIC-BAKER-COMMANDS] -- \ + [OCTEZ-BAKER-COMMANDS]@.@." ; + Format.printf + "OCTEZ-AGNOSTIC-BAKER-COMMANDS:\n\ + \ %s: display help\n\ + \ %s: path to the octez-baker binaries@.@." + help_arg + binaries_directory_arg ; + Format.printf + "OCTEZ-BAKER-COMMANDS:\n Run ./octez-baker- --help@." + +let help_cmd args = + if List.mem ~equal:String.equal help_arg args then ( + print_help () ; + exit 0) + else () + +let version_cmd args = + if List.mem ~equal:String.equal "--version" args then ( + Format.printf "%s@." Tezos_version_value.Bin_version.octez_version_string ; + exit 0) + else () + +let split_args ?(on = "--") = + let rec loop acc = function + | [] -> (List.rev acc, []) + | hd :: tl when hd = on -> (List.rev acc, tl) + | hd :: tl -> loop (hd :: acc) tl + in + loop [] + +let get_arg_value ~arg ?(short_arg = "") = + let rec loop = function + | [] -> None + | x :: y :: _ when x = arg || x = short_arg -> Some y + | _ :: l -> loop l + in + loop + +let get_endpoint = get_arg_value ~arg:endpoint_arg ~short_arg:endpoint_short_arg + +let get_binaries_directory = get_arg_value ~arg:binaries_directory_arg + +let fail_on_empty_baker_args baker_args = + if List.is_empty baker_args then ( + Format.eprintf + "Cannot run agnostic baker without any baker arguments. Please refer to \ + the following help:@." ; + print_help () ; + exit 1) + +let get_base_dir = get_arg_value ~arg:base_dir_arg ~short_arg:base_dir_short_arg + +let parse_args all_args = + let all_args = Array.to_list all_args in + (* Specific vesrion case *) + let () = version_cmd all_args in + (* Remove the binary path *) + let all_args = Option.value ~default:[] (List.tl all_args) in + (* Split agnostic baker and baker arguments, that aims to be delimited by -- *) + let agnostic_baker_args, baker_args = split_args all_args in + let () = fail_on_empty_baker_args baker_args in + let () = help_cmd agnostic_baker_args in + let endpoint = + Option.value ~default:Parameters.default_node_addr (get_endpoint baker_args) + in + let binaries_directory = get_binaries_directory agnostic_baker_args in + let base_dir = get_base_dir baker_args in + (endpoint, base_dir, binaries_directory, baker_args) -- GitLab From ff12efd48bafd96cc884dd3f6581abb247b63663 Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 09:22:22 +0200 Subject: [PATCH 02/12] Agnostic_baker: standalone events module --- .../agnostic_baker_events.ml | 90 ++++++++++++++ src/bin_agnostic_baker/main_agnostic_baker.ml | 115 +++--------------- 2 files changed, 108 insertions(+), 97 deletions(-) create mode 100644 src/bin_agnostic_baker/agnostic_baker_events.ml diff --git a/src/bin_agnostic_baker/agnostic_baker_events.ml b/src/bin_agnostic_baker/agnostic_baker_events.ml new file mode 100644 index 000000000000..00ba3eeb3527 --- /dev/null +++ b/src/bin_agnostic_baker/agnostic_baker_events.ml @@ -0,0 +1,90 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +include Internal_event.Simple + +let section = ["agnostic-baker"] + +let alternative_color = Internal_event.Green + +(* Notice *) +let starting_baker = + declare_2 + ~section + ~alternative_color + ~level:Notice + ~name:"starting_baker" + ~msg:"starting baker for protocol {proto} with arguments: {args}" + ("proto", Protocol_hash.encoding) + ("args", string) + ~pp1:Protocol_hash.pp_short + +let baker_running = + declare_1 + ~section + ~alternative_color + ~level:Notice + ~name:"baker_running" + ~msg:"baker for protocol {proto} is now running" + ("proto", Protocol_hash.encoding) + ~pp1:Protocol_hash.pp_short + +let stopping_baker = + declare_1 + ~section + ~level:Notice + ~name:"stopping_baker" + ~msg:"stopping baker for protocol {proto}" + ("proto", Protocol_hash.encoding) + ~pp1:Protocol_hash.pp_short + +let starting_daemon = + declare_0 + ~section + ~alternative_color + ~level:Notice + ~name:"starting_daemon" + ~msg:"agnostic baker started" + () + +let stopping_daemon = + declare_0 + ~section + ~level:Notice + ~name:"stopping_daemon" + ~msg:"stopping agnostic daemon" + () + +let protocol_encountered = + declare_2 + ~section + ~level:Notice + ~name:"protocol_encountered" + ~msg:"the {status} protocol {proto_hash} was encountered" + ("status", Parameters.status_encoding) + ~pp1:Parameters.pp_status + ("proto_hash", Protocol_hash.encoding) + ~pp2:Protocol_hash.pp_short + +let waiting_for_active_protocol = + declare_0 + ~section + ~alternative_color + ~level:Notice + ~name:"waiting_for_active_protocol" + ~msg:"waiting for active protocol" + () + +let period_status = + declare_2 + ~section + ~alternative_color + ~level:Notice + ~name:"period_status" + ~msg:"new block on {period} period (remaining period duration {remaining})" + ("period", string) + ("remaining", int31) diff --git a/src/bin_agnostic_baker/main_agnostic_baker.ml b/src/bin_agnostic_baker/main_agnostic_baker.ml index f61857f7d44d..8322f777265f 100644 --- a/src/bin_agnostic_baker/main_agnostic_baker.ml +++ b/src/bin_agnostic_baker/main_agnostic_baker.ml @@ -43,93 +43,6 @@ let () = (function Lost_node_connection -> Some () | _ -> None) (fun () -> Lost_node_connection) -module Events = struct - include Internal_event.Simple - - let section = ["agnostic-baker"] - - let alternative_color = Internal_event.Green - - (* Notice *) - let starting_baker = - declare_2 - ~section - ~alternative_color - ~level:Notice - ~name:"starting_baker" - ~msg:"starting baker for protocol {proto} with arguments: {args}" - ("proto", Protocol_hash.encoding) - ("args", string) - ~pp1:Protocol_hash.pp_short - - let baker_running = - declare_1 - ~section - ~alternative_color - ~level:Notice - ~name:"baker_running" - ~msg:"baker for protocol {proto} is now running" - ("proto", Protocol_hash.encoding) - ~pp1:Protocol_hash.pp_short - - let stopping_baker = - declare_1 - ~section - ~level:Notice - ~name:"stopping_baker" - ~msg:"stopping baker for protocol {proto}" - ("proto", Protocol_hash.encoding) - ~pp1:Protocol_hash.pp_short - - let starting_daemon = - declare_0 - ~section - ~alternative_color - ~level:Notice - ~name:"starting_daemon" - ~msg:"agnostic baker started" - () - - let stopping_daemon = - declare_0 - ~section - ~level:Notice - ~name:"stopping_daemon" - ~msg:"stopping agnostic daemon" - () - - let protocol_encountered = - declare_2 - ~section - ~level:Notice - ~name:"protocol_encountered" - ~msg:"the {status} protocol {proto_hash} was encountered" - ("status", Parameters.status_encoding) - ~pp1:Parameters.pp_status - ("proto_hash", Protocol_hash.encoding) - ~pp2:Protocol_hash.pp_short - - let waiting_for_active_protocol = - declare_0 - ~section - ~alternative_color - ~level:Notice - ~name:"waiting_for_active_protocol" - ~msg:"waiting for active protocol" - () - - let period_status = - declare_2 - ~section - ~alternative_color - ~level:Notice - ~name:"period_status" - ~msg: - "new block on {period} period (remaining period duration {remaining})" - ("period", string) - ("remaining", int31) -end - module Baker = struct type t = { protocol_hash : Protocol_hash.t; @@ -146,7 +59,7 @@ module Baker = struct let shutdown protocol_hash process = let open Lwt_syntax in - let* () = Events.(emit stopping_baker) protocol_hash in + let* () = Agnostic_baker_events.(emit stopping_baker) protocol_hash in process#terminate ; Lwt.return_unit @@ -160,7 +73,9 @@ module Baker = struct Format.pp_print_string) baker_args in - let*! () = Events.(emit starting_baker) (protocol_hash, args_as_string) in + let*! () = + Agnostic_baker_events.(emit starting_baker) (protocol_hash, args_as_string) + in let binary_path = baker_path ?user_path:binaries_directory protocol_hash in let baker_args = binary_path :: baker_args in let baker_args = Array.of_list baker_args in @@ -170,7 +85,7 @@ module Baker = struct ~stderr:`Keep (binary_path, baker_args) in - let*! () = Events.(emit baker_running) protocol_hash in + let*! () = Agnostic_baker_events.(emit baker_running) protocol_hash in let ccid = Lwt_exit.register_clean_up_callback ~loc:__LOC__ (fun _ -> let*! () = shutdown protocol_hash process in @@ -330,7 +245,8 @@ module Daemon = struct Parameters.protocol_status (Protocol_hash.to_b58check next_protocol_hash) in let*! () = - Events.(emit protocol_encountered) (next_proto_status, next_protocol_hash) + Agnostic_baker_events.(emit protocol_encountered) + (next_proto_status, next_protocol_hash) in let*! () = match state.current_baker with @@ -358,7 +274,9 @@ module Daemon = struct match v with | Some _tick -> let* period_kind, remaining = RPC.get_current_period ~node_addr in - let*! () = Events.(emit period_status) (period_kind, remaining) in + let*! () = + Agnostic_baker_events.(emit period_status) (period_kind, remaining) + in let* next_protocol_hash = RPC.get_next_protocol_hash ~node_addr in let current_protocol_hash = match state.current_baker with @@ -396,7 +314,8 @@ module Daemon = struct | None -> Lwt.return_unit | Some h -> if not (Protocol_hash.equal h protocol_hash) then - Events.(emit protocol_encountered) (proto_status, protocol_hash) + Agnostic_baker_events.(emit protocol_encountered) + (proto_status, protocol_hash) else Lwt.return_unit in match proto_status with @@ -415,10 +334,12 @@ module Daemon = struct | Some v -> return v | None -> let*! () = - Events.(emit protocol_encountered) + Agnostic_baker_events.(emit protocol_encountered) (proto_status, protocol_hash) in - let*! () = Events.(emit waiting_for_active_protocol) () in + let*! () = + Agnostic_baker_events.(emit waiting_for_active_protocol) () + in monitor_heads ~node_addr:state.node_endpoint in let*! v = Lwt_stream.get head_stream in @@ -435,10 +356,10 @@ module Daemon = struct let run ~state = let open Lwt_result_syntax in let node_addr = state.node_endpoint in - let*! () = Events.(emit starting_daemon) () in + let*! () = Agnostic_baker_events.(emit starting_daemon) () in let _ccid = Lwt_exit.register_clean_up_callback ~loc:__LOC__ (fun _ -> - let*! () = Events.(emit stopping_daemon) () in + let*! () = Agnostic_baker_events.(emit stopping_daemon) () in Lwt.return_unit) in let* () = may_start_initial_baker state in -- GitLab From da690a869aff71b3f516d8295e73a9bce42ea632 Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 09:25:25 +0200 Subject: [PATCH 03/12] Agnostic_baker: standalone Rpc_services module --- src/bin_agnostic_baker/main_agnostic_baker.ml | 154 ++---------------- src/bin_agnostic_baker/rpc_services.ml | 141 ++++++++++++++++ 2 files changed, 151 insertions(+), 144 deletions(-) create mode 100644 src/bin_agnostic_baker/rpc_services.ml diff --git a/src/bin_agnostic_baker/main_agnostic_baker.ml b/src/bin_agnostic_baker/main_agnostic_baker.ml index 8322f777265f..642e1b477174 100644 --- a/src/bin_agnostic_baker/main_agnostic_baker.ml +++ b/src/bin_agnostic_baker/main_agnostic_baker.ml @@ -5,34 +5,9 @@ (* *) (*****************************************************************************) -type error += - | Cannot_connect_to_node of string - | Cannot_decode_node_data of string - | Lost_node_connection +type error += Lost_node_connection let () = - Error_monad.register_error_kind - `Permanent - ~id:"agnostic_baker.cannot_connect_to_node" - ~title:"Cannot connect to node" - ~description:"Cannot connect to node." - ~pp:(fun ppf uri -> - Format.fprintf - ppf - "Cannot connect to node. Connection refused (ECONNREFUSED): %s" - uri) - Data_encoding.(obj1 (req "uri" string)) - (function Cannot_connect_to_node uri -> Some uri | _ -> None) - (fun uri -> Cannot_connect_to_node uri) ; - Error_monad.register_error_kind - `Permanent - ~id:"agnostic_baker.cannot_decode_node_data" - ~title:"Cannot decode node data" - ~description:"Cannot decode node data." - ~pp:(fun ppf err -> Format.fprintf ppf "Cannot decode node data: %s" err) - Data_encoding.(obj1 (req "err" string)) - (function Cannot_decode_node_data err -> Some err | _ -> None) - (fun err -> Cannot_decode_node_data err) ; Error_monad.register_error_kind `Permanent ~id:"agnostic_baker.lost_node_connection" @@ -94,119 +69,6 @@ module Baker = struct return {protocol_hash; binary_path; process; ccid} end -module RPC = struct - open Cohttp_lwt_unix - - let request_uri ~node_addr ~uri = - let open Lwt_result_syntax in - Lwt.catch - (fun () -> - let*! r = Client.get (Uri.of_string uri) in - return r) - (function - | Unix.(Unix_error (ECONNREFUSED, _, _)) -> - tzfail (Cannot_connect_to_node node_addr) - | e -> raise e) - - let call_and_wrap_rpc ~node_addr ~uri ~f = - let open Lwt_result_syntax in - let* resp, body = request_uri ~node_addr ~uri in - let*! body_str = Cohttp_lwt.Body.to_string body in - match resp.status with - | `OK -> - let* json = - match Data_encoding.Json.from_string body_str with - | Ok json -> return json - | Error e -> tzfail (Cannot_decode_node_data e) - in - f json - | #Cohttp.Code.status_code -> - let*! () = - Lwt_fmt.printf - "Cannot fetch from node %s. Response status code %d\n%!" - uri - (Cohttp.Code.code_of_status resp.status) - in - raise Not_found - - let get_next_protocol_hash ~node_addr = - let open Lwt_result_syntax in - let f json = - (* Next_protocol hash field in the RPC result *) - let name = "next_protocol" in - let* v = - match json with - | `O fields -> ( - match List.assoc_opt ~equal:( = ) name fields with - | None -> tzfail (Cannot_decode_node_data ("missing field " ^ name)) - | Some node -> return node) - | _ -> tzfail (Cannot_decode_node_data "not an object") - in - let hash = Protocol_hash.of_b58check_exn (Ezjsonm.get_string v) in - return hash - in - let uri = Format.sprintf "%s/chains/main/blocks/head/metadata" node_addr in - call_and_wrap_rpc ~node_addr ~uri ~f - - let get_current_proposal ~node_addr = - let open Lwt_result_syntax in - let f json = - match json with - | `Null -> return_none - | `String s -> return_some @@ Protocol_hash.of_b58check_exn s - | _ -> tzfail (Cannot_decode_node_data "not an object") - in - let uri = - Format.sprintf - "%s/chains/main/blocks/head/votes/current_proposal" - node_addr - in - call_and_wrap_rpc ~node_addr ~uri ~f - - let get_current_period ~node_addr = - let open Lwt_result_syntax in - let voting_period_field = "voting_period" in - let kind_field = "kind" in - let remaining_field = "remaining" in - let f json = - let* kind = - match json with - | `O fields -> ( - match List.assoc_opt ~equal:( = ) voting_period_field fields with - | None -> - tzfail - (Cannot_decode_node_data - ("missing field " ^ voting_period_field)) - | Some node -> ( - match node with - | `O fields -> ( - match List.assoc_opt ~equal:( = ) kind_field fields with - | None -> - tzfail - (Cannot_decode_node_data - ("missing field " ^ voting_period_field)) - | Some node -> return @@ Ezjsonm.get_string node) - | _ -> tzfail (Cannot_decode_node_data "not an object"))) - | _ -> tzfail (Cannot_decode_node_data "not an object") - in - let* remaining = - match json with - | `O fields -> ( - match List.assoc_opt ~equal:( = ) remaining_field fields with - | None -> - tzfail - (Cannot_decode_node_data ("missing field " ^ remaining_field)) - | Some node -> return @@ Ezjsonm.get_int node) - | _ -> tzfail (Cannot_decode_node_data "not an object") - in - return (kind, remaining) - in - let uri = - Format.sprintf "%s/chains/main/blocks/head/votes/current_period" node_addr - in - call_and_wrap_rpc ~node_addr ~uri ~f -end - module Daemon = struct type state = { binaries_directory : string option; @@ -218,7 +80,7 @@ module Daemon = struct let monitor_heads ~node_addr = let open Lwt_result_syntax in let uri = Format.sprintf "%s/monitor/heads/main" node_addr in - let* _, body = RPC.request_uri ~node_addr ~uri in + let* _, body = Rpc_services.request_uri ~node_addr ~uri in let cohttp_stream = Cohttp_lwt.Body.to_stream body in let buffer = Buffer.create 2048 in let stream, push = Lwt_stream.create () in @@ -273,11 +135,15 @@ module Daemon = struct let*! v = Lwt_stream.get head_stream in match v with | Some _tick -> - let* period_kind, remaining = RPC.get_current_period ~node_addr in + let* period_kind, remaining = + Rpc_services.get_current_period ~node_addr + in let*! () = Agnostic_baker_events.(emit period_status) (period_kind, remaining) in - let* next_protocol_hash = RPC.get_next_protocol_hash ~node_addr in + let* next_protocol_hash = + Rpc_services.get_next_protocol_hash ~node_addr + in let current_protocol_hash = match state.current_baker with | None -> assert false @@ -304,7 +170,7 @@ module Daemon = struct let open Lwt_result_syntax in let rec may_start ?last_known_proto ~head_stream () = let* protocol_hash = - RPC.get_next_protocol_hash ~node_addr:state.node_endpoint + Rpc_services.get_next_protocol_hash ~node_addr:state.node_endpoint in let proto_status = Parameters.protocol_status (Protocol_hash.to_b58check protocol_hash) @@ -363,7 +229,7 @@ module Daemon = struct Lwt.return_unit) in let* () = may_start_initial_baker state in - let* _protocol_proposal = RPC.get_current_proposal ~node_addr in + let* _protocol_proposal = Rpc_services.get_current_proposal ~node_addr in let* head_stream = monitor_heads ~node_addr in (* Monitoring voting periods through heads monitoring to avoid missing UAUs. *) diff --git a/src/bin_agnostic_baker/rpc_services.ml b/src/bin_agnostic_baker/rpc_services.ml new file mode 100644 index 000000000000..7504e01fd7ba --- /dev/null +++ b/src/bin_agnostic_baker/rpc_services.ml @@ -0,0 +1,141 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs, *) +(* *) +(*****************************************************************************) +type error += + | Cannot_connect_to_node of string + | Cannot_decode_node_data of string + +let () = + Error_monad.register_error_kind + `Permanent + ~id:"agnostic_baker.cannot_connect_to_node" + ~title:"Cannot connect to node" + ~description:"Cannot connect to node." + ~pp:(fun ppf uri -> + Format.fprintf + ppf + "Cannot connect to node. Connection refused (ECONNREFUSED): %s" + uri) + Data_encoding.(obj1 (req "uri" string)) + (function Cannot_connect_to_node uri -> Some uri | _ -> None) + (fun uri -> Cannot_connect_to_node uri) ; + Error_monad.register_error_kind + `Permanent + ~id:"agnostic_baker.cannot_decode_node_data" + ~title:"Cannot decode node data" + ~description:"Cannot decode node data." + ~pp:(fun ppf err -> Format.fprintf ppf "Cannot decode node data: %s" err) + Data_encoding.(obj1 (req "err" string)) + (function Cannot_decode_node_data err -> Some err | _ -> None) + (fun err -> Cannot_decode_node_data err) + +open Cohttp_lwt_unix + +let request_uri ~node_addr ~uri = + let open Lwt_result_syntax in + Lwt.catch + (fun () -> + let*! r = Client.get (Uri.of_string uri) in + return r) + (function + | Unix.(Unix_error (ECONNREFUSED, _, _)) -> + tzfail (Cannot_connect_to_node node_addr) + | e -> raise e) + +let call_and_wrap_rpc ~node_addr ~uri ~f = + let open Lwt_result_syntax in + let* resp, body = request_uri ~node_addr ~uri in + let*! body_str = Cohttp_lwt.Body.to_string body in + match resp.status with + | `OK -> + let* json = + match Data_encoding.Json.from_string body_str with + | Ok json -> return json + | Error e -> tzfail (Cannot_decode_node_data e) + in + f json + | #Cohttp.Code.status_code -> + let*! () = + Lwt_fmt.printf + "Cannot fetch from node %s. Response status code %d\n%!" + uri + (Cohttp.Code.code_of_status resp.status) + in + raise Not_found + +let get_next_protocol_hash ~node_addr = + let open Lwt_result_syntax in + let f json = + (* Next_protocol hash field in the RPC result *) + let name = "next_protocol" in + let* v = + match json with + | `O fields -> ( + match List.assoc_opt ~equal:( = ) name fields with + | None -> tzfail (Cannot_decode_node_data ("missing field " ^ name)) + | Some node -> return node) + | _ -> tzfail (Cannot_decode_node_data "not an object") + in + let hash = Protocol_hash.of_b58check_exn (Ezjsonm.get_string v) in + return hash + in + let uri = Format.sprintf "%s/chains/main/blocks/head/metadata" node_addr in + call_and_wrap_rpc ~node_addr ~uri ~f + +let get_current_proposal ~node_addr = + let open Lwt_result_syntax in + let f json = + match json with + | `Null -> return_none + | `String s -> return_some @@ Protocol_hash.of_b58check_exn s + | _ -> tzfail (Cannot_decode_node_data "not an object") + in + let uri = + Format.sprintf "%s/chains/main/blocks/head/votes/current_proposal" node_addr + in + call_and_wrap_rpc ~node_addr ~uri ~f + +let get_current_period ~node_addr = + let open Lwt_result_syntax in + let voting_period_field = "voting_period" in + let kind_field = "kind" in + let remaining_field = "remaining" in + let f json = + let* kind = + match json with + | `O fields -> ( + match List.assoc_opt ~equal:( = ) voting_period_field fields with + | None -> + tzfail + (Cannot_decode_node_data ("missing field " ^ voting_period_field)) + | Some node -> ( + match node with + | `O fields -> ( + match List.assoc_opt ~equal:( = ) kind_field fields with + | None -> + tzfail + (Cannot_decode_node_data + ("missing field " ^ voting_period_field)) + | Some node -> return @@ Ezjsonm.get_string node) + | _ -> tzfail (Cannot_decode_node_data "not an object"))) + | _ -> tzfail (Cannot_decode_node_data "not an object") + in + let* remaining = + match json with + | `O fields -> ( + match List.assoc_opt ~equal:( = ) remaining_field fields with + | None -> + tzfail + (Cannot_decode_node_data ("missing field " ^ remaining_field)) + | Some node -> return @@ Ezjsonm.get_int node) + | _ -> tzfail (Cannot_decode_node_data "not an object") + in + return (kind, remaining) + in + let uri = + Format.sprintf "%s/chains/main/blocks/head/votes/current_period" node_addr + in + call_and_wrap_rpc ~node_addr ~uri ~f -- GitLab From 623e4e7f4d3e9276a87625dff6ef23b82db739b8 Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 09:28:40 +0200 Subject: [PATCH 04/12] Agnostic_baker: standalone Daemon module --- src/bin_agnostic_baker/daemon.ml | 234 ++++++++++++++++++ src/bin_agnostic_baker/main_agnostic_baker.ml | 232 ----------------- 2 files changed, 234 insertions(+), 232 deletions(-) create mode 100644 src/bin_agnostic_baker/daemon.ml diff --git a/src/bin_agnostic_baker/daemon.ml b/src/bin_agnostic_baker/daemon.ml new file mode 100644 index 000000000000..fa0516e2d5fe --- /dev/null +++ b/src/bin_agnostic_baker/daemon.ml @@ -0,0 +1,234 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs, *) +(* *) +(*****************************************************************************) +type error += Lost_node_connection + +let () = + Error_monad.register_error_kind + `Permanent + ~id:"agnostic_baker.lost_node_connection" + ~title:"Lost node connection" + ~description:"Connection with node lost." + ~pp:(fun ppf () -> Format.fprintf ppf "Connection with node was lost") + Data_encoding.(unit) + (function Lost_node_connection -> Some () | _ -> None) + (fun () -> Lost_node_connection) + +module Baker = struct + type t = { + protocol_hash : Protocol_hash.t; + binary_path : string; + process : Lwt_process.process_none; + ccid : Lwt_exit.clean_up_callback_id; + } + + let baker_path ?(user_path = "./") proto_hash = + let short_name = + Parameters.protocol_short_hash (Protocol_hash.to_b58check proto_hash) + in + Format.sprintf "%soctez-baker-%s" user_path short_name + + let shutdown protocol_hash process = + let open Lwt_syntax in + let* () = Agnostic_baker_events.(emit stopping_baker) protocol_hash in + process#terminate ; + Lwt.return_unit + + let spawn_baker protocol_hash ~binaries_directory ~baker_args = + let open Lwt_result_syntax in + let args_as_string = + Format.asprintf + "%a" + (Format.pp_print_list + ~pp_sep:Format.pp_print_space + Format.pp_print_string) + baker_args + in + let*! () = + Agnostic_baker_events.(emit starting_baker) (protocol_hash, args_as_string) + in + let binary_path = baker_path ?user_path:binaries_directory protocol_hash in + let baker_args = binary_path :: baker_args in + let baker_args = Array.of_list baker_args in + let process = + Lwt_process.open_process_none + ~stdout:`Keep + ~stderr:`Keep + (binary_path, baker_args) + in + let*! () = Agnostic_baker_events.(emit baker_running) protocol_hash in + let ccid = + Lwt_exit.register_clean_up_callback ~loc:__LOC__ (fun _ -> + let*! () = shutdown protocol_hash process in + Lwt.return_unit) + in + return {protocol_hash; binary_path; process; ccid} +end + +type state = { + binaries_directory : string option; + node_endpoint : string; + baker_args : string list; + mutable current_baker : Baker.t option; +} + +let monitor_heads ~node_addr = + let open Lwt_result_syntax in + let uri = Format.sprintf "%s/monitor/heads/main" node_addr in + let* _, body = Rpc_services.request_uri ~node_addr ~uri in + let cohttp_stream = Cohttp_lwt.Body.to_stream body in + let buffer = Buffer.create 2048 in + let stream, push = Lwt_stream.create () in + let on_chunk v = push (Some v) and on_close () = push None in + let rec loop () = + let*! v = Lwt_stream.get cohttp_stream in + match v with + | None -> + on_close () ; + Lwt.return_unit + | Some chunk -> + Buffer.add_string buffer chunk ; + let data = Buffer.contents buffer in + Buffer.reset buffer ; + on_chunk data ; + loop () + in + ignore (loop () : unit Lwt.t) ; + return stream + +let hot_swap_baker ~state ~next_protocol_hash = + let open Lwt_result_syntax in + let next_proto_status = + Parameters.protocol_status (Protocol_hash.to_b58check next_protocol_hash) + in + let*! () = + Agnostic_baker_events.(emit protocol_encountered) + (next_proto_status, next_protocol_hash) + in + let*! () = + match state.current_baker with + | None -> Lwt.return_unit (* Could be assert false*) + | Some b -> + let*! () = Baker.shutdown b.protocol_hash b.process in + let () = Lwt_exit.unregister_clean_up_callback b.ccid in + state.current_baker <- None ; + Lwt.return_unit + in + let* new_baker = + Baker.spawn_baker + next_protocol_hash + ~binaries_directory:state.binaries_directory + ~baker_args:state.baker_args + in + state.current_baker <- Some new_baker ; + return_unit + +let monitor_voting_periods ~state head_stream = + let open Lwt_result_syntax in + let node_addr = state.node_endpoint in + let rec loop () = + let*! v = Lwt_stream.get head_stream in + match v with + | Some _tick -> + let* period_kind, remaining = + Rpc_services.get_current_period ~node_addr + in + let*! () = + Agnostic_baker_events.(emit period_status) (period_kind, remaining) + in + let* next_protocol_hash = + Rpc_services.get_next_protocol_hash ~node_addr + in + let current_protocol_hash = + match state.current_baker with + | None -> assert false + | Some v -> v.protocol_hash + in + let* () = + if not (Protocol_hash.equal current_protocol_hash next_protocol_hash) + then hot_swap_baker ~state ~next_protocol_hash + else return_unit + in + loop () + | None -> return_unit + in + let* () = loop () in + return_unit + +(* Aims to start the baker associated to the current protocol. If + the protocol is considered as frozen (not active anymore), and + there is thus no actual baker binary anymore, the initial phase + consist in waiting until an active protocol is observed on + monitored heads. *) +let may_start_initial_baker state = + let open Lwt_result_syntax in + let rec may_start ?last_known_proto ~head_stream () = + let* protocol_hash = + Rpc_services.get_next_protocol_hash ~node_addr:state.node_endpoint + in + let proto_status = + Parameters.protocol_status (Protocol_hash.to_b58check protocol_hash) + in + let*! () = + match last_known_proto with + | None -> Lwt.return_unit + | Some h -> + if not (Protocol_hash.equal h protocol_hash) then + Agnostic_baker_events.(emit protocol_encountered) + (proto_status, protocol_hash) + else Lwt.return_unit + in + match proto_status with + | Active -> + let* current_baker = + Baker.spawn_baker + protocol_hash + ~binaries_directory:state.binaries_directory + ~baker_args:state.baker_args + in + state.current_baker <- Some current_baker ; + return_unit + | Frozen -> ( + let* head_stream = + match head_stream with + | Some v -> return v + | None -> + let*! () = + Agnostic_baker_events.(emit protocol_encountered) + (proto_status, protocol_hash) + in + let*! () = + Agnostic_baker_events.(emit waiting_for_active_protocol) () + in + monitor_heads ~node_addr:state.node_endpoint + in + let*! v = Lwt_stream.get head_stream in + match v with + | Some _tick -> + may_start + ~last_known_proto:protocol_hash + ~head_stream:(Some head_stream) + () + | None -> tzfail Lost_node_connection) + in + may_start ~head_stream:None () + +let run ~state = + let open Lwt_result_syntax in + let node_addr = state.node_endpoint in + let*! () = Agnostic_baker_events.(emit starting_daemon) () in + let _ccid = + Lwt_exit.register_clean_up_callback ~loc:__LOC__ (fun _ -> + let*! () = Agnostic_baker_events.(emit stopping_daemon) () in + Lwt.return_unit) + in + let* () = may_start_initial_baker state in + let* _protocol_proposal = Rpc_services.get_current_proposal ~node_addr in + let* head_stream = monitor_heads ~node_addr in + (* Monitoring voting periods through heads monitoring to avoid + missing UAUs. *) + let* () = monitor_voting_periods ~state head_stream in + return_unit diff --git a/src/bin_agnostic_baker/main_agnostic_baker.ml b/src/bin_agnostic_baker/main_agnostic_baker.ml index 642e1b477174..b6bbd9abaeb9 100644 --- a/src/bin_agnostic_baker/main_agnostic_baker.ml +++ b/src/bin_agnostic_baker/main_agnostic_baker.ml @@ -5,238 +5,6 @@ (* *) (*****************************************************************************) -type error += Lost_node_connection - -let () = - Error_monad.register_error_kind - `Permanent - ~id:"agnostic_baker.lost_node_connection" - ~title:"Lost node connection" - ~description:"Connection with node lost." - ~pp:(fun ppf () -> Format.fprintf ppf "Connection with node was lost") - Data_encoding.(unit) - (function Lost_node_connection -> Some () | _ -> None) - (fun () -> Lost_node_connection) - -module Baker = struct - type t = { - protocol_hash : Protocol_hash.t; - binary_path : string; - process : Lwt_process.process_none; - ccid : Lwt_exit.clean_up_callback_id; - } - - let baker_path ?(user_path = "./") proto_hash = - let short_name = - Parameters.protocol_short_hash (Protocol_hash.to_b58check proto_hash) - in - Format.sprintf "%soctez-baker-%s" user_path short_name - - let shutdown protocol_hash process = - let open Lwt_syntax in - let* () = Agnostic_baker_events.(emit stopping_baker) protocol_hash in - process#terminate ; - Lwt.return_unit - - let spawn_baker protocol_hash ~binaries_directory ~baker_args = - let open Lwt_result_syntax in - let args_as_string = - Format.asprintf - "%a" - (Format.pp_print_list - ~pp_sep:Format.pp_print_space - Format.pp_print_string) - baker_args - in - let*! () = - Agnostic_baker_events.(emit starting_baker) (protocol_hash, args_as_string) - in - let binary_path = baker_path ?user_path:binaries_directory protocol_hash in - let baker_args = binary_path :: baker_args in - let baker_args = Array.of_list baker_args in - let process = - Lwt_process.open_process_none - ~stdout:`Keep - ~stderr:`Keep - (binary_path, baker_args) - in - let*! () = Agnostic_baker_events.(emit baker_running) protocol_hash in - let ccid = - Lwt_exit.register_clean_up_callback ~loc:__LOC__ (fun _ -> - let*! () = shutdown protocol_hash process in - Lwt.return_unit) - in - return {protocol_hash; binary_path; process; ccid} -end - -module Daemon = struct - type state = { - binaries_directory : string option; - node_endpoint : string; - baker_args : string list; - mutable current_baker : Baker.t option; - } - - let monitor_heads ~node_addr = - let open Lwt_result_syntax in - let uri = Format.sprintf "%s/monitor/heads/main" node_addr in - let* _, body = Rpc_services.request_uri ~node_addr ~uri in - let cohttp_stream = Cohttp_lwt.Body.to_stream body in - let buffer = Buffer.create 2048 in - let stream, push = Lwt_stream.create () in - let on_chunk v = push (Some v) and on_close () = push None in - let rec loop () = - let*! v = Lwt_stream.get cohttp_stream in - match v with - | None -> - on_close () ; - Lwt.return_unit - | Some chunk -> - Buffer.add_string buffer chunk ; - let data = Buffer.contents buffer in - Buffer.reset buffer ; - on_chunk data ; - loop () - in - ignore (loop () : unit Lwt.t) ; - return stream - - let hot_swap_baker ~state ~next_protocol_hash = - let open Lwt_result_syntax in - let next_proto_status = - Parameters.protocol_status (Protocol_hash.to_b58check next_protocol_hash) - in - let*! () = - Agnostic_baker_events.(emit protocol_encountered) - (next_proto_status, next_protocol_hash) - in - let*! () = - match state.current_baker with - | None -> Lwt.return_unit (* Could be assert false*) - | Some b -> - let*! () = Baker.shutdown b.protocol_hash b.process in - let () = Lwt_exit.unregister_clean_up_callback b.ccid in - state.current_baker <- None ; - Lwt.return_unit - in - let* new_baker = - Baker.spawn_baker - next_protocol_hash - ~binaries_directory:state.binaries_directory - ~baker_args:state.baker_args - in - state.current_baker <- Some new_baker ; - return_unit - - let monitor_voting_periods ~state head_stream = - let open Lwt_result_syntax in - let node_addr = state.node_endpoint in - let rec loop () = - let*! v = Lwt_stream.get head_stream in - match v with - | Some _tick -> - let* period_kind, remaining = - Rpc_services.get_current_period ~node_addr - in - let*! () = - Agnostic_baker_events.(emit period_status) (period_kind, remaining) - in - let* next_protocol_hash = - Rpc_services.get_next_protocol_hash ~node_addr - in - let current_protocol_hash = - match state.current_baker with - | None -> assert false - | Some v -> v.protocol_hash - in - let* () = - if - not (Protocol_hash.equal current_protocol_hash next_protocol_hash) - then hot_swap_baker ~state ~next_protocol_hash - else return_unit - in - loop () - | None -> return_unit - in - let* () = loop () in - return_unit - - (* Aims to start the baker associated to the current protocol. If - the protocol is considered as frozen (not active anymore), and - there is thus no actual baker binary anymore, the initial phase - consist in waiting until an active protocol is observed on - monitored heads. *) - let may_start_initial_baker state = - let open Lwt_result_syntax in - let rec may_start ?last_known_proto ~head_stream () = - let* protocol_hash = - Rpc_services.get_next_protocol_hash ~node_addr:state.node_endpoint - in - let proto_status = - Parameters.protocol_status (Protocol_hash.to_b58check protocol_hash) - in - let*! () = - match last_known_proto with - | None -> Lwt.return_unit - | Some h -> - if not (Protocol_hash.equal h protocol_hash) then - Agnostic_baker_events.(emit protocol_encountered) - (proto_status, protocol_hash) - else Lwt.return_unit - in - match proto_status with - | Active -> - let* current_baker = - Baker.spawn_baker - protocol_hash - ~binaries_directory:state.binaries_directory - ~baker_args:state.baker_args - in - state.current_baker <- Some current_baker ; - return_unit - | Frozen -> ( - let* head_stream = - match head_stream with - | Some v -> return v - | None -> - let*! () = - Agnostic_baker_events.(emit protocol_encountered) - (proto_status, protocol_hash) - in - let*! () = - Agnostic_baker_events.(emit waiting_for_active_protocol) () - in - monitor_heads ~node_addr:state.node_endpoint - in - let*! v = Lwt_stream.get head_stream in - match v with - | Some _tick -> - may_start - ~last_known_proto:protocol_hash - ~head_stream:(Some head_stream) - () - | None -> tzfail Lost_node_connection) - in - may_start ~head_stream:None () - - let run ~state = - let open Lwt_result_syntax in - let node_addr = state.node_endpoint in - let*! () = Agnostic_baker_events.(emit starting_daemon) () in - let _ccid = - Lwt_exit.register_clean_up_callback ~loc:__LOC__ (fun _ -> - let*! () = Agnostic_baker_events.(emit stopping_daemon) () in - Lwt.return_unit) - in - let* () = may_start_initial_baker state in - let* _protocol_proposal = Rpc_services.get_current_proposal ~node_addr in - let* head_stream = monitor_heads ~node_addr in - (* Monitoring voting periods through heads monitoring to avoid - missing UAUs. *) - let* () = monitor_voting_periods ~state head_stream in - return_unit -end - let run () = let open Lwt_result_syntax in let node_endpoint, base_dir, binaries_directory, baker_args = -- GitLab From 29aaf4e474e2b3e0b491b9fc2853aa139fd9f4bb Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 09:51:20 +0200 Subject: [PATCH 05/12] Agnostic_baker: introduce Parameters interface --- src/bin_agnostic_baker/parameters.mli | 29 +++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/bin_agnostic_baker/parameters.mli diff --git a/src/bin_agnostic_baker/parameters.mli b/src/bin_agnostic_baker/parameters.mli new file mode 100644 index 000000000000..5ea9283fc9fa --- /dev/null +++ b/src/bin_agnostic_baker/parameters.mli @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** Default endpoint to contact the node. Based on the + [Octez_node_config.Config_file.default_rpc_port]. *) +val default_node_addr : string + +val log_config : base_dir:string option -> Tezos_base.Internal_event_config.t + +(** Status of a protocol, based on Manifest/Product_octez/Protocol. A + protocol is considered as Active while it is running on a network, + and thus, have dedicated binaries. Otherwise, the protocol is + Frozen as not running anymore and no associated binaries. + + Warning, it is needed to update status for each new protocol added. +*) +type status = Active | Frozen + +val pp_status : Format.formatter -> status -> unit + +val status_encoding : status t + +val protocol_short_hash : string -> string + +val protocol_status : string -> status -- GitLab From 06840c3f360b89f9ff4b3a5e272970598680360c Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 10:10:50 +0200 Subject: [PATCH 06/12] Agnostic_baker: improve and clean Parameters module --- src/bin_agnostic_baker/daemon.ml | 12 +++--------- src/bin_agnostic_baker/parameters.ml | 11 +++++++---- src/bin_agnostic_baker/parameters.mli | 6 +++--- src/bin_agnostic_baker/run_args.ml | 4 +++- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/bin_agnostic_baker/daemon.ml b/src/bin_agnostic_baker/daemon.ml index fa0516e2d5fe..4ffbb8d0300a 100644 --- a/src/bin_agnostic_baker/daemon.ml +++ b/src/bin_agnostic_baker/daemon.ml @@ -26,9 +26,7 @@ module Baker = struct } let baker_path ?(user_path = "./") proto_hash = - let short_name = - Parameters.protocol_short_hash (Protocol_hash.to_b58check proto_hash) - in + let short_name = Parameters.protocol_short_hash proto_hash in Format.sprintf "%soctez-baker-%s" user_path short_name let shutdown protocol_hash process = @@ -101,9 +99,7 @@ let monitor_heads ~node_addr = let hot_swap_baker ~state ~next_protocol_hash = let open Lwt_result_syntax in - let next_proto_status = - Parameters.protocol_status (Protocol_hash.to_b58check next_protocol_hash) - in + let next_proto_status = Parameters.protocol_status next_protocol_hash in let*! () = Agnostic_baker_events.(emit protocol_encountered) (next_proto_status, next_protocol_hash) @@ -169,9 +165,7 @@ let may_start_initial_baker state = let* protocol_hash = Rpc_services.get_next_protocol_hash ~node_addr:state.node_endpoint in - let proto_status = - Parameters.protocol_status (Protocol_hash.to_b58check protocol_hash) - in + let proto_status = Parameters.protocol_status protocol_hash in let*! () = match last_known_proto with | None -> Lwt.return_unit diff --git a/src/bin_agnostic_baker/parameters.ml b/src/bin_agnostic_baker/parameters.ml index d683a7e55ce2..8813b9a96c7c 100644 --- a/src/bin_agnostic_baker/parameters.ml +++ b/src/bin_agnostic_baker/parameters.ml @@ -5,7 +5,10 @@ (* *) (*****************************************************************************) -let default_node_addr = "http://127.0.0.1:8732" +let default_node_endpoint = + Format.sprintf + "http://localhost:%d" + Octez_node_config.Config_file.default_rpc_port let default_daily_logs_path = Some "octez-agnostic-baker" @@ -54,7 +57,7 @@ let status_encoding = ~title:"frozen" ~description: "Frozen protocols are currently unused on any network, and thus, \ - they do nothave dedicated delegate binaries." + they do not have dedicated delegate binaries." (Tag 1) (constant "frozen") (function Frozen -> Some () | _ -> None) @@ -93,6 +96,6 @@ let protocol_info = function | "ProtoALphaALphaALphaALphaALphaALphaALphaALphaDdp3zK" -> ("alpha", Active) | _ -> (*We assume that unmatched protocols are beta ones*) ("beta", Active) -let protocol_short_hash h = fst (protocol_info h) +let protocol_short_hash h = fst (protocol_info (Protocol_hash.to_b58check h)) -let protocol_status h = snd (protocol_info h) +let protocol_status h = snd (protocol_info (Protocol_hash.to_b58check h)) diff --git a/src/bin_agnostic_baker/parameters.mli b/src/bin_agnostic_baker/parameters.mli index 5ea9283fc9fa..1b57b0d250ec 100644 --- a/src/bin_agnostic_baker/parameters.mli +++ b/src/bin_agnostic_baker/parameters.mli @@ -7,7 +7,7 @@ (** Default endpoint to contact the node. Based on the [Octez_node_config.Config_file.default_rpc_port]. *) -val default_node_addr : string +val default_node_endpoint : string val log_config : base_dir:string option -> Tezos_base.Internal_event_config.t @@ -24,6 +24,6 @@ val pp_status : Format.formatter -> status -> unit val status_encoding : status t -val protocol_short_hash : string -> string +val protocol_short_hash : Protocol_hash.t -> string -val protocol_status : string -> status +val protocol_status : Protocol_hash.t -> status diff --git a/src/bin_agnostic_baker/run_args.ml b/src/bin_agnostic_baker/run_args.ml index a6566e523d36..686254961626 100644 --- a/src/bin_agnostic_baker/run_args.ml +++ b/src/bin_agnostic_baker/run_args.ml @@ -84,7 +84,9 @@ let parse_args all_args = let () = fail_on_empty_baker_args baker_args in let () = help_cmd agnostic_baker_args in let endpoint = - Option.value ~default:Parameters.default_node_addr (get_endpoint baker_args) + Option.value + ~default:Parameters.default_node_endpoint + (get_endpoint baker_args) in let binaries_directory = get_binaries_directory agnostic_baker_args in let base_dir = get_base_dir baker_args in -- GitLab From 19e03bb97c6ab08fb24049ea252c482582ad6b00 Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 09:54:53 +0200 Subject: [PATCH 07/12] Agnostic_baker: introduce Daemon interface --- src/bin_agnostic_baker/daemon.mli | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/bin_agnostic_baker/daemon.mli diff --git a/src/bin_agnostic_baker/daemon.mli b/src/bin_agnostic_baker/daemon.mli new file mode 100644 index 000000000000..fb830f7b9853 --- /dev/null +++ b/src/bin_agnostic_baker/daemon.mli @@ -0,0 +1,21 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** Daemon handling the bakers life cycle. *) + +module Baker : sig + type t +end + +type state = { + binaries_directory : string option; + node_endpoint : string; + baker_args : string list; + mutable current_baker : Baker.t option; +} + +val run : state:state -> unit tzresult Lwt.t -- GitLab From e448f8c00f731b9e06fbe1cbebb99d3969e0d1ef Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 09:58:27 +0200 Subject: [PATCH 08/12] Agnostic_baker: improve Daemon abstraction --- src/bin_agnostic_baker/daemon.ml | 7 ++++++- src/bin_agnostic_baker/daemon.mli | 21 ++++++++++--------- src/bin_agnostic_baker/main_agnostic_baker.ml | 7 ++----- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/bin_agnostic_baker/daemon.ml b/src/bin_agnostic_baker/daemon.ml index 4ffbb8d0300a..bb5b2bfb9c03 100644 --- a/src/bin_agnostic_baker/daemon.ml +++ b/src/bin_agnostic_baker/daemon.ml @@ -73,6 +73,8 @@ type state = { mutable current_baker : Baker.t option; } +type t = state + let monitor_heads ~node_addr = let open Lwt_result_syntax in let uri = Format.sprintf "%s/monitor/heads/main" node_addr in @@ -210,7 +212,10 @@ let may_start_initial_baker state = in may_start ~head_stream:None () -let run ~state = +let create ~binaries_directory ~node_endpoint ~baker_args = + {binaries_directory; node_endpoint; baker_args; current_baker = None} + +let run state = let open Lwt_result_syntax in let node_addr = state.node_endpoint in let*! () = Agnostic_baker_events.(emit starting_daemon) () in diff --git a/src/bin_agnostic_baker/daemon.mli b/src/bin_agnostic_baker/daemon.mli index fb830f7b9853..5dbd07c4d46d 100644 --- a/src/bin_agnostic_baker/daemon.mli +++ b/src/bin_agnostic_baker/daemon.mli @@ -7,15 +7,16 @@ (** Daemon handling the bakers life cycle. *) -module Baker : sig - type t -end +type t -type state = { - binaries_directory : string option; - node_endpoint : string; - baker_args : string list; - mutable current_baker : Baker.t option; -} +(** [create binaries_directory node_endpoint baker_args] returns a non + initialized daemon.*) +val create : + binaries_directory:string option -> + node_endpoint:string -> + baker_args:string trace -> + t -val run : state:state -> unit tzresult Lwt.t +(** [run t] Runs the daemon responsible for the spawn/stop of the + baker daemons. *) +val run : t -> unit tzresult Lwt.t diff --git a/src/bin_agnostic_baker/main_agnostic_baker.ml b/src/bin_agnostic_baker/main_agnostic_baker.ml index b6bbd9abaeb9..68bd7617c453 100644 --- a/src/bin_agnostic_baker/main_agnostic_baker.ml +++ b/src/bin_agnostic_baker/main_agnostic_baker.ml @@ -15,11 +15,8 @@ let run () = ~config:(Parameters.log_config ~base_dir) () in - let* _daemon = - Daemon.run - ~state: - {binaries_directory; node_endpoint; baker_args; current_baker = None} - in + let daemon = Daemon.create ~binaries_directory ~node_endpoint ~baker_args in + let* (_ : unit) = Daemon.run daemon in let*! () = Lwt_utils.never_ending () in return_unit -- GitLab From 739ebe58582704c5867ecc8a450db0884c5240a9 Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 10:02:16 +0200 Subject: [PATCH 09/12] Agnostic_baker: introduce Rpc_services interface --- src/bin_agnostic_baker/rpc_services.mli | 29 +++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/bin_agnostic_baker/rpc_services.mli diff --git a/src/bin_agnostic_baker/rpc_services.mli b/src/bin_agnostic_baker/rpc_services.mli new file mode 100644 index 000000000000..5b962315d3c9 --- /dev/null +++ b/src/bin_agnostic_baker/rpc_services.mli @@ -0,0 +1,29 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** request_uri ~node_addr ~uri] is a raw call that will return the + Cohttp response of a RPC call, given a [uri], against the + [node_addr]. *) +val request_uri : + node_addr:string -> + uri:string -> + (Cohttp_lwt_unix.Response.t * Cohttp_lwt.Body.t) tzresult Lwt.t + +(** [get_next_protocol_hash ~node_addr] returns the protocol hash + contained in the [next_protocol] field of the metadata of a + block. *) +val get_next_protocol_hash : node_addr:string -> Protocol_hash.t tzresult Lwt.t + +(** [get_next_protocol_hash ~node_addr] returns the protocol hash of + the current voting period, if any. *) +val get_current_proposal : + node_addr:string -> Protocol_hash.t option tzresult Lwt.t + +(** [get_next_protocol_hash ~node_addr] returns the current voting + period in addition to the number of remaining block until the end + of the period. *) +val get_current_period : node_addr:string -> (string * int) tzresult Lwt.t -- GitLab From c2353a1d7f4f17262852e747f575ee7e0f95a08d Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 10:03:22 +0200 Subject: [PATCH 10/12] Agnostic_baker: introduce Run_args interface --- src/bin_agnostic_baker/run_args.mli | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/bin_agnostic_baker/run_args.mli diff --git a/src/bin_agnostic_baker/run_args.mli b/src/bin_agnostic_baker/run_args.mli new file mode 100644 index 000000000000..124d40f490b5 --- /dev/null +++ b/src/bin_agnostic_baker/run_args.mli @@ -0,0 +1,12 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** [parse_args args] is a raw utility that aims to parse the give + arguments from the command line and to return, respectively, the + endpoint, base_dir, binaries_directory and baker_args. *) +val parse_args : + string array -> string * string option * string option * string list -- GitLab From 4368615ccdaa68065e75122e92606c79549e0c2f Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Thu, 17 Oct 2024 10:34:55 +0200 Subject: [PATCH 11/12] Agnostic_baker: improve Run_args abstraction --- src/bin_agnostic_baker/main_agnostic_baker.ml | 2 +- src/bin_agnostic_baker/run_args.ml | 11 +++++++++-- src/bin_agnostic_baker/run_args.mli | 11 +++++++++-- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/bin_agnostic_baker/main_agnostic_baker.ml b/src/bin_agnostic_baker/main_agnostic_baker.ml index 68bd7617c453..ac627582e02c 100644 --- a/src/bin_agnostic_baker/main_agnostic_baker.ml +++ b/src/bin_agnostic_baker/main_agnostic_baker.ml @@ -7,7 +7,7 @@ let run () = let open Lwt_result_syntax in - let node_endpoint, base_dir, binaries_directory, baker_args = + let Run_args.{node_endpoint; base_dir; binaries_directory; baker_args} = Run_args.parse_args Sys.argv in let*! () = diff --git a/src/bin_agnostic_baker/run_args.ml b/src/bin_agnostic_baker/run_args.ml index 686254961626..d9d7afcacb0d 100644 --- a/src/bin_agnostic_baker/run_args.ml +++ b/src/bin_agnostic_baker/run_args.ml @@ -73,6 +73,13 @@ let fail_on_empty_baker_args baker_args = let get_base_dir = get_arg_value ~arg:base_dir_arg ~short_arg:base_dir_short_arg +type args = { + node_endpoint : string; + base_dir : string option; + binaries_directory : string option; + baker_args : string list; +} + let parse_args all_args = let all_args = Array.to_list all_args in (* Specific vesrion case *) @@ -83,11 +90,11 @@ let parse_args all_args = let agnostic_baker_args, baker_args = split_args all_args in let () = fail_on_empty_baker_args baker_args in let () = help_cmd agnostic_baker_args in - let endpoint = + let node_endpoint = Option.value ~default:Parameters.default_node_endpoint (get_endpoint baker_args) in let binaries_directory = get_binaries_directory agnostic_baker_args in let base_dir = get_base_dir baker_args in - (endpoint, base_dir, binaries_directory, baker_args) + {node_endpoint; base_dir; binaries_directory; baker_args} diff --git a/src/bin_agnostic_baker/run_args.mli b/src/bin_agnostic_baker/run_args.mli index 124d40f490b5..ff420d04bb7d 100644 --- a/src/bin_agnostic_baker/run_args.mli +++ b/src/bin_agnostic_baker/run_args.mli @@ -5,8 +5,15 @@ (* *) (*****************************************************************************) +(** Simple wrapper to handle the arguments of the agnostic baker. *) +type args = { + node_endpoint : string; + base_dir : string option; + binaries_directory : string option; + baker_args : string list; +} + (** [parse_args args] is a raw utility that aims to parse the give arguments from the command line and to return, respectively, the endpoint, base_dir, binaries_directory and baker_args. *) -val parse_args : - string array -> string * string option * string option * string list +val parse_args : string array -> args -- GitLab From 21b77bce1da071ab686211c9cc5063c5f587f221 Mon Sep 17 00:00:00 2001 From: Victor Allombert Date: Tue, 5 Nov 2024 16:58:05 +0100 Subject: [PATCH 12/12] Agnostic_baker: introduce error module --- .../agnostic_baker_errors.ml | 44 +++++++++++++++++++ src/bin_agnostic_baker/daemon.ml | 12 +---- src/bin_agnostic_baker/rpc_services.ml | 28 +----------- 3 files changed, 46 insertions(+), 38 deletions(-) create mode 100644 src/bin_agnostic_baker/agnostic_baker_errors.ml diff --git a/src/bin_agnostic_baker/agnostic_baker_errors.ml b/src/bin_agnostic_baker/agnostic_baker_errors.ml new file mode 100644 index 000000000000..a4fd7da58ff5 --- /dev/null +++ b/src/bin_agnostic_baker/agnostic_baker_errors.ml @@ -0,0 +1,44 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +type error += + | Lost_node_connection + | Cannot_connect_to_node of string + | Cannot_decode_node_data of string + +let () = + Error_monad.register_error_kind + `Permanent + ~id:"agnostic_baker.lost_node_connection" + ~title:"Lost node connection" + ~description:"Connection with node lost." + ~pp:(fun ppf () -> Format.fprintf ppf "Connection with node was lost") + Data_encoding.(unit) + (function Lost_node_connection -> Some () | _ -> None) + (fun () -> Lost_node_connection) ; + Error_monad.register_error_kind + `Permanent + ~id:"agnostic_baker.cannot_connect_to_node" + ~title:"Cannot connect to node" + ~description:"Cannot connect to node." + ~pp:(fun ppf uri -> + Format.fprintf + ppf + "Cannot connect to node. Connection refused (ECONNREFUSED): %s" + uri) + Data_encoding.(obj1 (req "uri" string)) + (function Cannot_connect_to_node uri -> Some uri | _ -> None) + (fun uri -> Cannot_connect_to_node uri) ; + Error_monad.register_error_kind + `Permanent + ~id:"agnostic_baker.cannot_decode_node_data" + ~title:"Cannot decode node data" + ~description:"Cannot decode node data." + ~pp:(fun ppf err -> Format.fprintf ppf "Cannot decode node data: %s" err) + Data_encoding.(obj1 (req "err" string)) + (function Cannot_decode_node_data err -> Some err | _ -> None) + (fun err -> Cannot_decode_node_data err) diff --git a/src/bin_agnostic_baker/daemon.ml b/src/bin_agnostic_baker/daemon.ml index bb5b2bfb9c03..efdbdd905226 100644 --- a/src/bin_agnostic_baker/daemon.ml +++ b/src/bin_agnostic_baker/daemon.ml @@ -4,18 +4,8 @@ (* Copyright (c) 2024 Nomadic Labs, *) (* *) (*****************************************************************************) -type error += Lost_node_connection -let () = - Error_monad.register_error_kind - `Permanent - ~id:"agnostic_baker.lost_node_connection" - ~title:"Lost node connection" - ~description:"Connection with node lost." - ~pp:(fun ppf () -> Format.fprintf ppf "Connection with node was lost") - Data_encoding.(unit) - (function Lost_node_connection -> Some () | _ -> None) - (fun () -> Lost_node_connection) +open Agnostic_baker_errors module Baker = struct type t = { diff --git a/src/bin_agnostic_baker/rpc_services.ml b/src/bin_agnostic_baker/rpc_services.ml index 7504e01fd7ba..67866da85720 100644 --- a/src/bin_agnostic_baker/rpc_services.ml +++ b/src/bin_agnostic_baker/rpc_services.ml @@ -4,35 +4,9 @@ (* Copyright (c) 2024 Nomadic Labs, *) (* *) (*****************************************************************************) -type error += - | Cannot_connect_to_node of string - | Cannot_decode_node_data of string - -let () = - Error_monad.register_error_kind - `Permanent - ~id:"agnostic_baker.cannot_connect_to_node" - ~title:"Cannot connect to node" - ~description:"Cannot connect to node." - ~pp:(fun ppf uri -> - Format.fprintf - ppf - "Cannot connect to node. Connection refused (ECONNREFUSED): %s" - uri) - Data_encoding.(obj1 (req "uri" string)) - (function Cannot_connect_to_node uri -> Some uri | _ -> None) - (fun uri -> Cannot_connect_to_node uri) ; - Error_monad.register_error_kind - `Permanent - ~id:"agnostic_baker.cannot_decode_node_data" - ~title:"Cannot decode node data" - ~description:"Cannot decode node data." - ~pp:(fun ppf err -> Format.fprintf ppf "Cannot decode node data: %s" err) - Data_encoding.(obj1 (req "err" string)) - (function Cannot_decode_node_data err -> Some err | _ -> None) - (fun err -> Cannot_decode_node_data err) open Cohttp_lwt_unix +open Agnostic_baker_errors let request_uri ~node_addr ~uri = let open Lwt_result_syntax in -- GitLab