diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.ml b/src/proto_alpha/lib_protocol/test/helpers/block.ml index 69ff845c4c97a8231d1a8d1df264d7a719d08a1d..164fc047b9d1cbe4def685d64cedee64a2f6b3c1 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/block.ml @@ -35,6 +35,7 @@ type t = { header : Block_header.t; operations : Operation.packed list; context : Tezos_protocol_environment.Context.t; + constants : Constants.Parametric.t; } type block = t @@ -475,6 +476,7 @@ let genesis_with_parameters parameters = header = {shell; protocol_data = {contents; signature = Signature.zero}}; operations = []; context; + constants = parameters.constants; } let validate_bootstrap_accounts @@ -640,6 +642,7 @@ let genesis ?commitments ?consensus_threshold ?min_proposal_quorum header = {shell; protocol_data = {contents; signature = Signature.zero}}; operations = []; context; + constants; } let alpha_context ?commitments ?min_proposal_quorum @@ -788,9 +791,11 @@ let apply_with_metadata ?(policy = By_round 0) ?(check_size = true) ~baking_mode finalize_validation_and_application vstate (Some header.shell) >|= Environment.wrap_tzresult >|=? fun (validation, result) -> (validation.context, result) ) - >|=? fun (context, result) -> + >>=? fun (context, result) -> let hash = Block_header.hash header in - ({hash; header; operations; context}, result) + (* This function is duplicated from Context to avoid a cyclic dependency *) + Alpha_services.Constants.all rpc_ctxt pred >|=? fun constants -> + ({hash; header; operations; context; constants = constants.parametric}, result) let apply header ?(operations = []) ?(allow_manager_failures = false) pred = apply_with_metadata @@ -870,9 +875,6 @@ let bake ?(baking_mode = Application) ?(allow_manager_failures = false) (********** Cycles ****************) -(* This function is duplicated from Context to avoid a cyclic dependency *) -let get_constants b = Alpha_services.Constants.all rpc_ctxt b - let bake_n ?(baking_mode = Application) ?policy ?liquidity_baking_toggle_vote ?adaptive_inflation_vote n b = List.fold_left_es @@ -887,8 +889,10 @@ let bake_n ?(baking_mode = Application) ?policy ?liquidity_baking_toggle_vote (1 -- n) let rec bake_while_with_metadata ?(baking_mode = Application) ?policy - ?liquidity_baking_toggle_vote ?adaptive_inflation_vote predicate b = + ?liquidity_baking_toggle_vote ?adaptive_inflation_vote + ?(invariant = fun _ -> return_unit) predicate b = let open Lwt_result_syntax in + let* () = invariant b in let* new_block, metadata = bake_with_metadata ~baking_mode @@ -903,17 +907,19 @@ let rec bake_while_with_metadata ?(baking_mode = Application) ?policy ?policy ?liquidity_baking_toggle_vote ?adaptive_inflation_vote + ~invariant predicate new_block else return b let bake_while ?baking_mode ?policy ?liquidity_baking_toggle_vote - ?adaptive_inflation_vote predicate b = + ?adaptive_inflation_vote ?invariant predicate b = bake_while_with_metadata ?baking_mode ?policy ?liquidity_baking_toggle_vote ?adaptive_inflation_vote + ?invariant (fun block _metadata -> predicate block) b @@ -1029,7 +1035,7 @@ let bake_n_with_liquidity_baking_toggle_ema ?(baking_mode = Application) ?policy (1 -- n) let bake_until_cycle_end ?policy b = - get_constants b >>=? fun Constants.{parametric = {blocks_per_cycle; _}; _} -> + let blocks_per_cycle = b.constants.blocks_per_cycle in let current_level = b.header.shell.level in let current_level = Int32.rem current_level blocks_per_cycle in let delta = Int32.sub blocks_per_cycle current_level in @@ -1039,15 +1045,15 @@ let bake_until_n_cycle_end ?policy n b = List.fold_left_es (fun b _ -> bake_until_cycle_end ?policy b) b (1 -- n) let current_cycle b = - get_constants b >>=? fun Constants.{parametric = {blocks_per_cycle; _}; _} -> + let blocks_per_cycle = b.constants.blocks_per_cycle in let current_level = b.header.shell.level in let current_cycle = Int32.div current_level blocks_per_cycle in let current_cycle = Cycle.add Cycle.root (Int32.to_int current_cycle) in - return current_cycle + current_cycle let bake_until_cycle ?policy cycle (b : t) = let rec loop (b : t) = - current_cycle b >>=? fun current_cycle -> + let current_cycle = current_cycle b in if Cycle.equal cycle current_cycle then return b else bake_until_cycle_end ?policy b >>=? fun b -> loop b in diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.mli b/src/proto_alpha/lib_protocol/test/helpers/block.mli index 7eca613dbba5808b61fe495414a385a8c19fdaf4..c7cafb6949b7c47086ae4f8540b31c68947ebc00 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/block.mli @@ -33,6 +33,7 @@ type t = { header : Block_header.t; operations : Operation.packed list; context : Tezos_protocol_environment.Context.t; (** Resulting context *) + constants : Constants.Parametric.t; } type block = t @@ -287,20 +288,36 @@ val bake_n_with_metadata : block -> (block * block_header_metadata, Error_monad.tztrace) result Lwt.t -(* Bake blocks while a predicate over the block and its metadata - holds. The returned block is the last one for which the predicate - holds; in case the predicate never holds, the input block is - returned. *) +(** Bake blocks while a predicate over the block holds. The returned + block is the last one for which the predicate holds; in case the + predicate never holds, the input block is returned. When the + optional [invariant] argument is provided, it is checked on the + input block and on each baked block, including the returned one + (the last one satisfy the predicate); it is however not checked + on the next block (the first one to invalidate the predicate). *) +val bake_while : + ?baking_mode:baking_mode -> + ?policy:baker_policy -> + ?liquidity_baking_toggle_vote:Toggle_votes_repr.toggle_vote -> + ?adaptive_inflation_vote:Toggle_votes_repr.toggle_vote -> + ?invariant:(block -> unit tzresult Lwt.t) -> + (block -> bool) -> + block -> + block tzresult Lwt.t + +(* Same as [bake_while] but the predicate also has access to the + metadata resulting from the application of the block. *) val bake_while_with_metadata : ?baking_mode:baking_mode -> ?policy:baker_policy -> ?liquidity_baking_toggle_vote:Toggle_votes_repr.toggle_vote -> ?adaptive_inflation_vote:Toggle_votes_repr.toggle_vote -> + ?invariant:(block -> unit tzresult Lwt.t) -> (block -> block_header_metadata -> bool) -> block -> block tzresult Lwt.t -val current_cycle : t -> Cycle.t tzresult Lwt.t +val current_cycle : t -> Cycle.t (** Given a block [b] at level [l] bakes enough blocks to complete a cycle, that is [blocks_per_cycle - (l % blocks_per_cycle)]. *) diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.ml b/src/proto_alpha/lib_protocol/test/helpers/context.ml index 721bb1b46ce7835f6f9466e3aac4fccccdce59ee..65eb5847af2423b6d4f95ca7c8e861a480e74007 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/context.ml @@ -254,6 +254,9 @@ let get_liquidity_baking_cpmm_address ctxt = let get_adaptive_inflation_launch_cycle ctxt = Adaptive_inflation_services.launch_cycle rpc_ctxt ctxt +let get_total_frozen_stake ctxt = + Adaptive_inflation_services.total_frozen_stake rpc_ctxt ctxt + let get_seed_nonce_revelation_tip ctxt = get_constants ctxt >>=? fun {Constants.parametric = csts; _} -> return diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.mli b/src/proto_alpha/lib_protocol/test/helpers/context.mli index 9cc1b0dfbdc6d4da9e45296671e43d89bac8ec93..32f9b2fc6e1e99e3d509f17327aae794b3d4e8b4 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/context.mli @@ -118,6 +118,8 @@ val get_liquidity_baking_cpmm_address : t -> Contract_hash.t tzresult Lwt.t val get_adaptive_inflation_launch_cycle : t -> Cycle.t option tzresult Lwt.t +val get_total_frozen_stake : t -> Tez.t tzresult Lwt.t + val get_seed_nonce_revelation_tip : t -> Tez.t tzresult Lwt.t val get_vdf_revelation_tip : t -> Tez.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/helpers/incremental.ml b/src/proto_alpha/lib_protocol/test/helpers/incremental.ml index 08b512e6834d19b92bb0731357e77e17d3aaf3e5..0b191f089c67723d6d3c634362b5a97e524445ec 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/incremental.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/incremental.ml @@ -278,7 +278,15 @@ let finalize_block st = } in let hash = Block_header.hash header in - return {Block.hash; header; operations; context = validation_result.context} + let* constants = Alpha_services.Constants.all Block.rpc_ctxt st.predecessor in + return + { + Block.hash; + header; + operations; + context = validation_result.context; + constants = constants.parametric; + } let assert_validate_operation_fails expect_failure op block = let open Lwt_result_syntax in diff --git a/src/proto_alpha/lib_protocol/test/integration/gas/test_gas_levels.ml b/src/proto_alpha/lib_protocol/test/integration/gas/test_gas_levels.ml index 7732e31ee87faad542f5b8d91a010a82577cb159..0a2d878826e319a236eb3ad70cb828acc2a17d5a 100644 --- a/src/proto_alpha/lib_protocol/test/integration/gas/test_gas_levels.ml +++ b/src/proto_alpha/lib_protocol/test/integration/gas/test_gas_levels.ml @@ -233,7 +233,8 @@ let apply_with_gas header ?(operations = []) (pred : Block.t) = >|= Environment.wrap_tzresult >|=? fun (context, consumed_gas) -> let hash = Block_header.hash header in - ({Block.hash; header; operations; context}, consumed_gas) + ( {Block.hash; header; operations; context; constants = pred.constants}, + consumed_gas ) let bake_with_gas ?policy ?timestamp ?operation ?operations pred = let operations = diff --git a/src/proto_alpha/lib_protocol/test/integration/test_adaptive_inflation_launch.ml b/src/proto_alpha/lib_protocol/test/integration/test_adaptive_inflation_launch.ml index e83b840e067e118d1afe8765a1a397d3d8142159..54debbc98538d10af44880c0d08d65253c51bc8c 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_adaptive_inflation_launch.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_adaptive_inflation_launch.ml @@ -63,8 +63,7 @@ let assert_cycle_eq ~loc c1 c2 = c2 let assert_current_cycle ~loc (blk : Block.t) expected = - let open Lwt_result_syntax in - let* current_cycle = Block.current_cycle blk in + let current_cycle = Block.current_cycle blk in assert_cycle_eq ~loc current_cycle expected let stake ctxt contract amount = @@ -72,7 +71,13 @@ let stake ctxt contract amount = let*?@ entrypoint = Protocol.Alpha_context.Entrypoint.of_string_strict ~loc:0 "stake" in - Op.transaction ctxt ~entrypoint contract contract amount + Op.transaction + ctxt + ~entrypoint + ~fee:Protocol.Alpha_context.Tez.zero + contract + contract + amount let set_delegate_parameters ctxt delegate ~staking_over_baking_limit ~baking_over_staking_edge = @@ -94,18 +99,26 @@ let set_delegate_parameters ctxt delegate ~staking_over_baking_limit ctxt ~entrypoint ~parameters + ~fee:Protocol.Alpha_context.Tez.zero delegate delegate Protocol.Alpha_context.Tez.zero +(** Assert that the staking balance is the expected one. *) +let assert_total_frozen_stake ~loc block expected = + let open Lwt_result_syntax in + let* actual = Context.get_total_frozen_stake (B block) in + Assert.equal_tez ~loc actual expected + (* Test that: - the EMA of the adaptive inflation vote reaches the threshold after the expected duration, - the launch cycle is set as soon as the threshold is reached, - the launch cycle is not reset before it is reached, - - once the launch cycle is reached, costaking is allowed. *) + - once the launch cycle is reached, costaking is allowed, + - costaking increases total_frozen_stake. *) let test_launch threshold expected_vote_duration () = - let open Lwt_result_syntax in + let open Lwt_result_wrap_syntax in let assert_ema_above_threshold ~loc (metadata : Protocol.Main.block_header_metadata) = let ema = @@ -115,7 +128,7 @@ let test_launch threshold expected_vote_duration () = Assert.lt_int32 ~loc threshold ema in (* Initialize the state with a single delegate. *) - let* block, delegate = + let constants = let default_constants = Default_parameters.constants_test in let adaptive_inflation = { @@ -124,11 +137,18 @@ let test_launch threshold expected_vote_duration () = } in let consensus_threshold = 0 in - Context.init_with_constants1 - {default_constants with consensus_threshold; adaptive_inflation} + {default_constants with consensus_threshold; adaptive_inflation} in + let preserved_cycles = constants.preserved_cycles in + let* block, delegate = Context.init_with_constants1 constants in let delegate_pkh = Context.Contract.pkh delegate in let* () = assert_is_not_yet_set_to_launch ~loc:__LOC__ block in + let* () = + assert_total_frozen_stake + ~loc:__LOC__ + block + (Protocol.Alpha_context.Tez.of_mutez_exn 200_000_000_000L) + in (* To test that adaptive inflation is active, we test that costaking, a feature only available after the activation, is @@ -136,14 +156,21 @@ let test_launch threshold expected_vote_duration () = explicitely set a positive staking_over_baking_limit to allow them. Setting this limit does not immediately take effect but can be done before the activation. For these reasons, we set it at - the beginning. *) + the beginning. + + The baking_over_staking_edge indicates the portion of the rewards + sent to the delegate's liquid balance. It's expressed in + billionth, with 0 meaning that everything is frozen and one + billion meaning that everything is liquid. We send all rewards to + the liquid part to ease reasoning about the total frozen + stake. *) let* block = let* operation = set_delegate_parameters (B block) delegate - ~staking_over_baking_limit:1 - ~baking_over_staking_edge:0 + ~staking_over_baking_limit:1_000_000 + ~baking_over_staking_edge:1_000_000_000 in Block.bake ~operation ~adaptive_inflation_vote:Toggle_vote_on block in @@ -167,7 +194,7 @@ let test_launch threshold expected_vote_duration () = (B block) delegate wannabe_costaker - (Protocol.Alpha_context.Tez.of_mutez_exn 1_000_000_000L) + (Protocol.Alpha_context.Tez.of_mutez_exn 2_000_000_000_000L) in Block.bake ~operation ~adaptive_inflation_vote:Toggle_vote_on block in @@ -181,6 +208,16 @@ let test_launch threshold expected_vote_duration () = in Block.bake ~operation ~adaptive_inflation_vote:Toggle_vote_on block in + (* Self-staking most of the remaining balance. *) + let* block = + let* operation = + stake + (B block) + delegate + (Protocol.Alpha_context.Tez.of_mutez_exn 1_800_000_000_000L) + in + Block.bake ~operation ~adaptive_inflation_vote:Toggle_vote_on block + in (* We are now ready to activate the feature through by baking many more blocks voting in favor of the activation until the EMA @@ -241,30 +278,62 @@ let test_launch threshold expected_vote_duration () = (* Check that the current cycle is the one at which the launch is planned to happen. *) let* () = assert_current_cycle ~loc:__LOC__ block launch_cycle in + (* At this point, only the delegate has frozen any stake and its + frozen balance is about 2 million tez (it started with 4 million, + sent half to its delegate, and staked the rest). *) + let* () = + assert_total_frozen_stake + ~loc:__LOC__ + block + (Protocol.Alpha_context.Tez.of_mutez_exn 2_000_000_000_000L) + in - (* Test that the wannabe costaker is now allowed to stake a few - mutez. *) - let* operation = - stake - (B block) - wannabe_costaker - (Protocol.Alpha_context.Tez.of_mutez_exn 10L) + (* Test that the wannabe costaker is now allowed to stake almost all + its balance. It cannot totally costake it however because this is + considered by the protocol as an attempt to empty the account, and + emptying delegated accounts is forbidden. *) + let* balance = Context.Contract.balance (B block) wannabe_costaker in + let*?@ balance_to_stake = Protocol.Alpha_context.Tez.(balance -? one) in + let* operation = stake (B block) wannabe_costaker balance_to_stake in + let* block = Block.bake ~operation block in + (* The costaking operation leads to an increase of the + total_frozen_stake but only preserved_cycles after the + operation. *) + let start_cycle = Block.current_cycle block in + let* block = + Block.bake_while + ~invariant:(fun block -> + assert_total_frozen_stake + ~loc:__LOC__ + block + (Protocol.Alpha_context.Tez.of_mutez_exn 2_000_000_000_000L)) + (fun block -> + let current_cycle = Block.current_cycle block in + Protocol.Alpha_context.Cycle.( + current_cycle <= add start_cycle preserved_cycles)) + block + in + let* block = Block.bake block in + let* () = + assert_total_frozen_stake + ~loc:__LOC__ + block + (Protocol.Alpha_context.Tez.of_mutez_exn 3_999_999_000_000L) in - let* (_block : Block.t) = Block.bake ~operation block in return_unit let tests = [ Tztest.tztest "the EMA reaches the vote threshold at the expected level and adaptive \ - inflation launch cycle is set (very low threshold)" + inflation launches (very low threshold)" `Quick (test_launch 1000000l (* This means that the threshold is set at 0.05% *) 59l); Tztest.tztest "the EMA reaches the vote threshold at the expected level and adaptive \ - inflation launch cycle is set (realistic threshold)" + inflation launches (realistic threshold)" `Slow (test_launch Default_parameters.constants_test.adaptive_inflation