From dbbb31927477bb9f96008d00b0f076dd3bbaa4d6 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 24 May 2023 14:01:22 +0200 Subject: [PATCH 1/9] Proto: Add Reward_coeff to Storage --- src/proto_alpha/lib_protocol/storage.ml | 23 +++++++++++++++++++++++ src/proto_alpha/lib_protocol/storage.mli | 7 +++++++ 2 files changed, 30 insertions(+) diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index 71ecd68277a2..910eb91ac896 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -1108,6 +1108,28 @@ module Cycle = struct let encoding = Sampler.encoding Raw_context.consensus_pk_encoding end) + module Reward_coeff = + Indexed_context.Make_map + (Registered) + (struct + let name = ["reward_coeff"] + end) + (struct + type t = Q.t + + let encoding = + Data_encoding.( + conv_with_guard + (fun Q.{num; den} -> (num, den)) + (fun (num, den) -> + if Compare.Z.(num > Z.zero && den > Z.zero) then + Ok (Q.make num den) + else + Error + "Invalid Reward Coefficient: only positive values allowed") + (obj2 (req "numerator" n) (req "denominator" n))) + end) + type unrevealed_nonce = { nonce_hash : Nonce_hash.t; delegate : Signature.Public_key_hash.t; @@ -1226,6 +1248,7 @@ module Stake = struct end module Delegate_sampler_state = Cycle.Delegate_sampler_state +module Reward_coeff = Cycle.Reward_coeff (** Votes *) diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 3e5c8405eefb..20e431e8e4c1 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -493,6 +493,13 @@ module Delegate_sampler_state : and type value = Raw_context.consensus_pk Sampler.t and type t := Raw_context.t +(** Multiplicative coefficient for rewards under Adaptive Inflation *) +module Reward_coeff : + Indexed_data_storage + with type key = Cycle_repr.t + and type value = Q.t + and type t := Raw_context.t + (** Votes *) module Vote : sig -- GitLab From 6941db18ec63f2870d26c9cafab540a833aaf85a Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 25 May 2023 17:08:39 +0200 Subject: [PATCH 2/9] Proto: Add reward coefficient in context --- src/proto_alpha/lib_protocol/raw_context.ml | 9 +++++++++ src/proto_alpha/lib_protocol/raw_context.mli | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index e12d06d69c14..8833613bf244 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -251,6 +251,7 @@ type back = { sampler_state : (Seed_repr.seed * consensus_pk Sampler.t) Cycle_repr.Map.t; stake_distribution_for_current_cycle : Stake_repr.t Signature.Public_key_hash.Map.t option; + reward_coeff_for_current_cycle : Q.t; sc_rollup_current_messages : Sc_rollup_inbox_merkelized_payload_hashes_repr.t; dal_slot_fee_market : Dal_slot_repr.Slot_market.t; (* DAL/FIXME https://gitlab.com/tezos/tezos/-/issues/3105 @@ -336,6 +337,9 @@ let[@inline] dictator_proposal_seen ctxt = ctxt.back.dictator_proposal_seen let[@inline] sampler_state ctxt = ctxt.back.sampler_state +let[@inline] reward_coeff_for_current_cycle ctxt = + ctxt.back.reward_coeff_for_current_cycle + let[@inline] update_back ctxt back = {ctxt with back} let[@inline] update_remaining_block_gas ctxt remaining_block_gas = @@ -377,6 +381,10 @@ let[@inline] update_dictator_proposal_seen ctxt dictator_proposal_seen = let[@inline] update_sampler_state ctxt sampler_state = update_back ctxt {ctxt.back with sampler_state} +let[@inline] update_reward_coeff_for_current_cycle ctxt + reward_coeff_for_current_cycle = + update_back ctxt {ctxt.back with reward_coeff_for_current_cycle} + type error += Too_many_internal_operations (* `Permanent *) type error += Block_quota_exceeded (* `Temporary *) @@ -835,6 +843,7 @@ let prepare ~level ~predecessor_timestamp ~timestamp ctxt = dictator_proposal_seen = false; sampler_state = Cycle_repr.Map.empty; stake_distribution_for_current_cycle = None; + reward_coeff_for_current_cycle = Q.one; sc_rollup_current_messages; dal_slot_fee_market = Dal_slot_repr.Slot_market.init diff --git a/src/proto_alpha/lib_protocol/raw_context.mli b/src/proto_alpha/lib_protocol/raw_context.mli index fbda6aab8a01..579c0ba61ea9 100644 --- a/src/proto_alpha/lib_protocol/raw_context.mli +++ b/src/proto_alpha/lib_protocol/raw_context.mli @@ -287,6 +287,16 @@ val stake_distribution_for_current_cycle : val init_stake_distribution_for_current_cycle : t -> Stake_repr.t Signature.Public_key_hash.Map.t -> t +(** Returns the reward coefficient for the current cycle + This value is equal to the value in {!Storage.Reward_coeff} if it exists, + or equal to [Q.one] otherwise. *) +val reward_coeff_for_current_cycle : t -> Q.t + +(** Updates the reward coefficient for the current cycle. + This update should only be called once per cycle. It is done in + [Adaptive_inflation_storage] *) +val update_reward_coeff_for_current_cycle : t -> Q.t -> t + module Internal_for_tests : sig val add_level : t -> int -> t -- GitLab From 9fdbd44a54dbf7ba3235032ecff878b5d3b101d6 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 24 May 2023 14:06:12 +0200 Subject: [PATCH 3/9] Proto: Add module for Adaptive Inflation Storage --- src/proto_alpha/lib_protocol/TEZOS_PROTOCOL | 1 + .../adaptive_inflation_storage.ml | 36 +++++++++++++++++++ .../adaptive_inflation_storage.mli | 24 +++++++++++++ src/proto_alpha/lib_protocol/dune | 4 +++ 4 files changed, 65 insertions(+) create mode 100644 src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml create mode 100644 src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index a1488bba9f01..e79e9d7f833c 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -136,6 +136,7 @@ "Contract_storage", "Token", "Fees_storage", + "Adaptive_inflation_storage", "Delegate_consensus_key", "Delegate_storage", "Delegate_sampler", diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml new file mode 100644 index 000000000000..054913f01d1f --- /dev/null +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml @@ -0,0 +1,36 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(* Default reward coefficient when AI is not in effect, chosen so that + rewards * coeff = rewards *) +let default = Q.one + +let get_reward_coeff ctxt ~current_cycle = + let open Lwt_result_syntax in + let ai_enable = (Raw_context.constants ctxt).adaptive_inflation.enable in + if ai_enable then + let* k_opt = Storage.Reward_coeff.find ctxt current_cycle in + return (Option.value ~default k_opt) + else return default diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli new file mode 100644 index 000000000000..48fcc1a4b1b4 --- /dev/null +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli @@ -0,0 +1,24 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) diff --git a/src/proto_alpha/lib_protocol/dune b/src/proto_alpha/lib_protocol/dune index 2b41e116e6a2..abb8ee717650 100644 --- a/src/proto_alpha/lib_protocol/dune +++ b/src/proto_alpha/lib_protocol/dune @@ -154,6 +154,7 @@ Contract_storage Token Fees_storage + Adaptive_inflation_storage Delegate_consensus_key Delegate_storage Delegate_sampler @@ -411,6 +412,7 @@ contract_storage.ml contract_storage.mli token.ml token.mli fees_storage.ml fees_storage.mli + adaptive_inflation_storage.ml adaptive_inflation_storage.mli delegate_consensus_key.ml delegate_consensus_key.mli delegate_storage.ml delegate_storage.mli delegate_sampler.ml delegate_sampler.mli @@ -670,6 +672,7 @@ contract_storage.ml contract_storage.mli token.ml token.mli fees_storage.ml fees_storage.mli + adaptive_inflation_storage.ml adaptive_inflation_storage.mli delegate_consensus_key.ml delegate_consensus_key.mli delegate_storage.ml delegate_storage.mli delegate_sampler.ml delegate_sampler.mli @@ -913,6 +916,7 @@ contract_storage.ml contract_storage.mli token.ml token.mli fees_storage.ml fees_storage.mli + adaptive_inflation_storage.ml adaptive_inflation_storage.mli delegate_consensus_key.ml delegate_consensus_key.mli delegate_storage.ml delegate_storage.mli delegate_sampler.ml delegate_sampler.mli -- GitLab From de2829712d4f3baea6f7aeb183cae9f9a47e0ff0 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 24 May 2023 14:08:49 +0200 Subject: [PATCH 4/9] Proto: Use reward coeff in reward calculations --- .../lib_protocol/alpha_context.mli | 8 ++- .../lib_protocol/delegate_rewards.ml | 69 ++++++++++++------- .../lib_protocol/delegate_rewards.mli | 11 ++- .../lib_protocol/test/helpers/context.ml | 12 ++-- .../test/helpers/liquidity_baking_machine.ml | 2 +- .../consensus/test_double_endorsement.ml | 2 +- .../consensus/test_participation.ml | 2 +- .../test/integration/test_constants.ml | 2 +- 8 files changed, 71 insertions(+), 37 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index a8d569e2d902..21e721348fa7 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2231,8 +2231,14 @@ module Delegate : sig | Seed_nonce_revelation_tip | Vdf_revelation_tip + (** [reward_from_constants ~coeff csts ~reward_kind] returns the amount of + rewards in {!Tez.t} for the given [reward_kind], according to the + given parameters in [csts]. The (optional) value [coeff] is a + multiplicative factor applied to the rewards (default = 1). + It verifies [reward_from_constants ~coeff csts ~reward_kind = + coeff * reward_from_constants csts ~reward_kind]. *) val reward_from_constants : - csts:Constants.Parametric.t -> reward_kind:reward_kind -> Tez.t + ?coeff:Q.t -> Constants.Parametric.t -> reward_kind:reward_kind -> Tez.t end end end diff --git a/src/proto_alpha/lib_protocol/delegate_rewards.ml b/src/proto_alpha/lib_protocol/delegate_rewards.ml index 7003053be459..b19f87406ce7 100644 --- a/src/proto_alpha/lib_protocol/delegate_rewards.ml +++ b/src/proto_alpha/lib_protocol/delegate_rewards.ml @@ -59,7 +59,9 @@ let tez_from_weights in normalized_rewards_per_block -module Internal_for_tests = struct +(* Bundling some functions inside a module so they can be exported as part + of `Internal_for_tests` further down. *) +module M = struct type reward_kind = | Baking_reward_fixed_portion | Baking_reward_bonus_per_slot @@ -68,7 +70,8 @@ module Internal_for_tests = struct | Seed_nonce_revelation_tip | Vdf_revelation_tip - let reward_from_constants ~(csts : Constants_parametric_repr.t) ~reward_kind = + let reward_from_constants ~(csts : Constants_parametric_repr.t) ~reward_kind + ~(coeff : Q.t) = let reward_weights = csts.reward_weights in let weight = match reward_kind with @@ -93,36 +96,52 @@ module Internal_for_tests = struct let rewards = tez_from_weights ~reward_weights ~weight ~minimal_block_delay in - match reward_kind with - | Baking_reward_bonus_per_slot -> - let bonus_committee_size = - csts.consensus_committee_size - csts.consensus_threshold - in - if Compare.Int.(bonus_committee_size <= 0) then Tez_repr.zero - else Tez_repr.div_exn rewards bonus_committee_size - | Endorsing_reward_per_slot -> - Tez_repr.div_exn rewards csts.consensus_committee_size - | _ -> rewards + let base_rewards = + match reward_kind with + | Baking_reward_bonus_per_slot -> + let bonus_committee_size = + csts.consensus_committee_size - csts.consensus_threshold + in + if Compare.Int.(bonus_committee_size <= 0) then Tez_repr.zero + else Tez_repr.div_exn rewards bonus_committee_size + | Endorsing_reward_per_slot -> + Tez_repr.div_exn rewards csts.consensus_committee_size + | _ -> rewards + in + let mutez_base_rewards = Tez_repr.to_mutez base_rewards |> Z.of_int64 in + let mutez_rewards = Z.(div (mul mutez_base_rewards coeff.num) coeff.den) in + Tez_repr.of_mutez_exn (Z.to_int64 mutez_rewards) end -open Internal_for_tests +open M -let reward_from_context ctxt reward_kind = +let reward_from_context ~ctxt ~reward_kind = let csts = Raw_context.constants ctxt in - reward_from_constants ~csts ~reward_kind + let coeff = Raw_context.reward_coeff_for_current_cycle ctxt in + reward_from_constants ~csts ~reward_kind ~coeff -let baking_reward_fixed_portion c = - reward_from_context c Baking_reward_fixed_portion +let baking_reward_fixed_portion ctxt = + reward_from_context ~ctxt ~reward_kind:Baking_reward_fixed_portion -let baking_reward_bonus_per_slot c = - reward_from_context c Baking_reward_bonus_per_slot +let baking_reward_bonus_per_slot ctxt = + reward_from_context ~ctxt ~reward_kind:Baking_reward_bonus_per_slot -let endorsing_reward_per_slot c = - reward_from_context c Endorsing_reward_per_slot +let endorsing_reward_per_slot ctxt = + reward_from_context ~ctxt ~reward_kind:Endorsing_reward_per_slot -let liquidity_baking_subsidy c = reward_from_context c Liquidity_baking_subsidy +let liquidity_baking_subsidy ctxt = + reward_from_context ~ctxt ~reward_kind:Liquidity_baking_subsidy -let seed_nonce_revelation_tip c = - reward_from_context c Seed_nonce_revelation_tip +let seed_nonce_revelation_tip ctxt = + reward_from_context ~ctxt ~reward_kind:Seed_nonce_revelation_tip -let vdf_revelation_tip c = reward_from_context c Vdf_revelation_tip +let vdf_revelation_tip ctxt = + reward_from_context ~ctxt ~reward_kind:Vdf_revelation_tip + +module Internal_for_tests = struct + include M + + let reward_from_constants ?(coeff = Q.one) + (csts : Constants_parametric_repr.t) ~reward_kind = + reward_from_constants ~csts ~reward_kind ~coeff +end diff --git a/src/proto_alpha/lib_protocol/delegate_rewards.mli b/src/proto_alpha/lib_protocol/delegate_rewards.mli index 0b6bc7572dec..b595c3cee251 100644 --- a/src/proto_alpha/lib_protocol/delegate_rewards.mli +++ b/src/proto_alpha/lib_protocol/delegate_rewards.mli @@ -47,6 +47,15 @@ module Internal_for_tests : sig | Seed_nonce_revelation_tip | Vdf_revelation_tip + (** [reward_from_constants ~coeff csts ~reward_kind] returns the amount of + rewards in {!Tez_repr.t} for the given [reward_kind], according to the + given parameters in [csts]. The (optional) value [coeff] is a + multiplicative factor applied to the rewards (default = 1). + It verifies [reward_from_constants ~coeff csts ~reward_kind = + coeff * reward_from_constants csts ~reward_kind]. *) val reward_from_constants : - csts:Constants_parametric_repr.t -> reward_kind:reward_kind -> Tez_repr.t + ?coeff:Q.t -> + Constants_parametric_repr.t -> + reward_kind:reward_kind -> + Tez_repr.t end diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.ml b/src/proto_alpha/lib_protocol/test/helpers/context.ml index 9c24fd52b49b..888f979b8dcf 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/context.ml @@ -206,7 +206,7 @@ let get_baking_reward_fixed_portion ctxt = get_constants ctxt >>=? fun {Constants.parametric = csts; _} -> return (Delegate.Rewards.Internal_for_tests.reward_from_constants - ~csts + csts ~reward_kind:Baking_reward_fixed_portion) let get_bonus_reward ctxt ~endorsing_power = @@ -214,7 +214,7 @@ let get_bonus_reward ctxt ~endorsing_power = >>=? fun {Constants.parametric = {consensus_threshold; _} as csts; _} -> let baking_reward_bonus_per_slot = Delegate.Rewards.Internal_for_tests.reward_from_constants - ~csts + csts ~reward_kind:Baking_reward_bonus_per_slot in let multiplier = max 0 (endorsing_power - consensus_threshold) in @@ -224,7 +224,7 @@ let get_endorsing_reward ctxt ~expected_endorsing_power = get_constants ctxt >>=? fun {Constants.parametric = csts; _} -> let endorsing_reward_per_slot = Delegate.Rewards.Internal_for_tests.reward_from_constants - ~csts + csts ~reward_kind:Endorsing_reward_per_slot in Lwt.return @@ -235,7 +235,7 @@ let get_liquidity_baking_subsidy ctxt = get_constants ctxt >>=? fun {Constants.parametric = csts; _} -> return (Delegate.Rewards.Internal_for_tests.reward_from_constants - ~csts + csts ~reward_kind:Liquidity_baking_subsidy) let get_liquidity_baking_cpmm_address ctxt = @@ -245,14 +245,14 @@ let get_seed_nonce_revelation_tip ctxt = get_constants ctxt >>=? fun {Constants.parametric = csts; _} -> return (Delegate.Rewards.Internal_for_tests.reward_from_constants - ~csts + csts ~reward_kind:Seed_nonce_revelation_tip) let get_vdf_revelation_tip ctxt = get_constants ctxt >>=? fun {Constants.parametric = csts; _} -> return (Delegate.Rewards.Internal_for_tests.reward_from_constants - ~csts + csts ~reward_kind:Vdf_revelation_tip) (* Voting *) diff --git a/src/proto_alpha/lib_protocol/test/helpers/liquidity_baking_machine.ml b/src/proto_alpha/lib_protocol/test/helpers/liquidity_baking_machine.ml index b14304a68500..e1fa246720ac 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/liquidity_baking_machine.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/liquidity_baking_machine.ml @@ -382,7 +382,7 @@ let default_subsidy = let c = Default_parameters.constants_test in Tez.to_mutez @@ Delegate.Rewards.Internal_for_tests.reward_from_constants - ~csts:c + c ~reward_kind:Liquidity_baking_subsidy let security_deposit = 640_000_000L diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_endorsement.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_endorsement.ml index 9b14080caf94..9f9299120539 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_endorsement.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_endorsement.ml @@ -120,7 +120,7 @@ let test_valid_double_endorsement_evidence () = - half of the frozen_deposits for including the evidence *) let baking_reward = Delegate.Rewards.Internal_for_tests.reward_from_constants - ~csts:csts.parametric + csts.parametric ~reward_kind:Baking_reward_fixed_portion in let evidence_reward = Test_tez.(frozen_deposits_after /! 2L) in diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_participation.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_participation.ml index de442a1be1d8..366978870f44 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_participation.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_participation.ml @@ -139,7 +139,7 @@ let test_participation_rpc () = let allowed_missed_slots = expected_cycle_activity - minimal_cycle_activity in let endorsing_reward_per_slot = Alpha_context.Delegate.Rewards.Internal_for_tests.reward_from_constants - ~csts:csts.parametric + csts.parametric ~reward_kind:Endorsing_reward_per_slot in let expected_endorsing_rewards = diff --git a/src/proto_alpha/lib_protocol/test/integration/test_constants.ml b/src/proto_alpha/lib_protocol/test/integration/test_constants.ml index 9330d0d50b7e..aa4c07a207f0 100644 --- a/src/proto_alpha/lib_protocol/test/integration/test_constants.ml +++ b/src/proto_alpha/lib_protocol/test/integration/test_constants.ml @@ -181,7 +181,7 @@ let liquidity_baking_subsidy_param () = let get_reward = Protocol.Alpha_context.Delegate.Rewards.Internal_for_tests .reward_from_constants - ~csts:constants + constants in let baking_reward_bonus_per_slot = get_reward ~reward_kind:Baking_reward_bonus_per_slot -- GitLab From 926d0eea2fb47d0dbe851b53cee7ed15bfad527f Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 24 May 2023 14:09:53 +0200 Subject: [PATCH 5/9] Proto: Add dummy coeff computation --- src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml index 054913f01d1f..4816f71a8b42 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml @@ -34,3 +34,9 @@ let get_reward_coeff ctxt ~current_cycle = let* k_opt = Storage.Reward_coeff.find ctxt current_cycle in return (Option.value ~default k_opt) else return default + +let compute_coeff ~total_supply ~total_frozen_stake = + ignore total_supply ; + ignore total_frozen_stake ; + default + -- GitLab From 9deb61e3505f1fde8cc443ddcfa2213d5d4574ab Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 24 May 2023 14:12:02 +0200 Subject: [PATCH 6/9] Proto: Update Adaptive Inflation Storage at end of cycle --- .../adaptive_inflation_storage.ml | 34 +++++++++++++++++-- .../adaptive_inflation_storage.mli | 12 +++++++ .../lib_protocol/delegate_cycles.ml | 3 +- src/proto_alpha/lib_protocol/stake_repr.ml | 2 ++ src/proto_alpha/lib_protocol/stake_repr.mli | 3 ++ 5 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml index 4816f71a8b42..81d9a648456d 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml @@ -27,11 +27,13 @@ rewards * coeff = rewards *) let default = Q.one -let get_reward_coeff ctxt ~current_cycle = +let get_reward_coeff ctxt ~cycle = let open Lwt_result_syntax in let ai_enable = (Raw_context.constants ctxt).adaptive_inflation.enable in if ai_enable then - let* k_opt = Storage.Reward_coeff.find ctxt current_cycle in + (* Even if AI is enabled, the storage can be empty: this is the case for + the first 5 cycles after AI is enabled *) + let* k_opt = Storage.Reward_coeff.find ctxt cycle in return (Option.value ~default k_opt) else return default @@ -40,3 +42,31 @@ let compute_coeff ~total_supply ~total_frozen_stake = ignore total_frozen_stake ; default +let compute_and_store_reward_coeff_at_cycle_end ctxt ~new_cycle = + let open Lwt_result_syntax in + let ai_enable = (Raw_context.constants ctxt).adaptive_inflation.enable in + if not ai_enable then return ctxt + else + let preserved = Constants_storage.preserved_cycles ctxt in + let for_cycle = Cycle_repr.add new_cycle preserved in + let* total_supply = Storage.Contract.Total_supply.get ctxt in + let* total_stake = Stake_storage.get_total_active_stake ctxt for_cycle in + let total_frozen_stake = Stake_repr.get_frozen total_stake in + let coeff = compute_coeff ~total_supply ~total_frozen_stake in + let*! ctxt = Storage.Reward_coeff.add ctxt for_cycle coeff in + return ctxt + +let clear_outdated_reward_data ctxt ~new_cycle = + match Cycle_repr.sub new_cycle 1 with + | None -> Lwt.return ctxt + | Some cycle -> Storage.Reward_coeff.remove ctxt cycle + +let update_stored_rewards_at_cycle_end ctxt ~new_cycle = + let open Lwt_result_syntax in + let* ctxt = compute_and_store_reward_coeff_at_cycle_end ctxt ~new_cycle in + let*! ctxt = clear_outdated_reward_data ctxt ~new_cycle in + let* new_reward = get_reward_coeff ctxt ~cycle:new_cycle in + let ctxt = + Raw_context.update_reward_coeff_for_current_cycle ctxt new_reward + in + return ctxt diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli index 48fcc1a4b1b4..dbcde4b4fb0b 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli @@ -22,3 +22,15 @@ (* DEALINGS IN THE SOFTWARE. *) (* *) (*****************************************************************************) + +(** [update_stored_rewards_at_cycle_end ctxt ~new_cycle] updates + {!Storage.Reward_coeff} with a new coefficient that will be applied + [preserved_cycles] cycles after the given [new_cycle]. This new coefficient + depends on the current {!Storage.Total_supply}, and the total active stake + for when this coefficient is computed. + + This function also removes obsolete values from {!Storage.Reward_coeff}, + and stores the current cycle's coefficient in the context for faster + access. *) +val update_stored_rewards_at_cycle_end : + Raw_context.t -> new_cycle:Cycle_repr.t -> Raw_context.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/delegate_cycles.ml b/src/proto_alpha/lib_protocol/delegate_cycles.ml index 5697955d5467..d0dd4b581765 100644 --- a/src/proto_alpha/lib_protocol/delegate_cycles.ml +++ b/src/proto_alpha/lib_protocol/delegate_cycles.ml @@ -284,7 +284,8 @@ let cycle_end ctxt last_cycle = Stake_storage.clear_at_cycle_end ctxt ~new_cycle >>=? fun ctxt -> Delegate_sampler.clear_outdated_sampling_data ctxt ~new_cycle >>=? fun ctxt -> update_activity ctxt last_cycle >>=? fun (ctxt, deactivated_delegates) -> - return (ctxt, balance_updates, deactivated_delegates) + Adaptive_inflation_storage.update_stored_rewards_at_cycle_end ctxt ~new_cycle + >>=? fun ctxt -> return (ctxt, balance_updates, deactivated_delegates) let init_first_cycles ctxt ~origin = let preserved = Constants_storage.preserved_cycles ctxt in diff --git a/src/proto_alpha/lib_protocol/stake_repr.ml b/src/proto_alpha/lib_protocol/stake_repr.ml index 655ba7e3b8ea..f501850b33c8 100644 --- a/src/proto_alpha/lib_protocol/stake_repr.ml +++ b/src/proto_alpha/lib_protocol/stake_repr.ml @@ -29,6 +29,8 @@ let make ~frozen ~delegated = {frozen; delegated} let total {frozen; delegated} = Tez_repr.(frozen +? delegated) +let get_frozen {frozen; _} = frozen + let encoding = let open Data_encoding in conv diff --git a/src/proto_alpha/lib_protocol/stake_repr.mli b/src/proto_alpha/lib_protocol/stake_repr.mli index 70a0e131584f..2ff52b1ffc6c 100644 --- a/src/proto_alpha/lib_protocol/stake_repr.mli +++ b/src/proto_alpha/lib_protocol/stake_repr.mli @@ -35,6 +35,9 @@ val encoding : t Data_encoding.t (** Sum of the [frozen] and [delegated] parts of a stake. *) val total : t -> Tez_repr.t tzresult +(** Returns only the frozen part of a stake *) +val get_frozen : t -> Tez_repr.t + (** Weight for staking rights. *) val staking_weight : t -> int64 -- GitLab From 8e443f11f493502b8150a66208a92054a5357b27 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 24 May 2023 16:23:11 +0200 Subject: [PATCH 7/9] Proto: Compute new rewards under Adaptive Inflation --- .../adaptive_inflation_storage.ml | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml index 81d9a648456d..bd58fa325b7f 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml @@ -37,10 +37,28 @@ let get_reward_coeff ctxt ~cycle = return (Option.value ~default k_opt) else return default -let compute_coeff ~total_supply ~total_frozen_stake = - ignore total_supply ; - ignore total_frozen_stake ; - default +let compute_coeff = + let q_400 = Q.of_int 400 in + let q_min_per_year = Q.of_int 525600 in + fun ~base_total_rewards_per_minute ~total_supply ~total_frozen_stake -> + let q_total_supply = Tez_repr.to_mutez total_supply |> Q.of_int64 in + let q_total_frozen_stake = + Tez_repr.to_mutez total_frozen_stake |> Q.of_int64 + in + let q_base_total_rewards_per_minute = + Tez_repr.to_mutez base_total_rewards_per_minute |> Q.of_int64 + in + let x = + Q.div q_total_frozen_stake q_total_supply (* = portion of frozen stake *) + in + let inv_f = Q.(mul (mul x x) q_400) in + let f = Q.inv inv_f (* f = 1/400 * (1/x)^2 = yearly inflation rate *) in + (* f is truncated so that 0.5% <= f <= 10% *) + let f = Q.(min f (1 // 10)) in + let f = Q.(max f (5 // 1000)) in + let f = Q.div f q_min_per_year (* = inflation per minute *) in + let f = Q.mul f q_total_supply (* = rewards per minute *) in + Q.div f q_base_total_rewards_per_minute let compute_and_store_reward_coeff_at_cycle_end ctxt ~new_cycle = let open Lwt_result_syntax in @@ -51,8 +69,16 @@ let compute_and_store_reward_coeff_at_cycle_end ctxt ~new_cycle = let for_cycle = Cycle_repr.add new_cycle preserved in let* total_supply = Storage.Contract.Total_supply.get ctxt in let* total_stake = Stake_storage.get_total_active_stake ctxt for_cycle in + let base_total_rewards_per_minute = + (Constants_storage.reward_weights ctxt).base_total_rewards_per_minute + in let total_frozen_stake = Stake_repr.get_frozen total_stake in - let coeff = compute_coeff ~total_supply ~total_frozen_stake in + let coeff = + compute_coeff + ~base_total_rewards_per_minute + ~total_supply + ~total_frozen_stake + in let*! ctxt = Storage.Reward_coeff.add ctxt for_cycle coeff in return ctxt -- GitLab From cd91128f88644d892e07120a63f1440ba520927b Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Fri, 26 May 2023 15:28:47 +0200 Subject: [PATCH 8/9] Proto: init reward coeff in context --- .../lib_protocol/adaptive_inflation_storage.ml | 17 ++++++++++++----- .../lib_protocol/adaptive_inflation_storage.mli | 4 ++++ src/proto_alpha/lib_protocol/alpha_context.ml | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml index bd58fa325b7f..1baeed660054 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.ml @@ -37,6 +37,14 @@ let get_reward_coeff ctxt ~cycle = return (Option.value ~default k_opt) else return default +let load_reward_coeff ctxt ~cycle = + let open Lwt_result_syntax in + let* new_reward = get_reward_coeff ctxt ~cycle in + let ctxt = + Raw_context.update_reward_coeff_for_current_cycle ctxt new_reward + in + return ctxt + let compute_coeff = let q_400 = Q.of_int 400 in let q_min_per_year = Q.of_int 525600 in @@ -91,8 +99,7 @@ let update_stored_rewards_at_cycle_end ctxt ~new_cycle = let open Lwt_result_syntax in let* ctxt = compute_and_store_reward_coeff_at_cycle_end ctxt ~new_cycle in let*! ctxt = clear_outdated_reward_data ctxt ~new_cycle in - let* new_reward = get_reward_coeff ctxt ~cycle:new_cycle in - let ctxt = - Raw_context.update_reward_coeff_for_current_cycle ctxt new_reward - in - return ctxt + load_reward_coeff ctxt ~cycle:new_cycle + +let load_reward_coeff ctxt = + load_reward_coeff ctxt ~cycle:(Raw_context.current_level ctxt).cycle diff --git a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli index dbcde4b4fb0b..0af8728cdfb4 100644 --- a/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli +++ b/src/proto_alpha/lib_protocol/adaptive_inflation_storage.mli @@ -23,6 +23,10 @@ (* *) (*****************************************************************************) +(** [load_reward_coeff ctxt] loads the current cycle's reward coeff from the + storage into the context *) +val load_reward_coeff : Raw_context.t -> Raw_context.t tzresult Lwt.t + (** [update_stored_rewards_at_cycle_end ctxt ~new_cycle] updates {!Storage.Reward_coeff} with a new coefficient that will be applied [preserved_cycles] cycles after the given [new_cycle]. This new coefficient diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index e8a99ef4345b..e27119b98605 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -558,6 +558,7 @@ let prepare ctxt ~level ~predecessor_timestamp ~timestamp = >>=? fun (ctxt, balance_updates, origination_results) -> Consensus.load_endorsement_branch ctxt >>=? fun ctxt -> Delegate.load_forbidden_delegates ctxt >>=? fun ctxt -> + Adaptive_inflation_storage.load_reward_coeff ctxt >>=? fun ctxt -> return (ctxt, balance_updates, origination_results) let finalize ?commit_message:message c fitness = -- GitLab From 613c7e20cda1de6662dd16fae1c73f87826f63cc Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Fri, 26 May 2023 16:09:17 +0200 Subject: [PATCH 9/9] Proto/test: add Adaptive Inflation reward coeff test --- manifest/main.ml | 1 + src/proto_alpha/lib_protocol/test/unit/dune | 3 +- .../test/unit/test_adaptive_inflation.ml | 64 +++++++++++++++++++ 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/proto_alpha/lib_protocol/test/unit/test_adaptive_inflation.ml diff --git a/manifest/main.ml b/manifest/main.ml index 2a3ebf094a16..5dff50231223 100644 --- a/manifest/main.ml +++ b/manifest/main.ml @@ -4825,6 +4825,7 @@ end = struct ("test_dal_slot_proof", N.(number >= 016)); ("test_tx_rollup_l2_apply", N.(number >= 015 && number <= 016)); ("test_tx_rollup_l2", N.(number >= 015 && number <= 016)); + ("test_adaptive_inflation", N.(number >= 018)); ] |> List.filter_map (fun (n, b) -> if b then Some n else None) in diff --git a/src/proto_alpha/lib_protocol/test/unit/dune b/src/proto_alpha/lib_protocol/test/unit/dune index 75d1f001ab4b..501d73ce3659 100644 --- a/src/proto_alpha/lib_protocol/test/unit/dune +++ b/src/proto_alpha/lib_protocol/test/unit/dune @@ -71,7 +71,8 @@ test_sc_rollup_inbox_legacy test_sc_rollup_wasm test_local_contexts - test_dal_slot_proof)) + test_dal_slot_proof + test_adaptive_inflation)) (executable (name main) diff --git a/src/proto_alpha/lib_protocol/test/unit/test_adaptive_inflation.ml b/src/proto_alpha/lib_protocol/test/unit/test_adaptive_inflation.ml new file mode 100644 index 000000000000..9ccf5e6521a4 --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/unit/test_adaptive_inflation.ml @@ -0,0 +1,64 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (rewards) + Invocation: dune exec src/proto_alpha/lib_protocol/test/unit/main.exe \ + -- --file test_adaptive_inflation.ml + Subject: Test reward values under adaptive inflation +*) + +open Protocol +open Alpha_context + +let test_reward_coefficient () = + let csts = Default_parameters.constants_test in + let default = + Delegate.Rewards.Internal_for_tests.( + reward_from_constants csts ~reward_kind:Baking_reward_fixed_portion) + in + let default_times_4 = + Delegate.Rewards.Internal_for_tests.( + reward_from_constants + ~coeff:(Q.of_int 4) + csts + ~reward_kind:Baking_reward_fixed_portion) + in + assert (Tez.(equal (mul_exn default 4) default_times_4)) ; + return_unit + +let tests = + Tztest. + [ + tztest + "adaptive inflation - application of coefficient to rewards" + `Quick + test_reward_coefficient; + ] + +let () = + Alcotest_lwt.run ~__FILE__ Protocol.name [("adaptive inflation", tests)] + |> Lwt_main.run -- GitLab