diff --git a/CHANGES.rst b/CHANGES.rst index 7aec0128c3905a8334a69f0d49a14e9655c0ef41..6eca214e387ae72708d3f98a8c2340cd199fcda2 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -238,6 +238,9 @@ Smart Rollup node - New CLI switch ``--unsafe-disable-wasm-kernel-checks`` which allows to bypass invalid kernel checks in the WASM VM, for use by jstz. (MR :gl:`!15910`) +- Support ``remote`` signer scheme and check remote signer available on + startup. (MR :gl:`!16651`) + Smart Rollup WASM Debugger -------------------------- diff --git a/src/bin_smart_rollup_node/main_smart_rollup_node.ml b/src/bin_smart_rollup_node/main_smart_rollup_node.ml index ac66aa5c07fdfd1ba6072a79d58f3707ce7ceae4..19ca7cd7289ea3b524665300c60d98aa4208bf3c 100644 --- a/src/bin_smart_rollup_node/main_smart_rollup_node.ml +++ b/src/bin_smart_rollup_node/main_smart_rollup_node.ml @@ -731,7 +731,7 @@ module Daemon_node_config = struct let default_media_type = Daemon_config.default_media_type - let other_registrations = None + let other_registrations = Client_config.other_registrations let default_daily_logs_path = None diff --git a/src/lib_injector/injector_functor.ml b/src/lib_injector/injector_functor.ml index 554ad7fa2eedcb5ffa2cc8c1f208a7975ac8af6a..0ba10408d5f6e7a0f37fd3e8d3df375cafa7776f 100644 --- a/src/lib_injector/injector_functor.ml +++ b/src/lib_injector/injector_functor.ml @@ -249,6 +249,21 @@ module Make (Parameters : PARAMETERS) = struct cctxt (List.map (fun k -> k.alias) signers) in + let* () = + List.iter_es + (fun s -> + let* pk_uri = Client_keys.neuterize s.sk in + (* Fetch public key for remote signer to make sure it is reachable. *) + trace_eval + (fun () -> + error_of_fmt + "Cannot get public key for signer %s. Most likely, the remote \ + signer cannot be reached." + s.alias) + (let* (_ : Signature.public_key) = Client_keys.public_key pk_uri in + return_unit)) + signers + in let data_dir = Filename.concat data_dir "injector" in let*! () = Lwt_utils_unix.create_dir data_dir in let filter op_proj op = diff --git a/tezt/lib_tezos/client.ml b/tezt/lib_tezos/client.ml index b2ee589fd5679af5254fcaebd8c6798c164f231d..cf72583335db1bd4da90907d4e619402c010be30 100644 --- a/tezt/lib_tezos/client.ml +++ b/tezt/lib_tezos/client.ml @@ -60,6 +60,7 @@ type t = { mutable mode : mode; runner : Runner.t option; dal_node : Dal_node.t option; + remote_signer : Uri.t option; } type stresstest_gas_estimation = { @@ -139,7 +140,7 @@ let address ?(hostname = false) ?from peer = let create_with_mode ?runner ?(path = Uses.path Constant.octez_client) ?(admin_path = Uses.path Constant.octez_admin_client) ?name - ?(color = Log.Color.FG.blue) ?base_dir ?dal_node mode = + ?(color = Log.Color.FG.blue) ?base_dir ?dal_node ?remote_signer mode = let name = match name with None -> fresh_name () | Some name -> name in let base_dir = match base_dir with None -> Temp.dir ?runner name | Some dir -> dir @@ -155,10 +156,11 @@ let create_with_mode ?runner ?(path = Uses.path Constant.octez_client) mode; runner; dal_node; + remote_signer; } let create ?runner ?path ?admin_path ?name ?color ?base_dir ?endpoint - ?media_type ?dal_node () = + ?media_type ?dal_node ?remote_signer () = create_with_mode ?runner ?path @@ -167,6 +169,7 @@ let create ?runner ?path ?admin_path ?name ?color ?base_dir ?endpoint ?color ?base_dir ?dal_node + ?remote_signer (Client (endpoint, media_type)) let base_dir_arg client = ["--base-dir"; client.base_dir] @@ -215,6 +218,11 @@ let mode_arg client = | Light _ -> ["--mode"; "light"; "--sources"; sources_file client] | Proxy _ -> ["--mode"; "proxy"] +let remote_signer_arg client = + match client.remote_signer with + | None -> [] + | Some uri -> ["--remote-signer"; Uri.to_string uri] + let spawn_command ?log_command ?log_status_on_exit ?log_output ?(env = String_map.empty) ?endpoint ?hooks ?(admin = false) ?protocol_hash ?config_file ?(no_base_dir_warnings = false) ?block client command = @@ -243,8 +251,8 @@ let spawn_command ?log_command ?log_status_on_exit ?log_output (if admin then client.admin_path else client.path) @@ endpoint_arg ?endpoint client @ protocol_arg @ media_type_arg client.mode @ mode_arg client - @ base_dir_arg client @ config_file_arg @ no_base_dir_warnings_arg @ block_arg - @ command + @ base_dir_arg client @ config_file_arg @ remote_signer_arg client + @ no_base_dir_warnings_arg @ block_arg @ command let spawn_command_with_stdin ?log_command ?log_status_on_exit ?log_output ?(env = String_map.empty) ?endpoint ?hooks ?(admin = false) ?protocol_hash @@ -268,7 +276,7 @@ let spawn_command_with_stdin ?log_command ?log_status_on_exit ?log_output (if admin then client.admin_path else client.path) @@ endpoint_arg ?endpoint client @ protocol_arg @ media_type_arg client.mode @ mode_arg client - @ base_dir_arg client @ command + @ base_dir_arg client @ remote_signer_arg client @ command let url_encode str = let buffer = Buffer.create (String.length str * 3) in @@ -609,24 +617,27 @@ let spawn_import_secret_key ?(force = false) ?endpoint client client (["import"; "secret"; "key"; alias; sk_uri] @ force) -let spawn_import_signer_key ?endpoint ?(force = false) client ~public_key_hash - ~alias signer_uri = - let uri = Uri.with_path signer_uri public_key_hash in +let spawn_import_signer_key ?endpoint ?(force = false) ?signer ~public_key_hash + ~alias client = + let key = + match signer with + | Some signer_uri -> + Uri.with_path signer_uri public_key_hash |> Uri.to_string + | None -> "remote:" ^ public_key_hash + in spawn_command ?endpoint client - (["import"; "secret"; "key"; alias; Uri.to_string uri] - @ if force then ["--force"] else []) + (["import"; "secret"; "key"; alias; key] @ if force then ["--force"] else []) -let import_signer_key ?endpoint ?force client ~public_key_hash ~alias signer_uri - = +let import_signer_key ?endpoint ?force ?signer ~public_key_hash ~alias client = spawn_import_signer_key ?endpoint ?force - client + ?signer ~public_key_hash ~alias - signer_uri + client |> Process.check let import_public_key ?force ?endpoint client public_key ~alias = @@ -2825,9 +2836,18 @@ module Zk_rollup = struct end let init ?path ?admin_path ?name ?color ?base_dir ?endpoint - ?(keys = Constant.all_secret_keys) ?media_type () = + ?(keys = Constant.all_secret_keys) ?media_type ?remote_signer () = let client = - create ?path ?admin_path ?name ?color ?base_dir ?endpoint ?media_type () + create + ?path + ?admin_path + ?name + ?color + ?base_dir + ?endpoint + ?media_type + ?remote_signer + () in Account.write keys ~base_dir:client.base_dir ; return client @@ -2870,7 +2890,8 @@ let write_sources_file ~min_agreement ~uris client = Lwt_io.fprintf oc "%s" @@ Ezjsonm.value_to_string obj) let init_light ?path ?admin_path ?name ?color ?base_dir ?(min_agreement = 0.66) - ?event_level ?event_sections_levels ?(nodes_args = []) ?dal_node () = + ?event_level ?event_sections_levels ?(nodes_args = []) ?dal_node + ?remote_signer () = let filter_node_arg = function | Node.Connections _ | Synchronisation_threshold _ -> None | x -> Some x @@ -2893,6 +2914,7 @@ let init_light ?path ?admin_path ?name ?color ?base_dir ?(min_agreement = 0.66) ?color ?base_dir ?dal_node + ?remote_signer (Light (min_agreement, List.map (fun n -> Node n) nodes)) in let* () = @@ -2985,7 +3007,8 @@ let get_parameter_file ?additional_bootstrap_accounts ?default_accounts_balance let init_with_node ?path ?admin_path ?name ?node_name ?color ?base_dir ?event_level ?event_sections_levels ?(nodes_args = Node.[Connections 0; Synchronisation_threshold 0]) - ?(keys = Constant.all_secret_keys) ?rpc_external ?dal_node tag () = + ?(keys = Constant.all_secret_keys) ?rpc_external ?dal_node ?remote_signer + tag () = match tag with | (`Client | `Proxy) as mode -> let* node = @@ -3003,7 +3026,15 @@ let init_with_node ?path ?admin_path ?name ?node_name ?color ?base_dir | `Proxy -> Proxy endpoint in let client = - create_with_mode ?path ?admin_path ?name ?color ?base_dir ?dal_node mode + create_with_mode + ?path + ?admin_path + ?name + ?color + ?base_dir + ?dal_node + ?remote_signer + mode in Account.write keys ~base_dir:client.base_dir ; return (node, client) @@ -3025,7 +3056,8 @@ let init_with_protocol ?path ?admin_path ?name ?node_name ?color ?base_dir ?event_level ?event_sections_levels ?nodes_args ?additional_bootstrap_account_count ?additional_revealed_bootstrap_account_count ?default_accounts_balance - ?parameter_file ?timestamp ?keys ?rpc_external ?dal_node tag ~protocol () = + ?parameter_file ?timestamp ?keys ?rpc_external ?dal_node ?remote_signer tag + ~protocol () = let* node, client = init_with_node ?path @@ -3040,6 +3072,7 @@ let init_with_protocol ?path ?admin_path ?name ?node_name ?color ?base_dir ?keys ?rpc_external ?dal_node + ?remote_signer tag () in diff --git a/tezt/lib_tezos/client.mli b/tezt/lib_tezos/client.mli index f5a81986ef391b2a1c549713d40d3f0ffacd39ea..4c527b4c84e5ccda79bc6aec9e4205e0e755eed6 100644 --- a/tezt/lib_tezos/client.mli +++ b/tezt/lib_tezos/client.mli @@ -133,6 +133,7 @@ val create : ?endpoint:endpoint -> ?media_type:media_type -> ?dal_node:Dal_node.t -> + ?remote_signer:Uri.t -> unit -> t @@ -145,6 +146,7 @@ val create_with_mode : ?color:Log.Color.t -> ?base_dir:string -> ?dal_node:Dal_node.t -> + ?remote_signer:Uri.t -> mode -> t @@ -466,10 +468,10 @@ val import_secret_key : val import_signer_key : ?endpoint:endpoint -> ?force:bool -> - t -> + ?signer:Uri.t -> public_key_hash:string -> alias:string -> - Uri.t -> + t -> unit Lwt.t (** Same as [import_secret_key] for signer, but do not wait for the @@ -477,10 +479,10 @@ val import_signer_key : val spawn_import_signer_key : ?endpoint:endpoint -> ?force:bool -> - t -> + ?signer:Uri.t -> public_key_hash:string -> alias:string -> - Uri.t -> + t -> Process.t (** Same as [import_secret_key], but do not wait for the process to exit. *) @@ -2482,6 +2484,7 @@ val init : ?endpoint:endpoint -> ?keys:Account.key list -> ?media_type:media_type -> + ?remote_signer:Uri.t -> unit -> t Lwt.t @@ -2506,6 +2509,7 @@ val init_with_node : ?keys:Account.key list -> ?rpc_external:bool -> ?dal_node:Dal_node.t -> + ?remote_signer:Uri.t -> [`Client | `Light | `Proxy] -> unit -> (Node.t * t) Lwt.t @@ -2542,6 +2546,7 @@ val init_with_protocol : ?keys:Account.key list -> ?rpc_external:bool -> ?dal_node:Dal_node.t -> + ?remote_signer:Uri.t -> [`Client | `Light | `Proxy] -> protocol:Protocol.t -> unit -> @@ -2583,6 +2588,7 @@ val init_light : ?event_sections_levels:(string * Daemon.Level.level) list -> ?nodes_args:Node.argument list -> ?dal_node:Dal_node.t -> + ?remote_signer:Uri.t -> unit -> (t * Node.t * Node.t) Lwt.t diff --git a/tezt/lib_tezos/sc_rollup_node.ml b/tezt/lib_tezos/sc_rollup_node.ml index 9294d336aac0fae778b2fe2bbfb65c474a60573b..4f1d8c258defad7465873706efb83f4c96645d21 100644 --- a/tezt/lib_tezos/sc_rollup_node.ml +++ b/tezt/lib_tezos/sc_rollup_node.ml @@ -199,6 +199,7 @@ module Parameters = struct type persistent_state = { data_dir : string; base_dir : string; + remote_signer : Uri.t option; mutable operators : (purpose * string) list; default_operator : string option; metrics_addr : string option; @@ -330,6 +331,10 @@ let make_command_arguments ?endpoint ?password_file node = in ["--endpoint"; endpoint; "--base-dir"; base_dir node] @ Cli_arg.optional_arg "password-filename" Fun.id password_file + @ Cli_arg.optional_arg + "remote-signer" + Uri.to_string + node.persistent_state.remote_signer let spawn_command sc_node args = Process.spawn @@ -559,10 +564,11 @@ let handle_event sc_node {name; value; timestamp = _} = | _ -> () let create_with_endpoint ?runner ?path ?name ?color ?data_dir ~base_dir - ?event_pipe ?metrics_addr ?metrics_port ?(rpc_host = Constant.default_host) - ?rpc_port ?(operators = []) ?default_operator - ?(dal_node : Dal_node.t option) ?loser_mode ?(allow_degraded = false) - ?(gc_frequency = 1) ?(history_mode = Full) ?password_file mode endpoint = + ?remote_signer ?event_pipe ?metrics_addr ?metrics_port + ?(rpc_host = Constant.default_host) ?rpc_port ?(operators = []) + ?default_operator ?(dal_node : Dal_node.t option) ?loser_mode + ?(allow_degraded = false) ?(gc_frequency = 1) ?(history_mode = Full) + ?password_file mode endpoint = 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 @@ -586,6 +592,7 @@ let create_with_endpoint ?runner ?path ?name ?color ?data_dir ~base_dir { data_dir; base_dir; + remote_signer; metrics_addr; metrics_port; rpc_host; @@ -608,10 +615,10 @@ let create_with_endpoint ?runner ?path ?name ?color ?data_dir ~base_dir on_event sc_node (handle_event sc_node) ; sc_node -let create ?runner ?path ?name ?color ?data_dir ~base_dir ?event_pipe - ?metrics_addr ?metrics_port ?rpc_host ?rpc_port ?operators ?default_operator - ?dal_node ?loser_mode ?allow_degraded ?gc_frequency ?history_mode - ?password_file mode (node : Node.t) = +let create ?runner ?path ?name ?color ?data_dir ~base_dir ?remote_signer + ?event_pipe ?metrics_addr ?metrics_port ?rpc_host ?rpc_port ?operators + ?default_operator ?dal_node ?loser_mode ?allow_degraded ?gc_frequency + ?history_mode ?password_file mode (node : Node.t) = create_with_endpoint ?runner ?path @@ -619,6 +626,7 @@ let create ?runner ?path ?name ?color ?data_dir ~base_dir ?event_pipe ?color ?data_dir ~base_dir + ?remote_signer ?event_pipe ?metrics_addr ?metrics_port diff --git a/tezt/lib_tezos/sc_rollup_node.mli b/tezt/lib_tezos/sc_rollup_node.mli index 603ffc0ac0dfcf879c1dfd6d30b52c325f7ed35e..fc43271f5920234b317d1baae316fe5b4c26f00b 100644 --- a/tezt/lib_tezos/sc_rollup_node.mli +++ b/tezt/lib_tezos/sc_rollup_node.mli @@ -118,6 +118,10 @@ val string_of_history_mode : history_mode -> string GC, and the [gc_frequency] is [1] by default to make it runs on every occasion during tests. + [remote_signer] makes the rollup node use a remote signer at the provided + URL to sign messages for keys that were registered with the ["remote:"] + scheme. + *) val create : ?runner:Runner.t -> @@ -126,6 +130,7 @@ val create : ?color:Log.Color.t -> ?data_dir:string -> base_dir:string -> + ?remote_signer:Uri.t -> ?event_pipe:string -> ?metrics_addr:string -> ?metrics_port:int -> @@ -151,6 +156,7 @@ val create_with_endpoint : ?color:Log.Color.t -> ?data_dir:string -> base_dir:string -> + ?remote_signer:Uri.t -> ?event_pipe:string -> ?metrics_addr:string -> ?metrics_port:int -> diff --git a/tezt/tests/agnostic_baker_test.ml b/tezt/tests/agnostic_baker_test.ml index 4f751f1f0702f3d7eee73cfb3b8f039334b1cf24..838c20814516a4115a31e98f3b4cb74ad7514447 100644 --- a/tezt/tests/agnostic_baker_test.ml +++ b/tezt/tests/agnostic_baker_test.ml @@ -66,7 +66,7 @@ let perform_protocol_migration ?(resilience_test = false) ?node_name Lwt_list.iter_s (fun account -> let Account.{alias; public_key_hash; _} = account in - Client.import_signer_key client ~alias ~public_key_hash uri) + Client.import_signer_key client ~alias ~public_key_hash ~signer:uri) keys else unit in diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index 39815ede44b011afc24f0ec8a1f8a3aeb445ae43..ad90472b8f474ec4932bc273912f86351e7aa020 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -3925,7 +3925,10 @@ let test_interrupt_rollup_node = let* _ = Sc_rollup_node.wait_for_level ~timeout:20. sc_rollup_node 18 in unit -let test_remote_signer = +let remote_signer_uri signer ~yes = + if yes then Some (Signer.uri signer) else None + +let test_remote_signer ~hardcoded_remote_signer = let default_operator = Constant.bootstrap2 in let operators = [ @@ -3938,7 +3941,10 @@ let test_remote_signer = { tags = ["remote"; "signer"]; variant = None; - description = "rollup node can sign operations with remote signer"; + description = + sf + "rollup node can sign operations with %s remote signer" + (if hardcoded_remote_signer then "hardcoded" else "relocatable"); } ~uses:(fun _ -> [Constant.octez_signer]) ~commitment_period:3 @@ -3947,10 +3953,31 @@ let test_remote_signer = ~operator:default_operator.public_key_hash ~operators: (List.map (fun (p, k) -> (p, k.Account.public_key_hash)) operators) - @@ fun _protocol sc_rollup_node sc_rollup node client -> + @@ fun _protocol sc_rollup_node sc_rollup node _client -> let keys = default_operator :: List.map snd operators in Log.info "Starting remote signer" ; let* signer = Signer.init ~keys () in + let client_remote_signer = + remote_signer_uri signer ~yes:(not hardcoded_remote_signer) + in + let base_dir = Sc_rollup_node.base_dir sc_rollup_node in + let* client = + Client.init + ~base_dir + ~endpoint:(Node node) + ?remote_signer:client_remote_signer + () + in + let sc_rollup_node = + Sc_rollup_node.create + ~default_operator:default_operator.public_key_hash + ~operators: + (List.map (fun (p, k) -> (p, k.Account.public_key_hash)) operators) + ?remote_signer:client_remote_signer + ~base_dir + Operator + node + in Log.info "Registering keys as remote in client" ; let import (k : Account.key) = Client.import_signer_key @@ -3958,7 +3985,7 @@ let test_remote_signer = ~force:true ~public_key_hash:k.public_key_hash ~alias:k.alias - (Signer.uri signer) + ?signer:(remote_signer_uri signer ~yes:hardcoded_remote_signer) in let* () = Lwt_list.iter_s import keys in let sks = @@ -3970,8 +3997,11 @@ let test_remote_signer = let open JSON in let entry = List.find (fun e -> e |-> "name" |> as_string = k.alias) sks in let sk = entry |-> "value" |> as_string in - if not @@ String.starts_with ~prefix:"http://" sk then - Test.fail ~__LOC__ "Key %s not using remote signer" k.alias + if + not + @@ (String.starts_with ~prefix:"http://" sk + || String.starts_with ~prefix:"remote:" sk) + then Test.fail ~__LOC__ "Key %s not using remote signer" k.alias in List.iter check_config_key keys ; Log.info "Create wallet just for baking" ; @@ -3984,6 +4014,23 @@ let test_remote_signer = Constant.bootstrap1.secret_key ~alias:Constant.bootstrap1.alias in + Log.info "Stopping signer" ; + let* () = Signer.terminate signer in + let* () = Sc_rollup_node.run ~wait_ready:false sc_rollup_node sc_rollup [] + and* () = + Lwt.choose + [ + (let* () = Lwt_unix.sleep 30. in + Test.fail + "Rollup node did not detect the remote signer was unreachable"); + Sc_rollup_node.check_error + ~exit_code:1 + ~msg:(rex "Cannot get public key for signer") + sc_rollup_node; + ] + in + Log.info "Restart signer" ; + let* () = Signer.restart signer in Log.info "Starting rollup node" ; let* () = Sc_rollup_node.run ~event_level:`Debug sc_rollup_node sc_rollup [] @@ -7159,4 +7206,5 @@ let register_protocol_independent () = bailout_mode_fail_to_start_without_operator ~kind protocols ; bailout_mode_fail_operator_no_stake ~kind protocols ; bailout_mode_recover_bond_starting_no_commitment_staked ~kind protocols ; - test_remote_signer ~kind protocols + test_remote_signer ~hardcoded_remote_signer:true ~kind protocols ; + test_remote_signer ~hardcoded_remote_signer:false ~kind protocols diff --git a/tezt/tests/signer_test.ml b/tezt/tests/signer_test.ml index 25637b31e0f0e8170674889c762c0167d1e95727..9a1fd1d62f689cd339a19ea6d49bb393b70f8ff4 100644 --- a/tezt/tests/signer_test.ml +++ b/tezt/tests/signer_test.ml @@ -57,7 +57,7 @@ let signer_test protocol ~keys = Lwt_list.iter_s (fun account -> let Account.{alias; public_key_hash; _} = account in - Client.import_signer_key client ~alias ~public_key_hash uri) + Client.import_signer_key client ~alias ~public_key_hash ~signer:uri) keys in let level_2_promise = Node.wait_for_level node 2 in @@ -93,9 +93,12 @@ let signer_magic_bytes_test = Signer.init ~keys:[Constant.tz4_account] ~magic_byte:"0x03" () in let* () = - let uri = Signer.uri signer in let Account.{alias; public_key_hash; _} = Constant.tz4_account in - Client.import_signer_key client ~alias ~public_key_hash uri + Client.import_signer_key + client + ~alias + ~public_key_hash + ~signer:(Signer.uri signer) in (* Check allowed magic byte. *) let* _ = @@ -121,9 +124,12 @@ let signer_bls_test = let* _node, client = Client.init_with_protocol `Client ~protocol () in let* signer = Signer.init ~keys:[Constant.tz4_account] () in let* () = - let uri = Signer.uri signer in let Account.{alias; public_key_hash; _} = Constant.tz4_account in - Client.import_signer_key client ~alias ~public_key_hash uri + Client.import_signer_key + client + ~alias + ~public_key_hash + ~signer:(Signer.uri signer) in let* () = Client.transfer