From 304bb75d88d84f15ab5d2233492ec163ad10a2b2 Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Fri, 15 Mar 2019 11:08:36 -0400 Subject: [PATCH 01/10] Client: add `--force` to `submit proposals` --- .../client_proto_context_commands.ml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index e0149dedd5a3..b1f1e1693be4 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -656,7 +656,11 @@ let commands version () = end ; command ~group ~desc: "Submit protocol proposals" - no_options + (args1 + (switch + ~doc:"Do not fail when the checks that try to prevent the user \ + from shooting themselves in the foot do." + ~long:"force" ())) (prefixes [ "submit" ; "proposals" ; "for" ] @@ ContractAlias.destination_param ~name: "delegate" @@ -670,7 +674,7 @@ let commands version () = match Protocol_hash.of_b58check_opt x with | None -> Error_monad.failwith "Invalid proposal hash: '%s'" x | Some hash -> return hash)))) - begin fun () (_name, source) proposals (cctxt : Proto_alpha.full) -> + begin fun force (_name, source) proposals (cctxt : Proto_alpha.full) -> get_period_info ~chain:cctxt#chain ~block:cctxt#block cctxt >>=? fun info -> begin match info.current_period_kind with | Proposal -> return_unit @@ -700,6 +704,9 @@ let commands version () = check_proposals proposals >>=? fun all_valid -> begin if all_valid then cctxt#message "All proposals are valid" + else if force then + cctxt#message + "Some proposals are not valid, but `--force` was used" else cctxt#error "Submission failed because of invalid proposals" end >>= fun () -> -- GitLab From bed959b23cb180e16becef0ea2c17f30d2082975 Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Fri, 15 Mar 2019 12:16:40 -0400 Subject: [PATCH 02/10] Client: improve Too many proposals error message --- .../lib_client_commands/client_proto_context_commands.ml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index b1f1e1693be4..59650267bbd6 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -690,7 +690,8 @@ let commands version () = let n = List.length proposals in if n = 0 then cctxt#error "Empty proposal" else if n > Constants.fixed.max_proposals_per_delegate then - cctxt#error "Too many proposals" + cctxt#error "Too many proposals: %d > %d" + n Constants.fixed.max_proposals_per_delegate else fold_left_s (fun acc (p : Protocol_hash.t) -> if (List.mem p known_protos) || -- GitLab From a17b42214ce8d06f31a1d717be6e6f4205016cd0 Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Fri, 15 Mar 2019 12:17:01 -0400 Subject: [PATCH 03/10] Client: check for duplicate proposals --- .../client_proto_context_commands.ml | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index 59650267bbd6..71dbd3923708 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -693,15 +693,22 @@ let commands version () = cctxt#error "Too many proposals: %d > %d" n Constants.fixed.max_proposals_per_delegate else - fold_left_s (fun acc (p : Protocol_hash.t) -> - if (List.mem p known_protos) || - (Alpha_environment.Protocol_hash.Map.mem p known_proposals) - then return acc - else cctxt#message "Protocol %a is not a known proposal" - Protocol_hash.pp p >>= fun () -> - return false) - true proposals - in + begin match Base.List.find_a_dup ~compare proposals with + | Some dup -> + cctxt#error "There are duplicate proposals, e.g. %a" + Protocol_hash.pp dup + >>= fun () -> + return_false + | None -> + fold_left_s (fun acc (p : Protocol_hash.t) -> + if (List.mem p known_protos) || + (Alpha_environment.Protocol_hash.Map.mem p known_proposals) + then return acc + else cctxt#message "Protocol %a is not a known proposal" + Protocol_hash.pp p >>= fun () -> + return false) + true proposals + end in check_proposals proposals >>=? fun all_valid -> begin if all_valid then cctxt#message "All proposals are valid" -- GitLab From be46b7394987829c54f378ca1199a3df877db188 Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Fri, 15 Mar 2019 13:22:43 -0400 Subject: [PATCH 04/10] Client: improve display of proposal errors --- .../client_proto_context_commands.ml | 83 ++++++++++++++----- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index 71dbd3923708..563e88d349f1 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -682,33 +682,73 @@ let commands version () = end >>=? fun () -> Shell_services.Protocol.list cctxt >>=? fun known_protos -> get_proposals ~chain:cctxt#chain ~block:cctxt#block cctxt >>=? fun known_proposals -> + Alpha_services.Voting.listings cctxt (`Main, cctxt#block) >>=? fun listings -> + Client_proto_context.get_manager + cctxt ~chain:`Main ~block:cctxt#block + source >>=? fun (src_name, src_pkh, _src_pk, src_sk) -> (* for a proposal to be valid it must either a protocol that was already proposed by somebody else or a protocol known by the node, because the user is the first proposer and just injected it with tezos-admin-client *) let check_proposals proposals : bool tzresult Lwt.t = let n = List.length proposals in - if n = 0 then cctxt#error "Empty proposal" - else if n > Constants.fixed.max_proposals_per_delegate then - cctxt#error "Too many proposals: %d > %d" - n Constants.fixed.max_proposals_per_delegate + let errors = ref [] in + let error ppf = + Format.kasprintf (fun s -> errors := s :: !errors) ppf in + if n = 0 then error "Empty proposal list." ; + if n > Constants.fixed.max_proposals_per_delegate then + error "Too many proposals: %d > %d." + n Constants.fixed.max_proposals_per_delegate ; + begin match + Base.List.find_all_dups ~compare:Protocol_hash.compare proposals with + | [] -> () + | dups -> + error "There %s: %a." + (if List.length dups = 1 + then "is a duplicate proposal" + else "are duplicate proposals") + Format.( + pp_print_list + ~pp_sep:(fun ppf () -> pp_print_string ppf ", ") + Protocol_hash.pp) + dups + end ; + List.iter (fun (p : Protocol_hash.t) -> + if (List.mem p known_protos) || + (Alpha_environment.Protocol_hash.Map.mem p known_proposals) + then () + else + error "Protocol %a is not a known proposal." Protocol_hash.pp p + ) proposals ; + if not ( + List.exists + (fun (pkh, _) -> Signature.Public_key_hash.equal pkh src_pkh) + listings) + then + error "Public-key-hash `%a` from account `%s` does not appear to \ + have voting rights." + Signature.Public_key_hash.pp src_pkh + src_name ; + if !errors <> [] + then + cctxt#message "There %s with the submission:%t" + (if List.length !errors = 1 then "is an issue" else "are issues") + Format.(fun ppf -> + pp_print_cut ppf () ; + pp_open_vbox ppf 0 ; + List.iter (fun msg -> + pp_open_hovbox ppf 2 ; + pp_print_string ppf "* "; + pp_print_text ppf msg ; + pp_close_box ppf () ; + pp_print_cut ppf ()) + !errors ; + pp_close_box ppf ()) + >>= fun () -> + return_false else - begin match Base.List.find_a_dup ~compare proposals with - | Some dup -> - cctxt#error "There are duplicate proposals, e.g. %a" - Protocol_hash.pp dup - >>= fun () -> - return_false - | None -> - fold_left_s (fun acc (p : Protocol_hash.t) -> - if (List.mem p known_protos) || - (Alpha_environment.Protocol_hash.Map.mem p known_proposals) - then return acc - else cctxt#message "Protocol %a is not a known proposal" - Protocol_hash.pp p >>= fun () -> - return false) - true proposals - end in + return_true + in check_proposals proposals >>=? fun all_valid -> begin if all_valid then cctxt#message "All proposals are valid" @@ -718,9 +758,6 @@ let commands version () = else cctxt#error "Submission failed because of invalid proposals" end >>= fun () -> - Client_proto_context.get_manager - cctxt ~chain:cctxt#chain ~block:cctxt#block - source >>=? fun (_src_name, src_pkh, _src_pk, src_sk) -> submit_proposals cctxt ~chain:cctxt#chain ~block:cctxt#block ~src_sk src_pkh proposals >>=? fun _res -> return_unit -- GitLab From 6728bbb1ffdee485262892bbc93054d529c7bf1b Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Fri, 15 Mar 2019 14:28:21 -0400 Subject: [PATCH 05/10] Client: improve display of proposals (show voting) --- .../client_proto_context_commands.ml | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index 563e88d349f1..de95647dac1b 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -815,6 +815,7 @@ let commands version () = Proto_alpha.Alpha_context.Voting_period.kind_encoding info.current_period_kind) info.remaining >>= fun () -> + Shell_services.Protocol.list cctxt >>=? fun known_protos -> get_proposals ~chain:cctxt#chain ~block:cctxt#block cctxt >>=? fun props -> let ranks = Alpha_environment.Protocol_hash.Map.bindings props |> List.sort (fun (_,v1) (_,v2) -> Int32.(compare v2 v1)) in @@ -825,13 +826,17 @@ let commands version () = in match info.current_period_kind with | Proposal -> - (* TODO improve printing of proposals *) - let proposals_string = - if List.length ranks = 0 then " none" else - List.fold_left (fun acc (p,w) -> - Format.asprintf "%s\n%a %ld" acc Protocol_hash.pp p w) "" ranks - in - cctxt#answer "Current proposals:%s" proposals_string + cctxt#answer "Current proposals:%t" + Format.(fun ppf -> + pp_print_cut ppf () ; + pp_open_vbox ppf 0 ; + List.iter + (fun (p, w) -> + fprintf ppf "* %a %ld (%sknown by the node)@." + Protocol_hash.pp p w + (if (List.mem p known_protos) then "" else "not ")) + ranks ; + pp_close_box ppf () ) >>= fun () -> return_unit | Testing_vote | Promotion_vote -> print_proposal info.current_proposal >>= fun () -> -- GitLab From 58ee0418a8c8dabb65003abe91c75147e2d056cb Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Fri, 15 Mar 2019 14:29:02 -0400 Subject: [PATCH 06/10] Client: fix punctuation of `submit proposals` --- .../lib_client_commands/client_proto_context_commands.ml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index de95647dac1b..168d4025ee43 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -751,12 +751,12 @@ let commands version () = in check_proposals proposals >>=? fun all_valid -> begin if all_valid then - cctxt#message "All proposals are valid" + cctxt#message "All proposals are valid." else if force then cctxt#message - "Some proposals are not valid, but `--force` was used" + "Some proposals are not valid, but `--force` was used." else - cctxt#error "Submission failed because of invalid proposals" + cctxt#error "Submission failed because of invalid proposals." end >>= fun () -> submit_proposals cctxt ~chain:cctxt#chain ~block:cctxt#block ~src_sk src_pkh proposals >>=? fun _res -> -- GitLab From cd1898a148acbb56ad4c85c397213a60837bbc9a Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Fri, 15 Mar 2019 16:22:35 -0400 Subject: [PATCH 07/10] Client: add `--dry-run` to `submit proposals` --- src/proto_alpha/lib_client/client_proto_context.ml | 3 ++- src/proto_alpha/lib_client/client_proto_context.mli | 1 + .../lib_client_commands/client_proto_context_commands.ml | 8 +++++--- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/proto_alpha/lib_client/client_proto_context.ml b/src/proto_alpha/lib_client/client_proto_context.ml index fc6b6d4bfdb9..13a947891834 100644 --- a/src/proto_alpha/lib_client/client_proto_context.ml +++ b/src/proto_alpha/lib_client/client_proto_context.ml @@ -482,6 +482,7 @@ let get_proposals Alpha_services.Voting.proposals cctxt cb let submit_proposals + ?dry_run (cctxt : #Proto_alpha.full) ~chain ~block ?confirmations ~src_sk source proposals = (* We need the next level, not the current *) @@ -490,7 +491,7 @@ let submit_proposals let contents = Single ( Proposals { source ; period ; proposals } ) in Injection.inject_operation cctxt ~chain ~block ?confirmations ~fee_parameter:Injection.dummy_fee_parameter - ~src_sk contents + ?dry_run ~src_sk contents let submit_ballot (cctxt : #Proto_alpha.full) diff --git a/src/proto_alpha/lib_client/client_proto_context.mli b/src/proto_alpha/lib_client/client_proto_context.mli index a5cc310d9053..5ea5cc4ab807 100644 --- a/src/proto_alpha/lib_client/client_proto_context.mli +++ b/src/proto_alpha/lib_client/client_proto_context.mli @@ -251,6 +251,7 @@ val get_proposals : Int32.t Alpha_environment.Protocol_hash.Map.t tzresult Lwt.t val submit_proposals: + ?dry_run:bool -> #Proto_alpha.full -> chain:Shell_services.chain -> block:Shell_services.block -> diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index 168d4025ee43..ab30fa6cacfc 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -656,7 +656,8 @@ let commands version () = end ; command ~group ~desc: "Submit protocol proposals" - (args1 + (args2 + dry_run_switch (switch ~doc:"Do not fail when the checks that try to prevent the user \ from shooting themselves in the foot do." @@ -674,7 +675,7 @@ let commands version () = match Protocol_hash.of_b58check_opt x with | None -> Error_monad.failwith "Invalid proposal hash: '%s'" x | Some hash -> return hash)))) - begin fun force (_name, source) proposals (cctxt : Proto_alpha.full) -> + begin fun (dry_run, force) (_name, source) proposals (cctxt : Proto_alpha.full) -> get_period_info ~chain:cctxt#chain ~block:cctxt#block cctxt >>=? fun info -> begin match info.current_period_kind with | Proposal -> return_unit @@ -758,7 +759,8 @@ let commands version () = else cctxt#error "Submission failed because of invalid proposals." end >>= fun () -> - submit_proposals cctxt ~chain:cctxt#chain ~block:cctxt#block ~src_sk src_pkh + submit_proposals ~dry_run + cctxt ~chain:cctxt#chain ~block:cctxt#block ~src_sk src_pkh proposals >>=? fun _res -> return_unit end ; -- GitLab From ca5b13057d1f7d47d4b4d71f74fd9c941228bc25 Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Fri, 15 Mar 2019 16:30:49 -0400 Subject: [PATCH 08/10] Client: add `--dry-run` to `submit ballot` --- src/proto_alpha/lib_client/client_proto_context.ml | 4 ++-- src/proto_alpha/lib_client/client_proto_context.mli | 1 + .../lib_client_commands/client_proto_context_commands.ml | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/proto_alpha/lib_client/client_proto_context.ml b/src/proto_alpha/lib_client/client_proto_context.ml index 13a947891834..f609c091e659 100644 --- a/src/proto_alpha/lib_client/client_proto_context.ml +++ b/src/proto_alpha/lib_client/client_proto_context.ml @@ -494,7 +494,7 @@ let submit_proposals ?dry_run ~src_sk contents let submit_ballot - (cctxt : #Proto_alpha.full) + ?dry_run (cctxt : #Proto_alpha.full) ~chain ~block ?confirmations ~src_sk source proposal ballot = (* The user must provide the proposal explicitly to make himself sure for what he is voting. *) @@ -503,7 +503,7 @@ let submit_ballot let contents = Single ( Ballot { source ; period ; proposal ; ballot } ) in Injection.inject_operation cctxt ~chain ~block ?confirmations ~fee_parameter:Injection.dummy_fee_parameter - ~src_sk contents + ?dry_run ~src_sk contents let pp_operation formatter (a : Alpha_block_services.operation) = match a.receipt, a.protocol_data with diff --git a/src/proto_alpha/lib_client/client_proto_context.mli b/src/proto_alpha/lib_client/client_proto_context.mli index 5ea5cc4ab807..7badc296e885 100644 --- a/src/proto_alpha/lib_client/client_proto_context.mli +++ b/src/proto_alpha/lib_client/client_proto_context.mli @@ -262,6 +262,7 @@ val submit_proposals: Kind.proposals Injection.result_list tzresult Lwt.t val submit_ballot: + ?dry_run:bool -> #Proto_alpha.full -> chain:Shell_services.chain -> block:Shell_services.block -> diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index ab30fa6cacfc..b127c1bdc340 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -766,7 +766,7 @@ let commands version () = end ; command ~group ~desc: "Submit a ballot" - no_options + (args1 dry_run_switch) (prefixes [ "submit" ; "ballot" ; "for" ] @@ ContractAlias.destination_param ~name: "delegate" @@ -791,7 +791,7 @@ let commands version () = | "pass" -> return Vote.Pass | s -> failwith "Invalid ballot: '%s'" s)) @@ stop) - begin fun () (_name, source) proposal ballot (cctxt : Proto_alpha.full) -> + begin fun dry_run (_name, source) proposal ballot (cctxt : Proto_alpha.full) -> get_period_info ~chain:cctxt#chain ~block:cctxt#block cctxt >>=? fun info -> begin match info.current_period_kind with | Testing_vote | Promotion_vote -> return_unit @@ -801,7 +801,7 @@ let commands version () = cctxt ~chain:cctxt#chain ~block:cctxt#block source >>=? fun (_src_name, src_pkh, _src_pk, src_sk) -> submit_ballot cctxt ~chain:cctxt#chain ~block:cctxt#block ~src_sk src_pkh - proposal ballot >>=? fun _res -> + ~dry_run proposal ballot >>=? fun _res -> return_unit end ; -- GitLab From 187d24e64ed5f498ec5e803cffa1920d0673803d Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Mon, 18 Mar 2019 13:01:06 -0400 Subject: [PATCH 09/10] Client: improve voting error display --- .../client_proto_context_commands.ml | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index b127c1bdc340..ab789de6b691 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -761,8 +761,24 @@ let commands version () = end >>= fun () -> submit_proposals ~dry_run cctxt ~chain:cctxt#chain ~block:cctxt#block ~src_sk src_pkh - proposals >>=? fun _res -> - return_unit + proposals >>= function + | Ok _res -> return_unit + | Error errs -> + begin match errs with + | Unregistred_error + (`O [ "kind", `String "generic" ; + "error", `String msg ]) :: [] -> + cctxt#message "Error:@[@.%a@]" + Format.pp_print_text + (String.split_on_char ' ' msg + |> List.filter (function "" | "\n" -> false | _ -> true) + |> String.concat " " + |> String.map (function '\n' | '\t' -> ' ' | c -> c)) + | el -> + cctxt#message "Error:@ %a" pp_print_error el + end + >>= fun () -> + failwith "Failed to submit proposals" end ; command ~group ~desc: "Submit a ballot" -- GitLab From 1aecd5ff015ec6f8b9726336a3a69e9c8c8f6e8d Mon Sep 17 00:00:00 2001 From: Sebastien Mondet Date: Tue, 19 Mar 2019 13:33:12 -0400 Subject: [PATCH 10/10] =?UTF-8?q?Client:=20mention=20=E2=80=9Cyea=E2=80=9D?= =?UTF-8?q?=20and=20add=20Oxford=20comma=20in=20help?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib_client_commands/client_proto_context_commands.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml index ab789de6b691..ff98e7be7417 100644 --- a/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml +++ b/src/proto_alpha/lib_client_commands/client_proto_context_commands.ml @@ -797,7 +797,7 @@ let commands version () = | Some hash -> return hash)) @@ param ~name:"ballot" - ~desc:"the ballot value (yay, nay or pass)" + ~desc:"the ballot value (yea/yay, nay, or pass)" (parameter ~autocomplete: (fun _ -> return [ "yea" ; "nay" ; "pass" ]) (fun _ s -> (* We should have [Vote.of_string]. *) -- GitLab