From 30f498f6a62abee90d168e8aea5904446be361aa Mon Sep 17 00:00:00 2001 From: Olha Nemkovych Date: Mon, 1 Dec 2025 15:10:56 +0100 Subject: [PATCH 01/10] Proto: SWRR cycle-end distribution --- src/proto_alpha/lib_protocol/constants_storage.ml | 3 +++ src/proto_alpha/lib_protocol/constants_storage.mli | 3 +++ src/proto_alpha/lib_protocol/delegate_sampler.ml | 14 ++++++++++---- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/proto_alpha/lib_protocol/constants_storage.ml b/src/proto_alpha/lib_protocol/constants_storage.ml index 7ecc17586ab3..40cbbd7102ee 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.ml +++ b/src/proto_alpha/lib_protocol/constants_storage.ml @@ -290,6 +290,9 @@ let round_durations ctxt = Raw_context.round_durations ctxt let native_contracts_enable c = (Raw_context.constants c).native_contracts_enable +let swrr_new_baker_lottery_enable c = + (Raw_context.constants c).swrr_new_baker_lottery_enable + let all ctxt = Constants_repr.all_of_parametric (parametric ctxt) (* Derived pseudo-constants *) diff --git a/src/proto_alpha/lib_protocol/constants_storage.mli b/src/proto_alpha/lib_protocol/constants_storage.mli index 35bd388b6406..26d76774a51c 100644 --- a/src/proto_alpha/lib_protocol/constants_storage.mli +++ b/src/proto_alpha/lib_protocol/constants_storage.mli @@ -174,6 +174,9 @@ val round_durations : Raw_context.t -> Round_repr.Durations.t (** Native contracts feature flag *) val native_contracts_enable : Raw_context.t -> bool +(** SWRR new baker lottery feature flag *) +val swrr_new_baker_lottery_enable : Raw_context.t -> bool + (** Builds a representation of all constants (fixed and parametric) from the context. *) val all : Raw_context.t -> Constants_repr.t diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.ml b/src/proto_alpha/lib_protocol/delegate_sampler.ml index 89551ba3675e..9ad3d77ade6b 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.ml +++ b/src/proto_alpha/lib_protocol/delegate_sampler.ml @@ -301,10 +301,16 @@ let select_distribution_for_cycle ctxt cycle = stakes in let total_stake = Stake_repr.staking_weight total_stake in - let state = Sampler.create stakes_pk in - let* ctxt = Delegate_sampler_state.init ctxt cycle state in - (* pre-allocate the sampler *) - let*? ctxt = Raw_context.init_sampler_for_cycle ctxt cycle seed state in + let* ctxt = + if Constants_storage.swrr_new_baker_lottery_enable ctxt then + Swrr_sampler.select_bakers_at_cycle_end ctxt ~target_cycle:cycle + else + let state = Sampler.create stakes_pk in + let* ctxt = Delegate_sampler_state.init ctxt cycle state in + (* pre-allocate the sampler *) + let*? ctxt = Raw_context.init_sampler_for_cycle ctxt cycle seed state in + return ctxt + in (* pre-allocate the raw stake distribution info *) let*? ctxt = Raw_context.init_stake_info_for_cycle ctxt cycle ~total_stake stakes_pk -- GitLab From 2f0688b673116c6e9e4873fc8685f53bed652c15 Mon Sep 17 00:00:00 2001 From: Olha Nemkovych Date: Mon, 1 Dec 2025 18:12:40 +0100 Subject: [PATCH 02/10] Proto: SWRR cycle credit reset --- src/proto_alpha/lib_protocol/delegate_cycles.ml | 8 ++++++++ src/proto_alpha/lib_protocol/swrr_sampler.ml | 14 ++++++++++++++ src/proto_alpha/lib_protocol/swrr_sampler.mli | 5 +++++ 3 files changed, 27 insertions(+) diff --git a/src/proto_alpha/lib_protocol/delegate_cycles.ml b/src/proto_alpha/lib_protocol/delegate_cycles.ml index a666a47b9b40..2d31093dd88f 100644 --- a/src/proto_alpha/lib_protocol/delegate_cycles.ml +++ b/src/proto_alpha/lib_protocol/delegate_cycles.ml @@ -240,6 +240,14 @@ let cycle_end ctxt last_cycle = in (* Deactivating delegates which didn't participate to consensus for too long *) let* ctxt, deactivated_delegates = update_activity ctxt last_cycle in + (* Reset SWRR credits for delegates that have been deactivated *) + let* ctxt = + if Constants_storage.swrr_new_baker_lottery_enable ctxt then + Swrr_sampler.reset_credit_for_deactivated_delegates + ctxt + deactivated_delegates + else return ctxt + in (* Computing future staking rights *) let* ctxt = Delegate_sampler.select_new_distribution_at_cycle_end ctxt ~new_cycle diff --git a/src/proto_alpha/lib_protocol/swrr_sampler.ml b/src/proto_alpha/lib_protocol/swrr_sampler.ml index adddb2ebd199..3a5ed5ead38d 100644 --- a/src/proto_alpha/lib_protocol/swrr_sampler.ml +++ b/src/proto_alpha/lib_protocol/swrr_sampler.ml @@ -107,3 +107,17 @@ let get_baker ctxt level round = | Some pkh -> let* pk = Delegate_consensus_key.active_pubkey ctxt pkh in return (ctxt, pk) + +let reset_credit_for_deactivated_delegates ctxt deactivated_delegates = + let open Lwt_result_syntax in + let*! ctxt = + List.fold_left_s + (fun ctxt pkh -> + Storage.Contract.SWRR_credit.add + ctxt + (Contract_repr.Implicit pkh) + Z.zero) + ctxt + deactivated_delegates + in + return ctxt diff --git a/src/proto_alpha/lib_protocol/swrr_sampler.mli b/src/proto_alpha/lib_protocol/swrr_sampler.mli index 93284f82a74f..3c2e8d2d02b7 100644 --- a/src/proto_alpha/lib_protocol/swrr_sampler.mli +++ b/src/proto_alpha/lib_protocol/swrr_sampler.mli @@ -16,3 +16,8 @@ val get_baker : Level_repr.t -> Round_repr.round -> (Raw_context.t * Delegate_consensus_key.pk) tzresult Lwt.t + +val reset_credit_for_deactivated_delegates : + Raw_context.t -> + Signature.Public_key_hash.t list -> + Raw_context.t tzresult Lwt.t -- GitLab From 8ac339b21e2937548bea9b2352acfc6f17e164ca Mon Sep 17 00:00:00 2001 From: Olha Nemkovych Date: Tue, 9 Dec 2025 14:18:31 +0100 Subject: [PATCH 03/10] Proto: add swrr to baking_rights_owner --- .../lib_protocol/delegate_sampler.ml | 7 +++++- src/proto_alpha/lib_protocol/swrr_sampler.ml | 23 +++++++++++-------- src/proto_alpha/lib_protocol/swrr_sampler.mli | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.ml b/src/proto_alpha/lib_protocol/delegate_sampler.ml index 9ad3d77ade6b..9756707322ef 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.ml +++ b/src/proto_alpha/lib_protocol/delegate_sampler.ml @@ -174,7 +174,12 @@ let baking_rights_owner c (level : Level_repr.t) ~round = (* We use [Round.to_slot] to have a limited number of unique rounds (it should loop after some time) *) let*? slot = Round_repr.to_slot ~committee_size round in - let* ctxt, pk = Random.owner c level (Slot_repr.to_int slot) in + let* ctxt, pk = + let* baker_opt = Swrr_sampler.get_baker c level round in + match baker_opt with + | Some (ctxt, pk) -> return (ctxt, pk) + | None -> Random.owner c level (Slot_repr.to_int slot) + in return (ctxt, slot, pk) let load_sampler_for_cycle ctxt cycle = diff --git a/src/proto_alpha/lib_protocol/swrr_sampler.ml b/src/proto_alpha/lib_protocol/swrr_sampler.ml index 3a5ed5ead38d..b34b2fb9c2be 100644 --- a/src/proto_alpha/lib_protocol/swrr_sampler.ml +++ b/src/proto_alpha/lib_protocol/swrr_sampler.ml @@ -96,17 +96,20 @@ let get_baker ctxt level round = let pos = level.Level_repr.cycle_position in let*? round_int = Round_repr.to_int round in - let* selected_bakers = Storage.Stake.Selected_bakers.get ctxt cycle in - let len = List.length selected_bakers in - let idx = (Int32.to_int pos + (3 * round_int)) mod len in + let* selected_bakers = Storage.Stake.Selected_bakers.find ctxt cycle in + match selected_bakers with + | None -> return_none + | Some selected_bakers -> ( + let len = List.length selected_bakers in + let idx = (Int32.to_int pos + (3 * round_int)) mod len in - match List.nth_opt selected_bakers idx with - | None -> - assert - false (* should not happen if select_bakers_at_cycle_end is correct *) - | Some pkh -> - let* pk = Delegate_consensus_key.active_pubkey ctxt pkh in - return (ctxt, pk) + match List.nth_opt selected_bakers idx with + | None -> + assert false + (* should not happen if select_bakers_at_cycle_end is correct *) + | Some pkh -> + let* pk = Delegate_consensus_key.active_pubkey ctxt pkh in + return (Some (ctxt, pk))) let reset_credit_for_deactivated_delegates ctxt deactivated_delegates = let open Lwt_result_syntax in diff --git a/src/proto_alpha/lib_protocol/swrr_sampler.mli b/src/proto_alpha/lib_protocol/swrr_sampler.mli index 3c2e8d2d02b7..d536b7a91f6c 100644 --- a/src/proto_alpha/lib_protocol/swrr_sampler.mli +++ b/src/proto_alpha/lib_protocol/swrr_sampler.mli @@ -15,7 +15,7 @@ val get_baker : Raw_context.t -> Level_repr.t -> Round_repr.round -> - (Raw_context.t * Delegate_consensus_key.pk) tzresult Lwt.t + (Raw_context.t * Delegate_consensus_key.pk) option tzresult Lwt.t val reset_credit_for_deactivated_delegates : Raw_context.t -> -- GitLab From 9a810ebfa8aa6c9ccad726f36ca31a4166acbd98 Mon Sep 17 00:00:00 2001 From: Olha Nemkovych Date: Tue, 9 Dec 2025 14:05:33 +0100 Subject: [PATCH 04/10] Proto: change storage accessors to be more permissive --- src/proto_alpha/lib_protocol/delegate_sampler.ml | 7 ++++--- src/proto_alpha/lib_protocol/swrr_sampler.ml | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.ml b/src/proto_alpha/lib_protocol/delegate_sampler.ml index 9756707322ef..aece7efaa6db 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.ml +++ b/src/proto_alpha/lib_protocol/delegate_sampler.ml @@ -84,11 +84,12 @@ module Delegate_sampler_state = struct return (ctxt, v) | Some v -> return (ctxt, v) - let remove_existing ctxt cycle = + let remove ctxt cycle = let open Lwt_result_syntax in let id = identifier_of_cycle cycle in let*? ctxt = Cache.update ctxt id None in - Storage.Delegate_sampler_state.remove_existing ctxt cycle + let*! ctxt = Storage.Delegate_sampler_state.remove ctxt cycle in + return ctxt end module Random = struct @@ -342,7 +343,7 @@ let clear_outdated_sampling_data ctxt ~new_cycle = match Cycle_storage.cycle_to_clear_of_sampling_data ~new_cycle with | None -> return ctxt | Some outdated_cycle -> - let* ctxt = Delegate_sampler_state.remove_existing ctxt outdated_cycle in + let* ctxt = Delegate_sampler_state.remove ctxt outdated_cycle in Seed_storage.remove_for_cycle ctxt outdated_cycle let attesting_power ~all_bakers_attest_enabled ctxt level = diff --git a/src/proto_alpha/lib_protocol/swrr_sampler.ml b/src/proto_alpha/lib_protocol/swrr_sampler.ml index b34b2fb9c2be..9455f310e814 100644 --- a/src/proto_alpha/lib_protocol/swrr_sampler.ml +++ b/src/proto_alpha/lib_protocol/swrr_sampler.ml @@ -78,10 +78,10 @@ let select_bakers_at_cycle_end ctxt ~target_cycle = let*! ctxt = Storage.Stake.Selected_bakers.add ctxt target_cycle selected_bakers in - let* ctxt = - List.fold_left_es + let*! ctxt = + List.fold_left_s (fun ctxt {pkh; credit; _} -> - Storage.Contract.SWRR_credit.update + Storage.Contract.SWRR_credit.add ctxt (Contract_repr.Implicit pkh) credit) -- GitLab From 12da9dd09eeec6c1d826ad2351df57cf887e5ec8 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 4 Dec 2025 15:27:11 +0100 Subject: [PATCH 05/10] Proto/RPC: add swrr_selected_bakers to get the SWRR result --- src/proto_alpha/lib_plugin/RPC.ml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index 09b5c218bbfd..880652d4cbdf 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -4330,6 +4330,15 @@ module S = struct let open RPC_query in query Fun.id |+ opt_field "cycle" Cycle.rpc_arg Fun.id |> seal + let swrr_selected_bakers = + RPC_service.get_service + ~description: + "Returns the selected bakers for the round 0 of the cycle, selected \ + via the SWRR algorithm." + ~query:cycle_query + ~output:Data_encoding.(option (list Signature.Public_key_hash.encoding)) + RPC_path.(path / "swrr_selected_bakers") + let tz4_baker_number_ratio = RPC_service.get_service ~description:"Returns the ratio of active bakers using a tz4." @@ -4419,6 +4428,13 @@ let register () = List.map (fun (x, y) -> (Consensus_key.pkh x, y)) stake_info_list in return (total_stake, stake_info_list)) ; + Registration.register0 ~chunked:false S.swrr_selected_bakers (fun ctxt q () -> + let cycle = + Option.value ~default:(Cycle.current ctxt) q + |> Cycle.to_int32 |> Cycle_repr.of_int32_exn + in + let ctxt = Alpha_context.Internal_for_tests.to_raw ctxt in + Storage.Stake.Selected_bakers.find ctxt cycle) ; Registration.register0 ~chunked:false S.tz4_baker_number_ratio -- GitLab From 9ab52ebf805fff09a4cf98a0a494e9224b717a23 Mon Sep 17 00:00:00 2001 From: Olha Nemkovych Date: Thu, 4 Dec 2025 15:52:20 +0100 Subject: [PATCH 06/10] Proto/RPC: swrr credits --- src/proto_alpha/lib_plugin/RPC.ml | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index 880652d4cbdf..289b1d08919f 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -4259,6 +4259,15 @@ let get_blocks_preservation_cycles ~get_context = in return constants_parametrics.blocks_preservation_cycles +type swrr_credit_entry = {delegate : Signature.Public_key_hash.t; credit : Z.t} + +let swrr_credit_entry_encoding = + let open Data_encoding in + conv + (fun {delegate; credit} -> (delegate, credit)) + (fun (delegate, credit) -> {delegate; credit}) + (obj2 (req "delegate" Signature.Public_key_hash.encoding) (req "credit" z)) + module S = struct open Data_encoding @@ -4339,6 +4348,15 @@ module S = struct ~output:Data_encoding.(option (list Signature.Public_key_hash.encoding)) RPC_path.(path / "swrr_selected_bakers") + let swrr_credits = + RPC_service.get_service + ~description: + "Returns the current SWRR state which contains the remaining credits \ + for all the active delegates." + ~query:RPC_query.empty + ~output:Data_encoding.(list swrr_credit_entry_encoding) + RPC_path.(path / "swrr_credits") + let tz4_baker_number_ratio = RPC_service.get_service ~description:"Returns the ratio of active bakers using a tz4." @@ -4435,6 +4453,18 @@ let register () = in let ctxt = Alpha_context.Internal_for_tests.to_raw ctxt in Storage.Stake.Selected_bakers.find ctxt cycle) ; + Registration.register0 ~chunked:false S.swrr_credits (fun ctxt () () -> + let ctxt = Alpha_context.Internal_for_tests.to_raw ctxt in + Stake_storage.fold_on_active_delegates_with_minimal_stake_es + ctxt + ~order:`Undefined + ~init:[] + ~f:(fun pkh acc -> + let* credit = + Storage.Contract.SWRR_credit.get ctxt (Contract_repr.Implicit pkh) + in + let entry = {delegate = pkh; credit} in + return (entry :: acc))) ; Registration.register0 ~chunked:false S.tz4_baker_number_ratio -- GitLab From 81eb79076a6cbfb74948f6604951bd0b6afa81fc Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Tue, 9 Dec 2025 15:40:03 +0100 Subject: [PATCH 07/10] Scripts: regenerate protocol alpha patches --- scripts/README.md | 2 +- scripts/profile_alpha.patch | 59 +++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 26 deletions(-) diff --git a/scripts/README.md b/scripts/README.md index 41a04f9572ee..cfa8cb2eb504 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -61,7 +61,7 @@ commit `Patch alpha` on top of it. If there are conflicts, resolve them. ``` git format-patch -n HEAD^ git reset --hard HEAD^ # to remove the patched commit, but not the generated file -mv scripts/profiler_alpha.patch +mv scripts/profile_alpha.patch git commit -a -m "Scripts: regenerate protocol alpha patches" ``` diff --git a/scripts/profile_alpha.patch b/scripts/profile_alpha.patch index 0c00661ecfea..f4b2dec670b8 100644 --- a/scripts/profile_alpha.patch +++ b/scripts/profile_alpha.patch @@ -1,25 +1,25 @@ -From b9179f897a3f03ce43cf67eb7aefd8f554c233f5 Mon Sep 17 00:00:00 2001 -From: Pierrick Couderc -Date: Wed, 22 Oct 2025 15:05:41 +0200 -Subject: [PATCH 1/1] Proto_alpha: profiler patch +From ef878df6ee090163ac643e0dc510035dbd76c156 Mon Sep 17 00:00:00 2001 +From: Lucas Randazzo +Date: Tue, 9 Dec 2025 15:35:00 +0100 +Subject: [PATCH 1/1] Patch alpha --- src/proto_alpha/lib_protocol/apply.ml | 17 ++-- src/proto_alpha/lib_protocol/baking.ml | 4 +- - .../lib_protocol/delegate_cycles.ml | 78 +++++++++++++++---- + .../lib_protocol/delegate_cycles.ml | 79 +++++++++++++++---- src/proto_alpha/lib_protocol/dune | 2 + - src/proto_alpha/lib_protocol/init_storage.ml | 24 +++++- + src/proto_alpha/lib_protocol/init_storage.ml | 26 +++++- src/proto_alpha/lib_protocol/raw_context.ml | 4 +- src/proto_alpha/lib_protocol/script_cache.ml | 19 ++--- .../lib_protocol/script_interpreter.ml | 15 ++++ - .../lib_protocol/script_ir_translator.ml | 26 ++++--- - 9 files changed, 142 insertions(+), 47 deletions(-) + .../lib_protocol/script_ir_translator.ml | 26 +++--- + 9 files changed, 145 insertions(+), 47 deletions(-) diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml -index cdbeea9ee4..b4df332c44 100644 +index b412a56dcbc..587de1c9f1e 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml -@@ -2508,7 +2508,11 @@ let apply_manager_operations ctxt ~payload_producer chain_id ~mempool_mode +@@ -2560,7 +2560,11 @@ let apply_manager_operations ctxt ~payload_producer chain_id ~mempool_mode ~source ~operation contents_list = let open Lwt_result_syntax in let ctxt = if mempool_mode then Gas.reset_block_gas ctxt else ctxt in @@ -32,7 +32,7 @@ index cdbeea9ee4..b4df332c44 100644 let gas_cost_for_sig_check = let algo = Michelson_v1_gas.Cost_of.Interpreter.algo_of_public_key_hash source -@@ -2787,11 +2791,12 @@ let may_start_new_cycle ctxt = +@@ -2839,11 +2843,12 @@ let may_start_new_cycle ctxt = match Level.dawn_of_a_new_cycle ctxt with | None -> return (ctxt, [], []) | Some last_cycle -> @@ -51,7 +51,7 @@ index cdbeea9ee4..b4df332c44 100644 let apply_liquidity_baking_subsidy ctxt ~per_block_vote = let open Lwt_result_syntax in diff --git a/src/proto_alpha/lib_protocol/baking.ml b/src/proto_alpha/lib_protocol/baking.ml -index 7cf362b259..a45d1eda4a 100644 +index 8c060118f0e..d763f1fdbed 100644 --- a/src/proto_alpha/lib_protocol/baking.ml +++ b/src/proto_alpha/lib_protocol/baking.ml @@ -114,7 +114,7 @@ type ordered_slots = { @@ -71,12 +71,12 @@ index 7cf362b259..a45d1eda4a 100644 + return (ctxt, map)) [@profiler.record_s {verbosity = Notice} "attesting_rights"] let incr_slot att_rights = - let one = Attesting_power.make ~slots:1 ~stake:0L in + let one = Attesting_power.make ~slots:1 ~baking_power:0L in diff --git a/src/proto_alpha/lib_protocol/delegate_cycles.ml b/src/proto_alpha/lib_protocol/delegate_cycles.ml -index a666a47b9b..6c87495e8a 100644 +index 2d31093dd88..4364c85d051 100644 --- a/src/proto_alpha/lib_protocol/delegate_cycles.ml +++ b/src/proto_alpha/lib_protocol/delegate_cycles.ml -@@ -225,42 +225,92 @@ let distribute_attesting_rewards ctxt last_cycle unrevealed_nonces = +@@ -225,50 +225,101 @@ let distribute_attesting_rewards ctxt last_cycle unrevealed_nonces = let cycle_end ctxt last_cycle = let open Lwt_result_syntax in (* attributing attesting rewards *) @@ -120,6 +120,15 @@ index a666a47b9b..6c87495e8a 100644 + ctxt + last_cycle [@profiler.record_s {verbosity = Notice} "update activity"]) + in + (* Reset SWRR credits for delegates that have been deactivated *) + let* ctxt = + if Constants_storage.swrr_new_baker_lottery_enable ctxt then + Swrr_sampler.reset_credit_for_deactivated_delegates + ctxt + deactivated_delegates ++ [@profiler.record_s {verbosity = Notice} "swrr reset credits"] + else return ctxt + in (* Computing future staking rights *) let* ctxt = - Delegate_sampler.select_new_distribution_at_cycle_end ctxt ~new_cycle @@ -184,7 +193,7 @@ index a666a47b9b..6c87495e8a 100644 let balance_updates = slashing_balance_updates @ attesting_balance_updates in return (ctxt, balance_updates, deactivated_delegates) diff --git a/src/proto_alpha/lib_protocol/dune b/src/proto_alpha/lib_protocol/dune -index f1a9e3bf62..bce1980044 100644 +index 4949243fd34..c546f4bdd71 100644 --- a/src/proto_alpha/lib_protocol/dune +++ b/src/proto_alpha/lib_protocol/dune @@ -23,6 +23,8 @@ @@ -197,10 +206,10 @@ index f1a9e3bf62..bce1980044 100644 (flags (:standard) diff --git a/src/proto_alpha/lib_protocol/init_storage.ml b/src/proto_alpha/lib_protocol/init_storage.ml -index 84795cc0c52..df298fe7dcc 100644 +index 20be8e1481c..9ac5fdfd81b 100644 --- a/src/proto_alpha/lib_protocol/init_storage.ml +++ b/src/proto_alpha/lib_protocol/init_storage.ml -@@ -252,10 +252,20 @@ let prepare_first_block chain_id ctxt ~typecheck_smart_contract +@@ -259,10 +259,20 @@ let prepare_first_block chain_id ctxt ~typecheck_smart_contract return (ctxt, commitments_balance_updates @ bootstrap_balance_updates) (* Start of Alpha stitching. Comment used for automatic snapshot *) | Alpha -> @@ -223,7 +232,7 @@ index 84795cc0c52..df298fe7dcc 100644 in return (ctxt, []) (* End of Alpha stitching. Comment used for automatic snapshot *) -@@ -263,11 +273,19 @@ let prepare_first_block chain_id ctxt ~typecheck_smart_contract +@@ -270,11 +280,19 @@ let prepare_first_block chain_id ctxt ~typecheck_smart_contract | T024 -> let* ctxt = let*! ctxt = Storage.Tenderbake.First_level_of_protocol.remove ctxt in @@ -246,10 +255,10 @@ index 84795cc0c52..df298fe7dcc 100644 return (ctxt, []) (* End of alpha predecessor stitching. Comment used for automatic snapshot *) diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml -index c501d7fc16..00e5338465 100644 +index cab958b3fb7..f5d7e115f71 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml -@@ -1628,12 +1628,12 @@ let prepare_first_block ~level ~timestamp chain_id ctxt = +@@ -1635,12 +1635,12 @@ let prepare_first_block ~level ~timestamp chain_id ctxt = (* End of alpha predecessor stitching. Comment used for automatic snapshot *) in let+ ctxt = @@ -265,7 +274,7 @@ index c501d7fc16..00e5338465 100644 (previous_proto, previous_proto_constants, ctxt) diff --git a/src/proto_alpha/lib_protocol/script_cache.ml b/src/proto_alpha/lib_protocol/script_cache.ml -index 35cc6b5178..5c679ad606 100644 +index 35cc6b51781..5c679ad606b 100644 --- a/src/proto_alpha/lib_protocol/script_cache.ml +++ b/src/proto_alpha/lib_protocol/script_cache.ml @@ -98,15 +98,16 @@ let find ctxt addr = @@ -295,7 +304,7 @@ index 35cc6b5178..5c679ad606 100644 let update ctxt identifier updated_script approx_size = Cache.update ctxt identifier (Some (updated_script, approx_size)) diff --git a/src/proto_alpha/lib_protocol/script_interpreter.ml b/src/proto_alpha/lib_protocol/script_interpreter.ml -index 182af698fa..23620cd13c 100644 +index 182af698fae..23620cd13c7 100644 --- a/src/proto_alpha/lib_protocol/script_interpreter.ml +++ b/src/proto_alpha/lib_protocol/script_interpreter.ml @@ -1878,10 +1878,12 @@ let execute_any_arg logger ctxt mode step_constants ~entrypoint ~internal @@ -332,7 +341,7 @@ index 182af698fa..23620cd13c 100644 ~script ~entrypoint ~parameter_ty ~location ~parameter ~internal = execute_any_arg diff --git a/src/proto_alpha/lib_protocol/script_ir_translator.ml b/src/proto_alpha/lib_protocol/script_ir_translator.ml -index 05e30ca6ee..b618445e78 100644 +index 55309ad122f..c818b4ecdf3 100644 --- a/src/proto_alpha/lib_protocol/script_ir_translator.ml +++ b/src/proto_alpha/lib_protocol/script_ir_translator.ml @@ -5269,21 +5269,27 @@ let parse_script : @@ -382,4 +391,4 @@ index 05e30ca6ee..b618445e78 100644 let parse_view ~elab_conf ctxt ty view = parse_view ~unparse_code_rec ~elab_conf ctxt ty view -- -2.51.1.dirty +2.51.0 -- GitLab From 3a43f9c8d20cfe380154bd45e9f1e2c2f15592aa Mon Sep 17 00:00:00 2001 From: Olha Nemkovych Date: Thu, 11 Dec 2025 11:42:39 +0100 Subject: [PATCH 08/10] Proto: clean swrr storage --- src/proto_alpha/lib_protocol/delegate_sampler.ml | 4 +++- src/proto_alpha/lib_protocol/swrr_sampler.ml | 2 ++ src/proto_alpha/lib_protocol/swrr_sampler.mli | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.ml b/src/proto_alpha/lib_protocol/delegate_sampler.ml index aece7efaa6db..e80e69a1b3d3 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.ml +++ b/src/proto_alpha/lib_protocol/delegate_sampler.ml @@ -344,7 +344,9 @@ let clear_outdated_sampling_data ctxt ~new_cycle = | None -> return ctxt | Some outdated_cycle -> let* ctxt = Delegate_sampler_state.remove ctxt outdated_cycle in - Seed_storage.remove_for_cycle ctxt outdated_cycle + let* ctxt = Seed_storage.remove_for_cycle ctxt outdated_cycle in + let*! ctxt = Swrr_sampler.remove_outdated_cycle ctxt outdated_cycle in + return ctxt let attesting_power ~all_bakers_attest_enabled ctxt level = let open Lwt_result_syntax in diff --git a/src/proto_alpha/lib_protocol/swrr_sampler.ml b/src/proto_alpha/lib_protocol/swrr_sampler.ml index 9455f310e814..4c7d81e762ce 100644 --- a/src/proto_alpha/lib_protocol/swrr_sampler.ml +++ b/src/proto_alpha/lib_protocol/swrr_sampler.ml @@ -124,3 +124,5 @@ let reset_credit_for_deactivated_delegates ctxt deactivated_delegates = deactivated_delegates in return ctxt + +let remove_outdated_cycle = Storage.Stake.Selected_bakers.remove diff --git a/src/proto_alpha/lib_protocol/swrr_sampler.mli b/src/proto_alpha/lib_protocol/swrr_sampler.mli index d536b7a91f6c..7c962c91738b 100644 --- a/src/proto_alpha/lib_protocol/swrr_sampler.mli +++ b/src/proto_alpha/lib_protocol/swrr_sampler.mli @@ -21,3 +21,5 @@ val reset_credit_for_deactivated_delegates : Raw_context.t -> Signature.Public_key_hash.t list -> Raw_context.t tzresult Lwt.t + +val remove_outdated_cycle : Raw_context.t -> Cycle_repr.t -> Raw_context.t Lwt.t -- GitLab From 8916c3c3d45810b266d379c5a5a7bd6f232ec36c Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Fri, 12 Dec 2025 15:57:45 +0100 Subject: [PATCH 09/10] Proto/tests: Add RPC regresison tests --- tezt/lib_tezos/RPC.ml | 13 ++++++ tezt/lib_tezos/RPC.mli | 15 +++++++ tezt/tests/RPC_test.ml | 24 ++++++++++- ...t) RPC regression tests- misc_protocol.out | 40 ++++++++++++++----- ... regression tests- misc_protocol_abaab.out | 40 ++++++++++++++----- 5 files changed, 112 insertions(+), 20 deletions(-) diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index 7ada6f51c6b1..2e4a566cdbc2 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -2082,3 +2082,16 @@ let get_chain_block_context_destination_index ?(chain = "main") "index"; ] @@ JSON.as_int_opt + +let get_chain_block_helpers_swrr_credits ?(chain = "main") ?(block = "head") () + = + make GET ["chains"; chain; "blocks"; block; "helpers"; "swrr_credits"] Fun.id + +let get_chain_block_helpers_swrr_selected_bakers ?(chain = "main") + ?(block = "head") ?cycle () = + let query_string = Option.map (fun c -> [("cycle", Int.to_string c)]) cycle in + make + ?query_string + GET + ["chains"; chain; "blocks"; block; "helpers"; "swrr_selected_bakers"] + Fun.id diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 30f870b5143d..f93c6f559cfd 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -1503,3 +1503,18 @@ val get_abaab_activation_level : [block] defaults to ["head"]. *) val get_chain_block_context_destination_index : ?chain:string -> ?block:string -> string -> int option t + +(** RPC: [GET /chains//blocks//helpers/swrr_credits] + + [chain] defaults to ["main"]. + [block] defaults to ["head"]. *) +val get_chain_block_helpers_swrr_credits : + ?chain:string -> ?block:string -> unit -> JSON.t t + +(** RPC: [GET /chains//blocks//helpers/swrr_selected_bakers?cycle=] + + [chain] defaults to ["main"]. + [block] defaults to ["head"]. + [cycle] doesn't have to be specified (defaults to current cycle). *) +val get_chain_block_helpers_swrr_selected_bakers : + ?chain:string -> ?block:string -> ?cycle:int -> unit -> JSON.t t diff --git a/tezt/tests/RPC_test.ml b/tezt/tests/RPC_test.ml index 55005fbf12cd..f932a2067d5c 100644 --- a/tezt/tests/RPC_test.ml +++ b/tezt/tests/RPC_test.ml @@ -759,6 +759,19 @@ let test_misc_protocol _test_mode_tag protocol ?endpoint client = unit else unit in + let* () = + if Protocol.(number protocol >= 025) then + let* _ = + Client.RPC.call ?endpoint ~hooks client + @@ RPC.get_chain_block_helpers_swrr_credits () + in + let* _ = + Client.RPC.call ?endpoint ~hooks client + @@ RPC.get_chain_block_helpers_swrr_selected_bakers () + in + unit + else unit + in unit let mempool_hooks = @@ -1680,6 +1693,11 @@ let register protocols = `Int 0 ); ] in + let swrr_flag protocol = + if Protocol.(number protocol >= 025) then + [(["swrr_new_baker_lottery_enable"], `Bool true)] + else [] + in check_rpc_regression "contracts" ~test_function:test_contracts @@ -1707,7 +1725,8 @@ let register protocols = check_rpc_regression "misc_protocol" ~test_function:test_misc_protocol - ~parameter_overrides:consensus_threshold ; + ~parameter_overrides:(fun protocol -> + consensus_threshold protocol @ swrr_flag protocol) ; check_rpc_regression "misc_protocol_abaab" ~test_function:test_misc_protocol @@ -1718,7 +1737,8 @@ let register protocols = ( ["all_bakers_attest_activation_threshold"], `O [("numerator", `Float 0.); ("denominator", `Float 1.)] ); ] - @ consensus_threshold protocol) ; + @ consensus_threshold protocol + @ swrr_flag protocol) ; (match test_mode_tag with | `Light -> () | _ -> diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out index 2420a7c6ba94..14d5bbf4c2d0 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol.out @@ -83,7 +83,7 @@ "allow_tz4_delegate_enable": true, "all_bakers_attest_activation_threshold": { "numerator": 1, "denominator": 2 }, "native_contracts_enable": true, - "swrr_new_baker_lottery_enable": false, "issuance_modification_delay": 2, + "swrr_new_baker_lottery_enable": true, "issuance_modification_delay": 2, "consensus_key_activation_delay": 2, "unstake_finalization_delay": 3 } ./octez-client rpc get /chains/main/blocks/head/helpers/baking_rights @@ -100,12 +100,12 @@ "round": 3, "estimated_time": "[TIMESTAMP]", "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 10, "estimated_time": "[TIMESTAMP]", + "round": 6, "estimated_time": "[TIMESTAMP]", "consensus_key": "[PUBLIC_KEY_HASH]" } ] ./octez-client rpc get '/chains/main/blocks/head/helpers/baking_rights?delegate=[PUBLIC_KEY_HASH]' [ { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 2, "estimated_time": "[TIMESTAMP]", + "round": 1, "estimated_time": "[TIMESTAMP]", "consensus_key": "[PUBLIC_KEY_HASH]" } ] ./octez-client rpc get '/chains/main/blocks/head/helpers/current_level?offset=0' @@ -119,26 +119,26 @@ [ { "level": 1, "delegates": [ { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 11, "attesting_power": 50, + "first_slot": 6, "attesting_power": 32, "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 4, "attesting_power": 47, + "first_slot": 4, "attesting_power": 64, "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 2, "attesting_power": 46, + "first_slot": 2, "attesting_power": 64, "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 1, "attesting_power": 55, + "first_slot": 1, "attesting_power": 32, "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 0, "attesting_power": 58, + "first_slot": 0, "attesting_power": 64, "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] ./octez-client rpc get '/chains/main/blocks/head/helpers/attestation_rights?delegate=[PUBLIC_KEY_HASH]' [ { "level": 1, "delegates": [ { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 11, "attesting_power": 50, + "first_slot": 6, "attesting_power": 32, "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] ./octez-client rpc get /chains/main/blocks/head/helpers/levels_in_current_cycle @@ -152,3 +152,25 @@ ./octez-client rpc get /chains/main/blocks/head/helpers/all_bakers_attest_activation_level null + +./octez-client rpc get /chains/main/blocks/head/helpers/swrr_credits +[ { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "-1466666666666" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "-1466666666666" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "5866666666664" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "-1466666666666" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "-1466666666666" } ] + +./octez-client rpc get /chains/main/blocks/head/helpers/swrr_selected_bakers +[ "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]" ] diff --git a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol_abaab.out b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol_abaab.out index 787beb645e2f..3478b8d2ea14 100644 --- a/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol_abaab.out +++ b/tezt/tests/expected/RPC_test.ml/Alpha- (mode client) RPC regression tests- misc_protocol_abaab.out @@ -83,7 +83,7 @@ "allow_tz4_delegate_enable": true, "all_bakers_attest_activation_threshold": { "numerator": 0, "denominator": 1 }, "native_contracts_enable": true, - "swrr_new_baker_lottery_enable": false, "issuance_modification_delay": 2, + "swrr_new_baker_lottery_enable": true, "issuance_modification_delay": 2, "consensus_key_activation_delay": 2, "unstake_finalization_delay": 3 } ./octez-client rpc get /chains/main/blocks/head/helpers/baking_rights @@ -100,12 +100,12 @@ "round": 3, "estimated_time": "[TIMESTAMP]", "consensus_key": "[PUBLIC_KEY_HASH]" }, { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 10, "estimated_time": "[TIMESTAMP]", + "round": 6, "estimated_time": "[TIMESTAMP]", "consensus_key": "[PUBLIC_KEY_HASH]" } ] ./octez-client rpc get '/chains/main/blocks/head/helpers/baking_rights?delegate=[PUBLIC_KEY_HASH]' [ { "level": 2, "delegate": "[PUBLIC_KEY_HASH]", - "round": 2, "estimated_time": "[TIMESTAMP]", + "round": 1, "estimated_time": "[TIMESTAMP]", "consensus_key": "[PUBLIC_KEY_HASH]" } ] ./octez-client rpc get '/chains/main/blocks/head/helpers/current_level?offset=0' @@ -119,26 +119,26 @@ [ { "level": 1, "delegates": [ { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 4, "attesting_power": 55, + "first_slot": 4, "attesting_power": 64, "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 3, "attesting_power": 47, + "first_slot": 3, "attesting_power": 32, "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 2, "attesting_power": 46, + "first_slot": 2, "attesting_power": 64, "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 1, "attesting_power": 50, + "first_slot": 1, "attesting_power": 32, "consensus_key": "[PUBLIC_KEY_HASH]" }, { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 0, "attesting_power": 58, + "first_slot": 0, "attesting_power": 64, "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] ./octez-client rpc get '/chains/main/blocks/head/helpers/attestation_rights?delegate=[PUBLIC_KEY_HASH]' [ { "level": 1, "delegates": [ { "delegate": "[PUBLIC_KEY_HASH]", - "first_slot": 1, "attesting_power": 50, + "first_slot": 1, "attesting_power": 32, "consensus_key": "[PUBLIC_KEY_HASH]" } ] } ] ./octez-client rpc get /chains/main/blocks/head/helpers/levels_in_current_cycle @@ -153,3 +153,25 @@ ./octez-client rpc get /chains/main/blocks/head/helpers/all_bakers_attest_activation_level { "level": 1, "level_position": 0, "cycle": 0, "cycle_position": 0, "expected_commitment": false } + +./octez-client rpc get /chains/main/blocks/head/helpers/swrr_credits +[ { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "-1466666666666" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "-1466666666666" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "5866666666664" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "-1466666666666" }, + { "delegate": "[PUBLIC_KEY_HASH]", + "credit": "-1466666666666" } ] + +./octez-client rpc get /chains/main/blocks/head/helpers/swrr_selected_bakers +[ "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]", + "[PUBLIC_KEY_HASH]" ] -- GitLab From cd24055da633da6b8d58dccd93a7be43eeb70ea4 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Fri, 12 Dec 2025 15:59:21 +0100 Subject: [PATCH 10/10] todo integration tests --- manifest/product_octez.ml | 1 + .../lib_protocol/test/integration/dune | 3 +- .../test/integration/test_swrr.ml | 59 +++++++++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/proto_alpha/lib_protocol/test/integration/test_swrr.ml diff --git a/manifest/product_octez.ml b/manifest/product_octez.ml index 65826966578b..b610fd5df245 100644 --- a/manifest/product_octez.ml +++ b/manifest/product_octez.ml @@ -6451,6 +6451,7 @@ end = struct ("test_token", true); ("test_native_contracts", N.(number >= 025)); ("test_clst", N.(number >= 025)); + ("test_swrr", N.(number >= 025)); ] |> conditional_list in diff --git a/src/proto_alpha/lib_protocol/test/integration/dune b/src/proto_alpha/lib_protocol/test/integration/dune index 6e0fe85d7478..91dd3cde438c 100644 --- a/src/proto_alpha/lib_protocol/test/integration/dune +++ b/src/proto_alpha/lib_protocol/test/integration/dune @@ -41,7 +41,8 @@ test_storage test_token test_native_contracts - test_clst)) + test_clst + test_swrr)) (executable (name main) diff --git a/src/proto_alpha/lib_protocol/test/integration/test_swrr.ml b/src/proto_alpha/lib_protocol/test/integration/test_swrr.ml new file mode 100644 index 000000000000..4b7e1f52071c --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/integration/test_swrr.ml @@ -0,0 +1,59 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (SWRR) + Invocation: dune exec src/proto_alpha/lib_protocol/test/integration/main.exe \ + -- --file test_swrr.ml + Subject: SWRR sampler +*) + +open Protocol +open Alpha_context + +let test_swrr_sampler_correct_length () = + let open Lwt_result_wrap_syntax in + let* block, _ = Context.init3 () in + _ + +let test_swrr_sampler_no_empty_value () = + let open Lwt_result_warp_syntax in + let* block, _ = Context.init3 () in + _ + +let test_swrr_sampler_manual_scenario () = + let open Lwt_result_wrap_syntax in + let* block, baker_list = + Context.init_n _ ~bootstrap_balances:[1_000_000_000_000L; _] () + in + _ + +let test_swrr_sampler_check_variance () = + let open Lwt_result_wrap_syntax in + let* block, _ = Context.init3 ~blocks_per_cycle:_ () in + _ + +let register_test ~title = + Tezt_helpers.register_test_es + ~__FILE__ + ~file_tags:["sampler"; "swrr"] + ~title:("SWRR: " ^ title) + +let () = + register_test + ~title:"SWRR sampler correct length" + test_swrr_sampler_correct_length ; + register_test + ~title:"SWRR sampler no empty value" + test_swrr_sampler_no_empty_value ; + register_test + ~title:"SWRR sampler manual scenario" + test_swrr_sampler_manual_scenario ; + register_test + ~title:"SWRR sampler check_variance" + test_swrr_sampler_check_variance -- GitLab