From 67512523175a1446582d019da79053dd98398b22 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 6 Aug 2025 14:36:26 +0200 Subject: [PATCH 1/4] Proto: move consensus_threshold It and the committee will depend on the current level. The committee does need to stay exposed, because of its use in other parts of the protocol. --- src/proto_alpha/lib_protocol/TEZOS_PROTOCOL | 1 + src/proto_alpha/lib_protocol/alpha_context.ml | 3 ++- src/proto_alpha/lib_protocol/alpha_context.mli | 11 ++++++++--- src/proto_alpha/lib_protocol/baking.ml | 2 +- .../consensus_parameters_storage.ml | 17 +++++++++++++++++ .../consensus_parameters_storage.mli | 14 ++++++++++++++ .../delegate_missed_attestations_storage.ml | 2 +- .../delegate_missed_attestations_storage.mli | 2 +- .../lib_protocol/delegate_sampler.ml | 5 ----- .../lib_protocol/delegate_sampler.mli | 4 ---- src/proto_alpha/lib_protocol/dune | 4 ++++ src/proto_alpha/lib_protocol/validate.ml | 8 ++++++-- 12 files changed, 55 insertions(+), 18 deletions(-) create mode 100644 src/proto_alpha/lib_protocol/consensus_parameters_storage.ml create mode 100644 src/proto_alpha/lib_protocol/consensus_parameters_storage.mli diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index 72c050c0c315..8dfea6c7ed20 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -144,6 +144,7 @@ "Global_constants_costs", "Ticket_hash_builder", "Constants_storage", + "Consensus_parameters_storage", "Level_storage", "Cycle_storage", "Nonce_storage", diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index a2259dd4359b..fb2adfaaa1e4 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -673,10 +673,11 @@ module Migration = Migration_repr module Attestation_power = struct include Attestation_power_repr + include Consensus_parameters_storage let get ctxt level {slots; stake} = let all_bakers_attest_enabled = - Delegate_sampler.check_all_bakers_attest_at_level ctxt level + check_all_bakers_attest_at_level ctxt level in if all_bakers_attest_enabled then stake else Int64.of_int slots diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 54aa682a5b10..81d97d858b13 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -1051,10 +1051,10 @@ module Constants : sig (** See {!Raw_context.round_durations}. *) val round_durations : context -> Round.round_durations + (** To be used for rounds and DAL. For attestations, + see {!Attestation_power.consensus_committee}. *) val consensus_committee_size : context -> int - val consensus_threshold_size : context -> int - val minimal_participation_ratio : context -> Ratio.t val limit_of_delegation_over_baking : context -> int @@ -2242,7 +2242,8 @@ module Receipt : sig val balance_updates_encoding : balance_updates Data_encoding.t end -(** This module re-exports definitions from {!Attestation_power_repr}. *) +(** This module re-exports definitions from {!Attestation_power_repr} and + {!Consensus_parameters_storage}. *) module Attestation_power : sig type t @@ -2259,6 +2260,10 @@ module Attestation_power : sig val get : context -> Level.t -> t -> int64 val get_slots : t -> int + + val consensus_threshold : context -> Level.t -> int + + val consensus_committee : context -> Level.t -> int end (** This module re-exports definitions from {!Delegate_consensus_key}. *) diff --git a/src/proto_alpha/lib_protocol/baking.ml b/src/proto_alpha/lib_protocol/baking.ml index 540bd7d8941f..41be5dc8b419 100644 --- a/src/proto_alpha/lib_protocol/baking.ml +++ b/src/proto_alpha/lib_protocol/baking.ml @@ -63,7 +63,7 @@ let bonus_baking_reward ctxt level ~attestation_power = (* TODO ABAAB : only works if flag is false *) let attestation_power = Attestation_power.get ctxt level attestation_power in let consensus_threshold_size = - Constants.consensus_threshold_size ctxt |> Int64.of_int + Attestation_power.consensus_threshold ctxt level |> Int64.of_int in let* baking_reward_bonus_per_slot = Delegate.Rewards.baking_reward_bonus_per_slot ctxt diff --git a/src/proto_alpha/lib_protocol/consensus_parameters_storage.ml b/src/proto_alpha/lib_protocol/consensus_parameters_storage.ml new file mode 100644 index 000000000000..22361c7490ec --- /dev/null +++ b/src/proto_alpha/lib_protocol/consensus_parameters_storage.ml @@ -0,0 +1,17 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +let check_all_bakers_attest_at_level ctxt level = + match Constants_storage.all_bakers_attest_activation_level ctxt with + | None -> false + | Some act_level -> Raw_level_repr.(level.Level_repr.level >= act_level) + +let consensus_threshold ctxt _level = + Constants_storage.consensus_threshold_size ctxt + +let consensus_committee ctxt _level = + Constants_storage.consensus_committee_size ctxt diff --git a/src/proto_alpha/lib_protocol/consensus_parameters_storage.mli b/src/proto_alpha/lib_protocol/consensus_parameters_storage.mli new file mode 100644 index 000000000000..b5c1094c95a9 --- /dev/null +++ b/src/proto_alpha/lib_protocol/consensus_parameters_storage.mli @@ -0,0 +1,14 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** [check_all_bakers_attest_at_level ctxt level] checks that at the given + level, all bakers were allowed (and expected) to attest. *) +val check_all_bakers_attest_at_level : Raw_context.t -> Level_repr.t -> bool + +val consensus_threshold : Raw_context.t -> Level_repr.t -> int + +val consensus_committee : Raw_context.t -> Level_repr.t -> int 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 a8f7b770ec59..c22c88e7ab55 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml @@ -210,7 +210,7 @@ let check_and_reset_delegate_participation ctxt delegate = Level_repr.first_level_in_cycle_from_eras ~cycle_eras current_cycle in let all_bakers_attest_enabled = - Delegate_sampler.check_all_bakers_attest_at_level + Consensus_parameters_storage.check_all_bakers_attest_at_level ctxt first_level_of_cycle in 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 bfe77f20079d..fa4d610f9e7d 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli @@ -32,7 +32,7 @@ (** 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. *) + wrt total active stake. *) val expected_slots_for_given_active_stake : Raw_context.t -> total_active_stake_weight:int64 -> diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.ml b/src/proto_alpha/lib_protocol/delegate_sampler.ml index 39dffc1f2851..b069653747c4 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.ml +++ b/src/proto_alpha/lib_protocol/delegate_sampler.ml @@ -148,11 +148,6 @@ module Random = struct return (c, pk) end -let check_all_bakers_attest_at_level ctxt level = - match Constants_storage.all_bakers_attest_activation_level ctxt with - | None -> false - | Some act_level -> Raw_level_repr.(level.Level_repr.level >= act_level) - let slot_owner c level slot = Random.owner c level (Slot_repr.to_int slot) let baking_rights_owner c (level : Level_repr.t) ~round = diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.mli b/src/proto_alpha/lib_protocol/delegate_sampler.mli index 3163ad43ba44..13a507807a26 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.mli +++ b/src/proto_alpha/lib_protocol/delegate_sampler.mli @@ -93,10 +93,6 @@ val attesting_rights_count : Level_repr.t -> (Raw_context.t * int Signature.Public_key_hash.Map.t) tzresult Lwt.t -(** [check_all_bakers_attest_at_level ctxt level] checks that at the given - level, all bakers were allowed (and expected) to attest. *) -val check_all_bakers_attest_at_level : Raw_context.t -> Level_repr.t -> bool - val cleanup_values_for_protocol_t : Raw_context.t -> previous_consensus_rights_delay:int -> diff --git a/src/proto_alpha/lib_protocol/dune b/src/proto_alpha/lib_protocol/dune index 9d8c157e2fc0..bc02145ac528 100644 --- a/src/proto_alpha/lib_protocol/dune +++ b/src/proto_alpha/lib_protocol/dune @@ -163,6 +163,7 @@ Global_constants_costs Ticket_hash_builder Constants_storage + Consensus_parameters_storage Level_storage Cycle_storage Nonce_storage @@ -457,6 +458,7 @@ global_constants_costs.ml global_constants_costs.mli ticket_hash_builder.ml ticket_hash_builder.mli constants_storage.ml constants_storage.mli + consensus_parameters_storage.ml consensus_parameters_storage.mli level_storage.ml level_storage.mli cycle_storage.ml cycle_storage.mli nonce_storage.ml nonce_storage.mli @@ -753,6 +755,7 @@ global_constants_costs.ml global_constants_costs.mli ticket_hash_builder.ml ticket_hash_builder.mli constants_storage.ml constants_storage.mli + consensus_parameters_storage.ml consensus_parameters_storage.mli level_storage.ml level_storage.mli cycle_storage.ml cycle_storage.mli nonce_storage.ml nonce_storage.mli @@ -1033,6 +1036,7 @@ global_constants_costs.ml global_constants_costs.mli ticket_hash_builder.ml ticket_hash_builder.mli constants_storage.ml constants_storage.mli + consensus_parameters_storage.ml consensus_parameters_storage.mli level_storage.ml level_storage.mli cycle_storage.ml cycle_storage.mli nonce_storage.ml nonce_storage.mli diff --git a/src/proto_alpha/lib_protocol/validate.ml b/src/proto_alpha/lib_protocol/validate.ml index 3b008427eb56..2856cbbab89c 100644 --- a/src/proto_alpha/lib_protocol/validate.ml +++ b/src/proto_alpha/lib_protocol/validate.ml @@ -4024,7 +4024,10 @@ let check_attestation_power vi bs = return Compare.Int32.(level_position_in_protocol > 1l) in if are_attestations_required then - let required = Constants.consensus_threshold_size vi.ctxt |> Int64.of_int in + let required = + Attestation_power.consensus_threshold vi.ctxt vi.current_level + |> Int64.of_int + in (* TODO ABAAB : required should depend on the flag *) let provided = Attestation_power.get vi.ctxt vi.current_level bs.attestation_power @@ -4076,7 +4079,8 @@ let check_preattestation_round_and_power vi vs round = in (* TODO ABAAB : threshold should depend on abaab flag *) let consensus_threshold = - Constants.consensus_threshold_size vi.ctxt |> Int64.of_int + Attestation_power.consensus_threshold vi.ctxt vi.current_level + |> Int64.of_int in let total_attesting_power = Attestation_power.get vi.ctxt vi.current_level total_attesting_power -- GitLab From d8faa6cbbdd3a054566001e5b680d1e288bfcf7a Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 6 Aug 2025 16:58:43 +0200 Subject: [PATCH 2/4] Proto: avoid consensus_threshold_size direct call from constants This value will depend on the level. Correct uses of this constant have been commented. Most uses were in the baker, so an update to the Validators RPC has been made. Now, the validators are regrouped by level, and level data like the consensus threshold is also given (this avoids some redundant information about the level being sent through the RPC for every delegate. This level field was also never used in the baker anyways?). This is a breaking change for the RPC btw --- docs/protocols/alpha.rst | 11 ++- .../lib_delegate/baking_actions.ml | 3 +- src/proto_alpha/lib_delegate/baking_lib.ml | 12 +-- .../lib_delegate/baking_scheduling.ml | 28 ++++--- src/proto_alpha/lib_delegate/baking_state.ml | 80 +++++++++++-------- src/proto_alpha/lib_delegate/baking_state.mli | 3 + .../lib_delegate/baking_state_types.ml | 1 - .../lib_delegate/baking_state_types.mli | 3 +- .../client_baking_denunciation.ml | 27 ++++--- .../lib_delegate/state_transitions.ml | 3 +- src/proto_alpha/lib_plugin/RPC.ml | 67 ++++++++++++---- .../lib_protocol/delegate_rewards.ml | 3 + .../lib_protocol/test/helpers/context.ml | 32 +++++--- .../lib_protocol/test/helpers/context.mli | 6 +- .../integration/consensus/test_aggregate.ml | 2 +- .../consensus/test_double_attestation.ml | 4 +- .../consensus/test_double_preattestation.ml | 2 +- 17 files changed, 187 insertions(+), 100 deletions(-) diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index 0231d358d6d0..c992bc6bf9f2 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -30,7 +30,7 @@ Michelson --------- - A new instruction named ``INDEX_ADDRESS`` has been added, it - provides a unique identifier of type ``nat`` for values + provides a unique identifier of type ``nat`` for values of type ``address``, stored in the context. (MR :gl:`!18866`) Gas improvements @@ -39,6 +39,15 @@ Gas improvements Breaking Changes ---------------- +- Updated ``GET + /chains//blocks//helpers/validators`` to group delegates by level. + The returned list contains one element for each queried level (by default, only the current level), + and contains three fields: the ``level`` itself, the ``consensus_threshold`` required for the current + level, and ``delegates`` which is the list of validators for that level. Each element of this last + list contains the fields present in the previous version of this RPC: ``delegate``, ``slots``, + ``consensus_key``, and ``companion_key`` (optional). + (MR :gl:`!18931`) + RPC Changes ----------- diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index 8ce7ed7d17dd..50db3b504897 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -1016,8 +1016,9 @@ let inject_block ?(force_injection = false) ?(asynchronous = true) state return new_state let prepare_waiting_for_quorum state = + (* TODO ABAAB *) let consensus_threshold = - state.global_state.constants.parametric.consensus_threshold_size + Delegate_slots.consensus_threshold state.level_state.delegate_slots in let get_slot_voting_power ~slot = Delegate_slots.voting_power state.level_state.delegate_slots ~slot diff --git a/src/proto_alpha/lib_delegate/baking_lib.ml b/src/proto_alpha/lib_delegate/baking_lib.ml index ccfe3895e162..7768367bb97d 100644 --- a/src/proto_alpha/lib_delegate/baking_lib.ml +++ b/src/proto_alpha/lib_delegate/baking_lib.ml @@ -348,10 +348,11 @@ let propose_at_next_level ~minimal_timestamp state = let attestation_quorum state = let power, attestations = state_attesting_power state in - if - Compare.Int.( - power >= state.global_state.constants.parametric.consensus_threshold_size) - then Some (power, attestations) + (* TODO ABAAB *) + let consensus_threshold = + Delegate_slots.consensus_threshold state.level_state.delegate_slots + in + if Compare.Int.(power >= consensus_threshold) then Some (power, attestations) else None (* Here's the sketch of the algorithm: @@ -708,8 +709,9 @@ let rec baking_minimal_timestamp ~count state own_attestations.unsigned_consensus_votes |> attestations_attesting_power state in + (* TODO ABAAB *) let consensus_threshold = - state.global_state.constants.parametric.consensus_threshold_size + Delegate_slots.consensus_threshold state.level_state.delegate_slots in let* () = if Compare.Int.(total_voting_power < consensus_threshold) then diff --git a/src/proto_alpha/lib_delegate/baking_scheduling.ml b/src/proto_alpha/lib_delegate/baking_scheduling.ml index 3a65c8616a61..4e147b5ca17e 100644 --- a/src/proto_alpha/lib_delegate/baking_scheduling.ml +++ b/src/proto_alpha/lib_delegate/baking_scheduling.ml @@ -933,19 +933,27 @@ let try_resolve_consensus_keys cctxt key = ~consensus_keys:[pkh] in match attesting_rights with - | Error _ | Ok [] -> try_find_delegate_key (head_offset - 1) + | Error _ | Ok [Plugin.RPC.Validators.{delegates = []; _}] -> + try_find_delegate_key (head_offset - 1) | Ok - (Plugin.RPC.Validators. - { - delegate; - level = _; - consensus_key = _; - companion_key = _; - slots = _; - } - :: _) -> + Plugin.RPC.Validators. + [ + { + delegates = + { + delegate; + consensus_key = _; + companion_key = _; + slots = _; + } + :: _; + _; + }; + ] -> (* The primary registered key as delegate found. Return it. *) return delegate + | Ok (_ :: _ :: _) | Ok [] -> assert false + (* we query only one level, the returned list length must be 1 *) in try_find_delegate_key levels_to_inspect diff --git a/src/proto_alpha/lib_delegate/baking_state.ml b/src/proto_alpha/lib_delegate/baking_state.ml index c5633cb2fd29..0521419a28c3 100644 --- a/src/proto_alpha/lib_delegate/baking_state.ml +++ b/src/proto_alpha/lib_delegate/baking_state.ml @@ -149,6 +149,7 @@ module Delegate_slots = struct non-first-slot operations from the mempool because this check is skipped in the mempool to increase its speed; the baker can and should ignore such operations. *) + consensus_threshold : int; } let own_delegates slots = slots.own_delegates @@ -169,6 +170,8 @@ module Delegate_slots = struct let voting_power slots ~slot = SlotMap.find slot slots.all_delegate_voting_power + + let consensus_threshold {consensus_threshold; _} = consensus_threshold end type delegate_slots = Delegate_slots.t @@ -935,38 +938,51 @@ let may_load_attestable_data state = let delegate_slots attesting_rights delegates = let open Lwt_syntax in let known_keys = Key.Set.of_list delegates in - let* own_delegate_first_slots, own_delegate_slots, all_delegate_voting_power = - Lwt_list.fold_left_s - (fun (own_list, own_map, all_map) validator -> - let {Plugin.RPC.Validators.slots; _} = validator in - let first_slot = Stdlib.List.hd slots in - let attesting_power = List.length slots in - let all_map = SlotMap.add first_slot attesting_power all_map in - let* own_list, own_map = - let* delegate_opt = Delegate.of_validator ~known_keys validator in - match delegate_opt with - | None -> return (own_list, own_map) - | Some delegate -> - let attesting_slot = {delegate; first_slot; attesting_power} in - return - ( attesting_slot :: own_list, - List.fold_left - (fun own_map slot -> - SlotMap.add slot attesting_slot own_map) - own_map - slots ) - in - return (own_list, own_map, all_map)) - ([], SlotMap.empty, SlotMap.empty) - attesting_rights - in - return - Delegate_slots. - { - own_delegates = own_delegate_first_slots; - own_delegate_slots; - all_delegate_voting_power; - } + match attesting_rights with + | [] | _ :: _ :: _ -> assert false + | [ + { + Plugin.RPC.Validators.level = _; + consensus_threshold; + delegates = attesting_rights; + }; + ] -> + let* ( own_delegate_first_slots, + own_delegate_slots, + all_delegate_voting_power ) = + Lwt_list.fold_left_s + (fun (own_list, own_map, all_map) validator -> + let {Plugin.RPC.Validators.slots; _} = validator in + let first_slot = Stdlib.List.hd slots in + let attesting_power = List.length slots in + let all_map = SlotMap.add first_slot attesting_power all_map in + let* own_list, own_map = + let* delegate_opt = Delegate.of_validator ~known_keys validator in + match delegate_opt with + | None -> return (own_list, own_map) + | Some delegate -> + let attesting_slot = + {delegate; first_slot; attesting_power} + in + return + ( attesting_slot :: own_list, + List.fold_left + (fun own_map slot -> + SlotMap.add slot attesting_slot own_map) + own_map + slots ) + in + return (own_list, own_map, all_map)) + ([], SlotMap.empty, SlotMap.empty) + attesting_rights + in + return + { + Delegate_slots.own_delegates = own_delegate_first_slots; + own_delegate_slots; + all_delegate_voting_power; + consensus_threshold; + } let compute_delegate_slots (cctxt : Protocol_client_context.full) ?(block = `Head 0) ~level ~chain delegates = diff --git a/src/proto_alpha/lib_delegate/baking_state.mli b/src/proto_alpha/lib_delegate/baking_state.mli index 6dbfc7eb446c..c537547dcb88 100644 --- a/src/proto_alpha/lib_delegate/baking_state.mli +++ b/src/proto_alpha/lib_delegate/baking_state.mli @@ -67,6 +67,9 @@ module Delegate_slots : sig (** Returns the slot with the smallest index, along with its associated delegate. Returns [None] if the map is empty. *) val min_slot : t -> (Slot.t * delegate_slot) option + + (** Returns the consensus threshold at the level the slots were computed *) + val consensus_threshold : t -> int end type delegate_slots = Delegate_slots.t diff --git a/src/proto_alpha/lib_delegate/baking_state_types.ml b/src/proto_alpha/lib_delegate/baking_state_types.ml index 87cb0194d202..2904339ddddd 100644 --- a/src/proto_alpha/lib_delegate/baking_state_types.ml +++ b/src/proto_alpha/lib_delegate/baking_state_types.ml @@ -183,7 +183,6 @@ module Delegate = struct companion_key = companion_bls_pkh_opt; delegate = manager_pkh; slots = _; - level = _; } = let open Lwt_syntax in match Key.Set.find_pkh consensus_pkh known_keys with diff --git a/src/proto_alpha/lib_delegate/baking_state_types.mli b/src/proto_alpha/lib_delegate/baking_state_types.mli index 007e62c55c05..4d6206ab6055 100644 --- a/src/proto_alpha/lib_delegate/baking_state_types.mli +++ b/src/proto_alpha/lib_delegate/baking_state_types.mli @@ -122,5 +122,6 @@ module Delegate : sig in [known_keys], emits an error event but nevertheless returns a {!t} where [companion_key = None]. (This function is in Lwt to be able to emit this event.) *) - val of_validator : known_keys:Key.Set.t -> RPC.Validators.t -> t option Lwt.t + val of_validator : + known_keys:Key.Set.t -> RPC.Validators.delegate -> t option Lwt.t end diff --git a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml index d2b1a462feb7..57074b44bebe 100644 --- a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml +++ b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml @@ -187,22 +187,25 @@ let add_consensus_operation consensus_key op_kind recorded_operation map = let get_validator_rights state cctxt level = let open Lwt_result_syntax in match Validators_cache.find_opt state.validators_rights level with - | None -> + | None -> ( let* validators = Plugin.RPC.Validators.get cctxt (cctxt#chain, `Head 0) ~levels:[level] in - let validators = - List.fold_left - (fun acc ({consensus_key; slots; _} : RPC.Validators.t) -> + match validators with + | [{delegates = validators; _}] -> + let validators = List.fold_left - (fun acc slot -> Slot.Map.add slot consensus_key acc) - acc - slots) - Slot.Map.empty - validators - in - Validators_cache.replace state.validators_rights level validators ; - return validators + (fun acc ({consensus_key; slots; _} : RPC.Validators.delegate) -> + List.fold_left + (fun acc slot -> Slot.Map.add slot consensus_key acc) + acc + slots) + Slot.Map.empty + validators + in + Validators_cache.replace state.validators_rights level validators ; + return validators + | _ -> assert false) | Some t -> return t let events_of_kind op_kind = diff --git a/src/proto_alpha/lib_delegate/state_transitions.ml b/src/proto_alpha/lib_delegate/state_transitions.ml index 0c62bebb4d13..22b8c697110e 100644 --- a/src/proto_alpha/lib_delegate/state_transitions.ml +++ b/src/proto_alpha/lib_delegate/state_transitions.ml @@ -222,8 +222,9 @@ let extract_pqc state (new_proposal : proposal) = 0 prequorum.preattestations in + (* TODO ABAAB *) let consensus_threshold = - state.global_state.constants.parametric.consensus_threshold_size + Delegate_slots.consensus_threshold state.level_state.delegate_slots in if Compare.Int.(voting_power >= consensus_threshold) then Some (prequorum.preattestations, prequorum.round) diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index a23f4b4ea8af..69ec4e5757b4 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -3974,28 +3974,44 @@ module Attestation_rights = struct end module Validators = struct - type t = { - level : Raw_level.t; + type delegate = { delegate : Signature.Public_key_hash.t; consensus_key : Signature.public_key_hash; companion_key : Bls.Public_key_hash.t option; slots : Slot.t list; } - let encoding = + type t = { + level : Raw_level.t; + consensus_threshold : int; + delegates : delegate list; + } + + let delegate_encoding = let open Data_encoding in conv - (fun {level; delegate; consensus_key; companion_key; slots} -> - (level, delegate, slots, consensus_key, companion_key)) - (fun (level, delegate, slots, consensus_key, companion_key) -> - {level; delegate; consensus_key; companion_key; slots}) - (obj5 - (req "level" Raw_level.encoding) + (fun {delegate; consensus_key; companion_key; slots} -> + (delegate, slots, consensus_key, companion_key)) + (fun (delegate, slots, consensus_key, companion_key) -> + {delegate; consensus_key; companion_key; slots}) + (obj4 (req "delegate" Signature.Public_key_hash.encoding) (req "slots" (list Slot.encoding)) (req "consensus_key" Signature.Public_key_hash.encoding) (opt "companion_key" Bls.Public_key_hash.encoding)) + let encoding = + let open Data_encoding in + conv + (fun {level; consensus_threshold; delegates} -> + (level, consensus_threshold, delegates)) + (fun (level, consensus_threshold, delegates) -> + {level; consensus_threshold; delegates}) + (obj3 + (req "level" Raw_level.encoding) + (req "consensus_threshold" int31) + (req "delegates" (list delegate_encoding))) + module S = struct open Data_encoding @@ -4036,7 +4052,7 @@ module Validators = struct path end - let add_attestation_slots_at_level (ctxt, acc) level = + let attestation_slots_at_level ctxt level = let open Lwt_result_syntax in let+ ctxt, rights = Baking.attesting_rights ctxt level in let aggregate_attestation = Constants.aggregate_attestation ctxt in @@ -4048,10 +4064,9 @@ module Validators = struct | Bls _ when aggregate_attestation -> companion_key | _ -> None in - {level = level.level; delegate; consensus_key; companion_key; slots} - :: acc) + {delegate; consensus_key; companion_key; slots} :: acc) rights - acc ) + [] ) let register () = let open Lwt_result_syntax in @@ -4061,10 +4076,25 @@ module Validators = struct in let+ _ctxt, rights = List.fold_left_es - add_attestation_slots_at_level + (fun (ctxt, acc) level -> + let consensus_threshold = + Attestation_power.consensus_threshold ctxt level + in + let* ctxt, delegates = attestation_slots_at_level ctxt level in + return + ( ctxt, + ( {level = level.level; consensus_threshold; delegates = []}, + delegates ) + :: acc )) (ctxt, []) (List.rev levels) in + let filter_with f list = + List.map + (fun (level_info, delegates) -> + (level_info, List.filter f delegates)) + list + in let rights = match q.delegates with | [] -> rights @@ -4074,7 +4104,7 @@ module Validators = struct (Signature.Public_key_hash.equal p.delegate) delegates in - List.filter is_requested rights + filter_with is_requested rights in let rights = match q.consensus_keys with @@ -4085,7 +4115,12 @@ module Validators = struct (Signature.Public_key_hash.equal p.consensus_key) delegates in - List.filter is_requested rights + filter_with is_requested rights + in + let rights = + List.map + (fun (level_info, delegates) -> {level_info with delegates}) + rights in rights) diff --git a/src/proto_alpha/lib_protocol/delegate_rewards.ml b/src/proto_alpha/lib_protocol/delegate_rewards.ml index c020ca33982e..510ad06937d1 100644 --- a/src/proto_alpha/lib_protocol/delegate_rewards.ml +++ b/src/proto_alpha/lib_protocol/delegate_rewards.ml @@ -115,6 +115,9 @@ module M = struct in let base_rewards = match reward_kind with + (* Since these the "_per_slot" rewards are given per slot, they do not depend on whether + all bakers attest or not. We can use the constants directly. *) + (* TODO ABAAB: baking bonus and attesting rewards without slots *) | Baking_reward_bonus_per_slot -> let bonus_committee_size = csts.consensus_committee_size - csts.consensus_threshold_size diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.ml b/src/proto_alpha/lib_protocol/test/helpers/context.ml index ce9dffd30a49..09b7d940790d 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/context.ml @@ -135,15 +135,19 @@ let rpc_ctxt = | I bl -> Incremental.rpc_ctxt#call_proto_service3 s bl a b c q i end -type attester = Plugin.RPC.Validators.t = { - level : Raw_level.t; +type attester = Plugin.RPC.Validators.delegate = { delegate : Signature.public_key_hash; consensus_key : Signature.public_key_hash; companion_key : Signature.Bls.Public_key_hash.t option; slots : Slot.t list; } -let get_attesters ctxt = Plugin.RPC.Validators.get rpc_ctxt ctxt +let get_attesters ctxt = + let open Lwt_result_syntax in + let* attesters = Plugin.RPC.Validators.get rpc_ctxt ctxt in + match attesters with + | [{delegates; _}] -> return delegates + | _ -> assert false let get_attester ?manager_pkh ctxt = let open Lwt_result_syntax in @@ -165,7 +169,7 @@ let get_first_different_attesters ctxt = let get_attester_n ctxt n = let open Lwt_result_syntax in - let+ attesters = Plugin.RPC.Validators.get rpc_ctxt ctxt in + let+ attesters = get_attesters ctxt in let attester = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth attesters n in @@ -190,14 +194,17 @@ let get_attesting_power_for_delegate ctxt ?level pkh = let open Lwt_result_syntax in let levels = Option.map (fun level -> [level]) level in let* attesters = Plugin.RPC.Validators.get rpc_ctxt ?levels ctxt in - let rec find_slots_for_delegate = function - | [] -> return 0 - | {Plugin.RPC.Validators.delegate; slots; _} :: t -> - if Signature.Public_key_hash.equal delegate pkh then - return (List.length slots) - else find_slots_for_delegate t - in - find_slots_for_delegate attesters + match attesters with + | [{delegates = attesters; _}] -> + let rec find_slots_for_delegate = function + | [] -> return 0 + | {Plugin.RPC.Validators.delegate; slots; _} :: t -> + if Signature.Public_key_hash.equal delegate pkh then + return (List.length slots) + else find_slots_for_delegate t + in + find_slots_for_delegate attesters + | _ -> assert false let get_cumulated_attesting_power_for_delegate ctxt ~levels pkh = let open Lwt_result_syntax in @@ -284,6 +291,7 @@ let get_bonus_reward ctxt ~attesting_power = let* {Constants.parametric = {consensus_threshold_size; _} as csts; _} = get_constants ctxt in + (* TODO ABAAB: will depend on level/feature flag *) let*?@ baking_reward_bonus_per_slot = Delegate.Rewards.For_RPC.reward_from_constants csts diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.mli b/src/proto_alpha/lib_protocol/test/helpers/context.mli index 9140e1c1d5b3..c5f56a26465a 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/context.mli @@ -39,8 +39,7 @@ val pred_branch : t -> Block_hash.t val get_level : t -> Raw_level.t tzresult (** A delegate's keys and attesting slots at a given level. *) -type attester = Plugin.RPC.Validators.t = { - level : Raw_level.t; +type attester = Plugin.RPC.Validators.delegate = { delegate : Signature.public_key_hash; consensus_key : Signature.public_key_hash; companion_key : Signature.Bls.Public_key_hash.t option; @@ -60,8 +59,7 @@ val get_attesters : t -> attester list tzresult Lwt.t val get_attester : ?manager_pkh:public_key_hash -> t -> attester tzresult Lwt.t (** Return the two first elements of the list returns by [get_attesters]. *) -val get_first_different_attesters : - t -> (Plugin.RPC.Validators.t * Plugin.RPC.Validators.t) tzresult Lwt.t +val get_first_different_attesters : t -> (attester * attester) tzresult Lwt.t (** Return the [n]th element of the list returns by [get_attesters]. *) val get_attester_n : t -> int -> (public_key_hash * Slot.t list) tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_aggregate.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_aggregate.ml index 1e0e14232e75..0fdaf14461f0 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_aggregate.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_aggregate.ml @@ -103,7 +103,7 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters let* () = let voting_power = List.fold_left - (fun acc (delegate : RPC.Validators.t) -> + (fun acc (delegate : RPC.Validators.delegate) -> List.length delegate.slots + acc) 0 attesters diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_attestation.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_attestation.ml index 507a6062bc7b..9391752bc858 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_attestation.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_attestation.ml @@ -263,7 +263,7 @@ let test_different_slots () = WithExceptions.Option.get ~loc:__LOC__ (List.find_map - (fun (attester : RPC.Validators.t) -> + (fun (attester : RPC.Validators.delegate) -> match attester.slots with | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) | _ -> None) @@ -987,7 +987,7 @@ let different_slots_under_feature_flag () = WithExceptions.Option.get ~loc:__LOC__ (List.find_map - (fun (attester : RPC.Validators.t) -> + (fun (attester : RPC.Validators.delegate) -> match attester.slots with | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) | _ -> None) diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_preattestation.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_preattestation.ml index 471ec9d11086..939cd06108af 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_preattestation.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_preattestation.ml @@ -407,7 +407,7 @@ end = struct WithExceptions.Option.get ~loc:__LOC__ (List.find_map - (fun (attester : RPC.Validators.t) -> + (fun (attester : RPC.Validators.delegate) -> match attester.slots with | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) | _ -> None) -- GitLab From 833d541a02752f40e53cb2754bb56c33e5997085 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 7 Aug 2025 13:50:17 +0200 Subject: [PATCH 3/4] Proto: fix tests Adapting for the breaking changes of the RPC --- tezt/lib_tezos/operation_core.ml | 34 ++++++-- tezt/lib_tezos/operation_core.mli | 12 ++- tezt/tests/baker_test.ml | 8 +- tezt/tests/companion_key.ml | 41 ++++++++-- tezt/tests/dal.ml | 131 ++++++++++++++++++++++-------- tezt/tests/double_consensus.ml | 24 ++++-- tezt/tests/prevalidator.ml | 14 ++-- 7 files changed, 197 insertions(+), 67 deletions(-) diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index 9b48ad2b0f7c..d63269f8ba7f 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -507,31 +507,45 @@ module Consensus = struct in inject ?request ?force ?error ~protocol op client - let get_slots ~level client = + let get_slots ~level ~protocol client = let* rpc_json = Client.RPC.call client @@ RPC.get_chain_block_helper_validators ~level () in let open JSON in + let list = + if Protocol.number protocol >= 024 then + match as_list rpc_json with + | [] | _ :: _ :: _ -> assert false + | [rpc_json] -> as_list (rpc_json |-> "delegates") + else as_list rpc_json + in return @@ List.map (fun json -> let delegate = json |-> "delegate" |> as_string in let slots = json |-> "slots" |> as_list |> List.map as_int in (delegate, slots)) - (as_list rpc_json) + list - let get_slots_by_consensus_key ~level client = + let get_slots_by_consensus_key ~level ~protocol client = let* rpc_json = Client.RPC.call client @@ RPC.get_chain_block_helper_validators ~level () in let open JSON in + let list = + if Protocol.number protocol >= 024 then + match as_list rpc_json with + | [] | _ :: _ :: _ -> assert false + | [rpc_json] -> as_list (rpc_json |-> "delegates") + else as_list rpc_json + in return @@ List.map (fun json -> let consensus_key = json |-> "consensus_key" |> as_string in let slots = json |-> "slots" |> as_list |> List.map as_int in (consensus_key, slots)) - (as_list rpc_json) + list let first_slot ~slots (delegate : Account.key) = match List.assoc_opt delegate.public_key_hash slots with @@ -720,7 +734,7 @@ module Anonymous = struct "vh3cjL2UL3p73CHhSLpAcLvB9obU9jSrRsu1Y9tg85os3i3akAig" let make_double_consensus_evidence_with_distinct_bph ~kind ~misbehaviour_level - ~misbehaviour_round ~culprit client = + ~misbehaviour_round ~culprit ~protocol client = let* slots = Client.RPC.call_via_endpoint client @@ RPC.get_chain_block_helper_validators @@ -729,8 +743,14 @@ module Anonymous = struct () in let slot = - JSON.( - slots |> as_list |> List.hd |-> "slots" |> as_list |> List.hd |> as_int) + if Protocol.number protocol >= 024 then + JSON.( + slots |> as_list |> List.hd |-> "delegates" |> as_list |> List.hd + |-> "slots" |> as_list |> List.hd |> as_int) + else + JSON.( + slots |> as_list |> List.hd |-> "slots" |> as_list |> List.hd + |> as_int) in let mk_consensus_op block_payload_hash = let consensus = diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index 8026409765fe..5777ea7e89cf 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -313,11 +313,18 @@ module Consensus : sig [GET /chains//blocks//helpers/validators] RPC. Returns an association list that maps a public key hash to the owned slot list *) - val get_slots : level:int -> Client.t -> (string * int list) list Lwt.t + val get_slots : + level:int -> + protocol:Protocol.t -> + Client.t -> + (string * int list) list Lwt.t (** Same as [get_slots] but maps a consensus key to the owned slot list. *) val get_slots_by_consensus_key : - level:int -> Client.t -> (string * int list) list Lwt.t + level:int -> + protocol:Protocol.t -> + Client.t -> + (string * int list) list Lwt.t (** Returns the first slot of the provided delegate in the [slots] association list that describes all attestation rights at some level. @@ -438,6 +445,7 @@ module Anonymous : sig misbehaviour_level:int -> misbehaviour_round:int -> culprit:Account.key -> + protocol:Protocol.t -> Client.t -> t Lwt.t end diff --git a/tezt/tests/baker_test.ml b/tezt/tests/baker_test.ml index 5c64d95ba7dd..1109e62113de 100644 --- a/tezt/tests/baker_test.ml +++ b/tezt/tests/baker_test.ml @@ -801,7 +801,7 @@ let prequorum_check_levels = return @@ JSON.(json |-> "payload_hash" |> as_string) in let preattest_for ~delegate level = - let* slots = Operation.Consensus.get_slots ~level client in + let* slots = Operation.Consensus.get_slots ~level ~protocol client in let slot = Operation.Consensus.first_slot ~slots delegate in let* _ = Operation.Consensus.preattest_for @@ -961,7 +961,10 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = (* BLS consensus keys are now activated. We feed the node with just enough consensus operations for the baker to bake a block at [base_level + 1]. *) let* slots = - Operation.Consensus.get_slots_by_consensus_key ~level:base_level client + Operation.Consensus.get_slots_by_consensus_key + ~level:base_level + ~protocol + client in let* round = fetch_round client in let* branch = @@ -1060,6 +1063,7 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = let* slots = Operation.Consensus.get_slots_by_consensus_key ~level:(base_level + 1) + ~protocol client in let* round = fetch_round client in diff --git a/tezt/tests/companion_key.ml b/tezt/tests/companion_key.ml index 568978efcf8c..095468d95bb4 100644 --- a/tezt/tests/companion_key.ml +++ b/tezt/tests/companion_key.ml @@ -44,7 +44,8 @@ let companion_key_typ : companion_key Check.typ = (active_companion_key, pending_companion_keys)) (tuple2 (option string) (list (tuple2 int string)))) -let get_validators_companion_key ?level (delegate : Account.key) client = +let get_validators_companion_key ?level ~protocol (delegate : Account.key) + client = let* json = Client.RPC.call client @@ RPC.get_chain_block_helper_validators @@ -52,16 +53,23 @@ let get_validators_companion_key ?level (delegate : Account.key) client = ~delegate:delegate.public_key_hash () in - let companion_key = JSON.(json |=> 0 |-> "companion_key" |> as_string_opt) in + let companion_key = + if Protocol.number protocol >= 024 then + JSON.( + json |=> 0 |-> "delegates" |=> 0 |-> "companion_key" |> as_string_opt) + else JSON.(json |=> 0 |-> "companion_key" |> as_string_opt) + in Log.info ~color:Log.Color.FG.green "companion_key = %s" (match companion_key with Some ck -> ck | None -> "None") ; return companion_key -let check_validators_companion_key ~__LOC__ ?level (delegate : Account.key) - client ~expected = - let* companion_key = get_validators_companion_key ?level delegate client in +let check_validators_companion_key ~__LOC__ ?level ~protocol + (delegate : Account.key) client ~expected = + let* companion_key = + get_validators_companion_key ?level ~protocol delegate client + in Check.( (companion_key = expected) (option string) @@ -135,7 +143,7 @@ let init_node_and_client ~protocol = in return (node, client) -let check_active_companion_and_consensus_keys delegate ~companion_key +let check_active_companion_and_consensus_keys ~protocol delegate ~companion_key ~consensus_key client = Log.info "Checking keys are activated" ; let* () = @@ -149,12 +157,18 @@ let check_active_companion_and_consensus_keys delegate ~companion_key check_companion_key ~__LOC__ delegate ~expected_active:companion_key client in let* () = - check_validators_companion_key ~__LOC__ delegate ~expected:None client + check_validators_companion_key + ~__LOC__ + ~protocol + delegate + ~expected:None + client in let* current_level = get_current_level client in let* () = check_validators_companion_key ~__LOC__ + ~protocol ~level:(current_level.level + 1) delegate ~expected:(Some companion_key.public_key_hash) @@ -200,6 +214,7 @@ let test_update_companion_key = let* () = bake_n_cycles (consensus_rights_delay + 1) client in let* () = check_active_companion_and_consensus_keys + ~protocol delegate ~companion_key:companion_key_bls ~consensus_key:consensus_key_bls @@ -241,12 +256,18 @@ let test_update_companion_key_for_non_tz4_delegate = client in let* () = - check_validators_companion_key ~__LOC__ delegate ~expected:None client + check_validators_companion_key + ~__LOC__ + ~protocol + delegate + ~expected:None + client in let* current_level = get_current_level client in let* () = check_validators_companion_key ~__LOC__ + ~protocol ~level:(current_level.level + 1) delegate ~expected:None @@ -303,6 +324,7 @@ let test_update_companion_key_for_tz4_delegate = let* () = bake_n_cycles (consensus_rights_delay + 1) client in let* () = check_active_companion_and_consensus_keys + ~protocol delegate ~companion_key:companion_key_bls ~consensus_key:delegate @@ -407,6 +429,7 @@ let test_register_keys_and_stake = let* () = bake_n_cycles (consensus_rights_delay + 1) client in let* () = check_active_companion_and_consensus_keys + ~protocol delegate ~companion_key:companion_key_bls ~consensus_key:consensus_key_bls @@ -489,6 +512,7 @@ let test_register_keys_with_proofs_and_stake = let* () = bake_n_cycles (consensus_rights_delay + 1) client in let* () = check_active_companion_and_consensus_keys + ~protocol delegate ~companion_key:companion_key_bls ~consensus_key:consensus_key_bls @@ -542,6 +566,7 @@ let test_update_keys_with_proofs = let* () = bake_n_cycles (consensus_rights_delay + 1) client in let* () = check_active_companion_and_consensus_keys + ~protocol delegate ~companion_key:companion_key_bls ~consensus_key:consensus_key_bls diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index a253927a222b..deaffcfb7dba 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -197,12 +197,16 @@ let next_level node = let* current_level = Node.get_level node in return (current_level + 1) -let check_in_TB_committee ~__LOC__ node ?(inside = true) ?level pkh = +let check_in_TB_committee ~__LOC__ ~protocol node ?(inside = true) ?level pkh = let* slots = Node.RPC.call node @@ RPC.get_chain_block_helper_validators ?level ~delegate:pkh () in - let in_committee = JSON.as_list slots <> [] in + let in_committee = + if Protocol.number protocol >= 024 then + JSON.(as_list slots |> List.hd |-> "delegates" |> as_list) <> [] + else JSON.as_list slots <> [] + in Check.( (in_committee = inside) ~__LOC__ @@ -870,8 +874,8 @@ type attestation_availability = | Bitset of bool array | No_dal_attestation -let craft_dal_attestation ?level ?round ?payload_level ~signer ~nb_slots - availability client = +let craft_dal_attestation ~protocol ?level ?round ?payload_level ~signer + ~nb_slots availability client = let dal_attestation = match availability with | Bitset bitset -> Some bitset @@ -891,7 +895,12 @@ let craft_dal_attestation ?level ?round ?payload_level ~signer ~nb_slots ~delegate:signer.Account.public_key_hash () in - match JSON.(json |> as_list) with + let slots = + if Protocol.number protocol >= 024 then + JSON.(json |> as_list |> List.hd |-> "delegates" |> as_list) + else JSON.as_list json + in + match slots with | [] -> Log.info "[craft_dal_attestation] %s not in TB committee at level %d" @@ -935,10 +944,11 @@ let craft_dal_attestation ?level ?round ?payload_level ~signer ~nb_slots ~__LOC__ "Unexpected format for get_chain_block_helper_validators RPC" -let craft_dal_attestation_exn ?level ?round ?payload_level ~signer ~nb_slots - availability client = +let craft_dal_attestation_exn ~protocol ?level ?round ?payload_level ~signer + ~nb_slots availability client = let* res = craft_dal_attestation + ~protocol ?level ?round ?payload_level @@ -955,10 +965,11 @@ let craft_dal_attestation_exn ?level ?round ?payload_level ~signer ~nb_slots signer.Account.public_key_hash | Some v -> return v -let inject_dal_attestation ?level ?round ?payload_level ?force ?error ?request - ~signer ~nb_slots availability client = +let inject_dal_attestation ~protocol ?level ?round ?payload_level ?force ?error + ?request ~signer ~nb_slots availability client = let* op_opt = craft_dal_attestation + ~protocol ?level ?round ?payload_level @@ -973,10 +984,11 @@ let inject_dal_attestation ?level ?round ?payload_level ?force ?error ?request let* oph = Operation.inject ?force ?error ?request op client in some (op, oph) -let inject_dal_attestation_exn ?level ?round ?payload_level ?force ?error - ?request ~signer ~nb_slots availability client = +let inject_dal_attestation_exn ~protocol ?level ?round ?payload_level ?force + ?error ?request ~signer ~nb_slots availability client = let* res = inject_dal_attestation + ~protocol ?level ?round ?payload_level @@ -996,12 +1008,13 @@ let inject_dal_attestation_exn ?level ?round ?payload_level ?force ?error signer.Account.public_key_hash | Some v -> return v -let inject_dal_attestations ?payload_level ?level ?round ?force ?request - ?(signers = Array.to_list Account.Bootstrap.keys) ~nb_slots availability - client = +let inject_dal_attestations ~protocol ?payload_level ?level ?round ?force + ?request ?(signers = Array.to_list Account.Bootstrap.keys) ~nb_slots + availability client = Lwt_list.filter_map_s (fun signer -> inject_dal_attestation + ~protocol ?payload_level ?level ?round @@ -1013,19 +1026,25 @@ let inject_dal_attestations ?payload_level ?level ?round ?force ?request client) signers -let inject_dal_attestations_and_bake node client ~number_of_slots indexes = +let inject_dal_attestations_and_bake ~protocol node client ~number_of_slots + indexes = let* baker = let* level = Node.get_level node in baker_for_round_zero node ~level:(level + 1) in let signers = different_delegates baker in let* _op_and_op_hash_list = - inject_dal_attestations ~signers ~nb_slots:number_of_slots indexes client + inject_dal_attestations + ~protocol + ~signers + ~nb_slots:number_of_slots + indexes + client in bake_for ~delegates:(`For [baker]) client -let inject_dal_attestation_for_assigned_shards ~nb_slots ~attested_level - ~attester_account ~attester_dal_node client = +let inject_dal_attestation_for_assigned_shards ~protocol ~nb_slots + ~attested_level ~attester_account ~attester_dal_node client = let* attestable_slots = Dal_RPC.( call attester_dal_node @@ -1036,6 +1055,7 @@ let inject_dal_attestation_for_assigned_shards ~nb_slots ~attested_level Test.fail "attester %s not in committee" attester_account.alias | Attestable_slots slots -> inject_dal_attestation + ~protocol ~level:(attested_level - 1) (Bitset (Array.of_list slots)) ~signer:attester_account @@ -1359,6 +1379,7 @@ let test_slot_management_logic protocol parameters cryptobox node client let* () = repeat (lag - 1) (fun () -> bake_for client) in let* _ = inject_dal_attestations + ~protocol ~nb_slots ~signers:[Constant.bootstrap1; Constant.bootstrap2] (Slots [1; 0]) @@ -1366,6 +1387,7 @@ let test_slot_management_logic protocol parameters cryptobox node client in let* _ = inject_dal_attestations + ~protocol ~nb_slots ~signers:[Constant.bootstrap3; Constant.bootstrap4; Constant.bootstrap5] (Slots [1]) @@ -1401,7 +1423,7 @@ let test_slot_management_logic protocol parameters cryptobox node client (** This test tests various situations related to DAL slots attestation. See the steps inside the test. *) -let test_slots_attestation_operation_behavior _protocol parameters _cryptobox +let test_slots_attestation_operation_behavior protocol parameters _cryptobox node client _bootstrap_key = (* Some helpers *) let nb_slots = parameters.Dal.Parameters.number_of_slots in @@ -1410,6 +1432,7 @@ let test_slots_attestation_operation_behavior _protocol parameters _cryptobox let attest ?payload_level ?(signer = Constant.bootstrap2) ~level () = let* _op, op_hash = inject_dal_attestation_exn + ~protocol ?payload_level ~force:true ~nb_slots @@ -1588,7 +1611,7 @@ let test_all_available_slots _protocol parameters cryptobox node client from a DAL-committee member. This test creates a new account and registers it as a baker, and bakes blocks until it reaches a level where the new account is in the TB committee but not in the DAL committee).*) -let test_slots_attestation_operation_dal_committee_membership_check _protocol +let test_slots_attestation_operation_dal_committee_membership_check protocol parameters _cryptobox node client _bootstrap_key = (* The attestation from the bootstrap account should succeed as the bootstrap node has sufficient stake to be in the DAL committee. *) @@ -1599,6 +1622,7 @@ let test_slots_attestation_operation_dal_committee_membership_check _protocol let* level = Client.level client in let* _op, `OpHash _oph = inject_dal_attestation_exn + ~protocol ~nb_slots ~level ~signer:Constant.bootstrap1 @@ -1661,10 +1685,16 @@ let test_slots_attestation_operation_dal_committee_membership_check _protocol Log.info "The new account is not in the DAL committee" ; Log.info "We check that the new account is in the Tenderbake committee" ; let* () = - check_in_TB_committee ~__LOC__ node new_account.public_key_hash ~level + check_in_TB_committee + ~__LOC__ + ~protocol + node + new_account.public_key_hash + ~level in let* _op, `OpHash _oph = inject_dal_attestation_exn + ~protocol ~error:Operation.dal_data_availibility_attester_not_in_committee ~nb_slots ~level @@ -1803,8 +1833,8 @@ let publish_store_and_wait_slot ?counter ?force ?(fee = 12_000) node client let* res = p in return (published_level, commitment, res) -let publish_store_and_attest_slot ?counter ?force ?fee client node dal_node - source ~index ~content ~attestation_lag ~number_of_slots = +let publish_store_and_attest_slot ~protocol ?counter ?force ?fee client node + dal_node source ~index ~content ~attestation_lag ~number_of_slots = let* _commitment = Helpers.publish_and_store_slot ?counter @@ -1817,7 +1847,12 @@ let publish_store_and_attest_slot ?counter ?force ?fee client node dal_node content in let* () = repeat attestation_lag (fun () -> bake_for client) in - inject_dal_attestations_and_bake node client ~number_of_slots (Slots [index]) + inject_dal_attestations_and_bake + ~protocol + node + client + ~number_of_slots + (Slots [index]) let check_get_commitment dal_node ~slot_level check_result slots_info = Lwt_list.iter_s @@ -1905,7 +1940,7 @@ let check_slot_status ~__LOC__ ?expected_status dal_node ~slot_level slots_info in Lwt_list.iter_s test slots_info -let test_dal_node_slots_headers_tracking _protocol parameters _cryptobox node +let test_dal_node_slots_headers_tracking protocol parameters _cryptobox node client dal_node = let slot_size = parameters.Dal.Parameters.cryptobox.slot_size in let number_of_slots = parameters.Dal.Parameters.number_of_slots in @@ -2045,6 +2080,7 @@ let test_dal_node_slots_headers_tracking _protocol parameters _cryptobox node in let* () = inject_dal_attestations_and_bake + ~protocol node client ~number_of_slots @@ -2541,7 +2577,12 @@ let rollup_node_applies_dal_pages protocol parameters dal_node sc_rollup_node Log.info "Step 5: attest only slots 1 and 2" ; let* () = repeat (attestation_lag - 1) (fun () -> bake_for client) in let* () = - inject_dal_attestations_and_bake node client ~number_of_slots (Slots [2; 1]) + inject_dal_attestations_and_bake + ~protocol + node + client + ~number_of_slots + (Slots [2; 1]) in let* slot_confirmed_level = Sc_rollup_node.wait_for_level @@ -2583,7 +2624,7 @@ let rollup_node_applies_dal_pages protocol parameters dal_node sc_rollup_node - At level N, publish a slot to the L1 and DAL. - Bake until [attestation_lag] blocks so the L1 attests the published slot. - Confirm that the kernel downloaded the slot and wrote the content to "/output/slot-". *) -let test_reveal_dal_page_in_fast_exec_wasm_pvm _protocol parameters dal_node +let test_reveal_dal_page_in_fast_exec_wasm_pvm protocol parameters dal_node sc_rollup_node _sc_rollup_address node client pvm_name = Log.info "Assert attestation_lag value." ; (* TODO: https://gitlab.com/tezos/tezos/-/issues/6270 @@ -2628,6 +2669,7 @@ let test_reveal_dal_page_in_fast_exec_wasm_pvm _protocol parameters dal_node let slot_content = generate_dummy_slot slot_size in let* () = publish_store_and_attest_slot + ~protocol client node dal_node @@ -7358,6 +7400,7 @@ module Tx_kernel_e2e = struct (String.length payload1) ; let* () = publish_store_and_attest_slot + ~protocol client node dal_node @@ -7375,6 +7418,7 @@ module Tx_kernel_e2e = struct (String.length payload2) ; let* () = publish_store_and_attest_slot + ~protocol client node dal_node @@ -7414,7 +7458,7 @@ module Tx_kernel_e2e = struct ~error_msg:"Expected %R, got %L") ; unit - let test_echo_kernel_e2e _protocol parameters dal_node sc_rollup_node + let test_echo_kernel_e2e protocol parameters dal_node sc_rollup_node _sc_rollup_address node client pvm_name = Log.info "Originate the echo kernel." ; let* {boot_sector; _} = @@ -7444,6 +7488,7 @@ module Tx_kernel_e2e = struct let payload = "hello" in let* () = publish_store_and_attest_slot + ~protocol client node dal_node @@ -7488,7 +7533,7 @@ module Tx_kernel_e2e = struct in Test.fail "%s" message - let test_manual_echo_kernel_for_bandwidth _protocol parameters dal_node + let test_manual_echo_kernel_for_bandwidth protocol parameters dal_node sc_rollup_node _sc_rollup_address node client pvm_name = Log.info "Originate the echo kernel." ; let config = @@ -7530,6 +7575,7 @@ module Tx_kernel_e2e = struct let payload = "hello" in let* () = publish_store_and_attest_slot + ~protocol client node dal_node @@ -8125,7 +8171,7 @@ module Refutations = struct - The refutation game is lost by the faulty rollup node. *) let scenario_with_two_rollups_a_faulty_dal_node_and_a_correct_one - ~refute_operations_priority _protocol parameters _dal_node _sc_rollup_node + ~refute_operations_priority protocol parameters _dal_node _sc_rollup_node _sc_rollup_address node client pvm_name = (* Initializing the real SRS. *) let faulty_operator_key = Constant.bootstrap4.public_key_hash in @@ -8226,6 +8272,7 @@ module Refutations = struct let* () = bake_for ~count:parameters.attestation_lag client in let* () = inject_dal_attestations_and_bake + ~protocol node client ~number_of_slots:parameters.number_of_slots @@ -8612,7 +8659,7 @@ let rollup_batches_and_publishes_optimal_dal_slots _protocol parameters dal_node (* We have a bootstrap node, a producer node and an attester node for a new attester. We check that as soon as the attester is in the DAL committee it attests. *) -let test_new_attester_attests _protocol dal_parameters _cryptobox node client +let test_new_attester_attests protocol dal_parameters _cryptobox node client dal_bootstrap = let peer_id dal_node = Dal_node.read_identity dal_node in let slot_size = dal_parameters.Dal.Parameters.cryptobox.slot_size in @@ -8780,6 +8827,7 @@ let test_new_attester_attests _protocol dal_parameters _cryptobox node client let* () = check_in_TB_committee ~__LOC__ + ~protocol node new_account.public_key_hash ~inside:false @@ -8798,6 +8846,7 @@ let test_new_attester_attests _protocol dal_parameters _cryptobox node client let* () = check_in_TB_committee ~__LOC__ + ~protocol node new_account.public_key_hash ~level:(level + 1) @@ -9166,6 +9215,7 @@ let test_inject_accusation protocol dal_parameters cryptobox node client let signer = Constant.bootstrap2 in let* attestation, _op_hash = inject_dal_attestation_exn + ~protocol ~signer ~nb_slots:number_of_slots availability @@ -9425,7 +9475,9 @@ let test_inject_accusation_aggregated_attestation nb_attesting_tz4 protocol Log.info "Inject an attestation" ; let level = publication_level + lag - 1 in (* BLS consensus keys are now activated *) - let* slots = Operation.Consensus.get_slots_by_consensus_key ~level client in + let* slots = + Operation.Consensus.get_slots_by_consensus_key ~level ~protocol client + in let* round = Baker_test.fetch_round client in let* branch = Operation.Consensus.get_branch ~attested_level:level client in let* block_payload_hash = @@ -9515,7 +9567,7 @@ let test_inject_accusation_aggregated_attestation nb_attesting_tz4 protocol A producer DAL node publishes "Hello world!" (produced with key [bootstrap1]) on a slot. An attestation, which attests the block is emitted with key [bootstrap2]. The published commitment is attested.*) -let test_producer_attester (_protocol : Protocol.t) +let test_producer_attester (protocol : Protocol.t) (dal_params : Dal_common.Parameters.t) (_cryptobox : Cryptobox.t) (node : Node.t) (client : Client.t) (_dal_node : Dal_node.t) : unit Lwt.t = let log_step = init_logger () in @@ -9549,6 +9601,7 @@ let test_producer_attester (_protocol : Protocol.t) so we have to inject them now. *) let* _ = inject_dal_attestations + ~protocol ~nb_slots:dal_params.number_of_slots (* Since the attestation threshold of the test is set to 1%, having only [bootstrap2] signing is sufficient. *) @@ -9597,7 +9650,7 @@ let test_producer_attester (_protocol : Protocol.t) (* Check if the [attester_did_not_attest] warning is correctly emitted. This test is a variation of [test_producer_attester] where an attestation not attesting the published DAL slot is injected. *) -let test_attester_did_not_attest (_protocol : Protocol.t) +let test_attester_did_not_attest (protocol : Protocol.t) (dal_params : Dal_common.Parameters.t) (_cryptobox : Cryptobox.t) (node : Node.t) (client : Client.t) (_dal_node : Dal_node.t) : unit Lwt.t = let log_step = init_logger () in @@ -9645,6 +9698,7 @@ let test_attester_did_not_attest (_protocol : Protocol.t) "Crafting attestation for [bootstrap3] (with expected DAL attestation)." ; let* op1 = craft_dal_attestation_exn + ~protocol ~nb_slots:dal_params.number_of_slots ~signer:Constant.bootstrap3 (Slots [index]) @@ -9655,6 +9709,7 @@ let test_attester_did_not_attest (_protocol : Protocol.t) log_step "Crafting attestation for [bootstrap2] (with empty DAL attestation)." ; let* op2 = craft_dal_attestation_exn + ~protocol ~nb_slots:dal_params.number_of_slots ~signer:Constant.bootstrap2 (Slots []) @@ -9801,6 +9856,7 @@ let test_duplicate_denunciations protocol dal_parameters cryptobox node client let signer = Constant.bootstrap2 in let* attestation, _op_hash = inject_dal_attestation_exn + ~protocol ~signer ~nb_slots:dal_parameters.number_of_slots availability @@ -9952,6 +10008,7 @@ let test_denunciation_next_cycle protocol dal_parameters cryptobox node client let availability = Slots [slot_index] in let* attestation, _op_hash = inject_dal_attestation_exn + ~protocol ~signer:Constant.bootstrap2 ~nb_slots:dal_parameters.number_of_slots availability @@ -10002,6 +10059,7 @@ let test_denunciation_next_cycle protocol dal_parameters cryptobox node client let signer = Constant.bootstrap2 in let* attestation, _op_hash = inject_dal_attestation_exn + ~protocol ~signer ~nb_slots:dal_parameters.number_of_slots availability @@ -10549,6 +10607,7 @@ let test_dal_rewards_distribution protocol dal_parameters cryptobox node client Slots all_slots) in inject_dal_attestation_exn + ~protocol ~signer:baker ~nb_slots baker_attestation @@ -10566,6 +10625,7 @@ let test_dal_rewards_distribution protocol dal_parameters cryptobox node client Slots [10]) in inject_dal_attestation_exn + ~protocol ~signer:attesting_dal_slot_10 ~nb_slots attestation @@ -10578,6 +10638,7 @@ let test_dal_rewards_distribution protocol dal_parameters cryptobox node client if !level mod 2 = 0 then No_dal_attestation else Slots [] in inject_dal_attestation_exn + ~protocol ~signer:not_attesting_dal ~nb_slots dal_attestation @@ -10593,6 +10654,7 @@ let test_dal_rewards_distribution protocol dal_parameters cryptobox node client else No_dal_attestation in inject_dal_attestation_exn + ~protocol ~signer:not_sufficiently_attesting_dal_slot_10 ~nb_slots slots_to_attest @@ -10603,6 +10665,7 @@ let test_dal_rewards_distribution protocol dal_parameters cryptobox node client let slots_to_attest = Slots [10] in let* res = inject_dal_attestation + ~protocol ~signer:small_baker ~nb_slots slots_to_attest diff --git a/tezt/tests/double_consensus.ml b/tezt/tests/double_consensus.ml index e04a88aa7794..928e6f026b25 100644 --- a/tezt/tests/double_consensus.ml +++ b/tezt/tests/double_consensus.ml @@ -104,7 +104,11 @@ let double_consensus_init let slots = List.map JSON.as_int - JSON.(List.hd JSON.(slots |> as_list) |-> "slots" |> as_list) + (if Protocol.number protocol >= 024 then + JSON.( + slots |> as_list |> List.hd |-> "delegates" |> as_list |> List.hd + |-> "slots" |> as_list) + else JSON.(slots |> as_list |> List.hd |-> "slots" |> as_list)) in Log.info "Inject valid %s." consensus_name ; let waiter = Node.wait_for_request ~request:`Inject node in @@ -388,7 +392,11 @@ let operation_too_far_in_future = let slots = List.map JSON.as_int - JSON.(List.hd JSON.(slots |> as_list) |-> "slots" |> as_list) + (if Protocol.number protocol >= 024 then + JSON.( + slots |> as_list |> List.hd |-> "delegates" |> as_list |> List.hd + |-> "slots" |> as_list) + else JSON.(slots |> as_list |> List.hd |-> "slots" |> as_list)) in Log.info "Craft and inject an attestation 3 levels in the future and wait for \ @@ -563,7 +571,7 @@ let attestation_and_aggregation_wrong_payload_hash = (* Attest for bootstrap1 with a dummy block_payload_hash *) let* _ = let open Operation.Consensus in - let* slots = get_slots_by_consensus_key ~level client in + let* slots = get_slots_by_consensus_key ~level ~protocol client in let slot = first_slot ~slots ck1 in let* branch = get_branch ~attested_level:level client in let* bph_level_4 = get_block_payload_hash ~block:"4" client in @@ -591,7 +599,7 @@ let attestation_and_aggregation_wrong_payload_hash = [(bootstrap1, (Attestation, Attestations_aggregate))] in let open Operation.Consensus in - let* slots = get_slots_by_consensus_key ~level client in + let* slots = get_slots_by_consensus_key ~level ~protocol client in let* branch = get_branch ~attested_level:level client in let* block_payload_hash = get_block_payload_hash client in (* Attest for bootstrap1 and check that he is forbidden *) @@ -729,7 +737,7 @@ let double_aggregation_wrong_payload_hash = let open Operation.Consensus in let* branch = get_branch ~attested_level:level client1 in let* block_payload_hash = get_block_payload_hash client1 in - let* slots = get_slots_by_consensus_key ~level client1 in + let* slots = get_slots_by_consensus_key ~level ~protocol client1 in (* Attest with the double attesting keys and check that they are forbidden *) let* () = Lwt_list.iter_s @@ -904,7 +912,7 @@ let preattestation_and_aggregation_wrong_payload_hash = let open Operation.Consensus in let* branch = get_branch ~attested_level:level client in let* block_payload_hash = get_block_payload_hash ~block:"2" client in - let* slots = get_slots_by_consensus_key ~level client in + let* slots = get_slots_by_consensus_key ~level ~protocol client in Log.info "preattesting level %d round 1 for bootstrap1, bootstrap2 and bootstrap4" level ; @@ -957,7 +965,7 @@ let preattestation_and_aggregation_wrong_payload_hash = (* Attest with the misbehaving keys and check that they are forbidden *) let* branch = get_branch ~attested_level:level client in let* block_payload_hash = get_block_payload_hash client in - let* slots = get_slots_by_consensus_key ~level client in + let* slots = get_slots_by_consensus_key ~level ~protocol client in let* () = Lwt_list.iter_s (fun ck -> @@ -1120,7 +1128,7 @@ let double_preattestation_aggregation_wrong_payload_hash = let open Operation.Consensus in let* branch = get_branch ~attested_level:level client1 in let* block_payload_hash = get_block_payload_hash client1 in - let* slots = get_slots_by_consensus_key ~level client1 in + let* slots = get_slots_by_consensus_key ~level ~protocol client1 in (* Attest with the double preattesting keys and check that they are forbidden *) let* () = Lwt_list.iter_s diff --git a/tezt/tests/prevalidator.ml b/tezt/tests/prevalidator.ml index 17c907e7cce8..2ddad0bad453 100644 --- a/tezt/tests/prevalidator.ml +++ b/tezt/tests/prevalidator.ml @@ -1908,7 +1908,7 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level client in + let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation (delegate : Account.key) = Operation.Consensus.inject (Operation.Consensus.attestation @@ -2159,7 +2159,7 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level client in + let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation (delegate : Account.key) = let* op = Operation.Consensus.operation @@ -2421,7 +2421,7 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level client in + let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation (account : Account.key) = Operation.Consensus.inject (Operation.Consensus.attestation @@ -2534,7 +2534,7 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level client in + let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation (account : Account.key) = Operation.Consensus.inject (Operation.Consensus.attestation @@ -2666,7 +2666,7 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level client in + let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation ~(account : Account.key) ~(signer : Account.key) = Operation.Consensus.inject (Operation.Consensus.attestation @@ -3808,7 +3808,9 @@ module Revamped = struct let* validated, refused = Lwt_list.fold_left_s (fun (validated, refused) level -> - let* attesting_rights = Operation.Consensus.get_slots ~level client in + let* attesting_rights = + Operation.Consensus.get_slots ~level ~protocol client + in (* Look for a delegate that has more than one slot *) let delegate, slots = let delegate_opt = -- GitLab From 659e13a53e24873db2258928b1f0b6d472dbea61 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Thu, 7 Aug 2025 16:09:20 +0200 Subject: [PATCH 4/4] Proto: avoid consensus_committee_size direct call from constants Also update the Validators RPC, for good measure --- .../testnet_experiment_tools/tool_alpha.ml | 6 +---- docs/protocols/alpha.rst | 5 ++-- .../lib_delegate/baking_actions.ml | 13 +++++++--- src/proto_alpha/lib_delegate/baking_lib.ml | 2 +- .../lib_delegate/baking_scheduling.ml | 2 +- src/proto_alpha/lib_delegate/baking_state.ml | 5 ++++ src/proto_alpha/lib_delegate/baking_state.mli | 3 +++ .../lib_delegate/operation_worker.ml | 26 +++++++++---------- .../lib_delegate/operation_worker.mli | 7 +++-- src/proto_alpha/lib_plugin/RPC.ml | 22 +++++++++++----- .../lib_protocol/delegate_sampler.ml | 5 ++++ .../lib_protocol/slash_percentage.ml | 9 ++++--- .../lib_protocol/slash_percentage.mli | 1 + .../test/unit/test_slashing_percentage.ml | 2 ++ 14 files changed, 70 insertions(+), 38 deletions(-) diff --git a/devtools/testnet_experiment_tools/tool_alpha.ml b/devtools/testnet_experiment_tools/tool_alpha.ml index a23a16b73475..8f806513c794 100644 --- a/devtools/testnet_experiment_tools/tool_alpha.ml +++ b/devtools/testnet_experiment_tools/tool_alpha.ml @@ -248,12 +248,8 @@ let create_state cctxt ?synchronize ?monitor_node_mempool ~config let open Lwt_result_syntax in let chain = cctxt#chain in let monitor_node_operations = monitor_node_mempool in - let* chain_id = Shell_services.Chain.chain_id cctxt ~chain () in - let* constants = - Alpha_services.Constants.all cctxt (`Hash chain_id, `Head 0) - in let*! operation_worker = - Operation_worker.run ?monitor_node_operations ~constants cctxt + Operation_worker.run ?monitor_node_operations cctxt in Baking_scheduling.create_initial_state cctxt diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index c992bc6bf9f2..822457290988 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -42,8 +42,9 @@ Breaking Changes - Updated ``GET /chains//blocks//helpers/validators`` to group delegates by level. The returned list contains one element for each queried level (by default, only the current level), - and contains three fields: the ``level`` itself, the ``consensus_threshold`` required for the current - level, and ``delegates`` which is the list of validators for that level. Each element of this last + and contains four fields: the ``level`` itself, the ``consensus_threshold`` required for the current + level, the ``consensus_committee`` of the current level, and ``delegates`` which is the list + of validators for that level. Each element of this last list contains the fields present in the previous version of this RPC: ``delegate``, ``slots``, ``consensus_key``, and ``companion_key`` (optional). (MR :gl:`!18931`) diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index 50db3b504897..3da1c7a87876 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -1020,6 +1020,9 @@ let prepare_waiting_for_quorum state = let consensus_threshold = Delegate_slots.consensus_threshold state.level_state.delegate_slots in + let consensus_committee = + Delegate_slots.consensus_committee state.level_state.delegate_slots + in let get_slot_voting_power ~slot = Delegate_slots.voting_power state.level_state.delegate_slots ~slot in @@ -1037,27 +1040,31 @@ let prepare_waiting_for_quorum state = else None); } in - (consensus_threshold, get_slot_voting_power, candidate) + (consensus_threshold, consensus_committee, get_slot_voting_power, candidate) let start_waiting_for_preattestation_quorum state = - let consensus_threshold, get_slot_voting_power, candidate = + let consensus_threshold, consensus_committee, get_slot_voting_power, candidate + = prepare_waiting_for_quorum state in let operation_worker = state.global_state.operation_worker in Operation_worker.monitor_preattestation_quorum operation_worker ~consensus_threshold + ~consensus_committee ~get_slot_voting_power candidate let start_waiting_for_attestation_quorum state = - let consensus_threshold, get_slot_voting_power, candidate = + let consensus_threshold, consensus_committee, get_slot_voting_power, candidate + = prepare_waiting_for_quorum state in let operation_worker = state.global_state.operation_worker in Operation_worker.monitor_attestation_quorum operation_worker ~consensus_threshold + ~consensus_committee ~get_slot_voting_power candidate diff --git a/src/proto_alpha/lib_delegate/baking_lib.ml b/src/proto_alpha/lib_delegate/baking_lib.ml index 7768367bb97d..324b944f7f49 100644 --- a/src/proto_alpha/lib_delegate/baking_lib.ml +++ b/src/proto_alpha/lib_delegate/baking_lib.ml @@ -58,7 +58,7 @@ let create_state cctxt ?dal_node_rpc_ctxt ?synchronize ?monitor_node_mempool Alpha_services.Constants.all cctxt (`Hash chain_id, `Head 0) in let*! operation_worker = - Operation_worker.run ?monitor_node_operations ~constants cctxt + Operation_worker.run ?monitor_node_operations cctxt in Baking_scheduling.create_initial_state cctxt diff --git a/src/proto_alpha/lib_delegate/baking_scheduling.ml b/src/proto_alpha/lib_delegate/baking_scheduling.ml index 4e147b5ca17e..cafa36369e51 100644 --- a/src/proto_alpha/lib_delegate/baking_scheduling.ml +++ b/src/proto_alpha/lib_delegate/baking_scheduling.ml @@ -1015,7 +1015,7 @@ let run cctxt ?dal_node_rpc_ctxt ?canceler ?(stop_on_event = fun _ -> false) | Some current_head -> return current_head | None -> failwith "head stream unexpectedly ended" in - let*! operation_worker = Operation_worker.run ~constants cctxt in + let*! operation_worker = Operation_worker.run cctxt in Option.iter (fun canceler -> Lwt_canceler.on_cancel canceler (fun () -> diff --git a/src/proto_alpha/lib_delegate/baking_state.ml b/src/proto_alpha/lib_delegate/baking_state.ml index 0521419a28c3..7c7cb80960b0 100644 --- a/src/proto_alpha/lib_delegate/baking_state.ml +++ b/src/proto_alpha/lib_delegate/baking_state.ml @@ -150,6 +150,7 @@ module Delegate_slots = struct skipped in the mempool to increase its speed; the baker can and should ignore such operations. *) consensus_threshold : int; + consensus_committee : int; } let own_delegates slots = slots.own_delegates @@ -172,6 +173,8 @@ module Delegate_slots = struct SlotMap.find slot slots.all_delegate_voting_power let consensus_threshold {consensus_threshold; _} = consensus_threshold + + let consensus_committee {consensus_committee; _} = consensus_committee end type delegate_slots = Delegate_slots.t @@ -944,6 +947,7 @@ let delegate_slots attesting_rights delegates = { Plugin.RPC.Validators.level = _; consensus_threshold; + consensus_committee; delegates = attesting_rights; }; ] -> @@ -982,6 +986,7 @@ let delegate_slots attesting_rights delegates = own_delegate_slots; all_delegate_voting_power; consensus_threshold; + consensus_committee; } let compute_delegate_slots (cctxt : Protocol_client_context.full) diff --git a/src/proto_alpha/lib_delegate/baking_state.mli b/src/proto_alpha/lib_delegate/baking_state.mli index c537547dcb88..bd1734032854 100644 --- a/src/proto_alpha/lib_delegate/baking_state.mli +++ b/src/proto_alpha/lib_delegate/baking_state.mli @@ -70,6 +70,9 @@ module Delegate_slots : sig (** Returns the consensus threshold at the level the slots were computed *) val consensus_threshold : t -> int + + (** Returns the consensus committee at the level the slots were computed *) + val consensus_committee : t -> int end type delegate_slots = Delegate_slots.t diff --git a/src/proto_alpha/lib_delegate/operation_worker.ml b/src/proto_alpha/lib_delegate/operation_worker.ml index 139c96af3c33..000fe7a216aa 100644 --- a/src/proto_alpha/lib_delegate/operation_worker.ml +++ b/src/proto_alpha/lib_delegate/operation_worker.ml @@ -270,6 +270,7 @@ type pqc_watched = { candidate_watched : candidate; get_slot_voting_power : slot:Slot.t -> int option; consensus_threshold : int; + consensus_committee : int; mutable current_voting_power : int; mutable preattestations_received : Preattestation_set.t; mutable preattestations_count : int; @@ -280,6 +281,7 @@ type qc_watched = { candidate_watched : candidate; get_slot_voting_power : slot:Slot.t -> int option; consensus_threshold : int; + consensus_committee : int; mutable current_voting_power : int; mutable attestations_received : Attestation_set.t; mutable attestations_count : int; @@ -305,7 +307,6 @@ type t = { qc_event_stream : quorum_event_stream; lock : Lwt_mutex.t; monitor_node_operations : bool; (* Keep on monitoring node operations *) - committee_size : int; } let monitor_operations (cctxt : #Protocol_client_context.full) = @@ -339,14 +340,11 @@ let monitor_operations (cctxt : #Protocol_client_context.full) = in return ((shell_header.level, round), operation_stream, stream_stopper) -let make_initial_state ?(monitor_node_operations = true) ~constants () = +let make_initial_state ?(monitor_node_operations = true) () = let qc_event_stream = let stream, push = Lwt_stream.create () in {stream; push} in - let committee_size = - constants.Constants.parametric.consensus_committee_size - in let canceler = Lwt_canceler.create () in let operation_pool = Operation_pool.empty in let lock = Lwt_mutex.create () in @@ -357,7 +355,6 @@ let make_initial_state ?(monitor_node_operations = true) ~constants () = qc_event_stream; lock; monitor_node_operations; - committee_size; } let is_eligible (candidate : candidate) branch consensus_content = @@ -547,7 +544,8 @@ let update_monitoring ?(should_lock = true) state ops = else let* () = let current_ratio = - pqc_watched.current_voting_power * 100 / state.committee_size + pqc_watched.current_voting_power * 100 + / pqc_watched.consensus_committee in (* We only want to output an event if the quorum progression has progressed of at least [quorum_progression_increment] *) @@ -595,7 +593,8 @@ let update_monitoring ?(should_lock = true) state ops = else let* () = let current_ratio = - qc_watched.current_voting_power * 100 / state.committee_size + qc_watched.current_voting_power * 100 + / qc_watched.consensus_committee in (* We only want to output an event if the quorum progression has progressed of at least [quorum_progression_increment] *) @@ -632,7 +631,7 @@ let monitor_quorum state new_proposal_watched = update_monitoring ~should_lock:false state current_consensus_operations let monitor_preattestation_quorum state ~consensus_threshold - ~get_slot_voting_power candidate_watched = + ~consensus_committee ~get_slot_voting_power candidate_watched = let new_proposal = Some (Pqc_watch @@ -640,6 +639,7 @@ let monitor_preattestation_quorum state ~consensus_threshold candidate_watched; get_slot_voting_power; consensus_threshold; + consensus_committee; current_voting_power = 0; preattestations_received = Preattestation_set.empty; preattestations_count = 0; @@ -648,8 +648,8 @@ let monitor_preattestation_quorum state ~consensus_threshold in monitor_quorum state new_proposal -let monitor_attestation_quorum state ~consensus_threshold ~get_slot_voting_power - candidate_watched = +let monitor_attestation_quorum state ~consensus_threshold ~consensus_committee + ~get_slot_voting_power candidate_watched = let new_proposal = Some (Qc_watch @@ -657,6 +657,7 @@ let monitor_attestation_quorum state ~consensus_threshold ~get_slot_voting_power candidate_watched; get_slot_voting_power; consensus_threshold; + consensus_committee; current_voting_power = 0; attestations_received = Attestation_set.empty; attestations_count = 0; @@ -717,12 +718,11 @@ let flush_operation_pool state (head_level, head_round) = let operation_pool = {Operation_pool.empty with consensus = attestations} in state.operation_pool <- operation_pool -let run ?(monitor_node_operations = true) ~constants +let run ?(monitor_node_operations = true) (cctxt : #Protocol_client_context.full) = let open Lwt_syntax in let state = (make_initial_state - ~constants ~monitor_node_operations () [@profiler.record_f {verbosity = Notice} "make initial state"]) in diff --git a/src/proto_alpha/lib_delegate/operation_worker.mli b/src/proto_alpha/lib_delegate/operation_worker.mli index 944bfbd54fb9..96d54f887c90 100644 --- a/src/proto_alpha/lib_delegate/operation_worker.mli +++ b/src/proto_alpha/lib_delegate/operation_worker.mli @@ -61,10 +61,7 @@ type event = [true]). Set [monitor_node_operations] to [false] to only consider externally provided (non-node) operations. *) val run : - ?monitor_node_operations:bool -> - constants:Constants.t -> - #Protocol_client_context.full -> - t Lwt.t + ?monitor_node_operations:bool -> #Protocol_client_context.full -> t Lwt.t (** {1 Utilities} *) @@ -87,6 +84,7 @@ val get_quorum_event_stream : t -> event Lwt_stream.t val monitor_preattestation_quorum : t -> consensus_threshold:int -> + consensus_committee:int -> get_slot_voting_power:(slot:Slot.t -> int option) -> candidate -> unit Lwt.t @@ -99,6 +97,7 @@ val monitor_preattestation_quorum : val monitor_attestation_quorum : t -> consensus_threshold:int -> + consensus_committee:int -> get_slot_voting_power:(slot:Slot.t -> int option) -> candidate -> unit Lwt.t diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index 69ec4e5757b4..8107b5b2aecb 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -3984,6 +3984,7 @@ module Validators = struct type t = { level : Raw_level.t; consensus_threshold : int; + consensus_committee : int; delegates : delegate list; } @@ -4003,13 +4004,14 @@ module Validators = struct let encoding = let open Data_encoding in conv - (fun {level; consensus_threshold; delegates} -> - (level, consensus_threshold, delegates)) - (fun (level, consensus_threshold, delegates) -> - {level; consensus_threshold; delegates}) - (obj3 + (fun {level; consensus_threshold; consensus_committee; delegates} -> + (level, consensus_threshold, consensus_committee, delegates)) + (fun (level, consensus_threshold, consensus_committee, delegates) -> + {level; consensus_threshold; consensus_committee; delegates}) + (obj4 (req "level" Raw_level.encoding) (req "consensus_threshold" int31) + (req "consensus_committee" int31) (req "delegates" (list delegate_encoding))) module S = struct @@ -4080,10 +4082,18 @@ module Validators = struct let consensus_threshold = Attestation_power.consensus_threshold ctxt level in + let consensus_committee = + Attestation_power.consensus_committee ctxt level + in let* ctxt, delegates = attestation_slots_at_level ctxt level in return ( ctxt, - ( {level = level.level; consensus_threshold; delegates = []}, + ( { + level = level.level; + consensus_threshold; + consensus_committee; + delegates = []; + }, delegates ) :: acc )) (ctxt, []) diff --git a/src/proto_alpha/lib_protocol/delegate_sampler.ml b/src/proto_alpha/lib_protocol/delegate_sampler.ml index b069653747c4..af73de9fc7db 100644 --- a/src/proto_alpha/lib_protocol/delegate_sampler.ml +++ b/src/proto_alpha/lib_protocol/delegate_sampler.ml @@ -152,6 +152,7 @@ let slot_owner c level slot = Random.owner c level (Slot_repr.to_int slot) let baking_rights_owner c (level : Level_repr.t) ~round = let open Lwt_result_syntax in + (* This committee is used for rounds *) let committee_size = Constants_storage.consensus_committee_size c in (* We use [Round.to_slot] to have a limited number of unique rounds (it should loop after some time) *) @@ -286,7 +287,11 @@ let clear_outdated_sampling_data ctxt ~new_cycle = let* ctxt = Delegate_sampler_state.remove_existing ctxt outdated_cycle in Seed_storage.remove_for_cycle ctxt outdated_cycle +(* This function is relevant only when all bakers don't attest *) let attesting_rights_count ctxt level = + assert ( + not + (Consensus_parameters_storage.check_all_bakers_attest_at_level ctxt level)) ; let consensus_committee_size = Constants_storage.consensus_committee_size ctxt in diff --git a/src/proto_alpha/lib_protocol/slash_percentage.ml b/src/proto_alpha/lib_protocol/slash_percentage.ml index b7d6bc22433b..42e410234b0d 100644 --- a/src/proto_alpha/lib_protocol/slash_percentage.ml +++ b/src/proto_alpha/lib_protocol/slash_percentage.ml @@ -8,7 +8,7 @@ let for_double_baking ctxt = Constants_storage.percentage_of_frozen_deposits_slashed_per_double_baking ctxt -let for_double_attestation ctxt rights denounced = +let for_double_attestation ctxt rights level denounced = let total_rights_denounced = List.fold_left (fun total delegate -> @@ -19,7 +19,10 @@ let for_double_attestation ctxt rights denounced = 0 denounced in - let committee_size = Constants_storage.consensus_committee_size ctxt in + (* TODO ABAAB. Note that the [rights] amount would also depend on the flag status. *) + let committee_size = + Consensus_parameters_storage.consensus_committee ctxt level + in let Ratio_repr.{numerator; denominator} = Constants_storage.max_slashing_threshold ctxt in @@ -39,7 +42,7 @@ let get ctxt ~(kind : Misbehaviour_repr.kind) ~(level : Level_repr.t) | Double_baking -> return (ctxt, for_double_baking ctxt) | Double_attesting | Double_preattesting -> let* ctxt, rights = Delegate_sampler.attesting_rights_count ctxt level in - return (ctxt, for_double_attestation ctxt rights denounced) + return (ctxt, for_double_attestation ctxt rights level denounced) module Internal_for_tests = struct let for_double_attestation = for_double_attestation diff --git a/src/proto_alpha/lib_protocol/slash_percentage.mli b/src/proto_alpha/lib_protocol/slash_percentage.mli index 3a557576f44c..6eb06bc18a09 100644 --- a/src/proto_alpha/lib_protocol/slash_percentage.mli +++ b/src/proto_alpha/lib_protocol/slash_percentage.mli @@ -25,6 +25,7 @@ module Internal_for_tests : sig val for_double_attestation : Raw_context.t -> int Signature.Public_key_hash.Map.t -> + Level_repr.t -> Signature.Public_key_hash.t list -> Percentage.t end diff --git a/src/proto_alpha/lib_protocol/test/unit/test_slashing_percentage.ml b/src/proto_alpha/lib_protocol/test/unit/test_slashing_percentage.ml index 04f8c88d74c0..3e94e340d11d 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_slashing_percentage.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_slashing_percentage.ml @@ -63,12 +63,14 @@ let make_fake_culprits_with_rights_from_int_list il = let get_pct ~max_slashing_threshold ~max_slashing_per_block int_list = let open Lwt_result_syntax in + (* TODO ABAAB: test with and without flag *) let* ctxt = raw_context ~max_slashing_threshold ~max_slashing_per_block () in let*? map, pkh_list = make_fake_culprits_with_rights_from_int_list int_list in return @@ Protocol.Slash_percentage.Internal_for_tests.for_double_attestation ctxt map + Protocol.Level_repr.level_zero_use_with_care pkh_list (** Tests that the slashing amount for several delegates is the same as long -- GitLab