diff --git a/src/bin_dac_client/main_dac_client.ml b/src/bin_dac_client/main_dac_client.ml index 12c47f266d8eddc3957efff4e393e29c1997a00e..e873d38cdbe84905e0318c4dbbee9f6131f9d485 100644 --- a/src/bin_dac_client/main_dac_client.ml +++ b/src/bin_dac_client/main_dac_client.ml @@ -115,13 +115,47 @@ let hex_root_hash_param ?(name = "hex root hash") ~desc (Tezos_clic.map_parameter ~f:Dac_plugin.raw_hash_of_bytes hex_parameter) +let content_filename_param ?(name = "payload filename") + ?(desc = "A filename containing a payload") = + let desc = String.concat "\n" [desc; "Payload must be in binary format"] in + Tezos_clic.param ~name ~desc (Client_config.string_parameter ()) + let group = { Tezos_clic.name = "dac-client"; title = "Dac client commands for interacting with a Dac node"; } -let send_dac_payload = +let send_raw_payload threshold coordinator_cctxt payload = + let open Lwt_result_syntax in + let* root_hash = Command_handlers.send_preimage coordinator_cctxt payload in + match threshold with + | None -> + return + @@ Format.printf + "Payload stored under root hash: %a" + Dac_plugin.pp_raw_hash + root_hash + | Some threshold -> ( + let* certificate_opt = + Command_handlers.wait_for_certificate + coordinator_cctxt + root_hash + threshold + in + match certificate_opt with + | None -> + return + @@ Format.printf + "No certificate could be obtained.\n\ + Payload stored under root hash: %a\n" + Dac_plugin.pp_raw_hash + root_hash + | Some certificate -> + return + @@ Format.printf "Certificate received: %a\n" Hex.pp certificate) + +let send_dac_payload_input_from_command_line = let open Tezos_clic in command ~group @@ -132,35 +166,31 @@ let send_dac_payload = @@ prefixes ["with"; "content"] @@ hex_payload_param @@ stop) (fun threshold coordinator_cctxt payload _cctxt -> + send_raw_payload threshold coordinator_cctxt payload) + +let send_dac_payload_input_from_file = + let open Tezos_clic in + command + ~group + ~desc:"Send the contents of a file as payload to the DAC coordinator." + (args1 wait_for_threshold_arg) + (prefixes ["send"; "payload"; "to"; "coordinator"] + @@ coordinator_rpc_param + @@ prefixes ["from"; "file"] + @@ content_filename_param @@ stop) + (fun threshold coordinator_cctxt filename _cctxt -> let open Lwt_result_syntax in - let* root_hash = - Command_handlers.send_preimage coordinator_cctxt payload + let* payload = + Lwt.catch + (fun () -> + let*! payload = Lwt_utils_unix.read_file filename in + return @@ String.to_bytes payload) + (fun exn -> + Stdlib.failwith + (Format.sprintf "Cannot read from file %s: %s" filename + @@ Printexc.to_string exn)) in - match threshold with - | None -> - return - @@ Format.printf - "Payload stored under root hash: %a" - Dac_plugin.pp_raw_hash - root_hash - | Some threshold -> ( - let* certificate_opt = - Command_handlers.wait_for_certificate - coordinator_cctxt - root_hash - threshold - in - match certificate_opt with - | None -> - return - @@ Format.printf - "No certificate could be obtained.\n\ - Payload stored under root hash: %a\n" - Dac_plugin.pp_raw_hash - root_hash - | Some certificate -> - return - @@ Format.printf "Certificate received: %a\n" Hex.pp certificate)) + send_raw_payload threshold coordinator_cctxt payload) let get_dac_certificate = let open Tezos_clic in @@ -188,7 +218,12 @@ let get_dac_certificate = return @@ Format.printf "Certificate received: %a\n" Hex.pp certificate) -let commands () = [send_dac_payload; get_dac_certificate] +let commands () = + [ + send_dac_payload_input_from_command_line; + send_dac_payload_input_from_file; + get_dac_certificate; + ] let select_commands _ _ = let open Lwt_result_syntax in diff --git a/tezt/lib_tezos/dac_client.ml b/tezt/lib_tezos/dac_client.ml index c326ffde057f1403c9221e637291607014ab9010..efe4d173f2f804763ca7ff63105bbf3dae7638c0 100644 --- a/tezt/lib_tezos/dac_client.ml +++ b/tezt/lib_tezos/dac_client.ml @@ -92,7 +92,7 @@ let get_certificate_output raw_output = | Some hex -> Some (Certificate (`Hex hex)) | None -> assert false) -let send_payload ?hooks ?threshold dac_client hex_payload = +let send_hex_payload ?hooks ?threshold dac_client hex_payload = let coordinator_endpoint = Printf.sprintf "%s:%d" @@ -123,6 +123,37 @@ let send_payload ?hooks ?threshold dac_client hex_payload = let* raw_output = Process.check_and_read_stdout process in Lwt.return @@ send_payload_output raw_output +let send_payload_from_file ?hooks ?threshold dac_client filename = + let coordinator_endpoint = + Printf.sprintf + "%s:%d" + (Dac_node.rpc_host dac_client.dac_node) + (Dac_node.rpc_port dac_client.dac_node) + in + let threshold_arg = + match threshold with + | None -> [] + | Some n -> ["--wait-for-threshold"; string_of_int n] + in + let*? process = + spawn_command + ?hooks + dac_client + ([ + "send"; + "payload"; + "to"; + "coordinator"; + coordinator_endpoint; + "from"; + "file"; + filename; + ] + @ threshold_arg) + in + let* raw_output = Process.check_and_read_stdout process in + Lwt.return @@ send_payload_output raw_output + let get_certificate ?hooks dac_client hex_root_hash = let coordinator_endpoint = Printf.sprintf diff --git a/tezt/lib_tezos/dac_client.mli b/tezt/lib_tezos/dac_client.mli index 70900879c9f0b800d6ea4982b6843aebf90ea42f..e8a6d0996baa610dad9c1a77e75382e2f33b6300 100644 --- a/tezt/lib_tezos/dac_client.mli +++ b/tezt/lib_tezos/dac_client.mli @@ -40,14 +40,23 @@ val create : Can be either a root hash or a certificate. *) type output = Root_hash of Hex.t | Certificate of Hex.t -(** [send_payload ?hooks ?threshold dac_client hex] sends the Hex payload [hex] - to the coordinator of [dac_client]. If the [threshold] value is specified, - then the command will wait for a [Certificate] with an amount of - signatures greater or equal to [threshold], before returning. Otherwise, - the [Root_hash] of the payload is returned. *) -val send_payload : +(** [send_hex_payload ?hooks ?threshold dac_client hex] sends the Hex + payload [hex] to the coordinator of [dac_client]. If the [threshold] value + is specified, the command will wait for a [Certificate] with an + amount of signatures greater or equal to [threshold], before returning. + Otherwise, the [Root_hash] of the payload is returned. *) +val send_hex_payload : ?hooks:Process_hooks.t -> ?threshold:int -> t -> Hex.t -> output Lwt.t +(** [send_payload_from_file ?hooks ?threshold dac_client filename] reads the + payload content from [file] and sends it to the coordinator of + [dac_client]. If the [threshold] value is specified, then the command will + wait for a [Certificate] with an amount of signatures greater or equal to + [threshold], before returning. Otherwise, the [Root_hash] of the payload is + returned. *) +val send_payload_from_file : + ?hooks:Process_hooks.t -> ?threshold:int -> t -> string -> output Lwt.t + (** [get_certificate ?hooks dac_client root_hash] returns the certificate available to the coordinator of [dac_client] for [root_hash], if any. Otherwise, [None] is returned. *) diff --git a/tezt/tests/dac.ml b/tezt/tests/dac.ml index 93bd8b66acc5ed3697520327779220ce943a4cbb..1d78e4bcaffa6fb482dae90bad604c696de8659b 100644 --- a/tezt/tests/dac.ml +++ b/tezt/tests/dac.ml @@ -1404,7 +1404,7 @@ module Full_infrastructure = struct "Raw certificate does not match the expected one: Actual = %L <> %R \ = Expected") - let test_client + let test_client ~send_payload_from_file Scenarios. { coordinator_node; @@ -1474,10 +1474,18 @@ module Full_infrastructure = struct (* 2. Dac client posts a preimage to coordinator, and waits for all committee members to sign. *) let* client_sends_payload_output = - Dac_client.send_payload - coordinator_client - (Hex.of_string payload) - ~threshold:(List.length committee_members) + if send_payload_from_file then + let filename = Temp.file "dac_payload" in + let () = write_file filename ~contents:payload in + Dac_client.send_payload_from_file + coordinator_client + filename + ~threshold:(List.length committee_members) + else + Dac_client.send_hex_payload + coordinator_client + (Hex.of_string payload) + ~threshold:(List.length committee_members) in let last_certificate_update = match client_sends_payload_output with @@ -2580,8 +2588,16 @@ let register ~protocols = ~observers:0 ~committee_size:2 ~tags:["dac"; "dac_node"] - "test client commands" - Full_infrastructure.test_client + "test client commands (hex payload from CLI)" + (Full_infrastructure.test_client ~send_payload_from_file:false) + protocols ; + scenario_with_full_dac_infrastructure + ~__FILE__ + ~observers:0 + ~committee_size:2 + ~tags:["dac"; "dac_node"] + "test client commands (binary payload from file)" + (Full_infrastructure.test_client ~send_payload_from_file:true) protocols ; Tx_kernel_e2e.test_tx_kernel_e2e_with_dac_observer_synced_with_dac protocols ; Tx_kernel_e2e.test_tx_kernel_e2e_with_dac_observer_missing_pages protocols