From cacd3826e448b22204f27d9deb35c359e13a2344 Mon Sep 17 00:00:00 2001 From: Marco Stronati Date: Wed, 19 Dec 2018 10:55:43 +0100 Subject: [PATCH] Client: tweak 'show voting period', add rpc to test, check right period --- src/bin_client/test/test_voting.sh | 115 ++++++++-------- .../lib_client/client_proto_context.ml | 125 ++++++------------ .../lib_client/client_proto_context.mli | 30 ++++- .../client_proto_context_commands.ml | 62 ++++++++- 4 files changed, 188 insertions(+), 144 deletions(-) diff --git a/src/bin_client/test/test_voting.sh b/src/bin_client/test/test_voting.sh index 0d0870c42..55fe7df9b 100755 --- a/src/bin_client/test/test_voting.sh +++ b/src/bin_client/test/test_voting.sh @@ -20,35 +20,52 @@ activate_alpha echo Alpha activated -res=`$client show votes` -echo $res +function get_ballot_list() { + $client rpc get /chains/main/blocks/head/votes/ballot_list +} +function get_ballots() { + $client rpc get /chains/main/blocks/head/votes/ballots +} +function get_current_period_kind() { + $client rpc get /chains/main/blocks/head/votes/current_period_kind +} +function get_current_proposal() { + $client rpc get /chains/main/blocks/head/votes/current_proposal +} +function get_current_quorum() { + $client rpc get /chains/main/blocks/head/votes/current_quorum +} +function get_listings() { + $client rpc get /chains/main/blocks/head/votes/listings +} +function get_proposals() { + $client rpc get /chains/main/blocks/head/votes/proposals +} +function get_period_position() { + #TODO why offset 1? + $client rpc get /chains/main/blocks/head/helpers/current_level?offset=1 | jq .voting_period_position +} -[ `echo $res | jq .voting_period_position` = '1' ] \ +$client show voting period + +[ `get_period_position` = '1' ] \ || { echo "strange voting_period_position" ; exit 1 ; } -[ `echo $res | jq .voting_period_remaining` = '3' ] \ - || { echo "strange voting_period_remaining" ; exit 1 ; } echo Checking the bug of the empty listing in the first voting period... -[ `echo $res | jq .listings` = '[]' ] \ +[ `get_listings` = '[]' ] \ || { echo "empty listings bug was fixed?!" ; exit 1 ; } bake # pos=2 -res=`$client show votes` -[ `echo $res | jq .voting_period_position` = '2' ] \ +[ `get_period_position` = '2' ] \ || { echo "strange voting_period_position" ; exit 1 ; } -[ `echo $res | jq .voting_period_remaining` = '2' ] \ - || { echo "strange voting_period_remaining" ; exit 1 ; } bake # pos=3 bake # new period, pos=0 echo 'Checking the current period = proposal with non empty listings' -res=`$client show votes` -[ `echo $res | jq .voting_period_position` = '0' ] \ +[ `get_period_position` = '0' ] \ || { echo "strange voting_period_position" ; exit 1 ; } -[ `echo $res | jq .voting_period_remaining` = '4' ] \ - || { echo "strange voting_period_remaining" ; exit 1 ; } -[ "`echo $res | jq .listings`" != '[]' ] \ +[ "`get_listings`" != '[]' ] \ || { echo "strange listings" ; exit 1 ; } # Prepare 3 different protocol sources @@ -72,8 +89,13 @@ proto=($proto_str) # Proposals +[ `get_proposals` == '[]' ] \ + || { echo "strange proposals" ; exit 1 ; } + echo 'Proposal voting...' +$client show voting period + $client submit proposals for bootstrap1 ${proto[0]} $client submit proposals for bootstrap2 ${proto[0]} ${proto[1]} $client submit proposals for bootstrap3 ${proto[1]} @@ -81,8 +103,9 @@ $client submit proposals for bootstrap4 ${proto[2]} bake -res=`$client show votes` -[ "`echo $res | jq .proposals`" != '[]' ] \ +$client show voting period + +[ "`get_proposals`" != '[]' ] \ || { echo "strange proposals" ; exit 1 ; } bake # pos=2 @@ -90,23 +113,20 @@ bake # pos=2 echo 'Breaking the tie' $client submit proposals for bootstrap4 ${proto[1]} # To make ${proto[1]} win -$client show votes +$client show voting period bake # pos=3 bake # new period! pos=0 echo The phase must be testing_vote... -res=`$client show votes` -echo $res -[ `echo $res | jq .voting_period_position` = '0' ] \ + +[ `get_period_position` = '0' ] \ || { echo "strange voting_period_position" ; exit 1 ; } -[ `echo $res | jq .voting_period_remaining` = '4' ] \ - || { echo "strange voting_period_remaining" ; exit 1 ; } -[ `echo $res | jq .current_period_kind` = '"testing_vote"' ] \ +[ `get_current_period_kind` = '"testing_vote"' ] \ || { echo "strange current_period_kind" ; exit 1 ; } -[ "`echo $res | jq .listings`" != '[]' ] \ +[ "`get_listings`" != '[]' ] \ || { echo "strange listings" ; exit 1 ; } -[ `echo $res | jq .current_proposal` = '"'${proto[1]}'"' ] \ +[ `get_current_proposal` = '"'${proto[1]}'"' ] \ || { echo "strange current_proposal" ; exit 1 ; } echo Ballots 1 @@ -125,23 +145,20 @@ $client submit ballot for bootstrap1 ${proto[1]} yay \ bake # pos=2 bake # pos=3 -$client show votes +$client show voting period bake # new period pos=0 echo Testing vote should be done -res=`$client show votes` -[ `echo $res | jq .voting_period_position` = '0' ] \ +[ `get_period_position` = '0' ] \ || { echo "strange voting_period_position" ; exit 1 ; } -[ `echo $res | jq .voting_period_remaining` = '4' ] \ - || { echo "strange voting_period_remaining" ; exit 1 ; } -[ `echo $res | jq .current_period_kind` = '"testing"' ] \ +[ `get_current_period_kind` = '"testing"' ] \ || { echo "strange current_period_kind" ; exit 1 ; } -[ "`echo $res | jq .listings`" = '[]' ] \ +[ "`get_listings`" = '[]' ] \ || { echo "strange listings" ; exit 1 ; } -[ `echo $res | jq .current_proposal` = '"'${proto[1]}'"' ] \ +[ `get_current_proposal` = '"'${proto[1]}'"' ] \ || { echo "strange current_proposal" ; exit 1 ; } -[ `echo $res | jq .ballot_list` = '[]' ] \ +[ `get_ballot_list` = '[]' ] \ || { echo "strange ballot_list" ; exit 1 ; } bake # pos=1 @@ -150,18 +167,15 @@ bake # pos=3 bake # new period pos=0 echo Testing should be done -res=`$client show votes` -[ `echo $res | jq .voting_period_position` = '0' ] \ +[ `get_period_position` = '0' ] \ || { echo "strange voting_period_position" ; exit 1 ; } -[ `echo $res | jq .voting_period_remaining` = '4' ] \ - || { echo "strange voting_period_remaining" ; exit 1 ; } -[ `echo $res | jq .current_period_kind` = '"promotion_vote"' ] \ +[ `get_current_period_kind` = '"promotion_vote"' ] \ || { echo "strange current_period_kind" ; exit 1 ; } -[ "`echo $res | jq .listings`" != '[]' ] \ +[ "`get_listings`" != '[]' ] \ || { echo "strange listings" ; exit 1 ; } -[ `echo $res | jq .current_proposal` = '"'${proto[1]}'"' ] \ +[ `get_current_proposal` = '"'${proto[1]}'"' ] \ || { echo "strange current_proposal" ; exit 1 ; } -[ `echo $res | jq .ballot_list` = '[]' ] \ +[ `get_ballot_list` = '[]' ] \ || { echo "strange ballot_list" ; exit 1 ; } $client submit ballot for bootstrap1 ${proto[1]} yay @@ -173,21 +187,18 @@ bake # pos=1 bake # pos=2 bake # pos=3 -$client show votes +$client show voting period bake # new period pos=0 echo 'Promotion vote should be over now negatively' -res=`$client show votes` -[ `echo $res | jq .voting_period_position` = '0' ] \ +[ `get_period_position` = '0' ] \ || { echo "strange voting_period_position" ; exit 1 ; } -[ `echo $res | jq .voting_period_remaining` = '4' ] \ - || { echo "strange voting_period_remaining" ; exit 1 ; } -[ `echo $res | jq .current_period_kind` = '"proposal"' ] \ +[ `get_current_period_kind` = '"proposal"' ] \ || { echo "strange current_period_kind" ; exit 1 ; } -[ "`echo $res | jq .listings`" != '[]' ] \ +[ "`get_listings`" != '[]' ] \ || { echo "strange listings" ; exit 1 ; } -[ `echo $res | jq .current_proposal` = 'null' ] \ +[ `get_current_proposal` = 'null' ] \ || { echo "strange current_proposal" ; exit 1 ; } -[ `echo $res | jq .ballot_list` = '[]' ] \ +[ `get_ballot_list` = '[]' ] \ || { echo "strange ballot_list" ; exit 1 ; } diff --git a/src/proto_alpha/lib_client/client_proto_context.ml b/src/proto_alpha/lib_client/client_proto_context.ml index f041a0af3..d46d09bf3 100644 --- a/src/proto_alpha/lib_client/client_proto_context.ml +++ b/src/proto_alpha/lib_client/client_proto_context.ml @@ -420,18 +420,18 @@ let activate_existing_account | Some _ -> failwith "Only Ed25519 accounts can be activated" | None -> failwith "Unknown account" -type vote_info = { - current_period_kind : Voting_period.kind ; - voting_period_position : int32 ; - voting_period_remaining : int32 ; - current_quorum : Int32.t ; - listings : (public_key_hash * int32) list ; - (* The equality between Alpha_environment.Protocol_hash.t - and Protocol_hash.t is dropped at Tezos_protocol_environment.Make(_).V1 *) - proposals : Int32.t Alpha_environment.Protocol_hash.Map.t ; - current_proposal : Protocol_hash.t option ; - ballots : Vote.ballots ; - ballot_list : (public_key_hash * Vote.ballot) list ; +type period_info = { + current_period_kind : Voting_period.kind ; + position : Int32.t ; + remaining : Int32.t ; + current_proposal : Protocol_hash.t option ; +} + +type ballots_info = { + current_quorum : Int32.t ; + participation : Int32.t ; + supermajority : Int32.t ; + ballots : Vote.ballots ; } (* Should be moved to src/proto_alpha/lib_protocol/src/vote_storage.ml *) @@ -440,83 +440,47 @@ let ballot_list_encoding = (req "pkh" Signature.Public_key_hash.encoding) (req "ballot" Vote.ballot_encoding))) -let vote_info_encoding = - let open Data_encoding in - conv - (fun { current_period_kind ; - voting_period_position ; - voting_period_remaining ; - current_quorum ; - listings ; - proposals ; - current_proposal ; - ballots ; - ballot_list } -> - ( current_period_kind , - voting_period_position , - voting_period_remaining , - current_quorum , - listings , - proposals , - current_proposal , - ballots , - ballot_list )) - (fun ( current_period_kind , - voting_period_position , - voting_period_remaining , - current_quorum , - listings , - proposals , - current_proposal , - ballots , - ballot_list ) -> - { current_period_kind ; - voting_period_position ; - voting_period_remaining ; - current_quorum ; - listings ; - proposals ; - current_proposal ; - ballots ; - ballot_list }) - @@ obj9 - (req "current_period_kind" Voting_period.kind_encoding) - (req "voting_period_position" Data_encoding.int32) - (req "voting_period_remaining" Data_encoding.int32) - (req "current_quorum" Data_encoding.int32) - (req "listings" Vote.listings_encoding) - (req "proposals" (Alpha_environment.Protocol_hash.Map.encoding Data_encoding.int32)) - (req "current_proposal" (Data_encoding.option Protocol_hash.encoding)) - (req "ballots" Vote.ballots_encoding) - (req "ballot_list" ballot_list_encoding) +let get_ballots_info + (cctxt : #Proto_alpha.full) + ~chain ~block = + (* Get the next level, not the current *) + let cb = (chain, block) in + Alpha_services.Voting.ballots cctxt cb >>=? fun ballots -> + Alpha_services.Voting.current_quorum cctxt cb >>=? fun current_quorum -> + Alpha_services.Voting.listings cctxt cb >>=? fun listings -> + let max_participation = + List.fold_left (fun acc (_, w) -> Int32.add w acc) 0l listings in + let all_votes = Int32.(add (add ballots.yay ballots.nay) ballots.pass) in + let participation = Int32.(div (mul all_votes 100_00l) max_participation) in + let supermajority = Int32.(div (mul 8l (add ballots.yay ballots.nay)) 10l) in + return { current_quorum ; + participation ; + supermajority ; + ballots } -let get_vote_info +let get_period_info (cctxt : #Proto_alpha.full) ~chain ~block = (* Get the next level, not the current *) let cb = (chain, block) in Alpha_services.Helpers.current_level cctxt ~offset:1l cb >>=? fun level -> Alpha_services.Constants.all cctxt cb >>=? fun constants -> - let voting_period_position = level.voting_period_position in - let voting_period_remaining = - Int32.(sub constants.parametric.blocks_per_voting_period voting_period_position) in - Alpha_services.Voting.ballots cctxt cb >>=? fun ballots -> - Alpha_services.Voting.ballot_list cctxt cb >>=? fun ballot_list -> + Alpha_services.Voting.current_proposal cctxt cb >>=? fun current_proposal -> + let position = level.voting_period_position in + let remaining = + Int32.(sub constants.parametric.blocks_per_voting_period position) in Alpha_services.Voting.current_period_kind cctxt cb >>=? fun current_period_kind -> - Alpha_services.Voting.current_quorum cctxt cb >>=? fun current_quorum -> - Alpha_services.Voting.listings cctxt cb >>=? fun listings -> - Alpha_services.Voting.proposals cctxt cb >>=? fun proposals -> - Alpha_services.Voting.current_proposal cctxt cb >>=? fun current_proposal -> - return { voting_period_position ; - voting_period_remaining ; - ballots ; - ballot_list ; - current_period_kind ; - current_quorum ; - listings ; - proposals ; + return { current_period_kind ; + position ; + remaining ; current_proposal } +let get_proposals + (cctxt : #Proto_alpha.full) + ~chain ~block = + let cb = (chain, block) in + Alpha_services.Voting.proposals cctxt cb + let submit_proposals (cctxt : #Proto_alpha.full) ~chain ~block ?confirmations ~src_sk source proposals = @@ -532,8 +496,7 @@ let submit_ballot (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. - *) + for what he is voting. *) Alpha_services.Helpers.current_level cctxt ~offset:1l (chain, block) >>=? fun (level : Level.t) -> let period = level.voting_period in let contents = Single ( Ballot { source ; period ; proposal ; ballot } ) in diff --git a/src/proto_alpha/lib_client/client_proto_context.mli b/src/proto_alpha/lib_client/client_proto_context.mli index bec4636c1..a5cc310d9 100644 --- a/src/proto_alpha/lib_client/client_proto_context.mli +++ b/src/proto_alpha/lib_client/client_proto_context.mli @@ -218,15 +218,37 @@ val activate_existing_account: Blinded_public_key_hash.activation_code -> Kind.activate_account Injection.result tzresult Lwt.t -type vote_info +type period_info = { + current_period_kind : Voting_period.kind ; + position : Int32.t ; + remaining : Int32.t ; + current_proposal : Protocol_hash.t option ; +} -val vote_info_encoding : vote_info Data_encoding.t +type ballots_info = { + current_quorum : Int32.t ; + participation : Int32.t ; + supermajority : Int32.t ; + ballots : Vote.ballots ; +} -val get_vote_info : +val get_period_info : #Proto_alpha.full -> chain:Shell_services.chain -> block:Shell_services.block -> - vote_info tzresult Lwt.t + period_info tzresult Lwt.t + +val get_ballots_info : + #Proto_alpha.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + ballots_info tzresult Lwt.t + +val get_proposals : + #Proto_alpha.full -> + chain:Shell_services.chain -> + block:Shell_services.block -> + Int32.t Alpha_environment.Protocol_hash.Map.t tzresult Lwt.t val submit_proposals: #Proto_alpha.full -> 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 a853afa5d..1b2964d05 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 @@ -658,6 +658,11 @@ let commands version () = | None -> Error_monad.failwith "Invalid proposal hash: '%s'" x | Some hash -> return hash)))) begin fun () (_name, source) proposals (cctxt : Proto_alpha.full) -> + get_period_info ~chain:`Main ~block:cctxt#block cctxt >>=? fun info -> + begin match info.current_period_kind with + | Proposal -> return_unit + | _ -> cctxt#error "Not in a proposal period" + end >>=? fun () -> Shell_services.Protocol.list cctxt >>=? fun known_protos -> let check_proposals proposals : unit tzresult Lwt.t = let n = List.length proposals in @@ -676,7 +681,8 @@ let commands version () = Client_proto_context.get_manager cctxt ~chain:`Main ~block:cctxt#block source >>=? fun (_src_name, src_pkh, _src_pk, src_sk) -> - submit_proposals cctxt ~chain:`Main ~block:cctxt#block ~src_sk src_pkh proposals >>=? fun _res -> + submit_proposals cctxt ~chain:`Main ~block:cctxt#block ~src_sk src_pkh + proposals >>=? fun _res -> return_unit end ; @@ -707,6 +713,11 @@ let commands version () = | b -> return b)) @@ stop) begin fun () (_name, source) proposal ballot (cctxt : Proto_alpha.full) -> + get_period_info ~chain:`Main ~block:cctxt#block cctxt >>=? fun info -> + begin match info.current_period_kind with + | Testing_vote | Promotion_vote -> return_unit + | _ -> cctxt#error "Not in a Testing_vote or Promotion_vote period" + end >>=? fun () -> Client_proto_context.get_manager cctxt ~chain:`Main ~block:cctxt#block source >>=? fun (_src_name, src_pkh, _src_pk, src_sk) -> @@ -715,14 +726,51 @@ let commands version () = return_unit end ; - command ~group ~desc: "Summarize the current voting information." + command ~group ~desc: "Summarize the current voting period." no_options - (fixed [ "show" ; "votes" ]) + (fixed [ "show" ; "voting" ; "period" ]) begin fun () (cctxt : Proto_alpha.full) -> - get_vote_info ~chain:`Main ~block:cctxt#block cctxt >>=? fun vote_info -> - cctxt#message "%a" Data_encoding.Json.pp - (Data_encoding.Json.construct vote_info_encoding vote_info) >>= fun () -> - return_unit + get_period_info ~chain:`Main ~block:cctxt#block cctxt >>=? fun info -> + cctxt#message "Current period: %a\n\ + Blocks remaining until end of period: %ld" + Data_encoding.Json.pp + (Data_encoding.Json.construct + Proto_alpha.Alpha_context.Voting_period.kind_encoding + info.current_period_kind) + info.remaining >>= fun () -> + get_proposals ~chain:`Main ~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 + let print_proposal = function + | None -> assert false (* not called during proposal phase *) + | Some proposal -> cctxt#message "Current proposal: %a" + Protocol_hash.pp proposal + 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 + >>= fun () -> return_unit + | Testing_vote | Promotion_vote -> + print_proposal info.current_proposal >>= fun () -> + get_ballots_info ~chain:`Main ~block:cctxt#block cctxt >>=? fun ballots_info -> + cctxt#answer "Ballots: %a@,\ + Current participation %.2f%%, necessary quorum %.2f%%@,\ + Current in favor %ld, needed supermajority %ld" + Data_encoding.Json.pp (Data_encoding.Json.construct + Vote.ballots_encoding ballots_info.ballots) + ((Int32.to_float ballots_info.current_quorum) /. 100.) + ((Int32.to_float ballots_info.participation) /. 100.) + ballots_info.ballots.yay + ballots_info.supermajority + >>= fun () -> return_unit + | Testing -> print_proposal info.current_proposal >>= fun () -> + return_unit end ; ]