Tests: add tests for endorsement and activation operations

This commit is contained in:
Vincent Botbol 2018-06-04 14:38:20 +02:00 committed by Grégoire Henry
parent d9a11caeb8
commit 7505a66904
3 changed files with 598 additions and 0 deletions

View File

@ -0,0 +1,350 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
(** The activation operation creates an implicit contract from a
registered commitment present in the context. It is parametrized by
a public key hash (pkh) and a secret.
The commitments are composed of :
- half a pkh ;
- a blinded pkh that can be revealed by the secret ;
- an amount.
The commitments and the secrets are generated from
/scripts/create_genesis/create_genenis.py and should be coherent.
*)
open Proto_alpha
open Alpha_context
open Test_utils
open Test_tez
(* Generated commitments and secrets *)
let commitments =
List.map (fun (bpkh, a) ->
Commitment_repr.{
blinded_public_key_hash=Blinded_public_key_hash.of_b58check_exn bpkh ;
amount = Tez_repr.of_mutez_exn (Int64.of_string a)}
)
[ ( "btz1bRL4X5BWo2Fj4EsBdUwexXqgTf75uf1qa", "23932454669343" ) ;
( "btz1SxjV1syBgftgKy721czKi3arVkVwYUFSv", "72954577464032" ) ;
( "btz1LtoNCjiW23txBTenALaf5H6NKF1L3c1gw", "217487035428349" ) ;
( "btz1SUd3mMhEBcWudrn8u361MVAec4WYCcFoy", "4092742372031" ) ;
( "btz1MvBXf4orko1tsGmzkjLbpYSgnwUjEe81r", "17590039016550" ) ;
( "btz1LoDZ3zsjgG3k3cqTpUMc9bsXbchu9qMXT", "26322312350555" ) ;
( "btz1RMfq456hFV5AeDiZcQuZhoMv2dMpb9hpP", "244951387881443" ) ;
( "btz1Y9roTh4A7PsMBkp8AgdVFrqUDNaBE59y1", "80065050465525" ) ;
( "btz1Q1N2ePwhVw5ED3aaRVek6EBzYs1GDkSVD", "3569618927693" ) ;
( "btz1VFFVsVMYHd5WfaDTAt92BeQYGK8Ri4eLy", "9034781424478" ) ;
]
type secret_account = {
account : public_key_hash ;
activation_code : Blinded_public_key_hash.activation_code ;
amount : Tez.t ;
}
let secrets () =
(* Exported from proto_alpha client - TODO : remove when relocated to lib_crypto *)
let read_key mnemonic email password =
match Bip39.of_words mnemonic with
| None -> assert false
| Some t ->
(* TODO: unicode normalization (NFKD)... *)
let sk = Bip39.to_seed ~passphrase:(email ^ password) t in
let sk = Cstruct.(to_bigarray (sub sk 0 32)) in
let sk : Signature.Secret_key.t =
Ed25519 (Data_encoding.Binary.of_bytes_exn Ed25519.Secret_key.encoding sk) in
let pk = Signature.Secret_key.to_public_key sk in
let pkh = Signature.Public_key.hash pk in
(pkh, pk, sk)
in
List.map (fun (mnemonic, secret, amount, pkh, password, email) ->
let (pkh', pk, sk) = read_key mnemonic email password in
let pkh = Signature.Public_key_hash.of_b58check_exn pkh in
assert (Signature.Public_key_hash.equal pkh pkh');
let account = Account.{ pkh ; pk ; sk } in
Account.add_account account ;
{ account = account.pkh ;
activation_code = Blinded_public_key_hash.activation_code_of_hex secret ;
amount = Option.unopt_exn (Invalid_argument "tez conversion")
(Tez.of_mutez (Int64.of_string amount))
})
[
(["envelope"; "hospital"; "mind"; "sunset"; "cancel"; "muscle"; "leisure";
"thumb"; "wine"; "market"; "exit"; "lucky"; "style"; "picnic"; "success"],
"0f39ed0b656509c2ecec4771712d9cddefe2afac",
"23932454669343",
"tz1MawerETND6bqJqx8GV3YHUrvMBCDasRBF",
"z0eZHQQGKt",
"cjgfoqmk.wpxnvnup@tezos.example.org"
);
(["flag"; "quote"; "will"; "valley"; "mouse"; "chat"; "hold"; "prosper";
"silk"; "tent"; "cruel"; "cause"; "demise"; "bottom"; "practice"],
"41f98b15efc63fa893d61d7d6eee4a2ce9427ac4",
"72954577464032",
"tz1X4maqF9tC1Yn4jULjHRAyzjAtc25Z68TX",
"MHErskWPE6",
"oklmcktr.ztljnpzc@tezos.example.org"
);
(["library"; "away"; "inside"; "paper"; "wise"; "focus"; "sweet"; "expose";
"require"; "change"; "stove"; "planet"; "zone"; "reflect"; "finger"],
"411dfef031eeecc506de71c9df9f8e44297cf5ba",
"217487035428349",
"tz1SWBY7rWMutEuWS54Pt33MkzAS6eWkUuTc",
"0AO6BzQNfN",
"ctgnkvqm.kvtiybky@tezos.example.org"
);
(["cruel"; "fluid"; "damage"; "demand"; "mimic"; "above"; "village"; "alpha";
"vendor"; "staff"; "absent"; "uniform"; "fire"; "asthma"; "milk"],
"08d7d355bc3391d12d140780b39717d9f46fcf87",
"4092742372031",
"tz1amUjiZaevaxQy5wKn4SSRvVoERCip3nZS",
"9kbZ7fR6im",
"bnyxxzqr.tdszcvqb@tezos.example.org"
) ;
(["opera"; "divorce"; "easy"; "myself"; "idea"; "aim"; "dash"; "scout";
"case"; "resource"; "vote"; "humor"; "ticket"; "client"; "edge"],
"9b7cad042fba557618bdc4b62837c5f125b50e56",
"17590039016550",
"tz1Zaee3QBtD4ErY1SzqUvyYTrENrExu6yQM",
"suxT5H09yY",
"iilkhohu.otnyuvna@tezos.example.org"
) ;
(["token"; "similar"; "ginger"; "tongue"; "gun"; "sort"; "piano"; "month";
"hotel"; "vote"; "undo"; "success"; "hobby"; "shell"; "cart"],
"124c0ca217f11ffc6c7b76a743d867c8932e5afd",
"26322312350555",
"tz1geDUUhfXK1EMj7VQdRjug1MoFe6gHWnCU",
"4odVdLykaa",
"kwhlglvr.slriitzy@tezos.example.org"
) ;
(["shield"; "warrior"; "gorilla"; "birth"; "steak"; "neither"; "feel";
"only"; "liberty"; "float"; "oven"; "extend"; "pulse"; "suffer"; "vapor"],
"ac7a2125beea68caf5266a647f24dce9fea018a7",
"244951387881443",
"tz1h3nY7jcZciJgAwRhWcrEwqfVp7VQoffur",
"A6yeMqBFG8",
"lvrmlbyj.yczltcxn@tezos.example.org"
) ;
(["waste"; "open"; "scan"; "tip"; "subway"; "dance"; "rent"; "copper";
"garlic"; "laundry"; "defense"; "clerk"; "another"; "staff"; "liar"],
"2b3e94be133a960fa0ef87f6c0922c19f9d87ca2",
"80065050465525",
"tz1VzL4Xrb3fL3ckvqCWy6bdGMzU2w9eoRqs",
"oVZqpq60sk",
"rfodmrha.zzdndvyk@tezos.example.org"
) ;
(["fiber"; "next"; "property"; "cradle"; "silk"; "obey"; "gossip";
"push"; "key"; "second"; "across"; "minimum"; "nice"; "boil"; "age"],
"dac31640199f2babc157aadc0021cd71128ca9ea",
"3569618927693",
"tz1RUHg536oRKhPLFfttcB5gSWAhh4E9TWjX",
"FfytQTTVbu",
"owecikdy.gxnyttya@tezos.example.org"
) ;
(["print"; "labor"; "budget"; "speak"; "poem"; "diet"; "chunk"; "eternal";
"book"; "saddle"; "pioneer"; "ankle"; "happy"; "only"; "exclude"],
"bb841227f250a066eb8429e56937ad504d7b34dd",
"9034781424478",
"tz1M1LFbgctcPWxstrao9aLr2ECW1fV4pH5u",
"zknAl3lrX2",
"ettilrvh.zsrqrbud@tezos.example.org"
) ;
]
let activation_init () =
Context.init ~commitments 1 >>=? fun (b, cs) ->
secrets () |> fun ss ->
return (b, cs, ss)
let simple_init_with_commitments () =
activation_init () >>=? fun (blk, _contracts, _secrets) ->
Block.bake blk >>=? fun _ ->
return ()
(** A single activation *)
let single_activation () =
activation_init () >>=? fun (blk, _contracts, secrets) ->
let { account ; activation_code ; amount=expected_amount ; _ } as _first_one = List.hd secrets in
(* Contract does not exist *)
Assert.balance_is ~loc:__LOC__ (B blk) (Contract.implicit_contract account) Tez.zero >>=? fun () ->
Op.activation (B blk) account activation_code >>=? fun operation ->
Block.bake ~operation blk >>=? fun blk ->
(* Contract does exist *)
Assert.balance_is ~loc:__LOC__ (B blk) (Contract.implicit_contract account) expected_amount
(** 10 activations, one per bake *)
let multi_activation_1 () =
activation_init () >>=? fun (blk, _contracts, secrets) ->
Error_monad.fold_left_s (fun blk { account ; activation_code ; amount = expected_amount ; _ } ->
Op.activation (B blk) account activation_code >>=? fun operation ->
Block.bake ~operation blk >>=? fun blk ->
Assert.balance_is ~loc:__LOC__ (B blk) (Contract.implicit_contract account) expected_amount >>=? fun () ->
return blk
) blk secrets >>=? fun _ ->
return ()
(** All in one bake *)
let multi_activation_2 () =
activation_init () >>=? fun (blk, _contracts, secrets) ->
Error_monad.fold_left_s (fun ops { account ; activation_code ; _ } ->
Op.activation (B blk) account activation_code >>=? fun op ->
return (op::ops)
) [] secrets >>=? fun ops ->
Block.bake ~operations:ops blk >>=? fun blk ->
Error_monad.iter_s (fun { account ; amount = expected_amount ; _ } ->
(* Contract does exist *)
Assert.balance_is ~loc:__LOC__ (B blk) (Contract.implicit_contract account) expected_amount
) secrets
(** Transfer with activated account *)
let activation_and_transfer () =
activation_init () >>=? fun (blk, contracts, secrets) ->
let { account ; activation_code ; _ } as _first_one = List.hd secrets in
let bootstrap_contract = List.hd contracts in
let first_contract = Contract.implicit_contract account in
Op.activation (B blk) account activation_code >>=? fun operation ->
Block.bake ~operation blk >>=? fun blk ->
Context.Contract.balance (B blk) bootstrap_contract >>=? fun amount ->
Tez.(/?) amount 2L >>?= fun half_amount ->
Context.Contract.balance (B blk) first_contract >>=? fun activated_amount_before ->
Op.transaction (B blk) bootstrap_contract first_contract half_amount >>=? fun operation ->
Block.bake ~operation blk >>=? fun blk ->
Assert.balance_was_credited ~loc:__LOC__ (B blk) (Contract.implicit_contract account) activated_amount_before half_amount
(** Transfer to an unactivated account and then activating it *)
let transfer_to_unactivated_then_activate () =
activation_init () >>=? fun (blk, contracts, secrets) ->
let { account ; activation_code ; amount } as _first_one = List.hd secrets in
let bootstrap_contract = List.hd contracts in
let unactivated_commitment_contract = Contract.implicit_contract account in
Context.Contract.balance (B blk) bootstrap_contract >>=? fun b_amount ->
Tez.(/?) b_amount 2L >>?= fun b_half_amount ->
Incremental.begin_construction blk >>=? fun inc ->
Op.transaction (I inc) bootstrap_contract unactivated_commitment_contract b_half_amount >>=? fun op ->
Incremental.add_operation inc op >>=? fun inc ->
Op.activation (I inc) account activation_code >>=? fun op' ->
Incremental.add_operation inc op' >>=? fun inc ->
Incremental.finalize_block inc >>=? fun blk2 ->
Assert.balance_was_credited ~loc:__LOC__ (B blk2) (Contract.implicit_contract account) amount b_half_amount
(****************************************************************)
(* The following test scenarios are supposed to raise errors. *)
(****************************************************************)
(** Invalid pkh activation : expected to fail as the context does not
contain any commitment *)
let invalid_activation_with_no_commitments () =
Context.init 1 >>=? fun (blk, _) ->
let secrets = secrets () in
let { account ; activation_code ; _ } as _first_one = List.hd secrets in
Op.activation (B blk) account activation_code >>=? fun operation ->
Block.bake ~operation blk >>= fun res ->
Assert.proto_error ~loc:__LOC__ res begin function
| Apply.Invalid_activation _ -> true
| _ -> false
end
(** Wrong activation : wrong secret given in the operation *)
let invalid_activation_wrong_secret () =
activation_init () >>=? fun (blk, _, secrets) ->
let { account ; _ } as _first_one = List.nth secrets 0 in
let { activation_code ; _ } as _second_one = List.nth secrets 1 in
Op.activation (B blk) account activation_code >>=? fun operation ->
Block.bake ~operation blk >>= fun res ->
Assert.proto_error ~loc:__LOC__ res begin function
| Apply.Invalid_activation _ -> true
| _ -> false
end
(** Invalid pkh activation : expected to fail as the context does not
contain an associated commitment *)
let invalid_activation_inexistent_pkh () =
activation_init () >>=? fun (blk, _, secrets) ->
let { activation_code ; _ } as _first_one = List.hd secrets in
let inexistent_pkh = Signature.Public_key_hash.of_b58check_exn
"tz1PeQHGKPWSpNoozvxgqLN9TFsj6rDqNV3o" in
Op.activation (B blk) inexistent_pkh activation_code >>=? fun operation ->
Block.bake ~operation blk >>= fun res ->
Assert.proto_error ~loc:__LOC__ res begin function
| Apply.Invalid_activation _ -> true
| _ -> false
end
(** Invalid pkh activation : expected to fail as the commitment has
already been claimed *)
let invalid_double_activation () =
activation_init () >>=? fun (blk, _, secrets) ->
let { account ; activation_code ; _ } as _first_one = List.hd secrets in
Incremental.begin_construction blk >>=? fun inc ->
Op.activation (I inc) account activation_code >>=? fun op ->
Incremental.add_operation inc op >>=? fun inc ->
Op.activation (I inc) account activation_code >>=? fun op' ->
Incremental.add_operation inc op' >>= fun res ->
Assert.proto_error ~loc:__LOC__ res begin function
| Apply.Invalid_activation _ -> true
| _ -> false
end
(** Transfer from an unactivated commitment account *)
let invalid_transfer_from_unactived_account () =
activation_init () >>=? fun (blk, contracts, secrets) ->
let { account ; _ } as _first_one = List.hd secrets in
let bootstrap_contract = List.hd contracts in
let unactivated_commitment_contract = Contract.implicit_contract account in
(* No activation *)
Op.transaction (B blk) unactivated_commitment_contract bootstrap_contract Tez.one >>=? fun operation ->
Block.bake ~operation blk >>= fun res ->
Assert.proto_error ~loc:__LOC__ res begin function
| Contract_storage.Empty_implicit_contract pkh -> if pkh = account then true else false
| _ -> false
end
let tests = [
Test.tztest "init with commitments" `Quick simple_init_with_commitments ;
Test.tztest "single activation" `Quick single_activation ;
Test.tztest "multi-activation one-by-one" `Quick multi_activation_1 ;
Test.tztest "multi-activation all at a time" `Quick multi_activation_2 ;
Test.tztest "activation and transfer" `Quick activation_and_transfer ;
Test.tztest "transfer to unactivated account then activate" `Quick transfer_to_unactivated_then_activate ;
Test.tztest "invalid activation with no commitments" `Quick invalid_activation_with_no_commitments ;
Test.tztest "invalid activation with commitments" `Quick invalid_activation_inexistent_pkh ;
Test.tztest "invalid double activation" `Quick invalid_double_activation ;
Test.tztest "wrong activation code" `Quick invalid_activation_wrong_secret ;
Test.tztest "invalid transfer from unactivated account" `Quick invalid_transfer_from_unactived_account
]

View File

@ -0,0 +1,246 @@
(**************************************************************************)
(* *)
(* Copyright (c) 2014 - 2018. *)
(* Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* All rights reserved. No warranty, explicit or implicit, provided. *)
(* *)
(**************************************************************************)
(** Endorsing a block adds an extra layer of confidence to the Tezos's
PoS algorithm. The block endorsing operation must be included in
the following block. Each endorser possess a slot corresponding to
their priority. After [preserved_cycles], a reward is given to the
endorser. This reward depends on the priority of the endorsed
block. *)
open Proto_alpha
open Alpha_context
open Test_utils
open Test_tez
(****************************************************************)
(* Utility functions *)
(****************************************************************)
let get_expected_reward ?(priority=0) ~nb_baking ~nb_endorsement ctxt =
Context.get_constants ctxt >>=? fun Constants.
{ parametric = { endorsement_reward ; block_reward ; _ } ; _ } ->
let open Alpha_environment in let open Tez in
endorsement_reward /? Int64.(succ (of_int priority)) >>?= fun endorsement_reward ->
endorsement_reward *? (Int64.of_int nb_endorsement) >>?= fun endorsement_reward ->
block_reward *? (Int64.of_int nb_baking) >>?= fun baking_reward ->
endorsement_reward +? baking_reward >>?= fun reward -> return reward
let get_expected_deposit ctxt ~nb_baking ~nb_endorsement =
Context.get_constants ctxt >>=? fun Constants.
{ parametric = { endorsement_security_deposit ;
block_security_deposit ; _ } ; _ } ->
let open Alpha_environment in let open Tez in
endorsement_security_deposit *? (Int64.of_int nb_endorsement) >>?= fun endorsement_deposit ->
block_security_deposit *? (Int64.of_int nb_baking) >>?= fun baking_deposit ->
endorsement_deposit +? baking_deposit >>?= fun deposit -> return deposit
let assert_endorser_balance_consistency ~loc ?(priority=0) ?(nb_baking=0) ~nb_endorsement
ctxt pkh initial_balance =
let contract = Contract.implicit_contract pkh in
get_expected_reward ~priority ~nb_baking ~nb_endorsement ctxt >>=? fun reward ->
get_expected_deposit ctxt ~nb_baking ~nb_endorsement >>=? fun deposit ->
Assert.balance_was_debited ~loc ctxt contract initial_balance deposit >>=? fun () ->
Context.Contract.balance ~kind:Rewards ctxt contract >>=? fun reward_balance ->
Assert.equal_tez ~loc reward_balance reward >>=? fun () ->
Context.Contract.balance ~kind:Deposit ctxt contract >>=? fun deposit_balance ->
Assert.equal_tez ~loc deposit_balance deposit
(****************************************************************)
(* Tests *)
(****************************************************************)
(** Apply a single endorsement from the slot 0 endorser *)
let simple_endorsement () =
Context.init 5 >>=? fun (b, _) ->
let slot = 0 in
Incremental.begin_construction b >>=? fun inc ->
Context.get_endorser (B b) slot >>=? fun endorser ->
Op.endorsement ~delegate:endorser (I inc) slot >>=? fun op ->
Incremental.add_operation inc op >>=? fun inc ->
Context.Contract.balance (B b) (Contract.implicit_contract endorser) >>=? fun initial_balance ->
assert_endorser_balance_consistency ~loc:__LOC__
(I inc) ~nb_endorsement:1 endorser initial_balance
(** Apply a maximum number of endorsement. A endorser can be selected
twice. *)
let max_endorsement () =
let endorsers_per_block = 16 in
Context.init ~endorsers_per_block 32 >>=? fun (b, _) ->
Context.get_endorsers (B b) >>=? fun endorsers ->
Assert.equal_int ~loc:__LOC__
(List.length endorsers) endorsers_per_block >>=? fun () ->
fold_left_s (fun (ops, balances) (delegate, slot) ->
Context.Contract.balance (B b) (Contract.implicit_contract delegate) >>=? fun balance ->
Op.endorsement ~delegate (B b) slot >>=? fun op ->
return (op :: ops, balance :: balances)
)
([], [])
(List.combine endorsers (0--(endorsers_per_block - 1))) >>=? fun (ops, previous_balances) ->
Block.bake ~policy:(Excluding endorsers) ~operations:(List.rev ops) b >>=? fun b ->
let count acc =
List.find_all ((=) acc) endorsers |> List.length
in
(* One account can endorse more than one time per level, we must
check that the bonds are summed up *)
iter_s (fun (endorser_account, previous_balance) ->
let nb_endorsement = count endorser_account in
assert_endorser_balance_consistency ~loc:__LOC__
(B b) ~nb_endorsement endorser_account previous_balance
) (List.combine endorsers (List.rev previous_balances))
(** Check that an endorser balance is consistent with a different piority *)
let consistent_priority () =
Context.init 32 >>=? fun (b, _) ->
Block.get_next_baker ~policy:(By_priority 15) b >>=? fun (baker_account, _, _) ->
Block.bake ~policy:(By_priority 15) b >>=? fun b ->
(* Grab an endorser that didn't bake the previous block *)
Context.get_endorser (B b) 0 >>=? fun endorser_0 ->
Context.get_endorser (B b) 1 >>=? fun endorser_1 ->
let (endorser, slot) =
if endorser_0 = baker_account then endorser_1, 1 else endorser_0, 0
in
Context.Contract.balance (B b) (Contract.implicit_contract endorser) >>=? fun balance ->
Op.endorsement ~delegate:endorser (B b) slot >>=? fun operation ->
Block.bake ~policy:( Excluding [ endorser ] ) ~operation b >>=? fun b ->
assert_endorser_balance_consistency ~loc:__LOC__ ~priority:15
(B b) ~nb_endorsement:1 endorser balance
(** Check every 32 endorser's balances are consistent with a different piority *)
let consistent_priorities () =
let priorities = 15 -- 31 in
Context.init 64 >>=? fun (b, _) ->
iter_s (fun priority ->
(* Bake with a specific priority *)
Block.get_next_baker ~policy:(By_priority priority) b >>=? fun (baker_account, _, _) ->
Block.bake ~policy:(By_priority priority) b >>=? fun b ->
(* Grab an endorser that didn't bake the previous block *)
Context.get_endorser (B b) 0 >>=? fun endorser_0 ->
Context.get_endorser (B b) 1 >>=? fun endorser_1 ->
let (endorser, slot) =
if endorser_0 = baker_account then endorser_1, 1 else endorser_0, 0
in
Context.Contract.balance (B b) (Contract.implicit_contract endorser) >>=? fun balance ->
Op.endorsement ~delegate:endorser (B b) slot >>=? fun operation ->
Block.bake ~policy:( Excluding [ endorser ] ) ~operation b >>=? fun b ->
assert_endorser_balance_consistency ~loc:__LOC__ ~priority
(B b) ~nb_endorsement:1 endorser balance
) priorities
(** Check that after a cycle the endorser gets his reward *)
let reward_retrieval () =
Context.init 5 >>=? fun (b, _) ->
Context.get_constants (B b) >>=? fun Constants.
{ parametric = { preserved_cycles ; endorsement_reward ; _ } ; _ } ->
let slot = 0 in
Context.get_endorser (B b) slot >>=? fun endorser ->
Context.Contract.balance (B b) (Contract.implicit_contract endorser) >>=? fun balance ->
Op.endorsement ~delegate:endorser (B b) slot >>=? fun operation ->
Block.bake ~policy:(Excluding [ endorser ]) ~operation b >>=? fun b ->
(* Bake (preserved_cycles + 1) cycles *)
fold_left_s (fun b _ ->
Block.bake_until_cycle_end ~policy:(Excluding [ endorser ]) b
) b (0 -- preserved_cycles) >>=? fun b ->
Assert.balance_was_credited ~loc:__LOC__ (B b) (Contract.implicit_contract endorser) balance endorsement_reward
(****************************************************************)
(* The following test scenarios are supposed to raise errors. *)
(****************************************************************)
(** Wrong endorsement predecessor : apply an endorsement with an
incorrect block predecessor *)
let wrong_endorsement_predecessor () =
Context.init 5 >>=? fun (b, _) ->
Context.get_endorser (B b) 0 >>=? fun genesis_endorser ->
Block.bake b >>=? fun b' ->
Op.endorsement ~delegate:genesis_endorser ~signing_context:(B b') (B b) 0 >>=? fun operation ->
Block.bake ~operation b' >>= fun res ->
Assert.proto_error ~loc:__LOC__ res begin function
| Apply.Wrong_endorsement_predecessor _ -> true
| _ -> false
end
(** Invalid_endorsement_level : apply an endorsement with an incorrect
level (i.e. the predecessor level) *)
let invalid_endorsement_level () =
Context.init 5 >>=? fun (b, _) ->
Context.get_level (B b) >>=? fun genesis_level ->
Block.bake b >>=? fun b ->
Op.endorsement ~level:genesis_level (B b) 0 >>=? fun operation ->
Block.bake ~operation b >>= fun res ->
Assert.proto_error ~loc:__LOC__ res begin function
| Apply.Invalid_endorsement_level -> true
| _ -> false
end
(** Duplicate endorsement : apply an endorsement that has already been done *)
let duplicate_endorsement () =
Context.init 5 >>=? fun (b, _) ->
Incremental.begin_construction b >>=? fun inc ->
Op.endorsement (B b) 0 >>=? fun operation ->
Incremental.add_operation inc operation >>=? fun inc ->
Op.endorsement (B b) 0 >>=? fun operation ->
Incremental.add_operation inc operation >>= fun res ->
Assert.proto_error ~loc:__LOC__ res begin function
| Apply.Duplicate_endorsement _ -> true
| _ -> false
end
(** Invalid_endorsement_slot : making an endorsement with an invalid slot *)
let invalid_endorsement_slot () =
Context.init 64 >>=? fun (b, _) ->
Context.get_constants (B b) >>=? fun Constants.
{ parametric = { endorsers_per_block ; _ } ; _ } ->
Op.endorsement (B b) (endorsers_per_block + 1) >>=? fun operation ->
Block.bake ~operation b >>= fun res ->
Assert.proto_error ~loc:__LOC__ res begin function
| Baking.Invalid_endorsement_slot _ -> true
| _ -> false
end
let tests = [
Test.tztest "Simple endorsement" `Quick simple_endorsement ;
Test.tztest "Maximum endorsement" `Quick max_endorsement ;
Test.tztest "Consistent priority" `Quick consistent_priority ;
Test.tztest "Consistent priorities" `Quick consistent_priorities ;
Test.tztest "Reward retrieval" `Quick reward_retrieval ;
(* Fail scenarios *)
Test.tztest "Wrong endorsement predecessor" `Quick wrong_endorsement_predecessor ;
Test.tztest "Invalid endorsement level" `Quick invalid_endorsement_level ;
Test.tztest "Duplicate endorsement" `Quick duplicate_endorsement ;
Test.tztest "Invalid endorsement slot" `Quick invalid_endorsement_slot ;
]

View File

@ -11,4 +11,6 @@ let () =
Alcotest.run "protocol_alpha" [ Alcotest.run "protocol_alpha" [
"transfer", Transfer.tests ; "transfer", Transfer.tests ;
"origination", Origination.tests ; "origination", Origination.tests ;
"activation", Activation.tests ;
"endorsement", Endorsement.tests ;
] ]