diff --git a/manifest/product_octez.ml b/manifest/product_octez.ml index 3a97892fc78a014e0d654d897e606035fd3e31b6..c69504fd481608aa622230888f499fb249e0cb8f 100644 --- a/manifest/product_octez.ml +++ b/manifest/product_octez.ml @@ -237,7 +237,7 @@ let octez_stdlib = ~internal_name:"tezos_stdlib" ~path:"src/lib_stdlib" ~synopsis:"Yet-another local-extension of the OCaml standard library" - ~deps:[hex; zarith; lwt; aches] + ~deps:[hex; zarith; lwt; aches; data_encoding] ~inline_tests:ppx_expect ~foreign_stubs: {language = C; flags = []; names = ["tzBytes_c"]; include_dirs = []} diff --git a/src/lib_protocol_environment/sigs/v16.ml b/src/lib_protocol_environment/sigs/v16.ml index 31ba26fc7f1c751032feac99e83bf8ba0a5a737d..4f157e0023ad2ac3b61980abe38bb9c6ae256264 100644 --- a/src/lib_protocol_environment/sigs/v16.ml +++ b/src/lib_protocol_environment/sigs/v16.ml @@ -5900,6 +5900,12 @@ val fold : ('b -> 'a -> 'b) -> 'a t -> 'b -> 'b [fallback] is required to initialize a fresh array before it can be filled. *) val fold_map : ('b -> 'a -> 'b * 'c) -> 'a t -> 'b -> 'c -> 'b * 'c t + +(** [encoding ?max_length e] is a data encoding for fallback arrays + whose elements are encoded with [e]. If [max_length] is provided, + the length of the encoded arrays is bounded by [max_length]. *) +val encoding : + ?max_length:int -> 'a Data_encoding.encoding -> 'a t Data_encoding.encoding end # 48 "v16.in.ml" diff --git a/src/lib_protocol_environment/sigs/v16/fallbackArray.mli b/src/lib_protocol_environment/sigs/v16/fallbackArray.mli index 604bec65029e62cfbccf0d3ce91f28e8e7097a2a..5b57b61f1c50ff4e4a52da541b6384e459142828 100644 --- a/src/lib_protocol_environment/sigs/v16/fallbackArray.mli +++ b/src/lib_protocol_environment/sigs/v16/fallbackArray.mli @@ -82,3 +82,9 @@ val fold : ('b -> 'a -> 'b) -> 'a t -> 'b -> 'b [fallback] is required to initialize a fresh array before it can be filled. *) val fold_map : ('b -> 'a -> 'b * 'c) -> 'a t -> 'b -> 'c -> 'b * 'c t + +(** [encoding ?max_length e] is a data encoding for fallback arrays + whose elements are encoded with [e]. If [max_length] is provided, + the length of the encoded arrays is bounded by [max_length]. *) +val encoding : + ?max_length:int -> 'a Data_encoding.encoding -> 'a t Data_encoding.encoding diff --git a/src/lib_stdlib/dune b/src/lib_stdlib/dune index 6266e6e4743b303298172150abab3ccbdf58e03f..ac2c3b77c9b4136c53798483c0d18c93f8ff39e5 100644 --- a/src/lib_stdlib/dune +++ b/src/lib_stdlib/dune @@ -9,7 +9,8 @@ hex zarith lwt - aches) + aches + octez-libs.data-encoding) (inline_tests (flags -verbose) (modes native)) (preprocess (pps ppx_expect)) (foreign_stubs (language c) (names tzBytes_c))) diff --git a/src/lib_stdlib/fallbackArray.mli b/src/lib_stdlib/fallbackArray.mli index 604bec65029e62cfbccf0d3ce91f28e8e7097a2a..5b57b61f1c50ff4e4a52da541b6384e459142828 100644 --- a/src/lib_stdlib/fallbackArray.mli +++ b/src/lib_stdlib/fallbackArray.mli @@ -82,3 +82,9 @@ val fold : ('b -> 'a -> 'b) -> 'a t -> 'b -> 'b [fallback] is required to initialize a fresh array before it can be filled. *) val fold_map : ('b -> 'a -> 'b * 'c) -> 'a t -> 'b -> 'c -> 'b * 'c t + +(** [encoding ?max_length e] is a data encoding for fallback arrays + whose elements are encoded with [e]. If [max_length] is provided, + the length of the encoded arrays is bounded by [max_length]. *) +val encoding : + ?max_length:int -> 'a Data_encoding.encoding -> 'a t Data_encoding.encoding diff --git a/src/lib_stdlib/readOnlyArray.ml b/src/lib_stdlib/readOnlyArray.ml index df2724b5018ddd48c3b45cec04aea97c0e211741..74e83c6fef8fd8bbd69bfdb9435bbb463e2fc788 100644 --- a/src/lib_stdlib/readOnlyArray.ml +++ b/src/lib_stdlib/readOnlyArray.ml @@ -102,3 +102,5 @@ let fold_map f array init fallback = aux accu (idx + 1) in (aux init 0, output) + +let encoding = Data_encoding.array diff --git a/src/proto_alpha/lib_parameters/default_parameters.ml b/src/proto_alpha/lib_parameters/default_parameters.ml index 042c0b44438776abf8841081c847b77909fb5403..611b67188b17225792c7d519e87a7618369b89f1 100644 --- a/src/proto_alpha/lib_parameters/default_parameters.ml +++ b/src/proto_alpha/lib_parameters/default_parameters.ml @@ -388,6 +388,8 @@ let constants_mainnet : Constants.Parametric.t = cache_stake_distribution_cycles = 5; (* One for the sampler state for all cycles stored at any moment (as above). *) cache_sampler_state_cycles = 5; + (* One for the SWRR selected distribution for all cycles stored at any moment (as above). *) + cache_swrr_selected_distribution_cycles = 5; dal = default_dal; sc_rollup; zk_rollup = diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index 289b1d08919f1fd82cd6f9269823e4daf486c74e..67f31d05850cf5704666b335f2283d9cabb97382 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -4452,7 +4452,13 @@ let register () = |> 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) ; + let* baker_array = Storage.Stake.Selected_bakers.find ctxt cycle in + match baker_array with + | None -> return_none + | Some baker_array -> + return_some + FallbackArray.( + Stdlib.List.init (length baker_array) (get baker_array))) ; 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 diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index a72e6da59fd190a4d184f158ec7b2bd7b6eec2d3..41597dab5ad2b23630c5c61483db47b0971d56a3 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -980,6 +980,7 @@ module Constants : sig cache_script_size : int; cache_stake_distribution_cycles : int; cache_sampler_state_cycles : int; + cache_swrr_selected_distribution_cycles : int; dal : dal; sc_rollup : sc_rollup; zk_rollup : zk_rollup; diff --git a/src/proto_alpha/lib_protocol/constants_parametric_repr.ml b/src/proto_alpha/lib_protocol/constants_parametric_repr.ml index 73d79d97910b28b1a79e4d597faa56e02be1e3cc..4384787aa2d0ff2f3f0344a541d0920ac6bb66c4 100644 --- a/src/proto_alpha/lib_protocol/constants_parametric_repr.ml +++ b/src/proto_alpha/lib_protocol/constants_parametric_repr.ml @@ -325,6 +325,7 @@ type t = { cache_script_size : int; cache_stake_distribution_cycles : int; cache_sampler_state_cycles : int; + cache_swrr_selected_distribution_cycles : int; dal : dal; sc_rollup : sc_rollup; zk_rollup : zk_rollup; @@ -632,7 +633,8 @@ let encoding = c.initial_seed ), ( ( c.cache_script_size, c.cache_stake_distribution_cycles, - c.cache_sampler_state_cycles ), + c.cache_sampler_state_cycles, + c.cache_swrr_selected_distribution_cycles ), ( c.dal, ( (c.sc_rollup, c.zk_rollup), ( c.adaptive_issuance, @@ -679,7 +681,8 @@ let encoding = initial_seed ), ( ( cache_script_size, cache_stake_distribution_cycles, - cache_sampler_state_cycles ), + cache_sampler_state_cycles, + cache_swrr_selected_distribution_cycles ), ( dal, ( (sc_rollup, zk_rollup), ( adaptive_issuance, @@ -729,6 +732,7 @@ let encoding = cache_script_size; cache_stake_distribution_cycles; cache_sampler_state_cycles; + cache_swrr_selected_distribution_cycles; dal; sc_rollup; zk_rollup; @@ -792,10 +796,11 @@ let encoding = (opt "testnet_dictator" Signature.Public_key_hash.encoding) (opt "initial_seed" State_hash.encoding)) (merge_objs - (obj3 + (obj4 (req "cache_script_size" int31) (req "cache_stake_distribution_cycles" int8) - (req "cache_sampler_state_cycles" int8)) + (req "cache_sampler_state_cycles" int8) + (req "cache_swrr_selected_distribution_cycles" int8)) (merge_objs (obj1 (req "dal_parametric" dal_encoding)) (merge_objs diff --git a/src/proto_alpha/lib_protocol/constants_parametric_repr.mli b/src/proto_alpha/lib_protocol/constants_parametric_repr.mli index 2d44cffef908d2288b4cb3f2a9bdee9cda0202fc..e9bdc676020c69d93450d495baa5e82c017a27f0 100644 --- a/src/proto_alpha/lib_protocol/constants_parametric_repr.mli +++ b/src/proto_alpha/lib_protocol/constants_parametric_repr.mli @@ -262,6 +262,8 @@ type t = { (* in cycles *) cache_sampler_state_cycles : int; (* in cycles *) + cache_swrr_selected_distribution_cycles : int; + (* in cycles *) dal : dal; sc_rollup : sc_rollup; zk_rollup : zk_rollup; diff --git a/src/proto_alpha/lib_protocol/constants_repr.ml b/src/proto_alpha/lib_protocol/constants_repr.ml index cdddf4f53e39642adf07cdfaa1e38f1692bdf8f0..390b539eedc9d522339cd419fb70e4658682f8e3 100644 --- a/src/proto_alpha/lib_protocol/constants_repr.ml +++ b/src/proto_alpha/lib_protocol/constants_repr.ml @@ -64,7 +64,7 @@ let michelson_maximum_type_size = 2001 (* This constant declares the number of subcaches used by the cache mechanism (see {Context.Cache}). *) -let cache_layout_size = 3 +let cache_layout_size = 4 (* /!\ Several parts of the codebase may assume that [denunciation_period = 1] and [slashing_delay = 1] **without being @@ -608,4 +608,5 @@ let cache_layout p = p.cache_script_size; p.cache_stake_distribution_cycles; p.cache_sampler_state_cycles; + p.cache_swrr_selected_distribution_cycles; ] diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.ml b/src/proto_alpha/lib_protocol/delegate_sampler.ml index d5c42f1f57d2916ed71984e740664688c426337f..94309190ccd5ee6cb1a4a2b9634b053d2afd09b9 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.ml +++ b/src/proto_alpha/lib_protocol/delegate_sampler.ml @@ -345,7 +345,7 @@ let clear_outdated_sampling_data ctxt ~new_cycle = | Some outdated_cycle -> let* ctxt = Delegate_sampler_state.remove ctxt outdated_cycle in let* ctxt = Seed_storage.remove_for_cycle ctxt outdated_cycle in - let*! ctxt = Swrr_sampler.remove_outdated_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 = diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index a567971a705941a7486995ec72a0ca643c579443..f754260d80647a300f02f8c45e39529a2e0a3e0c 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -1269,6 +1269,7 @@ let prepare_first_block ~level ~timestamp chain_id ctxt = cache_script_size; cache_stake_distribution_cycles; cache_sampler_state_cycles; + cache_swrr_selected_distribution_cycles; dal = _; sc_rollup = _; zk_rollup = _; @@ -1323,6 +1324,7 @@ let prepare_first_block ~level ~timestamp chain_id ctxt = cache_script_size; cache_stake_distribution_cycles; cache_sampler_state_cycles; + cache_swrr_selected_distribution_cycles; dal; sc_rollup; zk_rollup; @@ -1622,6 +1624,7 @@ let prepare_first_block ~level ~timestamp chain_id ctxt = cache_script_size; cache_stake_distribution_cycles; cache_sampler_state_cycles; + cache_swrr_selected_distribution_cycles = cache_sampler_state_cycles; dal; sc_rollup; zk_rollup; diff --git a/src/proto_alpha/lib_protocol/storage.ml b/src/proto_alpha/lib_protocol/storage.ml index 39345190f47a8bf34e67b8d169357910cd473308..6c94f333772ad758167bb9aba66d242bf9a0d11c 100644 --- a/src/proto_alpha/lib_protocol/storage.ml +++ b/src/proto_alpha/lib_protocol/storage.ml @@ -1330,10 +1330,9 @@ module Cycle = struct let name = ["selected_bakers"] end) (struct - type t = Signature.Public_key_hash.t list + type t = Signature.Public_key_hash.t FallbackArray.t - let encoding = - Data_encoding.(Variable.list Signature.Public_key_hash.encoding) + let encoding = FallbackArray.encoding Signature.Public_key_hash.encoding end) module Total_active_stake = diff --git a/src/proto_alpha/lib_protocol/storage.mli b/src/proto_alpha/lib_protocol/storage.mli index ec2958e7330634b572d0036f2abf22e0f3a37cce..00e1b8a608ab319f9561b4def0504cfbbc911318 100644 --- a/src/proto_alpha/lib_protocol/storage.mli +++ b/src/proto_alpha/lib_protocol/storage.mli @@ -620,7 +620,7 @@ module Stake : sig module Selected_bakers : Indexed_data_storage with type key = Cycle_repr.t - and type value = Signature.Public_key_hash.t list + and type value = Signature.Public_key_hash.t FallbackArray.t and type t := Raw_context.t (** Sum of the active stakes of all the delegates with diff --git a/src/proto_alpha/lib_protocol/swrr_sampler.ml b/src/proto_alpha/lib_protocol/swrr_sampler.ml index 20cad7b9330206b3701e089d6dfae0ab1d1bca61..470af2aecbe736169bd1f159f4b0d046441f2baf 100644 --- a/src/proto_alpha/lib_protocol/swrr_sampler.ml +++ b/src/proto_alpha/lib_protocol/swrr_sampler.ml @@ -7,6 +7,54 @@ type credit_info = {pkh : Signature.public_key_hash; credit : Z.t; stake : Z.t} +module Swrr_selected_distribution = struct + module Cache_client = struct + type cached_value = Signature.Public_key_hash.t FallbackArray.t + + let namespace = Cache_repr.create_namespace "swrr_selected_distribution" + + let cache_index = 3 + + let value_of_identifier ctxt identifier = + let cycle = Cycle_repr.of_string_exn identifier in + Storage.Stake.Selected_bakers.get ctxt cycle + end + + module Cache = (val Cache_repr.register_exn (module Cache_client)) + + let identifier_of_cycle cycle = Format.asprintf "%a" Cycle_repr.pp cycle + + (* that's symbolic: 1 cycle = 1 entry *) + let size = 1 + + let init ctxt cycle delegates = + let open Lwt_result_syntax in + let id = identifier_of_cycle cycle in + let* ctxt = Storage.Stake.Selected_bakers.init ctxt cycle delegates in + let*? ctxt = Cache.update ctxt id (Some (delegates, size)) in + return ctxt + + let find ctxt cycle = + let open Lwt_result_syntax in + let id = identifier_of_cycle cycle in + let* ctxt, cached_opt = Cache.find ctxt id in + match cached_opt with + | Some _ as some_cache -> return (ctxt, some_cache) + | None -> + let* delegates = Storage.Stake.Selected_bakers.find ctxt cycle in + let*? ctxt = + Cache.update ctxt id (Option.map (fun v -> (v, size)) delegates) + in + return (ctxt, delegates) + + 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 + let*! ctxt = Storage.Stake.Selected_bakers.remove ctxt cycle in + return ctxt +end + let select_bakers_at_cycle_end ctxt ~target_cycle = let open Lwt_result_syntax in let* total_stake = Stake_storage.get_total_active_stake ctxt target_cycle in @@ -75,8 +123,14 @@ let select_bakers_at_cycle_end ctxt ~target_cycle = in let new_credits, selected_bakers = loop 0 init_credit_list [] in (* update context *) - let*! ctxt = - Storage.Stake.Selected_bakers.add ctxt target_cycle selected_bakers + let* ctxt = + Swrr_selected_distribution.init + ctxt + target_cycle + (FallbackArray.of_list + ~fallback:Signature.Public_key_hash.zero + ~proj:(fun pkh -> pkh) + selected_bakers) in let*! ctxt = List.fold_left_s @@ -95,21 +149,15 @@ let get_baker ctxt level round = let cycle = level.Level_repr.cycle in let pos = level.Level_repr.cycle_position in let*? round_int = Round_repr.to_int round in - - let* selected_bakers = Storage.Stake.Selected_bakers.find ctxt cycle in + let* ctxt, selected_bakers = Swrr_selected_distribution.find ctxt cycle in match selected_bakers with | None -> return (ctxt, None) - | Some selected_bakers -> ( - let len = List.length selected_bakers in + | Some selected_bakers -> + let len = FallbackArray.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, Some pk)) + let pkh = FallbackArray.get selected_bakers idx in + let* pk = Delegate_consensus_key.active_pubkey ctxt pkh in + return (ctxt, Some pk) let reset_credit_for_deactivated_delegates ctxt deactivated_delegates = let open Lwt_result_syntax in @@ -125,4 +173,4 @@ let reset_credit_for_deactivated_delegates ctxt deactivated_delegates = in return ctxt -let remove_outdated_cycle = Storage.Stake.Selected_bakers.remove +let remove_outdated_cycle = Swrr_selected_distribution.remove diff --git a/src/proto_alpha/lib_protocol/swrr_sampler.mli b/src/proto_alpha/lib_protocol/swrr_sampler.mli index 1ef3bb332b5f57658098830764996eba0e51e07d..d3ef428dc30fe144e364633728130f546436ef16 100644 --- a/src/proto_alpha/lib_protocol/swrr_sampler.mli +++ b/src/proto_alpha/lib_protocol/swrr_sampler.mli @@ -22,4 +22,5 @@ val reset_credit_for_deactivated_delegates : 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 +val remove_outdated_cycle : + Raw_context.t -> Cycle_repr.t -> Raw_context.t tzresult Lwt.t