2016-09-08 21:13:10 +04:00
|
|
|
|
(**************************************************************************)
|
|
|
|
|
(* *)
|
|
|
|
|
(* Copyright (c) 2014 - 2016. *)
|
|
|
|
|
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
|
|
|
|
(* *)
|
|
|
|
|
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
|
|
|
|
(* *)
|
|
|
|
|
(**************************************************************************)
|
|
|
|
|
|
2017-01-14 16:14:17 +04:00
|
|
|
|
module V6 = Ipaddr.V6
|
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
open Hash
|
2016-09-08 21:13:10 +04:00
|
|
|
|
open Error_monad
|
|
|
|
|
open Logging.Node.Main
|
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let (//) = Filename.concat
|
|
|
|
|
|
|
|
|
|
let home =
|
|
|
|
|
try Sys.getenv "HOME"
|
|
|
|
|
with Not_found -> "/root"
|
|
|
|
|
|
|
|
|
|
let default_base_dir = home // ".tezos-node"
|
|
|
|
|
|
2016-09-08 21:13:10 +04:00
|
|
|
|
let genesis_block =
|
|
|
|
|
Block_hash.of_b48check
|
2016-11-25 22:46:50 +04:00
|
|
|
|
"grHGHkVfgJb5gPaRd5AtQsa65g9GyLcXgQsHbSnQ5SD5DEp2ctqck"
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
|
|
let genesis_protocol =
|
|
|
|
|
Protocol_hash.of_b48check
|
2016-11-25 22:46:50 +04:00
|
|
|
|
"4p64VagsbXchSF88eaPy5XrkqMLEjBCaSnaGv2vQkhv8e37Nnqmrd"
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
|
|
let test_protocol =
|
|
|
|
|
Some (Protocol_hash.of_b48check
|
2016-11-25 22:46:50 +04:00
|
|
|
|
"2gagsSEvTKAHRjxAamgSdBNkv39VtNCqpaDXrrH4K8R4KQAAHrhe3")
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
|
|
let genesis_time =
|
2016-11-25 22:46:50 +04:00
|
|
|
|
Time.of_notation_exn "2016-11-01T00:00:00Z"
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
|
|
let genesis = {
|
|
|
|
|
Store.time = genesis_time ;
|
|
|
|
|
block = genesis_block ;
|
|
|
|
|
protocol = genesis_protocol ;
|
|
|
|
|
}
|
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
module Sockaddr = struct
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
type t = V6.t * int
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let of_string str =
|
|
|
|
|
match String.rindex str ':' with
|
|
|
|
|
| exception Not_found -> `Error "not a sockaddr"
|
|
|
|
|
| pos ->
|
|
|
|
|
let len = String.length str in
|
|
|
|
|
let addr, port =
|
|
|
|
|
String.sub str 0 pos, String.sub str (pos+1) (len - pos - 1) in
|
|
|
|
|
match Ipaddr.of_string_exn addr, int_of_string port with
|
|
|
|
|
| exception Failure _ -> `Error "not a sockaddr"
|
|
|
|
|
| V4 ipv4, port -> `Ok (Ipaddr.v6_of_v4 ipv4, port)
|
|
|
|
|
| V6 ipv6, port -> `Ok (ipv6, port)
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let of_string_exn str =
|
|
|
|
|
match of_string str with
|
|
|
|
|
| `Ok saddr -> saddr
|
|
|
|
|
| `Error msg -> invalid_arg msg
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let pp fmt (ip, port) = Format.fprintf fmt "%a:%d" V6.pp_hum ip port
|
|
|
|
|
let to_string saddr = Format.asprintf "%a" pp saddr
|
|
|
|
|
|
|
|
|
|
let encoding =
|
|
|
|
|
Data_encoding.conv to_string of_string_exn Data_encoding.string
|
|
|
|
|
|
|
|
|
|
let converter : t Cmdliner.Arg.converter = of_string, pp
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module Cfg_file = struct
|
|
|
|
|
|
|
|
|
|
open Data_encoding
|
|
|
|
|
|
|
|
|
|
type t = {
|
|
|
|
|
db : db ;
|
|
|
|
|
net : net ;
|
|
|
|
|
rpc : rpc ;
|
|
|
|
|
log : log ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
and db = {
|
2016-11-30 17:12:42 +04:00
|
|
|
|
store : string ;
|
|
|
|
|
context : string ;
|
|
|
|
|
protocol : string ;
|
2017-01-23 14:10:07 +04:00
|
|
|
|
}
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
and net = {
|
|
|
|
|
identity : string ;
|
|
|
|
|
expected_pow : float ;
|
|
|
|
|
bootstrap_peers : Sockaddr.t list ;
|
|
|
|
|
peers_metadata : string ;
|
|
|
|
|
listen_addr : Sockaddr.t option ;
|
2016-11-30 17:12:42 +04:00
|
|
|
|
closed : bool ;
|
2017-01-23 14:10:07 +04:00
|
|
|
|
limits : P2p.limits ;
|
|
|
|
|
}
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
and rpc = {
|
|
|
|
|
listen_addr : Sockaddr.t option ;
|
2016-12-06 16:58:21 +04:00
|
|
|
|
cors_origins : string list ;
|
|
|
|
|
cors_headers : string list ;
|
2017-01-23 14:10:07 +04:00
|
|
|
|
tls : tls option ;
|
|
|
|
|
}
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
and tls = {
|
|
|
|
|
cert : string ;
|
|
|
|
|
key : string ;
|
2016-11-30 17:12:42 +04:00
|
|
|
|
}
|
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
and log = {
|
|
|
|
|
output : Logging.kind ;
|
|
|
|
|
default_level : Logging.level ;
|
|
|
|
|
rules : string option ;
|
|
|
|
|
template : Logging.template ;
|
|
|
|
|
}
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let default_net_limits : P2p.limits = {
|
|
|
|
|
authentification_timeout = 5. ;
|
|
|
|
|
min_connections = 50 ;
|
|
|
|
|
expected_connections = 100 ;
|
|
|
|
|
max_connections = 200 ;
|
|
|
|
|
backlog = 20 ;
|
|
|
|
|
max_incoming_connections = 20 ;
|
|
|
|
|
max_download_speed = None ;
|
|
|
|
|
max_upload_speed = None ;
|
|
|
|
|
read_buffer_size = 1 lsl 14 ;
|
|
|
|
|
read_queue_size = None ;
|
|
|
|
|
write_queue_size = None ;
|
|
|
|
|
incoming_app_message_queue_size = None ;
|
|
|
|
|
incoming_message_queue_size = None ;
|
|
|
|
|
outgoing_message_queue_size = None ;
|
|
|
|
|
}
|
2017-01-14 16:14:17 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let default_net base_dir = {
|
|
|
|
|
identity = base_dir // "identity.json" ;
|
|
|
|
|
expected_pow = 24. ;
|
|
|
|
|
bootstrap_peers = [] ;
|
|
|
|
|
peers_metadata = base_dir // "peers.json" ;
|
2017-01-24 20:03:24 +04:00
|
|
|
|
listen_addr = Some (V6.unspecified, 9732) ;
|
2017-01-23 14:10:07 +04:00
|
|
|
|
closed = false ;
|
|
|
|
|
limits = default_net_limits ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let default_rpc = {
|
|
|
|
|
listen_addr = None ;
|
|
|
|
|
cors_origins = [] ;
|
|
|
|
|
cors_headers = [] ;
|
|
|
|
|
tls = None ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let default_log = {
|
|
|
|
|
output = Stderr ;
|
|
|
|
|
default_level = Notice ;
|
|
|
|
|
rules = None ;
|
|
|
|
|
template = Logging.default_template ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let default_db base_dir = {
|
|
|
|
|
store = base_dir // "store" ;
|
|
|
|
|
context = base_dir // "context" ;
|
|
|
|
|
protocol = base_dir // "protocol" ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let default_config base_dir = {
|
|
|
|
|
db = default_db base_dir ;
|
|
|
|
|
net = default_net base_dir ;
|
|
|
|
|
rpc = default_rpc ;
|
|
|
|
|
log = default_log ;
|
|
|
|
|
}
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
|
|
|
|
let db =
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let default = default_db default_base_dir in
|
|
|
|
|
conv
|
|
|
|
|
(fun { store ; context ; protocol } ->
|
|
|
|
|
(store, context, protocol))
|
|
|
|
|
(fun (store, context, protocol) ->
|
|
|
|
|
{ store ; context ; protocol })
|
|
|
|
|
(obj3
|
|
|
|
|
(dft "store" string default.store)
|
|
|
|
|
(dft "context" string default.context)
|
|
|
|
|
(dft "protocol" string default.protocol))
|
|
|
|
|
|
|
|
|
|
let limit : P2p.limits Data_encoding.t =
|
|
|
|
|
conv
|
|
|
|
|
(fun { P2p.authentification_timeout ;
|
|
|
|
|
min_connections ; expected_connections ; max_connections ;
|
|
|
|
|
backlog ; max_incoming_connections ;
|
|
|
|
|
max_download_speed ; max_upload_speed ;
|
|
|
|
|
read_buffer_size ; read_queue_size ; write_queue_size ;
|
|
|
|
|
incoming_app_message_queue_size ;
|
|
|
|
|
incoming_message_queue_size ; outgoing_message_queue_size } ->
|
|
|
|
|
( ( authentification_timeout, min_connections, expected_connections,
|
|
|
|
|
max_connections, backlog, max_incoming_connections,
|
|
|
|
|
max_download_speed, max_upload_speed) ,
|
|
|
|
|
( read_buffer_size, read_queue_size, write_queue_size,
|
|
|
|
|
incoming_app_message_queue_size,
|
|
|
|
|
incoming_message_queue_size, outgoing_message_queue_size )))
|
|
|
|
|
(fun ( ( authentification_timeout, min_connections, expected_connections,
|
|
|
|
|
max_connections, backlog, max_incoming_connections,
|
|
|
|
|
max_download_speed, max_upload_speed) ,
|
|
|
|
|
( read_buffer_size, read_queue_size, write_queue_size,
|
|
|
|
|
incoming_app_message_queue_size,
|
|
|
|
|
incoming_message_queue_size, outgoing_message_queue_size ) ) ->
|
|
|
|
|
{ authentification_timeout ; min_connections ; expected_connections ;
|
|
|
|
|
max_connections ; backlog ; max_incoming_connections ;
|
|
|
|
|
max_download_speed ; max_upload_speed ;
|
|
|
|
|
read_buffer_size ; read_queue_size ; write_queue_size ;
|
|
|
|
|
incoming_app_message_queue_size ;
|
|
|
|
|
incoming_message_queue_size ; outgoing_message_queue_size })
|
|
|
|
|
(merge_objs
|
|
|
|
|
(obj8
|
|
|
|
|
(dft "authentification_timeout"
|
|
|
|
|
float default_net_limits.authentification_timeout)
|
|
|
|
|
(dft "min_connections" int31
|
|
|
|
|
default_net_limits.min_connections)
|
|
|
|
|
(dft "expected_connections" int31
|
|
|
|
|
default_net_limits.expected_connections)
|
|
|
|
|
(dft "max_connections" int31
|
|
|
|
|
default_net_limits.max_connections)
|
|
|
|
|
(dft "backlog" int31
|
|
|
|
|
default_net_limits.backlog)
|
|
|
|
|
(dft "max_incoming_connections" int31
|
|
|
|
|
default_net_limits.max_incoming_connections)
|
|
|
|
|
(opt "max_download_speed" int31)
|
|
|
|
|
(opt "max_upload_speed" int31))
|
|
|
|
|
(obj6
|
|
|
|
|
(dft "read_buffer_size" int31
|
|
|
|
|
default_net_limits.read_buffer_size)
|
|
|
|
|
(opt "read_queue_size" int31)
|
|
|
|
|
(opt "write_queue_size" int31)
|
|
|
|
|
(opt "incoming_app_message_queue_size" int31)
|
|
|
|
|
(opt "incoming_message_queue_size" int31)
|
|
|
|
|
(opt "outgoing_message_queue_size" int31)))
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
|
|
|
|
let net =
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let default = default_net default_base_dir in
|
|
|
|
|
conv
|
|
|
|
|
(fun { identity ; expected_pow ; bootstrap_peers ; peers_metadata ;
|
|
|
|
|
listen_addr ; closed ; limits } ->
|
|
|
|
|
( identity, expected_pow, bootstrap_peers, peers_metadata,
|
|
|
|
|
listen_addr, closed, limits ))
|
|
|
|
|
(fun ( identity, expected_pow, bootstrap_peers, peers_metadata,
|
|
|
|
|
listen_addr, closed, limits ) ->
|
|
|
|
|
{ identity ; expected_pow ; bootstrap_peers ; peers_metadata ;
|
|
|
|
|
listen_addr ; closed ; limits })
|
|
|
|
|
(obj7
|
|
|
|
|
(dft "identity" string default.identity)
|
|
|
|
|
(dft "expected-proof-or-work" float default.expected_pow)
|
|
|
|
|
(dft "bootstrap_peers"
|
|
|
|
|
(list Sockaddr.encoding) default.bootstrap_peers)
|
|
|
|
|
(dft "peers-metadata" string default.peers_metadata)
|
|
|
|
|
(opt "listen-addr" Sockaddr.encoding)
|
|
|
|
|
(dft "closed" bool false)
|
|
|
|
|
(dft "limits" limit default_net_limits))
|
|
|
|
|
|
|
|
|
|
let rpc : rpc Data_encoding.t =
|
|
|
|
|
conv
|
|
|
|
|
(fun { cors_origins ; cors_headers ; listen_addr ; tls } ->
|
|
|
|
|
let cert, key =
|
|
|
|
|
match tls with
|
|
|
|
|
| None -> None, None
|
|
|
|
|
| Some { cert ; key } -> Some cert, Some key in
|
|
|
|
|
(listen_addr, cors_origins, cors_headers, cert, key ))
|
|
|
|
|
(fun (listen_addr, cors_origins, cors_headers, cert, key ) ->
|
|
|
|
|
let tls =
|
|
|
|
|
match cert, key with
|
|
|
|
|
| None, _ | _, None -> None
|
|
|
|
|
| Some cert, Some key -> Some { cert ; key } in
|
|
|
|
|
{ listen_addr ; cors_origins ; cors_headers ; tls })
|
|
|
|
|
(obj5
|
|
|
|
|
(opt "listen-addr" Sockaddr.encoding)
|
|
|
|
|
(dft "cors-origin" (list string) default_rpc.cors_origins)
|
|
|
|
|
(dft "cors-headers" (list string) default_rpc.cors_headers)
|
|
|
|
|
(opt "crt" string)
|
|
|
|
|
(opt "key" string))
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
|
|
|
|
let log =
|
2017-01-23 14:10:07 +04:00
|
|
|
|
conv
|
|
|
|
|
(fun {output ; default_level ; rules ; template } ->
|
|
|
|
|
(output, default_level, rules, template))
|
|
|
|
|
(fun (output, default_level, rules, template) ->
|
|
|
|
|
{ output ; default_level ; rules ; template })
|
|
|
|
|
(obj4
|
|
|
|
|
(dft "output" Logging.kind_encoding default_log.output)
|
|
|
|
|
(dft "level" Logging.level_encoding default_log.default_level)
|
|
|
|
|
(opt "rules" string)
|
|
|
|
|
(dft "template" string default_log.template))
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let encoding =
|
2016-11-30 17:12:42 +04:00
|
|
|
|
conv
|
2017-01-23 14:10:07 +04:00
|
|
|
|
(fun { db ; rpc ; net ; log } -> (db, rpc, net, log))
|
|
|
|
|
(fun (db, rpc, net, log) -> { db ; rpc ; net ; log })
|
2016-11-30 17:12:42 +04:00
|
|
|
|
(obj4
|
2017-01-23 14:10:07 +04:00
|
|
|
|
(dft "db" db (default_db default_base_dir))
|
|
|
|
|
(dft "rpc" rpc default_rpc)
|
2016-11-30 17:12:42 +04:00
|
|
|
|
(req "net" net)
|
2017-01-23 14:10:07 +04:00
|
|
|
|
(dft "log" log default_log))
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
|
|
|
|
let read fp =
|
2017-01-23 14:10:07 +04:00
|
|
|
|
Data_encoding_ezjsonm.read_file fp >>=? fun json ->
|
|
|
|
|
try return (Data_encoding.Json.destruct encoding json)
|
|
|
|
|
with exn -> fail (Exn exn)
|
|
|
|
|
|
|
|
|
|
let write fp cfg =
|
|
|
|
|
Data_encoding_ezjsonm.write_file fp
|
|
|
|
|
(Data_encoding.Json.construct encoding cfg)
|
|
|
|
|
|
2016-11-30 17:12:42 +04:00
|
|
|
|
end
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
2016-11-30 17:12:42 +04:00
|
|
|
|
module Cmdline = struct
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
type t = {
|
|
|
|
|
sandbox : string option option ;
|
|
|
|
|
verbosity : Logging.level option ;
|
|
|
|
|
generate_identity : bool ;
|
|
|
|
|
write_cfg : 'a 'b 'c 'd. (string * (string -> 'a, 'b, 'c, 'a) format4) option ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
open Cmdliner
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
2016-11-30 17:12:42 +04:00
|
|
|
|
(* cli args *)
|
|
|
|
|
let misc_sect = "MISC"
|
2017-01-23 14:10:07 +04:00
|
|
|
|
|
2016-09-08 21:13:10 +04:00
|
|
|
|
let base_dir =
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let doc =
|
|
|
|
|
"The directory where the Tezos node will store all its data." in
|
|
|
|
|
Arg.(value & opt (some string) None &
|
|
|
|
|
info ~docs:"CONFIG" ~doc ~docv:"DIR" ["base-dir"])
|
|
|
|
|
|
2016-09-08 21:13:10 +04:00
|
|
|
|
let config_file =
|
2016-11-30 17:12:42 +04:00
|
|
|
|
let doc = "The main configuration file." in
|
2017-01-23 14:10:07 +04:00
|
|
|
|
Arg.(value & opt (some string) None &
|
|
|
|
|
info ~docs:"CONFIG" ~doc ~docv:"FILE" ["config-file"])
|
|
|
|
|
|
2016-09-08 21:13:10 +04:00
|
|
|
|
let sandbox =
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let doc =
|
|
|
|
|
"Run the daemon in a sandbox: P2P is disabled, and constants of \
|
|
|
|
|
the economical protocol might be altered by the optionnal JSON file."
|
|
|
|
|
in
|
|
|
|
|
Arg.(value & opt ~vopt:(Some None) (some (some string)) None &
|
|
|
|
|
info ~docs:"NETWORK" ~doc ~docv:"FILE.json" ["sandbox"])
|
|
|
|
|
|
|
|
|
|
let verbosity =
|
|
|
|
|
let doc =
|
|
|
|
|
"Increase log level. \
|
|
|
|
|
Use several times to increase log level, e.g. `-vv'." in
|
2016-11-30 17:12:42 +04:00
|
|
|
|
Arg.(value & flag_all & info ~docs:misc_sect ~doc ["v"])
|
2017-01-23 14:10:07 +04:00
|
|
|
|
|
2016-11-30 17:12:42 +04:00
|
|
|
|
let reset_config =
|
|
|
|
|
let doc = "Overwrite config file with factory defaults." in
|
|
|
|
|
Arg.(value & flag & info ~docs:"CONFIG" ~doc ["reset-config"])
|
2017-01-23 14:10:07 +04:00
|
|
|
|
|
2016-11-30 17:12:42 +04:00
|
|
|
|
let update_config =
|
|
|
|
|
let doc = "Update config file with values from the command line." in
|
|
|
|
|
Arg.(value & flag & info ~docs:"CONFIG" ~doc ["update-config"])
|
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let generate_identity =
|
|
|
|
|
let doc =
|
|
|
|
|
"Generate a new cryptographic identity for the node. \
|
|
|
|
|
It also generates the associated stamp of proof-of-work. \
|
|
|
|
|
See `--expected-pow` for adjusting the required amount of \
|
|
|
|
|
proof-of-work" in
|
|
|
|
|
Arg.(value & flag & info ~docs:"CONFIG" ~doc ["generate-identity"])
|
|
|
|
|
|
|
|
|
|
(* net args *)
|
|
|
|
|
let expected_connections =
|
|
|
|
|
let doc =
|
|
|
|
|
"The number of running connections that we must try to maintain
|
|
|
|
|
(approximativaly)." in
|
|
|
|
|
Arg.(value & opt (some int) None &
|
|
|
|
|
info ~docs:"NETWORK" ~doc ~docv:"NUM" ["expected-connections"])
|
|
|
|
|
|
|
|
|
|
let max_download_speed =
|
|
|
|
|
let doc =
|
|
|
|
|
"The maximum number of bytes read per second." in
|
|
|
|
|
Arg.(value & opt (some int) None &
|
|
|
|
|
info ~docs:"NETWORK" ~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:"NETWORK" ~doc ~docv:"NUM" ["max-upload-speed"])
|
|
|
|
|
|
|
|
|
|
let listen_addr =
|
|
|
|
|
let doc =
|
|
|
|
|
"The TCP address and port at which this instance can be reached." in
|
|
|
|
|
Arg.(value & opt (some Sockaddr.converter) None &
|
|
|
|
|
info ~docs:"NETWORK" ~doc ~docv:"ADDR:PORT" ["net-addr"])
|
|
|
|
|
|
|
|
|
|
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 Sockaddr.converter [] &
|
|
|
|
|
info ~docs:"NETWORK" ~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:"NETWORK" ~doc ~docv:"FLOAT" ["expected-pow"])
|
|
|
|
|
|
|
|
|
|
let closed =
|
|
|
|
|
let doc =
|
|
|
|
|
"Only accept connections from the configured bootstrap peers." in
|
|
|
|
|
Arg.(value & flag & info ~docs:"NETWORK" ~doc ["closed"])
|
|
|
|
|
|
2016-11-30 17:12:42 +04:00
|
|
|
|
(* rpc args *)
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let rpc_listen_addr =
|
|
|
|
|
let doc =
|
|
|
|
|
"The TCP socket address at which this RPC server \
|
|
|
|
|
instance can be reached." in
|
|
|
|
|
Arg.(value & opt (some Sockaddr.converter) None &
|
|
|
|
|
info ~docs:"RPC" ~doc ~docv:"ADDR:PORT" ["rpc-addr"])
|
|
|
|
|
|
2016-12-01 23:03:39 +04:00
|
|
|
|
let rpc_tls =
|
2017-01-23 14:10:07 +04:00
|
|
|
|
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:"RPC" ~doc ~docv:"crt,key" ["rpc-tls"])
|
|
|
|
|
|
2016-12-06 16:58:21 +04:00
|
|
|
|
let cors_origins =
|
2017-01-23 14:10:07 +04:00
|
|
|
|
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:"RPC" ~doc ~docv:"ORIGIN" ["cors-origin"])
|
|
|
|
|
|
2016-12-06 16:58:21 +04:00
|
|
|
|
let cors_headers =
|
2017-01-23 14:10:07 +04:00
|
|
|
|
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:"RPC" ~doc ~docv:"HEADER" ["cors-header"])
|
|
|
|
|
|
|
|
|
|
exception Fail of string
|
|
|
|
|
let fail fmt =
|
|
|
|
|
Format.kasprintf (fun msg -> Lwt.fail (Fail msg)) fmt
|
|
|
|
|
|
|
|
|
|
let parse
|
|
|
|
|
base_dir config_file
|
|
|
|
|
sandbox verbosity
|
|
|
|
|
expected_connections
|
|
|
|
|
max_download_speed max_upload_speed
|
|
|
|
|
listen_addr bootstrap_peers closed expected_pow
|
|
|
|
|
rpc_listen_addr rpc_tls cors_origins cors_headers
|
|
|
|
|
reset_cfg update_cfg generate_identity =
|
|
|
|
|
|
|
|
|
|
let actual_base_dir =
|
|
|
|
|
match base_dir with
|
|
|
|
|
| None -> default_base_dir
|
|
|
|
|
| Some dir -> dir in
|
|
|
|
|
|
|
|
|
|
let config_file =
|
|
|
|
|
match config_file with
|
|
|
|
|
| None -> actual_base_dir // "config.json"
|
|
|
|
|
| Some file -> file in
|
|
|
|
|
|
|
|
|
|
(* When --base-dir is provided, we ignore the `db`, `net.identity`
|
|
|
|
|
and `net.peers_metadata` of the configuration file. *)
|
|
|
|
|
let db = Utils.map_option Cfg_file.default_db base_dir in
|
|
|
|
|
let identity, peers_metadata =
|
|
|
|
|
let default_net = Utils.map_option Cfg_file.default_net base_dir in
|
|
|
|
|
Utils.map_option
|
|
|
|
|
~f:(fun net -> net.Cfg_file.identity) default_net,
|
|
|
|
|
Utils.map_option
|
|
|
|
|
~f:(fun net -> net.Cfg_file.peers_metadata) default_net in
|
|
|
|
|
|
|
|
|
|
let read () =
|
|
|
|
|
if reset_cfg && update_cfg then
|
|
|
|
|
fail "The options --reset-config and --update-config \
|
|
|
|
|
cannot be used together"
|
|
|
|
|
else if reset_cfg then
|
|
|
|
|
Lwt.return
|
|
|
|
|
(Cfg_file.default_config actual_base_dir, true)
|
|
|
|
|
else if update_cfg && not (Sys.file_exists config_file) then
|
|
|
|
|
fail "Cannot update a non-existant configuration file."
|
|
|
|
|
else if not (Sys.file_exists config_file) then
|
|
|
|
|
Lwt.return
|
|
|
|
|
(Cfg_file.default_config actual_base_dir, true)
|
|
|
|
|
else
|
|
|
|
|
Cfg_file.read config_file >>= function
|
|
|
|
|
| Error err ->
|
|
|
|
|
fail
|
|
|
|
|
"@[Corrupted configuration file, \
|
|
|
|
|
fix it or use --reset-config.@ %a@]"
|
|
|
|
|
pp_print_error err
|
|
|
|
|
| Ok cfg -> Lwt.return (cfg, update_cfg)
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let verbosity =
|
|
|
|
|
match verbosity with
|
|
|
|
|
| [] -> None
|
|
|
|
|
| [_] -> Some Logging.Info
|
|
|
|
|
| _ -> Some Logging.Debug
|
|
|
|
|
in
|
|
|
|
|
|
|
|
|
|
let rpc_tls =
|
|
|
|
|
Utils.map_option
|
|
|
|
|
(fun (cert, key) -> { Cfg_file.cert ; key })
|
|
|
|
|
rpc_tls in
|
|
|
|
|
|
|
|
|
|
let unopt_list ~default = function
|
|
|
|
|
| [] -> default
|
|
|
|
|
| l -> l in
|
|
|
|
|
|
|
|
|
|
(* when `--expected-connections` is used,
|
|
|
|
|
override all the bounds defined in the configuration file. *)
|
|
|
|
|
let min_connections, expected_connections, max_connections =
|
|
|
|
|
match expected_connections with
|
|
|
|
|
| None -> None, None, None
|
|
|
|
|
| Some x -> Some (x/2), Some x, Some (3*x/2) in
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
Lwt_main.run begin
|
|
|
|
|
Lwt_utils.create_dir ~perm:0o700 actual_base_dir >>= fun () ->
|
|
|
|
|
read () >>= fun (cfg, write_cfg) ->
|
|
|
|
|
let db = Utils.unopt ~default:cfg.db db in
|
|
|
|
|
let limits : P2p.limits = {
|
|
|
|
|
cfg.net.limits with
|
|
|
|
|
min_connections =
|
|
|
|
|
Utils.unopt
|
|
|
|
|
~default:cfg.net.limits.min_connections
|
|
|
|
|
min_connections ;
|
|
|
|
|
expected_connections =
|
|
|
|
|
Utils.unopt
|
|
|
|
|
~default:cfg.net.limits.expected_connections
|
|
|
|
|
expected_connections ;
|
|
|
|
|
max_connections =
|
|
|
|
|
Utils.unopt
|
|
|
|
|
~default:cfg.net.limits.max_connections
|
|
|
|
|
max_connections ;
|
|
|
|
|
max_download_speed =
|
|
|
|
|
Utils.first_some
|
|
|
|
|
max_download_speed cfg.net.limits.max_download_speed ;
|
|
|
|
|
max_upload_speed =
|
|
|
|
|
Utils.first_some
|
|
|
|
|
max_upload_speed cfg.net.limits.max_upload_speed ;
|
|
|
|
|
} in
|
|
|
|
|
let net : Cfg_file.net = {
|
|
|
|
|
identity =
|
|
|
|
|
Utils.unopt ~default:cfg.net.identity identity ;
|
|
|
|
|
expected_pow =
|
|
|
|
|
Utils.unopt ~default:cfg.net.expected_pow expected_pow ;
|
|
|
|
|
bootstrap_peers =
|
|
|
|
|
unopt_list ~default:cfg.net.bootstrap_peers bootstrap_peers ;
|
|
|
|
|
peers_metadata =
|
|
|
|
|
Utils.unopt ~default:cfg.net.peers_metadata peers_metadata ;
|
|
|
|
|
listen_addr =
|
|
|
|
|
Utils.first_some listen_addr cfg.net.listen_addr ;
|
|
|
|
|
closed = cfg.net.closed || closed ;
|
|
|
|
|
limits ;
|
|
|
|
|
}
|
|
|
|
|
and rpc : Cfg_file.rpc = {
|
|
|
|
|
listen_addr =
|
|
|
|
|
Utils.first_some rpc_listen_addr cfg.rpc.listen_addr ;
|
|
|
|
|
cors_origins =
|
|
|
|
|
unopt_list ~default:cfg.rpc.cors_origins cors_origins ;
|
|
|
|
|
cors_headers =
|
|
|
|
|
unopt_list ~default:cfg.rpc.cors_headers cors_headers ;
|
|
|
|
|
tls =
|
|
|
|
|
Utils.first_some rpc_tls cfg.rpc.tls ;
|
|
|
|
|
} in
|
|
|
|
|
let cfg_file = { Cfg_file.db ; net ; rpc ; log = cfg.log } in
|
|
|
|
|
let write_cfg : (string * _ format6) option =
|
|
|
|
|
if not write_cfg then None
|
|
|
|
|
else if reset_cfg then
|
|
|
|
|
Some (config_file, "Reseting configuration file '%s'.")
|
|
|
|
|
else if update_cfg then
|
|
|
|
|
Some (config_file, "Updating configuration file '%s'.")
|
|
|
|
|
else
|
|
|
|
|
Some (config_file, "Writing initial configuration file '%s'.")
|
|
|
|
|
in
|
|
|
|
|
let cmdline =
|
|
|
|
|
{ sandbox ; verbosity ; generate_identity ; write_cfg } in
|
|
|
|
|
Lwt.return (`Ok (cfg_file, cmdline))
|
|
|
|
|
end
|
|
|
|
|
with Fail msg -> `Error (false, msg)
|
2016-11-30 17:12:42 +04:00
|
|
|
|
|
|
|
|
|
let cmd =
|
|
|
|
|
let open Term in
|
|
|
|
|
ret (const parse $ base_dir $ config_file
|
2017-01-23 14:10:07 +04:00
|
|
|
|
$ sandbox $ verbosity
|
|
|
|
|
$ expected_connections
|
|
|
|
|
$ max_download_speed $ max_upload_speed
|
|
|
|
|
$ listen_addr $ peers $ closed $ expected_pow
|
|
|
|
|
$ rpc_listen_addr $ rpc_tls $ cors_origins $ cors_headers
|
|
|
|
|
$ reset_config $ update_config $ generate_identity
|
2016-11-30 17:12:42 +04:00
|
|
|
|
),
|
|
|
|
|
let doc = "The Tezos daemon" in
|
|
|
|
|
let man = [
|
|
|
|
|
`S "NETWORK";
|
|
|
|
|
`S "RPC";
|
|
|
|
|
`S "CONFIG";
|
|
|
|
|
`S misc_sect;
|
|
|
|
|
`S "EXAMPLES" ;
|
2017-01-23 14:10:07 +04:00
|
|
|
|
`P "Use `$(mname) --sandbox \
|
|
|
|
|
--base-dir /path/to/a/custom/data/dir \
|
|
|
|
|
--rpc-addr :::8732' \
|
2016-11-30 17:12:42 +04:00
|
|
|
|
to run a single instance in sandbox mode, \
|
|
|
|
|
listening to RPC commands at localhost port 8732.";
|
|
|
|
|
`P "Use `$(mname)' for a node that accepts network connections.";
|
|
|
|
|
`S "BUGS"; `P "Check bug reports at https://github.com/tezos/tezos/issues.";
|
|
|
|
|
]
|
|
|
|
|
in
|
|
|
|
|
info ~sdocs:misc_sect ~man ~doc "tezos-node"
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
2016-11-30 17:12:42 +04:00
|
|
|
|
let parse () = Term.eval cmd
|
2017-01-23 14:10:07 +04:00
|
|
|
|
|
2016-09-08 21:13:10 +04:00
|
|
|
|
end
|
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let init_logger ?verbosity (log_config : Cfg_file.log) =
|
2016-09-08 21:13:10 +04:00
|
|
|
|
let open Logging in
|
2017-01-23 14:10:07 +04:00
|
|
|
|
begin
|
|
|
|
|
match verbosity with
|
|
|
|
|
| Some level ->
|
|
|
|
|
Lwt_log_core.add_rule "*" level
|
|
|
|
|
| None ->
|
|
|
|
|
Lwt_log_core.add_rule "*" log_config.default_level ;
|
|
|
|
|
let rules =
|
|
|
|
|
match Sys.getenv "TEZOS_LOG" with
|
|
|
|
|
| rules -> Some rules
|
|
|
|
|
| exception Not_found ->
|
|
|
|
|
match Sys.getenv "LWT_LOG" with
|
|
|
|
|
| rules -> Some rules
|
|
|
|
|
| exception Not_found -> log_config.rules in
|
|
|
|
|
Utils.iter_option Lwt_log_core.load_rules rules
|
|
|
|
|
end ;
|
|
|
|
|
Logging.init ~template:log_config.template log_config.output
|
|
|
|
|
|
|
|
|
|
type error += No_identity
|
|
|
|
|
type error += Existent_identity_file
|
|
|
|
|
|
|
|
|
|
let read_identity target file =
|
|
|
|
|
Lwt_unix.file_exists file >>= function
|
|
|
|
|
| true ->
|
|
|
|
|
Data_encoding_ezjsonm.read_file file >>=? fun json ->
|
|
|
|
|
let id = Data_encoding.Json.destruct P2p.Identity.encoding json in
|
|
|
|
|
Lwt_utils.unless
|
|
|
|
|
(Crypto_box.check_proof_of_work
|
|
|
|
|
id.public_key id.proof_of_work_stamp target)
|
|
|
|
|
(fun () ->
|
|
|
|
|
lwt_warn "The amount of proof-of-work stamp in the node's identity \
|
|
|
|
|
is below your own expectations.") >>= fun () ->
|
|
|
|
|
return id
|
|
|
|
|
| false ->
|
|
|
|
|
fail No_identity
|
|
|
|
|
|
|
|
|
|
let init_node ?sandbox (config : Cfg_file.t) =
|
2016-09-08 21:13:10 +04:00
|
|
|
|
let patch_context json ctxt =
|
|
|
|
|
let module Proto = (val Updater.get_exn genesis_protocol) in
|
2017-01-23 14:10:07 +04:00
|
|
|
|
Lwt_utils.protect begin fun () ->
|
|
|
|
|
Proto.configure_sandbox ctxt json
|
|
|
|
|
end >|= function
|
|
|
|
|
| Error err ->
|
|
|
|
|
warn
|
|
|
|
|
"@[Error while configuring ecoproto for the sandboxed mode:@ %a@]"
|
|
|
|
|
pp_print_error err ;
|
|
|
|
|
ctxt
|
|
|
|
|
| Ok ctxt -> ctxt in
|
2016-09-08 21:13:10 +04:00
|
|
|
|
begin
|
2016-11-30 17:12:42 +04:00
|
|
|
|
match sandbox with
|
2016-09-08 21:13:10 +04:00
|
|
|
|
| None -> Lwt.return_none
|
2017-01-23 14:10:07 +04:00
|
|
|
|
| Some sandbox_param ->
|
2016-11-30 17:12:42 +04:00
|
|
|
|
match sandbox_param with
|
2016-09-08 21:13:10 +04:00
|
|
|
|
| None -> Lwt.return (Some (patch_context None))
|
|
|
|
|
| Some file ->
|
2016-12-01 21:27:53 +04:00
|
|
|
|
Data_encoding_ezjsonm.read_file file >>= function
|
2017-01-23 14:10:07 +04:00
|
|
|
|
| Error err ->
|
2016-09-08 21:13:10 +04:00
|
|
|
|
lwt_warn
|
2017-01-23 14:10:07 +04:00
|
|
|
|
"Can't parse sandbox parameters: %s" file >>= fun () ->
|
|
|
|
|
lwt_debug "%a" pp_print_error err >>= fun () ->
|
2016-09-08 21:13:10 +04:00
|
|
|
|
Lwt.return (Some (patch_context None))
|
2017-01-23 14:09:45 +04:00
|
|
|
|
| Ok json ->
|
|
|
|
|
Lwt.return (Some (patch_context (Some json)))
|
2016-09-08 21:13:10 +04:00
|
|
|
|
end >>= fun patch_context ->
|
2017-01-23 14:10:07 +04:00
|
|
|
|
begin
|
2016-09-08 21:13:10 +04:00
|
|
|
|
let open P2p in
|
2016-11-30 17:12:42 +04:00
|
|
|
|
match sandbox with
|
2017-01-23 14:10:07 +04:00
|
|
|
|
| Some _ -> return None
|
2016-09-08 21:13:10 +04:00
|
|
|
|
| None ->
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let proof_of_work_target =
|
|
|
|
|
Crypto_box.make_target config.net.expected_pow in
|
|
|
|
|
read_identity
|
|
|
|
|
proof_of_work_target config.net.identity >>=? fun identity ->
|
|
|
|
|
lwt_log_notice "Peers' id: %a" P2p.Gid.pp identity.gid >>= fun () ->
|
|
|
|
|
let p2p_config : P2p.config =
|
|
|
|
|
{ listening_port = Utils.map_option snd config.net.listen_addr ;
|
|
|
|
|
listening_addr = Utils.map_option fst config.net.listen_addr ;
|
|
|
|
|
trusted_points = config.net.bootstrap_peers ;
|
|
|
|
|
peers_file = config.net.peers_metadata ;
|
|
|
|
|
closed_network = config.net.closed ;
|
2017-01-14 16:14:17 +04:00
|
|
|
|
identity ;
|
|
|
|
|
proof_of_work_target ;
|
|
|
|
|
}
|
2016-09-08 21:13:10 +04:00
|
|
|
|
in
|
2017-01-23 14:10:07 +04:00
|
|
|
|
return (Some (p2p_config, config.net.limits))
|
|
|
|
|
end >>=? fun p2p_config ->
|
|
|
|
|
let node_config : Node.config = {
|
|
|
|
|
genesis ;
|
|
|
|
|
test_protocol ;
|
|
|
|
|
patch_context ;
|
|
|
|
|
store_root = config.db.store ;
|
|
|
|
|
context_root = config.db.context ;
|
|
|
|
|
p2p = p2p_config ;
|
|
|
|
|
} in
|
|
|
|
|
Node.create node_config
|
|
|
|
|
|
|
|
|
|
let () =
|
|
|
|
|
let old_hook = !Lwt.async_exception_hook in
|
|
|
|
|
Lwt.async_exception_hook := function
|
|
|
|
|
| Ssl.Read_error _ -> ()
|
|
|
|
|
| exn -> old_hook exn
|
|
|
|
|
|
|
|
|
|
let init_rpc (rpc_config: Cfg_file.rpc) node =
|
|
|
|
|
match rpc_config.listen_addr with
|
|
|
|
|
| None ->
|
|
|
|
|
lwt_log_notice "Not listening to RPC calls." >>= fun () ->
|
|
|
|
|
Lwt.return_none
|
|
|
|
|
| Some (addr, port) ->
|
2017-01-14 16:14:17 +04:00
|
|
|
|
let host = Ipaddr.V6.to_string addr in
|
2016-12-01 23:03:39 +04:00
|
|
|
|
let dir = Node_rpc.build_rpc_directory node in
|
2017-01-23 14:10:07 +04:00
|
|
|
|
let mode =
|
|
|
|
|
match rpc_config.tls with
|
|
|
|
|
| None -> `TCP (`Port port)
|
|
|
|
|
| Some { cert ; key } ->
|
|
|
|
|
`TLS (`Crt_file_path cert, `Key_file_path key,
|
|
|
|
|
`No_password, `Port port) in
|
|
|
|
|
lwt_log_notice
|
|
|
|
|
"Starting the RPC server listening on port %d%s."
|
|
|
|
|
port
|
|
|
|
|
(if rpc_config.tls = None then "" else " (TLS enabled)") >>= fun () ->
|
|
|
|
|
RPC_server.launch ~host mode dir
|
|
|
|
|
rpc_config.cors_origins rpc_config.cors_headers >>= fun server ->
|
2016-12-01 23:03:39 +04:00
|
|
|
|
Lwt.return (Some server)
|
2017-01-23 14:10:07 +04:00
|
|
|
|
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
|
|
let init_signal () =
|
2016-12-01 21:27:53 +04:00
|
|
|
|
let handler id = try Lwt_exit.exit id with _ -> () in
|
2016-10-10 16:23:14 +04:00
|
|
|
|
ignore (Lwt_unix.on_signal Sys.sigint handler : Lwt_unix.signal_handler_id)
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
2017-01-23 14:10:07 +04:00
|
|
|
|
module Identity = struct
|
|
|
|
|
|
|
|
|
|
let generate (command : Cmdline.t) (config : Cfg_file.t) =
|
|
|
|
|
let file = config.net.identity in
|
|
|
|
|
if not command.generate_identity then
|
|
|
|
|
return ()
|
|
|
|
|
else if Sys.file_exists file then
|
|
|
|
|
fail Existent_identity_file
|
|
|
|
|
else
|
|
|
|
|
let target = Crypto_box.make_target config.net.expected_pow in
|
|
|
|
|
Format.eprintf "Generating a new identity... " ;
|
|
|
|
|
let identity =
|
|
|
|
|
P2p.Identity.generate_with_animation Format.err_formatter target in
|
|
|
|
|
Data_encoding_ezjsonm.write_file file
|
|
|
|
|
(Data_encoding.Json.construct P2p.Identity.encoding identity)
|
|
|
|
|
>>=? fun () ->
|
|
|
|
|
Format.eprintf
|
|
|
|
|
"Stored the new identity (%a) into '%s'@."
|
|
|
|
|
P2p.Gid.pp identity.gid file ;
|
|
|
|
|
return ()
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
module Node = struct
|
|
|
|
|
|
|
|
|
|
let may_write_config (command : Cmdline.t) (config : Cfg_file.t) =
|
|
|
|
|
match command.write_cfg with
|
|
|
|
|
| None -> return ()
|
|
|
|
|
| Some (file, fmt) ->
|
|
|
|
|
Format.eprintf "%(%s%)@." fmt file ;
|
|
|
|
|
Cfg_file.write file config
|
|
|
|
|
|
|
|
|
|
let run (command : Cmdline.t) (config : Cfg_file.t) =
|
|
|
|
|
may_write_config command config >>=? fun () ->
|
|
|
|
|
init_signal () ;
|
|
|
|
|
init_logger ?verbosity:command.verbosity config.log >>= fun () ->
|
|
|
|
|
Updater.init config.db.protocol ;
|
|
|
|
|
lwt_log_notice "Starting the Tezos node..." >>= fun () ->
|
|
|
|
|
init_node ?sandbox:command.sandbox config >>=? fun node ->
|
|
|
|
|
init_rpc config.rpc node >>= fun rpc ->
|
|
|
|
|
lwt_log_notice "The Tezos node is now running!" >>= fun () ->
|
|
|
|
|
Lwt_exit.termination_thread >>= fun x ->
|
|
|
|
|
lwt_log_notice "Shutting down the Tezos node..." >>= fun () ->
|
|
|
|
|
Node.shutdown node >>= fun () ->
|
|
|
|
|
lwt_log_notice "Shutting down the RPC server..." >>= fun () ->
|
|
|
|
|
Lwt_utils.may RPC_server.shutdown rpc >>= fun () ->
|
|
|
|
|
lwt_log_notice "BYE (%d)" x >>= fun () ->
|
|
|
|
|
return ()
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
let main (command : Cmdline.t) (config : Cfg_file.t) =
|
2016-09-08 21:13:10 +04:00
|
|
|
|
Random.self_init () ;
|
|
|
|
|
Sodium.Random.stir () ;
|
2017-01-23 14:10:07 +04:00
|
|
|
|
Identity.generate command config >>=? fun () ->
|
|
|
|
|
Node.run command config
|
2016-09-08 21:13:10 +04:00
|
|
|
|
|
|
|
|
|
let () =
|
2016-11-30 17:12:42 +04:00
|
|
|
|
match Cmdline.parse () with
|
|
|
|
|
| `Error _ -> exit 1
|
|
|
|
|
| `Help -> exit 1
|
|
|
|
|
| `Version -> exit 1
|
2017-01-23 14:10:07 +04:00
|
|
|
|
| `Ok (config, command) ->
|
2016-11-30 17:12:42 +04:00
|
|
|
|
Lwt_main.run begin
|
2017-01-23 14:10:07 +04:00
|
|
|
|
main command config >>= function
|
2016-11-30 17:12:42 +04:00
|
|
|
|
| Ok () -> Lwt.return_unit
|
2017-01-23 14:10:07 +04:00
|
|
|
|
| Error [No_identity] ->
|
|
|
|
|
Format.eprintf
|
|
|
|
|
"Cannot find the identity file '%s'!\n%a@."
|
|
|
|
|
config.net.identity
|
|
|
|
|
Utils.display_paragraph
|
|
|
|
|
(Format.sprintf
|
|
|
|
|
"In order to proceed, Tezos needs a cryptographic identity. \
|
|
|
|
|
You may generate a new identity by running:\n\
|
|
|
|
|
\n\
|
|
|
|
|
%s --generate-identity --expected-pow %.1f\n\
|
|
|
|
|
where `%.1f` is the expected level of proof-of-work in \
|
|
|
|
|
the stamp associated to the new identity. \
|
|
|
|
|
For quick testing, you may use '--expected-pow 0'."
|
|
|
|
|
Sys.argv.(0)
|
|
|
|
|
config.net.expected_pow
|
|
|
|
|
config.net.expected_pow) ;
|
|
|
|
|
exit 2
|
|
|
|
|
| Error [Existent_identity_file] ->
|
|
|
|
|
Format.eprintf
|
|
|
|
|
"Error: Cannot implicitely overwrite an existing identity.\n\
|
|
|
|
|
\n\
|
|
|
|
|
\ Please remove the old identity file '%s'.@."
|
|
|
|
|
config.net.identity ;
|
|
|
|
|
exit 2
|
2016-11-30 17:12:42 +04:00
|
|
|
|
| Error err ->
|
2017-01-23 14:10:07 +04:00
|
|
|
|
lwt_log_error
|
|
|
|
|
"@[<v 2>Unexpected error while initializing the node:@ %a@]@."
|
|
|
|
|
pp_print_error err >>= fun () ->
|
|
|
|
|
exit 1
|
2016-11-30 17:12:42 +04:00
|
|
|
|
end
|