diff --git a/lib_embedded_protocol_alpha/src/apply.ml b/lib_embedded_protocol_alpha/src/apply.ml index 2e2344081..92f66b61c 100644 --- a/lib_embedded_protocol_alpha/src/apply.ml +++ b/lib_embedded_protocol_alpha/src/apply.ml @@ -13,6 +13,7 @@ open Tezos_context type error += Wrong_voting_period of Voting_period.t * Voting_period.t (* `Temporary *) type error += Wrong_endorsement_predecessor of Block_hash.t * Block_hash.t (* `Temporary *) +type error += Duplicate_endorsement of int (* `Permanent *) type error += Bad_contract_parameter of Contract.t * Script.expr option * Script.expr option (* `Permanent *) type error += Too_many_faucet @@ -60,6 +61,16 @@ let () = (function Bad_contract_parameter (c, expected, supplied) -> Some (c, expected, supplied) | _ -> None) (fun (c, expected, supplied) -> Bad_contract_parameter (c, expected, supplied)) ; + register_error_kind + `Permanent + ~id:"operation.duplicate_endorsement" + ~title:"Duplicate endorsement" + ~description:"Two endorsements received for the same slot" + ~pp:(fun ppf k -> + Format.fprintf ppf "Duplicate endorsement for slot %d." k) + Data_encoding.(obj1 (req "slot" uint16)) + (function Duplicate_endorsement k -> Some k | _ -> None) + (fun k -> Duplicate_endorsement k); register_error_kind `Temporary ~id:"operation.too_many_faucet" @@ -79,7 +90,11 @@ let apply_delegate_operation_content fail_unless (Block_hash.equal block pred_block) (Wrong_endorsement_predecessor (pred_block, block)) >>=? fun () -> + fail_when + (endorsement_already_recorded ctxt slot) + (Duplicate_endorsement (slot)) >>=? fun () -> Baking.check_signing_rights ctxt slot delegate >>=? fun () -> + let ctxt = record_endorsement ctxt slot in let ctxt = Fitness.increase ctxt in Baking.pay_endorsement_bond ctxt delegate >>=? fun (ctxt, bond) -> Baking.endorsement_reward ~block_priority >>=? fun reward -> diff --git a/lib_embedded_protocol_alpha/src/raw_context.ml b/lib_embedded_protocol_alpha/src/raw_context.ml index 0405949d1..4f9200b7e 100644 --- a/lib_embedded_protocol_alpha/src/raw_context.ml +++ b/lib_embedded_protocol_alpha/src/raw_context.ml @@ -7,6 +7,8 @@ (* *) (**************************************************************************) +module Int_set = Set.Make (Compare.Int) + type t = { context: Context.t ; constants: Constants_repr.constants ; @@ -16,7 +18,9 @@ type t = { fitness: Int64.t ; roll_value: Tez_repr.t ; faucet_count: int; + endorsements_received: Int_set.t; } + type context = t type root_context = t @@ -29,6 +33,9 @@ let constants ctxt = ctxt.constants let roll_value ctxt = ctxt.roll_value let recover ctxt = ctxt.context +let record_endorsement ctxt k = { ctxt with endorsements_received = Int_set.add k ctxt.endorsements_received } +let endorsement_already_recorded ctxt k = Int_set.mem k ctxt.endorsements_received + let incr_faucet_count ctxt = { ctxt with faucet_count = ctxt.faucet_count + 1 } let set_current_fitness ctxt fitness = { ctxt with fitness } @@ -228,7 +235,7 @@ let prepare ~level ~timestamp ~fitness ctxt = level in return ({ context = ctxt ; constants ; level ; timestamp ; fitness ; first_level ; roll_value ; - faucet_count = 0 ; + faucet_count = 0 ; endorsements_received = Int_set.empty ; }, first_block) @@ -257,6 +264,7 @@ let register_resolvers enc resolve = fitness = 0L ; roll_value = Tez_repr.zero ; faucet_count = 0 ; + endorsements_received = Int_set.empty ; } in resolve faked_context str in Context.register_resolver enc resolve diff --git a/lib_embedded_protocol_alpha/src/raw_context.mli b/lib_embedded_protocol_alpha/src/raw_context.mli index 4023011e1..19494fdd3 100644 --- a/lib_embedded_protocol_alpha/src/raw_context.mli +++ b/lib_embedded_protocol_alpha/src/raw_context.mli @@ -134,6 +134,10 @@ end include T with type t := t and type context := context +val record_endorsement: context -> int -> context +val endorsement_already_recorded: context -> int -> bool + + (** HACK alphanet *) val double_roll_value: context -> int -> context tzresult Lwt.t val faucet_count: context -> int diff --git a/lib_embedded_protocol_alpha/src/tezos_context.ml b/lib_embedded_protocol_alpha/src/tezos_context.ml index a7b479ba1..474990bec 100644 --- a/lib_embedded_protocol_alpha/src/tezos_context.ml +++ b/lib_embedded_protocol_alpha/src/tezos_context.ml @@ -153,3 +153,6 @@ let fork_test_network = Raw_context.fork_test_network let faucet_count = Raw_context.faucet_count let incr_faucet_count = Raw_context.incr_faucet_count + +let endorsement_already_recorded = Raw_context.endorsement_already_recorded +let record_endorsement = Raw_context.record_endorsement diff --git a/lib_embedded_protocol_alpha/src/tezos_context.mli b/lib_embedded_protocol_alpha/src/tezos_context.mli index eca1b515d..1621945f7 100644 --- a/lib_embedded_protocol_alpha/src/tezos_context.mli +++ b/lib_embedded_protocol_alpha/src/tezos_context.mli @@ -726,6 +726,9 @@ val configure_sandbox: val activate: context -> Protocol_hash.t -> context Lwt.t val fork_test_network: context -> Protocol_hash.t -> Time.t -> context Lwt.t +val endorsement_already_recorded: context -> int -> bool +val record_endorsement: context -> int -> context + (**/**) (* HACK alphanet *)