diff --git a/src/bin_dal_node/cli.ml b/src/bin_dal_node/cli.ml index 12b498c3b874000681ef289358d549f063143456..b18beca68a62fd634ba86245e5b66889ef292ab6 100644 --- a/src/bin_dal_node/cli.ml +++ b/src/bin_dal_node/cli.ml @@ -125,11 +125,10 @@ module Term = struct let peers = let open Cmdliner in let default_list = Configuration_file.default.peers in - let default_port = snd Configuration_file.default.listen_addr in let doc = "A list of points at which peers can be reached." in Arg.( value - & opt (list (p2p_point_arg ~default_port)) default_list + & opt (list string) default_list & info ~docs ~doc ~docv:"ADDR:PORT,..." ["peers"]) let term process = @@ -196,7 +195,7 @@ type options = { listen_addr : P2p_point.Id.t option; endpoint : Uri.t option; profile : Services.Types.profile option; - peers : P2p_point.Id.t list; + peers : string list; } type t = Run | Config_init diff --git a/src/bin_dal_node/cli.mli b/src/bin_dal_node/cli.mli index 70bb9ed52fc3abfb0e8c701c8d548da5bc656671..f9526a888cac6735da64f68652eeb70e9a48acdb 100644 --- a/src/bin_dal_node/cli.mli +++ b/src/bin_dal_node/cli.mli @@ -42,7 +42,7 @@ type options = { endpoint : Uri.t option; (** The endpoint on which to contact the L1 node. *) profile : Services.Types.profile option; (** Profile of the DAL node used for tracking shards. *) - peers : P2p_point.Id.t list; (** DAL nodes to connect to. *) + peers : string list; (** DAL nodes to connect to. *) } (** Subcommands that can be used by the DAL node. In the future this type diff --git a/src/bin_dal_node/configuration_file.ml b/src/bin_dal_node/configuration_file.ml index e2b68b63045df40a07f807312d4522f0e2a548b2..24c3d3b63c8d2f0c15e32e60b7c2b2b3dbf8694d 100644 --- a/src/bin_dal_node/configuration_file.ml +++ b/src/bin_dal_node/configuration_file.ml @@ -30,7 +30,7 @@ type t = { rpc_addr : P2p_point.Id.t; neighbors : neighbor list; listen_addr : P2p_point.Id.t; - peers : P2p_point.Id.t list; + peers : string list; expected_pow : float; network_name : string; endpoint : Uri.t; @@ -162,7 +162,7 @@ let encoding : t Data_encoding.t = (dft "peers" ~description:"P2P addresses of remote peers" - (list P2p_point.Id.encoding) + (list string) default_peers) (dft "expected-pow" diff --git a/src/bin_dal_node/configuration_file.mli b/src/bin_dal_node/configuration_file.mli index 15ef1bbc5f5f98a42b798dfd24044ae87e8daae3..9828bf54a32bb4d6a2a3b0ac42ea4db4c0bccc13 100644 --- a/src/bin_dal_node/configuration_file.mli +++ b/src/bin_dal_node/configuration_file.mli @@ -31,8 +31,7 @@ type t = { neighbors : neighbor list; (** List of neighbors to reach within the DAL *) listen_addr : P2p_point.Id.t; (** The TCP address and port at which this instance can be reached. *) - peers : P2p_point.Id.t list; - (** A list of P2P peers to connect to at startup. *) + peers : string list; (** A list of P2P peers to connect to at startup. *) expected_pow : float; (** Expected P2P identity's PoW. *) network_name : string; (** A string that identifies the network's name. E.g. dal-sandbox. *) diff --git a/src/bin_dal_node/daemon.ml b/src/bin_dal_node/daemon.ml index 3f8b16c6ae416edd85a907b65fcb2cae193c8453..be31eaa6252c955fd21836db92e875686fe70783 100644 --- a/src/bin_dal_node/daemon.ml +++ b/src/bin_dal_node/daemon.ml @@ -357,6 +357,13 @@ let connect_gossipsub_with_p2p gs_worker transport_layer node_store = ^ Printexc.to_string exn |> Stdlib.failwith) +let resolve peers = + List.concat_map_es + (Tezos_base_unix.P2p_resolve.resolve_addr + ~default_addr:"::" + ~default_port:(Configuration_file.default.listen_addr |> snd)) + peers + (* FIXME: https://gitlab.com/tezos/tezos/-/issues/3605 Improve general architecture, handle L1 disconnection etc *) @@ -410,9 +417,10 @@ let run ~data_dir configuration_override = let ctxt = Node_context.init config store gs_worker transport_layer cctxt in let* rpc_server = RPC_server.(start config ctxt) in connect_gossipsub_with_p2p gs_worker transport_layer store ; + let* points = resolve peers in (* activate the p2p instance. *) let*! () = - Gossipsub.Transport_layer.activate ~additional_points:peers transport_layer + Gossipsub.Transport_layer.activate ~additional_points:points transport_layer in let _ = RPC_server.install_finalizer rpc_server in diff --git a/src/lib_base/unix/p2p_resolve.ml b/src/lib_base/unix/p2p_resolve.ml new file mode 100644 index 0000000000000000000000000000000000000000..4ad7b94839c26adf56f10bc095253e8fd78a1299 --- /dev/null +++ b/src/lib_base/unix/p2p_resolve.ml @@ -0,0 +1,94 @@ +(*****************************************************************************) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += Failed_to_parse_address of (string * string) + +let () = + (* Parsing of an address failed with an explanation *) + register_error_kind + `Permanent + ~id:"p2p_resolve.parsing_address_failed" + ~title:"Parsing of an address failed" + ~description:"Failed to parse the address given." + ~pp:(fun ppf (addr, explanation) -> + Format.fprintf ppf "Failed to parse address '%s': %s@." addr explanation) + Data_encoding.(obj2 (req "addr" string) (req "explanation" string)) + (function Failed_to_parse_address s -> Some s | _ -> None) + (fun s -> Failed_to_parse_address s) + +let peer_id_unused = + let open Internal_event.Simple in + declare_1 + ~section:["config"] + ~level:Warning + ~name:"config_peer_id_unused" + ~msg:"While parsing {string} a peer id was provided but will not be used." + ("string", Data_encoding.string) + +let no_points_found = + let open Internal_event.Simple in + declare_1 + ~section:["config"] + ~level:Warning + ~name:"config_no_points_found" + ~msg:"The DNS lookup of {string} returns 0 point." + ("string", Data_encoding.string) + +let resolve_addr_with_peer_id ~default_addr ~default_port ?(passive = false) + peer : (P2p_point.Id.t * P2p_peer.Id.t option) list tzresult Lwt.t = + let open Lwt_result_syntax in + match P2p_point.Id.parse_addr_port_id peer with + | Error err -> + tzfail + (Failed_to_parse_address (peer, P2p_point.Id.string_of_parsing_error err)) + | Ok {addr; port; peer_id} -> + let service_port = + match (port, default_port) with + | Some port, _ -> port + | None, default_port -> default_port + in + let service = string_of_int service_port in + let node = if addr = "" || addr = "_" then default_addr else addr in + let*! l = Lwt_utils_unix.getaddrinfo ~passive ~node ~service in + let*! () = + if List.is_empty l then + Internal_event.Simple.(emit no_points_found peer) + else Lwt.return_unit + in + return (List.map (fun point -> (point, peer_id)) l) + +let resolve_addr ~default_addr ~default_port ?passive peer : + P2p_point.Id.t list tzresult Lwt.t = + let open Lwt_result_syntax in + let* l = + resolve_addr_with_peer_id ~default_addr ~default_port ?passive peer + in + let points = List.map fst l in + let*! () = + if List.exists (function _, Some _ -> true | _ -> false) l then + Internal_event.Simple.(emit peer_id_unused) peer + else Lwt.return_unit + in + return points diff --git a/src/lib_base/unix/p2p_resolve.mli b/src/lib_base/unix/p2p_resolve.mli new file mode 100644 index 0000000000000000000000000000000000000000..5118729c67964b2854a0bb4b738bc7c3bef6a53d --- /dev/null +++ b/src/lib_base/unix/p2p_resolve.mli @@ -0,0 +1,58 @@ +(*****************************************************************************) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +type error += Failed_to_parse_address of (string * string) + +(** [resolve_addr_with_peer_id ~default_addr ~default_port ?passive + addr] parses [addr] to return the corresponding points. + + The format of [addr] can be either an IP address (v4 or v6) or a + domain name. If a domain name is provided, a DNS lookup is made + (see {!val:Unix.getaddrinfo}). + + Moreover, a peer id can be provided by postfixing the addr with + [#]. The peer id should be provided using the b58 format. + + An event is emitted if the DNS lookup returned 0 points. + + The error [Failed_to_parse_address] is returned if the parsing failed. *) +val resolve_addr_with_peer_id : + default_addr:string -> + default_port:int -> + ?passive:bool -> + string -> + (P2p_point.Id.t * P2p_peer.Id.t option) list tzresult Lwt.t + +(** [resolve_addr] is the same as [resolve_addr_with_peer_id] but no + peer id is expected. + + A warning event is emitted if a peer_id was provided. +*) +val resolve_addr : + default_addr:string -> + default_port:int -> + ?passive:bool -> + string -> + P2p_point.Id.t list tzresult Lwt.t diff --git a/src/lib_node_config/config_file.ml b/src/lib_node_config/config_file.ml index 04160b0db59eea667cafe9c809d8ba9426496162..ec1353298557c4f0a1cb95553f4920cedab6ad67 100644 --- a/src/lib_node_config/config_file.ml +++ b/src/lib_node_config/config_file.ml @@ -983,21 +983,6 @@ let update ?(disable_config_validation = false) ?data_dir ?min_connections metrics_addr; } -type Error_monad.error += Failed_to_parse_address of (string * string) - -let () = - (* Parsing of an address failed with an explanation *) - Error_monad.register_error_kind - `Permanent - ~id:"config_file.parsing_address_failed" - ~title:"Parsing of an address failed" - ~description:"Parsing an address failed with an explanation." - ~pp:(fun ppf (addr, explanation) -> - Format.fprintf ppf "Failed to parse address '%s': %s@." addr explanation) - Data_encoding.(obj2 (req "addr" string) (req "explanation" string)) - (function Failed_to_parse_address s -> Some s | _ -> None) - (fun s -> Failed_to_parse_address s) - let to_ipv4 ipv6_l = let open Lwt_syntax in let convert_or_warn (ipv6, port) = @@ -1012,99 +997,45 @@ let to_ipv4 ipv6_l = in List.filter_map_s convert_or_warn ipv6_l -(* Parse an address. - - - [peer] is a string representing the peer. - - - if [no_peer_id_expected] is true, then parsing a representation - containing a peer id will result in an error. - - - [default_addr] is the used if no hostname or IP is given or if - the hostname "_" is used. - - - [default_port] is the used if port is given. *) -let resolve_addr ~default_addr ?(no_peer_id_expected = true) ?default_port - ?(passive = false) peer : - (P2p_point.Id.t * P2p_peer.Id.t option) list tzresult Lwt.t = - let open Lwt_result_syntax in - match P2p_point.Id.parse_addr_port_id peer with - | (Error (P2p_point.Id.Bad_id_format _) | Ok {peer_id = Some _; _}) - when no_peer_id_expected -> - tzfail - (Failed_to_parse_address - (peer, "no peer identity should be specified here")) - | Error err -> - tzfail - (Failed_to_parse_address (peer, P2p_point.Id.string_of_parsing_error err)) - | Ok {addr; port; peer_id} -> - let service_port = - match (port, default_port) with - | Some port, _ -> port - | None, Some default_port -> default_port - | None, None -> default_p2p_port - in - let service = string_of_int service_port in - let node = if addr = "" || addr = "_" then default_addr else addr in - let*! l = Lwt_utils_unix.getaddrinfo ~passive ~node ~service in - return (List.map (fun point -> (point, peer_id)) l) - -let resolve_addrs ?default_port ?passive ?no_peer_id_expected ~default_addr - addrs = - List.concat_map_es - (resolve_addr ~default_addr ?default_port ?passive ?no_peer_id_expected) - addrs - let resolve_discovery_addrs discovery_addr = let open Lwt_result_syntax in - let* addrs = - resolve_addr + let* points = + P2p_resolve.resolve_addr ~default_addr:Ipaddr.V4.(to_string broadcast) ~default_port:default_discovery_port ~passive:true discovery_addr in - let*! addrs = to_ipv4 (List.map fst addrs) in - return addrs + let*! points = to_ipv4 points in + return points let resolve_listening_addrs listen_addr = - let open Lwt_result_syntax in - let+ addrs = - resolve_addr - ~default_addr:"::" - ~default_port:default_p2p_port - ~passive:true - listen_addr - in - List.map fst addrs + P2p_resolve.resolve_addr + ~default_addr:"::" + ~default_port:default_p2p_port + ~passive:true + listen_addr let resolve_rpc_listening_addrs listen_addr = - let open Lwt_result_syntax in - let+ addrs = - resolve_addr - ~default_addr:"localhost" - ~default_port:default_rpc_port - ~passive:true - listen_addr - in - List.map fst addrs + P2p_resolve.resolve_addr + ~default_addr:"localhost" + ~default_port:default_rpc_port + ~passive:true + listen_addr let resolve_metrics_addrs ?(default_metrics_port = default_metrics_port) metrics_addr = - let open Lwt_result_syntax in - let+ addrs = - resolve_addr - ~default_addr:"localhost" - ~default_port:default_metrics_port - ~passive:true - metrics_addr - in - List.map fst addrs + P2p_resolve.resolve_addr + ~default_addr:"localhost" + ~default_port:default_metrics_port + ~passive:true + metrics_addr let resolve_bootstrap_addrs peers = - resolve_addrs - ~no_peer_id_expected:false - ~default_addr:"::" - ~default_port:default_p2p_port + List.concat_map_es + (P2p_resolve.resolve_addr_with_peer_id + ~default_addr:"::" + ~default_port:default_p2p_port) peers let bootstrap_peers config = diff --git a/src/lib_node_config/config_file.mli b/src/lib_node_config/config_file.mli index 861b3b1f078b86b09475b25ad7d664cc469ca976..5fa1107e2fdc2360c916dc827e1305d407aed34d 100644 --- a/src/lib_node_config/config_file.mli +++ b/src/lib_node_config/config_file.mli @@ -147,8 +147,6 @@ val read : string -> t tzresult Lwt.t is a data directory. *) val write : string -> t -> unit tzresult Lwt.t -type error += Failed_to_parse_address of (string * string) - (** [resolve_listening_addrs listening_addr] parses [listening_addr] and returns a list of [points]. The default port is [default_p2p_port]. Fails if the address could not be parsed. *) diff --git a/src/lib_node_config/config_validation.ml b/src/lib_node_config/config_validation.ml index e1bc21e537806290f90c21e0019c34e95b2956de..412cfe2a8a02400db9b0fc0b6cac68b01e04480e 100644 --- a/src/lib_node_config/config_validation.ml +++ b/src/lib_node_config/config_validation.ml @@ -263,7 +263,7 @@ let validate_addr ?e_resolve ?e_parse ~field ~addr resolver = let open Lwt_result_syntax in let*! r = resolver addr in match r with - | Error [Config_file.Failed_to_parse_address (addr, why)] -> + | Error [P2p_resolve.Failed_to_parse_address (addr, why)] -> return_some (mk_alert ~event:(Option.value e_parse ~default:cannot_parse_addr)