(**************************************************************************) (* *) (* Copyright (c) 2014 - 2017. *) (* Dynamic Ledger Solutions, Inc. *) (* *) (* All rights reserved. No warranty, explicit or implicit, provided. *) (* *) (**************************************************************************) open Cmdliner open Logging.Node.Main let (//) = Filename.concat type t = { data_dir: string option ; config_file: string ; min_connections: int option ; expected_connections: int option ; max_connections: int option ; max_download_speed: int option ; max_upload_speed: int option ; binary_chunks_size: int option ; peer_table_size: int option ; expected_pow: float option ; peers: string list ; no_bootstrap_peers: bool ; listen_addr: string option ; rpc_listen_addr: string option ; closed: bool ; cors_origins: string list ; cors_headers: string list ; rpc_tls: Node_config_file.tls option ; log_output: Logging.Output.t option ; bootstrap_threshold: int option ; } let wrap data_dir config_file connections max_download_speed max_upload_speed binary_chunks_size peer_table_size listen_addr peers no_bootstrap_peers closed expected_pow rpc_listen_addr rpc_tls cors_origins cors_headers log_output = let actual_data_dir = Option.unopt ~default:Node_config_file.default_data_dir data_dir in let config_file = Option.unopt ~default:(actual_data_dir // "config.json") config_file in let rpc_tls = Option.map ~f:(fun (cert, key) -> { Node_config_file.cert ; key }) rpc_tls in (* when `--expected-connections` is used, override all the bounds defined in the configuration file. *) let bootstrap_threshold, min_connections, expected_connections, max_connections = match connections with | None -> None, None, None, None | Some x -> Some (min (x/4) 2), Some (x/2), Some x, Some (3*x/2) in { data_dir ; config_file ; min_connections ; expected_connections ; max_connections ; max_download_speed ; max_upload_speed ; binary_chunks_size ; expected_pow ; peers ; no_bootstrap_peers ; listen_addr ; rpc_listen_addr ; closed ; cors_origins ; cors_headers ; rpc_tls ; log_output ; peer_table_size ; bootstrap_threshold ; } module Manpage = struct let misc_section = "MISC OPTIONS" let network_section = "NETWORK OPTIONS" let rpc_section = "RPC OPTIONS" let args = [ `S network_section ; `S rpc_section ; `S misc_section ; ] let bugs = [ `S "BUGS"; `P "Check bug reports at https://github.com/tezos/tezos/issues."; ] end module Term = struct let log_output_converter = (fun s -> match Logging.Output.of_string s with | Some res -> `Ok res | None -> `Error s), Logging.Output.pp (* misc args *) let docs = Manpage.misc_section let log_output = let doc = "Log output. Either $(i,stdout), $(i,stderr), \ $(i,syslog:) or a file path." in Arg.(value & opt (some log_output_converter) None & info ~docs ~docv:"OUTPUT" ~doc ["log-output"]) let data_dir = let doc = "The directory where the Tezos node will store all its data." in Arg.(value & opt (some string) None & info ~docs ~doc ~docv:"DIR" ["data-dir"]) let config_file = let doc = "The main configuration file." in Arg.(value & opt (some string) None & info ~docs ~doc ~docv:"FILE" ["config-file"]) (* net args *) let docs = Manpage.network_section let connections = let doc = "The number of running connections that we aim for." in Arg.(value & opt (some int) None & info ~docs ~doc ~docv:"NUM" ["connections"]) let max_download_speed = let doc = "The maximum number of bytes read per second." in Arg.(value & opt (some int) None & info ~docs ~doc ~docv:"NUM" ["max-download-speed"]) let max_upload_speed = let doc = "The maximum number of bytes sent per second." in Arg.(value & opt (some int) None & info ~docs ~doc ~docv:"NUM" ["max-upload-speed"]) let binary_chunks_size = let doc = Format.sprintf "Size limit (in kB) of binary blocks that are sent to other peers." in Arg.(value & opt (some int) None & info ~docs ~doc ~docv:"NUM" ["binary-chunks-size"]) let peer_table_size = let doc = "Maximum size of internal peer tables, \ used to store metadata/logs about a peer or about a \ to-be-authenticated host:port couple." in Arg.(value & opt (some int) None & info ~docs ~doc ~docv:"NUM" ["peer-table-size"]) let listen_addr = let doc = "The TCP address and port at which this instance can be reached." in Arg.(value & opt (some string) None & info ~docs ~doc ~docv:"ADDR:PORT" ["net-addr"]) let no_bootstrap_peers = let doc = "Ignore the peers found in the config file (or the hard-coded \ bootstrap peers in the absence of config file)." in Arg.(value & flag & info ~docs ~doc ["no-bootstrap-peers"]) let peers = let doc = "A peer to bootstrap the network from. \ Can be used several times to add several peers." in Arg.(value & opt_all string [] & info ~docs ~doc ~docv:"ADDR:PORT" ["peer"]) let expected_pow = let doc = "Expected level of proof-of-work for peers identity." in Arg.(value & opt (some float) None & info ~docs ~doc ~docv:"FLOAT" ["expected-pow"]) let closed = let doc = "Only accept connections from the configured bootstrap peers." in Arg.(value & flag & info ~docs ~doc ["closed"]) (* rpc args *) let docs = Manpage.rpc_section let rpc_listen_addr = let doc = "The TCP socket address at which this RPC server \ instance can be reached." in Arg.(value & opt (some string) None & info ~docs ~doc ~docv:"ADDR:PORT" ["rpc-addr"]) let rpc_tls = let doc = "Enable TLS for this RPC server \ with the provided certificate and key." in Arg.(value & opt (some (pair string string)) None & info ~docs ~doc ~docv:"crt,key" ["rpc-tls"]) let cors_origins = let doc = "CORS origin allowed by the RPC server \ via Access-Control-Allow-Origin; may be used multiple times" in Arg.(value & opt_all string [] & info ~docs ~doc ~docv:"ORIGIN" ["cors-origin"]) let cors_headers = let doc = "Header reported by Access-Control-Allow-Headers \ reported during CORS preflighting; may be used multiple times" in Arg.(value & opt_all string [] & info ~docs ~doc ~docv:"HEADER" ["cors-header"]) let args = let open Term in const wrap $ data_dir $ config_file $ connections $ max_download_speed $ max_upload_speed $ binary_chunks_size $ peer_table_size $ listen_addr $ peers $ no_bootstrap_peers $ closed $ expected_pow $ rpc_listen_addr $ rpc_tls $ cors_origins $ cors_headers $ log_output end let read_and_patch_config_file ?(ignore_bootstrap_peers=false) args = begin if Sys.file_exists args.config_file then Node_config_file.read args.config_file else return Node_config_file.default_config end >>=? fun cfg -> let { data_dir ; min_connections ; expected_connections ; max_connections ; max_download_speed ; max_upload_speed ; binary_chunks_size ; peer_table_size ; expected_pow ; peers ; no_bootstrap_peers ; listen_addr ; closed ; rpc_listen_addr ; rpc_tls ; cors_origins ; cors_headers ; log_output ; bootstrap_threshold ; } = args in let bootstrap_peers = if no_bootstrap_peers || ignore_bootstrap_peers then begin log_info "Ignoring bootstrap peers" ; peers end else cfg.net.bootstrap_peers @ peers in Node_config_file.update ?data_dir ?min_connections ?expected_connections ?max_connections ?max_download_speed ?max_upload_speed ?binary_chunks_size ?peer_table_size ?expected_pow ~bootstrap_peers ?listen_addr ?rpc_listen_addr ~closed ~cors_origins ~cors_headers ?rpc_tls ?log_output ?bootstrap_threshold cfg