From dba4b58fce1e929192265e72f188082c06e4356e Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Mon, 28 Jan 2019 17:12:58 -0500 Subject: [PATCH 1/4] Add support for test-chain-related APDUs --- src/bin_client/main_client.ml | 4 +- src/bin_signer/main_signer.ml | 2 +- src/lib_signer_backends/dune | 2 + src/lib_signer_backends/ledger.ml | 145 +++++++++++++++--- src/lib_signer_backends/ledger.mli | 4 +- .../tezos-signer-backends.opam | 1 + .../src/ledgerwallet_tezos.ml | 41 +++++ .../src/ledgerwallet_tezos.mli | 35 ++++- 8 files changed, 206 insertions(+), 28 deletions(-) diff --git a/src/bin_client/main_client.ml b/src/bin_client/main_client.ml index 43b61b543891..e4d687962b76 100644 --- a/src/bin_client/main_client.ml +++ b/src/bin_client/main_client.ml @@ -127,11 +127,11 @@ let select_commands ctxt { block ; protocol } = check_network ctxt >>= fun network -> get_commands_for_version ctxt network block protocol >>|? fun (_, commands_for_version) -> Client_rpc_commands.commands @ + Tezos_signer_backends.Ledger.commands () @ List.map (Clic.map_command (fun (o : Client_context.full) -> (o :> Client_context.io_wallet))) - (Tezos_signer_backends.Ledger.commands () @ - Client_keys_commands.commands network) @ + (Client_keys_commands.commands network) @ Client_helpers_commands.commands () @ commands_for_version diff --git a/src/bin_signer/main_signer.ml b/src/bin_signer/main_signer.ml index 5bb62c4afe6b..109698ad49fd 100644 --- a/src/bin_signer/main_signer.ml +++ b/src/bin_signer/main_signer.ml @@ -96,7 +96,7 @@ let high_watermark_switch = let commands base_dir require_auth = Client_keys_commands.commands None @ - Tezos_signer_backends.Ledger.commands () @ + (* Tezos_signer_backends.Ledger.commands () @ *) [ command ~group ~desc: "Launch a signer daemon over a TCP socket." (args4 diff --git a/src/lib_signer_backends/dune b/src/lib_signer_backends/dune index ecc819e13119..7817f02fe951 100644 --- a/src/lib_signer_backends/dune +++ b/src/lib_signer_backends/dune @@ -6,6 +6,7 @@ tezos-client-base tezos-rpc-http tezos-signer-services + tezos-shell-services pbkdf bip39 ledgerwallet-tezos) @@ -13,6 +14,7 @@ -open Tezos_stdlib_unix -open Tezos_client_base -open Tezos_signer_services + -open Tezos_shell_services -open Tezos_rpc_http))) (alias diff --git a/src/lib_signer_backends/ledger.ml b/src/lib_signer_backends/ledger.ml index 4d5fc9467738..81433ad5b78e 100644 --- a/src/lib_signer_backends/ledger.ml +++ b/src/lib_signer_backends/ledger.ml @@ -180,19 +180,23 @@ let wrap_ledger_cmd f = | Ok v -> return v -let get_public_key - ?(authorize_baking=false) +let public_key_returning_instruction which ?(prompt=false) ledger curve path = let path = tezos_root @ path in - begin match authorize_baking with - | false -> wrap_ledger_cmd begin fun pp -> + begin match which with + | `Get_public_key -> wrap_ledger_cmd begin fun pp -> Ledgerwallet_tezos.get_public_key ~prompt ~pp ledger curve path end - | true -> + | `Authorize_baking -> wrap_ledger_cmd begin fun pp -> Ledgerwallet_tezos.authorize_baking ~pp ledger curve path end + | `Setup (main_chain_id, main_hwm, test_hwm) -> + wrap_ledger_cmd begin fun pp -> + Ledgerwallet_tezos.setup_baking ~pp ledger curve path + ~main_chain_id ~main_hwm ~test_hwm + end end >>|? fun pk -> let pk = Cstruct.to_bigarray pk in match curve with @@ -218,6 +222,8 @@ let get_public_key let _nb_written = write_key ~compress:true (MBytes.sub buf 1 pklen) pk in Data_encoding.Binary.of_bytes_exn Signature.Public_key.encoding buf +let get_public_key = public_key_returning_instruction `Get_public_key + module Ledger = struct type t = { device_info : Hidapi.device_info ; @@ -491,7 +497,7 @@ let commands = ~desc: "List supported Ledger Nano S devices connected." no_options (fixed [ "list" ; "connected" ; "ledgers" ]) - (fun () (cctxt : Client_context.io_wallet) -> + (fun () (cctxt : Client_context.full) -> find_ledgers () >>=? function | [] -> cctxt#message "No device found." >>= fun () -> @@ -537,7 +543,7 @@ let commands = (prefixes [ "show" ; "ledger" ] @@ Client_keys.sk_uri_param @@ stop) - (fun test_sign sk_uri (cctxt : Client_context.io_wallet) -> + (fun test_sign sk_uri (cctxt : Client_context.full) -> neuterize sk_uri >>=? fun pk_uri -> id_of_pk_uri pk_uri >>=? fun id -> find_ledgers ~id () >>=? function @@ -605,7 +611,7 @@ let commands = (prefixes [ "get" ; "ledger" ; "authorized" ; "path" ; "for" ] @@ Public_key.alias_param @@ stop) - (fun () (name, (pk_uri, _)) (cctxt : Client_context.io_wallet) -> + (fun () (name, (pk_uri, _)) (cctxt : Client_context.full) -> id_of_pk_uri pk_uri >>=? fun root_id -> with_ledger root_id begin fun h _version _of_curve _to_curve -> wrap_ledger_cmd begin fun pp -> @@ -624,17 +630,19 @@ let commands = end) ; Clic.command ~group - ~desc: "Authorize a Ledger to bake for a key" + ~desc: "Authorize a Ledger to bake for a key (deprecated, \ + use `setup ledger ...` with recent versions of the Baking app)" no_options (prefixes [ "authorize" ; "ledger" ; "to" ; "bake" ; "for" ] @@ Public_key.alias_param @@ stop) - (fun () (_, (pk_uri, _)) (cctxt : Client_context.io_wallet) -> + (fun () (_, (pk_uri, _)) (cctxt : Client_context.full) -> id_of_pk_uri pk_uri >>=? fun root_id -> with_ledger root_id begin fun h _version _of_curve _of_pkh -> let path = path_of_pk_uri pk_uri in curve_of_id root_id >>=? fun curve -> - get_public_key ~authorize_baking:true h curve path >>=? fun pk -> + public_key_returning_instruction `Authorize_baking h curve path + >>=? fun pk -> let pkh = Signature.Public_key.hash pk in cctxt#message "@[Authorized baking for address: %a@,\ @@ -644,26 +652,125 @@ let commands = return_unit end) ; + Clic.command ~group + ~desc: "Setup a Ledger to bake for a key" + (let hwm_arg kind = + let doc = + Printf.sprintf + "Use as %s chain high watermark instead of asking the ledger." + kind in + let long = kind ^ "-hwm" in + default_arg ~doc ~long ~placeholder:"HWM" + ~default:"ASK-LEDGER" + (parameter + (fun _ -> function + | "ASK-LEDGER" -> return None + | s -> + try return (Some (Int32.of_string s)) with _ -> + failwith "Parameter %S should be a 32-bits integer" s)) + in + args3 + (default_arg + ~doc:"Use as main chain-id instead of asking the node." + ~long:"main-chain-id" ~placeholder:"ID" + ~default:"ASK-NODE" + (parameter + (fun _ -> function + | "ASK-NODE" -> return `Ask_node + | s -> + try return (`Int32 (Int32.of_string s)) + with _ -> + (try return (`Chain_id (Chain_id.of_b58check_exn s)) + with _ -> + failwith "Parameter %S should be a 32-bits integer \ + or a Base58 chain-id" s)))) + (hwm_arg "main") (hwm_arg "test")) + (prefixes [ "setup" ; "ledger" ; "to" ; "bake" ; "for" ] + @@ Public_key.alias_param + @@ stop) + (fun (chain_id_opt, main_hwm_opt, test_hwm_opt) + (_, (pk_uri, _)) (cctxt : Client_context.full) -> + let chain_id_of_int32 i32 = + let open Int32 in + let byte n = + logand 0xFFl (shift_right i32 (n * 8)) + |> Int32.to_int |> char_of_int in + Chain_id.of_string_exn + (Stringext.of_array (Array.init 4 (fun i -> byte (3 - i)))) in + begin match chain_id_opt with + | `Ask_node -> + Chain_services.chain_id cctxt () + | `Int32 s -> return (chain_id_of_int32 s) + | `Chain_id chid -> return chid + end + >>=? fun main_chain_id -> + id_of_pk_uri pk_uri >>=? fun root_id -> + with_ledger root_id begin fun h _version _of_curve _of_pkh -> + let path = path_of_pk_uri pk_uri in + curve_of_id root_id >>=? fun curve -> + wrap_ledger_cmd begin fun pp -> + Ledgerwallet_tezos.get_all_high_watermarks ~pp h + end + >>=? fun (`Main_hwm current_mh, `Test_hwm current_th, `Chain_id current_ci) -> + let main_hwm = Option.unopt main_hwm_opt ~default:current_mh in + let test_hwm = Option.unopt test_hwm_opt ~default:current_th in + cctxt#message "Setting up the ledger:@.\ + * Main chain ID: %a -> %a@.\ + * Main chain High Watermark: %ld -> %ld@.\ + * Test chain High Watermark: %ld -> %ld" + Chain_id.pp (Chain_id.of_string_exn current_ci) + Chain_id.pp main_chain_id + current_mh main_hwm + current_th test_hwm + >>= fun () -> + public_key_returning_instruction + (`Setup (Chain_id.to_string main_chain_id, main_hwm, test_hwm)) + h curve path + >>=? fun pk -> + let pkh = Signature.Public_key.hash pk in + cctxt#message + "@[Authorized baking for address: %a@,\ + Corresponding full public key: %a@]" + Signature.Public_key_hash.pp pkh + Signature.Public_key.pp pk >>= fun () -> + return_unit + end) ; + Clic.command ~group ~desc: "Get high water mark of a Ledger" - no_options + (args1 (switch ~doc:"Use the (deprecated) Ledger instructions \ + (for older versions of the Baking app)" + ~long:"use-legacy-instructions" ())) (prefixes [ "get" ; "ledger" ; "high" ; "watermark" ; "for" ] @@ Client_keys.sk_uri_param @@ stop) - (fun () sk_uri (cctxt : Client_context.io_wallet) -> + (fun legacy_apdu sk_uri (cctxt : Client_context.full) -> id_of_sk_uri sk_uri >>=? fun id -> with_ledger id begin fun h version _ _ -> match version.app_class with | Tezos -> - failwith "Fatal: this operation is only valid with TezBake" - | TezBake -> + failwith "Fatal: this operation is only valid with the \ + Tezos Baking application" + | TezBake when legacy_apdu -> wrap_ledger_cmd begin fun pp -> Ledgerwallet_tezos.get_high_watermark ~pp h - end >>=? fun hwm -> - cctxt#message - "@[%a has high water mark: %ld@]" + end + >>=? fun hwm -> + cctxt#message "The high water mark for@ %a@ is %ld." pp_id id hwm >>= fun () -> return_unit + | TezBake -> + wrap_ledger_cmd begin fun pp -> + Ledgerwallet_tezos.get_all_high_watermarks ~pp h + end + >>=? fun (`Main_hwm mh, `Test_hwm th, `Chain_id ci) -> + cctxt#message + "The high water mark values for@ %a@ are\ + @ %ld for the main-chain@ (%a)@ \ + and@ %ld for the test-chain." + pp_id id mh Chain_id.pp Chain_id.(of_string_exn ci) th + >>= fun () -> + return_unit end ) ; @@ -680,7 +787,7 @@ let commands = try return (Int32.of_string s) with _ -> failwith "%s is not an int32 value" s))) @@ stop) - (fun () sk_uri hwm (cctxt : Client_context.io_wallet) -> + (fun () sk_uri hwm (cctxt : Client_context.full) -> id_of_sk_uri sk_uri >>=? fun id -> with_ledger id begin fun h version _ _ -> match version.app_class with diff --git a/src/lib_signer_backends/ledger.mli b/src/lib_signer_backends/ledger.mli index 86c608634836..aa4c749f330f 100644 --- a/src/lib_signer_backends/ledger.mli +++ b/src/lib_signer_backends/ledger.mli @@ -37,4 +37,6 @@ end include Client_keys.SIGNER -val commands : unit -> Client_context.io_wallet Clic.command list + + +val commands : unit -> Client_context.full Clic.command list diff --git a/src/lib_signer_backends/tezos-signer-backends.opam b/src/lib_signer_backends/tezos-signer-backends.opam index 05fa561c1a89..96e885218ab5 100644 --- a/src/lib_signer_backends/tezos-signer-backends.opam +++ b/src/lib_signer_backends/tezos-signer-backends.opam @@ -13,6 +13,7 @@ depends: [ "tezos-client-base" "tezos-rpc-http" "tezos-signer-services" + "tezos-shell-services" "pbkdf" "bip39" "ledgerwallet-tezos" diff --git a/vendors/ocaml-ledger-wallet/src/ledgerwallet_tezos.ml b/vendors/ocaml-ledger-wallet/src/ledgerwallet_tezos.ml index 61efe165e743..6868bef2994e 100644 --- a/vendors/ocaml-ledger-wallet/src/ledgerwallet_tezos.ml +++ b/vendors/ocaml-ledger-wallet/src/ledgerwallet_tezos.ml @@ -64,6 +64,8 @@ type ins = | Reset_high_watermark | Query_high_watermark | Get_authorized_key + | Setup + | Query_all_high_watermarks let int_of_ins = function | Version -> 0x00 @@ -76,6 +78,8 @@ let int_of_ins = function | Query_high_watermark -> 0x08 | Git_commit -> 0x09 | Get_authorized_key -> 0x07 + | Setup -> 0x0A + | Query_all_high_watermarks -> 0x0B type curve = | Ed25519 @@ -154,11 +158,48 @@ let get_public_key ?(prompt=true) = let authorize_baking = get_public_key_like Authorize_baking +let setup_baking ?pp ?buf h ~main_chain_id ~main_hwm ~test_hwm curve path = + let nb_derivations = List.length path in + if nb_derivations > 10 then + invalid_arg "Ledgerwallet_tezos.setup: max 10 derivations" ; + let lc = + (* [ chain-id | main-hwm | test-hwm | derivations-path ] *) + (* derivations-path = [ length | paths ] *) + (3 * 4) + 1 + (4 * nb_derivations) in + let data_init = Cstruct.create lc in + (* If the size of chain-ids changes, then all assumptions of this + binary format are broken (the ledger expects an int32). *) + assert (String.length main_chain_id = 4) ; + for ith = 0 to 3 do + Cstruct.set_uint8 data_init ith (int_of_char main_chain_id.[ith]) ; + done ; + Cstruct.BE.set_uint32 data_init 4 main_hwm ; + Cstruct.BE.set_uint32 data_init 8 test_hwm ; + Cstruct.set_uint8 data_init 12 nb_derivations ; + let (_ : Cstruct.t) = + let data = Cstruct.shift data_init (12 + 1) in + write_path data path in + let msg = "setup" in + let apdu = + Apdu.create + ~p2:(int_of_curve curve) ~lc ~data:data_init (wrap_ins Setup) in + Transport.apdu ~msg ?pp ?buf h apdu >>| fun addr -> + let keylen = Cstruct.get_uint8 addr 0 in + Cstruct.sub addr 1 keylen + let get_high_watermark ?pp ?buf h = let apdu = Apdu.create (wrap_ins Query_high_watermark) in Transport.apdu ~msg:"get_high_watermark" ?pp ?buf h apdu >>| fun hwm -> Cstruct.BE.get_uint32 hwm 0 +let get_all_high_watermarks ?pp ?buf h = + let apdu = Apdu.create (wrap_ins Query_all_high_watermarks) in + Transport.apdu ~msg:"get_high_watermark" ?pp ?buf h apdu >>| fun tuple -> + let main_hwm = Cstruct.BE.get_uint32 tuple 0 in + let test_hwm = Cstruct.BE.get_uint32 tuple 4 in + let chain_id = Cstruct.copy tuple 8 4 in + (`Main_hwm main_hwm, `Test_hwm test_hwm, `Chain_id chain_id) + let set_high_watermark ?pp ?buf h hwm = let data = Cstruct.create 4 in Cstruct.BE.set_uint32 data 0 hwm ; diff --git a/vendors/ocaml-ledger-wallet/src/ledgerwallet_tezos.mli b/vendors/ocaml-ledger-wallet/src/ledgerwallet_tezos.mli index 579121336e34..2e2eefff300d 100644 --- a/vendors/ocaml-ledger-wallet/src/ledgerwallet_tezos.mli +++ b/vendors/ocaml-ledger-wallet/src/ledgerwallet_tezos.mli @@ -65,20 +65,45 @@ val authorize_baking : (** [authorize_baking ?pp ?buf ?prompt ledger curve path] is like [get_public_key] with [prompt = true], but only works with the baking Ledger application and serves to indicate that the key from - [curve] at [path] is allowed to bake. *) + [curve] at [path] is allowed to bake. + + This is deprecated as it ignores test-chains, see {!setup_baking}. *) + +val setup_baking : + ?pp:Format.formatter -> ?buf:Cstruct.t -> Hidapi.t -> + main_chain_id: string -> main_hwm:int32 -> test_hwm:int32 -> + curve -> int32 list -> (Cstruct.t, Transport.error) result +(** [setup_baking ?pp ?buf ?prompt ledger ~main_chain_id ~main_hwm ~test_hwm curve path] + sets up the Ledger's Baking application: it informs + the device of the ID of the main chain (should be of length [4]), + sets the high watermarks for the main and test chains, {i and} + indicates that the key at the given [curve/path] is authorized for + baking. *) val get_high_watermark : ?pp:Format.formatter -> ?buf:Cstruct.t -> Hidapi.t -> (int32, Transport.error) result (** [get_high_watermark ?pp ?buf ledger] is the current value of the - high water mark on [ledger]. This works with the baking app - only. *) + high water mark for the main-chain on [ledger]. This works with + the baking app only. See {!get_all_high_watermarks} for a more + complete query. *) + +val get_all_high_watermarks : + ?pp:Format.formatter -> + ?buf:Cstruct.t -> + Hidapi.t -> + ([ `Main_hwm of int32 ] * [ `Test_hwm of int32 ] * [ `Chain_id of string ], + Transport.error) result +(** Query the high water marks for the main and test chains, as well as the ID + of the main-chain (string of length 4) recorded by the Ledger Baking app. *) val set_high_watermark : ?pp:Format.formatter -> ?buf:Cstruct.t -> Hidapi.t -> int32 -> (unit, Transport.error) result -(** [get_high_watermark ?pp ?buf ledger hwm] reset the high water - mark on [ledger] to [hwm]. This works with the baking app only. *) +(** [set_high_watermark ?pp ?buf ledger hwm] reset the high water + mark on [ledger] to [hwm] for the main-chain. + This works with the baking app only. Use {!setup_baking} to be able to also + reset all the test-chain water mark. *) val sign : ?pp:Format.formatter -> -- GitLab From ab6e67abc64249e22d8c8ab818c9266a75957be5 Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Wed, 30 Jan 2019 17:58:21 -0500 Subject: [PATCH 2/4] Improve UX of ledger commands --- src/lib_signer_backends/ledger.ml | 85 +++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/src/lib_signer_backends/ledger.ml b/src/lib_signer_backends/ledger.ml index 81433ad5b78e..85d683115d4a 100644 --- a/src/lib_signer_backends/ledger.ml +++ b/src/lib_signer_backends/ledger.ml @@ -638,7 +638,28 @@ let commands = @@ stop) (fun () (_, (pk_uri, _)) (cctxt : Client_context.full) -> id_of_pk_uri pk_uri >>=? fun root_id -> - with_ledger root_id begin fun h _version _of_curve _of_pkh -> + with_ledger root_id begin fun h version _of_curve _of_pkh -> + begin match version with + | { Ledgerwallet_tezos.Version.app_class = Tezos ; _ } -> + failwith "This command (`authorize ledger ...`) only \ + works with the Tezos Baking app" + | { Ledgerwallet_tezos.Version.app_class = TezBake ; + major ; _ } when major >= 2 -> + failwith + "This command (`authorize ledger ...`) is@ \ + not compatible with@ this version of the Ledger@ \ + Baking app (%a >= 2.0.0),@ please use the command@ \ + `setup ledger to bake for ...`@ from now on." + Ledgerwallet_tezos.Version.pp version + | _ -> + cctxt#message + "This Ledger Baking app is outdated (%a)@ running@ \ + in backwards@ compatibility mode." + Ledgerwallet_tezos.Version.pp version + >>= fun () -> + return_unit + end + >>=? fun () -> let path = path_of_pk_uri pk_uri in curve_of_id root_id >>=? fun curve -> public_key_returning_instruction `Authorize_baking h curve path @@ -690,22 +711,39 @@ let commands = @@ stop) (fun (chain_id_opt, main_hwm_opt, test_hwm_opt) (_, (pk_uri, _)) (cctxt : Client_context.full) -> - let chain_id_of_int32 i32 = - let open Int32 in - let byte n = - logand 0xFFl (shift_right i32 (n * 8)) - |> Int32.to_int |> char_of_int in - Chain_id.of_string_exn - (Stringext.of_array (Array.init 4 (fun i -> byte (3 - i)))) in - begin match chain_id_opt with - | `Ask_node -> - Chain_services.chain_id cctxt () - | `Int32 s -> return (chain_id_of_int32 s) - | `Chain_id chid -> return chid - end - >>=? fun main_chain_id -> id_of_pk_uri pk_uri >>=? fun root_id -> - with_ledger root_id begin fun h _version _of_curve _of_pkh -> + with_ledger root_id begin fun h version _of_curve _of_pkh -> + begin + let open Ledgerwallet_tezos.Version in + match version with + | { app_class = Tezos ; _ } -> + failwith "This command (`setup ledger ...`) only \ + works with the Tezos Baking app" + | { app_class = TezBake ; + major ; _ } when major < 2 -> + failwith + "This command (`setup ledger ...`)@ is not@ compatible@ with \ + this version@ of the Ledger Baking app@ (%a < 2.0.0),@ \ + please upgrade@ your ledger@ or use the command@ \ + `authorize ledger to bake for ...`" + pp version + | _ -> return_unit + end + >>=? fun () -> + let chain_id_of_int32 i32 = + let open Int32 in + let byte n = + logand 0xFFl (shift_right i32 (n * 8)) + |> Int32.to_int |> char_of_int in + Chain_id.of_string_exn + (Stringext.of_array (Array.init 4 (fun i -> byte (3 - i)))) in + begin match chain_id_opt with + | `Ask_node -> + Chain_services.chain_id cctxt () + | `Int32 s -> return (chain_id_of_int32 s) + | `Chain_id chid -> return chid + end + >>=? fun main_chain_id -> let path = path_of_pk_uri pk_uri in curve_of_id root_id >>=? fun curve -> wrap_ledger_cmd begin fun pp -> @@ -738,20 +776,20 @@ let commands = Clic.command ~group ~desc: "Get high water mark of a Ledger" - (args1 (switch ~doc:"Use the (deprecated) Ledger instructions \ - (for older versions of the Baking app)" - ~long:"use-legacy-instructions" ())) + (args1 (switch ~doc:"Prevent the fallback to the (deprecated) Ledger \ + instructions (for 1.x.y versions of the Baking app)" + ~long:"no-legacy-instructions" ())) (prefixes [ "get" ; "ledger" ; "high" ; "watermark" ; "for" ] @@ Client_keys.sk_uri_param @@ stop) - (fun legacy_apdu sk_uri (cctxt : Client_context.full) -> + (fun no_legacy_apdu sk_uri (cctxt : Client_context.full) -> id_of_sk_uri sk_uri >>=? fun id -> with_ledger id begin fun h version _ _ -> match version.app_class with | Tezos -> failwith "Fatal: this operation is only valid with the \ Tezos Baking application" - | TezBake when legacy_apdu -> + | TezBake when not no_legacy_apdu && version.major < 2 -> wrap_ledger_cmd begin fun pp -> Ledgerwallet_tezos.get_high_watermark ~pp h end @@ -759,6 +797,11 @@ let commands = cctxt#message "The high water mark for@ %a@ is %ld." pp_id id hwm >>= fun () -> return_unit + | TezBake when no_legacy_apdu && version.major < 2 -> + failwith + "Cannot get the high water mark with@ \ + `--no-legacy-instructions` and version %a" + Ledgerwallet_tezos.Version.pp version | TezBake -> wrap_ledger_cmd begin fun pp -> Ledgerwallet_tezos.get_all_high_watermarks ~pp h -- GitLab From acad6cce1916ec3efde8c5fab5c607e5ca191c8b Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Tue, 12 Feb 2019 14:03:44 -0500 Subject: [PATCH 3/4] =?UTF-8?q?Fix=20client=20display=20for=20=E2=80=9Cuns?= =?UTF-8?q?pecified=E2=80=9D=20chain-id?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib_signer_backends/ledger.ml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/lib_signer_backends/ledger.ml b/src/lib_signer_backends/ledger.ml index 85d683115d4a..31d34ca8ae44 100644 --- a/src/lib_signer_backends/ledger.ml +++ b/src/lib_signer_backends/ledger.ml @@ -441,6 +441,12 @@ let curve_of_id = function | Pkh pkh -> return (curve_of_pkh pkh) | Animals (a, curve_opt) -> unopt_curve a curve_opt +(* The Ledger uses a special value 0x00000000 for the “any” chain-id: *) +let pp_ledger_chain_id fmt s = + match s with + | "\x00\x00\x00\x00" -> Format.fprintf fmt "'Unspecified'" + | other -> Format.fprintf fmt "%a" Chain_id.pp (Chain_id.of_string_exn other) + let sign ?watermark sk_uri msg = id_of_sk_uri sk_uri >>=? fun id -> with_ledger id begin fun ledger { major; minor; patch; _ } _of_curve _of_pkh -> @@ -756,7 +762,7 @@ let commands = * Main chain ID: %a -> %a@.\ * Main chain High Watermark: %ld -> %ld@.\ * Test chain High Watermark: %ld -> %ld" - Chain_id.pp (Chain_id.of_string_exn current_ci) + pp_ledger_chain_id current_ci Chain_id.pp main_chain_id current_mh main_hwm current_th test_hwm @@ -811,7 +817,7 @@ let commands = "The high water mark values for@ %a@ are\ @ %ld for the main-chain@ (%a)@ \ and@ %ld for the test-chain." - pp_id id mh Chain_id.pp Chain_id.(of_string_exn ci) th + pp_id id mh pp_ledger_chain_id ci th >>= fun () -> return_unit end -- GitLab From fdbcf07acdd3d63a20260c9a599f41d72d5cf2d0 Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Wed, 20 Feb 2019 16:24:52 -0500 Subject: [PATCH 4/4] Fix use of ledger in `main_signer` --- src/bin_signer/main_signer.ml | 289 +++++++++++++++++----------------- 1 file changed, 147 insertions(+), 142 deletions(-) diff --git a/src/bin_signer/main_signer.ml b/src/bin_signer/main_signer.ml index 109698ad49fd..8725aa83f6a0 100644 --- a/src/bin_signer/main_signer.ml +++ b/src/bin_signer/main_signer.ml @@ -94,143 +94,146 @@ let high_watermark_switch = ~long: "check-high-watermark" () -let commands base_dir require_auth = - Client_keys_commands.commands None @ - (* Tezos_signer_backends.Ledger.commands () @ *) - [ command ~group - ~desc: "Launch a signer daemon over a TCP socket." - (args4 - magic_bytes_arg - high_watermark_switch - (default_arg - ~doc: "listening address or host name" - ~short: 'a' - ~long: "address" - ~placeholder: "host|address" - ~default: default_tcp_host - (parameter (fun _ s -> return s))) - (default_arg - ~doc: "listening TCP port or service name" - ~short: 'p' - ~long: "port" - ~placeholder: "port number" - ~default: default_tcp_port - (parameter (fun _ s -> return s)))) - (prefixes [ "launch" ; "socket" ; "signer" ] @@ stop) - (fun (magic_bytes, check_high_watermark, host, port) cctxt -> - Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> - Socket_daemon.run - cctxt (Tcp (host, port, [AI_SOCKTYPE SOCK_STREAM])) - ?magic_bytes ~check_high_watermark ~require_auth >>=? fun _ -> - return_unit) ; - command ~group - ~desc: "Launch a signer daemon over a local Unix socket." - (args3 - magic_bytes_arg - high_watermark_switch - (default_arg - ~doc: "path to the local socket file" - ~short: 's' - ~long: "socket" - ~placeholder: "path" - ~default: (Filename.concat base_dir "socket") - (parameter (fun _ s -> return s)))) - (prefixes [ "launch" ; "local" ; "signer" ] @@ stop) - (fun (magic_bytes, check_high_watermark, path) cctxt -> - Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> - Socket_daemon.run - cctxt (Unix path) ?magic_bytes ~check_high_watermark ~require_auth >>=? fun _ -> - return_unit) ; - command ~group - ~desc: "Launch a signer daemon over HTTP." - (args4 - magic_bytes_arg - high_watermark_switch - (default_arg - ~doc: "listening address or host name" - ~short: 'a' - ~long: "address" - ~placeholder: "host|address" - ~default: default_http_host - (parameter (fun _ s -> return s))) - (default_arg - ~doc: "listening HTTP port" - ~short: 'p' - ~long: "port" - ~placeholder: "port number" - ~default: default_http_port - (parameter - (fun _ x -> - try return (int_of_string x) - with Failure _ -> failwith "Invalid port %s" x)))) - (prefixes [ "launch" ; "http" ; "signer" ] @@ stop) - (fun (magic_bytes, check_high_watermark, host, port) cctxt -> - Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> - Http_daemon.run_http cctxt ~host ~port ?magic_bytes ~check_high_watermark ~require_auth) ; - command ~group - ~desc: "Launch a signer daemon over HTTPS." - (args4 - magic_bytes_arg - high_watermark_switch - (default_arg - ~doc: "listening address or host name" - ~short: 'a' - ~long: "address" - ~placeholder: "host|address" - ~default: default_https_host - (parameter (fun _ s -> return s))) - (default_arg - ~doc: "listening HTTPS port" - ~short: 'p' - ~long: "port" - ~placeholder: "port number" - ~default: default_https_port - (parameter - (fun _ x -> - try return (int_of_string x) - with Failure _ -> failwith "Invalid port %s" x)))) - (prefixes [ "launch" ; "https" ; "signer" ] @@ - param - ~name:"cert" - ~desc: "path to th TLS certificate" - (parameter (fun _ s -> - if not (Sys.file_exists s) then - failwith "No such TLS certificate file %s" s - else - return s)) @@ - param - ~name:"key" - ~desc: "path to th TLS key" - (parameter (fun _ s -> - if not (Sys.file_exists s) then - failwith "No such TLS key file %s" s - else - return s)) @@ stop) - (fun (magic_bytes, check_high_watermark, host, port) cert key cctxt -> - Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> - Http_daemon.run_https cctxt ~host ~port ~cert ~key ?magic_bytes ~check_high_watermark ~require_auth) ; - command ~group - ~desc: "Authorize a given public key to perform signing requests." - (args1 - (arg - ~doc: "an optional name for the key (defaults to the hash)" - ~short: 'N' - ~long: "name" - ~placeholder: "name" - (parameter (fun _ s -> return s)))) - (prefixes [ "add" ; "authorized" ; "key" ] @@ - param - ~name:"pk" - ~desc: "full public key (Base58 encoded)" - (parameter (fun _ s -> Lwt.return (Signature.Public_key.of_b58check s))) @@ - stop) - (fun name key cctxt -> - let pkh = Signature.Public_key.hash key in - let name = match name with - | Some name -> name - | None -> Signature.Public_key_hash.to_b58check pkh in - Handler.Authorized_key.add ~force:false cctxt name key) - ] +let commands base_dir require_auth : Client_context.full command list = + Tezos_signer_backends.Ledger.commands () @ + List.map + (Clic.map_command + (fun (o : Client_context.full) -> (o :> Client_context.io_wallet))) + (Client_keys_commands.commands None @ + [ command ~group + ~desc: "Launch a signer daemon over a TCP socket." + (args4 + magic_bytes_arg + high_watermark_switch + (default_arg + ~doc: "listening address or host name" + ~short: 'a' + ~long: "address" + ~placeholder: "host|address" + ~default: default_tcp_host + (parameter (fun _ s -> return s))) + (default_arg + ~doc: "listening TCP port or service name" + ~short: 'p' + ~long: "port" + ~placeholder: "port number" + ~default: default_tcp_port + (parameter (fun _ s -> return s)))) + (prefixes [ "launch" ; "socket" ; "signer" ] @@ stop) + (fun (magic_bytes, check_high_watermark, host, port) cctxt -> + Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> + Socket_daemon.run + cctxt (Tcp (host, port, [AI_SOCKTYPE SOCK_STREAM])) + ?magic_bytes ~check_high_watermark ~require_auth >>=? fun _ -> + return_unit) ; + command ~group + ~desc: "Launch a signer daemon over a local Unix socket." + (args3 + magic_bytes_arg + high_watermark_switch + (default_arg + ~doc: "path to the local socket file" + ~short: 's' + ~long: "socket" + ~placeholder: "path" + ~default: (Filename.concat base_dir "socket") + (parameter (fun _ s -> return s)))) + (prefixes [ "launch" ; "local" ; "signer" ] @@ stop) + (fun (magic_bytes, check_high_watermark, path) cctxt -> + Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> + Socket_daemon.run + cctxt (Unix path) ?magic_bytes ~check_high_watermark ~require_auth >>=? fun _ -> + return_unit) ; + command ~group + ~desc: "Launch a signer daemon over HTTP." + (args4 + magic_bytes_arg + high_watermark_switch + (default_arg + ~doc: "listening address or host name" + ~short: 'a' + ~long: "address" + ~placeholder: "host|address" + ~default: default_http_host + (parameter (fun _ s -> return s))) + (default_arg + ~doc: "listening HTTP port" + ~short: 'p' + ~long: "port" + ~placeholder: "port number" + ~default: default_http_port + (parameter + (fun _ x -> + try return (int_of_string x) + with Failure _ -> failwith "Invalid port %s" x)))) + (prefixes [ "launch" ; "http" ; "signer" ] @@ stop) + (fun (magic_bytes, check_high_watermark, host, port) cctxt -> + Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> + Http_daemon.run_http cctxt ~host ~port ?magic_bytes ~check_high_watermark ~require_auth) ; + command ~group + ~desc: "Launch a signer daemon over HTTPS." + (args4 + magic_bytes_arg + high_watermark_switch + (default_arg + ~doc: "listening address or host name" + ~short: 'a' + ~long: "address" + ~placeholder: "host|address" + ~default: default_https_host + (parameter (fun _ s -> return s))) + (default_arg + ~doc: "listening HTTPS port" + ~short: 'p' + ~long: "port" + ~placeholder: "port number" + ~default: default_https_port + (parameter + (fun _ x -> + try return (int_of_string x) + with Failure _ -> failwith "Invalid port %s" x)))) + (prefixes [ "launch" ; "https" ; "signer" ] @@ + param + ~name:"cert" + ~desc: "path to th TLS certificate" + (parameter (fun _ s -> + if not (Sys.file_exists s) then + failwith "No such TLS certificate file %s" s + else + return s)) @@ + param + ~name:"key" + ~desc: "path to th TLS key" + (parameter (fun _ s -> + if not (Sys.file_exists s) then + failwith "No such TLS key file %s" s + else + return s)) @@ stop) + (fun (magic_bytes, check_high_watermark, host, port) cert key cctxt -> + Tezos_signer_backends.Encrypted.decrypt_all cctxt >>=? fun () -> + Http_daemon.run_https cctxt ~host ~port ~cert ~key ?magic_bytes ~check_high_watermark ~require_auth) ; + command ~group + ~desc: "Authorize a given public key to perform signing requests." + (args1 + (arg + ~doc: "an optional name for the key (defaults to the hash)" + ~short: 'N' + ~long: "name" + ~placeholder: "name" + (parameter (fun _ s -> return s)))) + (prefixes [ "add" ; "authorized" ; "key" ] @@ + param + ~name:"pk" + ~desc: "full public key (Base58 encoded)" + (parameter (fun _ s -> Lwt.return (Signature.Public_key.of_b58check s))) @@ + stop) + (fun name key cctxt -> + let pkh = Signature.Public_key.hash key in + let name = match name with + | Some name -> name + | None -> Signature.Public_key_hash.to_b58check pkh in + Handler.Authorized_key.add ~force:false cctxt name key) + ]) let home = try Sys.getenv "HOME" with Not_found -> "/root" @@ -299,11 +302,13 @@ let main () = (global_options ()) () original_args >>=? fun ((base_dir, require_auth, password_filename), remaining) -> let base_dir = Option.unopt ~default:default_base_dir base_dir in - let cctxt = object - inherit Client_context_unix.unix_logger ~base_dir - inherit Client_context_unix.unix_prompter - inherit Client_context_unix.unix_wallet ~base_dir ~password_filename - end in + let cctxt = + new Client_context_unix.unix_full + ~block:Client_config.default_block + ~confirmations:None + ~password_filename + ~base_dir + ~rpc_config:RPC_client.default_config in Client_keys.register_signer (module Tezos_signer_backends.Encrypted.Make(struct let cctxt = new Client_context_unix.unix_prompter -- GitLab