From eac47fa36e0da9ff8071525e8709a9377a029f7f Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 1 Oct 2024 11:14:30 +0200 Subject: [PATCH 01/12] Alpha/DAL: export Dal.Attestation.intersection --- src/proto_alpha/lib_protocol/alpha_context.mli | 2 ++ src/proto_alpha/lib_protocol/dal_attestation_repr.ml | 2 ++ src/proto_alpha/lib_protocol/dal_attestation_repr.mli | 3 +++ 3 files changed, 7 insertions(+) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 60ccef1fbe7c..771aa0870540 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2802,6 +2802,8 @@ module Dal : sig val expected_size_in_bits : max_index:Slot_index.t -> int + val intersection : t -> t -> t + val record_number_of_attested_shards : context -> t -> int -> context end diff --git a/src/proto_alpha/lib_protocol/dal_attestation_repr.ml b/src/proto_alpha/lib_protocol/dal_attestation_repr.ml index d8429e61a2e9..9472193bc912 100644 --- a/src/proto_alpha/lib_protocol/dal_attestation_repr.ml +++ b/src/proto_alpha/lib_protocol/dal_attestation_repr.ml @@ -80,6 +80,8 @@ let expected_size_in_bits ~max_index = let number_of_attested_slots = Bitset.hamming_weight +let intersection = Bitset.inter + type shard_index = int module Shard_map = Map.Make (struct diff --git a/src/proto_alpha/lib_protocol/dal_attestation_repr.mli b/src/proto_alpha/lib_protocol/dal_attestation_repr.mli index 93a1a0b75d5a..06d59da6dd1a 100644 --- a/src/proto_alpha/lib_protocol/dal_attestation_repr.mli +++ b/src/proto_alpha/lib_protocol/dal_attestation_repr.mli @@ -73,6 +73,9 @@ val expected_size_in_bits : max_index:Dal_slot_index_repr.t -> int slots in an attestation. *) val number_of_attested_slots : t -> int +(** [intersection a1 a2] returns the slots attested in both [a1] and [a2]. *) +val intersection : t -> t -> t + (** A shard_index is a positive number. *) type shard_index = int -- GitLab From 642460c0628b58ebe72ad886f374d858f8b0e813 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Mon, 30 Sep 2024 16:18:17 +0200 Subject: [PATCH 02/12] Alpha/DAL: refactor DAL related fields in Raw_context Also remove reference to closed issue #3105 --- src/proto_alpha/lib_protocol/raw_context.ml | 78 ++++++++++++--------- 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index 3230d55952c9..ea31cbb7a642 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -223,6 +223,24 @@ module Raw_consensus = struct {t with attestation_branch = Some attestation_branch} end +module Raw_dal = struct + type t = { + cryptobox : Dal.t option; + slot_fee_market : Dal_slot_repr.Slot_market.t; + (** records the published slot headers *) + slot_accountability : Dal_attestation_repr.Accountability.t; + (** records attested shards, in order to determine protocol-attested slots *) + } + + let init ~number_of_slots = + { + cryptobox = None; + slot_fee_market = Dal_slot_repr.Slot_market.init ~length:number_of_slots; + slot_accountability = + Dal_attestation_repr.Accountability.init ~number_of_slots; + } +end + type back = { context : Context.t; constants : Constants_parametric_repr.t; @@ -246,22 +264,7 @@ type back = { 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 - - We associate to a slot header some fees. This enable the use - of a fee market for slot publication. However, this is not - resilient from the game theory point of view. Probably we can find - better incentives here. In any case, because we want the following - invariant: - - - For each level and for each slot there is at most one slot - header. - - - We need to provide an incentive to avoid byzantines to post - dummy slot headers. *) - dal_attestation_slot_accountability : Dal_attestation_repr.Accountability.t; - dal_cryptobox : Dal.t option; + dal : Raw_dal.t; adaptive_issuance_enable : bool; } @@ -869,14 +872,10 @@ let prepare ~level ~predecessor_timestamp ~timestamp ~adaptive_issuance_enable 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 - ~length:constants.Constants_parametric_repr.dal.number_of_slots; - dal_attestation_slot_accountability = - Dal_attestation_repr.Accountability.init + dal = + Raw_dal.init ~number_of_slots: constants.Constants_parametric_repr.dal.number_of_slots; - dal_cryptobox = None; adaptive_issuance_enable; }; } @@ -2129,7 +2128,7 @@ module Dal = struct let open Result_syntax in (* Dal.make takes some time (on the order of 10ms) so we memoize its result to avoid calling it more than once per block. *) - match ctxt.back.dal_cryptobox with + match ctxt.back.dal.cryptobox with | Some cryptobox -> return (ctxt, cryptobox) | None -> ( let Constants_parametric_repr.{dal = {cryptobox_parameters; _}; _} = @@ -2137,7 +2136,12 @@ module Dal = struct in match Dal.make cryptobox_parameters with | Ok cryptobox -> - let back = {ctxt.back with dal_cryptobox = Some cryptobox} in + let back = + { + ctxt.back with + dal = {ctxt.back.dal with cryptobox = Some cryptobox}; + } + in return ({ctxt with back}, cryptobox) | Error (`Fail explanation) -> tzfail (Dal_errors_repr.Dal_cryptobox_error {explanation})) @@ -2148,37 +2152,45 @@ module Dal = struct ctxt.back.constants.dal.cryptobox_parameters.number_of_shards let record_number_of_attested_shards ctxt attestation number = - let dal_attestation_slot_accountability = + let slot_accountability = Dal_attestation_repr.Accountability.record_number_of_attested_shards - ctxt.back.dal_attestation_slot_accountability + ctxt.back.dal.slot_accountability attestation number in - {ctxt with back = {ctxt.back with dal_attestation_slot_accountability}} + { + ctxt with + back = {ctxt.back with dal = {ctxt.back.dal with slot_accountability}}; + } let register_slot_header ctxt slot_header ~source = let open Result_syntax in match Dal_slot_repr.Slot_market.register - ctxt.back.dal_slot_fee_market + ctxt.back.dal.slot_fee_market slot_header ~source with | None -> let length = - Dal_slot_repr.Slot_market.length ctxt.back.dal_slot_fee_market + Dal_slot_repr.Slot_market.length ctxt.back.dal.slot_fee_market in tzfail (Dal_errors_repr.Dal_register_invalid_slot_header {length; slot_header}) - | Some (dal_slot_fee_market, updated) -> + | Some (slot_fee_market, updated) -> if not updated then tzfail (Dal_errors_repr.Dal_publish_commitment_duplicate {slot_header}) - else return {ctxt with back = {ctxt.back with dal_slot_fee_market}} + else + return + { + ctxt with + back = {ctxt.back with dal = {ctxt.back.dal with slot_fee_market}}; + } let candidates ctxt = - Dal_slot_repr.Slot_market.candidates ctxt.back.dal_slot_fee_market + Dal_slot_repr.Slot_market.candidates ctxt.back.dal.slot_fee_market let is_slot_index_attested ctxt = let threshold = @@ -2189,7 +2201,7 @@ module Dal = struct .number_of_shards in Dal_attestation_repr.Accountability.is_slot_attested - ctxt.back.dal_attestation_slot_accountability + ctxt.back.dal.slot_accountability ~threshold ~number_of_shards end -- GitLab From 07a6a3919d6ac475d6043d668d8a19eb42997470 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 7 Nov 2024 16:16:52 +0100 Subject: [PATCH 03/12] Alpha/DAL: use accessors in Raw_context --- src/proto_alpha/lib_protocol/raw_context.ml | 58 +++++++++------------ 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index ea31cbb7a642..c6f60933292d 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -335,6 +335,8 @@ 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] dal ctxt = ctxt.back.dal + let[@inline] adaptive_issuance_enable ctxt = ctxt.back.adaptive_issuance_enable let[@inline] update_back ctxt back = {ctxt with back} @@ -382,6 +384,8 @@ 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} +let[@inline] update_dal ctxt dal = update_back ctxt {ctxt.back with dal} + let[@inline] set_adaptive_issuance_enable ctxt = update_back ctxt {ctxt.back with adaptive_issuance_enable = true} @@ -2128,7 +2132,8 @@ module Dal = struct let open Result_syntax in (* Dal.make takes some time (on the order of 10ms) so we memoize its result to avoid calling it more than once per block. *) - match ctxt.back.dal.cryptobox with + let dal = dal ctxt in + match dal.cryptobox with | Some cryptobox -> return (ctxt, cryptobox) | None -> ( let Constants_parametric_repr.{dal = {cryptobox_parameters; _}; _} = @@ -2136,45 +2141,34 @@ module Dal = struct in match Dal.make cryptobox_parameters with | Ok cryptobox -> - let back = - { - ctxt.back with - dal = {ctxt.back.dal with cryptobox = Some cryptobox}; - } - in - return ({ctxt with back}, cryptobox) + let ctxt = update_dal ctxt {dal with cryptobox = Some cryptobox} in + return (ctxt, cryptobox) | Error (`Fail explanation) -> tzfail (Dal_errors_repr.Dal_cryptobox_error {explanation})) - let number_of_slots ctxt = ctxt.back.constants.dal.number_of_slots + let[@inline] number_of_slots ctxt = ctxt.back.constants.dal.number_of_slots - let number_of_shards ctxt = + let[@inline] number_of_shards ctxt = ctxt.back.constants.dal.cryptobox_parameters.number_of_shards let record_number_of_attested_shards ctxt attestation number = + let dal = dal ctxt in let slot_accountability = Dal_attestation_repr.Accountability.record_number_of_attested_shards - ctxt.back.dal.slot_accountability + dal.slot_accountability attestation number in - { - ctxt with - back = {ctxt.back with dal = {ctxt.back.dal with slot_accountability}}; - } + update_dal ctxt {dal with slot_accountability} let register_slot_header ctxt slot_header ~source = let open Result_syntax in + let dal = dal ctxt in match - Dal_slot_repr.Slot_market.register - ctxt.back.dal.slot_fee_market - slot_header - ~source + Dal_slot_repr.Slot_market.register dal.slot_fee_market slot_header ~source with | None -> - let length = - Dal_slot_repr.Slot_market.length ctxt.back.dal.slot_fee_market - in + let length = Dal_slot_repr.Slot_market.length dal.slot_fee_market in tzfail (Dal_errors_repr.Dal_register_invalid_slot_header {length; slot_header}) @@ -2182,26 +2176,24 @@ module Dal = struct if not updated then tzfail (Dal_errors_repr.Dal_publish_commitment_duplicate {slot_header}) - else - return - { - ctxt with - back = {ctxt.back with dal = {ctxt.back.dal with slot_fee_market}}; - } + else return @@ update_dal ctxt {dal with slot_fee_market} - let candidates ctxt = - Dal_slot_repr.Slot_market.candidates ctxt.back.dal.slot_fee_market + let[@inline] candidates ctxt = + let dal = dal ctxt in + Dal_slot_repr.Slot_market.candidates dal.slot_fee_market let is_slot_index_attested ctxt = + let dal = dal ctxt in + let constants = constants ctxt in let threshold = - ctxt.back.constants.Constants_parametric_repr.dal.attestation_threshold + constants.Constants_parametric_repr.dal.attestation_threshold in let number_of_shards = - ctxt.back.constants.Constants_parametric_repr.dal.cryptobox_parameters + constants.Constants_parametric_repr.dal.cryptobox_parameters .number_of_shards in Dal_attestation_repr.Accountability.is_slot_attested - ctxt.back.dal.slot_accountability + dal.slot_accountability ~threshold ~number_of_shards end -- GitLab From 506b547e3cca788af4037870f54253294ce01492 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Wed, 13 Nov 2024 13:07:20 +0100 Subject: [PATCH 04/12] Alpha/DAL: uniformize the use of constants with rest of the code --- src/proto_alpha/lib_protocol/alpha_context.mli | 14 ++++++-------- src/proto_alpha/lib_protocol/baking.ml | 2 +- src/proto_alpha/lib_protocol/constants_storage.ml | 4 ++++ src/proto_alpha/lib_protocol/constants_storage.mli | 2 ++ src/proto_alpha/lib_protocol/dal_apply.ml | 8 ++++---- src/proto_alpha/lib_protocol/dal_services.ml | 2 +- src/proto_alpha/lib_protocol/raw_context.ml | 10 +--------- src/proto_alpha/lib_protocol/raw_context.mli | 4 ---- 8 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 771aa0870540..1b3a9b11b7a3 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -833,8 +833,6 @@ module Constants : sig rewards_ratio : Q.t; } - val dal_encoding : dal Data_encoding.t - type sc_rollup_reveal_hashing_schemes = {blake2B : Raw_level.t} type sc_rollup_reveal_activation_level = { @@ -1048,12 +1046,16 @@ module Constants : sig val testnet_dictator : context -> public_key_hash option + val dal_enable : context -> bool + + val dal_number_of_slots : context -> int + + val dal_number_of_shards : context -> int + val sc_rollup_arith_pvm_enable : context -> bool val sc_rollup_riscv_pvm_enable : context -> bool - val dal_enable : context -> bool - val sc_rollup_origination_size : context -> int val sc_rollup_stake_amount : t -> Tez.t @@ -2740,10 +2742,6 @@ module Dal : sig val make : context -> (context * cryptobox) tzresult - val number_of_slots : context -> int - - val number_of_shards : context -> int - (** This module re-exports definitions from {!Dal_slot_index_repr}. *) module Slot_index : sig type t diff --git a/src/proto_alpha/lib_protocol/baking.ml b/src/proto_alpha/lib_protocol/baking.ml index 7cc21c60edc0..dc9214784df2 100644 --- a/src/proto_alpha/lib_protocol/baking.ml +++ b/src/proto_alpha/lib_protocol/baking.ml @@ -110,7 +110,7 @@ let attesting_rights_by_first_slot ctxt level = let*? slots = Slot.Range.create ~min:0 ~count:(Constants.consensus_committee_size ctxt) in - let number_of_shards = Dal.number_of_shards ctxt in + let number_of_shards = Constants.dal_number_of_shards ctxt in let* ctxt, (_, slots_map) = Slot.Range.fold_es (fun (ctxt, (delegates_map, slots_map)) slot -> diff --git a/src/proto_alpha/lib_protocol/constants_storage.ml b/src/proto_alpha/lib_protocol/constants_storage.ml index 46b63e8266f6..6cb9c8a6c637 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.ml +++ b/src/proto_alpha/lib_protocol/constants_storage.ml @@ -249,6 +249,10 @@ let dal_number_of_slots c = let constants = Raw_context.constants c in constants.dal.number_of_slots +let dal_number_of_shards c = + let constants = Raw_context.constants c in + constants.dal.cryptobox_parameters.number_of_shards + let dal_enable c = let constants = Raw_context.constants c in constants.dal.feature_enable diff --git a/src/proto_alpha/lib_protocol/constants_storage.mli b/src/proto_alpha/lib_protocol/constants_storage.mli index 02d0a21ad23d..5e019236121e 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.mli +++ b/src/proto_alpha/lib_protocol/constants_storage.mli @@ -131,6 +131,8 @@ val sc_rollup_private_enable : Raw_context.t -> bool val dal_number_of_slots : Raw_context.t -> int +val dal_number_of_shards : Raw_context.t -> int + val dal_enable : Raw_context.t -> bool val zk_rollup_enable : Raw_context.t -> bool diff --git a/src/proto_alpha/lib_protocol/dal_apply.ml b/src/proto_alpha/lib_protocol/dal_apply.ml index 912771e7a147..94682a0f7c3a 100644 --- a/src/proto_alpha/lib_protocol/dal_apply.ml +++ b/src/proto_alpha/lib_protocol/dal_apply.ml @@ -56,7 +56,7 @@ let pkh_of_consensus_key (consensus_key : Consensus_key.pk) = let validate_attestation ctxt level slot consensus_key attestation = let open Lwt_result_syntax in let*? () = assert_dal_feature_enabled ctxt in - let number_of_slots = Dal.number_of_slots ctxt in + let number_of_slots = Constants.dal_number_of_slots ctxt in let*? max_index = number_of_slots - 1 |> slot_of_int_e ~number_of_slots in let maximum_size = Dal.Attestation.expected_size_in_bits ~max_index in let size = Dal.Attestation.occupied_size_in_bits attestation in @@ -65,7 +65,7 @@ let validate_attestation ctxt level slot consensus_key attestation = Compare.Int.(size <= maximum_size) (Dal_attestation_size_limit_exceeded {maximum_size; got = size}) in - let number_of_shards = Dal.number_of_shards ctxt in + let number_of_shards = Constants.dal_number_of_shards ctxt in fail_when Compare.Int.(Slot.to_int slot >= number_of_shards) (let attester = pkh_of_consensus_key consensus_key in @@ -90,7 +90,7 @@ let validate_publish_commitment ctxt _operation = let apply_publish_commitment ctxt operation ~source = let open Result_syntax in let* ctxt = Gas.consume ctxt Dal_costs.cost_Dal_publish_commitment in - let number_of_slots = Dal.number_of_slots ctxt in + let number_of_slots = Constants.dal_number_of_slots ctxt in let* ctxt, cryptobox = Dal.make ctxt in let current_level = (Level.current ctxt).level in let* slot_header = @@ -125,7 +125,7 @@ let finalisation ctxt = - disallow proofs involving pages of slots that have been confirmed at the level where the game started. *) - let number_of_slots = Dal.number_of_slots ctxt in + let number_of_slots = Constants.dal_number_of_slots ctxt in let+ ctxt, attestation = Dal.Slot.finalize_pending_slot_headers ctxt ~number_of_slots in diff --git a/src/proto_alpha/lib_protocol/dal_services.ml b/src/proto_alpha/lib_protocol/dal_services.ml index 1668c2f1b40a..04031bd105aa 100644 --- a/src/proto_alpha/lib_protocol/dal_services.ml +++ b/src/proto_alpha/lib_protocol/dal_services.ml @@ -37,7 +37,7 @@ let assert_dal_feature_enabled ctxt = let shards ctxt ~level = let open Lwt_result_syntax in let*? () = assert_dal_feature_enabled ctxt in - let number_of_shards = Dal.number_of_shards ctxt in + let number_of_shards = Constants.dal_number_of_shards ctxt in let*? slots = Slot.Range.create ~min:0 ~count:number_of_shards in Slot.Range.rev_fold_es (fun (ctxt, map) slot -> diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index c6f60933292d..f1877ecfb0e5 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -2136,21 +2136,13 @@ module Dal = struct match dal.cryptobox with | Some cryptobox -> return (ctxt, cryptobox) | None -> ( - let Constants_parametric_repr.{dal = {cryptobox_parameters; _}; _} = - ctxt.back.constants - in - match Dal.make cryptobox_parameters with + match Dal.make (constants ctxt).dal.cryptobox_parameters with | Ok cryptobox -> let ctxt = update_dal ctxt {dal with cryptobox = Some cryptobox} in return (ctxt, cryptobox) | Error (`Fail explanation) -> tzfail (Dal_errors_repr.Dal_cryptobox_error {explanation})) - let[@inline] number_of_slots ctxt = ctxt.back.constants.dal.number_of_slots - - let[@inline] number_of_shards ctxt = - ctxt.back.constants.dal.cryptobox_parameters.number_of_shards - let record_number_of_attested_shards ctxt attestation number = let dal = dal ctxt in let slot_accountability = diff --git a/src/proto_alpha/lib_protocol/raw_context.mli b/src/proto_alpha/lib_protocol/raw_context.mli index c073e3d2b43e..9790d0bf2c22 100644 --- a/src/proto_alpha/lib_protocol/raw_context.mli +++ b/src/proto_alpha/lib_protocol/raw_context.mli @@ -432,10 +432,6 @@ module Dal : sig val make : t -> (t * cryptobox) tzresult - val number_of_slots : t -> int - - val number_of_shards : t -> int - (** [record_number_of_attested_shards ctxt attestation number_of_shards] records that the [number_of_shards] shards were attested (declared available by some attester). *) -- GitLab From 60da4c6aa4d7d424b6dde2ffa50639804d1698fc Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Mon, 18 Nov 2024 11:55:49 +0100 Subject: [PATCH 05/12] Alpha/DAL: move flag checking functions in Raw_context.Dal --- .../lib_protocol/alpha_context.mli | 6 ++++++ src/proto_alpha/lib_protocol/dal_apply.ml | 20 +++++-------------- src/proto_alpha/lib_protocol/dal_services.ml | 9 +-------- src/proto_alpha/lib_protocol/raw_context.ml | 14 +++++++++++++ src/proto_alpha/lib_protocol/raw_context.mli | 11 ++++++++++ 5 files changed, 37 insertions(+), 23 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 1b3a9b11b7a3..3eed599a6467 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2742,6 +2742,12 @@ module Dal : sig val make : context -> (context * cryptobox) tzresult + val assert_feature_enabled : t -> unit tzresult + + val only_if_feature_enabled : t -> default:(t -> 'a) -> (t -> 'a) -> 'a + + val only_if_incentives_enabled : t -> default:(t -> 'a) -> (t -> 'a) -> 'a + (** This module re-exports definitions from {!Dal_slot_index_repr}. *) module Slot_index : sig type t diff --git a/src/proto_alpha/lib_protocol/dal_apply.ml b/src/proto_alpha/lib_protocol/dal_apply.ml index 94682a0f7c3a..56fb4eb4f0a2 100644 --- a/src/proto_alpha/lib_protocol/dal_apply.ml +++ b/src/proto_alpha/lib_protocol/dal_apply.ml @@ -28,22 +28,12 @@ open Alpha_context open Dal_errors -let assert_dal_feature_enabled ctxt = - let open Constants in - let Parametric.{dal = {feature_enable; _}; _} = parametric ctxt in - error_unless Compare.Bool.(feature_enable = true) Dal_feature_disabled - -let only_if_dal_feature_enabled ctxt ~default f = - let open Constants in - let Parametric.{dal = {feature_enable; _}; _} = parametric ctxt in - if feature_enable then f ctxt else default ctxt - let slot_of_int_e ~number_of_slots n = let open Result_syntax in match Dal.Slot_index.of_int_opt ~number_of_slots n with | None -> tzfail - @@ Dal_errors.Dal_slot_index_above_hard_limit + @@ Dal_slot_index_above_hard_limit {given = n; limit = number_of_slots - 1} | Some slot_index -> return slot_index @@ -55,7 +45,7 @@ let pkh_of_consensus_key (consensus_key : Consensus_key.pk) = let validate_attestation ctxt level slot consensus_key attestation = let open Lwt_result_syntax in - let*? () = assert_dal_feature_enabled ctxt in + let*? () = Dal.assert_feature_enabled ctxt in let number_of_slots = Constants.dal_number_of_slots ctxt in let*? max_index = number_of_slots - 1 |> slot_of_int_e ~number_of_slots in let maximum_size = Dal.Attestation.expected_size_in_bits ~max_index in @@ -73,7 +63,7 @@ let validate_attestation ctxt level slot consensus_key attestation = let apply_attestation ctxt attestation ~power = let open Result_syntax in - let* () = assert_dal_feature_enabled ctxt in + let* () = Dal.assert_feature_enabled ctxt in return (Dal.Attestation.record_number_of_attested_shards ctxt attestation power) @@ -85,7 +75,7 @@ let apply_attestation ctxt attestation ~power = malicious (or if there is a bug). In that case, it is better to ensure fees will be taken. *) let validate_publish_commitment ctxt _operation = - assert_dal_feature_enabled ctxt + Dal.assert_feature_enabled ctxt let apply_publish_commitment ctxt operation ~source = let open Result_syntax in @@ -105,7 +95,7 @@ let apply_publish_commitment ctxt operation ~source = let finalisation ctxt = let open Lwt_result_syntax in - only_if_dal_feature_enabled + Dal.only_if_feature_enabled ctxt ~default:(fun ctxt -> return (ctxt, Dal.Attestation.empty)) (fun ctxt -> diff --git a/src/proto_alpha/lib_protocol/dal_services.ml b/src/proto_alpha/lib_protocol/dal_services.ml index 04031bd105aa..9b1a2d3441f7 100644 --- a/src/proto_alpha/lib_protocol/dal_services.ml +++ b/src/proto_alpha/lib_protocol/dal_services.ml @@ -25,18 +25,11 @@ open Alpha_context -let assert_dal_feature_enabled ctxt = - let open Constants in - let Parametric.{dal = {feature_enable; _}; _} = parametric ctxt in - error_unless - Compare.Bool.(feature_enable = true) - Dal_errors.Dal_feature_disabled - (* Slots returned by this function are assumed by consumers to be in increasing order, hence the use of [Slot.Range.rev_fold_es]. *) let shards ctxt ~level = let open Lwt_result_syntax in - let*? () = assert_dal_feature_enabled ctxt in + let*? () = Dal.assert_feature_enabled ctxt in let number_of_shards = Constants.dal_number_of_shards ctxt in let*? slots = Slot.Range.create ~min:0 ~count:number_of_shards in Slot.Range.rev_fold_es diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index f1877ecfb0e5..db12ff23a87b 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -2188,6 +2188,20 @@ module Dal = struct dal.slot_accountability ~threshold ~number_of_shards + + let assert_feature_enabled ctxt = + let constants = constants ctxt in + error_unless + Compare.Bool.(constants.dal.feature_enable = true) + Dal_errors_repr.Dal_feature_disabled + + let only_if_feature_enabled ctxt ~default f = + let constants = constants ctxt in + if constants.dal.feature_enable then f ctxt else default ctxt + + let only_if_incentives_enabled ctxt ~default f = + let constants = constants ctxt in + if constants.dal.incentives_enable then f ctxt else default ctxt end (* The type for relative context accesses instead from the root. In order for diff --git a/src/proto_alpha/lib_protocol/raw_context.mli b/src/proto_alpha/lib_protocol/raw_context.mli index 9790d0bf2c22..838a428e4e74 100644 --- a/src/proto_alpha/lib_protocol/raw_context.mli +++ b/src/proto_alpha/lib_protocol/raw_context.mli @@ -461,4 +461,15 @@ module Dal : sig t -> Dal_slot_index_repr.t -> Dal_attestation_repr.Accountability.attestation_status + + (* Check whether the DAL feature flag is set and return an error if not. *) + val assert_feature_enabled : t -> unit tzresult + + (* [only_if_dal_feature_enabled ctxt ~default f] executes [f ctxt] if the DAL + feature flag is enabled and otherwise [default ctxt]. *) + val only_if_feature_enabled : t -> default:(t -> 'a) -> (t -> 'a) -> 'a + + (* [only_if_dal_incentives_enabled ctxt ~default f] executes [f ctxt] if the + DAL incentives flag is enabled and otherwise [default ctxt]. *) + val only_if_incentives_enabled : t -> default:(t -> 'a) -> (t -> 'a) -> 'a end -- GitLab From 1c17485d68ceb8008c55471e866d3dffab36bde5 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 1 Oct 2024 11:18:54 +0200 Subject: [PATCH 06/12] Alpha/DAL: record delegate attestations --- src/proto_alpha/lib_protocol/alpha_context.mli | 6 ++++++ src/proto_alpha/lib_protocol/apply.ml | 6 +++++- src/proto_alpha/lib_protocol/dal_apply.ml | 8 +++++++- src/proto_alpha/lib_protocol/dal_apply.mli | 8 +++++--- src/proto_alpha/lib_protocol/raw_context.ml | 16 ++++++++++++++++ src/proto_alpha/lib_protocol/raw_context.mli | 8 ++++++++ 6 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 3eed599a6467..79fd628b5214 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2806,9 +2806,15 @@ module Dal : sig val expected_size_in_bits : max_index:Slot_index.t -> int + val number_of_attested_slots : t -> int + val intersection : t -> t -> t val record_number_of_attested_shards : context -> t -> int -> context + + val record_attestation : context -> tb_slot:Slot.t -> t -> context + + val attestations : context -> t Slot.Map.t end type slot_id = {published_level : Raw_level.t; index : Slot_index.t} diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index eb5ea70a8182..1b79a1f49353 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -2296,7 +2296,11 @@ let record_attestation ctxt (mode : mode) (consensus : consensus_content) Option.fold ~none:(Result_syntax.return ctxt) ~some:(fun dal -> - Dal_apply.apply_attestation ctxt dal.attestation ~power:dal_power) + Dal_apply.apply_attestation + ctxt + ~tb_slot:consensus.slot + dal.attestation + ~power:dal_power) dal in return (ctxt, mk_attestation_result consensus_key power) diff --git a/src/proto_alpha/lib_protocol/dal_apply.ml b/src/proto_alpha/lib_protocol/dal_apply.ml index 56fb4eb4f0a2..7b65a16ae506 100644 --- a/src/proto_alpha/lib_protocol/dal_apply.ml +++ b/src/proto_alpha/lib_protocol/dal_apply.ml @@ -61,9 +61,15 @@ let validate_attestation ctxt level slot consensus_key attestation = (let attester = pkh_of_consensus_key consensus_key in Dal_data_availibility_attester_not_in_committee {attester; level; slot}) -let apply_attestation ctxt attestation ~power = +let apply_attestation ctxt attestation ~tb_slot ~power = let open Result_syntax in let* () = Dal.assert_feature_enabled ctxt in + let ctxt = + Dal.only_if_incentives_enabled + ctxt + ~default:(fun ctxt -> ctxt) + (fun ctxt -> Dal.Attestation.record_attestation ctxt ~tb_slot attestation) + in return (Dal.Attestation.record_number_of_attested_shards ctxt attestation power) diff --git a/src/proto_alpha/lib_protocol/dal_apply.mli b/src/proto_alpha/lib_protocol/dal_apply.mli index 7dcb0d7b9f98..628071b0e096 100644 --- a/src/proto_alpha/lib_protocol/dal_apply.mli +++ b/src/proto_alpha/lib_protocol/dal_apply.mli @@ -45,10 +45,12 @@ val validate_attestation : Dal.Attestation.t -> unit tzresult Lwt.t -(** [apply_attestation ctxt attestation] records in the context that the given - [attestation] was issued and the corresponding attester has the given +(** [apply_attestation ctxt attestation ~tb_slot ~power] records in the context + that the given [attestation] was issued by the delegate with initial + Tenderbake slot [tb_slot] and the corresponding attester has the given [power]. *) -val apply_attestation : t -> Dal.Attestation.t -> power:int -> t tzresult +val apply_attestation : + t -> Dal.Attestation.t -> tb_slot:Slot.t -> power:int -> t tzresult (** [validate_publish_commitment ctxt slot] ensures that [slot_header] is valid and prevents an operation containing [slot_header] to be diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index db12ff23a87b..c8ab44e654af 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -230,6 +230,8 @@ module Raw_dal = struct (** records the published slot headers *) slot_accountability : Dal_attestation_repr.Accountability.t; (** records attested shards, in order to determine protocol-attested slots *) + attestations : Dal_attestation_repr.t Slot_repr.Map.t; + (** records the included DAL attestations *) } let init ~number_of_slots = @@ -238,6 +240,7 @@ module Raw_dal = struct slot_fee_market = Dal_slot_repr.Slot_market.init ~length:number_of_slots; slot_accountability = Dal_attestation_repr.Accountability.init ~number_of_slots; + attestations = Slot_repr.Map.empty; } end @@ -2174,6 +2177,19 @@ module Dal = struct let dal = dal ctxt in Dal_slot_repr.Slot_market.candidates dal.slot_fee_market + let record_attestation ctxt ~tb_slot attestation = + let dal = dal ctxt in + update_dal + ctxt + { + dal with + attestations = Slot_repr.Map.add tb_slot attestation dal.attestations; + } + + let[@inline] attestations ctxt = + let dal = dal ctxt in + dal.attestations + let is_slot_index_attested ctxt = let dal = dal ctxt in let constants = constants ctxt in diff --git a/src/proto_alpha/lib_protocol/raw_context.mli b/src/proto_alpha/lib_protocol/raw_context.mli index 838a428e4e74..e98c2376864f 100644 --- a/src/proto_alpha/lib_protocol/raw_context.mli +++ b/src/proto_alpha/lib_protocol/raw_context.mli @@ -445,6 +445,14 @@ module Dal : sig val register_slot_header : t -> Dal_slot_repr.Header.t -> source:Contract_repr.t -> t tzresult + (** [record_attestation ctxt ~tb_slot attestation] records that the delegate + with Tenderbake slot [tb_slot] emitted [attestation]. *) + val record_attestation : + t -> tb_slot:Slot_repr.t -> Dal_attestation_repr.t -> t + + (** [attestations] returns the recorded attestations *) + val attestations : t -> Dal_attestation_repr.t Slot_repr.Map.t + (** [candidates ctxt] returns the current list of slot for which there is at least one candidate alongside the addresses that published them. *) val candidates : t -> (Dal_slot_repr.Header.t * Contract_repr.t) list -- GitLab From 2e59c10c7205a28236f78d56909f90357d2816fe Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 1 Oct 2024 15:53:51 +0200 Subject: [PATCH 07/12] Alpha/DAL: store number of protocol-attested slots --- .../lib_protocol/dal_slot_storage.ml | 22 +++++++++++++++++++ .../delegate_missed_attestations_storage.ml | 3 +++ .../delegate_missed_attestations_storage.mli | 3 +++ src/proto_alpha/lib_protocol/storage.ml | 7 ++++++ src/proto_alpha/lib_protocol/storage.mli | 4 ++++ 5 files changed, 39 insertions(+) diff --git a/src/proto_alpha/lib_protocol/dal_slot_storage.ml b/src/proto_alpha/lib_protocol/dal_slot_storage.ml index ef6062f96af7..4b30e6bc0417 100644 --- a/src/proto_alpha/lib_protocol/dal_slot_storage.ml +++ b/src/proto_alpha/lib_protocol/dal_slot_storage.ml @@ -95,6 +95,22 @@ let update_skip_list ctxt ~slot_headers_statuses ~published_level in return ctxt +let update_number_of_attested_slots ctxt num_attested_slots = + let open Lwt_result_syntax in + Raw_context.Dal.only_if_incentives_enabled ctxt ~default:return (fun ctxt -> + if Compare.Int.(num_attested_slots = 0) then return ctxt + else + let* res = Storage.Dal.Total_attested_slots.find ctxt in + match res with + | None -> + Storage.Dal.Total_attested_slots.init + ctxt + (Int32.of_int num_attested_slots) + | Some v -> + Storage.Dal.Total_attested_slots.update + ctxt + Int32.(add v (of_int num_attested_slots))) + let finalize_pending_slot_headers ctxt ~number_of_slots = let open Lwt_result_syntax in let {Level_repr.level = raw_level; _} = Raw_context.current_level ctxt in @@ -116,6 +132,12 @@ let finalize_pending_slot_headers ctxt ~number_of_slots = in compute_slot_headers_statuses ~is_slot_attested published_slots in + let num_attested_slots = + Dal_attestation_repr.number_of_attested_slots attestation + in + let* ctxt = + update_number_of_attested_slots ctxt num_attested_slots + in return (ctxt, attestation, slot_headers_statuses) in let* ctxt = diff --git a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml index 75e22cc632c7..454b8269e27e 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml @@ -43,6 +43,9 @@ let expected_slots_for_given_active_stake ctxt ~total_active_stake_weight (Z.of_int number_of_attestations_per_cycle)) (Z.of_int64 total_active_stake_weight)) +let remove_total_dal_attested_slots ctxt = + Storage.Dal.Total_attested_slots.remove ctxt + type level_participation = Participated | Didn't_participate (* Note that the participation for the last block of a cycle is diff --git a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli index 6f343fd43438..b3578e155093 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli @@ -36,6 +36,9 @@ val expected_slots_for_given_active_stake : active_stake_weight:int64 -> int +(** Removes the [Storage.Dal.Total_attested_slots] value from the context. *) +val remove_total_dal_attested_slots : Raw_context.t -> Raw_context.t Lwt.t + type level_participation = Participated | Didn't_participate (** Record the participation of a delegate as a validator. *) diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index d9c4caed4854..189b7555da73 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -2210,6 +2210,13 @@ module Dal = struct (req "cell" H.encoding)) end) end + + module Total_attested_slots = + Make_single_data_storage (Registered) (Raw_context) + (struct + let name = ["total_attested_slots"] + end) + (Encoding.Int32) end module Zk_rollup = struct diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index 8d9350b94d8f..fc2ec0259a4d 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -1046,6 +1046,10 @@ module Dal : sig attested or to access its attestation ratio). *) (Dal_slot_repr.History.Pointer_hash.t * Dal_slot_repr.History.t) list end + + (** The number of protocol-attested DAL slots for the current cycle. *) + module Total_attested_slots : + Single_data_storage with type t := Raw_context.t and type value = Int32.t end module Zk_rollup : sig -- GitLab From e78dea24765fc6ce80b9452907e2c952608c55e5 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 1 Oct 2024 11:40:29 +0200 Subject: [PATCH 08/12] Alpha/DAL: store delegate participation --- .../lib_protocol/alpha_context.mli | 6 ++++ src/proto_alpha/lib_protocol/apply.ml | 23 ++++++++++----- src/proto_alpha/lib_protocol/dal_apply.ml | 17 +++++++++++ src/proto_alpha/lib_protocol/dal_apply.mli | 10 +++++++ .../delegate_missed_attestations_storage.ml | 28 +++++++++++++++++++ .../delegate_missed_attestations_storage.mli | 19 ++++++++++++- src/proto_alpha/lib_protocol/storage.ml | 8 ++++++ src/proto_alpha/lib_protocol/storage.mli | 8 ++++++ 8 files changed, 111 insertions(+), 8 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 79fd628b5214..0f03600f496a 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2313,6 +2313,12 @@ module Delegate : sig attesting_power:int -> context tzresult Lwt.t + val record_dal_participation : + context -> + delegate:Signature.Public_key_hash.t -> + number_of_attested_slots:int -> + context tzresult Lwt.t + val current_frozen_deposits : context -> public_key_hash -> Tez.t tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 1b79a1f49353..3a58d352f8d2 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -2764,7 +2764,9 @@ let are_attestations_required ctxt ~level = let level_position_in_protocol = Raw_level.diff level first_level in Compare.Int32.(level_position_in_protocol > 1l) -let record_attesting_participation ctxt = +(* It also records participation in the DAL. *) +let record_attesting_participation ctxt dal_attestation = + let open Lwt_result_syntax in match Consensus.allowed_attestations ctxt with | None -> tzfail (Consensus.Slot_map_not_found {loc = __LOC__}) | Some validators -> @@ -2777,11 +2779,18 @@ let record_attesting_participation ctxt = Delegate.Participated else Delegate.Didn't_participate in - Delegate.record_attesting_participation + let* ctxt = + Delegate.record_attesting_participation + ctxt + ~delegate:consensus_pk.delegate + ~participation + ~attesting_power:power + in + Dal_apply.record_dal_participation ctxt - ~delegate:consensus_pk.delegate - ~participation - ~attesting_power:power) + consensus_pk.delegate + initial_slot + dal_attestation) validators ctxt @@ -3000,9 +3009,10 @@ let finalize_application ctxt block_data_contents ~round ~predecessor_hash | Some nonce_hash -> Nonce.record_hash ctxt {nonce_hash; delegate = block_producer.delegate} in + let* ctxt, dal_attestation = Dal_apply.finalisation ctxt in let* ctxt, reward_bonus = if required_attestations then - let* ctxt = record_attesting_participation ctxt in + let* ctxt = record_attesting_participation ctxt dal_attestation in let*? rewards_bonus = Baking.bonus_baking_reward ctxt ~attestation_power in @@ -3027,7 +3037,6 @@ let finalize_application ctxt block_data_contents ~round ~predecessor_hash may_start_new_cycle ctxt in let* ctxt = Amendment.may_start_new_voting_period ctxt in - let* ctxt, dal_attestation = Dal_apply.finalisation ctxt in let* ctxt = Sc_rollup.Inbox.finalize_inbox_level ctxt in let balance_updates = migration_balance_updates @ baking_receipts @ cycle_end_balance_updates diff --git a/src/proto_alpha/lib_protocol/dal_apply.ml b/src/proto_alpha/lib_protocol/dal_apply.ml index 7b65a16ae506..6fc372cbbba5 100644 --- a/src/proto_alpha/lib_protocol/dal_apply.ml +++ b/src/proto_alpha/lib_protocol/dal_apply.ml @@ -99,6 +99,23 @@ let apply_publish_commitment ctxt operation ~source = let* ctxt = Dal.Slot.register_slot_header ctxt slot_header ~source in return (ctxt, slot_header) +let record_dal_participation ctxt delegate tb_slot dal_attestation = + let open Lwt_result_syntax in + let*? () = Dal.assert_feature_enabled ctxt in + Dal.only_if_incentives_enabled + ctxt + ~default:(fun ctxt -> return ctxt) + (fun ctxt -> + let number_of_attested_slots = + match Slot.Map.find_opt tb_slot (Dal.Attestation.attestations ctxt) with + | None -> 0 + | Some delegate_attestation -> + Dal.Attestation.( + intersection dal_attestation delegate_attestation + |> number_of_attested_slots) + in + Delegate.record_dal_participation ctxt ~delegate ~number_of_attested_slots) + let finalisation ctxt = let open Lwt_result_syntax in Dal.only_if_feature_enabled diff --git a/src/proto_alpha/lib_protocol/dal_apply.mli b/src/proto_alpha/lib_protocol/dal_apply.mli index 628071b0e096..df823e2be0c2 100644 --- a/src/proto_alpha/lib_protocol/dal_apply.mli +++ b/src/proto_alpha/lib_protocol/dal_apply.mli @@ -68,6 +68,16 @@ val apply_publish_commitment : source:Contract.t -> (t * Dal.Slot.Header.t) tzresult +(** [record_dal_participation ctxt delegate tb_slot dal_attestation] records the + number of protocol-attested slots (given in [dal_attestation] attested by + [delegate] (with the initial TB slot [tb_slot]) in the current block. *) +val record_dal_participation : + t -> + Signature.Public_key_hash.t -> + Slot.t -> + Dal.Attestation.t -> + t tzresult Lwt.t + (** [finalisation ctxt] should be executed at block finalisation time. A set of slots attested at level [ctxt.current_level - lag] is returned encapsulated into the attestation data-structure. diff --git a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml index 454b8269e27e..a30c490cf634 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml @@ -108,6 +108,24 @@ let record_attesting_participation ctxt ~delegate ~participation contract {remaining_slots; missed_levels = 1})) +let record_dal_participation ctxt ~delegate ~number_of_attested_slots = + let open Lwt_result_syntax in + if Compare.Int.(number_of_attested_slots = 0) then return ctxt + else + let contract = Contract_repr.Implicit delegate in + let* result = Storage.Contract.Attested_dal_slots.find ctxt contract in + match result with + | Some already_attested_slots -> + Storage.Contract.Attested_dal_slots.update + ctxt + contract + Int32.(add already_attested_slots (of_int number_of_attested_slots)) + | None -> + Storage.Contract.Attested_dal_slots.init + ctxt + contract + (Int32.of_int number_of_attested_slots) + let record_baking_activity_and_pay_rewards_and_fees ctxt ~payload_producer ~block_producer ~baking_reward ~reward_bonus = let open Lwt_result_syntax in @@ -156,6 +174,16 @@ let check_and_reset_delegate_participation ctxt delegate = let*! ctxt = Storage.Contract.Missed_attestations.remove ctxt contract in return (ctxt, Compare.Int.(missed_attestations.remaining_slots >= 0)) +let get_and_reset_delegate_dal_participation ctxt delegate = + let open Lwt_result_syntax in + let contract = Contract_repr.Implicit delegate in + let* result = Storage.Contract.Attested_dal_slots.find ctxt contract in + match result with + | None -> return (ctxt, 0l) + | Some num_slots -> + let*! ctxt = Storage.Contract.Attested_dal_slots.remove ctxt contract in + return (ctxt, num_slots) + module For_RPC = struct type participation_info = { expected_cycle_activity : int; diff --git a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli index b3578e155093..3e9d4b99fcc2 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli @@ -41,7 +41,8 @@ val remove_total_dal_attested_slots : Raw_context.t -> Raw_context.t Lwt.t type level_participation = Participated | Didn't_participate -(** Record the participation of a delegate as a validator. *) +(** Update the participation of a delegate as a validator in the current cycle + with its participation at the current level. *) val record_attesting_participation : Raw_context.t -> delegate:Signature.Public_key_hash.t -> @@ -49,6 +50,15 @@ val record_attesting_participation : attesting_power:int -> Raw_context.t tzresult Lwt.t +(** Update the participation of a delegate as a DAL attester in the current + cycle with its participation (ie the number of DAL slots it attested) at the + current level. *) +val record_dal_participation : + Raw_context.t -> + delegate:Signature.Public_key_hash.t -> + number_of_attested_slots:int -> + Raw_context.t tzresult Lwt.t + (** Sets the payload and block producer as active. Pays the baking reward and the fees to the payload producer and the reward bonus to the payload producer (if the reward_bonus is not None).*) @@ -68,6 +78,13 @@ val check_and_reset_delegate_participation : Signature.Public_key_hash.t -> (Raw_context.t * bool) tzresult Lwt.t +(** Retrieve the number of DAL slots a delegate DAL-attested during the last + cycle, and then reset the participation for preparing the next cycle. *) +val get_and_reset_delegate_dal_participation : + Raw_context.t -> + Signature.Public_key_hash.t -> + (Raw_context.t * int32) tzresult Lwt.t + module For_RPC : sig (** Participation information. We denote by: - "static" information that does not change during the cycle diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index 189b7555da73..364cf96d761c 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -286,6 +286,14 @@ module Contract = struct end) (Missed_attestations_info) + module Attested_dal_slots = + Indexed_context.Make_map + (Registered) + (struct + let name = ["attested_dal_slots"] + end) + (Encoding.Int32) + module Manager = Indexed_context.Make_map (Registered) diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index fc2ec0259a4d..f5a4258a191d 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -140,6 +140,14 @@ module Contract : sig and type value = missed_attestations_info and type t := Raw_context.t + (** The number of protocol-attested DAL slots attested by a delegate during a + cycle. *) + module Attested_dal_slots : + Indexed_data_storage + with type key = Contract_repr.t + and type value = Int32.t + and type t := Raw_context.t + (** The manager of a contract *) module Manager : Indexed_data_storage_with_local_context -- GitLab From b53282db23da14d2bca90dd5f126cf706d4a0711 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 1 Oct 2024 15:57:27 +0200 Subject: [PATCH 09/12] Alpha/DAL: distribute rewards for attesting --- .../lib_client/operation_result.ml | 3 + .../lib_protocol/alpha_context.mli | 7 + .../lib_protocol/delegate_cycles.ml | 121 ++++++++++++++++-- .../delegate_missed_attestations_storage.ml | 14 ++ .../delegate_missed_attestations_storage.mli | 12 ++ .../lib_protocol/delegate_rewards.ml | 9 ++ .../lib_protocol/delegate_rewards.mli | 3 + src/proto_alpha/lib_protocol/receipt_repr.ml | 29 +++++ src/proto_alpha/lib_protocol/receipt_repr.mli | 4 + src/proto_alpha/lib_protocol/token.ml | 4 + src/proto_alpha/lib_protocol/token.mli | 3 + 11 files changed, 199 insertions(+), 10 deletions(-) diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index 3654b22538d6..5041035e76b4 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -421,6 +421,7 @@ let pp_balance_updates ppf balance_updates = | Attesting_rewards -> "attesting rewards" | Baking_rewards -> "baking rewards" | Baking_bonuses -> "baking bonuses" + | Dal_attesting_rewards -> "DAL attesting rewards" | Storage_fees -> "storage fees" | Double_signing_punishments -> "double signing punishments" | Lost_attesting_rewards (pkh, p, r) -> @@ -432,6 +433,8 @@ let pp_balance_updates ppf balance_updates = | true, true -> ",participation,revelation" in Format.asprintf "lost attesting rewards(%a%s)" pp_baker pkh reason + | Lost_dal_attesting_rewards pkh -> + Format.asprintf "lost DAL attesting rewards(%a)" pp_baker pkh | Liquidity_baking_subsidies -> "liquidity baking subsidies" | Burned -> "burned" | Commitments bpkh -> diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 0f03600f496a..cdb8ce18c2e4 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2157,9 +2157,11 @@ module Receipt : sig | Attesting_rewards : Tez.t balance | Baking_rewards : Tez.t balance | Baking_bonuses : Tez.t balance + | Dal_attesting_rewards : Tez.t balance | Storage_fees : Tez.t balance | Double_signing_punishments : Tez.t balance | Lost_attesting_rewards : public_key_hash * bool * bool -> Tez.t balance + | Lost_dal_attesting_rewards : public_key_hash -> Tez.t balance | Liquidity_baking_subsidies : Tez.t balance | Burned : Tez.t balance | Commitments : Blinded_public_key_hash.t -> Tez.t balance @@ -2364,6 +2366,8 @@ module Delegate : sig val attesting_reward_per_slot : t -> Tez.t tzresult + val dal_attesting_reward_per_shard : t -> Tez.t tzresult + val liquidity_baking_subsidy : t -> Tez.t tzresult val seed_nonce_revelation_tip : t -> Tez.t tzresult @@ -2375,6 +2379,7 @@ module Delegate : sig | Baking_reward_fixed_portion | Baking_reward_bonus_per_slot | Attesting_reward_per_slot + | Dal_attesting_reward_per_shard | Seed_nonce_revelation_tip | Vdf_revelation_tip @@ -5267,6 +5272,7 @@ module Token : sig | `Attesting_rewards | `Baking_rewards | `Baking_bonuses + | `Dal_attesting_rewards | `Minted | `Liquidity_baking_subsidies | `Sc_rollup_refutation_rewards @@ -5276,6 +5282,7 @@ module Token : sig [ `Storage_fees | `Double_signing_punishments | `Lost_attesting_rewards of public_key_hash * bool * bool + | `Lost_dal_attesting_rewards of public_key_hash | `Burned | `Sc_rollup_refutation_punishments | container ] diff --git a/src/proto_alpha/lib_protocol/delegate_cycles.ml b/src/proto_alpha/lib_protocol/delegate_cycles.ml index 658598d58ea0..22f997346a71 100644 --- a/src/proto_alpha/lib_protocol/delegate_cycles.ml +++ b/src/proto_alpha/lib_protocol/delegate_cycles.ml @@ -52,6 +52,82 @@ let update_activity ctxt last_cycle = let delegate_has_revealed_nonces delegate unrevelead_nonces_set = not (Signature.Public_key_hash.Set.mem delegate unrevelead_nonces_set) +let distribute_dal_attesting_rewards ctxt delegate + ~dal_attesting_reward_per_shard ~total_dal_attested_slots + ~total_active_stake_weight ~active_stake_weight active_stake = + let open Lwt_result_syntax in + let* ctxt, dal_attested_slots_by_delegate = + Delegate_missed_attestations_storage + .get_and_reset_delegate_dal_participation + ctxt + delegate + in + let minimal_dal_participation_ratio = + (Raw_context.constants ctxt).dal.minimal_participation_ratio + in + let sufficient_dal_participation = + let open Z in + geq + (of_int32 dal_attested_slots_by_delegate) + (div + (mul + (of_int32 total_dal_attested_slots) + minimal_dal_participation_ratio.num) + minimal_dal_participation_ratio.den) + in + let expected_dal_shards = + Delegate_missed_attestations_storage + .expected_dal_shards_for_given_active_stake + ctxt + ~total_active_stake_weight + ~active_stake_weight + in + let dal_rewards = + Tez_repr.mul_exn dal_attesting_reward_per_shard expected_dal_shards + in + if sufficient_dal_participation then + Shared_stake.pay_rewards + ctxt + ~active_stake + ~source:`Dal_attesting_rewards + ~delegate + dal_rewards + else + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7606 + Handle the case when the delegate had no DAL slot during the + cycle. Currently the probability for this to happen is very low: + (1-f)^(number_of_shards * blocks_per_cycle), where f if the delegate's + stake fraction. For the smallest baker, f is around 6000 / 7 * 10^8. With + the Q parameters, that's 2.6e-21. *) + Token.transfer + ctxt + `Dal_attesting_rewards + (`Lost_dal_attesting_rewards delegate) + dal_rewards + +let maybe_distribute_dal_attesting_rewards ctxt delegate + ~dal_attesting_reward_per_shard ~total_dal_attested_slots + ~total_active_stake_weight ~active_stake_weight active_stake = + let open Lwt_result_syntax in + Raw_context.Dal.only_if_incentives_enabled + ctxt + ~default:(fun ctxt -> return (ctxt, [])) + (fun ctxt -> + let dal_attesting_reward_per_shard, total_dal_attested_slots = + match (dal_attesting_reward_per_shard, total_dal_attested_slots) with + | Some v1, Some v2 -> (v1, v2) + | _ -> (* unreachable *) (Tez_repr.zero, 0l) + in + distribute_dal_attesting_rewards + ctxt + delegate + ~dal_attesting_reward_per_shard + ~total_dal_attested_slots + ~total_active_stake_weight + ~active_stake_weight + active_stake) + +(* This includes DAL rewards. *) let distribute_attesting_rewards ctxt last_cycle unrevealed_nonces = let open Lwt_result_syntax in let*? attesting_reward_per_slot = @@ -70,6 +146,18 @@ let distribute_attesting_rewards ctxt last_cycle unrevealed_nonces = let total_active_stake_weight = Stake_repr.staking_weight total_active_stake in + let* dal_attesting_reward_per_shard, total_dal_attested_slots = + Raw_context.Dal.only_if_incentives_enabled + ctxt + ~default:(fun _ctxt -> return (None, None)) + (fun ctxt -> + let*? dal_attesting_reward_per_shard = + Delegate_rewards.dal_attesting_reward_per_shard ctxt + in + let+ total_opt = Storage.Dal.Total_attested_slots.find ctxt in + let total = match total_opt with None -> Some 0l | v -> v in + (Some dal_attesting_reward_per_shard, total)) + in let* delegates = Stake_storage.get_selected_distribution ctxt last_cycle in List.fold_left_es (fun (ctxt, balance_updates) (delegate, active_stake) -> @@ -91,28 +179,38 @@ let distribute_attesting_rewards ctxt last_cycle unrevealed_nonces = ~active_stake_weight in let rewards = Tez_repr.mul_exn attesting_reward_per_slot expected_slots in - if sufficient_participation && has_revealed_nonces then - (* Sufficient participation: we pay the rewards *) - let+ ctxt, payed_rewards_receipts = + let* ctxt, payed_rewards_receipts = + if sufficient_participation && has_revealed_nonces then + (* Sufficient participation: we pay the rewards *) Shared_stake.pay_rewards ctxt ~active_stake ~source:`Attesting_rewards ~delegate rewards - in - (ctxt, payed_rewards_receipts @ balance_updates) - else - (* Insufficient participation or unrevealed nonce: no rewards *) - let+ ctxt, payed_rewards_receipts = + else + (* Insufficient participation or unrevealed nonce: no rewards *) Token.transfer ctxt `Attesting_rewards (`Lost_attesting_rewards (delegate, not sufficient_participation, not has_revealed_nonces)) rewards - in - (ctxt, payed_rewards_receipts @ balance_updates)) + in + let* ctxt, payed_dal_rewards_receipts = + maybe_distribute_dal_attesting_rewards + ctxt + delegate + ~dal_attesting_reward_per_shard + ~total_dal_attested_slots + ~total_active_stake_weight + ~active_stake_weight + active_stake + in + return + ( ctxt, + payed_dal_rewards_receipts @ payed_rewards_receipts @ balance_updates + )) (ctxt, []) delegates @@ -123,6 +221,9 @@ let cycle_end ctxt last_cycle = let* ctxt, attesting_balance_updates = distribute_attesting_rewards ctxt last_cycle unrevealed_nonces in + let*! ctxt = + Delegate_missed_attestations_storage.remove_total_dal_attested_slots ctxt + in (* Applying slashing related to expiring denunciations *) let* ctxt, slashing_balance_updates = Delegate_slashed_deposits_storage.apply_and_clear_denunciations ctxt diff --git a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml index a30c490cf634..91f3604a7ea6 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml @@ -43,6 +43,20 @@ let expected_slots_for_given_active_stake ctxt ~total_active_stake_weight (Z.of_int number_of_attestations_per_cycle)) (Z.of_int64 total_active_stake_weight)) +let expected_dal_shards_for_given_active_stake ctxt ~total_active_stake_weight + ~active_stake_weight = + let blocks_per_cycle = + Int32.to_int (Constants_storage.blocks_per_cycle ctxt) + in + let number_of_shards = Constants_storage.dal_number_of_shards ctxt in + let number_of_shards_per_cycle = number_of_shards * blocks_per_cycle in + Z.to_int + (Z.div + (Z.mul + (Z.of_int64 active_stake_weight) + (Z.of_int number_of_shards_per_cycle)) + (Z.of_int64 total_active_stake_weight)) + let remove_total_dal_attested_slots ctxt = Storage.Dal.Total_attested_slots.remove ctxt diff --git a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli index 3e9d4b99fcc2..71cf2fa21ccc 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli @@ -30,12 +30,24 @@ This module is responsible for maintaining the {!Storage.Contract.Missed_attestations} table. *) +(** Computes the number of validator slots that a delegate is expected to be + allocated during a cycle. This number is proportional to its active stake + wrt to total active stake. *) val expected_slots_for_given_active_stake : Raw_context.t -> total_active_stake_weight:int64 -> active_stake_weight:int64 -> int +(** Computes the number of DAL shards that a delegate is expected to be + allocated during a cycle. This number is proportional to its active stake + wrt to total active stake. *) +val expected_dal_shards_for_given_active_stake : + Raw_context.t -> + total_active_stake_weight:int64 -> + active_stake_weight:int64 -> + int + (** Removes the [Storage.Dal.Total_attested_slots] value from the context. *) val remove_total_dal_attested_slots : Raw_context.t -> Raw_context.t Lwt.t diff --git a/src/proto_alpha/lib_protocol/delegate_rewards.ml b/src/proto_alpha/lib_protocol/delegate_rewards.ml index 67b19ee0e28a..a16ea09a6fef 100644 --- a/src/proto_alpha/lib_protocol/delegate_rewards.ml +++ b/src/proto_alpha/lib_protocol/delegate_rewards.ml @@ -75,6 +75,7 @@ module M = struct | Baking_reward_fixed_portion | Baking_reward_bonus_per_slot | Attesting_reward_per_slot + | Dal_attesting_reward_per_shard | Seed_nonce_revelation_tip | Vdf_revelation_tip @@ -89,6 +90,7 @@ module M = struct | Baking_reward_bonus_per_slot -> issuance_weights.baking_reward_bonus_weight | Attesting_reward_per_slot -> issuance_weights.attesting_reward_weight + | Dal_attesting_reward_per_shard -> issuance_weights.dal_rewards_weight | Seed_nonce_revelation_tip -> (* Seed nonce revelation rewards are given every [blocks_per_commitment](=240)th block *) let blocks_per_commitment = Int32.to_int csts.blocks_per_commitment in @@ -113,6 +115,10 @@ module M = struct else Tez_repr.div_exn rewards bonus_committee_size | Attesting_reward_per_slot -> Tez_repr.div_exn rewards csts.consensus_committee_size + | Dal_attesting_reward_per_shard -> + Tez_repr.div_exn + rewards + csts.dal.cryptobox_parameters.number_of_shards | _ -> rewards in Tez_repr.mul_q ~rounding:`Down base_rewards coeff @@ -145,6 +151,9 @@ let baking_reward_bonus_per_slot ctxt = let attesting_reward_per_slot ctxt = reward_from_context ~ctxt ~reward_kind:Attesting_reward_per_slot +let dal_attesting_reward_per_shard ctxt = + reward_from_context ~ctxt ~reward_kind:Dal_attesting_reward_per_shard + let liquidity_baking_subsidy ctxt = let constants = Raw_context.constants ctxt in liquidity_baking_subsidy_from_constants constants diff --git a/src/proto_alpha/lib_protocol/delegate_rewards.mli b/src/proto_alpha/lib_protocol/delegate_rewards.mli index 309143c31bba..0aa8300da781 100644 --- a/src/proto_alpha/lib_protocol/delegate_rewards.mli +++ b/src/proto_alpha/lib_protocol/delegate_rewards.mli @@ -31,6 +31,8 @@ val baking_reward_bonus_per_slot : Raw_context.t -> Tez_repr.t tzresult val attesting_reward_per_slot : Raw_context.t -> Tez_repr.t tzresult +val dal_attesting_reward_per_shard : Raw_context.t -> Tez_repr.t tzresult + val liquidity_baking_subsidy : Raw_context.t -> Tez_repr.t tzresult val seed_nonce_revelation_tip : Raw_context.t -> Tez_repr.t tzresult @@ -42,6 +44,7 @@ module For_RPC : sig | Baking_reward_fixed_portion | Baking_reward_bonus_per_slot | Attesting_reward_per_slot + | Dal_attesting_reward_per_shard | Seed_nonce_revelation_tip | Vdf_revelation_tip diff --git a/src/proto_alpha/lib_protocol/receipt_repr.ml b/src/proto_alpha/lib_protocol/receipt_repr.ml index aa38d65ba1ad..93fa0f50cb40 100644 --- a/src/proto_alpha/lib_protocol/receipt_repr.ml +++ b/src/proto_alpha/lib_protocol/receipt_repr.ml @@ -80,11 +80,15 @@ type 'token balance = | Attesting_rewards : Tez_repr.t balance | Baking_rewards : Tez_repr.t balance | Baking_bonuses : Tez_repr.t balance + | Dal_attesting_rewards : Tez_repr.t balance | Storage_fees : Tez_repr.t balance | Double_signing_punishments : Tez_repr.t balance | Lost_attesting_rewards : Signature.Public_key_hash.t * bool * bool -> Tez_repr.t balance + | Lost_dal_attesting_rewards : + Signature.Public_key_hash.t + -> Tez_repr.t balance | Liquidity_baking_subsidies : Tez_repr.t balance | Burned : Tez_repr.t balance | Commitments : Blinded_public_key_hash.t -> Tez_repr.t balance @@ -113,9 +117,11 @@ let token_of_balance : type token. token balance -> token Token.t = function | Attesting_rewards -> Token.Tez | Baking_rewards -> Token.Tez | Baking_bonuses -> Token.Tez + | Dal_attesting_rewards -> Token.Tez | Storage_fees -> Token.Tez | Double_signing_punishments -> Token.Tez | Lost_attesting_rewards _ -> Token.Tez + | Lost_dal_attesting_rewards _ -> Token.Tez | Liquidity_baking_subsidies -> Token.Tez | Burned -> Token.Tez | Commitments _ -> Token.Tez @@ -147,6 +153,8 @@ let compare_balance : else let c = Compare.Bool.compare pa pb in if is_not_zero c then c else Compare.Bool.compare ra rb + | Lost_dal_attesting_rewards pkha, Lost_dal_attesting_rewards pkhb -> + Signature.Public_key_hash.compare pkha pkhb | Commitments bpkha, Commitments bpkhb -> Blinded_public_key_hash.compare bpkha bpkhb | Frozen_bonds (ca, ra), Frozen_bonds (cb, rb) -> @@ -183,6 +191,8 @@ let compare_balance : | Sc_rollup_refutation_rewards -> 20 | Staking_delegator_numerator _ -> 21 | Staking_delegate_denominator _ -> 22 + | Dal_attesting_rewards -> 23 + | Lost_dal_attesting_rewards _ -> 24 (* don't forget to add parameterized cases in the first part of the function *) in Compare.Int.compare (index ba) (index bb) @@ -461,6 +471,25 @@ let balance_and_update_encoding = | Staking_delegate_denominator {delegate} -> Some ((), (), delegate) | _ -> None) (fun ((), (), delegate) -> Staking_delegate_denominator {delegate}); + tez_case + (Tag 29) + ~title:"DAL_attesting_rewards" + (obj2 + (req "kind" (constant "minted")) + (req "category" (constant "DAL attesting rewards"))) + (function Dal_attesting_rewards -> Some ((), ()) | _ -> None) + (fun ((), ()) -> Dal_attesting_rewards); + tez_case + (Tag 30) + ~title:"Lost_DAL_attesting_rewards" + (obj3 + (req "kind" (constant "burned")) + (req "category" (constant "lost DAL attesting rewards")) + (req "delegate" Signature.Public_key_hash.encoding)) + (function + | Lost_dal_attesting_rewards delegate -> Some ((), (), delegate) + | _ -> None) + (fun ((), (), delegate) -> Lost_dal_attesting_rewards delegate); ] type update_origin = diff --git a/src/proto_alpha/lib_protocol/receipt_repr.mli b/src/proto_alpha/lib_protocol/receipt_repr.mli index 893729602fdc..34bb154e0ab3 100644 --- a/src/proto_alpha/lib_protocol/receipt_repr.mli +++ b/src/proto_alpha/lib_protocol/receipt_repr.mli @@ -53,11 +53,15 @@ type 'token balance = | Attesting_rewards : Tez_repr.t balance | Baking_rewards : Tez_repr.t balance | Baking_bonuses : Tez_repr.t balance + | Dal_attesting_rewards : Tez_repr.t balance | Storage_fees : Tez_repr.t balance | Double_signing_punishments : Tez_repr.t balance | Lost_attesting_rewards : Signature.Public_key_hash.t * bool * bool -> Tez_repr.t balance + | Lost_dal_attesting_rewards : + Signature.Public_key_hash.t + -> Tez_repr.t balance | Liquidity_baking_subsidies : Tez_repr.t balance | Burned : Tez_repr.t balance | Commitments : Blinded_public_key_hash.t -> Tez_repr.t balance diff --git a/src/proto_alpha/lib_protocol/token.ml b/src/proto_alpha/lib_protocol/token.ml index 88eb1f000085..2c31121bed8a 100644 --- a/src/proto_alpha/lib_protocol/token.ml +++ b/src/proto_alpha/lib_protocol/token.ml @@ -39,6 +39,7 @@ type infinite_source = | `Attesting_rewards | `Baking_rewards | `Baking_bonuses + | `Dal_attesting_rewards | `Minted | `Liquidity_baking_subsidies | `Sc_rollup_refutation_rewards ] @@ -49,6 +50,7 @@ type infinite_sink = [ `Storage_fees | `Double_signing_punishments | `Lost_attesting_rewards of Signature.Public_key_hash.t * bool * bool + | `Lost_dal_attesting_rewards of Signature.Public_key_hash.t | `Sc_rollup_refutation_punishments | `Burned ] @@ -73,6 +75,7 @@ let credit ctxt receiver amount origin = | `Storage_fees -> Storage_fees | `Double_signing_punishments -> Double_signing_punishments | `Lost_attesting_rewards (d, p, r) -> Lost_attesting_rewards (d, p, r) + | `Lost_dal_attesting_rewards d -> Lost_dal_attesting_rewards d | `Sc_rollup_refutation_punishments -> Sc_rollup_refutation_punishments | `Burned -> Burned @@ -149,6 +152,7 @@ let spend ctxt giver amount origin = | `Attesting_rewards -> Attesting_rewards | `Baking_rewards -> Baking_rewards | `Baking_bonuses -> Baking_bonuses + | `Dal_attesting_rewards -> Dal_attesting_rewards | `Sc_rollup_refutation_rewards -> Sc_rollup_refutation_rewards in let* old_total_supply = Storage.Contract.Total_supply.get ctxt in diff --git a/src/proto_alpha/lib_protocol/token.mli b/src/proto_alpha/lib_protocol/token.mli index 42e0097e01e8..a4b4a653257f 100644 --- a/src/proto_alpha/lib_protocol/token.mli +++ b/src/proto_alpha/lib_protocol/token.mli @@ -83,6 +83,7 @@ type infinite_source = | `Attesting_rewards (** Consensus attesting rewards *) | `Baking_rewards (** Consensus baking fixed rewards *) | `Baking_bonuses (** Consensus baking variable bonus *) + | `Dal_attesting_rewards (** DAL attesting rewards *) | `Minted (** Generic source for test purpose *) | `Liquidity_baking_subsidies (** Subsidy for liquidity-baking contract *) | `Sc_rollup_refutation_rewards @@ -97,6 +98,8 @@ type infinite_sink = | `Double_signing_punishments (** Consensus slashing *) | `Lost_attesting_rewards of Signature.Public_key_hash.t * bool * bool (** Consensus rewards not distributed because the participation of the delegate was too low. *) + | `Lost_dal_attesting_rewards of Signature.Public_key_hash.t + (** DAL rewards not distributed because the participation of the delegate was too low. *) | `Sc_rollup_refutation_punishments (** Smart rollups refutation slashing *) | `Burned (** Generic sink mainly for test purpose *) ] -- GitLab From 3bc10219b3ed69cfc9f1e4d6631dbbf76c179bbc Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 1 Oct 2024 15:57:39 +0200 Subject: [PATCH 10/12] Alpha/DAL: add DAL rewards to bootstrap_storage.ml --- src/proto_alpha/lib_protocol/bootstrap_storage.ml | 1 + src/proto_alpha/lib_protocol/storage.ml | 14 ++++++++++---- src/proto_alpha/lib_protocol/storage.mli | 1 + 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/proto_alpha/lib_protocol/bootstrap_storage.ml b/src/proto_alpha/lib_protocol/bootstrap_storage.ml index e445b02b6d58..c5ce006ac3a4 100644 --- a/src/proto_alpha/lib_protocol/bootstrap_storage.ml +++ b/src/proto_alpha/lib_protocol/bootstrap_storage.ml @@ -231,6 +231,7 @@ let init ctxt ~typecheck_smart_contract ~typecheck_smart_rollup constants.issuance_weights.base_total_issued_per_minute; baking_reward_bonus_per_slot = Tez_repr.zero; attesting_reward_per_slot = Tez_repr.zero; + dal_attesting_reward_per_shard = Tez_repr.zero; }) in (ctxt, balance_updates) diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index 364cf96d761c..6a759c5c41fe 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -1572,6 +1572,7 @@ module Ramp_up = struct baking_reward_fixed_portion : Tez_repr.t; baking_reward_bonus_per_slot : Tez_repr.t; attesting_reward_per_slot : Tez_repr.t; + dal_attesting_reward_per_shard : Tez_repr.t; } module Rewards = @@ -1591,22 +1592,27 @@ module Ramp_up = struct baking_reward_fixed_portion; baking_reward_bonus_per_slot; attesting_reward_per_slot; + dal_attesting_reward_per_shard; } -> ( baking_reward_fixed_portion, baking_reward_bonus_per_slot, - attesting_reward_per_slot )) + attesting_reward_per_slot, + dal_attesting_reward_per_shard )) (fun ( baking_reward_fixed_portion, baking_reward_bonus_per_slot, - attesting_reward_per_slot ) -> + attesting_reward_per_slot, + dal_attesting_reward_per_shard ) -> { baking_reward_fixed_portion; baking_reward_bonus_per_slot; attesting_reward_per_slot; + dal_attesting_reward_per_shard; }) - (obj3 + (obj4 (req "baking_reward_fixed_portion" Tez_repr.encoding) (req "baking_reward_bonus_per_slot" Tez_repr.encoding) - (req "attesting_reward_per_slot" Tez_repr.encoding))) + (req "attesting_reward_per_slot" Tez_repr.encoding) + (req "dal_attesting_reward_per_shard" Tez_repr.encoding))) end) end diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index f5a4258a191d..948cb6112c57 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -696,6 +696,7 @@ module Ramp_up : sig baking_reward_fixed_portion : Tez_repr.t; baking_reward_bonus_per_slot : Tez_repr.t; attesting_reward_per_slot : Tez_repr.t; + dal_attesting_reward_per_shard : Tez_repr.t; } module Rewards : -- GitLab From 9b7533157cc32ae32c4cc4059a9e38e6f123aa72 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 7 Nov 2024 11:31:19 +0100 Subject: [PATCH 11/12] Kaitai: update struct files --- .../files/alpha__receipt__balance_updates.ksy | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/client-libs/kaitai-struct-files/files/alpha__receipt__balance_updates.ksy b/client-libs/kaitai-struct-files/files/alpha__receipt__balance_updates.ksy index 10c98896160c..c48905de758e 100644 --- a/client-libs/kaitai-struct-files/files/alpha__receipt__balance_updates.ksy +++ b/client-libs/kaitai-struct-files/files/alpha__receipt__balance_updates.ksy @@ -117,6 +117,12 @@ types: - id: staking_delegate_denominator type: staking_delegate_denominator if: (alpha__operation_metadata__alpha__balance_and_update_tag == alpha__operation_metadata__alpha__balance_and_update_tag::staking_delegate_denominator) + - id: dal_attesting_rewards + type: alpha__operation_metadata__alpha__tez_balance_update + if: (alpha__operation_metadata__alpha__balance_and_update_tag == alpha__operation_metadata__alpha__balance_and_update_tag::dal_attesting_rewards) + - id: lost_dal_attesting_rewards + type: lost_dal_attesting_rewards + if: (alpha__operation_metadata__alpha__balance_and_update_tag == alpha__operation_metadata__alpha__balance_and_update_tag::lost_dal_attesting_rewards) alpha__operation_metadata__alpha__balance_updates: seq: - id: alpha__operation_metadata__alpha__balance_updates_entries @@ -213,6 +219,13 @@ types: enum: bool - id: alpha__operation_metadata__alpha__tez_balance_update type: alpha__operation_metadata__alpha__tez_balance_update + lost_dal_attesting_rewards: + seq: + - id: delegate + type: public_key_hash + doc: A Ed25519, Secp256k1, P256, or BLS public key hash + - id: alpha__operation_metadata__alpha__tez_balance_update + type: alpha__operation_metadata__alpha__tez_balance_update originated: seq: - id: contract_hash @@ -310,6 +323,8 @@ enums: 26: unstaked_deposits 27: staking_delegator_numerator 28: staking_delegate_denominator + 29: dal_attesting_rewards + 30: lost_dal_attesting_rewards alpha__operation_metadata__alpha__update_origin_tag: 0: block_application 1: protocol_migration -- GitLab From 7d46facd751490a0929a2ccb3dd2e2a50cc8d75b Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Wed, 13 Nov 2024 12:27:29 +0100 Subject: [PATCH 12/12] DAL/Tests: add test for DAL rewards --- tezt/tests/dal.ml | 220 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 182 insertions(+), 38 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index cce394d59540..f15496f5f091 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -235,6 +235,18 @@ let make_string_parameter name = function | None -> [] | Some value -> [(name, `String value)] +let make_q_parameter name = function + | None -> [] + | Some q -> + [ + ( name, + `O + [ + ("numerator", `String (Q.num q |> Z.to_int |> string_of_int)); + ("denominator", `String (Q.den q |> Z.to_int |> string_of_int)); + ] ); + ] + let test ~__FILE__ ?(regression = false) ?(tags = []) ?uses ?(supports = Protocol.From_protocol 19) title f = let tags = Tag.tezos2 :: "dal" :: tags in @@ -247,6 +259,9 @@ let test ~__FILE__ ?(regression = false) ?(tags = []) ?uses let dal_enable_param dal_enable = make_bool_parameter ["dal_parametric"; "feature_enable"] dal_enable +let incentives_enable_param enable = + make_bool_parameter ["dal_parametric"; "incentives_enable"] enable + let sc_rollup_activation_dal_params dal_enable = if Option.value dal_enable ~default:false then [ @@ -440,10 +455,11 @@ let with_layer1 ?custom_constants ?additional_bootstrap_accounts ?consensus_committee_size ?minimal_block_delay ?delay_increment_per_round ?attestation_lag ?slot_size ?number_of_slots ?page_size ?attestation_threshold ?number_of_shards ?redundancy_factor - ?commitment_period ?challenge_window ?dal_enable ?event_sections_levels - ?node_arguments ?activation_timestamp ?dal_bootstrap_peers - ?(parameters = []) ?(prover = true) ?smart_rollup_timeout_period_in_blocks - ?l1_history_mode f ~protocol = + ?commitment_period ?challenge_window ?dal_enable ?incentives_enable + ?dal_rewards_weight ?event_sections_levels ?node_arguments + ?activation_timestamp ?dal_bootstrap_peers ?(parameters = []) + ?(prover = true) ?smart_rollup_timeout_period_in_blocks ?l1_history_mode f + ~protocol = let parameter_overrides = make_int_parameter ["dal_parametric"; "attestation_lag"] attestation_lag @ make_int_parameter ["dal_parametric"; "number_of_shards"] number_of_shards @@ -459,6 +475,9 @@ let with_layer1 ?custom_constants ?additional_bootstrap_accounts @ make_int_parameter ["dal_parametric"; "attestation_threshold"] attestation_threshold + @ make_int_parameter + ["issuance_weights"; "dal_rewards_weight"] + dal_rewards_weight @ make_int_parameter ["smart_rollup_commitment_period_in_blocks"] commitment_period @@ -468,6 +487,7 @@ let with_layer1 ?custom_constants ?additional_bootstrap_accounts (* this will produce the empty list if dal_enable is not passed to the function invocation, hence the value from the protocol constants will be used. *) @ dal_enable_param dal_enable + @ incentives_enable_param incentives_enable @ sc_rollup_activation_dal_params dal_enable @ [(["smart_rollup_arith_pvm_enable"], `Bool true)] @ make_int_parameter ["consensus_committee_size"] consensus_committee_size @@ -577,9 +597,10 @@ let with_dal_node ?peers ?attester_profiles ?producer_profiles let scenario_with_layer1_node ?regression ?(tags = []) ?additional_bootstrap_accounts ?attestation_lag ?number_of_shards ?number_of_slots ?custom_constants ?commitment_period ?challenge_window - ?(dal_enable = true) ?event_sections_levels ?node_arguments - ?activation_timestamp ?consensus_committee_size ?minimal_block_delay - ?delay_increment_per_round variant scenario = + ?(dal_enable = true) ?incentives_enable ?dal_rewards_weight + ?event_sections_levels ?node_arguments ?activation_timestamp + ?consensus_committee_size ?minimal_block_delay ?delay_increment_per_round + variant scenario = let description = "Testing DAL L1 integration" in let tags = if List.mem team tags then tags else team :: tags in let tags = @@ -601,6 +622,8 @@ let scenario_with_layer1_node ?regression ?(tags = []) ?attestation_lag ?number_of_shards ?number_of_slots + ?incentives_enable + ?dal_rewards_weight ?commitment_period ?challenge_window ?event_sections_levels @@ -615,8 +638,9 @@ let scenario_with_layer1_and_dal_nodes ?regression ?(tags = []) ?(uses = fun _ -> []) ?custom_constants ?minimal_block_delay ?delay_increment_per_round ?redundancy_factor ?slot_size ?number_of_shards ?number_of_slots ?attestation_lag ?attestation_threshold ?commitment_period - ?challenge_window ?(dal_enable = true) ?activation_timestamp - ?bootstrap_profile ?producer_profiles ?history_mode ?prover ?l1_history_mode + ?challenge_window ?(dal_enable = true) ?incentives_enable + ?dal_rewards_weight ?activation_timestamp ?bootstrap_profile + ?producer_profiles ?history_mode ?prover ?l1_history_mode ?skip_list_storage_backend variant scenario = let description = "Testing DAL node" in let tags = if List.mem team tags then tags else team :: tags in @@ -647,6 +671,8 @@ let scenario_with_layer1_and_dal_nodes ?regression ?(tags = []) ?number_of_shards ?attestation_lag ?attestation_threshold + ?incentives_enable + ?dal_rewards_weight ?commitment_period ?challenge_window ?activation_timestamp @@ -667,11 +693,12 @@ let scenario_with_layer1_and_dal_nodes ?regression ?(tags = []) let scenario_with_all_nodes ?custom_constants ?node_arguments ?consensus_committee_size ?slot_size ?page_size ?number_of_shards ?redundancy_factor ?attestation_lag ?(tags = []) ?(uses = fun _ -> []) - ?(pvm_name = "arith") ?(dal_enable = true) ?commitment_period - ?challenge_window ?minimal_block_delay ?delay_increment_per_round - ?activation_timestamp ?bootstrap_profile ?producer_profiles - ?smart_rollup_timeout_period_in_blocks ?(regression = true) ?prover - ?attestation_threshold ?l1_history_mode variant scenario = + ?(pvm_name = "arith") ?(dal_enable = true) ?incentives_enable + ?dal_rewards_weight ?commitment_period ?challenge_window + ?minimal_block_delay ?delay_increment_per_round ?activation_timestamp + ?bootstrap_profile ?producer_profiles ?smart_rollup_timeout_period_in_blocks + ?(regression = true) ?prover ?attestation_threshold ?l1_history_mode variant + scenario = let description = "Testing DAL rollup and node with L1" in let tags = if List.mem team tags then tags else team :: tags in let tags = @@ -702,6 +729,8 @@ let scenario_with_all_nodes ?custom_constants ?node_arguments ?number_of_shards ?redundancy_factor ?attestation_lag + ?incentives_enable + ?dal_rewards_weight ?commitment_period ?challenge_window ?minimal_block_delay @@ -7936,35 +7965,43 @@ let rollup_batches_and_publishes_optimal_dal_slots _protocol parameters dal_node check_packs published_slots annotated_messages ; unit +(* Produce a slot, store it in the DAL node, and then (try to) publish the same + commitment for each level between [from] and [into]. *) let slot_producer ~slot_index ~slot_size ~from ~into dal_node l1_node l1_client = - let loop ~from ~into ~task = - Seq.ints from - |> Seq.take (into - from + 1) - |> Seq.map task |> List.of_seq |> Lwt.join - in (* This is the account used to sign injected slot headers on L1. *) let source = Constant.bootstrap2 in - let task current_level = - let* level = Node.wait_for_level l1_node current_level in - (* We expected to advance level by level, otherwise, the test should fail. *) - Check.( - (current_level = level) int ~error_msg:"Expected level is %L (got %R)") ; - let (publish_level as payload) = level in - Log.info - "[slot_producer] publish slot %d for level %d with payload %d at level %d" - slot_index - publish_level - payload - level ; - let* _ = - Helpers.publish_and_store_slot l1_client dal_node source ~index:slot_index - @@ Helpers.make_slot ~slot_size (sf " %d " payload) - in - let* () = bake_for l1_client in - unit + let slot = Helpers.make_slot ~slot_size "some data" in + let* commitment, proof = Helpers.store_slot ~slot_index dal_node slot in + (* Keep track of the counter to avoid an additional RPC call. *) + let counter = ref 1 in + let rec loop current_level = + if current_level > into then unit + else + let* level = Node.wait_for_level l1_node current_level in + (* We expected to advance level by level. *) + if current_level < level then + Log.info + "Missed some levels (expected level is %d, got %d)" + current_level + level ; + Log.info + "[slot_producer] publish at slot index %d at level %d" + slot_index + level ; + let* _op_hash = + publish_commitment + ~counter:!counter + ~source + ~index:slot_index + ~commitment + ~proof + l1_client + in + incr counter ; + loop (level + 1) in - let* () = loop ~from ~into ~task in + let* () = loop from in Log.info "[slot_producer] will terminate" ; unit @@ -8219,6 +8256,102 @@ let test_new_attester_attests _protocol dal_parameters _cryptobox node client expected %R") ; unit +(* We have one DAL attester node, and two baker daemons (for a two-sized + partition of the attesters). The first baker daemon runs as expected, the + other one runs without a DAL node for a small part of a cycle (so that its + participation is smaller than the required ratio, but non-zero). We check + that the attesters receive or not the DAL rewards depending on which daemon + they run on. *) +let test_attesters_receive_dal_rewards protocol dal_parameters _cryptobox node + client dal_node = + let* proto_params = + Node.RPC.call node @@ RPC.get_chain_block_context_constants () + in + let blocks_per_cycle = JSON.(proto_params |-> "blocks_per_cycle" |> as_int) in + assert (blocks_per_cycle >= dal_parameters.Dal.Parameters.attestation_lag) ; + + let all_delegates = + Account.Bootstrap.keys |> Array.to_list + |> List.map (fun key -> key.Account.alias) + in + let delegate_a = List.hd all_delegates in + let rest_delegates = List.tl all_delegates in + + let* first_level = Node.get_level node in + let middle_of_cycle_level = + first_level + blocks_per_cycle + (blocks_per_cycle / 4) + in + let last_level = first_level + (2 * blocks_per_cycle) in + Log.info + "Bake from first_level = %d to last_level = %d" + first_level + last_level ; + let _promise = + slot_producer + ~slot_index:0 + ~slot_size:dal_parameters.cryptobox.slot_size + ~from:first_level + ~into:last_level + dal_node + node + client + in + let* baker_a = + Baker.init ~protocol ~dal_node ~delegates:[delegate_a] node client + in + let* client_b = Client.init ~endpoint:(Node node) () in + let* baker_b = + Baker.init ~protocol ~dal_node ~delegates:rest_delegates node client_b + in + let* _level = Node.wait_for_level node middle_of_cycle_level in + let* () = Baker.terminate baker_a in + Log.info "Restart one of the bakers without a DAL node." ; + let* baker_a = Baker.init ~protocol ~delegates:[delegate_a] node client in + let* _level = Node.wait_for_level node last_level in + let* () = Baker.terminate baker_a in + let* () = Baker.terminate baker_b in + (* the last block in the cycle *) + let block = string_of_int (last_level - 1) in + let* level = + Node.RPC.call node @@ RPC.get_chain_block_helper_current_level ~block () + in + assert (level.cycle_position = blocks_per_cycle - 1) ; + let* metadata = + Node.RPC.call node @@ RPC.get_chain_block_metadata_raw ~block () + in + let balance_updates = JSON.(metadata |-> "balance_updates" |> as_list) in + let dal_rewards = + List.filter + (fun json -> + JSON.(json |-> "kind" |> as_string) |> String.equal "minted" + && JSON.(json |-> "category" |> as_string) + |> String.equal "DAL attesting rewards") + balance_updates + in + Check.(List.length dal_rewards > 1) + ~__LOC__ + Check.int + ~error_msg:"Expected %R minted DAL-related balance updates, got %L" ; + let lost_dal_rewards = + List.filter + (fun json -> + JSON.(json |-> "kind" |> as_string) |> String.equal "burned" + && JSON.(json |-> "category" |> as_string) + |> String.equal "lost DAL attesting rewards") + balance_updates + in + Check.(List.length lost_dal_rewards = 1) + ~__LOC__ + Check.int + ~error_msg:"Expected %R lost DAL reward, got %L" ; + let json = List.hd lost_dal_rewards in + let losing_delegate = JSON.(json |-> "delegate" |> as_string) in + Check.(Account.Bootstrap.keys.(0).public_key_hash = losing_delegate) + ~__LOC__ + Check.string + ~error_msg:"Unexpected delegate to lose DAL rewards (got %R expected %L)" ; + unit + let register ~protocols = (* Tests with Layer1 node only *) scenario_with_layer1_node @@ -8472,6 +8605,17 @@ let register ~protocols = "new attester attests" test_new_attester_attests protocols ; + scenario_with_layer1_and_dal_nodes + ~uses:(fun protocol -> [Protocol.baker protocol]) + ~number_of_slots:1 + ~producer_profiles:[0] + ~activation_timestamp:Now + ~minimal_block_delay:"3" + ~incentives_enable:true + ~dal_rewards_weight:5120 + "attesters receive DAL rewards" + test_attesters_receive_dal_rewards + (List.filter (fun p -> Protocol.number p >= 022) protocols) ; scenario_with_layer1_and_dal_nodes ~uses:(fun protocol -> [Protocol.baker protocol]) ~tags:["restart"] -- GitLab