Alpha: reintroduce duplicate endorsement error
This commit is contained in:
parent
1ab9a7a72c
commit
b5c275c5fa
@ -928,7 +928,7 @@ module Operation : sig
|
|||||||
type error += Invalid_signature (* `Permanent *)
|
type error += Invalid_signature (* `Permanent *)
|
||||||
|
|
||||||
val check_signature: public_key -> _ operation -> unit tzresult Lwt.t
|
val check_signature: public_key -> _ operation -> unit tzresult Lwt.t
|
||||||
val raw_check_signature: public_key -> _ operation -> unit tzresult
|
val check_signature_sync: public_key -> _ operation -> unit tzresult
|
||||||
|
|
||||||
val internal_operation_encoding: packed_internal_operation Data_encoding.t
|
val internal_operation_encoding: packed_internal_operation Data_encoding.t
|
||||||
|
|
||||||
@ -1059,10 +1059,10 @@ val record_endorsement:
|
|||||||
context -> Signature.Public_key_hash.t -> context
|
context -> Signature.Public_key_hash.t -> context
|
||||||
val allowed_endorsements:
|
val allowed_endorsements:
|
||||||
context ->
|
context ->
|
||||||
(Signature.Public_key.t * int list) Signature.Public_key_hash.Map.t
|
(Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t
|
||||||
val init_endorsements:
|
val init_endorsements:
|
||||||
context ->
|
context ->
|
||||||
(Signature.Public_key.t * int list) Signature.Public_key_hash.Map.t ->
|
(Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t ->
|
||||||
context
|
context
|
||||||
|
|
||||||
val reset_internal_nonce: context -> context
|
val reset_internal_nonce: context -> context
|
||||||
|
@ -13,6 +13,7 @@ open Alpha_context
|
|||||||
|
|
||||||
type error += Wrong_voting_period of Voting_period.t * Voting_period.t (* `Temporary *)
|
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 += Wrong_endorsement_predecessor of Block_hash.t * Block_hash.t (* `Temporary *)
|
||||||
|
type error += Duplicate_endorsement of Signature.Public_key_hash.t (* `Branch *)
|
||||||
type error += Invalid_endorsement_level
|
type error += Invalid_endorsement_level
|
||||||
type error += Invalid_commitment of { expected: bool }
|
type error += Invalid_commitment of { expected: bool }
|
||||||
type error += Internal_operation_replay of packed_internal_operation
|
type error += Internal_operation_replay of packed_internal_operation
|
||||||
@ -70,6 +71,17 @@ let () =
|
|||||||
(req "provided" Voting_period.encoding))
|
(req "provided" Voting_period.encoding))
|
||||||
(function Wrong_voting_period (e, p) -> Some (e, p) | _ -> None)
|
(function Wrong_voting_period (e, p) -> Some (e, p) | _ -> None)
|
||||||
(fun (e, p) -> Wrong_voting_period (e, p));
|
(fun (e, p) -> Wrong_voting_period (e, p));
|
||||||
|
register_error_kind
|
||||||
|
`Branch
|
||||||
|
~id:"operation.duplicate_endorsement"
|
||||||
|
~title:"Duplicate endorsement"
|
||||||
|
~description:"Two endorsements received from same delegate"
|
||||||
|
~pp:(fun ppf k ->
|
||||||
|
Format.fprintf ppf "Duplicate endorsement from delegate %a (possible replay attack)."
|
||||||
|
Signature.Public_key_hash.pp_short k)
|
||||||
|
Data_encoding.(obj1 (req "delegate" Signature.Public_key_hash.encoding))
|
||||||
|
(function Duplicate_endorsement k -> Some k | _ -> None)
|
||||||
|
(fun k -> Duplicate_endorsement k);
|
||||||
register_error_kind
|
register_error_kind
|
||||||
`Temporary
|
`Temporary
|
||||||
~id:"operation.invalid_endorsement_level"
|
~id:"operation.invalid_endorsement_level"
|
||||||
@ -597,14 +609,20 @@ let apply_contents_list
|
|||||||
: (context * kind contents_result_list) tzresult Lwt.t =
|
: (context * kind contents_result_list) tzresult Lwt.t =
|
||||||
match contents_list with
|
match contents_list with
|
||||||
| Single (Endorsement { block ; level }) ->
|
| Single (Endorsement { block ; level }) ->
|
||||||
let current_level = (Level.current ctxt).level in
|
|
||||||
fail_unless
|
fail_unless
|
||||||
(Block_hash.equal block pred_block)
|
(Block_hash.equal block pred_block)
|
||||||
(Wrong_endorsement_predecessor (pred_block, block)) >>=? fun () ->
|
(Wrong_endorsement_predecessor (pred_block, block)) >>=? fun () ->
|
||||||
|
let block = operation.shell.branch in
|
||||||
|
fail_unless
|
||||||
|
(Block_hash.equal block pred_block)
|
||||||
|
(Wrong_endorsement_predecessor (pred_block, block)) >>=? fun () ->
|
||||||
|
let current_level = (Level.current ctxt).level in
|
||||||
fail_unless
|
fail_unless
|
||||||
Raw_level.(succ level = current_level)
|
Raw_level.(succ level = current_level)
|
||||||
Invalid_endorsement_level >>=? fun () ->
|
Invalid_endorsement_level >>=? fun () ->
|
||||||
Baking.check_endorsement_rights ctxt operation >>=? fun (delegate, slots) ->
|
Baking.check_endorsement_rights ctxt operation >>=? fun (delegate, slots, used) ->
|
||||||
|
if used then fail (Duplicate_endorsement delegate)
|
||||||
|
else
|
||||||
let ctxt = record_endorsement ctxt delegate in
|
let ctxt = record_endorsement ctxt delegate in
|
||||||
let gap = List.length slots in
|
let gap = List.length slots in
|
||||||
let ctxt = Fitness.increase ~gap ctxt in
|
let ctxt = Fitness.increase ~gap ctxt in
|
||||||
@ -639,8 +657,8 @@ let apply_contents_list
|
|||||||
(Outdated_double_endorsement_evidence
|
(Outdated_double_endorsement_evidence
|
||||||
{ level = level.level ;
|
{ level = level.level ;
|
||||||
last = oldest_level }) >>=? fun () ->
|
last = oldest_level }) >>=? fun () ->
|
||||||
Baking.check_endorsement_rights ctxt op1 >>=? fun (delegate1, _) ->
|
Baking.check_endorsement_rights ctxt op1 >>=? fun (delegate1, _, _) ->
|
||||||
Baking.check_endorsement_rights ctxt op2 >>=? fun (delegate2, _) ->
|
Baking.check_endorsement_rights ctxt op2 >>=? fun (delegate2, _, _) ->
|
||||||
fail_unless
|
fail_unless
|
||||||
(Signature.Public_key_hash.equal delegate1 delegate2)
|
(Signature.Public_key_hash.equal delegate1 delegate2)
|
||||||
(Inconsistent_double_endorsement_evidence
|
(Inconsistent_double_endorsement_evidence
|
||||||
|
@ -13,7 +13,7 @@ open Misc
|
|||||||
|
|
||||||
type error += Invalid_fitness_gap of int64 * int64 (* `Permanent *)
|
type error += Invalid_fitness_gap of int64 * int64 (* `Permanent *)
|
||||||
type error += Timestamp_too_early of Timestamp.t * Timestamp.t (* `Permanent *)
|
type error += Timestamp_too_early of Timestamp.t * Timestamp.t (* `Permanent *)
|
||||||
type error += Unexpected_endorsement
|
type error += Unexpected_endorsement (* `Permanent *)
|
||||||
type error += Invalid_block_signature of Block_hash.t * Signature.Public_key_hash.t (* `Permanent *)
|
type error += Invalid_block_signature of Block_hash.t * Signature.Public_key_hash.t (* `Permanent *)
|
||||||
type error += Invalid_signature (* `Permanent *)
|
type error += Invalid_signature (* `Permanent *)
|
||||||
type error += Invalid_stamp (* `Permanent *)
|
type error += Invalid_stamp (* `Permanent *)
|
||||||
@ -158,11 +158,11 @@ let endorsement_rights c level =
|
|||||||
(fun acc slot ->
|
(fun acc slot ->
|
||||||
Roll.endorsement_rights_owner c level ~slot >>=? fun pk ->
|
Roll.endorsement_rights_owner c level ~slot >>=? fun pk ->
|
||||||
let pkh = Signature.Public_key.hash pk in
|
let pkh = Signature.Public_key.hash pk in
|
||||||
let slots =
|
let right =
|
||||||
match Signature.Public_key_hash.Map.find_opt pkh acc with
|
match Signature.Public_key_hash.Map.find_opt pkh acc with
|
||||||
| None -> (pk, [slot])
|
| None -> (pk, [slot], false)
|
||||||
| Some (pk, slots) -> (pk, slot :: slots) in
|
| Some (pk, slots, used) -> (pk, slot :: slots, used) in
|
||||||
return (Signature.Public_key_hash.Map.add pkh slots acc))
|
return (Signature.Public_key_hash.Map.add pkh right acc))
|
||||||
Signature.Public_key_hash.Map.empty
|
Signature.Public_key_hash.Map.empty
|
||||||
(0 --> (Constants.endorsers_per_block c - 1))
|
(0 --> (Constants.endorsers_per_block c - 1))
|
||||||
|
|
||||||
@ -174,20 +174,17 @@ let check_endorsement_rights ctxt (op : Kind.endorsement Operation.t) =
|
|||||||
return (Alpha_context.allowed_endorsements ctxt)
|
return (Alpha_context.allowed_endorsements ctxt)
|
||||||
else
|
else
|
||||||
endorsement_rights ctxt (Level.from_raw ctxt level)
|
endorsement_rights ctxt (Level.from_raw ctxt level)
|
||||||
end >>=? fun map ->
|
end >>=? fun endorsements ->
|
||||||
match
|
match
|
||||||
Signature.Public_key_hash.Map.find_first_opt
|
Signature.Public_key_hash.Map.fold (* no find_first *)
|
||||||
(fun pkh ->
|
(fun pkh (pk, slots, used) acc ->
|
||||||
let pk, _ = Signature.Public_key_hash.Map.find pkh map in
|
match Operation.check_signature_sync pk op with
|
||||||
match Operation.raw_check_signature pk op with
|
| Error _ -> acc
|
||||||
| Error _ -> false
|
| Ok () -> Some (pkh, slots, used))
|
||||||
| Ok () -> true)
|
endorsements None
|
||||||
map
|
|
||||||
with
|
with
|
||||||
| None ->
|
| None -> fail Unexpected_endorsement
|
||||||
fail Unexpected_endorsement
|
| Some v -> return v
|
||||||
| Some (pkh, (_pk, slots)) ->
|
|
||||||
return (pkh, slots)
|
|
||||||
|
|
||||||
let select_delegate delegate delegate_list max_priority =
|
let select_delegate delegate delegate_list max_priority =
|
||||||
let rec loop acc l n =
|
let rec loop acc l n =
|
||||||
|
@ -31,18 +31,19 @@ val check_baking_rights:
|
|||||||
context -> Block_header.contents -> Time.t ->
|
context -> Block_header.contents -> Time.t ->
|
||||||
public_key tzresult Lwt.t
|
public_key tzresult Lwt.t
|
||||||
|
|
||||||
(** [check_endorsements_rights c slots]:
|
(** For a given level computes who has the right to
|
||||||
* verifies that the endorsement slots are valid ;
|
include an endorsement in the next block.
|
||||||
* verifies that the endorsement slots correspond to the same delegate at the current level;
|
The result can be stored in Alpha_context.allowed_endorsements *)
|
||||||
*)
|
|
||||||
val check_endorsement_rights:
|
|
||||||
context -> Kind.endorsement Operation.t ->
|
|
||||||
(public_key_hash * int list) tzresult Lwt.t
|
|
||||||
|
|
||||||
val endorsement_rights:
|
val endorsement_rights:
|
||||||
context ->
|
context ->
|
||||||
Level.t ->
|
Level.t ->
|
||||||
(public_key * int list) Signature.Public_key_hash.Map.t tzresult Lwt.t
|
(public_key * int list * bool) Signature.Public_key_hash.Map.t tzresult Lwt.t
|
||||||
|
|
||||||
|
(** Check that the operation was signed by a delegate allowed
|
||||||
|
to endorse at the level specified by the endorsement. *)
|
||||||
|
val check_endorsement_rights:
|
||||||
|
context -> Kind.endorsement Operation.t ->
|
||||||
|
(public_key_hash * int list * bool) tzresult Lwt.t
|
||||||
|
|
||||||
(** Returns the endorsement reward calculated w.r.t a given priotiry. *)
|
(** Returns the endorsement reward calculated w.r.t a given priotiry. *)
|
||||||
val endorsement_reward: context -> block_priority:int -> int -> Tez.t tzresult Lwt.t
|
val endorsement_reward: context -> block_priority:int -> int -> Tez.t tzresult Lwt.t
|
||||||
|
@ -460,7 +460,7 @@ module Endorsing_rights = struct
|
|||||||
RPC_service.get_service
|
RPC_service.get_service
|
||||||
~description:
|
~description:
|
||||||
"Retrieves the delegates allowed to endorse a block.\n\
|
"Retrieves the delegates allowed to endorse a block.\n\
|
||||||
By default, it gives the endorsement slots for bakers that \
|
By default, it gives the endorsement slots for delegates that \
|
||||||
have at least one in the next block.\n\
|
have at least one in the next block.\n\
|
||||||
Parameters `level` and `cycle` can be used to specify the \
|
Parameters `level` and `cycle` can be used to specify the \
|
||||||
(valid) level(s) in the past or future at which the \
|
(valid) level(s) in the past or future at which the \
|
||||||
@ -483,7 +483,7 @@ module Endorsing_rights = struct
|
|||||||
Baking.endorsement_rights ctxt level >>=? fun rights ->
|
Baking.endorsement_rights ctxt level >>=? fun rights ->
|
||||||
return
|
return
|
||||||
(Signature.Public_key_hash.Map.fold
|
(Signature.Public_key_hash.Map.fold
|
||||||
(fun delegate (_, slots) acc -> {
|
(fun delegate (_, slots, _) acc -> {
|
||||||
level = level.level ; delegate ; slots ; estimated_time
|
level = level.level ; delegate ; slots ; estimated_time
|
||||||
} :: acc)
|
} :: acc)
|
||||||
rights [])
|
rights [])
|
||||||
@ -529,4 +529,3 @@ let baking_rights ctxt max_priority =
|
|||||||
List.map
|
List.map
|
||||||
(fun { Baking_rights.delegate ; timestamp ; _ } ->
|
(fun { Baking_rights.delegate ; timestamp ; _ } ->
|
||||||
(delegate, timestamp)) l)
|
(delegate, timestamp)) l)
|
||||||
|
|
||||||
|
@ -646,7 +646,7 @@ let () =
|
|||||||
(function Missing_signature -> Some () | _ -> None)
|
(function Missing_signature -> Some () | _ -> None)
|
||||||
(fun () -> Missing_signature)
|
(fun () -> Missing_signature)
|
||||||
|
|
||||||
let raw_check_signature (type kind) key ({ shell ; protocol_data } : kind operation) =
|
let check_signature_sync (type kind) key ({ shell ; protocol_data } : kind operation) =
|
||||||
let check ~watermark contents signature =
|
let check ~watermark contents signature =
|
||||||
let unsigned_operation =
|
let unsigned_operation =
|
||||||
Data_encoding.Binary.to_bytes_exn
|
Data_encoding.Binary.to_bytes_exn
|
||||||
@ -668,7 +668,7 @@ let raw_check_signature (type kind) key ({ shell ; protocol_data } : kind operat
|
|||||||
check ~watermark:Generic_operation (Contents_list contents) signature
|
check ~watermark:Generic_operation (Contents_list contents) signature
|
||||||
|
|
||||||
let check_signature pk op =
|
let check_signature pk op =
|
||||||
Lwt.return (raw_check_signature pk op)
|
Lwt.return (check_signature_sync pk op)
|
||||||
|
|
||||||
let hash_raw = Operation.hash
|
let hash_raw = Operation.hash
|
||||||
let hash (o : _ operation) =
|
let hash (o : _ operation) =
|
||||||
|
@ -165,7 +165,7 @@ type error += Invalid_signature (* `Permanent *)
|
|||||||
|
|
||||||
val check_signature:
|
val check_signature:
|
||||||
Signature.Public_key.t -> _ operation -> unit tzresult Lwt.t
|
Signature.Public_key.t -> _ operation -> unit tzresult Lwt.t
|
||||||
val raw_check_signature:
|
val check_signature_sync:
|
||||||
Signature.Public_key.t -> _ operation -> unit tzresult
|
Signature.Public_key.t -> _ operation -> unit tzresult
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ type t = {
|
|||||||
fitness: Int64.t ;
|
fitness: Int64.t ;
|
||||||
deposits: Tez_repr.t Signature.Public_key_hash.Map.t ;
|
deposits: Tez_repr.t Signature.Public_key_hash.Map.t ;
|
||||||
allowed_endorsements:
|
allowed_endorsements:
|
||||||
(Signature.Public_key.t * int list) Signature.Public_key_hash.Map.t ;
|
(Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t ;
|
||||||
fees: Tez_repr.t ;
|
fees: Tez_repr.t ;
|
||||||
rewards: Tez_repr.t ;
|
rewards: Tez_repr.t ;
|
||||||
block_gas: Z.t ;
|
block_gas: Z.t ;
|
||||||
@ -41,11 +41,23 @@ let constants ctxt = ctxt.constants
|
|||||||
let recover ctxt = ctxt.context
|
let recover ctxt = ctxt.context
|
||||||
|
|
||||||
let record_endorsement ctxt k =
|
let record_endorsement ctxt k =
|
||||||
|
match Signature.Public_key_hash.Map.find_opt k ctxt.allowed_endorsements with
|
||||||
|
| None -> assert false
|
||||||
|
| Some (_, _, true) -> assert false (* right already used *)
|
||||||
|
| Some (d, s, false) ->
|
||||||
{ ctxt with
|
{ ctxt with
|
||||||
allowed_endorsements =
|
allowed_endorsements =
|
||||||
Signature.Public_key_hash.Map.remove k ctxt.allowed_endorsements }
|
Signature.Public_key_hash.Map.add k (d,s,true) ctxt.allowed_endorsements }
|
||||||
|
|
||||||
let init_endorsements ctxt allowed_endorsements =
|
let init_endorsements ctxt allowed_endorsements =
|
||||||
{ ctxt with allowed_endorsements }
|
if Signature.Public_key_hash.Map.is_empty allowed_endorsements
|
||||||
|
then assert false (* can't initialize to empty *)
|
||||||
|
else begin
|
||||||
|
if Signature.Public_key_hash.Map.is_empty ctxt.allowed_endorsements
|
||||||
|
then { ctxt with allowed_endorsements }
|
||||||
|
else assert false (* can't initialize twice *)
|
||||||
|
end
|
||||||
|
|
||||||
let allowed_endorsements ctxt =
|
let allowed_endorsements ctxt =
|
||||||
ctxt.allowed_endorsements
|
ctxt.allowed_endorsements
|
||||||
|
|
||||||
|
@ -205,12 +205,19 @@ val record_internal_nonce: context -> int -> context
|
|||||||
(** Check is the internal operation nonce has been taken. *)
|
(** Check is the internal operation nonce has been taken. *)
|
||||||
val internal_nonce_already_recorded: context -> int -> bool
|
val internal_nonce_already_recorded: context -> int -> bool
|
||||||
|
|
||||||
val record_endorsement:
|
(** Returns a map where to each endorser's pkh is associated the list of its
|
||||||
context -> Signature.Public_key_hash.t -> context
|
endorsing slots (in decreasing order) for a given level. *)
|
||||||
val allowed_endorsements:
|
val allowed_endorsements:
|
||||||
context ->
|
context ->
|
||||||
(Signature.Public_key.t * int list) Signature.Public_key_hash.Map.t
|
(Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t
|
||||||
|
|
||||||
|
(** Initializes the map of allowed endorsements, this function must only be
|
||||||
|
called once. *)
|
||||||
val init_endorsements:
|
val init_endorsements:
|
||||||
context ->
|
context ->
|
||||||
(Signature.Public_key.t * int list) Signature.Public_key_hash.Map.t ->
|
(Signature.Public_key.t * int list * bool) Signature.Public_key_hash.Map.t ->
|
||||||
context
|
context
|
||||||
|
|
||||||
|
(** Marks an endorsment in the map as used. *)
|
||||||
|
val record_endorsement:
|
||||||
|
context -> Signature.Public_key_hash.t -> context
|
||||||
|
Loading…
Reference in New Issue
Block a user