Alpha/Vote: limit number of proposals per delegate to 20

This commit is contained in:
Marco Stronati 2018-11-20 22:51:30 +01:00 committed by Pierre Boutillier
parent 249bbbcb6d
commit 278ffb5a17
No known key found for this signature in database
GPG Key ID: C2F73508B56A193C
8 changed files with 85 additions and 12 deletions

View File

@ -346,6 +346,7 @@ module Constants : sig
nonce_length : int ; nonce_length : int ;
max_revelations_per_block : int ; max_revelations_per_block : int ;
max_operation_data_length : int ; max_operation_data_length : int ;
max_proposals_per_delegate : int ;
} }
val fixed_encoding: fixed Data_encoding.t val fixed_encoding: fixed Data_encoding.t
val fixed: fixed val fixed: fixed
@ -354,6 +355,7 @@ module Constants : sig
val nonce_length: int val nonce_length: int
val max_revelations_per_block: int val max_revelations_per_block: int
val max_operation_data_length: int val max_operation_data_length: int
val max_proposals_per_delegate: int
(** Constants parameterized by context *) (** Constants parameterized by context *)
type parametric = { type parametric = {
@ -731,11 +733,14 @@ module Vote : sig
val record_proposal: val record_proposal:
context -> Protocol_hash.t -> public_key_hash -> context -> Protocol_hash.t -> public_key_hash ->
context Lwt.t context tzresult Lwt.t
val get_proposals: val get_proposals:
context -> int32 Protocol_hash.Map.t tzresult Lwt.t context -> int32 Protocol_hash.Map.t tzresult Lwt.t
val clear_proposals: context -> context Lwt.t val clear_proposals: context -> context Lwt.t
val recorded_proposal_count_for_delegate:
context -> public_key_hash -> int tzresult Lwt.t
val listings_encoding : (Signature.Public_key_hash.t * int32) list Data_encoding.t val listings_encoding : (Signature.Public_key_hash.t * int32) list Data_encoding.t
val freeze_listings: context -> context tzresult Lwt.t val freeze_listings: context -> context tzresult Lwt.t
val clear_listings: context -> context tzresult Lwt.t val clear_listings: context -> context tzresult Lwt.t

View File

@ -121,6 +121,8 @@ type error += (* `Branch *)
| Invalid_proposal | Invalid_proposal
| Unexpected_proposal | Unexpected_proposal
| Unauthorized_proposal | Unauthorized_proposal
| Too_many_proposals
| Empty_proposal
| Unexpected_ballot | Unexpected_ballot
| Unauthorized_ballot | Unauthorized_ballot
@ -175,17 +177,45 @@ let () =
~pp:(fun ppf () -> Format.fprintf ppf "Unauthorized ballot") ~pp:(fun ppf () -> Format.fprintf ppf "Unauthorized ballot")
empty empty
(function Unauthorized_ballot -> Some () | _ -> None) (function Unauthorized_ballot -> Some () | _ -> None)
(fun () -> Unauthorized_ballot) (fun () -> Unauthorized_ballot) ;
(* Too many proposals *)
register_error_kind
`Branch
~id:"too_many_proposals"
~title:"Too many proposals"
~description:"The delegate reached the maximum number of allowed proposals."
~pp:(fun ppf () -> Format.fprintf ppf "Too many proposals")
empty
(function Too_many_proposals -> Some () | _ -> None)
(fun () -> Too_many_proposals) ;
(* Empty proposal *)
register_error_kind
`Branch
~id:"empty_proposal"
~title:"Empty proposal"
~description:"Proposal lists cannot be empty."
~pp:(fun ppf () -> Format.fprintf ppf "Empty proposal")
empty
(function Empty_proposal -> Some () | _ -> None)
(fun () -> Empty_proposal)
let record_proposals ctxt delegate proposals = let record_proposals ctxt delegate proposals =
begin match proposals with
| [] -> fail Empty_proposal
| _ :: _ -> return ()
end >>=? fun () ->
Vote.get_current_period_kind ctxt >>=? function Vote.get_current_period_kind ctxt >>=? function
| Proposal -> | Proposal ->
Vote.in_listings ctxt delegate >>= fun in_listings -> Vote.in_listings ctxt delegate >>= fun in_listings ->
if in_listings then if in_listings then
Lwt_list.fold_left_s fold_left_s
(fun ctxt proposal -> (fun ctxt proposal ->
Vote.record_proposal ctxt proposal delegate) Vote.record_proposal ctxt proposal delegate)
ctxt proposals >>= return ctxt proposals >>=? fun ctxt ->
Vote.recorded_proposal_count_for_delegate ctxt delegate >>=? fun count ->
if Compare.Int.(count > Constants.max_proposals_per_delegate) then
fail Too_many_proposals
else return ctxt
else else
fail Unauthorized_proposal fail Unauthorized_proposal
| Testing_vote | Testing | Promotion_vote -> | Testing_vote | Testing | Promotion_vote ->

View File

@ -31,6 +31,8 @@ val may_start_new_voting_cycle:
type error += type error +=
| Unexpected_proposal | Unexpected_proposal
| Unauthorized_proposal | Unauthorized_proposal
| Too_many_proposals
| Empty_proposal
val record_proposals: val record_proposals:
context -> context ->

View File

@ -27,13 +27,15 @@ let version_number = "\000"
let proof_of_work_nonce_size = 8 let proof_of_work_nonce_size = 8
let nonce_length = 32 let nonce_length = 32
let max_revelations_per_block = 32 let max_revelations_per_block = 32
let max_operation_data_length = 16 * 1024 ; (* 16kB *) let max_proposals_per_delegate = 20
let max_operation_data_length = 16 * 1024 (* 16kB *)
type fixed = { type fixed = {
proof_of_work_nonce_size : int ; proof_of_work_nonce_size : int ;
nonce_length : int ; nonce_length : int ;
max_revelations_per_block : int ; max_revelations_per_block : int ;
max_operation_data_length : int ; max_operation_data_length : int ;
max_proposals_per_delegate : int ;
} }
let fixed_encoding = let fixed_encoding =
@ -43,27 +45,32 @@ let fixed_encoding =
(c.proof_of_work_nonce_size, (c.proof_of_work_nonce_size,
c.nonce_length, c.nonce_length,
c.max_revelations_per_block, c.max_revelations_per_block,
c.max_operation_data_length)) c.max_operation_data_length,
c.max_proposals_per_delegate))
(fun (proof_of_work_nonce_size, (fun (proof_of_work_nonce_size,
nonce_length, nonce_length,
max_revelations_per_block, max_revelations_per_block,
max_operation_data_length) -> max_operation_data_length,
max_proposals_per_delegate) ->
{ proof_of_work_nonce_size ; { proof_of_work_nonce_size ;
nonce_length ; nonce_length ;
max_revelations_per_block ; max_revelations_per_block ;
max_operation_data_length ; max_operation_data_length ;
max_proposals_per_delegate ;
} ) } )
(obj4 (obj5
(req "proof_of_work_nonce_size" uint8) (req "proof_of_work_nonce_size" uint8)
(req "nonce_length" uint8) (req "nonce_length" uint8)
(req "max_revelations_per_block" uint8) (req "max_revelations_per_block" uint8)
(req "max_operation_data_length" int31)) (req "max_operation_data_length" int31)
(req "max_proposals_per_delegate" uint8))
let fixed = { let fixed = {
proof_of_work_nonce_size ; proof_of_work_nonce_size ;
nonce_length ; nonce_length ;
max_revelations_per_block ; max_revelations_per_block ;
max_operation_data_length ; max_operation_data_length ;
max_proposals_per_delegate ;
} }
type parametric = { type parametric = {

View File

@ -159,6 +159,11 @@ module Contract = struct
(struct let name = ["counter"] end) (struct let name = ["counter"] end)
(Z) (Z)
module Proposals =
Indexed_context.Make_map
(struct let name = ["proposals"] end)
(Int)
(* Consume gas for serilization and deserialization of expr in this (* Consume gas for serilization and deserialization of expr in this
module *) module *)
module Make_carbonated_map_expr (N : Storage_sigs.NAME) = struct module Make_carbonated_map_expr (N : Storage_sigs.NAME) = struct

View File

@ -178,6 +178,11 @@ module Contract : sig
and type value = Z.t and type value = Z.t
and type t := Raw_context.t and type t := Raw_context.t
module Proposals : Indexed_data_storage
with type key = Contract_repr.t
and type value = int
and type t := Raw_context.t
module Code : Non_iterable_indexed_carbonated_data_storage module Code : Non_iterable_indexed_carbonated_data_storage
with type key = Contract_repr.t with type key = Contract_repr.t
and type value = Script_repr.lazy_expr and type value = Script_repr.lazy_expr

View File

@ -23,8 +23,18 @@
(* *) (* *)
(*****************************************************************************) (*****************************************************************************)
let record_proposal ctxt delegate proposal = let recorded_proposal_count_for_delegate ctxt proposer =
Storage.Vote.Proposals.add ctxt (delegate, proposal) let delegate = Contract_repr.implicit_contract proposer in
Storage.Contract.Proposals.get_option ctxt delegate >>=? function
| None -> return 0
| Some count -> return count
let record_proposal ctxt proposal proposer =
recorded_proposal_count_for_delegate ctxt proposer >>=? fun count ->
let delegate = Contract_repr.implicit_contract proposer in
Storage.Contract.Proposals.init_set ctxt delegate (count + 1) >>= fun ctxt ->
Storage.Vote.Proposals.add ctxt (proposal, proposer) >>= fun ctxt ->
return ctxt
let get_proposals ctxt = let get_proposals ctxt =
Storage.Vote.Proposals.fold ctxt Storage.Vote.Proposals.fold ctxt
@ -42,6 +52,10 @@ let get_proposals ctxt =
end) end)
let clear_proposals ctxt = let clear_proposals ctxt =
Storage.Delegates.fold ctxt ~init:ctxt ~f:begin fun proposer ctxt ->
let delegate = Contract_repr.implicit_contract proposer in
Storage.Contract.Proposals.remove ctxt delegate
end >>= fun ctxt ->
Storage.Vote.Proposals.clear ctxt Storage.Vote.Proposals.clear ctxt
type ballots = { type ballots = {

View File

@ -23,9 +23,14 @@
(* *) (* *)
(*****************************************************************************) (*****************************************************************************)
(** Records a proposal per delegate *)
val record_proposal: val record_proposal:
Raw_context.t -> Protocol_hash.t -> Signature.Public_key_hash.t -> Raw_context.t -> Protocol_hash.t -> Signature.Public_key_hash.t ->
Raw_context.t Lwt.t Raw_context.t tzresult Lwt.t
val recorded_proposal_count_for_delegate:
Raw_context.t -> Signature.Public_key_hash.t ->
int tzresult Lwt.t
val get_proposals: val get_proposals:
Raw_context.t -> int32 Protocol_hash.Map.t tzresult Lwt.t Raw_context.t -> int32 Protocol_hash.Map.t tzresult Lwt.t