diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml index 045830ba5b04479e9906d13661164429d6bfc4a0..06659ba0125495a23f1e5cc6fb54f4f1182095cc 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_tx_rollup.ml @@ -251,11 +251,13 @@ let context_init1 ?tx_rollup_max_inboxes_count to not interfere with balances prediction. It returns the created context and 2 contracts. *) let context_init2 ?tx_rollup_max_inboxes_count - ?tx_rollup_max_ticket_payload_size ?cost_per_byte () = + ?tx_rollup_max_ticket_payload_size ?cost_per_byte + ?tx_rollup_hard_size_limit_per_message () = context_init ?tx_rollup_max_inboxes_count ?tx_rollup_max_ticket_payload_size ?cost_per_byte + ?tx_rollup_hard_size_limit_per_message 2 >|=? function | (b, contract_1 :: contract_2 :: _) -> (b, contract_1, contract_2) @@ -443,6 +445,7 @@ let make_incomplete_commitment_for_batch context level tx_rollup withdraw_list = in return (commitment, batches_result) +(** Check that the given contract has [count] pending bonded commitments *) let check_bond ctxt tx_rollup contract count = let pkh = is_implicit_exn contract in wrap_lwt (Tx_rollup_commitment.pending_bonded_commitments ctxt tx_rollup pkh) @@ -2182,9 +2185,9 @@ module Rejection = struct end module Prover_context = Tx_rollup_l2_context.Make (Prover_storage) - module Context = Tx_rollup_l2_context.Make (Storage) + module L2_Context = Tx_rollup_l2_context.Make (Storage) module Prover_apply = Tx_rollup_l2_apply.Make (Prover_context) - module Apply = Tx_rollup_l2_apply.Make (Context) + module Apply = Tx_rollup_l2_apply.Make (L2_Context) module C = Tezos_context_memory.Context_binary let previous_message_result : Tx_rollup_message_result.t = @@ -2255,7 +2258,7 @@ module Rejection = struct tree produced in this function. *) let init_l2_store () = - let open Context.Syntax in + let open L2_Context.Syntax in let store = C.empty in let time = time () in let tree = C.Tree.empty store in @@ -2268,17 +2271,17 @@ module Rejection = struct return store let get_tree_from_store store = - let open Context.Syntax in + let open L2_Context.Syntax in let* tree_opt = C.find_tree store [] in match tree_opt with Some x -> return x | None -> assert false let hash_tree_from_store store = - let open Context.Syntax in + let open L2_Context.Syntax in let+ tree = get_tree_from_store store in C.Tree.hash tree let commit_store store = - let open Context.Syntax in + let open L2_Context.Syntax in let time = time () in let* h = C.commit ~time store in let index = C.index store in @@ -2290,7 +2293,7 @@ module Rejection = struct the store generated by {!init_l2_store}. We then add a regression test to ensure these two are synchronized. *) let test_empty_l2_context_hash () = - let open Context.Syntax in + let open L2_Context.Syntax in let* store = init_l2_store () in let* hash_tree = hash_tree_from_store store in assert ( @@ -2300,7 +2303,7 @@ module Rejection = struct (** [make_proof store msg] applies [msg] on [store] and returns the created proof. *) let make_proof store l2_parameters msg = - let open Context.Syntax in + let open L2_Context.Syntax in let index = C.index store in let* hash = hash_tree_from_store store in let* (proof, ()) = @@ -2313,7 +2316,7 @@ module Rejection = struct return proof let valid_empty_proof l2_parameters = - let open Context.Syntax in + let open L2_Context.Syntax in let* l2_store = init_l2_store () in let (message, _) = Tx_rollup_message.make_batch "bogus" in make_proof l2_store l2_parameters message @@ -2329,7 +2332,7 @@ module Rejection = struct (** Takes a commitment and replaces the message results with valid results. *) let replace_commitment ~l2_parameters ~store ~commitment messages = - let open Context in + let open L2_Context in let open Syntax in let* (_, rev_results) = list_fold_left_m @@ -2371,8 +2374,8 @@ module Rejection = struct let init_with_deposit ?tx_rollup_hard_size_limit_per_message addr = init_l2_store () >>= fun store -> - context_init1 ?tx_rollup_hard_size_limit_per_message () - >>=? fun (b, account) -> + context_init2 ?tx_rollup_hard_size_limit_per_message () + >>=? fun (b, account, account2) -> originate b account >>=? fun (b, tx_rollup) -> make_deposit b tx_rollup account addr >>=? fun (b, (deposit, _), ticket_hash) -> @@ -2429,7 +2432,7 @@ module Rejection = struct for next operations *) Apply.apply_message store l2_parameters deposit >>= fun (store, _) -> commit_store store >>= fun store -> - return (b, account, tx_rollup, store, ticket_hash) + return (b, account, account2, tx_rollup, store, ticket_hash) let operation_content destination ticket_hash qty = let open Tx_rollup_l2_batch.V1 in @@ -2486,7 +2489,7 @@ module Rejection = struct let test_valid_proof_on_invalid_commitment () = let (sk, pk, addr) = gen_l2_account () in init_with_deposit addr - >>=? fun (b, account, tx_rollup, store, ticket_hash) -> + >>=? fun (b, account, _, tx_rollup, store, ticket_hash) -> hash_tree_from_store store >>= fun l2_context_hash -> (* Create a transfer from [pk] to a new address *) let (_, _, addr2) = gen_l2_account () in @@ -2544,7 +2547,11 @@ module Rejection = struct let test_valid_proof_on_valid_commitment () = let (sk, pk, addr) = gen_l2_account () in init_with_deposit addr - >>=? fun (b, account, tx_rollup, store, ticket_hash) -> + >>=? fun (b, account, _, tx_rollup, store, ticket_hash) -> + (* init_with_deposit creates a commitment -- we'll just check the bond + here so that this test is easier to read. *) + Incremental.begin_construction b >>=? fun i -> + check_bond (Incremental.alpha_ctxt i) tx_rollup account 1 >>=? fun () -> hash_tree_from_store store >>= fun l2_context_hash -> (* Create a transfer from [pk] to a new address *) let (_, _, addr2) = gen_l2_account () in @@ -2602,7 +2609,151 @@ module Rejection = struct (check_proto_error_f @@ function | Tx_rollup_errors.Proof_produced_rejected_state -> true | _ -> false) - >>=? fun _ -> return_unit + >>=? fun i -> + check_bond (Incremental.alpha_ctxt i) tx_rollup account 2 >>=? fun () -> + return_unit + + (** Test that rejection rewards and slashing work: + 1. Create two messages and two commitments + 2. Reject the second commitment + 3. Ensure that slashing and rewards happen + 4. Reject the first commitment + 5. Ensure that there is no further slashing or reward + *) + let test_rejection_rewards () = + let open Error_monad_operators in + let (_, _, addr) = gen_l2_account () in + init_l2_store () >>= fun store -> + context_init2 () >>=? fun (b, contract1, contract2) -> + originate b contract1 >>=? fun (b, tx_rollup) -> + make_deposit b tx_rollup contract1 addr + >>=? fun (b, (deposit_message, _), _ticket_hash) -> + Context.Contract.balance (B b) contract1 >>=? fun balance -> + Context.Contract.balance (B b) contract2 >>=? fun balance2 -> + (* [check_frozen] checks that contract1 has [expect] frozen tez. *) + let check_frozen ~loc i expect = + Contract.get_frozen_bonds (Incremental.alpha_ctxt i) contract1 + >>=?? fun frozen -> Assert.equal_tez ~loc expect frozen + in + Incremental.begin_construction b >>=? fun i -> + (* Nothing frozen to start *) + check_frozen ~loc:__LOC__ i Tez.zero >>=? fun () -> + (* No-op batch for second inbox *) + Op.tx_rollup_submit_batch (B b) contract1 tx_rollup "fake" + >>=? fun operation -> + Block.bake ~operation b >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + l2_parameters (B b) >>=? fun l2_parameters -> + let (message, _) = Tx_rollup_message.make_batch "fake" in + let message_hash = Tx_rollup_message_hash.hash_uncarbonated message in + let message_path = + assert_ok @@ Tx_rollup_inbox.Merkle.(compute_path [message_hash] 0) + in + hash_tree_from_store store >>= fun l2_context_hash -> + let make_invalid_commitment i level h = + (* Make some invalid commitments for the submitted messages *) + make_incomplete_commitment_for_batch (I i) level tx_rollup [] + >>=? fun (commitment, _) -> + (* Make this commitment bogus *) + let message_result = + Tx_rollup_message_result. + { + context_hash = h; + withdraw_list_hash = Tx_rollup_withdraw_list_hash.empty; + } + in + let message_result_hash = + Tx_rollup_message_result_hash.hash_uncarbonated message_result + in + let commitment = {commitment with messages = [message_result_hash]} in + Op.tx_rollup_commit (I i) contract1 tx_rollup commitment >>=? fun op -> + Incremental.add_operation i op >|=? fun i -> (i, commitment) + in + let level0 = tx_level 0l in + let level1 = tx_level 1l in + make_invalid_commitment i level0 l2_context_hash + >>=? fun (i, commitment0) -> + make_invalid_commitment i level1 Context_hash.zero + >>=? fun (i, commitment1) -> + Context.get_constants (I i) >>=? fun constants -> + let bond_cost = constants.parametric.tx_rollup_commitment_bond in + Assert.balance_was_debited ~loc:__LOC__ (I i) contract1 balance bond_cost + >>=? fun () -> + check_frozen ~loc:__LOC__ i bond_cost >>=? fun () -> + Incremental.finalize_block i >>=? fun b -> + Incremental.begin_construction b >>=? fun i -> + (* Now we produce a valid proof rejecting the second commitment *) + make_proof store l2_parameters message >>= fun proof -> + let message_position = 0 in + let (message_result_hash, message_result_path) = + message_result_hash_and_path commitment1 ~message_position + in + Op.tx_rollup_reject + (I i) + contract2 + tx_rollup + level1 + message + ~message_position + ~message_path + ~message_result_hash + ~message_result_path + ~proof + ~previous_message_result: + { + context_hash = l2_context_hash; + withdraw_list_hash = Tx_rollup_withdraw_list_hash.empty; + } + ~previous_message_result_path:Tx_rollup_commitment.Merkle.dummy_path + >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + check_bond (Incremental.alpha_ctxt i) tx_rollup contract1 0 >>=? fun () -> + Assert.balance_was_debited ~loc:__LOC__ (I i) contract1 balance bond_cost + >>=? fun () -> + (* Now we need to check that the tez is really gone -- not just frozen *) + check_frozen ~loc:__LOC__ i Tez.zero >>=? fun () -> + let reward = assert_ok Tez.(bond_cost /? 2L) in + Assert.balance_was_credited ~loc:__LOC__ (I i) contract2 balance2 reward + >>=? fun () -> + (* Now, we can still reject the root commitment, but we won't get a reward *) + Context.Contract.balance (I i) contract1 >>=? fun balance -> + Context.Contract.balance (I i) contract2 >>=? fun balance2 -> + make_proof store l2_parameters deposit_message >>= fun proof -> + let message_hash = + Tx_rollup_message_hash.hash_uncarbonated deposit_message + in + let message_path = + assert_ok @@ Tx_rollup_inbox.Merkle.(compute_path [message_hash] 0) + in + let message_position = 0 in + let (message_result_hash, message_result_path) = + message_result_hash_and_path commitment0 ~message_position + in + Op.tx_rollup_reject + (I i) + contract2 + tx_rollup + level0 + deposit_message + ~message_position + ~message_path + ~message_result_hash + ~message_result_path + ~proof + ~previous_message_result: + { + context_hash = l2_context_hash; + withdraw_list_hash = Tx_rollup_withdraw_list_hash.empty; + } + ~previous_message_result_path:Tx_rollup_commitment.Merkle.dummy_path + >>=? fun op -> + Incremental.add_operation i op >>=? fun i -> + check_bond (Incremental.alpha_ctxt i) tx_rollup contract1 0 >>=? fun () -> + Assert.balance_was_debited ~loc:__LOC__ (I i) contract1 balance Tez.zero + >>=? fun () -> + (* Now we need to check that the tez still really gone -- not just frozen *) + check_frozen ~loc:__LOC__ i Tez.zero >>=? fun () -> + Assert.balance_was_credited ~loc:__LOC__ (I i) contract2 balance2 Tez.zero (** Test the proof production (used in this test file) and the proof verification handles a hard failure. [make_bad_message] makes a @@ -2611,7 +2762,7 @@ module Rejection = struct let do_test_proof_with_hard_fail_message make_bad_message = let (sk, pk, addr) = gen_l2_account () in init_with_deposit addr - >>=? fun (b, account, tx_rollup, store, ticket_hash) -> + >>=? fun (b, account, _, tx_rollup, store, ticket_hash) -> hash_tree_from_store store >>= fun l2_context_hash -> let (message, batch_bytes) = make_bad_message sk pk addr ticket_hash in let message_hash = Tx_rollup_message_hash.hash_uncarbonated message in @@ -2656,7 +2807,9 @@ module Rejection = struct } ~previous_message_result_path:Tx_rollup_commitment.Merkle.dummy_path >>=? fun op -> - Incremental.add_operation i op >>=? fun _ -> return_unit + Incremental.add_operation i op >>=? fun i -> + check_bond (Incremental.alpha_ctxt i) tx_rollup account 0 >>=? fun () -> + return_unit (** Test that proof production and verification can handle an invalid signature *) @@ -3078,7 +3231,7 @@ module Rejection = struct Incremental.add_operation i op >>=? fun _ -> return_unit let add_store_to_ctxt ctxt store = - let open Context.Syntax in + let open L2_Context.Syntax in let time = Time.Protocol.of_seconds 0L in let* ctxt = C.add_tree ctxt [] store in let* h = C.commit ~time ctxt in @@ -3225,7 +3378,7 @@ module Rejection = struct let test_reject_withdrawals_helper ?expect_failure n_withdraw = let (sk, pk, addr) = gen_l2_account () in init_with_deposit ~tx_rollup_hard_size_limit_per_message:20_000 addr - >>=? fun (b, account, tx_rollup, store, ticket_hash) -> + >>=? fun (b, account, _, tx_rollup, store, ticket_hash) -> hash_tree_from_store store >>= fun l2_context_hash -> (* 1. Create a batch with [n_withdraw] withdrawals. *) let destination = is_implicit_exn account in @@ -3349,6 +3502,7 @@ module Rejection = struct "reject valid commitment fails" `Quick test_valid_proof_on_valid_commitment; + Tztest.tztest "rejection rewards" `Quick test_rejection_rewards; Tztest.tztest "proof for a hard failing message: invalid signature" `Quick diff --git a/src/proto_alpha/lib_protocol/test/integration/test_frozen_bonds.ml b/src/proto_alpha/lib_protocol/test/integration/test_frozen_bonds.ml index 7878b58fd5e489639e8a8f43f36740204a68e6b4..47b223b4067c55e9fe22a0cfe8d08241d6db3479 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_frozen_bonds.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_frozen_bonds.ml @@ -319,6 +319,252 @@ let test_rpcs () = Assert.equal_tez ~loc:__LOC__ balance_and_frozen_bonds balance | _ -> (* Exactly one account has been generated. *) assert false +(** A helper to test a particular delegation/freezing scenario *) +let test_scenario scenario = + init_test ~user_is_delegate:false + >>=? fun (ctxt, user_contract, user_account, delegate1) -> + let (delegate2, delegate_pk2, _) = Signature.generate_key () in + let delegate_contract2 = Contract.implicit_contract delegate2 in + let delegate_account2 = `Contract delegate_contract2 in + let delegate_balance2 = big_random_amount () in + Token.transfer ctxt `Minted delegate_account2 delegate_balance2 + >>>=? fun (ctxt, _) -> + (* Configure delegate, as a delegate by self-delegation, for which + revealing its manager key is a prerequisite. *) + Contract.reveal_manager_key ctxt delegate2 delegate_pk2 >>>=? fun ctxt -> + Delegate.set ctxt delegate_contract2 (Some delegate2) >>>=? fun ctxt -> + let (tx_rollup1, nonce) = mk_tx_rollup () in + let (tx_rollup2, _) = mk_tx_rollup ~nonce () in + let bond_id1 = Bond_id.Tx_rollup_bond_id tx_rollup1 in + let bond_id2 = Bond_id.Tx_rollup_bond_id tx_rollup2 in + let deposit_amount = Tez.of_mutez_exn 1000L in + let deposit_account1 = `Frozen_bonds (user_contract, bond_id1) in + let deposit_account2 = `Frozen_bonds (user_contract, bond_id2) in + let do_delegate ?(delegate = delegate1) ctxt = + (* Fetch staking balance before delegation *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance -> + (* Fetch user's initial balance before delegate. *) + Contract.get_balance_and_frozen_bonds ctxt user_contract + >>>=? fun user_balance -> + (* Let user delegate to "delegate". *) + Delegate.set ctxt user_contract (Some delegate) >>>=? fun ctxt -> + (* Fetch staking balance after delegation *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance' -> + Assert.equal_tez + ~loc:__LOC__ + staking_balance' + (staking_balance +! user_balance) + >|=? fun () -> (ctxt, user_balance) + in + let do_freeze ?(deposit_account = deposit_account1) ctxt = + (* Fetch staking balance before freeze *) + Delegate.staking_balance ctxt delegate1 >>>=? fun staking_balance1 -> + Delegate.staking_balance ctxt delegate2 >>>=? fun staking_balance2 -> + (* Freeze a tx-rollup deposit. *) + Token.transfer ctxt user_account deposit_account deposit_amount + >>>=? fun (ctxt, _) -> + (* Fetch staking balance after freeze. *) + Delegate.staking_balance ctxt delegate1 >>>=? fun staking_balance1' -> + Delegate.staking_balance ctxt delegate2 >>>=? fun staking_balance2' -> + (* Ensure staking balance did not change. *) + Assert.equal_tez ~loc:__LOC__ staking_balance1' staking_balance1 + >>=? fun () -> + Assert.equal_tez ~loc:__LOC__ staking_balance2' staking_balance2 + >|=? fun () -> ctxt + in + let do_unfreeze ?(deposit_account = deposit_account1) ctxt = + (* Fetch staking balance before unfreeze *) + Delegate.staking_balance ctxt delegate1 >>>=? fun staking_balance1 -> + Delegate.staking_balance ctxt delegate2 >>>=? fun staking_balance2 -> + (* Unfreeze the deposit *) + Token.transfer ctxt deposit_account user_account deposit_amount + >>>=? fun (ctxt, _) -> + (* Fetch staking balance after unfreeze. *) + Delegate.staking_balance ctxt delegate1 >>>=? fun staking_balance1' -> + Delegate.staking_balance ctxt delegate2 >>>=? fun staking_balance2' -> + (* Ensure staking balance did not change. *) + Assert.equal_tez ~loc:__LOC__ staking_balance1' staking_balance1 + >>=? fun () -> + Assert.equal_tez ~loc:__LOC__ staking_balance2' staking_balance2 + >|=? fun () -> ctxt + in + let do_slash ?(deposit_account = deposit_account1) + ?(current_delegate = Some delegate1) ctxt = + (* Fetch staking balance before slash *) + (match current_delegate with + | None -> return Tez.zero + | Some current_delegate -> Delegate.staking_balance ctxt current_delegate) + >>>=? fun staking_balance -> + (* Slash the deposit *) + Token.transfer + ctxt + deposit_account + `Tx_rollup_rejection_punishments + deposit_amount + >>>=? fun (ctxt, _) -> + (* Fetch staking balance after slash. *) + (match current_delegate with + | None -> return_unit + | Some current_delegate -> + Delegate.staking_balance ctxt current_delegate + >>>=? fun staking_balance' -> + (* Ensure balance slashed *) + Assert.equal_tez + ~loc:__LOC__ + staking_balance' + (staking_balance -! deposit_amount)) + >|=? fun () -> ctxt + in + let do_undelegate ?(delegate = delegate1) ctxt amount = + (* Fetch staking balance before undelegate *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance -> + (* Fetch user's initial balance before undelegate. *) + Token.balance ctxt user_account >>>=? fun (_, user_balance) -> + (* Remove delegation. *) + Delegate.set ctxt user_contract None >>>=? fun ctxt -> + (* Fetch staking balance after delegation removal. *) + Delegate.staking_balance ctxt delegate >>>=? fun staking_balance' -> + (* Ensure staking balance decreased by delegation amount *) + Assert.equal_tez ~loc:__LOC__ staking_balance' (staking_balance -! amount) + >>=? fun () -> + (* Fetch user's balance again. *) + Token.balance ctxt user_account >>>=? fun (_, user_balance') -> + (* Ensure user's balance unchanged. *) + Assert.equal_tez ~loc:__LOC__ user_balance' user_balance >|=? fun () -> ctxt + in + let initial_ctxt = ctxt in + (* delegate-then-freeze *) + do_delegate ctxt >>=? fun (ctxt, amount_delegated) -> + do_freeze ctxt >>=? fun ctxt -> + scenario + ctxt + ~accounts:(deposit_account1, deposit_account2) + ~delegates:(delegate1, delegate2) + amount_delegated + ~do_delegate + ~do_undelegate + ~do_freeze + ~do_unfreeze + ~do_slash + >>=? fun () -> + (* freeze-then-delegate *) + let ctxt = initial_ctxt in + do_freeze ctxt >>=? fun ctxt -> + do_delegate ctxt >>=? fun (ctxt, amount_delegated) -> + scenario + ctxt + ~accounts:(deposit_account1, deposit_account2) + ~delegates:(delegate1, delegate2) + amount_delegated + ~do_delegate + ~do_undelegate + ~do_freeze + ~do_unfreeze + ~do_slash + +let test_delegate_freeze_unfreeze_undelegate () = + test_scenario + (fun + ctxt + ~accounts:_ + ~delegates:_ + amount_delegated + ~do_delegate:_ + ~do_undelegate + ~do_freeze:_ + ~do_unfreeze + ~do_slash:_ + -> + do_unfreeze ctxt >>=? fun ctxt -> + do_undelegate ctxt amount_delegated >>=? fun _ -> return_unit) + +let test_delegate_freeze_undelegate_unfreeze () = + test_scenario + (fun + ctxt + ~accounts:_ + ~delegates:_ + amount_delegated + ~do_delegate:_ + ~do_undelegate + ~do_freeze:_ + ~do_unfreeze + ~do_slash:_ + -> + do_undelegate ctxt amount_delegated >>=? fun ctxt -> + do_unfreeze ctxt >>=? fun _ -> return_unit) + +let test_delegate_double_freeze_undelegate_unfreeze () = + test_scenario + (fun + ctxt + ~accounts:(deposit_account1, deposit_account2) + ~delegates:_ + amount_delegated + ~do_delegate:_ + ~do_undelegate + ~do_freeze + ~do_unfreeze + ~do_slash:_ + -> + do_freeze ~deposit_account:deposit_account2 ctxt >>=? fun ctxt -> + do_undelegate ctxt amount_delegated >>=? fun ctxt -> + do_unfreeze ~deposit_account:deposit_account1 ctxt >>=? fun _ -> + return_unit) + +let test_delegate_freeze_redelegate_unfreeze () = + test_scenario + (fun + ctxt + ~accounts:_ + ~delegates:(_delegate1, delegate2) + _amount_delegated + ~do_delegate + ~do_undelegate + ~do_freeze:_ + ~do_unfreeze + ~do_slash:_ + -> + do_delegate ~delegate:delegate2 ctxt >>=? fun (ctxt, amount2) -> + do_unfreeze ctxt >>=? fun ctxt -> + do_undelegate ~delegate:delegate2 ctxt amount2 >>=? fun _ -> return_unit) + +let test_delegate_freeze_unfreeze_freeze_redelegate () = + test_scenario + (fun + ctxt + ~accounts:_ + ~delegates:(_delegate1, delegate2) + _amount_delegated + ~do_delegate + ~do_undelegate + ~do_freeze + ~do_unfreeze + ~do_slash:_ + -> + do_unfreeze ctxt >>=? fun ctxt -> + do_freeze ctxt >>=? fun ctxt -> + do_delegate ~delegate:delegate2 ctxt >>=? fun (ctxt, amount2) -> + do_undelegate ~delegate:delegate2 ctxt amount2 >>=? fun _ -> return_unit) + +let test_delegate_freeze_slash_undelegate () = + let slash_amount = Tez.of_mutez_exn 1000L in + test_scenario + (fun + ctxt + ~accounts:_ + ~delegates:_ + amount_delegated + ~do_delegate:_ + ~do_undelegate + ~do_freeze:_ + ~do_unfreeze:_ + ~do_slash + -> + do_slash ctxt >>=? fun ctxt -> + do_undelegate ctxt (amount_delegated -! slash_amount) >>=? fun _ -> + return_unit) + let tests = Tztest. [ @@ -347,4 +593,28 @@ let tests = `Quick (test_total_stake ~user_is_delegate:true); tztest "frozen bonds - test rpcs" `Quick test_rpcs; + tztest + "test: delegate, freeze, unfreeze, undelegate" + `Quick + test_delegate_freeze_unfreeze_undelegate; + tztest + "test: delegate, freeze, undelegate, unfreeze" + `Quick + test_delegate_freeze_undelegate_unfreeze; + tztest + "test: delegate, double freeze, undelegate, unfreeze" + `Quick + test_delegate_double_freeze_undelegate_unfreeze; + tztest + "test: delegate, freeze, redelegate, unfreeze" + `Quick + test_delegate_freeze_redelegate_unfreeze; + tztest + "test: delegate, freeze, unfreeze, freeze, redelegate" + `Quick + test_delegate_freeze_unfreeze_freeze_redelegate; + tztest + "test: delegate, freeze, slash, undelegate" + `Quick + test_delegate_freeze_slash_undelegate; ]