diff --git a/src/proto_alpha/lib_protocol/per_block_votes_repr.ml b/src/proto_alpha/lib_protocol/per_block_votes_repr.ml index a30dd1bc94811af630b56ad4d74758ee68dd0a14..f61b6e633a703de78b62372157b582f007de0e9a 100644 --- a/src/proto_alpha/lib_protocol/per_block_votes_repr.ml +++ b/src/proto_alpha/lib_protocol/per_block_votes_repr.ml @@ -36,6 +36,8 @@ type per_block_votes = { adaptive_issuance_vote : per_block_vote; } +let ema_max = 2_000_000_000l + let per_block_vote_compact_encoding = let open Data_encoding in let open Compact in @@ -93,7 +95,7 @@ let per_block_votes_encoding = module Liquidity_baking_toggle_EMA = Votes_EMA_repr.Make (struct let baker_contribution = Z.of_int 500_000 - let ema_max = 2_000_000_000l + let ema_max = ema_max end) module Adaptive_issuance_launch_EMA = Votes_EMA_repr.Make (struct @@ -111,7 +113,7 @@ module Adaptive_issuance_launch_EMA = Votes_EMA_repr.Make (struct blocks are actually needed. *) let baker_contribution = Z.of_int 5730 - let ema_max = 2_000_000_000l + let ema_max = ema_max end) let compute_new_liquidity_baking_ema ~per_block_vote ema = @@ -125,3 +127,7 @@ let compute_new_adaptive_issuance_ema ~per_block_vote ema = | Per_block_vote_pass -> ema | Per_block_vote_off -> Adaptive_issuance_launch_EMA.update_ema_down ema | Per_block_vote_on -> Adaptive_issuance_launch_EMA.update_ema_up ema + +module Internal_for_tests = struct + let ema_max = ema_max +end diff --git a/src/proto_alpha/lib_protocol/per_block_votes_repr.mli b/src/proto_alpha/lib_protocol/per_block_votes_repr.mli index 6b026bf85f7fcc88281990155570e7f05e713908..abaa67352d9b4c5445757822df760b9b05a05010 100644 --- a/src/proto_alpha/lib_protocol/per_block_votes_repr.mli +++ b/src/proto_alpha/lib_protocol/per_block_votes_repr.mli @@ -81,3 +81,8 @@ val compute_new_adaptive_issuance_ema : per_block_vote:per_block_vote -> Adaptive_issuance_launch_EMA.t -> Adaptive_issuance_launch_EMA.t + +module Internal_for_tests : sig + (* Maximum value for EMA representation (both LB and AI) *) + val ema_max : Int32.t +end diff --git a/src/proto_alpha/lib_protocol/test/helpers/scenario_bake.ml b/src/proto_alpha/lib_protocol/test/helpers/scenario_bake.ml index 2f66162f1ea1dda59054806de1d85c876c679e2f..e42b9f6206e30a9cc810d9ee4bc2f3a356fef30d 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/scenario_bake.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/scenario_bake.ml @@ -10,7 +10,6 @@ open State open Scenario_dsl open Log_helpers open Scenario_base -open Adaptive_issuance_helpers (** Applies when baking the last block of a cycle *) let apply_end_cycle current_cycle previous_block block state : @@ -164,7 +163,7 @@ let bake ?baker : t -> t tzresult Lwt.t = baker_name ; let current_cycle = Block.current_cycle block in let adaptive_issuance_vote = - if state.activate_ai then + if state.force_ai_vote_yes then Protocol.Alpha_context.Per_block_votes.Per_block_vote_on else Per_block_vote_pass in @@ -313,6 +312,8 @@ let wait_cycle_until condition = let rec get_names condition = match condition with | `AI_activation -> ("AI activation", "AI activated") + | `AI_activation_with_votes -> + ("AI activation (with votes)", "AI activated") | `delegate_parameters_activation -> ("delegate parameters activation", "delegate parameters activated") | `And (cond1, cond2) -> @@ -323,36 +324,54 @@ let wait_cycle_until condition = get_names condition in let condition (init_block, init_state) = - let open Lwt_result_syntax in let rec stopper condition = match condition with - | `AI_activation -> + | `AI_activation -> ( fun (block, _state) -> - if init_state.State.activate_ai then - let* launch_cycle = get_launch_cycle ~loc:__LOC__ init_block in - let current_cycle = Block.current_cycle block in - return Cycle.(current_cycle >= launch_cycle) - else assert false + (* Expects the launch cycle to be already set *) + match init_state.State.ai_activation_cycle with + | Some launch_cycle -> + let current_cycle = Block.current_cycle block in + Cycle.(current_cycle >= launch_cycle) + | _ -> + Log.error + "wait_cycle_until `AI_activation: launch cycle not found, \ + aborting." ; + assert false) + | `AI_activation_with_votes -> + fun (block, state) -> + if State_ai_flags.AI_Activation.enabled init_state then + match state.State.ai_activation_cycle with + (* Since AI_activation is enabled, we expect the activation + cycle to be set eventually *) + | Some launch_cycle -> + let current_cycle = Block.current_cycle block in + Cycle.(current_cycle >= launch_cycle) + | _ -> false + else ( + Log.error + "wait_cycle_until `AI_activation_with_votes: AI cannot \ + activate with the current protocol parameters, aborting." ; + assert false) | `delegate_parameters_activation -> fun (block, _state) -> let init_cycle = Block.current_cycle init_block in let cycles_to_wait = init_state.constants.delegate_parameters_activation_delay in - return - Cycle.(Block.current_cycle block >= add init_cycle cycles_to_wait) + Cycle.(Block.current_cycle block >= add init_cycle cycles_to_wait) | `And (cond1, cond2) -> let stop1 = stopper cond1 in let stop2 = stopper cond2 in fun (block, state) -> - let* b1 = stop1 (block, state) in - let* b2 = stop2 (block, state) in - return (b1 && b2) + let b1 = stop1 (block, state) in + let b2 = stop2 (block, state) in + b1 && b2 in stopper condition in log ~color:time_color "Fast forward to %s" to_ - --> wait_cycle_f_es condition + --> wait_cycle_f condition --> log ~color:event_color "%s" done_ (** Wait until AI activates. diff --git a/src/proto_alpha/lib_protocol/test/helpers/scenario_begin.ml b/src/proto_alpha/lib_protocol/test/helpers/scenario_begin.ml index 2a20a38e6985040dfcffc1b0209477e6dd18a17e..af6cf73d1294e2f00ee7a3c17aabe4a801cb929b 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/scenario_begin.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/scenario_begin.ml @@ -46,12 +46,42 @@ let start_with_list ~(constants : (string * constants) list) : (Format.asprintf "%s: Cannot build scenarios from empty list" __LOC__) | _ -> fold_tag (fun constants -> start_with ~constants) constants -let activate_ai flag = - if flag then - log ~color:event_color "Setting ai threshold to 0" - --> set S.Adaptive_issuance.launch_ema_threshold 0l - --> set S.Adaptive_issuance.activation_vote_enable true - else Empty +let activate_ai mode = + match mode with + | `Force -> + log ~color:event_color "Forcing AI activation at initial cycle" + --> set S.Adaptive_issuance.force_activation true + | `Zero_threshold -> + (* Requires to wait until AI is activated *) + log ~color:event_color "Setting ai vote threshold to 0" + --> set S.Adaptive_issuance.force_activation false + --> set S.Adaptive_issuance.launch_ema_threshold 0l + | `With_vote_threshold t -> + (* Requires to wait for the votes to pass the threshold, then + wait some more before AI is activated *) + log ~color:event_color "Setting ai vote threshold to %ld" t + --> set S.Adaptive_issuance.force_activation false + --> set S.Adaptive_issuance.activation_vote_enable true + --> set S.Adaptive_issuance.launch_ema_threshold t + | `Force_and_vote_with_threshold t -> + (* Force should have priority on the vote *) + log + ~color:event_color + "Forcing AI activation at initial cycle, and setting ai vote threshold \ + to %ld" + t + --> set S.Adaptive_issuance.force_activation true + --> set S.Adaptive_issuance.activation_vote_enable true + --> set S.Adaptive_issuance.launch_ema_threshold t + | `No -> + (* AI cannot be activated. *) + log ~color:event_color "Setting AI as impossible to activate" + --> set + S.Adaptive_issuance.launch_ema_threshold + (Int32.succ + Protocol.Per_block_votes_repr.Internal_for_tests.ema_max) + --> set S.Adaptive_issuance.force_activation false + --> set S.Adaptive_issuance.activation_vote_enable false (** Initializes the constants for testing, with well chosen default values. Recommended over [start] or [start_with] *) @@ -141,9 +171,7 @@ let begin_test ?(burn_rewards = false) delegates_name_list : total_supply; constants; param_requests = []; - activate_ai = - constants.adaptive_issuance.activation_vote_enable - && constants.adaptive_issuance.launch_ema_threshold = 0l; + force_ai_vote_yes = true; baking_policy = None; last_level_rewards = init_level; snapshot_balances = String.Map.empty; diff --git a/src/proto_alpha/lib_protocol/test/helpers/state.ml b/src/proto_alpha/lib_protocol/test/helpers/state.ml index a890a5e3d5ce6f57885977f2050abd7758f6fe9e..5ecf1bec09a42ec96ef8cdd9ff028fff2fadced1 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/state.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/state.ml @@ -22,7 +22,7 @@ type t = { total_supply : Tez.t; constants : Protocol.Alpha_context.Constants.Parametric.t; param_requests : (string * staking_parameters * int) list; - activate_ai : bool; + force_ai_vote_yes : bool; baking_policy : Block.baker_policy option; last_level_rewards : Protocol.Alpha_context.Raw_level.t; snapshot_balances : (string * balance) list String.Map.t; diff --git a/src/proto_alpha/lib_protocol/test/helpers/state_ai_flags.ml b/src/proto_alpha/lib_protocol/test/helpers/state_ai_flags.ml index e3a2a63e3fcb6b6d288441fb1c9cd08523c1a69a..994f84f5981daa6533827f48fd9232264af438f9 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/state_ai_flags.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/state_ai_flags.ml @@ -16,10 +16,15 @@ module AI_Activation = struct [adaptive_issuance.force_activation], [adaptive_issuance.activation_vote_enable], and [adaptive_issuance.launch_ema_threshold]. *) - (** AI can be activated with both flags set to false if the threshold is set to 0 *) + (** AI can be activated with both flags set to false if the threshold is set to 0. + If the vote is enabled, but the threshold is above the maximum EMA, then the vote + cannot trigger the activation. *) let enabled state = state.constants.adaptive_issuance.force_activation - || state.constants.adaptive_issuance.activation_vote_enable + || (state.constants.adaptive_issuance.activation_vote_enable + && Compare.Int32.( + state.constants.adaptive_issuance.launch_ema_threshold + <= Protocol.Per_block_votes_repr.Internal_for_tests.ema_max)) || Compare.Int32.( state.constants.adaptive_issuance.launch_ema_threshold = 0l) diff --git a/src/proto_alpha/lib_protocol/test/integration/test_scenario_autostaking.ml b/src/proto_alpha/lib_protocol/test/integration/test_scenario_autostaking.ml index 9636285d50cdfdfb214e2e2be7883b0e62c37d3d..4b9a5e8e1cb7c7034e08f75d514f93261f1dc3f2 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_scenario_autostaking.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_scenario_autostaking.ml @@ -56,7 +56,7 @@ and delegator2 = "delegator2" let setup ~activate_ai = init_constants () --> set S.Adaptive_issuance.autostaking_enable true - --> Scenario_begin.activate_ai activate_ai + --> Scenario_begin.activate_ai (if activate_ai then `Force else `No) --> begin_test [delegate] --> add_account_with_funds delegator1 @@ -67,7 +67,6 @@ let setup ~activate_ai = "__bootstrap__" (Amount (Tez.of_mutez 2_000_000_000L)) --> next_cycle - --> (if activate_ai then wait_ai_activation else next_cycle) --> snapshot_balances "before delegation" [delegate] --> set_delegate delegator1 (Some delegate) --> check_snapshot_balances "before delegation" @@ -147,7 +146,7 @@ let test_overdelegation = begin with 4M tz, with 5% staked *) init_constants () --> set S.Adaptive_issuance.autostaking_enable true - --> activate_ai false + --> activate_ai `No --> begin_test ["delegate"; "faucet1"; "faucet2"; "faucet3"] --> add_account_with_funds "delegator_to_fund" diff --git a/src/proto_alpha/lib_protocol/test/integration/test_scenario_base.ml b/src/proto_alpha/lib_protocol/test/integration/test_scenario_base.ml index 88567a5502129b6256d652c1ac4980d2f73b6c87..37353d93f31e2a68f129256c9d13d87b04a79e5c 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_scenario_base.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_scenario_base.ml @@ -43,7 +43,7 @@ let init_scenario ?(force_ai = true) ?reward_per_block () = let name = if self_stake then "staker" else "delegate" in init_constants ?reward_per_block () --> set S.Adaptive_issuance.autostaking_enable false - --> Scenario_begin.activate_ai activate_ai + --> Scenario_begin.activate_ai (if activate_ai then `Force else `No) --> begin_test [name] --> set_delegate_params name init_params --> set_baker "__bootstrap__" @@ -58,7 +58,7 @@ let init_scenario ?(force_ai = true) ?reward_per_block () = "delegate" (Amount (Tez.of_mutez 2_000_000_000_000L)) --> set_delegate "staker" (Some "delegate")) - --> wait_ai_activation + --> wait_delegate_parameters_activation --> next_cycle in let ai_deactivated = diff --git a/src/proto_alpha/lib_protocol/test/integration/test_scenario_rewards.ml b/src/proto_alpha/lib_protocol/test/integration/test_scenario_rewards.ml index 805b601b0a0bf548438f9b5a98e206a76d1068c0..160069056bd73ef16325eb6ab772f1c39318fcb2 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_scenario_rewards.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_scenario_rewards.ml @@ -30,7 +30,7 @@ let test_wait_with_rewards = in init_constants ~reward_per_block:1_000_000_000L () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Zero_threshold --> begin_test ["delegate"; "faucet"] --> set_baker "faucet" --> (Tag "edge = 0" --> set_edge 0. @@ -79,7 +79,7 @@ let test_ai_curve_activation_time = in init_constants ~reward_per_block:1_000_000_000L ~deactivate_dynamic:true () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Zero_threshold --> begin_test ~burn_rewards:true [""] --> next_block --> save_current_rate (* before AI rate *) --> wait_ai_activation @@ -111,7 +111,7 @@ let test_static = in init_constants ~reward_per_block:1_000_000_000L ~deactivate_dynamic:true () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Zero_threshold --> begin_test ~burn_rewards:true ["delegate"] --> set_delegate_params "delegate" init_params --> save_current_rate --> wait_ai_activation diff --git a/src/proto_alpha/lib_protocol/test/integration/test_scenario_slashing.ml b/src/proto_alpha/lib_protocol/test/integration/test_scenario_slashing.ml index ab14e041bc7de4a4c0d9310e19b94baf1a41677f..ed20f9b38e0d65192fd579e770a32356c3b3ae61 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_scenario_slashing.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_scenario_slashing.ml @@ -49,7 +49,7 @@ let test_simple_slash = in init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Zero_threshold --> branch_flag S.Adaptive_issuance.ns_enable --> begin_test ["delegate"; "bootstrap1"; "bootstrap2"; "bootstrap3"] --> (Tag "No AI" --> next_cycle @@ -127,7 +127,7 @@ let check_is_not_forbidden baker = let test_delegate_forbidden = init_constants ~blocks_per_cycle:30l () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai false + --> activate_ai `No --> branch_flag S.Adaptive_issuance.ns_enable --> begin_test ["delegate"; "bootstrap1"; "bootstrap2"] --> set_baker "bootstrap1" @@ -172,7 +172,7 @@ let test_delegate_forbidden = let test_slash_unstake = init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai false + --> activate_ai `No --> branch_flag S.Adaptive_issuance.ns_enable --> begin_test ["delegate"; "bootstrap1"; "bootstrap2"] --> set_baker "bootstrap1" --> next_cycle --> unstake "delegate" Half @@ -185,7 +185,7 @@ let test_slash_monotonous_stake = let scenario ~offending_op ~op ~early_d = init_constants ~blocks_per_cycle:16l () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai false + --> activate_ai `No --> branch_flag S.Adaptive_issuance.ns_enable --> begin_test ["delegate"; "bootstrap1"] --> next_cycle @@ -235,7 +235,7 @@ let test_slash_monotonous_stake = let test_slash_timing = init_constants ~blocks_per_cycle:8l () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai false + --> activate_ai `No --> branch_flag S.Adaptive_issuance.ns_enable --> begin_test ["delegate"] --> next_cycle --> (Tag "stake" --> stake "delegate" Half @@ -266,13 +266,13 @@ let init_scenario_with_delegators delegate_name faucet_name delegators_list = in init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Force --> branch_flag S.Adaptive_issuance.ns_enable --> begin_test [delegate_name; faucet_name] --> set_baker faucet_name --> set_delegate_params "delegate" init_params --> init_delegators delegators_list - --> next_block --> wait_ai_activation + --> next_block --> wait_delegate_parameters_activation let test_many_slashes = let rec stake_unstake_for = function @@ -322,9 +322,8 @@ let test_no_shortcut_for_cheaters = in init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Force --> begin_test ["delegate"; "bootstrap1"] - --> next_block --> wait_ai_activation --> stake "delegate" (Amount (Tez.of_mutez 1_800_000_000_000L)) --> next_cycle --> double_bake "delegate" --> make_denunciations () --> set_baker "bootstrap1" (* exclude_bakers ["delegate"] *) @@ -351,9 +350,8 @@ let test_slash_correct_amount_after_stake_from_unstake = in init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Force --> begin_test ["delegate"; "bootstrap1"] - --> next_block --> wait_ai_activation --> stake "delegate" (Amount (Tez.of_mutez 1_800_000_000_000L)) --> next_cycle --> unstake "delegate" amount_to_unstake @@ -374,11 +372,8 @@ let test_slash_correct_amount_after_stake_from_unstake = let test_mini_slash = init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> (Tag "Yes AI" --> activate_ai true - --> begin_test ["delegate"; "baker"] - --> next_block --> wait_ai_activation - |+ Tag "No AI" --> activate_ai false --> begin_test ["delegate"; "baker"] - ) + --> (Tag "Yes AI" --> activate_ai `Force |+ Tag "No AI" --> activate_ai `No) + --> begin_test ["delegate"; "baker"] --> unstake "delegate" (Amount Tez.one_mutez) --> set_baker "baker" --> next_cycle --> (Tag "5% slash" --> double_bake "delegate" --> make_denunciations () @@ -395,10 +390,10 @@ let test_mini_slash = let test_slash_rounding = init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Force --> branch_flag S.Adaptive_issuance.ns_enable --> begin_test ["delegate"; "baker"] - --> set_baker "baker" --> next_block --> wait_ai_activation + --> set_baker "baker" --> unstake "delegate" (Amount (Tez.of_mutez 2L)) --> next_cycle --> double_bake "delegate" --> double_bake "delegate" --> make_denunciations () --> wait_n_cycles 7 diff --git a/src/proto_alpha/lib_protocol/test/integration/test_scenario_stake.ml b/src/proto_alpha/lib_protocol/test/integration/test_scenario_stake.ml index 0d59a03e2b733398d069abf822d29f69f2d6abd4..0b7694da9b7d922260f6db8ae11e23e1c8e7e0ce 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_scenario_stake.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_scenario_stake.ml @@ -71,8 +71,7 @@ let shorter_roundtrip_for_baker = in init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true --> begin_test ["delegate"] --> next_block - --> wait_ai_activation + --> activate_ai `Force --> begin_test ["delegate"] --> stake "delegate" (Amount (Tez.of_mutez 1_800_000_000_000L)) --> next_cycle --> snapshot_balances "init" ["delegate"] @@ -170,7 +169,7 @@ let change_delegate = in init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Force --> begin_test ["delegate1"; "delegate2"] --> set_delegate_params "delegate1" init_params --> set_delegate_params "delegate2" init_params @@ -179,7 +178,8 @@ let change_delegate = "delegate1" (Amount (Tez.of_mutez 2_000_000_000_000L)) --> set_delegate "staker" (Some "delegate1") - --> wait_ai_activation --> next_cycle --> stake "staker" Half --> next_cycle + --> wait_delegate_parameters_activation --> next_cycle --> stake "staker" Half + --> next_cycle --> set_delegate "staker" (Some "delegate2") --> next_cycle --> assert_failure (stake "staker" Half) @@ -192,7 +192,7 @@ let unset_delegate = in init_constants () --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true --> begin_test ["delegate"] + --> activate_ai `Force --> begin_test ["delegate"] --> set_delegate_params "delegate" init_params --> add_account_with_funds "staker" @@ -203,7 +203,7 @@ let unset_delegate = "delegate" (Amount (Tez.of_mutez 2_000_000L)) --> set_delegate "staker" (Some "delegate") - --> wait_ai_activation --> next_cycle --> stake "staker" Half + --> wait_delegate_parameters_activation --> next_cycle --> stake "staker" Half --> unstake "staker" All --> next_cycle --> set_delegate "staker" None --> next_cycle --> transfer "staker" "dummy" All @@ -228,7 +228,7 @@ let forbid_costaking = --> init_constants ~delegate_parameters_activation_delay:10 ()) (* Set flags *) --> set S.Adaptive_issuance.autostaking_enable false - --> activate_ai true + --> activate_ai `Zero_threshold (* Start scenario *) --> begin_test ["delegate"] --> set_delegate_params "delegate" init_params