Alpha: add operation Double_baking
This commit is contained in:
parent
09c1e317ab
commit
76d11fcafb
@ -25,9 +25,9 @@
|
|||||||
"Contract_repr",
|
"Contract_repr",
|
||||||
"Roll_repr",
|
"Roll_repr",
|
||||||
"Vote_repr",
|
"Vote_repr",
|
||||||
|
"Block_header_repr",
|
||||||
"Operation_repr",
|
"Operation_repr",
|
||||||
"Manager_repr",
|
"Manager_repr",
|
||||||
"Block_header_repr",
|
|
||||||
|
|
||||||
"Raw_context",
|
"Raw_context",
|
||||||
"Storage_sigs",
|
"Storage_sigs",
|
||||||
|
@ -87,6 +87,7 @@ module Raw_level : sig
|
|||||||
val succ: raw_level -> raw_level
|
val succ: raw_level -> raw_level
|
||||||
val pred: raw_level -> raw_level option
|
val pred: raw_level -> raw_level option
|
||||||
val to_int32: raw_level -> int32
|
val to_int32: raw_level -> int32
|
||||||
|
val of_int32: int32 -> raw_level tzresult
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -567,6 +568,56 @@ module Vote : sig
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
module Block_header : sig
|
||||||
|
|
||||||
|
type t = {
|
||||||
|
shell: Block_header.shell_header ;
|
||||||
|
protocol_data: protocol_data ;
|
||||||
|
signature: Ed25519.Signature.t ;
|
||||||
|
}
|
||||||
|
|
||||||
|
and protocol_data = {
|
||||||
|
priority: int ;
|
||||||
|
seed_nonce_hash: Nonce_hash.t option ;
|
||||||
|
proof_of_work_nonce: MBytes.t ;
|
||||||
|
}
|
||||||
|
|
||||||
|
type block_header = t
|
||||||
|
|
||||||
|
type raw = Block_header.t
|
||||||
|
type shell_header = Block_header.shell_header
|
||||||
|
|
||||||
|
val hash: block_header -> Block_hash.t
|
||||||
|
val hash_raw: raw -> Block_hash.t
|
||||||
|
|
||||||
|
val encoding: block_header Data_encoding.encoding
|
||||||
|
val raw_encoding: raw Data_encoding.t
|
||||||
|
val protocol_data_encoding: protocol_data Data_encoding.encoding
|
||||||
|
val shell_header_encoding: shell_header Data_encoding.encoding
|
||||||
|
|
||||||
|
val max_header_length: int
|
||||||
|
(** The maximum size of block headers in bytes *)
|
||||||
|
|
||||||
|
val parse: Block_header.t -> block_header tzresult
|
||||||
|
(** Parse the protocol-specific part of a block header. *)
|
||||||
|
|
||||||
|
val parse_unsigned_protocol_data: MBytes.t -> protocol_data tzresult
|
||||||
|
(** Parse the (unsigned) protocol-specific part of a block header. *)
|
||||||
|
|
||||||
|
val forge_unsigned_protocol_data: protocol_data -> MBytes.t
|
||||||
|
(** [forge_header proto_hdr] is the binary serialization
|
||||||
|
(using [protocol_data_encoding]) of the protocol-specific part
|
||||||
|
of a block header, without the signature. *)
|
||||||
|
|
||||||
|
val forge_unsigned:
|
||||||
|
Block_header.shell_header -> protocol_data -> MBytes.t
|
||||||
|
(** [forge_header shell_hdr proto_hdr] is the binary serialization
|
||||||
|
(using [unsigned_header_encoding]) of a block header,
|
||||||
|
comprising both the shell and the protocol part of the header,
|
||||||
|
without the signature. *)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
type operation = {
|
type operation = {
|
||||||
shell: Operation.shell_header ;
|
shell: Operation.shell_header ;
|
||||||
contents: proto_operation ;
|
contents: proto_operation ;
|
||||||
@ -586,6 +637,10 @@ and anonymous_operation =
|
|||||||
op1: operation ;
|
op1: operation ;
|
||||||
op2: operation ;
|
op2: operation ;
|
||||||
}
|
}
|
||||||
|
| Double_baking of {
|
||||||
|
bh1: Block_header.t ;
|
||||||
|
bh2: Block_header.t ;
|
||||||
|
}
|
||||||
| Faucet of {
|
| Faucet of {
|
||||||
id: Ed25519.Public_key_hash.t ;
|
id: Ed25519.Public_key_hash.t ;
|
||||||
nonce: MBytes.t ;
|
nonce: MBytes.t ;
|
||||||
@ -681,56 +736,6 @@ module Operation : sig
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
module Block_header : sig
|
|
||||||
|
|
||||||
type t = {
|
|
||||||
shell: Block_header.shell_header ;
|
|
||||||
protocol_data: protocol_data ;
|
|
||||||
signature: Ed25519.Signature.t ;
|
|
||||||
}
|
|
||||||
|
|
||||||
and protocol_data = {
|
|
||||||
priority: int ;
|
|
||||||
seed_nonce_hash: Nonce_hash.t option ;
|
|
||||||
proof_of_work_nonce: MBytes.t ;
|
|
||||||
}
|
|
||||||
|
|
||||||
type block_header = t
|
|
||||||
|
|
||||||
type raw = Block_header.t
|
|
||||||
type shell_header = Block_header.shell_header
|
|
||||||
|
|
||||||
val hash: block_header -> Block_hash.t
|
|
||||||
val hash_raw: raw -> Block_hash.t
|
|
||||||
|
|
||||||
val encoding: block_header Data_encoding.encoding
|
|
||||||
val raw_encoding: raw Data_encoding.t
|
|
||||||
val protocol_data_encoding: protocol_data Data_encoding.encoding
|
|
||||||
val shell_header_encoding: shell_header Data_encoding.encoding
|
|
||||||
|
|
||||||
val max_header_length: int
|
|
||||||
(** The maximum size of block headers in bytes *)
|
|
||||||
|
|
||||||
val parse: Block_header.t -> block_header tzresult
|
|
||||||
(** Parse the protocol-specific part of a block header. *)
|
|
||||||
|
|
||||||
val parse_unsigned_protocol_data: MBytes.t -> protocol_data tzresult
|
|
||||||
(** Parse the (unsigned) protocol-specific part of a block header. *)
|
|
||||||
|
|
||||||
val forge_unsigned_protocol_data: protocol_data -> MBytes.t
|
|
||||||
(** [forge_header proto_hdr] is the binary serialization
|
|
||||||
(using [protocol_data_encoding]) of the protocol-specific part
|
|
||||||
of a block header, without the signature. *)
|
|
||||||
|
|
||||||
val forge_unsigned:
|
|
||||||
Block_header.shell_header -> protocol_data -> MBytes.t
|
|
||||||
(** [forge_header shell_hdr proto_hdr] is the binary serialization
|
|
||||||
(using [unsigned_header_encoding]) of a block header,
|
|
||||||
comprising both the shell and the protocol part of the header,
|
|
||||||
without the signature. *)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
module Roll : sig
|
module Roll : sig
|
||||||
|
|
||||||
val value: context -> Tez.t
|
val value: context -> Tez.t
|
||||||
|
@ -26,6 +26,14 @@ type error += Too_early_double_endorsement of { level: Raw_level.t ; current: Ra
|
|||||||
type error += Outdated_double_endorsement of { level: Raw_level.t ; last: Raw_level.t } (* `Permanent *)
|
type error += Outdated_double_endorsement of { level: Raw_level.t ; last: Raw_level.t } (* `Permanent *)
|
||||||
|
|
||||||
|
|
||||||
|
type error += Invalid_double_baking of { level1: Int32.t ; level2: Int32.t } (* `Permanent *)
|
||||||
|
type error += Inconsistent_double_baking of { delegate1: Ed25519.Public_key_hash.t ; delegate2: Ed25519.Public_key_hash.t } (* `Permanent *)
|
||||||
|
type error += Unrequired_double_baking (* `Branch*)
|
||||||
|
type error += Too_early_double_baking of { level: Raw_level.t ; current: Raw_level.t } (* `Temporary *)
|
||||||
|
type error += Outdated_double_baking of { level: Raw_level.t ; last: Raw_level.t } (* `Permanent *)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let () =
|
let () =
|
||||||
register_error_kind
|
register_error_kind
|
||||||
`Temporary
|
`Temporary
|
||||||
@ -196,7 +204,97 @@ let () =
|
|||||||
Some (level, last)
|
Some (level, last)
|
||||||
| _ -> None)
|
| _ -> None)
|
||||||
(fun (level, last) ->
|
(fun (level, last) ->
|
||||||
Outdated_double_endorsement { level ; last })
|
Outdated_double_endorsement { level ; last }) ;
|
||||||
|
register_error_kind
|
||||||
|
`Permanent
|
||||||
|
~id:"block.invalid_double_baking"
|
||||||
|
~title:"Invalid double baking"
|
||||||
|
~description:"A double-baking denunciation is inconsistent \
|
||||||
|
\ (two distinct level)"
|
||||||
|
~pp:(fun ppf (level1, level2) ->
|
||||||
|
Format.fprintf ppf
|
||||||
|
"Inconsistent double-baking denunciation (levels: %ld and %ld)"
|
||||||
|
level1 level2)
|
||||||
|
Data_encoding.(obj2
|
||||||
|
(req "level1" int32)
|
||||||
|
(req "level2" int32))
|
||||||
|
(function
|
||||||
|
| Invalid_double_baking { level1 ; level2 } -> Some (level1, level2)
|
||||||
|
| _ -> None)
|
||||||
|
(fun (level1, level2) -> Invalid_double_baking { level1 ; level2 }) ;
|
||||||
|
register_error_kind
|
||||||
|
`Permanent
|
||||||
|
~id:"block.inconsistent_double_baking"
|
||||||
|
~title:"Inconsistent double baking"
|
||||||
|
~description:"A double-baking denunciation is inconsistent \
|
||||||
|
\ (two distinct delegates)"
|
||||||
|
~pp:(fun ppf (delegate1, delegate2) ->
|
||||||
|
Format.fprintf ppf
|
||||||
|
"Inconsistent double-baking 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_baking { delegate1 ; delegate2 } ->
|
||||||
|
Some (delegate1, delegate2)
|
||||||
|
| _ -> None)
|
||||||
|
(fun (delegate1, delegate2) ->
|
||||||
|
Inconsistent_double_baking { delegate1 ; delegate2 }) ;
|
||||||
|
register_error_kind
|
||||||
|
`Branch
|
||||||
|
~id:"block.unrequired_double_baking"
|
||||||
|
~title:"Unrequired double baking"
|
||||||
|
~description:"A double-baking denunciation is unrequired"
|
||||||
|
~pp:(fun ppf () ->
|
||||||
|
Format.fprintf ppf "A valid double-baking operation cannot \
|
||||||
|
\ be applied: the associated delegate \
|
||||||
|
\ has previously been denunciated in this cycle.")
|
||||||
|
Data_encoding.empty
|
||||||
|
(function Unrequired_double_baking -> Some () | _ -> None)
|
||||||
|
(fun () -> Unrequired_double_baking) ;
|
||||||
|
register_error_kind
|
||||||
|
`Temporary
|
||||||
|
~id:"block.too_early_double_baking"
|
||||||
|
~title:"Too early double baking"
|
||||||
|
~description:"A double-baking denunciation is in the future"
|
||||||
|
~pp:(fun ppf (level, current) ->
|
||||||
|
Format.fprintf ppf
|
||||||
|
"A double-baking denunciation is in the future \
|
||||||
|
\ (current level: %a, baking 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_baking { level ; current } ->
|
||||||
|
Some (level, current)
|
||||||
|
| _ -> None)
|
||||||
|
(fun (level, current) ->
|
||||||
|
Too_early_double_baking { level ; current }) ;
|
||||||
|
register_error_kind
|
||||||
|
`Permanent
|
||||||
|
~id:"block.outdated_double_baking"
|
||||||
|
~title:"Outdated double baking"
|
||||||
|
~description:"A double-baking denunciation is outdated."
|
||||||
|
~pp:(fun ppf (level, last) ->
|
||||||
|
Format.fprintf ppf
|
||||||
|
"A double-baking denunciation is outdated \
|
||||||
|
\ (last acceptable level: %a, baking 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_baking { level ; last } ->
|
||||||
|
Some (level, last)
|
||||||
|
| _ -> None)
|
||||||
|
(fun (level, last) ->
|
||||||
|
Outdated_double_baking { 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
|
||||||
@ -421,6 +519,42 @@ let apply_anonymous_operation ctxt delegate origination_nonce kind =
|
|||||||
return (ctxt, origination_nonce, Tez.zero, reward)
|
return (ctxt, origination_nonce, Tez.zero, reward)
|
||||||
| _, _ -> fail Invalid_double_endorsement
|
| _, _ -> fail Invalid_double_endorsement
|
||||||
end
|
end
|
||||||
|
| Double_baking { bh1 ; bh2 } ->
|
||||||
|
fail_unless Compare.Int32.(bh1.shell.level = bh2.shell.level)
|
||||||
|
(Invalid_double_baking
|
||||||
|
{ level1 = bh1.shell.level ;
|
||||||
|
level2 = bh2.shell.level }) >>=? fun () ->
|
||||||
|
Lwt.return (Raw_level.of_int32 bh1.shell.level) >>=? fun raw_level ->
|
||||||
|
let oldest_level = Level.last_allowed_fork_level ctxt in
|
||||||
|
fail_unless Raw_level.(raw_level < (Level.current ctxt).level)
|
||||||
|
(Too_early_double_baking
|
||||||
|
{ level = raw_level ;
|
||||||
|
current = (Level.current ctxt).level }) >>=? fun () ->
|
||||||
|
fail_unless Raw_level.(oldest_level <= raw_level)
|
||||||
|
(Outdated_double_baking
|
||||||
|
{ level = raw_level ;
|
||||||
|
last = oldest_level }) >>=? fun () ->
|
||||||
|
let level = Level.from_raw ctxt raw_level in
|
||||||
|
Roll.baking_rights_owner
|
||||||
|
ctxt level ~priority:bh1.protocol_data.priority >>=? fun delegate1 ->
|
||||||
|
Baking.check_signature bh1 delegate1 >>=? fun () ->
|
||||||
|
Roll.baking_rights_owner
|
||||||
|
ctxt level ~priority:bh2.protocol_data.priority >>=? fun delegate2 ->
|
||||||
|
Baking.check_signature bh2 delegate2 >>=? fun () ->
|
||||||
|
fail_unless
|
||||||
|
(Ed25519.Public_key.equal delegate1 delegate2)
|
||||||
|
(Inconsistent_double_baking
|
||||||
|
{ 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_baking >>=? 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)
|
||||||
| 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
|
||||||
|
@ -35,6 +35,10 @@ and anonymous_operation =
|
|||||||
op1: operation ;
|
op1: operation ;
|
||||||
op2: operation ;
|
op2: operation ;
|
||||||
}
|
}
|
||||||
|
| Double_baking of {
|
||||||
|
bh1: Block_header_repr.t ;
|
||||||
|
bh2: Block_header_repr.t ;
|
||||||
|
}
|
||||||
| Faucet of {
|
| Faucet of {
|
||||||
id: Ed25519.Public_key_hash.t ;
|
id: Ed25519.Public_key_hash.t ;
|
||||||
nonce: MBytes.t ;
|
nonce: MBytes.t ;
|
||||||
@ -324,6 +328,20 @@ module Encoding = struct
|
|||||||
)
|
)
|
||||||
(fun ((), op1, op2) -> Double_endorsement { op1 ; op2 })
|
(fun ((), op1, op2) -> Double_endorsement { op1 ; op2 })
|
||||||
|
|
||||||
|
let double_baking_encoding =
|
||||||
|
(obj3
|
||||||
|
(req "kind" (constant "double_baking"))
|
||||||
|
(req "op1" (dynamic_size Block_header_repr.encoding))
|
||||||
|
(req "op2" (dynamic_size Block_header_repr.encoding)))
|
||||||
|
|
||||||
|
let double_baking_case tag =
|
||||||
|
case tag double_baking_encoding
|
||||||
|
(function
|
||||||
|
| Double_baking { bh1 ; bh2 } -> Some ((), bh1, bh2)
|
||||||
|
| _ -> None
|
||||||
|
)
|
||||||
|
(fun ((), bh1, bh2) -> Double_baking { bh1 ; bh2 })
|
||||||
|
|
||||||
let faucet_encoding =
|
let faucet_encoding =
|
||||||
(obj3
|
(obj3
|
||||||
(req "kind" (constant "faucet"))
|
(req "kind" (constant "faucet"))
|
||||||
@ -346,7 +364,8 @@ module Encoding = struct
|
|||||||
(union [
|
(union [
|
||||||
seed_nonce_revelation_case (Tag 0) ;
|
seed_nonce_revelation_case (Tag 0) ;
|
||||||
double_endorsement_case (Tag 1) op_encoding ;
|
double_endorsement_case (Tag 1) op_encoding ;
|
||||||
faucet_case (Tag 2) ;
|
double_baking_case (Tag 2) ;
|
||||||
|
faucet_case (Tag 3) ;
|
||||||
]))))
|
]))))
|
||||||
(function Anonymous_operations ops -> Some ops | _ -> None)
|
(function Anonymous_operations ops -> Some ops | _ -> None)
|
||||||
(fun ops -> Anonymous_operations ops)
|
(fun ops -> Anonymous_operations ops)
|
||||||
|
@ -35,6 +35,10 @@ and anonymous_operation =
|
|||||||
op1: operation ;
|
op1: operation ;
|
||||||
op2: operation ;
|
op2: operation ;
|
||||||
}
|
}
|
||||||
|
| Double_baking of {
|
||||||
|
bh1: Block_header_repr.t ;
|
||||||
|
bh2: Block_header_repr.t ;
|
||||||
|
}
|
||||||
| 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