Alpha: add operation Double_endorsement

This commit is contained in:
Grégoire Henry 2018-03-15 00:20:37 +01:00 committed by Benjamin Canou
parent e1a1f754aa
commit 09c1e317ab
7 changed files with 192 additions and 24 deletions

View File

@ -665,6 +665,7 @@ module Encoding = struct
List.for_all (fun (Case { encoding = e }) -> is_obj e) cases
| Empty -> true
| Ignore -> true
| Mu (_,_,self) -> is_obj (self e)
| _ -> false
let rec is_tup : type a. a t -> bool = fun e ->
@ -675,6 +676,7 @@ module Encoding = struct
| Dynamic_size e -> is_tup e
| Union (_,_,cases) ->
List.for_all (function Case { encoding = e} -> is_tup e) cases
| Mu (_,_,self) -> is_tup (self e)
| _ -> false
let merge_objs o1 o2 =

View File

@ -507,7 +507,7 @@ module Delegate : sig
val punish:
context -> public_key_hash -> Cycle.t ->
context tzresult Lwt.t
(context * Tez.t) tzresult Lwt.t
val has_frozen_balance:
context -> public_key_hash -> Cycle.t ->
@ -582,6 +582,10 @@ and anonymous_operation =
level: Raw_level.t ;
nonce: Nonce.t ;
}
| Double_endorsement of {
op1: operation ;
op2: operation ;
}
| Faucet of {
id: Ed25519.Public_key_hash.t ;
nonce: MBytes.t ;

View File

@ -19,6 +19,12 @@ type error += Too_many_faucet
type error += Invalid_endorsement_level
type error += Invalid_commitment of { expected: bool }
type error += Invalid_double_endorsement (* `Permanent *)
type error += Inconsistent_double_endorsement of { delegate1: Ed25519.Public_key_hash.t ; delegate2: Ed25519.Public_key_hash.t } (* `Permanent *)
type error += Unrequired_double_endorsement (* `Branch*)
type error += Too_early_double_endorsement of { level: Raw_level.t ; current: Raw_level.t } (* `Temporary *)
type error += Outdated_double_endorsement of { level: Raw_level.t ; last: Raw_level.t } (* `Permanent *)
let () =
register_error_kind
@ -107,7 +113,90 @@ let () =
Format.fprintf ppf "Unexpected seed's nonce commitment in block header.")
Data_encoding.(obj1 (req "expected "bool))
(function Invalid_commitment { expected } -> Some expected | _ -> None)
(fun expected -> Invalid_commitment { expected })
(fun expected -> Invalid_commitment { expected }) ;
register_error_kind
`Permanent
~id:"block.invalid_double_endorsement"
~title:"Invalid double endorsement"
~description:"A double-endorsement denunciation is malformed"
~pp:(fun ppf () ->
Format.fprintf ppf "Malformed double-endorsement denunciation")
Data_encoding.empty
(function Invalid_double_endorsement -> Some () | _ -> None)
(fun () -> Invalid_double_endorsement) ;
register_error_kind
`Permanent
~id:"block.inconsistent_double_endorsement"
~title:"Inconsistent double endorsement"
~description:"A double-endorsement denunciation is inconsistent \
\ (two distinct delegates)"
~pp:(fun ppf (delegate1, delegate2) ->
Format.fprintf ppf
"Inconsistent double-endorsement denunciation \
\ (distinct delegate: %a and %a)"
Ed25519.Public_key_hash.pp_short delegate1
Ed25519.Public_key_hash.pp_short delegate2)
Data_encoding.(obj2
(req "delegate1" Ed25519.Public_key_hash.encoding)
(req "delegate2" Ed25519.Public_key_hash.encoding))
(function
| Inconsistent_double_endorsement { delegate1 ; delegate2 } ->
Some (delegate1, delegate2)
| _ -> None)
(fun (delegate1, delegate2) ->
Inconsistent_double_endorsement { delegate1 ; delegate2 }) ;
register_error_kind
`Branch
~id:"block.unrequired_double_endorsement"
~title:"Unrequired double endorsement"
~description:"A double-endorsement denunciation is unrequired"
~pp:(fun ppf () ->
Format.fprintf ppf "A valid double-endorsement operation cannot \
\ be applied: the associated delegate \
\ has previously been denunciated in this cycle.")
Data_encoding.empty
(function Unrequired_double_endorsement -> Some () | _ -> None)
(fun () -> Unrequired_double_endorsement) ;
register_error_kind
`Temporary
~id:"block.too_early_double_endorsement"
~title:"Too early double endorsement"
~description:"A double-endorsement denunciation is in the future"
~pp:(fun ppf (level, current) ->
Format.fprintf ppf
"A double-endorsement denunciation is in the future \
\ (current level: %a, endorsement level: %a)"
Raw_level.pp current
Raw_level.pp level)
Data_encoding.(obj2
(req "level" Raw_level.encoding)
(req "current" Raw_level.encoding))
(function
| Too_early_double_endorsement { level ; current } ->
Some (level, current)
| _ -> None)
(fun (level, current) ->
Too_early_double_endorsement { level ; current }) ;
register_error_kind
`Permanent
~id:"block.outdated_double_endorsement"
~title:"Outdated double endorsement"
~description:"A double-endorsement denunciation is outdated."
~pp:(fun ppf (level, last) ->
Format.fprintf ppf
"A double-endorsement denunciation is outdated \
\ (last acceptable level: %a, endorsement level: %a)"
Raw_level.pp last
Raw_level.pp level)
Data_encoding.(obj2
(req "level" Raw_level.encoding)
(req "last" Raw_level.encoding))
(function
| Outdated_double_endorsement { level ; last } ->
Some (level, last)
| _ -> None)
(fun (level, last) ->
Outdated_double_endorsement { level ; last })
let apply_consensus_operation_content ctxt
pred_block block_priority operation = function
@ -292,6 +381,46 @@ let apply_anonymous_operation ctxt delegate origination_nonce kind =
Nonce.reveal ctxt level nonce >>=? fun ctxt ->
return (ctxt, origination_nonce,
Tez.zero, Constants.seed_nonce_revelation_tip)
| Double_endorsement { op1 ; op2 } -> begin
match op1.contents, op2.contents with
| Sourced_operations (Consensus_operation (Endorsements e1)),
Sourced_operations (Consensus_operation (Endorsements e2))
when Raw_level.(e1.level = e2.level) &&
not (Block_hash.equal e1.block e2.block) ->
let level = Level.from_raw ctxt e1.level in
let oldest_level = Level.last_allowed_fork_level ctxt in
fail_unless Level.(level < Level.current ctxt)
(Too_early_double_endorsement
{ level = level.level ;
current = (Level.current ctxt).level }) >>=? fun () ->
fail_unless Raw_level.(oldest_level <= level.level)
(Outdated_double_endorsement
{ level = level.level ;
last = oldest_level }) >>=? fun () ->
(* Whenever a delegate might have multiple endorsement slots for
given level, she should not endorse different block with different
slots. Hence, we don't check that [e1.slots] and [e2.slots]
intersect. *)
Baking.check_endorsements_rights ctxt level e1.slots >>=? fun delegate1 ->
Operation.check_signature delegate1 op1 >>=? fun () ->
Baking.check_endorsements_rights ctxt level e2.slots >>=? fun delegate2 ->
Operation.check_signature delegate2 op2 >>=? fun () ->
fail_unless
(Ed25519.Public_key.equal delegate1 delegate2)
(Inconsistent_double_endorsement
{ delegate1 = Ed25519.Public_key.hash delegate1 ;
delegate2 = Ed25519.Public_key.hash delegate2 }) >>=? fun () ->
let delegate = Ed25519.Public_key.hash delegate1 in
Delegate.has_frozen_balance ctxt delegate level.cycle >>=? fun valid ->
fail_unless valid Unrequired_double_endorsement >>=? fun () ->
Delegate.punish ctxt delegate level.cycle >>=? fun (ctxt, burned) ->
let reward =
match Tez.(burned /? 2L) with
| Ok v -> v
| Error _ -> Tez.zero in
return (ctxt, origination_nonce, Tez.zero, reward)
| _, _ -> fail Invalid_double_endorsement
end
| Faucet { id = manager ; _ } ->
(* Free tez for all! *)
if Compare.Int.(faucet_count ctxt < 5) then

View File

@ -261,7 +261,8 @@ let punish ctxt delegate cycle =
Storage.Contract.Frozen_bonds.remove (ctxt, contract) cycle >>= fun ctxt ->
Storage.Contract.Frozen_fees.remove (ctxt, contract) cycle >>= fun ctxt ->
Storage.Contract.Frozen_rewards.remove (ctxt, contract) cycle >>= fun ctxt ->
return ctxt
Lwt.return Tez_repr.(bond +? fees) >>=? fun burned ->
return (ctxt, burned)
let has_frozen_balance ctxt delegate cycle =

View File

@ -73,10 +73,10 @@ val cycle_end:
Raw_context.t tzresult Lwt.t
(** Burn all then frozen bond/fees/rewards for a delegate at a given
cycle. *)
cycle. Returns the burned amount. *)
val punish:
Raw_context.t -> Ed25519.Public_key_hash.t -> Cycle_repr.t ->
Raw_context.t tzresult Lwt.t
(Raw_context.t * Tez_repr.t) tzresult Lwt.t
(** Has the given key some frozen tokens in its implicit contract? *)
val has_frozen_balance:

View File

@ -31,6 +31,10 @@ and anonymous_operation =
level: Raw_level_repr.t ;
nonce: Seed_repr.nonce ;
}
| Double_endorsement of {
op1: operation ;
op2: operation ;
}
| Faucet of {
id: Ed25519.Public_key_hash.t ;
nonce: MBytes.t ;
@ -306,6 +310,20 @@ module Encoding = struct
)
(fun ((), level, nonce) -> Seed_nonce_revelation { level ; nonce })
let double_endorsement_encoding op_encoding =
(obj3
(req "kind" (constant "double_endorsement"))
(req "op1" (dynamic_size op_encoding))
(req "op2" (dynamic_size op_encoding)))
let double_endorsement_case tag op_encoding =
case tag (double_endorsement_encoding op_encoding)
(function
| Double_endorsement { op1 ; op2 } -> Some ((), op1, op2)
| _ -> None
)
(fun ((), op1, op2) -> Double_endorsement { op1 ; op2 })
let faucet_encoding =
(obj3
(req "kind" (constant "faucet"))
@ -320,48 +338,58 @@ module Encoding = struct
)
(fun ((), id, nonce) -> Faucet { id ; nonce })
let unsigned_operation_case tag =
let unsigned_operation_case tag op_encoding =
case tag
(obj1
(req "operations"
(list
(union [
seed_nonce_revelation_case (Tag 0) ;
faucet_case (Tag 1) ;
double_endorsement_case (Tag 1) op_encoding ;
faucet_case (Tag 2) ;
]))))
(function Anonymous_operations ops -> Some ops | _ -> None)
(fun ops -> Anonymous_operations ops)
let proto_operation_encoding =
let mu_proto_operation_encoding op_encoding =
union [
signed_operations_case (Tag 0) ;
unsigned_operation_case (Tag 1) ;
unsigned_operation_case (Tag 1) op_encoding ;
]
let mu_signed_proto_operation_encoding op_encoding =
merge_objs
(mu_proto_operation_encoding op_encoding)
(obj1 (varopt "signature" Ed25519.Signature.encoding))
let operation_encoding =
mu "operation"
(fun encoding ->
conv
(fun { shell ; contents ; signature } ->
(shell, (contents, signature)))
(fun (shell, (contents, signature)) ->
{ shell ; contents ; signature })
(merge_objs
Operation.shell_header_encoding
(mu_signed_proto_operation_encoding encoding)))
let proto_operation_encoding =
mu_proto_operation_encoding operation_encoding
let signed_proto_operation_encoding =
mu_signed_proto_operation_encoding operation_encoding
let unsigned_operation_encoding =
merge_objs
Operation.shell_header_encoding
proto_operation_encoding
let signed_proto_operation_encoding =
merge_objs
proto_operation_encoding
(obj1 (varopt "signature" Ed25519.Signature.encoding))
end
type error += Cannot_parse_operation
let encoding =
let open Data_encoding in
conv
(fun { shell ; contents ; signature } ->
(shell, (contents, signature)))
(fun (shell, (contents, signature)) ->
{ shell ; contents ; signature })
(merge_objs
Operation.shell_header_encoding
Encoding.signed_proto_operation_encoding)
let encoding = Encoding.operation_encoding
let () =
register_error_kind

View File

@ -31,6 +31,10 @@ and anonymous_operation =
level: Raw_level_repr.t ;
nonce: Seed_repr.nonce ;
}
| Double_endorsement of {
op1: operation ;
op2: operation ;
}
| Faucet of {
id: Ed25519.Public_key_hash.t ;
nonce: MBytes.t ;