Tests: add tests for double endorsement and double baking
This commit is contained in:
parent
7505a66904
commit
6e65a12206
164
src/proto_alpha/lib_protocol/test/double_baking.ml
Normal file
164
src/proto_alpha/lib_protocol/test/double_baking.ml
Normal file
@ -0,0 +1,164 @@
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Copyright (c) 2014 - 2018. *)
|
||||
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||
(* *)
|
||||
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(** Double baking evidence operation may happen when a baker
|
||||
baked two different blocks on the same level. *)
|
||||
|
||||
open Proto_alpha
|
||||
open Alpha_context
|
||||
|
||||
(****************************************************************)
|
||||
(* Utility functions *)
|
||||
(****************************************************************)
|
||||
|
||||
let get_first_different_baker baker bakers =
|
||||
return @@ List.find (fun baker' ->
|
||||
Signature.Public_key_hash.(<>) baker baker')
|
||||
bakers
|
||||
|
||||
let get_first_different_bakers ctxt =
|
||||
Context.get_bakers ctxt >>=? fun bakers ->
|
||||
let baker_1 = List.hd bakers in
|
||||
get_first_different_baker baker_1 (List.tl bakers) >>=? fun baker_2 ->
|
||||
return (baker_1, baker_2)
|
||||
|
||||
let get_first_different_endorsers ctxt =
|
||||
Context.get_endorsers ctxt >>=? fun endorsers ->
|
||||
let endorsers = List.combine endorsers (0--((List.length endorsers) - 1)) in
|
||||
let endorser_1 = List.hd endorsers in
|
||||
let endorser_2 =
|
||||
List.find (fun (endorser, _slot) ->
|
||||
Signature.Public_key_hash.(<>)
|
||||
(fst endorser_1) endorser)
|
||||
(List.tl endorsers)
|
||||
in
|
||||
return (endorser_1, endorser_2)
|
||||
|
||||
(** Bake two block at the same level using the same policy (i.e. same
|
||||
baker) *)
|
||||
let block_fork ?policy contracts b =
|
||||
let (contract_a, contract_b) =
|
||||
List.hd contracts, List.hd (List.tl contracts) in
|
||||
Op.transaction (B b) contract_a contract_b Alpha_context.Tez.one_cent >>=? fun operation ->
|
||||
Block.bake ?policy ~operation b >>=? fun blk_a ->
|
||||
Block.bake ?policy b >>=? fun blk_b ->
|
||||
return (blk_a, blk_b)
|
||||
|
||||
(****************************************************************)
|
||||
(* Tests *)
|
||||
(****************************************************************)
|
||||
|
||||
(** Simple scenario where two blocks are baked by a same baker and
|
||||
exposed by a double baking evidence operation *)
|
||||
let valid_double_baking_evidence () =
|
||||
Context.init 2 >>=? fun (b, contracts) ->
|
||||
|
||||
Context.get_bakers (B b) >>=? fun bakers ->
|
||||
let priority_0_baker = List.hd bakers in
|
||||
|
||||
block_fork ~policy:(By_priority 0) contracts b >>=? fun (blk_a, blk_b) ->
|
||||
|
||||
Op.double_baking (B blk_a) blk_a.header blk_b.header >>=? fun operation ->
|
||||
Block.bake ~policy:(Excluding [ priority_0_baker ]) ~operation blk_a >>=? fun blk ->
|
||||
|
||||
(* Check that the frozen deposit, the fees and rewards are removed *)
|
||||
iter_s (fun kind ->
|
||||
let contract = Alpha_context.Contract.implicit_contract priority_0_baker in
|
||||
Assert.balance_is ~loc:__LOC__ (B blk) contract ~kind Tez.zero)
|
||||
[ Deposit ; Fees ; Rewards ]
|
||||
(* TODO : check also that the baker receive half of the bad baker's frozen balance *)
|
||||
|
||||
(****************************************************************)
|
||||
(* The following test scenarios are supposed to raise errors. *)
|
||||
(****************************************************************)
|
||||
|
||||
(** Check that a double baking operation fails if it exposes the same two blocks *)
|
||||
let same_blocks () =
|
||||
Context.init 2 >>=? fun (b, _contracts) ->
|
||||
Block.bake b >>=? fun ba ->
|
||||
Op.double_baking (B ba) ba.header ba.header >>=? fun operation ->
|
||||
Block.bake ~operation ba >>=? fun _ ->
|
||||
(* TODO: should fail *)
|
||||
return ()
|
||||
|
||||
(** Check that a double baking operation exposing two blocks with
|
||||
different levels fails *)
|
||||
let different_levels () =
|
||||
Context.init 2 >>=? fun (b, contracts) ->
|
||||
|
||||
block_fork ~policy:(By_priority 0) contracts b >>=? fun (blk_a, blk_b) ->
|
||||
|
||||
Block.bake blk_b >>=? fun blk_b_2 ->
|
||||
|
||||
Op.double_baking (B blk_a) blk_a.header blk_b_2.header >>=? fun operation ->
|
||||
Block.bake ~operation blk_a >>= fun res ->
|
||||
Assert.proto_error ~loc:__LOC__ res begin function
|
||||
| Apply.Invalid_double_baking_evidence _ -> true
|
||||
| _ -> false end
|
||||
|
||||
(** Check that a double baking operation exposing two yet to be baked
|
||||
blocks fails *)
|
||||
let too_early_double_baking_evidence () =
|
||||
Context.init 2 >>=? fun (b, contracts) ->
|
||||
block_fork ~policy:(By_priority 0) contracts b >>=? fun (blk_a, blk_b) ->
|
||||
|
||||
Op.double_baking (B b) blk_a.header blk_b.header >>=? fun operation ->
|
||||
Block.bake ~operation b >>= fun res ->
|
||||
Assert.proto_error ~loc:__LOC__ res begin function
|
||||
| Apply.Too_early_double_baking_evidence _ -> true
|
||||
| _ -> false end
|
||||
|
||||
(** Check that after [preserved_cycles + 1], it is not possible to
|
||||
create a double baking operation anymore *)
|
||||
let too_late_double_baking_evidence () =
|
||||
Context.init 2 >>=? fun (b, contracts) ->
|
||||
Context.get_constants (B b)
|
||||
>>=? fun Constants.{ parametric = { preserved_cycles ; _ } ; _ } ->
|
||||
|
||||
block_fork ~policy:(By_priority 0) contracts b >>=? fun (blk_a, blk_b) ->
|
||||
|
||||
fold_left_s (fun blk _ -> Block.bake_until_cycle_end blk)
|
||||
blk_a (1 -- (preserved_cycles + 1)) >>=? fun blk ->
|
||||
|
||||
Op.double_baking (B blk) blk_a.header blk_b.header >>=? fun operation ->
|
||||
Block.bake ~operation blk >>= fun res ->
|
||||
Assert.proto_error ~loc:__LOC__ res begin function
|
||||
| Apply.Outdated_double_baking_evidence _ -> true
|
||||
| _ -> false end
|
||||
|
||||
(** Check that an invalid double baking evidence that exposes two block
|
||||
baking with same level made by different bakers fails *)
|
||||
let different_delegates () =
|
||||
Context.init 2 >>=? fun (b, _) ->
|
||||
|
||||
get_first_different_bakers (B b) >>=? fun (baker_1, baker_2) ->
|
||||
Block.bake ~policy:(By_account baker_1) b >>=? fun blk_a ->
|
||||
Block.bake ~policy:(By_account baker_2) b >>=? fun blk_b ->
|
||||
|
||||
Op.double_baking (B blk_a) blk_a.header blk_b.header >>=? fun operation ->
|
||||
Block.bake ~operation blk_a >>= fun e ->
|
||||
Assert.proto_error ~loc:__LOC__ e begin function
|
||||
| Apply.Inconsistent_double_baking_evidence _ -> true
|
||||
| _ -> false end
|
||||
|
||||
let wrong_delegate () =
|
||||
(* TODO: change bake and forge_header "policy" so that it can force
|
||||
a baker **and** a priority *)
|
||||
return ()
|
||||
|
||||
let tests = [
|
||||
Test.tztest "valid double baking evidence" `Quick valid_double_baking_evidence ;
|
||||
|
||||
(* Should fail*)
|
||||
(* Test.tztest "same blocks" `Quick same_blocks ; *)
|
||||
Test.tztest "different levels" `Quick different_levels ;
|
||||
Test.tztest "too early double baking evidence" `Quick too_early_double_baking_evidence ;
|
||||
Test.tztest "too late double baking evidence" `Quick too_late_double_baking_evidence ;
|
||||
Test.tztest "different delegates" `Quick different_delegates ;
|
||||
]
|
182
src/proto_alpha/lib_protocol/test/double_endorsement.ml
Normal file
182
src/proto_alpha/lib_protocol/test/double_endorsement.ml
Normal file
@ -0,0 +1,182 @@
|
||||
(**************************************************************************)
|
||||
(* *)
|
||||
(* Copyright (c) 2014 - 2018. *)
|
||||
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
|
||||
(* *)
|
||||
(* All rights reserved. No warranty, explicit or implicit, provided. *)
|
||||
(* *)
|
||||
(**************************************************************************)
|
||||
|
||||
(** Double endorsement evidence operation may happen when an endorser
|
||||
endorsed two different blocks on the same level. *)
|
||||
|
||||
open Proto_alpha
|
||||
open Alpha_context
|
||||
|
||||
(****************************************************************)
|
||||
(* Utility functions *)
|
||||
(****************************************************************)
|
||||
|
||||
let get_first_different_baker baker bakers =
|
||||
return @@ List.find (fun baker' ->
|
||||
Signature.Public_key_hash.(<>) baker baker')
|
||||
bakers
|
||||
|
||||
let get_first_different_bakers ctxt =
|
||||
Context.get_bakers ctxt >>=? fun bakers ->
|
||||
let baker_1 = List.hd bakers in
|
||||
get_first_different_baker baker_1 (List.tl bakers) >>=? fun baker_2 ->
|
||||
return (baker_1, baker_2)
|
||||
|
||||
let get_first_different_endorsers ctxt =
|
||||
Context.get_endorsers ctxt >>=? fun endorsers ->
|
||||
let endorsers = List.combine endorsers (0--((List.length endorsers) - 1)) in
|
||||
let endorser_1 = List.hd endorsers in
|
||||
let endorser_2 =
|
||||
List.find (fun (endorser, _slot) ->
|
||||
Signature.Public_key_hash.(<>)
|
||||
(fst endorser_1) endorser)
|
||||
(List.tl endorsers)
|
||||
in
|
||||
return (endorser_1, endorser_2)
|
||||
|
||||
let block_fork b =
|
||||
get_first_different_bakers (B b) >>=? fun (baker_1, baker_2) ->
|
||||
Block.bake ~policy:(By_account baker_1) b >>=? fun blk_a ->
|
||||
Block.bake ~policy:(By_account baker_2) b >>=? fun blk_b ->
|
||||
return (blk_a, blk_b)
|
||||
|
||||
(****************************************************************)
|
||||
(* Tests *)
|
||||
(****************************************************************)
|
||||
|
||||
(** Simple scenario where two endorsements are made from the same
|
||||
delegate and exposed by a double_endorsement operation. Also verify
|
||||
that punishment is operated. *)
|
||||
let valid_double_endorsement_evidence () =
|
||||
Context.init 2 >>=? fun (b, _) ->
|
||||
|
||||
block_fork b >>=? fun (blk_a, blk_b) ->
|
||||
|
||||
Context.get_endorser (B blk_a) 0 >>=? fun delegate ->
|
||||
Op.endorsement ~delegate (B blk_a) 0 >>=? fun endorsement_a ->
|
||||
Op.endorsement ~delegate (B blk_b) 0 >>=? fun endorsement_b ->
|
||||
Block.bake ~operations:[endorsement_a] blk_a >>=? fun blk_a ->
|
||||
(* Block.bake ~operations:[endorsement_b] blk_b >>=? fun _ -> *)
|
||||
|
||||
Op.double_endorsement (B blk_a) endorsement_a endorsement_b >>=? fun operation ->
|
||||
|
||||
(* Bake with someone different than the bad endorser *)
|
||||
Context.get_bakers (B blk_a) >>=? fun bakers ->
|
||||
get_first_different_baker delegate bakers >>=? fun baker ->
|
||||
|
||||
Block.bake ~policy:(By_account baker) ~operation blk_a >>=? fun blk ->
|
||||
|
||||
(* Check that the frozen deposit, the fees and rewards are removed *)
|
||||
iter_s (fun kind ->
|
||||
let contract = Alpha_context.Contract.implicit_contract delegate in
|
||||
Assert.balance_is ~loc:__LOC__ (B blk) contract ~kind Tez.zero)
|
||||
[ Deposit ; Fees ; Rewards ]
|
||||
(* TODO : check also that the baker receive half of the bad endorser's frozen balance *)
|
||||
|
||||
(****************************************************************)
|
||||
(* The following test scenarios are supposed to raise errors. *)
|
||||
(****************************************************************)
|
||||
|
||||
(** Check that an invalid double endorsement operation that exposes a valid
|
||||
endorsement fails. *)
|
||||
let invalid_double_endorsement () =
|
||||
Context.init 10 >>=? fun (b, _) ->
|
||||
Block.bake b >>=? fun b ->
|
||||
|
||||
Op.endorsement (B b) 0 >>=? fun endorsement ->
|
||||
Block.bake ~operation:endorsement b >>=? fun b ->
|
||||
|
||||
Op.double_endorsement (B b) endorsement endorsement >>=? fun operation ->
|
||||
Block.bake ~operation b >>= fun res ->
|
||||
Assert.proto_error ~loc:__LOC__ res begin function
|
||||
| Apply.Invalid_double_endorsement_evidence -> true
|
||||
| _ -> false end
|
||||
|
||||
(** Check that a double endorsement added at the same time as a double
|
||||
endorsement operation fails. *)
|
||||
let too_early_double_endorsement_evidence () =
|
||||
Context.init 2 >>=? fun (b, _) ->
|
||||
block_fork b >>=? fun (blk_a, blk_b) ->
|
||||
|
||||
Context.get_endorser (B blk_a) 0 >>=? fun delegate ->
|
||||
Op.endorsement ~delegate (B blk_a) 0 >>=? fun endorsement_a ->
|
||||
Op.endorsement ~delegate (B blk_b) 0 >>=? fun endorsement_b ->
|
||||
|
||||
Op.double_endorsement (B b) endorsement_a endorsement_b >>=? fun operation ->
|
||||
Block.bake ~operation b >>= fun res ->
|
||||
Assert.proto_error ~loc:__LOC__ res begin function
|
||||
| Apply.Too_early_double_endorsement_evidence _ -> true
|
||||
| _ -> false end
|
||||
|
||||
(** Check that after [preserved_cycles + 1], it is not possible
|
||||
to create a double_endorsement anymore. *)
|
||||
let too_late_double_endorsement_evidence () =
|
||||
Context.init 2 >>=? fun (b, _) ->
|
||||
Context.get_constants (B b)
|
||||
>>=? fun Constants.{ parametric = { preserved_cycles ; _ } ; _ } ->
|
||||
|
||||
block_fork b >>=? fun (blk_a, blk_b) ->
|
||||
|
||||
Context.get_endorser (B blk_a) 0 >>=? fun delegate ->
|
||||
Op.endorsement ~delegate (B blk_a) 0 >>=? fun endorsement_a ->
|
||||
Op.endorsement ~delegate (B blk_b) 0 >>=? fun endorsement_b ->
|
||||
|
||||
fold_left_s (fun blk _ -> Block.bake_until_cycle_end blk)
|
||||
blk_a (1 -- (preserved_cycles + 1)) >>=? fun blk ->
|
||||
|
||||
Op.double_endorsement (B blk) endorsement_a endorsement_b >>=? fun operation ->
|
||||
Block.bake ~operation blk >>= fun res ->
|
||||
Assert.proto_error ~loc:__LOC__ res begin function
|
||||
| Apply.Outdated_double_endorsement_evidence _ -> true
|
||||
| _ -> false end
|
||||
|
||||
(** Check that an invalid double endorsement evidence that expose two
|
||||
endorsements made by two different endorsers fails. *)
|
||||
let different_delegates () =
|
||||
Context.init 2 >>=? fun (b, _) ->
|
||||
|
||||
block_fork b >>=? fun (blk_a, blk_b) ->
|
||||
get_first_different_endorsers (B blk_a)
|
||||
>>=? fun ((endorser_a, slot_a), (endorser_b, slot_b)) ->
|
||||
|
||||
Op.endorsement ~delegate:endorser_a (B blk_a) slot_a >>=? fun e_a ->
|
||||
Op.endorsement ~delegate:endorser_b (B blk_b) slot_b >>=? fun e_b ->
|
||||
Op.double_endorsement (B blk_a) e_a e_b >>=? fun operation ->
|
||||
Block.bake ~operation blk_a >>= fun res ->
|
||||
Assert.proto_error ~loc:__LOC__ res begin function
|
||||
| Apply.Inconsistent_double_endorsement_evidence _ -> true
|
||||
| _ -> false end
|
||||
|
||||
(** Check that a double endorsement evidence that exposes a ill-formed
|
||||
endorsement fails. *)
|
||||
let wrong_delegate () =
|
||||
Context.init 2 >>=? fun (b, _) ->
|
||||
|
||||
block_fork b >>=? fun (blk_a, blk_b) ->
|
||||
get_first_different_endorsers (B blk_a)
|
||||
>>=? fun ((_endorser_a, slot_a), (endorser_b, slot_b)) ->
|
||||
|
||||
Op.endorsement ~delegate:endorser_b (B blk_a) slot_a >>=? fun endorsement_a ->
|
||||
Op.endorsement ~delegate:endorser_b (B blk_b) slot_b >>=? fun endorsement_b ->
|
||||
|
||||
Op.double_endorsement (B blk_a) endorsement_a endorsement_b >>=? fun operation ->
|
||||
Block.bake ~operation blk_a >>= fun e ->
|
||||
Assert.proto_error ~loc:__LOC__ e begin function
|
||||
| Operation_repr.Invalid_signature -> true
|
||||
| _ -> false end
|
||||
|
||||
let tests = [
|
||||
Test.tztest "valid double endorsement evidence" `Quick valid_double_endorsement_evidence ;
|
||||
|
||||
Test.tztest "invalid double endorsement evidence" `Quick invalid_double_endorsement ;
|
||||
Test.tztest "too early double endorsement evidence" `Quick too_early_double_endorsement_evidence ;
|
||||
Test.tztest "too late double endorsement evidence" `Quick too_late_double_endorsement_evidence ;
|
||||
Test.tztest "different delegates" `Quick different_delegates ;
|
||||
Test.tztest "wrong delegate" `Quick wrong_delegate ;
|
||||
]
|
@ -13,4 +13,6 @@ let () =
|
||||
"origination", Origination.tests ;
|
||||
"activation", Activation.tests ;
|
||||
"endorsement", Endorsement.tests ;
|
||||
"double endorsement", Double_endorsement.tests ;
|
||||
"double baking", Double_baking.tests ;
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user