diff --git a/CHANGES.rst b/CHANGES.rst index a339cf713314cd04bf29bd9d7f18a440da63dded..2275993d71f84cfb806e030658adfd05096aa76d 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -49,9 +49,16 @@ Client Baker ----- -- **Breaking change** Providing the endpoint of a running DAL node is required - for the baker to be launched, unless opted out with the newly introduced - ``--without-dal`` option. (MR :gl:`!16049`) +- **Breaking change** For ``proto_alpha``, providing the endpoint of a running + DAL node is required for the baker to be launched, unless opted out with the + newly introduced ``--without-dal`` option. (MR :gl:`!16049`) + +- **Deprecation:** For Paris and Quebec protocols, launching a + baker daemon without specifying a DAL node endpoint is deprecated. + To opt out of this requirement, use the newly introduced + ``--without-dal`` option (MR :gl:`!16213`). + The CLI argument ``--dal-node `` or ``--without-dal`` will be mandatory + in the next version of Octez. Accuser ------- diff --git a/src/proto_020_PsParisC/lib_delegate/baking_actions.ml b/src/proto_020_PsParisC/lib_delegate/baking_actions.ml index 88a04f07e34ea6e6b56a0c38e9a93d8efb2f4ade..8ffaeb6252980132be5fb2f66a2c40054ed8dc41 100644 --- a/src/proto_020_PsParisC/lib_delegate/baking_actions.ml +++ b/src/proto_020_PsParisC/lib_delegate/baking_actions.ml @@ -452,7 +452,7 @@ let only_if_dal_feature_enabled = incr no_dal_node_warning_counter ; let* () = if !no_dal_node_warning_counter mod 10 = 1 then - Events.(emit no_dal_node ()) + Events.(emit no_dal_node_running ()) else return_unit in return default_value diff --git a/src/proto_020_PsParisC/lib_delegate/baking_commands.ml b/src/proto_020_PsParisC/lib_delegate/baking_commands.ml index 8b317f2fc77e490f1388372dcb2586f4e17592c0..3c5cb7cd4002024fe5ac1eac2896bb9e891e9ca3 100644 --- a/src/proto_020_PsParisC/lib_delegate/baking_commands.ml +++ b/src/proto_020_PsParisC/lib_delegate/baking_commands.ml @@ -355,6 +355,14 @@ let endpoint_arg = ~doc:"endpoint of the DAL node, e.g. 'http://localhost:8933'" (Tezos_clic.parameter (fun _ s -> return @@ Uri.of_string s)) +let without_dal_arg = + Tezos_clic.switch + ~long:"without-dal" + ~doc: + "If without-dal flag is set, the daemon will not try to connect to a DAL \ + node." + () + let block_count_arg = Tezos_clic.default_arg ~long:"count" @@ -693,10 +701,36 @@ let lookup_default_vote_file_path (cctxt : Protocol_client_context.full) = 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). *) +let check_dal_node without_dal dal_node_rpc_ctxt = + let open Lwt_result_syntax in + let result_emit f x = + let*! () = Events.emit f x in + return_unit + in + match (dal_node_rpc_ctxt, without_dal) with + | None, true -> + (* The user is aware that no DAL node is running, since they explicitly + used the [--without-dal] option. However, we do not want to reduce the + exposition of bakers to warnings about DAL, so we keep it. *) + result_emit Events.no_dal_node_running () + | None, false -> result_emit Events.no_dal_deprecation () + | Some _, true -> tzfail Incompatible_dal_options + | Some ctxt, false -> ( + let*! health = Node_rpc.get_dal_health ctxt in + match health with + | Ok health -> ( + match health.status with + | Tezos_dal_node_services.Types.Health.Up -> return_unit + | _ -> result_emit Events.unhealthy_dal_node (ctxt#base, health)) + | Error _ -> result_emit Events.unreachable_dal_node ctxt#base) + type baking_mode = Local of {local_data_dir_path : string} | Remote let baker_args = - Tezos_clic.args16 + Tezos_clic.args17 pidfile_arg node_version_check_bypass_arg node_version_allowed_arg @@ -710,6 +744,7 @@ let baker_args = per_block_vote_file_arg operations_arg endpoint_arg + without_dal_arg state_recorder_switch_arg pre_emptive_forge_time_arg remote_calls_timeout_arg @@ -728,6 +763,7 @@ let run_baker per_block_vote_file, extra_operations, dal_node_endpoint, + without_dal, state_recorder, pre_emptive_forge_time, remote_calls_timeout ) baking_mode sources cctxt = @@ -752,6 +788,10 @@ let run_baker ~default_adaptive_issuance_vote:adaptive_issuance_vote ~per_block_vote_file in + let dal_node_rpc_ctxt = + Option.map Baking_scheduling.create_dal_node_rpc_ctxt dal_node_endpoint + in + let* () = check_dal_node without_dal dal_node_rpc_ctxt in let* delegates = get_delegates cctxt sources in let context_path = match baking_mode with diff --git a/src/proto_020_PsParisC/lib_delegate/baking_errors.ml b/src/proto_020_PsParisC/lib_delegate/baking_errors.ml index 0d28316b17160cb73e4474b00aee6d3d1534d37e..1ebc51e5a8f6743474c10e105c95bf60c5ffebea 100644 --- a/src/proto_020_PsParisC/lib_delegate/baking_errors.ml +++ b/src/proto_020_PsParisC/lib_delegate/baking_errors.ml @@ -402,3 +402,36 @@ let () = | _ -> None) (fun (chain, block_hash, length) -> Unexpected_empty_block_list {chain; block_hash; length}) + +(* DAL node related errors *) + +type error += No_dal_node_endpoint | Incompatible_dal_options + +let () = + register_error_kind + `Permanent + ~id:"Client_commands.no_dal_node_endpoint" + ~title:"Missing_dal_node_argument" + ~description:"Explicit DAL node configuration is required." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "Please connect a running DAL node using '--dal-node '. If \ + you do not want to run a DAL node, you have to opt-out using \ + '--without-dal'.") + Data_encoding.unit + (function No_dal_node_endpoint -> Some () | _ -> None) + (fun () -> No_dal_node_endpoint) ; + register_error_kind + `Permanent + ~id:"Client_commands.incompatible_dal_options" + ~title:"Incompatible_dal_options" + ~description:"'--dal-node' and '--without-dal' are incompatible." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "'--dal-node ' and '--without-dal' are incompatible. Please \ + do not pass '--without-dal' option.") + Data_encoding.unit + (function Incompatible_dal_options -> Some () | _ -> None) + (fun () -> Incompatible_dal_options) diff --git a/src/proto_020_PsParisC/lib_delegate/baking_events.ml b/src/proto_020_PsParisC/lib_delegate/baking_events.ml index b8b63d256938d76a7d8f347f5f359d46a55beee2..583ba7344a625d1d961c03b59a8039e68e08d4d8 100644 --- a/src/proto_020_PsParisC/lib_delegate/baking_events.ml +++ b/src/proto_020_PsParisC/lib_delegate/baking_events.ml @@ -71,6 +71,55 @@ module Commands = struct ( "baker_commit", Data_encoding.option Tezos_version.Octez_node_version.commit_info_encoding ) + + let no_dal_node_running = + declare_0 + ~section + ~name:"no_dal_node_running" + ~level:Warning + ~msg: + "No DAL node endpoint has been provided.\n\ + It will soon be required to launch a DAL node before running the \ + baker. For instructions on running a DAL node, please visit \ + https://docs.tezos.com/tutorials/join-dal-baker." + () + + let unhealthy_dal_node = + declare_2 + ~section + ~name:"unhealthy_dal_node" + ~level:Error + ~msg: + "The DAL node running on {endpoint} is not healthy. DAL attestations \ + cannot be sent.\n\ + Its health is {health}.\n\ + Please check your DAL node and possibly restart it." + ~pp1:Uri.pp + ("endpoint", Tezos_rpc.Encoding.uri_encoding) + ~pp2:Tezos_dal_node_services.Types.Health.pp + ("health", Tezos_dal_node_services.Types.Health.encoding) + + let unreachable_dal_node = + declare_1 + ~section + ~name:"unreachable_dal_node" + ~level:Error + ~msg: + "The DAL node cannot be reached on endpoint: {endpoint}.\n\ + Please check your DAL node and possibly restart it." + ~pp1:Uri.pp + ("endpoint", Tezos_rpc.Encoding.uri_encoding) + + let no_dal_deprecation = + declare_0 + ~section + ~name:"no_dal_deprecation" + ~level:Warning + ~msg: + "DEPRECATED: Please use a DAL node to launch a baker. If you purposely \ + do not run a DAL node, the option --without-dal will soon be \ + mandatory." + () end module State_transitions = struct @@ -1042,16 +1091,6 @@ module Actions = struct Protocol.Alpha_context.Per_block_votes.adaptive_issuance_vote_encoding ) - let no_dal_node = - declare_0 - ~section - ~name:"no_dal_node" - ~level:Notice - ~msg: - "DAL feature enabled, but no DAL node specified: cannot fetch \ - attestations" - () - let signature_timeout = declare_1 ~section @@ -1081,6 +1120,8 @@ module Actions = struct ("delegates", Data_encoding.list Baking_state.consensus_key_encoding) ~pp2:pp_int32 ("level", Data_encoding.int32) + + let no_dal_node_running = Commands.no_dal_node_running end module VDF = struct diff --git a/src/proto_020_PsParisC/lib_delegate/baking_scheduling.mli b/src/proto_020_PsParisC/lib_delegate/baking_scheduling.mli index 948cc995a19a1fa93ba99267839b736f58256b7d..ba9f10403d66af6f419522786dabb71c18fa4d02 100644 --- a/src/proto_020_PsParisC/lib_delegate/baking_scheduling.mli +++ b/src/proto_020_PsParisC/lib_delegate/baking_scheduling.mli @@ -109,3 +109,6 @@ val run : Baking_configuration.t -> consensus_key list -> unit tzresult Lwt.t + +val create_dal_node_rpc_ctxt : + Uri.t -> Tezos_rpc_http_client_unix.RPC_client_unix.http_ctxt diff --git a/src/proto_020_PsParisC/lib_delegate/node_rpc.ml b/src/proto_020_PsParisC/lib_delegate/node_rpc.ml index a07f5a61d3ce73feafb00368b54fc6fd6bdb9168..aaccad7870ed05ec47ccf33ca522698624809a22 100644 --- a/src/proto_020_PsParisC/lib_delegate/node_rpc.ml +++ b/src/proto_020_PsParisC/lib_delegate/node_rpc.ml @@ -404,3 +404,11 @@ let register_dal_profiles dal_node_rpc_ctxt delegates = () () profiles + +let get_dal_health dal_node_rpc_ctxt = + Tezos_rpc.Context.make_call + Tezos_dal_node_services.Services.health + dal_node_rpc_ctxt + () + () + () diff --git a/src/proto_020_PsParisC/lib_delegate/node_rpc.mli b/src/proto_020_PsParisC/lib_delegate/node_rpc.mli index ec8cb6d32012f4a7f24da42576e15afe7d2fb849..2998ac346c30a4149e0581bd1390fafc45d1e570 100644 --- a/src/proto_020_PsParisC/lib_delegate/node_rpc.mli +++ b/src/proto_020_PsParisC/lib_delegate/node_rpc.mli @@ -103,3 +103,8 @@ val register_dal_profiles : Tezos_rpc.Context.generic -> Baking_state.consensus_key list -> unit tzresult Lwt.t + +(** [get_dal_health ctxt] calls the DAL node RPC 'GET /health' *) +val get_dal_health : + Tezos_rpc.Context.generic -> + Tezos_dal_node_services.Types.Health.t tzresult Lwt.t diff --git a/src/proto_021_PsQuebec/lib_delegate/baking_actions.ml b/src/proto_021_PsQuebec/lib_delegate/baking_actions.ml index f4274807613f59be8ff1b0c1fc8de0fbc27cba74..4211c302bccd8cd73aca88510e16f67b3eab5551 100644 --- a/src/proto_021_PsQuebec/lib_delegate/baking_actions.ml +++ b/src/proto_021_PsQuebec/lib_delegate/baking_actions.ml @@ -454,7 +454,7 @@ let only_if_dal_feature_enabled = incr no_dal_node_warning_counter ; let* () = if !no_dal_node_warning_counter mod 10 = 1 then - Events.(emit no_dal_node ()) + Events.(emit no_dal_node_running ()) else return_unit in return default_value diff --git a/src/proto_021_PsQuebec/lib_delegate/baking_commands.ml b/src/proto_021_PsQuebec/lib_delegate/baking_commands.ml index e822d791d589049e9eadf1ed675dfeb72240889d..e673deadd9e426ae1556d5623b5ab70240f7d559 100644 --- a/src/proto_021_PsQuebec/lib_delegate/baking_commands.ml +++ b/src/proto_021_PsQuebec/lib_delegate/baking_commands.ml @@ -358,6 +358,14 @@ let endpoint_arg = ~doc:"endpoint of the DAL node, e.g. 'http://localhost:8933'" (Tezos_clic.parameter (fun _ s -> return @@ Uri.of_string s)) +let without_dal_arg = + Tezos_clic.switch + ~long:"without-dal" + ~doc: + "If without-dal flag is set, the daemon will not try to connect to a DAL \ + node." + () + let block_count_arg = Tezos_clic.default_arg ~long:"count" @@ -677,10 +685,36 @@ let lookup_default_vote_file_path (cctxt : Protocol_client_context.full) = 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). *) +let check_dal_node without_dal dal_node_rpc_ctxt = + let open Lwt_result_syntax in + let result_emit f x = + let*! () = Events.emit f x in + return_unit + in + match (dal_node_rpc_ctxt, without_dal) with + | None, true -> + (* The user is aware that no DAL node is running, since they explicitly + used the [--without-dal] option. However, we do not want to reduce the + exposition of bakers to warnings about DAL, so we keep it. *) + result_emit Events.no_dal_node_running () + | None, false -> result_emit Events.no_dal_deprecation () + | Some _, true -> tzfail Incompatible_dal_options + | Some ctxt, false -> ( + let*! health = Node_rpc.get_dal_health ctxt in + match health with + | Ok health -> ( + match health.status with + | Tezos_dal_node_services.Types.Health.Up -> return_unit + | _ -> result_emit Events.unhealthy_dal_node (ctxt#base, health)) + | Error _ -> result_emit Events.unreachable_dal_node ctxt#base) + type baking_mode = Local of {local_data_dir_path : string} | Remote let baker_args = - Tezos_clic.args16 + Tezos_clic.args17 pidfile_arg node_version_check_bypass_arg node_version_allowed_arg @@ -694,6 +728,7 @@ let baker_args = per_block_vote_file_arg operations_arg endpoint_arg + without_dal_arg state_recorder_switch_arg pre_emptive_forge_time_arg remote_calls_timeout_arg @@ -712,6 +747,7 @@ let run_baker per_block_vote_file, extra_operations, dal_node_endpoint, + without_dal, state_recorder, pre_emptive_forge_time, remote_calls_timeout ) baking_mode sources cctxt = @@ -736,6 +772,10 @@ let run_baker ~default_adaptive_issuance_vote:adaptive_issuance_vote ~per_block_vote_file in + let dal_node_rpc_ctxt = + Option.map Baking_scheduling.create_dal_node_rpc_ctxt dal_node_endpoint + in + let* () = check_dal_node without_dal dal_node_rpc_ctxt in let* delegates = get_delegates cctxt sources in let context_root_path = match baking_mode with diff --git a/src/proto_021_PsQuebec/lib_delegate/baking_errors.ml b/src/proto_021_PsQuebec/lib_delegate/baking_errors.ml index 0d28316b17160cb73e4474b00aee6d3d1534d37e..1ebc51e5a8f6743474c10e105c95bf60c5ffebea 100644 --- a/src/proto_021_PsQuebec/lib_delegate/baking_errors.ml +++ b/src/proto_021_PsQuebec/lib_delegate/baking_errors.ml @@ -402,3 +402,36 @@ let () = | _ -> None) (fun (chain, block_hash, length) -> Unexpected_empty_block_list {chain; block_hash; length}) + +(* DAL node related errors *) + +type error += No_dal_node_endpoint | Incompatible_dal_options + +let () = + register_error_kind + `Permanent + ~id:"Client_commands.no_dal_node_endpoint" + ~title:"Missing_dal_node_argument" + ~description:"Explicit DAL node configuration is required." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "Please connect a running DAL node using '--dal-node '. If \ + you do not want to run a DAL node, you have to opt-out using \ + '--without-dal'.") + Data_encoding.unit + (function No_dal_node_endpoint -> Some () | _ -> None) + (fun () -> No_dal_node_endpoint) ; + register_error_kind + `Permanent + ~id:"Client_commands.incompatible_dal_options" + ~title:"Incompatible_dal_options" + ~description:"'--dal-node' and '--without-dal' are incompatible." + ~pp:(fun ppf () -> + Format.fprintf + ppf + "'--dal-node ' and '--without-dal' are incompatible. Please \ + do not pass '--without-dal' option.") + Data_encoding.unit + (function Incompatible_dal_options -> Some () | _ -> None) + (fun () -> Incompatible_dal_options) diff --git a/src/proto_021_PsQuebec/lib_delegate/baking_events.ml b/src/proto_021_PsQuebec/lib_delegate/baking_events.ml index 8d418a7522d9aee675574038a7e739171370adb7..3b0dfceb64583e5c936c25763a73b57b8a629c8b 100644 --- a/src/proto_021_PsQuebec/lib_delegate/baking_events.ml +++ b/src/proto_021_PsQuebec/lib_delegate/baking_events.ml @@ -71,6 +71,55 @@ module Commands = struct ( "baker_commit", Data_encoding.option Tezos_version.Octez_node_version.commit_info_encoding ) + + let no_dal_node_running = + declare_0 + ~section + ~name:"no_dal_node_running" + ~level:Warning + ~msg: + "No DAL node endpoint has been provided.\n\ + It will soon be required to launch a DAL node before running the \ + baker. For instructions on running a DAL node, please visit \ + https://docs.tezos.com/tutorials/join-dal-baker." + () + + let unhealthy_dal_node = + declare_2 + ~section + ~name:"unhealthy_dal_node" + ~level:Error + ~msg: + "The DAL node running on {endpoint} is not healthy. DAL attestations \ + cannot be sent.\n\ + Its health is {health}.\n\ + Please check your DAL node and possibly restart it." + ~pp1:Uri.pp + ("endpoint", Tezos_rpc.Encoding.uri_encoding) + ~pp2:Tezos_dal_node_services.Types.Health.pp + ("health", Tezos_dal_node_services.Types.Health.encoding) + + let unreachable_dal_node = + declare_1 + ~section + ~name:"unreachable_dal_node" + ~level:Error + ~msg: + "The DAL node cannot be reached on endpoint: {endpoint}.\n\ + Please check your DAL node and possibly restart it." + ~pp1:Uri.pp + ("endpoint", Tezos_rpc.Encoding.uri_encoding) + + let no_dal_deprecation = + declare_0 + ~section + ~name:"no_dal_deprecation" + ~level:Warning + ~msg: + "DEPRECATED: Please use a DAL node to launch a baker. If you purposely \ + do not run a DAL node, the option --without-dal will soon be \ + mandatory." + () end module State_transitions = struct @@ -1045,16 +1094,6 @@ module Actions = struct Protocol.Alpha_context.Per_block_votes.adaptive_issuance_vote_encoding ) - let no_dal_node = - declare_0 - ~section - ~name:"no_dal_node" - ~level:Notice - ~msg: - "DAL feature enabled, but no DAL node specified: cannot fetch \ - attestations" - () - let signature_timeout = declare_1 ~section @@ -1084,6 +1123,8 @@ module Actions = struct ("delegates", Data_encoding.list Baking_state.consensus_key_encoding) ~pp2:pp_int32 ("level", Data_encoding.int32) + + let no_dal_node_running = Commands.no_dal_node_running end module VDF = struct diff --git a/src/proto_021_PsQuebec/lib_delegate/baking_scheduling.mli b/src/proto_021_PsQuebec/lib_delegate/baking_scheduling.mli index 948cc995a19a1fa93ba99267839b736f58256b7d..ba9f10403d66af6f419522786dabb71c18fa4d02 100644 --- a/src/proto_021_PsQuebec/lib_delegate/baking_scheduling.mli +++ b/src/proto_021_PsQuebec/lib_delegate/baking_scheduling.mli @@ -109,3 +109,6 @@ val run : Baking_configuration.t -> consensus_key list -> unit tzresult Lwt.t + +val create_dal_node_rpc_ctxt : + Uri.t -> Tezos_rpc_http_client_unix.RPC_client_unix.http_ctxt diff --git a/src/proto_021_PsQuebec/lib_delegate/node_rpc.ml b/src/proto_021_PsQuebec/lib_delegate/node_rpc.ml index 99dab7e59774cf881158b1379ac0d3cf046d99f5..9c3204246935bfae2803bdefd9eb12c1bf82691c 100644 --- a/src/proto_021_PsQuebec/lib_delegate/node_rpc.ml +++ b/src/proto_021_PsQuebec/lib_delegate/node_rpc.ml @@ -405,3 +405,11 @@ let register_dal_profiles dal_node_rpc_ctxt delegates = () () profiles + +let get_dal_health dal_node_rpc_ctxt = + Tezos_rpc.Context.make_call + Tezos_dal_node_services.Services.health + dal_node_rpc_ctxt + () + () + () diff --git a/src/proto_021_PsQuebec/lib_delegate/node_rpc.mli b/src/proto_021_PsQuebec/lib_delegate/node_rpc.mli index ec8cb6d32012f4a7f24da42576e15afe7d2fb849..2998ac346c30a4149e0581bd1390fafc45d1e570 100644 --- a/src/proto_021_PsQuebec/lib_delegate/node_rpc.mli +++ b/src/proto_021_PsQuebec/lib_delegate/node_rpc.mli @@ -103,3 +103,8 @@ val register_dal_profiles : Tezos_rpc.Context.generic -> Baking_state.consensus_key list -> unit tzresult Lwt.t + +(** [get_dal_health ctxt] calls the DAL node RPC 'GET /health' *) +val get_dal_health : + Tezos_rpc.Context.generic -> + Tezos_dal_node_services.Types.Health.t tzresult Lwt.t