diff --git a/src/bin_dal_node/main.ml b/src/bin_dal_node/main.ml index ee8451916b281435df276c3e5ac462a05f0a1b94..711ea3509d7c242f0277e0f8420df17c838486f4 100644 --- a/src/bin_dal_node/main.ml +++ b/src/bin_dal_node/main.ml @@ -34,6 +34,8 @@ let merge listen_addr; public_addr; endpoint; + http_backup_uris; + trust_http_backup_uris; metrics_addr; profile; peers; @@ -57,6 +59,14 @@ let merge ~lower_prio:configuration.profile ~higher_prio:from_cli in + let http_backup_uris, trust_http_backup_uris = + (* backup URIs from the CLI, if any, are favored over the ones in the + config file. *) + if List.is_empty http_backup_uris then + (configuration.http_backup_uris, configuration.trust_http_backup_uris) + else (http_backup_uris, trust_http_backup_uris) + in + { configuration with data_dir = Option.value ~default:configuration.data_dir data_dir; @@ -65,6 +75,8 @@ let merge public_addr = Option.value ~default:configuration.public_addr public_addr; expected_pow = Option.value ~default:configuration.expected_pow expected_pow; endpoint = Option.value ~default:configuration.endpoint endpoint; + http_backup_uris; + trust_http_backup_uris; profile; (* metrics are disabled unless a metrics_addr option is specified *) metrics_addr; diff --git a/src/lib_dal_node/cli.ml b/src/lib_dal_node/cli.ml index d11ee70dc9eac5c996431e869b416ab8871d57ae..78dfa34d8b8dede0b7eecf9f294926bb5730a80f 100644 --- a/src/lib_dal_node/cli.ml +++ b/src/lib_dal_node/cli.ml @@ -120,7 +120,7 @@ module Term = struct & opt (some (p2p_point_arg ~default_port)) None & info ~docs ~doc ~docv:"ADDR[:PORT]" ["public-addr"]) - let endpoint_arg = + let uri_arg = let open Cmdliner in let decoder string = try Uri.of_string string |> Result.ok @@ -137,9 +137,29 @@ module Term = struct in Arg.( value - & opt (some endpoint_arg) None + & opt (some uri_arg) None & info ~docs ~doc ~docv:"URI" ["endpoint"; "E"]) + let http_backup_uris = + let open Cmdliner in + let doc = + "List of HTTP base URIs to fetch missing DAL slots if they are \ + unavailable locally or cannot be reconstructed from shards. This option \ + can be specified multiple times to provide fallback sources." + in + Arg.(value & opt_all uri_arg [] & info ~doc ~docv:"URI" ["http-backup"]) + + let trust_http_backup_uris = + let open Cmdliner in + let doc = + "If set, skip cryptographic verification of slots downloaded from HTTP \ + backup URIs. Default is false. This can speed up slot retrieval when \ + replaying history or for debugging purposes, but should be used with \ + caution for normal operation or in the context of refutation games \ + (unless the HTTP source is fully trusted)." + in + Arg.(value & flag & info ~doc ["trust-http-backup-uris"]) + let ignore_l1_config_peers = let open Cmdliner in let doc = "Ignore the boot(strap) peers provided by L1 config." in @@ -367,10 +387,11 @@ module Term = struct Cmdliner.Term.( ret (const process $ data_dir $ rpc_addr $ expected_pow $ net_addr - $ public_addr $ endpoint $ metrics_addr $ attester_profile - $ operator_profile $ observer_profile $ bootstrap_profile $ peers - $ history_mode $ service_name $ service_namespace $ fetch_trusted_setup - $ verbose $ ignore_l1_config_peers)) + $ public_addr $ endpoint $ http_backup_uris $ trust_http_backup_uris + $ metrics_addr $ attester_profile $ operator_profile $ observer_profile + $ bootstrap_profile $ peers $ history_mode $ service_name + $ service_namespace $ fetch_trusted_setup $ verbose + $ ignore_l1_config_peers)) end type t = Run | Config_init | Config_update | Debug_print_store_schemas @@ -520,6 +541,8 @@ type options = { listen_addr : P2p_point.Id.t option; public_addr : P2p_point.Id.t option; endpoint : Uri.t option; + http_backup_uris : Uri.t list; + trust_http_backup_uris : bool; profile : Profile_manager.unresolved_profile option; metrics_addr : P2p_point.Id.t option; peers : string list; @@ -534,9 +557,9 @@ type options = { let make ~run = let run subcommand data_dir rpc_addr expected_pow listen_addr public_addr - endpoint metrics_addr attesters operators observers bootstrap_flag peers - history_mode service_name service_namespace fetch_trusted_setup verbose - ignore_l1_config_peers = + endpoint http_backup_uris trust_http_backup_uris metrics_addr attesters + operators observers bootstrap_flag peers history_mode service_name + service_namespace fetch_trusted_setup verbose ignore_l1_config_peers = let run profile = run subcommand @@ -547,6 +570,8 @@ let make ~run = listen_addr; public_addr; endpoint; + http_backup_uris; + trust_http_backup_uris; profile; metrics_addr; peers; diff --git a/src/lib_dal_node/cli.mli b/src/lib_dal_node/cli.mli index df0f8cba3b4a2d8cc7a60ac066e49a2618a1768a..2cda1c475864bc972426745af6b0ea79e176846c 100644 --- a/src/lib_dal_node/cli.mli +++ b/src/lib_dal_node/cli.mli @@ -46,6 +46,12 @@ type options = { public_addr : P2p_point.Id.t option; (** The endpoint on which the DAL node can be contacted by other DAL nodes. *) endpoint : Uri.t option; (** The endpoint on which to contact the L1 node. *) + http_backup_uris : Uri.t list; + (** (Optional) URIs to use as HTTP backup sources for slot data retrieval, + in case the slot is missing locally and reconstruction from shards is + not possible. *) + trust_http_backup_uris : bool; + (** Whether to trust the data downlaoded from the provided HTTP backup URIs. *) profile : Profile_manager.unresolved_profile option; (** Profiles of the DAL node used for tracking shards. *) metrics_addr : P2p_point.Id.t option; (** Metrics server endpoint. *) diff --git a/src/lib_dal_node/configuration_file.ml b/src/lib_dal_node/configuration_file.ml index eef10665c57460ba0fedafbf978f8a77061983df..708dcc285ae162d2694c0244ae46555d0a9e51c4 100644 --- a/src/lib_dal_node/configuration_file.ml +++ b/src/lib_dal_node/configuration_file.ml @@ -72,6 +72,8 @@ type t = { peers : string list; expected_pow : float; endpoint : Uri.t; + http_backup_uris : Uri.t list; + trust_http_backup_uris : bool; metrics_addr : P2p_point.Id.t option; profile : Profile_manager.unresolved_profile; history_mode : history_mode; @@ -132,6 +134,8 @@ let default = peers = default_peers; expected_pow = default_expected_pow; endpoint = default_endpoint; + http_backup_uris = []; + trust_http_backup_uris = false; metrics_addr = None; history_mode = default_history_mode; profile = Profile_manager.Empty; @@ -151,7 +155,7 @@ let neighbor_encoding : neighbor Data_encoding.t = (fun (addr, port) -> {addr; port}) (obj2 (req "rpc-addr" string) (req "rpc-port" uint16)) -let endpoint_encoding : Uri.t Data_encoding.t = +let uri_encoding : Uri.t Data_encoding.t = let open Data_encoding in conv_with_guard (fun uri -> Uri.to_string uri) @@ -159,7 +163,7 @@ let endpoint_encoding : Uri.t Data_encoding.t = try Uri.of_string str |> Result.ok with exn -> Format.asprintf - "endpoint decoding failed:@.%a@." + "uri decoding failed:@.%a@." Error_monad.pp_print_trace [Exn exn] |> Result.error) @@ -179,6 +183,8 @@ let encoding : t Data_encoding.t = peers; expected_pow; endpoint; + http_backup_uris; + trust_http_backup_uris; metrics_addr; history_mode; profile; @@ -197,6 +203,8 @@ let encoding : t Data_encoding.t = peers, expected_pow, endpoint, + http_backup_uris, + trust_http_backup_uris, metrics_addr ), ( history_mode, profile, @@ -214,6 +222,8 @@ let encoding : t Data_encoding.t = peers, expected_pow, endpoint, + http_backup_uris, + trust_http_backup_uris, metrics_addr ), ( history_mode, profile, @@ -232,6 +242,8 @@ let encoding : t Data_encoding.t = peers; expected_pow; endpoint; + http_backup_uris; + trust_http_backup_uris; metrics_addr; history_mode; profile; @@ -244,7 +256,7 @@ let encoding : t Data_encoding.t = ignore_l1_config_peers; }) (merge_objs - (obj8 + (obj10 (dft "data-dir" ~description:"Location of the data dir" @@ -278,8 +290,20 @@ let encoding : t Data_encoding.t = (dft "endpoint" ~description:"The Tezos node endpoint" - endpoint_encoding + uri_encoding default_endpoint) + (dft + "http_backup_uris" + ~description:"Optional HTTP endpoints to fetch missing slots from." + (list uri_encoding) + []) + (dft + "trust_http_backup_uris" + ~description: + "Whether to trust the data downlaoded from the provided HTTP \ + backup URIs." + bool + false) (dft "metrics-addr" ~description:"The point for the DAL node metrics server" @@ -412,7 +436,7 @@ module V0 = struct (dft "peers" (list string) default_peers) (dft "expected-pow" float default_expected_pow) (dft "network-name" string legacy_network_name) - (dft "endpoint" endpoint_encoding default_endpoint) + (dft "endpoint" uri_encoding default_endpoint) (dft "metrics-addr" P2p_point.Id.encoding default_metrics_addr)) (obj2 (dft "history_mode" history_mode_encoding default_history_mode) @@ -451,6 +475,8 @@ module V0 = struct fetch_trusted_setup = true; verbose = false; ignore_l1_config_peers = false; + http_backup_uris = []; + trust_http_backup_uris = false; } end @@ -507,7 +533,7 @@ module V1 = struct (dft "peers" (list string) default_peers) (dft "expected-pow" float default_expected_pow) (dft "network-name" string legacy_network_name) - (dft "endpoint" endpoint_encoding default_endpoint) + (dft "endpoint" uri_encoding default_endpoint) (dft "metrics-addr" (Encoding.option P2p_point.Id.encoding) None)) (obj8 (dft "history_mode" history_mode_encoding default_history_mode) @@ -565,6 +591,8 @@ module V1 = struct fetch_trusted_setup; verbose; ignore_l1_config_peers = false; + http_backup_uris = []; + trust_http_backup_uris = false; } end diff --git a/src/lib_dal_node/configuration_file.mli b/src/lib_dal_node/configuration_file.mli index 14dd1330c2549d0d521de125faa3c5b6e841bd03..2e2ea81943652d17bb036e1eca487f8c907269a2 100644 --- a/src/lib_dal_node/configuration_file.mli +++ b/src/lib_dal_node/configuration_file.mli @@ -52,6 +52,10 @@ type t = { expected_pow : float; (** The expected PoW difficulty level for the peers' identity. *) endpoint : Uri.t; (** The endpoint of a Tezos L1 node. *) + http_backup_uris : Uri.t list; + (** Backup URIs to fetch slot data if missing and unrecoverable from shards. *) + trust_http_backup_uris : bool; + (** Whether to trust the data downlaoded from the provided HTTP backup URIs. *) metrics_addr : P2p_point.Id.t option; (** The TCP address of the node's server used to export metrics. *) profile : Profile_manager.unresolved_profile;