123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044(*****************************************************************************)(* *)(* Open Source License *)(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)(* Copyright (c) 2019-2021 Nomadic Labs, <contact@nomadic-labs.com> *)(* *)(* 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. *)(* *)(*****************************************************************************)openCmdlineropenFilename.Infixtypenet_config=|BuiltInofConfig_file.blockchain_network|UrlofUri.t|Filenameofstringtypet={disable_config_validation:bool;data_dir:stringoption;config_file:string;network:net_configoption;connections:intoption;max_download_speed:intoption;max_upload_speed:intoption;binary_chunks_size:intoption;peer_table_size:intoption;expected_pow:floatoption;peers:stringlist;no_bootstrap_peers:bool;listen_addr:stringoption;advertised_net_port:intoption;discovery_addr:stringoption;rpc_listen_addrs:stringlist;private_mode:bool;disable_p2p_maintenance:bool;disable_p2p_swap:bool;disable_mempool:bool;enable_testchain:bool;cors_origins:stringlist;cors_headers:stringlist;rpc_tls:Config_file.tlsoption;log_output:Logs_simple_config.Output.toption;log_coloring:booloption;bootstrap_threshold:intoption;history_mode:History_mode.toption;synchronisation_threshold:intoption;latency:intoption;allow_all_rpc:P2p_point.Id.addr_port_idlist;media_type:Media_type.Command_line.t;max_active_rpc_connections:intoption;metrics_addr:stringlist;operation_metadata_size_limit:Shell_limits.operation_metadata_size_limitoption;}typeerror+=|Invalid_network_configofstring*string(* filename, exception raised *)|Network_http_errorof(Cohttp.Code.status_code*string)let()=register_error_kind`Permanent~id:"node.network.invalid_config"~title:"Invalid network config"~description:"The network config provided by --network argument is invalid."~pp:(funppf(path,error)->Format.fprintfppf"The network config at %s is invalid (%s)."patherror)Data_encoding.(obj2(req"path"Data_encoding.string)(req"error"Data_encoding.string))(function|Invalid_network_config(path,exn)->Some(path,exn)|_->None)(fun(path,exn)->Invalid_network_config(path,exn));lethttp_status_enc=letopenData_encodinginletopenCohttp.Codeinconvcode_of_statusstatus_of_codeint31inregister_error_kind`Permanent~id:"node.network.http_error"~title:"HTTP error when downloading network config"~description:"The node encountered an HTTP error when downloading the network config."~pp:(funppf(status,body)->Format.fprintfppf"Downloading network config resulted in: %s (%s)."(Cohttp.Code.string_of_statusstatus)body)Data_encoding.(obj2(req"status"http_status_enc)(req"body"Data_encoding.string))(function|Network_http_error(status,body)->Some(status,body)|_->None)(fun(status,body)->Network_http_error(status,body))moduleEvent=structincludeInternal_event.Simpleletsection=["node";"main"]letdisabled_bootstrap_peers=Internal_event.Simple.declare_0~section~name:"disabled_bootstrap_peers"~msg:"disabled bootstrap peers"()lettestchain_is_deprecated=Internal_event.Simple.declare_0~section~level:Warning~name:"enable_testchain_is_deprecated"~msg:"The command-line option `--enable-testchain` is deprecated."()letoverriding_config_file_arg=declare_1~section~name:"overriding_config_file_arg"~msg:"the data directory from the --config-file argument was overridden by \
the given --data-dir path: {path}"~level:Warning("path",Data_encoding.string)endletdecode_net_configsourcejson=letopenResult_syntaxinmatchData_encoding.Json.destructConfig_file.blockchain_network_encodingjsonwith|net_cfg->returnnet_cfg|exceptionJson_encoding.Cannot_destruct(path,exn)->letpath=Json_query.json_pointer_of_pathpathintzfail(Invalid_network_config(path,Printexc.to_stringexn))|exception((Json_encoding.Unexpected_|Json_encoding.No_case_matched_|Json_encoding.Bad_array_size_|Json_encoding.Missing_field_|Json_encoding.Unexpected_field_|Json_encoding.Bad_schema_)asexn)->tzfail(Invalid_network_config(source,Printexc.to_stringexn))letload_net_config=letopenLwt_result_syntaxinfunction|BuiltInnet->returnnet|Urluri->let*!resp,body=Cohttp_lwt_unix.Client.geturiinlet*!body_str=Cohttp_lwt.Body.to_stringbodyinlet*netconfig=matchresp.statuswith|`OK->(tryreturn(Ezjsonm.from_stringbody_str)withEzjsonm.Parse_error(_,msg)->tzfail(Invalid_network_config(Uri.to_stringuri,msg)))|#Cohttp.Code.status_code->tzfail(Network_http_error(resp.status,body_str))inlet*?net_config=decode_net_config(Uri.to_stringuri)netconfiginreturnnet_config|Filenamefilename->let*netconfig=Lwt_utils_unix.Json.read_filefilenameinlet*?net_config=decode_net_configfilenamenetconfiginreturnnet_configletwrapdata_dirconfig_filenetworkconnectionsmax_download_speedmax_upload_speedbinary_chunks_sizepeer_table_sizelisten_addradvertised_net_portdiscovery_addrpeersno_bootstrap_peersbootstrap_thresholdprivate_modedisable_p2p_maintenancedisable_p2p_swapdisable_mempoolenable_testchainexpected_powrpc_listen_addrsrpc_tlscors_originscors_headerslog_outputlog_coloringhistory_modesynchronisation_thresholdlatencydisable_config_validationallow_all_rpcmedia_typemax_active_rpc_connectionsmetrics_addroperation_metadata_size_limit=letactual_data_dir=Option.value~default:Config_file.default_data_dirdata_dirinletconfig_file=Option.value~default:(actual_data_dir//Data_version.default_config_file_name)config_fileinletrpc_tls=Option.map(fun(cert,key)->{Config_file.cert;key})rpc_tlsin{disable_config_validation;data_dir;config_file;network;connections;max_download_speed;max_upload_speed;binary_chunks_size;expected_pow;peers;no_bootstrap_peers;listen_addr;advertised_net_port;discovery_addr;rpc_listen_addrs;private_mode;disable_p2p_maintenance;disable_p2p_swap;disable_mempool;enable_testchain;cors_origins;cors_headers;rpc_tls;log_output;log_coloring;peer_table_size;bootstrap_threshold;history_mode;synchronisation_threshold;latency;allow_all_rpc;media_type;max_active_rpc_connections;metrics_addr;operation_metadata_size_limit;}letprocess_commandrun=Lwt.Exception_filter.(sethandle_all_except_runtime);matchLwt_main.run@@Lwt_exit.wrap_and_exitrunwith|Ok()->`Ok()|Errorerr->`Error(false,Format.asprintf"%a"pp_print_traceerr)moduleManpage=structletmisc_section="MISC OPTIONS"letp2p_section="P2P OPTIONS"letrpc_section="RPC OPTIONS"letargs=[`Sp2p_section;`Srpc_section;`Smisc_section]letbugs=[`S"BUGS";`P"Check bug reports at https://gitlab.com/tezos/tezos/issues.";]endmoduleTerm=structletlog_output_converter=((funs->matchLogs_simple_config.Output.of_stringswith|Someres->`Okres|None->`Errors),Logs_simple_config.Output.pp)lethistory_mode_converter=letopenHistory_modein(* Parses the history mode given as a string through [arg] from
the command line and returns the corresponding well formed
history mode. The colon punctuation mark (:) is used to delimit
offsets such as: "full:5" -> Full { offset = 5 }. *)letparse_history_modes=letdelim=':'inletargs=String.split_on_chardelimsinmatchargswith|["archive"]|["Archive"]->SomeArchive|["full"]|["Full"]->Somedefault_full|["full";n]|["Full";n]->Option.map(funoffset->Full(Some{offset}))(int_of_string_optn)|["rolling"]|["Rolling"]->Somedefault_rolling|["rolling";n]|["Rolling";n]->Option.map(funoffset->Rolling(Some{offset}))(int_of_string_optn)|["experimental-rolling"]->Somedefault_rolling|_->Nonein((funarg->matchparse_history_modeargwith|Somehm->`Okhm|None->`Errorarg),pp)letnetwork_printerppf=function|BuiltIn({alias;_}:Config_file.blockchain_network)->(* Should not fail by construction of Config_file.block_chain_network *)letalias=WithExceptions.Option.get~loc:__LOC__aliasinFormat.fprintfppf"built-in network: %s"alias|Urlurl->Format.fprintfppf"URL network: %s"(Uri.to_stringurl)|Filenamefile->Format.fprintfppf"local file network: %s"fileletnetwork_parser=letparse_network_names=List.assoc_opt~equal:String.equal(String.lowercase_asciis)Config_file.builtin_blockchain_networks|>Option.map(funnet->Result.ok(BuiltInnet))inletparse_network_urls=leturi=Uri.of_stringsinmatchUri.schemeuriwith|Some"http"|Some"https"->Some(Ok(Urluri))|Some_|None->Noneinletparse_file_configfilename=ifSys.file_existsfilenamethenSome(Result.ok(Filenamefilename))elseNoneinletparse_errors=Error(`Msg(Format.asprintf"invalid value '%s', expected one of '%a', a URL or an existing \
filename"s(Format.pp_print_list~pp_sep:(funppf()->Format.fprintfppf", ")Format.pp_print_string)(List.mapfstConfig_file.builtin_blockchain_networks)))inletparsers=let(<||>)=Option.either_fand(<|!>)optdefault=Option.value_f~defaultoptin(* Select the first parsing result that is not None. *)((parse_network_names<||>fun()->parse_network_urls)<||>fun()->parse_file_configs)<|!>fun()->parse_errorsin((parser:string->(net_config,[`Msgofstring])result),(network_printer:net_configCmdliner.Arg.printer))(* misc args *)letdocs=Manpage.misc_sectionletdisable_config_validation=letdoc="Disable the node configuration validation."inArg.(value&flag&info~docs~doc["disable-config-validation"])lethistory_mode=letdoc=Format.sprintf"Set the mode for the chain's data history storage. Possible values \
are $(i,archive), $(i,full) $(b,(default)), $(i,full:N), \
$(i,rolling), $(i,rolling:N). Archive mode retains all data since the \
genesis block. Full mode only maintains block headers and operations \
allowing replaying the chain since the genesis if wanted. Rolling \
mode retains only the most recent data and deletes the rest. For both \
Full and Rolling modes, it is possible to adjust the number of cycles \
to preserve by using the $(i,:N) annotation. The default number of \
preserved cycles is %d. The value $(i,experimental-rolling) is \
deprecated but is equivalent to $(i,rolling) which should be used \
instead."History_mode.default_additional_cycles.offsetinArg.(value&opt(somehistory_mode_converter)None&info~docs~doc~docv:"<mode>"["history-mode"])letlog_output=letdoc="Log output. Either $(i,stdout), $(i,stderr), $(i,syslog:<facility>) or \
a file path."inArg.(value&opt(somelog_output_converter)None&info~docs~docv:"OUTPUT"~doc["log-output"])letlog_coloring=letdoc="Enable or disable light coloring in default stdout logs. Coloring is \
enabled by default."inArg.(value&opt(somebool)None&info~docs~doc["log-coloring"])letdata_dir=letdoc="The directory where the Tezos node will store all its data. Parent \
directories are created if necessary."inletenv=Cmd.Env.info~docConfig_file.data_dir_env_nameinArg.(value&opt(somestring)None&info~docs~env~doc~docv:"DIR"["data-dir";"d"])letconfig_file=letdoc="The main configuration file."inArg.(value&opt(somestring)None&info~docs~doc~docv:"FILE"["config-file"])letnetwork=letopenCmdlinerinletdoc="Select which network to run. Possible values are: "^String.concat", "(List.mapfstConfig_file.builtin_blockchain_networks)^". Default is mainnet. You can also specify custom networks by passing \
a path to a file containing the custom network configuration, or by \
passing a URL from which such a file can be downloaded. If you have a \
file named after a built-in network, you can prefix its name with \
'./' so that the node treats it as a file. Otherwise it will be \
treated as a proper name of the built-in network. With commands other \
than 'config init', specifying this option causes the node to fail if \
the configuration implies another network."inArg.(value&opt(some(convnetwork_parser))None&info~docs~doc~docv:"NETWORK"["network"])letmetrics_addr=letdoc="Port on which to provide metrics over HTTP."inArg.(value&opt_allstring[]&info~docs~doc~docv:"ADDR:PORT or :PORT (by default ADDR is localhost and PORT is 9932)"["metrics-addr"])letoperation_metadata_size_limit=letconverter=letparses=ifString.(equal(lowercase_asciis)"unlimited")then`OkShell_limits.Unlimitedelsematchint_of_string_optswith|None->`Errors|Somei->`Ok(Limitedi)inletppfmt=function|Shell_limits.Unlimited->Format.fprintffmt"unlimited"|Limitedi->Format.pp_print_intfmtiin((funarg->parsearg),pp)inletdoc=letdefault=matchShell_limits.default_limits.block_validator_limits.operation_metadata_size_limitwith|Shell_limits.Unlimited->"$(i,unlimited)"|Limitedi->Format.sprintf"$(i,%d) bytes"iinFormat.sprintf"Size limit (in bytes) for operation's metadata to be stored on disk. \
Default limit is %s. Use $(i,unlimited) to disregard this limit."defaultinArg.(value&opt(someconverter)None&info~docs~doc~docv:"<limit-in-bytes>"["metadata-size-limit"])(* P2p args *)letdocs=Manpage.p2p_sectionletconnections=letdoc="Sets min_connections, expected_connections, max_connections to NUM / 2, \
NUM, (3 * NUM) / 2, respectively. Sets peer_table_size to 8 * NUM \
unless it is already defined on the command line. Sets \
synchronisation_threshold to max(NUM / 4, 2) unless it is already \
defined on the command line."inArg.(value&opt(someint)None&info~docs~doc~docv:"NUM"["connections"])letmax_download_speed=letdoc="The maximum number of bytes read per second."inArg.(value&opt(someint)None&info~docs~doc~docv:"NUM"["max-download-speed"])letmax_upload_speed=letdoc="The maximum number of bytes sent per second."inArg.(value&opt(someint)None&info~docs~doc~docv:"NUM"["max-upload-speed"])letbinary_chunks_size=letdoc="Size limit (in kB) of binary blocks that are sent to other peers."inArg.(value&opt(someint)None&info~docs~doc~docv:"NUM"["binary-chunks-size"])letpeer_table_size=letdoc="Maximum size of internal peer tables, used to store metadata/logs about \
a peer or about a to-be-authenticated host:port couple."inArg.(value&opt(someint)None&info~docs~doc~docv:"NUM"["peer-table-size"])letlisten_addr=letdoc="The TCP address and port at which this instance can be reached."inArg.(value&opt(somestring)None&info~docs~doc~docv:"ADDR:PORT"["net-addr"])letadvertised_net_port=letdoc="The alternative TCP port at which this instance can be reached. This \
instance does not actually binds to it. The port may be used by a NAT \
server to forward connections to the instance listenning port."inArg.(value&opt(someint)None&info~docs~doc~docv:"PORT"["advertised-net-port"])letdiscovery_addr=letdoc="The UDP address and port used for local peer discovery."inArg.(value&opt(somestring)None&info~docs~doc~docv:"ADDR:PORT"["discovery-addr"])letno_bootstrap_peers=letdoc="Ignore the peers found in the config file (or the hard-coded bootstrap \
peers in the absence of config file)."inArg.(value&flag&info~docs~doc["no-bootstrap-peers"])letbootstrap_threshold=letdoc="[DEPRECATED: use synchronisation-threshold instead] The number of peers \
to synchronize with before declaring the node bootstrapped."inArg.(value&opt(someint)None&info~docs~doc~docv:"NUM"["bootstrap-threshold"])letpeers=letdoc="A peer to bootstrap the network from. Can be used several times to add \
several peers. Optionally, the expected identity of the peer can be \
given using the b58 hash format of its public key."inArg.(value&opt_allstring[]&info~docs~doc~docv:"ADDR:PORT[#ID]"["peer"])letexpected_pow=letdoc="Expected level of proof-of-work for peers identity."inArg.(value&opt(somefloat)None&info~docs~doc~docv:"FLOAT"["expected-pow"])letprivate_mode=letdoc="Only open outgoing/accept incoming connections to/from peers listed in \
'bootstrap-peers' or provided with '--peer' option."inArg.(value&flag&info~docs~doc["private-mode"])letdisable_p2p_maintenance=letdoc="Disable the p2p maintenance. This option should be used for testing \
purposes only. The node will not try to establish or close connections \
by itself. It will accept incoming connections, and outgoing connection \
can be initiated by using the RPC 'POST /network/connections'."inArg.(value&flag&info~docs~doc["disable-p2p-maintenance"])letdisable_p2p_swap=letdoc="Disable p2p connection swaps. This option should be used for testing \
purposes only. The node will neither try to initiate a swap of \
connections with one of its neighbor nor answer to a swap request."inArg.(value&flag&info~docs~doc["disable-p2p-swap"])letdisable_mempool=letdoc="If set to [true], the node will not participate in the propagation of \
pending operations (mempool). Default value is [false]. It can be used \
to decrease the memory and computation footprints of the node."inArg.(value&flag&info~docs~doc["disable-mempool"])letenable_testchain=letdoc="DEPRECATED. If set to [true], the node will spawn a testchain during \
the protocol's testing voting period. Default value is [false]. It will \
increase the node storage usage and computation by additionally \
validating the test network blocks."inArg.(value&flag&info~docs~doc["enable-testchain"])letsynchronisation_threshold=letdoc="Set the number of peers with whom a chain synchronization must be \
completed to bootstrap the node"inArg.(value&opt(someint)None&info~docs~doc~docv:"NUM"["synchronisation-threshold"])letlatency=letdoc="[latency] is the time interval (in seconds) used to determine if a peer \
is synchronized with a chain. For instance, a peer whose known head has \
a timestamp T is considered synchronized if T >= now - max_latency. \
This parameter's default value was set with the chain's current \
protocol's baking rate in mind (and some allowance for network \
latency)."inArg.(value&opt(someint)None&info~docs~doc~docv:"NUM"["sync-latency"])(* rpc args *)letdocs=Manpage.rpc_sectionletrpc_listen_addrs=letdoc="The TCP socket address at which this RPC server instance can be reached."inArg.(value&opt_allstring[]&info~docs~doc~docv:"ADDR:PORT"["rpc-addr"])letrpc_tls=letdoc="Enable TLS for this RPC server with the provided certificate and key."inArg.(value&opt(some(pairfilefile))None&info~docs~doc~docv:"crt,key"["rpc-tls"])letcors_origins=letdoc="CORS origin allowed by the RPC server via Access-Control-Allow-Origin; \
may be used multiple times"inArg.(value&opt_allstring[]&info~docs~doc~docv:"ORIGIN"["cors-origin"])letcors_headers=letdoc="Header reported by Access-Control-Allow-Headers reported during CORS \
preflighting; may be used multiple times"inArg.(value&opt_allstring[]&info~docs~doc~docv:"HEADER"["cors-header"])letallow_all_rpc=letaddr_port_idstr=matchP2p_point.Id.parse_addr_port_idstrwith|Okaddr->`Okaddr|Errore->`Error(P2p_point.Id.string_of_parsing_errore)inletdoc="Apply allow-all policy to a given RPC listening address rather than the \
safe default."inArg.(value&opt_all(addr_port_id,P2p_point.Id.pp_addr_port_id)[]&info~docs~doc~docv:"ADDR:PORT"["allow-all-rpc"])letmedia_type=letmedia_typestr=matchMedia_type.Command_line.parse_cli_parameterstrwith|Somemedia_type->`Okmedia_type|None->`Error"media-type parameter must be `json`, `binary`, or `any`"inletdoc="Set the media-types supported by the server."inArg.(value&opt(media_type,Media_type.Command_line.pp_parameter)Media_type.Command_line.Any&info~docs~doc~docv:"MEDIATYPE"["media-type"])letmax_active_rpc_connections=letdoc="Sets the maximum number of active connections per RPC server."inArg.(value&opt(someint)(SomeConfig_file.default_max_active_rpc_connections)&info~docs~doc~docv:"NUM"["max-active-rpc-connections"])(* Args. *)letargs=letopenTerminconstwrap$data_dir$config_file$network$connections$max_download_speed$max_upload_speed$binary_chunks_size$peer_table_size$listen_addr$advertised_net_port$discovery_addr$peers$no_bootstrap_peers$bootstrap_threshold$private_mode$disable_p2p_maintenance$disable_p2p_swap$disable_mempool$enable_testchain$expected_pow$rpc_listen_addrs$rpc_tls$cors_origins$cors_headers$log_output$log_coloring$history_mode$synchronisation_threshold$latency$disable_config_validation$allow_all_rpc$media_type$max_active_rpc_connections$metrics_addr$operation_metadata_size_limitendletread_config_fileargs=letopenLwt_result_syntaxinifSys.file_existsargs.config_filethenConfig_file.readargs.config_fileelsereturnConfig_file.default_configletresolve_data_dir_and_config_file?data_dir?config_file()=letopenLwt_result_syntaxinletconfig_file_arg=Option.is_someconfig_fileinletactual_data_dir=Option.value~default:Config_file.default_data_dirdata_dirinletconfig_file=Option.value~default:Filename.Infix.(actual_data_dir//Data_version.default_config_file_name)config_fileinlet*node_config=Config_file.readconfig_filein(* Returns true if the given paths are equal, after removing the
potential trailing slash. *)letpaths_equalsp1p2=letfx=List.filter(funs->s<>String.empty)(String.split_on_char'/'x)infp1=fp2inlet*!data_dir=(* The --data-dir argument overrides the potentially given
configuration file. *)matchdata_dirwith|Somedata_dir->let*!()=if(not(paths_equalsdata_dirnode_config.data_dir))&&config_file_argthenEvent.(emitoverriding_config_file_arg)data_direlseLwt.return_unitinLwt.returndata_dir|None->Lwt.returnnode_config.data_dirinreturn(data_dir,node_config)typeerror+=|Network_configuration_mismatchof{configuration_file_chain_name:Distributed_db_version.Name.t;command_line_chain_name:Distributed_db_version.Name.t;}typeerror+=Invalid_command_line_argumentsofstringlet()=register_error_kind`Permanent~id:"node.config.network_configuration_mismatch"~title:"Network configuration mismatch"~description:"You specified a --network argument on the command line, but it does not \
match your current configuration"~pp:(funppf(configuration_file_chain_name,command_line_chain_name)->Format.fprintfppf"@[Specified@ --network@ has@ chain@ name@ %s,@ but@ current@ \
configuration@ implies@ expected@ chain@ name@ %s.@ Use:@ octez-node \
config init --network <NETWORK>@ to@ configure@ your@ node.@]"command_line_chain_nameconfiguration_file_chain_name)Data_encoding.(obj2(req"configuration_file_chain_name"string)(req"command_line_chain_name"string))(function|Network_configuration_mismatch{configuration_file_chain_name;command_line_chain_name}->Some((configuration_file_chain_name:>string),(command_line_chain_name:>string))|_->None)(fun(configuration_file_chain_name,command_line_chain_name)->Network_configuration_mismatch{configuration_file_chain_name=Distributed_db_version.Name.of_stringconfiguration_file_chain_name;command_line_chain_name=Distributed_db_version.Name.of_stringcommand_line_chain_name;});register_error_kind`Permanent~id:"node.config.invalidcommandlinearguments"~title:"Invalid command line arguments"~description:"Given command line arguments are invalid"~pp:(funppfexplanation->Format.fprintfppf"@[Specified command line arguments are invalid: %s@]"explanation)Data_encoding.(obj1(req"explanation"string))(functionInvalid_command_line_argumentsx->Somex|_->None)(funexplanation->Invalid_command_line_argumentsexplanation)letpatch_network?(cfg=Config_file.default_config)blockchain_network=letopenLwt_result_syntaxinreturn{cfgwithblockchain_network}letpatch_config?(may_override_network=false)?(emit=Event.emit)?(ignore_bootstrap_peers=false)?(cfg=Config_file.default_config)args=letopenLwt_result_syntaxinlet{data_dir;disable_config_validation;connections;max_download_speed;max_upload_speed;binary_chunks_size;peer_table_size;expected_pow;peers;no_bootstrap_peers;listen_addr;advertised_net_port;private_mode;discovery_addr;disable_p2p_maintenance;disable_p2p_swap;disable_mempool;enable_testchain;rpc_listen_addrs;rpc_tls;cors_origins;cors_headers;log_output;log_coloring;bootstrap_threshold;history_mode;network=network_arg;config_file=_;synchronisation_threshold;latency;allow_all_rpc;media_type;max_active_rpc_connections;metrics_addr;operation_metadata_size_limit;}=argsinlet*synchronisation_threshold=match(bootstrap_threshold,synchronisation_threshold)with|Some_,Some_->tzfail(Invalid_command_line_arguments"--bootstrap-threshold is deprecated; use \
--synchronisation-threshold instead. Do not use both at the same \
time.")|None,Somethreshold|Somethreshold,None->return_somethreshold|None,None->return_nonein(* Overriding the network with [--network] is a bad idea if the configuration
file already specifies it. Essentially, [--network] tells the node
"if there is no config file, use this network; otherwise, check that the
config file uses the network I expect". This behavior can be overridden
by [may_override_network], which is used when doing [config init]. *)let*cfg=matchnetwork_argwith|None->returncfg|Somenetwork_arg->let*network_arg=load_net_confignetwork_arginifDistributed_db_version.Name.equalcfg.blockchain_network.chain_namenetwork_arg.chain_name||may_override_networkthenpatch_network~cfgnetwork_argelse(* We assume that in the absence of store or context directories,
the data directory was never used to run an node.
Thus, the network configuration can be reset. *)let*!context_dir=Lwt_unix.file_exists@@Data_version.context_dir@@Option.value~default:cfg.data_dirargs.data_dirinlet*!store_dir=Lwt_unix.file_exists@@Data_version.store_dir@@Option.value~default:cfg.data_dirargs.data_dirinifcontext_dir||store_dirthentzfail(Network_configuration_mismatch{configuration_file_chain_name=cfg.blockchain_network.chain_name;command_line_chain_name=network_arg.chain_name;})elsepatch_network~cfgnetwork_argin(* Update bootstrap peers must take into account the updated config file
with the [--network] argument, so we cannot use [Config_file]. *)let*bootstrap_peers=ifno_bootstrap_peers||ignore_bootstrap_peersthenlet*!()=emitEvent.disabled_bootstrap_peers()inreturnpeerselseletcfg_peers=matchcfg.p2p.bootstrap_peerswith|Somepeers->peers|None->cfg.blockchain_network.default_bootstrap_peersinreturn(cfg_peers@peers)inlet*()=Option.iter_es(funconnections->fail_when(connections>100&&disable_config_validation=false)(Invalid_command_line_arguments"The number of expected connections is limited to `100`. This \
maximum cap may be overridden by manually modifying the \
configuration file. However, this should be done carefully. \
Exceeding this number of connections may degrade the performance \
of your node."))connectionsin(* when `--connections` is used,
override all the bounds defined in the configuration file. *)let(synchronisation_threshold,min_connections,expected_connections,max_connections,peer_table_size)=matchconnectionswith|None->(synchronisation_threshold,None,None,None,peer_table_size)|Somex->(letpeer_table_size=matchpeer_table_sizewith|None->Some(8*x)|Some_->peer_table_sizein(* connections sets a new value for the
[synchronisation_threshold] except if a value for it was
specified on the command line. *)matchsynchronisation_thresholdwith|None->(* We want to synchronise with at least 2 peers and to a
number of people proportional to the number of peers we
are connected with. Because a heuristic is used, we only
need to be synchronised with a sufficiently large number
of our peers. To avoid the lack of connections when x is
1, we define the minimum to 1 manually. (x/4) is enough
if the `synchronisation-threshold` is not set. *)(Some(max(x/4)2),Some(ifx=1thenxelsex/2),Somex,Some(3*x/2),peer_table_size)|Somethreshold->(Somethreshold,Some(ifx=1thenxelsex/2),Somex,Some(3*x/2),peer_table_size))inlet*!()=ifenable_testchainthenemitEvent.testchain_is_deprecated()elseLwt.return_unitinConfig_file.update~disable_config_validation?data_dir?min_connections?expected_connections?max_connections?max_download_speed?max_upload_speed?binary_chunks_size?peer_table_size?expected_pow~bootstrap_peers:(Somebootstrap_peers)?listen_addr?advertised_net_port?discovery_addr~rpc_listen_addrs~allow_all_rpc~media_type?max_active_rpc_connections~metrics_addr?operation_metadata_size_limit~private_mode~disable_p2p_maintenance~disable_p2p_swap~disable_mempool~enable_testchain~cors_origins~cors_headers?rpc_tls?log_output?log_coloring?synchronisation_threshold?history_mode?latencycfgletread_and_patch_config_file?may_override_network?emit?ignore_bootstrap_peersargs=letopenLwt_result_syntaxinlet*cfg=read_config_fileargsinpatch_config?may_override_network?emit?ignore_bootstrap_peers~cfgargs