ligo/vendors/ligo-utils/tezos-protocol-alpha/test/rolls.ml
2019-10-17 11:45:27 +02:00

251 lines
12 KiB
OCaml

(*****************************************************************************)
(* *)
(* Open Source License *)
(* Copyright (c) 2018 Dynamic Ledger Solutions, Inc. <contact@tezos.com> *)
(* *)
(* Permission is hereby granted, free of charge, to any person obtaining a *)
(* copy of this software and associated documentation files (the "Software"),*)
(* to deal in the Software without restriction, including without limitation *)
(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *)
(* and/or sell copies of the Software, and to permit persons to whom the *)
(* Software is furnished to do so, subject to the following conditions: *)
(* *)
(* The above copyright notice and this permission notice shall be included *)
(* in all copies or substantial portions of the Software. *)
(* *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *)
(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *)
(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *)
(* DEALINGS IN THE SOFTWARE. *)
(* *)
(*****************************************************************************)
open Protocol
open Alpha_context
open Test_tez
open Test_utils
let account_pair = function
| [a1; a2] -> (a1, a2)
| _ -> assert false
let wrap e = Lwt.return (Environment.wrap_error e)
let traverse_rolls ctxt head =
let rec loop acc roll =
Storage.Roll.Successor.get_option ctxt roll >>= wrap >>=? function
| None -> return (List.rev acc)
| Some next -> loop (next :: acc) next in
loop [head] head
let get_rolls ctxt delegate =
Storage.Roll.Delegate_roll_list.get_option ctxt delegate >>= wrap >>=? function
| None -> return_nil
| Some head_roll -> traverse_rolls ctxt head_roll
let check_rolls b (account:Account.t) =
Context.get_constants (B b) >>=? fun constants ->
Context.Delegate.info (B b) account.pkh >>=? fun { staking_balance ; _ } ->
let token_per_roll = constants.parametric.tokens_per_roll in
let expected_rolls = Int64.div (Tez.to_mutez staking_balance) (Tez.to_mutez token_per_roll) in
Raw_context.prepare b.context
~level:b.header.shell.level
~predecessor_timestamp:b.header.shell.timestamp
~timestamp:b.header.shell.timestamp
~fitness:b.header.shell.fitness >>= wrap >>=? fun ctxt ->
get_rolls ctxt account.pkh >>=? fun rolls ->
Assert.equal_int ~loc:__LOC__ (List.length rolls) (Int64.to_int expected_rolls)
let check_no_rolls (b : Block.t) (account:Account.t) =
Raw_context.prepare b.context
~level:b.header.shell.level
~predecessor_timestamp:b.header.shell.timestamp
~timestamp:b.header.shell.timestamp
~fitness:b.header.shell.fitness >>= wrap >>=? fun ctxt ->
get_rolls ctxt account.pkh >>=? fun rolls ->
Assert.equal_int ~loc:__LOC__ (List.length rolls) 0
let simple_staking_rights () =
Context.init 2 >>=? fun (b,accounts) ->
let (a1, _a2) = account_pair accounts in
Context.Contract.balance (B b) a1 >>=? fun balance ->
Context.Contract.manager (B b) a1 >>=? fun m1 ->
Context.Delegate.info (B b) m1.pkh >>=? fun info ->
Assert.equal_tez ~loc:__LOC__ balance info.staking_balance >>=? fun () ->
check_rolls b m1
let simple_staking_rights_after_baking () =
Context.init 2 >>=? fun (b,accounts) ->
let (a1, a2) = account_pair accounts in
Context.Contract.balance (B b) a1 >>=? fun balance ->
Context.Contract.manager (B b) a1 >>=? fun m1 ->
Context.Contract.manager (B b) a2 >>=? fun m2 ->
Block.bake_n ~policy:(By_account m2.pkh) 5 b >>=? fun b ->
Context.Delegate.info (B b) m1.pkh >>=? fun info ->
Assert.equal_tez ~loc:__LOC__ balance info.staking_balance >>=? fun () ->
check_rolls b m1 >>=? fun () ->
check_rolls b m2
let frozen_deposit (info:Context.Delegate.info) =
Cycle.Map.fold (fun _ { Delegate.deposit ; _ } acc ->
Test_tez.Tez.(deposit + acc))
info.frozen_balance_by_cycle Tez.zero
let check_activate_staking_balance ~loc ~deactivated b (a, (m:Account.t)) =
Context.Delegate.info (B b) m.pkh >>=? fun info ->
Assert.equal_bool ~loc info.deactivated deactivated >>=? fun () ->
Context.Contract.balance (B b) a >>=? fun balance ->
let deposit = frozen_deposit info in
Assert.equal_tez ~loc Test_tez.Tez.(balance + deposit) info.staking_balance
let run_until_deactivation () =
Context.init 2 >>=? fun (b,accounts) ->
let (a1, a2) = account_pair accounts in
Context.Contract.balance (B b) a1 >>=? fun balance_start ->
Context.Contract.manager (B b) a1 >>=? fun m1 ->
Context.Contract.manager (B b) a2 >>=? fun m2 ->
check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b (a1,m1) >>=? fun () ->
Context.Delegate.info (B b) m1.pkh >>=? fun info ->
Block.bake_until_cycle ~policy:(By_account m2.pkh) info.grace_period b >>=? fun b ->
check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b (a1,m1) >>=? fun () ->
Block.bake_until_cycle_end ~policy:(By_account m2.pkh) b >>=? fun b ->
check_activate_staking_balance ~loc:__LOC__ ~deactivated:true b (a1,m1) >>=? fun () ->
return (b, ((a1, m1), balance_start), (a2, m2))
let deactivation_then_bake () =
run_until_deactivation () >>=?
fun (b, ((_deactivated_contract, deactivated_account) as deactivated, _start_balance),
(_a2, _m2)) ->
Block.bake ~policy:(By_account deactivated_account.pkh) b >>=? fun b ->
check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b deactivated >>=? fun () ->
check_rolls b deactivated_account
let deactivation_then_self_delegation () =
run_until_deactivation () >>=?
fun (b, ((deactivated_contract, deactivated_account) as deactivated, start_balance),
(_a2, m2)) ->
Op.delegation (B b) deactivated_contract (Some deactivated_account.pkh) >>=? fun self_delegation ->
Block.bake ~policy:(By_account m2.pkh) b ~operation:self_delegation >>=? fun b ->
check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b deactivated >>=? fun () ->
Context.Contract.balance (B b) deactivated_contract >>=? fun balance ->
Assert.equal_tez ~loc:__LOC__ start_balance balance >>=? fun () ->
check_rolls b deactivated_account
let deactivation_then_empty_then_self_delegation () =
run_until_deactivation () >>=?
fun (b, ((deactivated_contract, deactivated_account) as deactivated, _start_balance),
(_a2, m2)) ->
(* empty the contract *)
Context.Contract.balance (B b) deactivated_contract >>=? fun balance ->
let sink_account = Account.new_account () in
let sink_contract = Contract.implicit_contract sink_account.pkh in
Context.get_constants (B b) >>=? fun { parametric = { origination_size ; cost_per_byte ; _ } ; _ } ->
Tez.(cost_per_byte *? Int64.of_int origination_size) >>?= fun origination_burn ->
let amount = match Tez.(balance -? origination_burn) with Ok r -> r | Error _ -> assert false in
Op.transaction (B b) deactivated_contract sink_contract amount >>=? fun empty_contract ->
Block.bake ~policy:(By_account m2.pkh) ~operation:empty_contract b >>=? fun b ->
(* self delegation *)
Op.delegation (B b) deactivated_contract (Some deactivated_account.pkh) >>=? fun self_delegation ->
Block.bake ~policy:(By_account m2.pkh) ~operation:self_delegation b >>=? fun b ->
check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b deactivated >>=? fun () ->
Context.Contract.balance (B b) deactivated_contract >>=? fun balance ->
Assert.equal_tez ~loc:__LOC__ Tez.zero balance >>=? fun () ->
check_rolls b deactivated_account
let deactivation_then_empty_then_self_delegation_then_recredit () =
run_until_deactivation () >>=?
fun (b, ((deactivated_contract, deactivated_account) as deactivated, balance),
(_a2, m2)) ->
(* empty the contract *)
let sink_account = Account.new_account () in
let sink_contract = Contract.implicit_contract sink_account.pkh in
Context.get_constants (B b) >>=? fun { parametric = { origination_size ; cost_per_byte ; _ } ; _ } ->
Tez.(cost_per_byte *? Int64.of_int origination_size) >>?= fun origination_burn ->
let amount = match Tez.(balance -? origination_burn) with Ok r -> r | Error _ -> assert false in
Op.transaction (B b) deactivated_contract sink_contract amount >>=? fun empty_contract ->
Block.bake ~policy:(By_account m2.pkh) ~operation:empty_contract b >>=? fun b ->
(* self delegation *)
Op.delegation (B b) deactivated_contract (Some deactivated_account.pkh) >>=? fun self_delegation ->
Block.bake ~policy:(By_account m2.pkh) ~operation:self_delegation b >>=? fun b ->
(* recredit *)
Op.transaction (B b) sink_contract deactivated_contract amount >>=? fun recredit_contract ->
Block.bake ~policy:(By_account m2.pkh) ~operation:recredit_contract b >>=? fun b ->
check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b deactivated >>=? fun () ->
Context.Contract.balance (B b) deactivated_contract >>=? fun balance ->
Assert.equal_tez ~loc:__LOC__ amount balance >>=? fun () ->
check_rolls b deactivated_account
let delegation () =
Context.init 2 >>=? fun (b,accounts) ->
let (a1, a2) = account_pair accounts in
let m3 = Account.new_account () in
Account.add_account m3;
Context.Contract.manager (B b) a1 >>=? fun m1 ->
Context.Contract.manager (B b) a2 >>=? fun m2 ->
let a3 = Contract.implicit_contract m3.pkh in
Context.Contract.delegate_opt (B b) a1 >>=? fun delegate ->
begin
match delegate with
| None -> assert false
| Some pkh ->
assert (Signature.Public_key_hash.equal pkh m1.pkh)
end;
Op.transaction (B b) a1 a3 Tez.fifty_cents >>=? fun transact ->
Block.bake ~policy:(By_account m2.pkh) b ~operation:transact >>=? fun b ->
Context.Contract.delegate_opt (B b) a3 >>=? fun delegate ->
begin
match delegate with
| None -> ()
| Some _ -> assert false
end;
check_no_rolls b m3 >>=? fun () ->
Op.delegation (B b) a3 (Some m3.pkh) >>=? fun delegation ->
Block.bake ~policy:(By_account m2.pkh) b ~operation:delegation >>=? fun b ->
Context.Contract.delegate_opt (B b) a3 >>=? fun delegate ->
begin
match delegate with
| None -> assert false
| Some pkh ->
assert (Signature.Public_key_hash.equal pkh m3.pkh)
end;
check_activate_staking_balance ~loc:__LOC__ ~deactivated:false b (a3,m3) >>=? fun () ->
check_rolls b m3 >>=? fun () ->
check_rolls b m1
let tests = [
Test.tztest "simple staking rights" `Quick (simple_staking_rights) ;
Test.tztest "simple staking rights after baking" `Quick (simple_staking_rights_after_baking) ;
Test.tztest "deactivation then bake" `Quick (deactivation_then_bake) ;
Test.tztest "deactivation then self delegation" `Quick (deactivation_then_self_delegation) ;
Test.tztest "deactivation then empty then self delegation" `Quick (deactivation_then_empty_then_self_delegation) ;
Test.tztest "deactivation then empty then self delegation then recredit" `Quick (deactivation_then_empty_then_self_delegation_then_recredit) ;
Test.tztest "delegation" `Quick (delegation) ;
]