main_tx_rollup_node_alpha.ml
(*****************************************************************************)
(* *)
(* Open Source License *)
(* Copyright (c) 2022 Nomadic Labs, <contact@nomadic-labs.com> *)
(* Copyright (c) 2022 Marigold, <contact@marigold.dev> *)
(* Copyright (c) 2022 Oxhead Alpha <info@oxhead-alpha.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. *)
(* *)
(*****************************************************************************)
let force_switch =
Tezos_clic.switch
~long:"force"
~doc:"Overwrites the configuration file when it exists."
()
let data_dir_doc =
Format.sprintf "The directory path to the transaction rollup node data."
let rpc_addr_doc =
Format.asprintf
"The address and port where the node listens to RPCs. The default is %s"
let reconnection_delay_doc =
Format.asprintf
"The reconnection delay when the connection is lost. The default delay is \
%f"
let data_dir_arg =
let doc = data_dir_doc in
Tezos_clic.arg
~long:"data-dir"
~placeholder:"data_dir"
~doc
Client_proto_args.string_parameter
let operator_arg =
Client_keys.Public_key_hash.source_arg
~long:"operator"
~placeholder:"operator"
~doc:"The operator of the rollup"
()
let batch_signer_arg =
Client_keys.Public_key_hash.source_arg
~long:"batch-signer"
~placeholder:"batch-signer"
~doc:"The signer for submission of batches"
()
let finalize_commitment_signer_arg =
Client_keys.Public_key_hash.source_arg
~long:"finalize-commitment-signer"
~placeholder:"finalize-commitment-signer"
~doc:"The signer for finalization of commitments"
()
let remove_commitment_signer_arg =
Client_keys.Public_key_hash.source_arg
~long:"remove-commitment-signer"
~placeholder:"remove-commitment-signer"
~doc:"The signer for removals of commitments"
()
let rejection_signer_arg =
Client_keys.Public_key_hash.source_arg
~long:"rejection-signer"
~placeholder:"rejection-signer"
~doc:"The signer for rejections"
()
let dispatch_withdrawals_signer_arg =
Client_keys.Public_key_hash.source_arg
~long:"dispatch-withdrawals-signer"
~placeholder:"dispatch-withdrawals-signer"
~doc:"The signer for dispatch withdrawals"
()
let rollup_id_param =
let open Client_proto_rollups in
Tezos_clic.parameter ~autocomplete:TxRollupAlias.autocomplete (fun cctxt s ->
let from_alias s = TxRollupAlias.find cctxt s in
let from_key s = TxRollupAlias.of_source s in
Client_aliases.parse_alternatives
[("alias", from_alias); ("key", from_key)]
s)
let origination_level_arg =
Tezos_clic.arg
~long:"origination-level"
~placeholder:"origination_level"
~doc:"The level of the block where the rollup was originated"
(Tezos_clic.parameter (fun _ str ->
match Int32.of_string_opt str with
| None -> failwith "Invalid origination level"
| Some l -> return l))
let rpc_addr_arg =
let default = P2p_point.Id.to_string Node_config.default_rpc_addr in
let doc = rpc_addr_doc default in
Tezos_clic.arg
~long:"rpc-addr"
~placeholder:"address:port"
~doc
(Tezos_clic.parameter (fun _ s ->
P2p_point.Id.of_string s
|> Result.map_error (fun e -> [Exn (Failure e)])
|> Lwt.return))
let rpc_addr_opt_arg =
let default = P2p_point.Id.to_string Node_config.default_rpc_addr in
let doc = rpc_addr_doc default in
Tezos_clic.arg
~long:"rpc-addr"
~placeholder:"address:port"
~doc
(Tezos_clic.parameter (fun _ s ->
P2p_point.Id.of_string s
|> Result.map_error (fun e -> [Exn (Failure e)])
|> Lwt.return))
let cors_origins_arg =
Tezos_clic.arg
~doc:
"CORS origins allowed by the RPC server via Access-Control-Allow-Origin"
~placeholder:"c1, c2, ..."
~long:"cors-origins"
@@ Tezos_clic.parameter (fun _ctxt s ->
String.split_no_empty ',' s |> List.map String.trim |> return)
let cors_headers_arg =
Tezos_clic.arg
~doc:
"Header reported by Access-Control-Allow-Headers reported during CORS \
preflighting"
~placeholder:"h1, h2, ..."
~long:"cors-headers"
@@ Tezos_clic.parameter (fun _ctxt s ->
String.split_no_empty ',' s |> List.map String.trim |> return)
let reconnection_delay_arg =
let default = Node_config.default_reconnection_delay in
let doc = reconnection_delay_doc default in
Tezos_clic.arg
~long:"reconnection-delay"
~placeholder:"delay"
~doc
(Tezos_clic.parameter (fun _ p ->
try return (float_of_string p) with _ -> failwith "Cannot read float"))
let possible_modes = List.map Node_config.string_of_mode Node_config.modes
let mode_parameter =
Tezos_clic.parameter
~autocomplete:(fun _ -> return possible_modes)
(fun _ m -> Lwt.return (Node_config.mode_of_string m))
let mode_param =
Tezos_clic.param
~name:"mode"
~desc:
(Printf.sprintf
"The mode for the rollup node (%s)"
(String.concat ", " possible_modes))
mode_parameter
let allow_deposit_arg =
Tezos_clic.switch
~doc:"Allow the operator to make a first deposit for commitments"
~long:"allow-deposit"
()
let group =
Tezos_clic.
{
name = "tx_rollup.node";
title = "Commands related to the transaction rollup node";
}
let config_from_args data_dir (rollup_id : Client_proto_rollups.TxRollupAlias.t)
mode operator batch_signer finalize_commitment_signer
remove_commitment_signer rejection_signer dispatch_withdrawals_signer
origination_level rpc_addr cors_origins cors_headers allow_deposit
reconnection_delay =
let open Lwt_syntax in
let origination_level =
Option.either rollup_id.origination_level origination_level
in
let rollup_id = rollup_id.rollup in
let+ data_dir =
match data_dir with
| Some d -> return d
| None -> Node_config.default_data_dir rollup_id
in
let rpc_addr = Option.value rpc_addr ~default:Node_config.default_rpc_addr in
let reconnection_delay =
Option.value
reconnection_delay
~default:Node_config.default_reconnection_delay
in
Node_config.
{
data_dir;
mode;
signers =
{
operator;
submit_batch = batch_signer;
finalize_commitment = finalize_commitment_signer;
remove_commitment = remove_commitment_signer;
rejection = rejection_signer;
dispatch_withdrawals = dispatch_withdrawals_signer;
};
rollup_id;
origination_level;
rpc_addr;
cors_origins = Option.value cors_origins ~default:[];
cors_headers = Option.value cors_headers ~default:[];
reconnection_delay;
allow_deposit;
l2_blocks_cache_size = default_l2_blocks_cache_size;
caps = default_caps;
batch_burn_limit = None;
}
let patch_config_from_args config
(rollup_id : Client_proto_rollups.TxRollupAlias.t) mode operator
batch_signer finalize_commitment_signer remove_commitment_signer
rejection_signer dispatch_withdrawals_signer origination_level rpc_addr
cors_origins cors_headers allow_deposit reconnection_delay =
let origination_level =
Option.either rollup_id.origination_level origination_level
in
let rollup_id = rollup_id.rollup in
if
Protocol.Alpha_context.Tx_rollup.(rollup_id <> config.Node_config.rollup_id)
then
error_with
"Rollup node is configured for rollup %a but asked to run for rollup %a"
Protocol.Alpha_context.Tx_rollup.pp
config.Node_config.rollup_id
Protocol.Alpha_context.Tx_rollup.pp
rollup_id
else
let operator = Option.either operator config.signers.operator in
let submit_batch = Option.either batch_signer config.signers.submit_batch in
let finalize_commitment =
Option.either
finalize_commitment_signer
config.signers.finalize_commitment
in
let remove_commitment =
Option.either remove_commitment_signer config.signers.remove_commitment
in
let dispatch_withdrawals =
Option.either
dispatch_withdrawals_signer
config.signers.dispatch_withdrawals
in
let rejection = Option.either rejection_signer config.signers.rejection in
let signers =
{
Node_config.operator;
submit_batch;
finalize_commitment;
remove_commitment;
dispatch_withdrawals;
rejection;
}
in
let origination_level =
Option.either origination_level config.origination_level
in
let rpc_addr = Option.value rpc_addr ~default:config.rpc_addr in
let cors_origins = Option.value cors_origins ~default:config.cors_origins in
let cors_headers = Option.value cors_headers ~default:config.cors_headers in
let reconnection_delay =
Option.value reconnection_delay ~default:config.reconnection_delay
in
let allow_deposit = allow_deposit || config.allow_deposit in
let config =
{
config with
mode;
signers;
origination_level;
rpc_addr;
cors_origins;
cors_headers;
reconnection_delay;
allow_deposit;
}
in
ok config
let configuration_init_command =
let open Tezos_clic in
command
~group
~desc:"Configure the transaction rollup daemon."
(args14
force_switch
data_dir_arg
operator_arg
batch_signer_arg
finalize_commitment_signer_arg
remove_commitment_signer_arg
rejection_signer_arg
dispatch_withdrawals_signer_arg
origination_level_arg
rpc_addr_arg
cors_origins_arg
cors_headers_arg
allow_deposit_arg
reconnection_delay_arg)
(prefix "init" @@ mode_param
@@ prefixes ["config"; "for"]
@@ Tezos_clic.param
~name:"rollup-id"
~desc:"address of the rollup"
rollup_id_param
@@ stop)
(fun ( force,
data_dir,
operator,
batch_signer,
finalize_commitment_signer,
remove_commitment_signer,
rejection_signer,
dispatch_withdrawals_signer,
origination_level,
rpc_addr,
cors_origins,
cors_headers,
allow_deposit,
reconnection_delay )
mode
rollup_id
cctxt ->
let open Lwt_result_syntax in
let*! () = Event.(emit preamble_warning) () in
let*! config =
config_from_args
data_dir
rollup_id
mode
operator
batch_signer
finalize_commitment_signer
remove_commitment_signer
rejection_signer
dispatch_withdrawals_signer
origination_level
rpc_addr
cors_origins
cors_headers
allow_deposit
reconnection_delay
in
let*? config = Node_config.check_mode config in
let* file = Node_config.save ~force config in
(* This is necessary because the node has not yet been launched, so event
listening can't be used. *)
let*! () = cctxt#message "Configuration written in %s" file in
let*! () = Event.(emit configuration_was_written) file in
return_unit)
let run_command =
let open Lwt_result_syntax in
let open Tezos_clic in
command
~group
~desc:"Run the transaction rollup daemon."
(args13
data_dir_arg
operator_arg
batch_signer_arg
finalize_commitment_signer_arg
remove_commitment_signer_arg
rejection_signer_arg
dispatch_withdrawals_signer_arg
origination_level_arg
rpc_addr_opt_arg
cors_origins_arg
cors_headers_arg
allow_deposit_arg
reconnection_delay_arg)
(prefix "run" @@ mode_param @@ prefix "for"
@@ Tezos_clic.param
~name:"rollup-id"
~desc:"address of the rollup"
rollup_id_param
@@ stop)
(fun ( data_dir,
operator,
batch_signer,
finalize_commitment_signer,
remove_commitment_signer,
rejection_signer,
dispatch_withdrawals_signer,
origination_level,
rpc_addr,
cors_origins,
cors_headers,
allow_deposit,
reconnection_delay )
mode
rollup_id
cctxt ->
let*! () = Event.(emit preamble_warning) () in
let*! config_from_args =
config_from_args
data_dir
rollup_id
mode
operator
batch_signer
finalize_commitment_signer
remove_commitment_signer
rejection_signer
dispatch_withdrawals_signer
origination_level
rpc_addr
cors_origins
cors_headers
allow_deposit
reconnection_delay
in
let* config =
match data_dir with
| None -> return config_from_args
| Some data_dir -> (
let*! disk_config = Node_config.load ~data_dir in
match disk_config with
| Error (Error.Tx_rollup_configuration_file_does_not_exists _ :: _)
->
return config_from_args
| Error _ as err -> Lwt.return err
| Ok config ->
let*? config =
patch_config_from_args
config
rollup_id
mode
operator
batch_signer
finalize_commitment_signer
remove_commitment_signer
rejection_signer
dispatch_withdrawals_signer
origination_level
rpc_addr
cors_origins
cors_headers
allow_deposit
reconnection_delay
in
return config)
in
let*? config = Node_config.check_mode config in
Daemon.run config cctxt)
let tx_rollup_commands () =
List.map
(Tezos_clic.map_command (new Protocol_client_context.wrap_full))
[configuration_init_command; run_command]
let select_commands _ _ = return (tx_rollup_commands ())
let () = Client_main_run.run (module Daemon_config) ~select_commands