diff --git a/src/proto_alpha/bin_sc_rollup_node/configuration.ml b/src/proto_alpha/bin_sc_rollup_node/configuration.ml index 5608d3760e36466a32c421ed7f8e86c831703ff8..f2d58fec18dbc4a1bd370ce69e6968edf98e9d23 100644 --- a/src/proto_alpha/bin_sc_rollup_node/configuration.ml +++ b/src/proto_alpha/bin_sc_rollup_node/configuration.ml @@ -23,9 +23,15 @@ (* *) (*****************************************************************************) +open Protocol.Alpha_context + +(* TODO: https://gitlab.com/tezos/tezos/-/issues/2793 + add fee parameters values in the configuration. +*) type t = { data_dir : string; - sc_rollup_address : Protocol.Alpha_context.Sc_rollup.t; + sc_rollup_address : Sc_rollup.t; + sc_rollup_node_operator : Signature.Public_key_hash.t; rpc_addr : string; rpc_port : int; } @@ -41,14 +47,55 @@ let default_rpc_addr = "127.0.0.1" let default_rpc_port = 8932 +(* TODO: https://gitlab.com/tezos/tezos/-/issues/2794 + the below default values have been copied from + `src/proto_alpha/lib_client/client_proto_args.ml`, but + we need to check whether these values are sensible for the rollup + node. +*) +let default_minimal_fees = + match Tez.of_mutez 100L with None -> assert false | Some t -> t + +let default_minimal_nanotez_per_gas_unit = Q.of_int 100 + +let default_minimal_nanotez_per_byte = Q.of_int 1000 + +let default_force_low_fee = false + +let default_fee_cap = + match Tez.of_string "1.0" with None -> assert false | Some t -> t + +let default_burn_cap = + match Tez.of_string "0" with None -> assert false | Some t -> t + +let default_fee_parameter : Injection.fee_parameter = + { + minimal_fees = default_minimal_fees; + minimal_nanotez_per_gas_unit = default_minimal_nanotez_per_gas_unit; + minimal_nanotez_per_byte = default_minimal_nanotez_per_byte; + force_low_fee = default_force_low_fee; + fee_cap = default_fee_cap; + burn_cap = default_burn_cap; + } + let encoding : t Data_encoding.t = let open Data_encoding in conv - (fun {data_dir; sc_rollup_address; rpc_addr; rpc_port} -> - (data_dir, sc_rollup_address, rpc_addr, rpc_port)) - (fun (data_dir, sc_rollup_address, rpc_addr, rpc_port) -> - {data_dir; sc_rollup_address; rpc_addr; rpc_port}) - (obj4 + (fun { + data_dir; + sc_rollup_address; + sc_rollup_node_operator; + rpc_addr; + rpc_port; + } -> + (data_dir, sc_rollup_address, sc_rollup_node_operator, rpc_addr, rpc_port)) + (fun ( data_dir, + sc_rollup_address, + sc_rollup_node_operator, + rpc_addr, + rpc_port ) -> + {data_dir; sc_rollup_address; sc_rollup_node_operator; rpc_addr; rpc_port}) + (obj5 (dft "data-dir" ~description:"Location of the data dir" @@ -58,6 +105,11 @@ let encoding : t Data_encoding.t = "sc-rollup-address" ~description:"Smart contract rollup address" Protocol.Alpha_context.Sc_rollup.Address.encoding) + (req + "sc-rollup-node-operator" + ~description: + "Public key hash of the Smart contract rollup node operator" + Signature.Public_key_hash.encoding) (dft "rpc-addr" ~description:"RPC address" string default_rpc_addr) (dft "rpc-port" ~description:"RPC port" int16 default_rpc_port)) diff --git a/src/proto_alpha/bin_sc_rollup_node/configuration.mli b/src/proto_alpha/bin_sc_rollup_node/configuration.mli index b3da9f98efc2066f50cdab5caf0102110a9a69cf..d8eb5434fd5374de8d4ed86428679046d916628f 100644 --- a/src/proto_alpha/bin_sc_rollup_node/configuration.mli +++ b/src/proto_alpha/bin_sc_rollup_node/configuration.mli @@ -26,6 +26,7 @@ type t = { data_dir : string; sc_rollup_address : Protocol.Alpha_context.Sc_rollup.t; + sc_rollup_node_operator : Signature.Public_key_hash.t; rpc_addr : string; rpc_port : int; } @@ -39,6 +40,8 @@ val default_rpc_addr : string (** [default_rpc_port] is the default value for [rpc_port]. *) val default_rpc_port : int +val default_fee_parameter : Injection.fee_parameter + (** [filename configuration] returns the [configuration] filename. *) val filename : t -> string diff --git a/src/proto_alpha/bin_sc_rollup_node/constants.ml b/src/proto_alpha/bin_sc_rollup_node/constants.ml new file mode 100644 index 0000000000000000000000000000000000000000..d27f249ea1d4177f872399b499c957a0e14c6a10 --- /dev/null +++ b/src/proto_alpha/bin_sc_rollup_node/constants.ml @@ -0,0 +1,65 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 TriliTech *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* TODO:https://gitlab.com/tezos/tezos/-/issues/2791 + This module should be deprecated in favour of a data structure that + contains rollup address, rollup node operator address, and rollup + origination level. +*) + +let unstarted_failure () = + Format.eprintf "Sc rollup state is not initialised.\n" ; + Lwt_exit.exit_and_raise 1 + +let make_ref () = + let reference = ref None in + ( (fun x -> reference := Some x), + fun () -> match !reference with None -> unstarted_failure () | Some a -> a + ) + +let (set_sc_rollup_address, get_sc_rollup_address) = make_ref () + +let (set_sc_rollup_node_operator, get_sc_rollup_node_operator) = make_ref () + +let (set_sc_rollup_initial_level, get_sc_rollup_initial_level) = make_ref () + +let get_operator_keys cctxt = + let open Lwt_tzresult_syntax in + let pkh = get_sc_rollup_node_operator () in + let+ (_, pk, sk) = Client_keys.get_key cctxt pkh in + (pkh, pk, sk) + +let init (cctxt : Protocol_client_context.full) sc_rollup_address + sc_rollup_node_operator = + let open Lwt_tzresult_syntax in + set_sc_rollup_address sc_rollup_address ; + set_sc_rollup_node_operator sc_rollup_node_operator ; + let+ initial_level = + Plugin.RPC.Sc_rollup.initial_level + cctxt + (cctxt#chain, cctxt#block) + sc_rollup_address + in + set_sc_rollup_initial_level initial_level diff --git a/src/proto_alpha/bin_sc_rollup_node/constants.mli b/src/proto_alpha/bin_sc_rollup_node/constants.mli new file mode 100644 index 0000000000000000000000000000000000000000..174df19d300652b53fa25b5ec0bf9b0d25ce3465 --- /dev/null +++ b/src/proto_alpha/bin_sc_rollup_node/constants.mli @@ -0,0 +1,72 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 TriliTech *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +open Protocol +open Alpha_context + +(** Returns the address of the smart contract rollup tracked by the rollup node. + This function reads a reference that gets initialised by the [init] function. + Invoking [get_sc_rollup_address] before [init] will cause the rollup node + to crash and exit with code 1. +*) +val get_sc_rollup_address : unit -> Sc_rollup.t + +(** Returns the address of the rollup node operator. + This function reads a reference that gets initialised by the [init] function. + Invoking [get_sc_rollup_node_operator] before [init] will cause the rollup + node to crash and exit with code 1. +*) +val get_sc_rollup_node_operator : unit -> Signature.Public_key_hash.t + +(** Returns the origination level of the smart contract rollup tracked by the + rollup node. This function reads a reference that gets initialised by the + [init] function. Invoking [get_sc_rollp_initial_level] before [init] will + cause the rollup node to crash and exit with code 1. +*) +val get_sc_rollup_initial_level : unit -> Raw_level.t + +(** [get_operator_keys cctxt] returns a triple [(pkh, pk, sk)] corresponding + to the address, public key, and secret key URI of the rollup node operator. + The rollup node operator address is read from a reference that is + initialised by the [init] function. Invoking [get_operator_keys] before + [init] will cause the rollup node to crash and exit with code 1. + The node will also crash if the public and secret key for the address + are not stored in the wallet of [cctxt]. +*) +val get_operator_keys : + Protocol_client_context.full -> + (Signature.Public_key_hash.t * Signature.Public_key.t * Client_keys.sk_uri) + tzresult + Lwt.t + +(* [init cctxt sc_rollup operator_pkh] initialises the global constants + provided by this module. The rollup origination level is fetched + via an RPC call to the layer1 node that [cctxt] uses for RPC requests. +*) +val init : + Protocol_client_context.full -> + Alpha_context.Sc_rollup.t -> + Signature.Public_key_hash.t -> + unit tzresult Lwt.t diff --git a/src/proto_alpha/bin_sc_rollup_node/daemon.ml b/src/proto_alpha/bin_sc_rollup_node/daemon.ml index f455b85853daebee42b671eab9eef2c62907f91f..374a640164dfb04e16cec8a9bcb9c2f17e3f87ae 100644 --- a/src/proto_alpha/bin_sc_rollup_node/daemon.ml +++ b/src/proto_alpha/bin_sc_rollup_node/daemon.ml @@ -58,12 +58,27 @@ let run ~data_dir (cctxt : Protocol_client_context.full) = let*! () = Event.starting_node () in let* configuration = Configuration.load ~data_dir in let open Configuration in - let {rpc_addr; rpc_port; sc_rollup_address; _} = configuration in + let {rpc_addr; rpc_port; sc_rollup_address; sc_rollup_node_operator; _} = + configuration + in let*! store = Store.load configuration in + let* rpc_server = RPC_server.Arith.start store configuration in + (* TODO:https://gitlab.com/tezos/tezos/-/issues/2791 + The Constants module should be deprecated in favour of a data + structure that contains rollup address, rollup node operator + address, and rollup origination level. + *) + let* () = Constants.init cctxt sc_rollup_address sc_rollup_node_operator in + (* Check that the public key hash is valid *) + let* (_pkh, _pk, _skh) = Constants.get_operator_keys cctxt in + (* Do not reorder the operations above this one, as + State depends on the RPC server to fetch the initial + rollup level, and modules below depend on State + to fetch in-memory variables + *) let* tezos_heads = Layer1.start configuration cctxt store in let*! () = Inbox.start store sc_rollup_address in let* () = Interpreter.Arith.start store in - let* rpc_server = RPC_server.Arith.start store configuration in let _ = install_finalizer store rpc_server in let*! () = Event.node_is_ready ~rpc_addr ~rpc_port in daemonize cctxt store tezos_heads diff --git a/src/proto_alpha/bin_sc_rollup_node/inbox.ml b/src/proto_alpha/bin_sc_rollup_node/inbox.ml index 30315b50b01820460fd2639ffd0ce8fdabc12699..2bc6a17c5b7a514b5658c023ba1471b073f3ad98 100644 --- a/src/proto_alpha/bin_sc_rollup_node/inbox.ml +++ b/src/proto_alpha/bin_sc_rollup_node/inbox.ml @@ -23,6 +23,10 @@ (* *) (*****************************************************************************) +(* module Constants will be shadowed by Alpha_context.Constansts + once we open Alpha_context, hence we we alias it to Rollup_node_constants +*) +module Rollup_node_constants = Constants open Protocol open Alpha_context module Block_services = Block_services.Make (Protocol) (Protocol) @@ -34,10 +38,6 @@ let head_processing_failure e = e ; Lwt_exit.exit_and_raise 1 -let unstarted_failure () = - Format.eprintf "Sc rollup node inbox is not started.\n" ; - Lwt_exit.exit_and_raise 1 - module State = struct let add_messages = Store.Messages.add @@ -51,14 +51,6 @@ module State = struct let history_of_hash = Store.Histories.get - let (set_sc_rollup_address, get_sc_rollup_address) = - let sc_rollup_address = ref None in - ( (fun x -> sc_rollup_address := Some x), - fun () -> - match !sc_rollup_address with - | None -> unstarted_failure () - | Some a -> a ) - let get_message_tree = Store.MessageTrees.get let set_message_tree = Store.MessageTrees.set @@ -88,7 +80,7 @@ let get_messages cctxt head rollup = List.concat_map process_operations operations let process_head cctxt store Layer1.(Head {level; hash = head_hash} as head) = - let rollup = State.get_sc_rollup_address () in + let rollup = Rollup_node_constants.get_sc_rollup_address () in let open Lwt_result_syntax in get_messages cctxt (head_hash, level) rollup >>= function | Error e -> head_processing_failure e @@ -139,7 +131,6 @@ let inbox_of_hash = State.inbox_of_hash let start store sc_rollup_address = let open Lwt_syntax in - State.set_sc_rollup_address sc_rollup_address ; Inbox_event.starting () >>= fun () -> State.inbox_exists store Layer1.genesis_hash >>= function | false -> diff --git a/src/proto_alpha/bin_sc_rollup_node/main_sc_rollup_node_alpha.ml b/src/proto_alpha/bin_sc_rollup_node/main_sc_rollup_node_alpha.ml index b11dbf5a614fe91bc7a0c0d4511327f085afa9f3..9a39f1e81f228ba68c66d25a54c947235b781020 100644 --- a/src/proto_alpha/bin_sc_rollup_node/main_sc_rollup_node_alpha.ml +++ b/src/proto_alpha/bin_sc_rollup_node/main_sc_rollup_node_alpha.ml @@ -32,11 +32,22 @@ let sc_rollup_address_param = | None -> failwith "Invalid smart-contract rollup address" | Some addr -> return addr)) +let sc_rollup_node_operator_param = + let open Lwt_tzresult_syntax in + Clic.param + ~name:"node-operator" + ~desc:"Public key hash of the the smart-contract rollup node operator" + (Clic.parameter (fun _ s -> + match Signature.Public_key_hash.of_b58check_opt s with + | None -> + failwith "Could not read public key hash for rollup node operator" + | Some pkh -> return pkh)) + let rpc_addr_arg = let default = Configuration.default_rpc_addr in Clic.default_arg ~long:"rpc-addr" - ~placeholder:"address|ip" + ~placeholder:"rpc-address|ip" ~doc: (Format.sprintf "The address the smart-contract rollup node listens to. Default value \ @@ -49,7 +60,7 @@ let rpc_port_arg = let default = Configuration.default_rpc_port |> string_of_int in Clic.default_arg ~long:"rpc-port" - ~placeholder:"port" + ~placeholder:"rpc-port" ~doc: (Format.sprintf "The port the smart-contract rollup node listens to. Default value is \ @@ -83,10 +94,24 @@ let config_init_command = ~group ~desc:"Configure the smart-contract rollup node." (args3 data_dir_arg rpc_addr_arg rpc_port_arg) - (prefixes ["config"; "init"; "on"] @@ sc_rollup_address_param @@ stop) - (fun (data_dir, rpc_addr, rpc_port) sc_rollup_address cctxt -> + (prefixes ["config"; "init"; "on"] + @@ sc_rollup_address_param + @@ prefixes ["with"; "operator"] + @@ sc_rollup_node_operator_param stop) + (fun (data_dir, rpc_addr, rpc_port) + sc_rollup_address + sc_rollup_node_operator + cctxt -> let open Configuration in - let config = {data_dir; sc_rollup_address; rpc_addr; rpc_port} in + let config = + { + data_dir; + sc_rollup_address; + sc_rollup_node_operator; + rpc_addr; + rpc_port; + } + in save config >>=? fun () -> cctxt#message "Smart-contract rollup node configuration written in %s" @@ -110,4 +135,6 @@ let sc_rollup_commands () = let select_commands _ _ = return (sc_rollup_commands () @ Client_helpers_commands.commands ()) +let main () = () + let () = Client_main_run.run (module Client_config) ~select_commands diff --git a/src/proto_alpha/lib_plugin/plugin.ml b/src/proto_alpha/lib_plugin/plugin.ml index 83cf62fc670a832636ad8a60d830a4d0b4c05b08..9f540f4fd69abe2c89f5c9c6dc22faf566171485 100644 --- a/src/proto_alpha/lib_plugin/plugin.ml +++ b/src/proto_alpha/lib_plugin/plugin.ml @@ -2928,7 +2928,7 @@ module RPC = struct RPC_service.get_service ~description:"Initial level for a smart-contract rollup" ~query:RPC_query.empty - ~output:Raw_level_repr.encoding + ~output:Raw_level.encoding RPC_path.(path /: Sc_rollup.Address.rpc_arg / "initial_level") let root = @@ -2973,7 +2973,7 @@ module RPC = struct let list ctxt block = RPC_context.make_call0 S.root ctxt block () () let initial_level ctxt block sc_rollup_address = - RPC_context.make_call1 S.initial_level ctxt block sc_rollup_address () + RPC_context.make_call1 S.initial_level ctxt block sc_rollup_address () () end module Forge = struct diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 7bf2ff240166241b8474808f4402f42c41d37004..ba08e9598d5d8bf78c50ee9cf7fbdfba5dc07fba 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2617,7 +2617,7 @@ module Sc_rollup : sig val list : context -> t list tzresult Lwt.t - val initial_level : context -> t -> Raw_level_repr.t tzresult Lwt.t + val initial_level : context -> t -> Raw_level.t tzresult Lwt.t module Internal_for_tests : sig val originated_sc_rollup : Origination_nonce.Internal_for_tests.t -> t diff --git a/tezt/lib_tezos/sc_rollup_node.ml b/tezt/lib_tezos/sc_rollup_node.ml index 24c7fabc757ff533c1a39beb8a8c25bd10686ef2..f3307b647ad529fd688863d7efa86a2b8ef3dc79 100644 --- a/tezt/lib_tezos/sc_rollup_node.ml +++ b/tezt/lib_tezos/sc_rollup_node.ml @@ -28,8 +28,10 @@ type 'a known = Unknown | Known of 'a module Parameters = struct type persistent_state = { data_dir : string; + operator_pkh : string; rpc_host : string; rpc_port : int; + client : Client.t; node : Node.t; mutable pending_ready : unit option Lwt.u list; mutable pending_level : (int * int option Lwt.u) list; @@ -73,6 +75,14 @@ let endpoint sc_node = let data_dir sc_node = sc_node.persistent_state.data_dir +let base_dir sc_node = Client.base_dir sc_node.persistent_state.client + +let operator_pkh sc_node = sc_node.persistent_state.operator_pkh + +let layer1_addr sc_node = Node.rpc_host sc_node.persistent_state.node + +let layer1_port sc_node = Node.rpc_port sc_node.persistent_state.node + let spawn_command sc_node = Process.spawn ~name:sc_node.name ~color:sc_node.color sc_node.path @@ -84,6 +94,9 @@ let spawn_config_init sc_node rollup_address = "init"; "on"; rollup_address; + "with"; + "operator"; + operator_pkh sc_node; "--data-dir"; data_dir sc_node; "--rpc-addr"; @@ -184,7 +197,8 @@ let handle_event sc_node {name; value} = | _ -> () let create ?(path = Constant.sc_rollup_node) ?name ?color ?data_dir ?event_pipe - ?(rpc_host = "127.0.0.1") ?rpc_port (node : Node.t) = + ?(rpc_host = "127.0.0.1") ?rpc_port ~operator_pkh (node : Node.t) + (client : Client.t) = let name = match name with None -> fresh_name () | Some name -> name in let data_dir = match data_dir with None -> Temp.dir name | Some dir -> dir @@ -202,7 +216,9 @@ let create ?(path = Constant.sc_rollup_node) ?name ?color ?data_dir ?event_pipe data_dir; rpc_host; rpc_port; + operator_pkh; node; + client; pending_ready = []; pending_level = []; } @@ -213,10 +229,9 @@ let create ?(path = Constant.sc_rollup_node) ?name ?color ?data_dir ?event_pipe let make_arguments node = [ "--endpoint"; - Printf.sprintf - "http://%s:%d" - (Node.rpc_host node.persistent_state.node) - (Node.rpc_port node.persistent_state.node); + Printf.sprintf "http://%s:%d" (layer1_addr node) (layer1_port node); + "--base-dir"; + base_dir node; ] let do_runlike_command node arguments = diff --git a/tezt/lib_tezos/sc_rollup_node.mli b/tezt/lib_tezos/sc_rollup_node.mli index 2c4188829409a9b56cf818d28495fb0811a11d9a..4aa1fbd06b691d0715f88bda5e03fb7d675fb2d4 100644 --- a/tezt/lib_tezos/sc_rollup_node.mli +++ b/tezt/lib_tezos/sc_rollup_node.mli @@ -62,7 +62,9 @@ val create : ?event_pipe:string -> ?rpc_host:string -> ?rpc_port:int -> + operator_pkh:string -> Node.t -> + Client.t -> t (** Get the name of an sc node. *) @@ -80,6 +82,12 @@ val endpoint : t -> string (** Get the data-dir of an sc node. *) val data_dir : t -> string +(** Get the base-dir of an sc node *) +val base_dir : t -> string + +(** Get the public key hash of the sc node oeprator *) +val operator_pkh : t -> string + (** Wait until an sc node terminates and check its status. If the sc node is not running, diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index b91f2ce366a6118559059077d0c75b80b7a89e3d..c727741442ec1f904c54eb8de61c5454c942df35 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -123,7 +123,9 @@ let with_fresh_rollup f tezos_node tezos_client bootstrap1_key = ~boot_sector:"" tezos_client in - let sc_rollup_node = Sc_rollup_node.create tezos_node in + let sc_rollup_node = + Sc_rollup_node.create tezos_node tezos_client ~operator_pkh:bootstrap1_key + in let* configuration_filename = Sc_rollup_node.config_init sc_rollup_node rollup_address in