Alpha: add operation Double_endorsement
This commit is contained in:
parent
e1a1f754aa
commit
09c1e317ab
@ -665,6 +665,7 @@ module Encoding = struct
|
|||||||
List.for_all (fun (Case { encoding = e }) -> is_obj e) cases
|
List.for_all (fun (Case { encoding = e }) -> is_obj e) cases
|
||||||
| Empty -> true
|
| Empty -> true
|
||||||
| Ignore -> true
|
| Ignore -> true
|
||||||
|
| Mu (_,_,self) -> is_obj (self e)
|
||||||
| _ -> false
|
| _ -> false
|
||||||
|
|
||||||
let rec is_tup : type a. a t -> bool = fun e ->
|
let rec is_tup : type a. a t -> bool = fun e ->
|
||||||
@ -675,6 +676,7 @@ module Encoding = struct
|
|||||||
| Dynamic_size e -> is_tup e
|
| Dynamic_size e -> is_tup e
|
||||||
| Union (_,_,cases) ->
|
| Union (_,_,cases) ->
|
||||||
List.for_all (function Case { encoding = e} -> is_tup e) cases
|
List.for_all (function Case { encoding = e} -> is_tup e) cases
|
||||||
|
| Mu (_,_,self) -> is_tup (self e)
|
||||||
| _ -> false
|
| _ -> false
|
||||||
|
|
||||||
let merge_objs o1 o2 =
|
let merge_objs o1 o2 =
|
||||||
|
@ -507,7 +507,7 @@ module Delegate : sig
|
|||||||
|
|
||||||
val punish:
|
val punish:
|
||||||
context -> public_key_hash -> Cycle.t ->
|
context -> public_key_hash -> Cycle.t ->
|
||||||
context tzresult Lwt.t
|
(context * Tez.t) tzresult Lwt.t
|
||||||
|
|
||||||
val has_frozen_balance:
|
val has_frozen_balance:
|
||||||
context -> public_key_hash -> Cycle.t ->
|
context -> public_key_hash -> Cycle.t ->
|
||||||
@ -582,6 +582,10 @@ and anonymous_operation =
|
|||||||
level: Raw_level.t ;
|
level: Raw_level.t ;
|
||||||
nonce: Nonce.t ;
|
nonce: Nonce.t ;
|
||||||
}
|
}
|
||||||
|
| Double_endorsement of {
|
||||||
|
op1: operation ;
|
||||||
|
op2: operation ;
|
||||||
|
}
|
||||||
| Faucet of {
|
| Faucet of {
|
||||||
id: Ed25519.Public_key_hash.t ;
|
id: Ed25519.Public_key_hash.t ;
|
||||||
nonce: MBytes.t ;
|
nonce: MBytes.t ;
|
||||||
|
@ -19,6 +19,12 @@ type error += Too_many_faucet
|
|||||||
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 += 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 () =
|
let () =
|
||||||
register_error_kind
|
register_error_kind
|
||||||
@ -107,7 +113,90 @@ let () =
|
|||||||
Format.fprintf ppf "Unexpected seed's nonce commitment in block header.")
|
Format.fprintf ppf "Unexpected seed's nonce commitment in block header.")
|
||||||
Data_encoding.(obj1 (req "expected "bool))
|
Data_encoding.(obj1 (req "expected "bool))
|
||||||
(function Invalid_commitment { expected } -> Some expected | _ -> None)
|
(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
|
let apply_consensus_operation_content ctxt
|
||||||
pred_block block_priority operation = function
|
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 ->
|
Nonce.reveal ctxt level nonce >>=? fun ctxt ->
|
||||||
return (ctxt, origination_nonce,
|
return (ctxt, origination_nonce,
|
||||||
Tez.zero, Constants.seed_nonce_revelation_tip)
|
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 ; _ } ->
|
| Faucet { id = manager ; _ } ->
|
||||||
(* Free tez for all! *)
|
(* Free tez for all! *)
|
||||||
if Compare.Int.(faucet_count ctxt < 5) then
|
if Compare.Int.(faucet_count ctxt < 5) then
|
||||||
|
@ -261,7 +261,8 @@ let punish ctxt delegate cycle =
|
|||||||
Storage.Contract.Frozen_bonds.remove (ctxt, contract) cycle >>= fun ctxt ->
|
Storage.Contract.Frozen_bonds.remove (ctxt, contract) cycle >>= fun ctxt ->
|
||||||
Storage.Contract.Frozen_fees.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 ->
|
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 =
|
let has_frozen_balance ctxt delegate cycle =
|
||||||
|
@ -73,10 +73,10 @@ val cycle_end:
|
|||||||
Raw_context.t tzresult Lwt.t
|
Raw_context.t tzresult Lwt.t
|
||||||
|
|
||||||
(** Burn all then frozen bond/fees/rewards for a delegate at a given
|
(** Burn all then frozen bond/fees/rewards for a delegate at a given
|
||||||
cycle. *)
|
cycle. Returns the burned amount. *)
|
||||||
val punish:
|
val punish:
|
||||||
Raw_context.t -> Ed25519.Public_key_hash.t -> Cycle_repr.t ->
|
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? *)
|
(** Has the given key some frozen tokens in its implicit contract? *)
|
||||||
val has_frozen_balance:
|
val has_frozen_balance:
|
||||||
|
@ -31,6 +31,10 @@ and anonymous_operation =
|
|||||||
level: Raw_level_repr.t ;
|
level: Raw_level_repr.t ;
|
||||||
nonce: Seed_repr.nonce ;
|
nonce: Seed_repr.nonce ;
|
||||||
}
|
}
|
||||||
|
| Double_endorsement of {
|
||||||
|
op1: operation ;
|
||||||
|
op2: operation ;
|
||||||
|
}
|
||||||
| Faucet of {
|
| Faucet of {
|
||||||
id: Ed25519.Public_key_hash.t ;
|
id: Ed25519.Public_key_hash.t ;
|
||||||
nonce: MBytes.t ;
|
nonce: MBytes.t ;
|
||||||
@ -306,6 +310,20 @@ module Encoding = struct
|
|||||||
)
|
)
|
||||||
(fun ((), level, nonce) -> Seed_nonce_revelation { level ; nonce })
|
(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 =
|
let faucet_encoding =
|
||||||
(obj3
|
(obj3
|
||||||
(req "kind" (constant "faucet"))
|
(req "kind" (constant "faucet"))
|
||||||
@ -320,40 +338,33 @@ module Encoding = struct
|
|||||||
)
|
)
|
||||||
(fun ((), id, nonce) -> Faucet { id ; nonce })
|
(fun ((), id, nonce) -> Faucet { id ; nonce })
|
||||||
|
|
||||||
let unsigned_operation_case tag =
|
let unsigned_operation_case tag op_encoding =
|
||||||
case tag
|
case tag
|
||||||
(obj1
|
(obj1
|
||||||
(req "operations"
|
(req "operations"
|
||||||
(list
|
(list
|
||||||
(union [
|
(union [
|
||||||
seed_nonce_revelation_case (Tag 0) ;
|
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)
|
(function Anonymous_operations ops -> Some ops | _ -> None)
|
||||||
(fun ops -> Anonymous_operations ops)
|
(fun ops -> Anonymous_operations ops)
|
||||||
|
|
||||||
let proto_operation_encoding =
|
let mu_proto_operation_encoding op_encoding =
|
||||||
union [
|
union [
|
||||||
signed_operations_case (Tag 0) ;
|
signed_operations_case (Tag 0) ;
|
||||||
unsigned_operation_case (Tag 1) ;
|
unsigned_operation_case (Tag 1) op_encoding ;
|
||||||
]
|
]
|
||||||
|
|
||||||
let unsigned_operation_encoding =
|
let mu_signed_proto_operation_encoding op_encoding =
|
||||||
merge_objs
|
merge_objs
|
||||||
Operation.shell_header_encoding
|
(mu_proto_operation_encoding op_encoding)
|
||||||
proto_operation_encoding
|
|
||||||
|
|
||||||
let signed_proto_operation_encoding =
|
|
||||||
merge_objs
|
|
||||||
proto_operation_encoding
|
|
||||||
(obj1 (varopt "signature" Ed25519.Signature.encoding))
|
(obj1 (varopt "signature" Ed25519.Signature.encoding))
|
||||||
|
|
||||||
end
|
let operation_encoding =
|
||||||
|
mu "operation"
|
||||||
type error += Cannot_parse_operation
|
(fun encoding ->
|
||||||
|
|
||||||
let encoding =
|
|
||||||
let open Data_encoding in
|
|
||||||
conv
|
conv
|
||||||
(fun { shell ; contents ; signature } ->
|
(fun { shell ; contents ; signature } ->
|
||||||
(shell, (contents, signature)))
|
(shell, (contents, signature)))
|
||||||
@ -361,7 +372,24 @@ let encoding =
|
|||||||
{ shell ; contents ; signature })
|
{ shell ; contents ; signature })
|
||||||
(merge_objs
|
(merge_objs
|
||||||
Operation.shell_header_encoding
|
Operation.shell_header_encoding
|
||||||
Encoding.signed_proto_operation_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
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
type error += Cannot_parse_operation
|
||||||
|
|
||||||
|
let encoding = Encoding.operation_encoding
|
||||||
|
|
||||||
let () =
|
let () =
|
||||||
register_error_kind
|
register_error_kind
|
||||||
|
@ -31,6 +31,10 @@ and anonymous_operation =
|
|||||||
level: Raw_level_repr.t ;
|
level: Raw_level_repr.t ;
|
||||||
nonce: Seed_repr.nonce ;
|
nonce: Seed_repr.nonce ;
|
||||||
}
|
}
|
||||||
|
| Double_endorsement of {
|
||||||
|
op1: operation ;
|
||||||
|
op2: operation ;
|
||||||
|
}
|
||||||
| Faucet of {
|
| Faucet of {
|
||||||
id: Ed25519.Public_key_hash.t ;
|
id: Ed25519.Public_key_hash.t ;
|
||||||
nonce: MBytes.t ;
|
nonce: MBytes.t ;
|
||||||
|
Loading…
Reference in New Issue
Block a user