From 439554f04ea151ae542fed14d024c5b5ea62abaa Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 14 May 2025 13:59:58 +0200 Subject: [PATCH 1/8] Proto/abaab: check level in alpha_context --- src/proto_alpha/lib_protocol/alpha_context.ml | 3 +++ src/proto_alpha/lib_protocol/alpha_context.mli | 2 ++ 2 files changed, 5 insertions(+) diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index df9752cc6165..08c3eac02073 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -625,6 +625,9 @@ module Delegate = struct end module Stake_distribution = struct + let check_all_bakers_attest_at_level = + Delegate_sampler.check_all_bakers_attest_at_level + let baking_rights_owner = Delegate_sampler.baking_rights_owner let slot_owner = Delegate_sampler.slot_owner diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index e29efc3d8bd3..c337d571a3d9 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -5204,6 +5204,8 @@ end (** This module re-exports definitions from {!Stake_storage}, {!Delegate_storage} and {!Delegate}. *) module Stake_distribution : sig + val check_all_bakers_attest_at_level : context -> Level.t -> bool + val baking_rights_owner : context -> Level.t -> -- GitLab From ed13299bfccf084182e1a5e024697660091650b5 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Tue, 29 Jul 2025 14:52:31 +0200 Subject: [PATCH 2/8] Proto: refactor slot maps --- src/proto_alpha/lib_plugin/RPC.ml | 30 ++++--- .../lib_protocol/alpha_context.mli | 4 +- src/proto_alpha/lib_protocol/apply.ml | 49 +++++++---- src/proto_alpha/lib_protocol/baking.ml | 28 ++++-- src/proto_alpha/lib_protocol/baking.mli | 2 +- .../lib_protocol/delegate_consensus_key.ml | 6 ++ .../lib_protocol/delegate_consensus_key.mli | 7 ++ src/proto_alpha/lib_protocol/raw_context.ml | 30 ++++--- src/proto_alpha/lib_protocol/raw_context.mli | 25 ++++-- src/proto_alpha/lib_protocol/validate.ml | 85 +++++++++---------- 10 files changed, 165 insertions(+), 101 deletions(-) diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index 13a6247505a4..706e15cc1a9b 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -3897,17 +3897,27 @@ module Attestation_rights = struct let rights = Slot.Map.fold (fun first_slot - ( { - Consensus_key.delegate; - consensus_pk = _; - consensus_pkh = consensus_key; - companion_pk = _; - companion_pkh = _; - }, - attestation_power, - _dal_power ) + ({ + consensus_key = + { + Consensus_key.delegate; + consensus_pk = _; + consensus_pkh = consensus_key; + companion_pk = _; + companion_pkh = _; + }; + attesting_power; + dal_power = _; + } : + Consensus_key.power) acc -> - {delegate; consensus_key; first_slot; attestation_power} :: acc) + { + delegate; + consensus_key; + first_slot; + attestation_power = attesting_power; + } + :: acc) rights [] in diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index c337d571a3d9..2de22af12c8f 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2249,6 +2249,8 @@ module Consensus_key : sig consensus_pkh : Signature.Public_key_hash.t; } + type power = {consensus_key : pk; attesting_power : int; dal_power : int} + val encoding : t Data_encoding.t val zero : t @@ -5502,7 +5504,7 @@ module Consensus : sig and type 'a level_map := 'a Level.Map.t and type slot_set := Slot.Set.t and type round := Round.t - and type consensus_pk := Consensus_key.pk + and type consensus_power := Consensus_key.power (** [store_attestation_branch context branch] sets the "attestation branch" (see {!Storage.Tenderbake.Attestation_branch} to [branch] in both the disk diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index b8e5d86d6220..6da808a1731b 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -2293,8 +2293,7 @@ let find_in_slot_map slot slot_map = | None -> (* This should not happen: operation validation should have failed. *) tzfail Faulty_validation_wrong_slot - | Some (consensus_key, power, dal_power) -> - return (consensus_key, power, dal_power)) + | Some x -> return x) let record_preattestation ctxt (mode : mode) (content : consensus_content) : (context * Kind.preattestation contents_result_list) tzresult Lwt.t = @@ -2320,7 +2319,7 @@ let record_preattestation ctxt (mode : mode) (content : consensus_content) : in match mode with | Application _ | Full_construction _ -> - let*? consensus_key, power, _dal_power = + let*? {consensus_key; attesting_power = power; dal_power = _} = find_in_slot_map content.slot (Consensus.allowed_preattestations ctxt) in let*? ctxt = @@ -2371,14 +2370,17 @@ let record_attestation ctxt (mode : mode) (consensus : consensus_content) in match mode with | Application _ | Full_construction _ -> - let*? consensus_key, power, dal_power = + let*? {consensus_key; attesting_power; dal_power} = find_in_slot_map consensus.slot (Consensus.allowed_attestations ctxt) in let*? ctxt = - Consensus.record_attestation ctxt ~initial_slot:consensus.slot ~power + Consensus.record_attestation + ctxt + ~initial_slot:consensus.slot + ~power:attesting_power in let*? ctxt = record_dal_content ctxt consensus.slot ~dal_power dal in - return (ctxt, mk_attestation_result consensus_key power) + return (ctxt, mk_attestation_result consensus_key attesting_power) | Partial_construction _ -> (* In mempool mode, attestations are allowed for various levels and rounds. We do not record attestations because we could get @@ -2404,16 +2406,25 @@ let record_attestations_aggregate ctxt (mode : mode) committee : let open Result_syntax in List.fold_left_e (fun (ctxt, consensus_keys, consensus_power) (slot, dal) -> - let* {delegate; consensus_pkh; _}, power, dal_power = + let* { + consensus_key = {delegate; consensus_pkh; _}; + attesting_power; + dal_power; + } = find_in_slot_map slot slot_map in let* ctxt = - Consensus.record_attestation ctxt ~initial_slot:slot ~power + Consensus.record_attestation + ctxt + ~initial_slot:slot + ~power:attesting_power in let* ctxt = record_dal_content ctxt slot ~dal_power dal in let key = ({delegate; consensus_pkh} : Consensus_key.t) in return - (ctxt, (key, power) :: consensus_keys, power + consensus_power)) + ( ctxt, + (key, attesting_power) :: consensus_keys, + attesting_power + consensus_power )) (ctxt, [], 0) committee in @@ -2453,19 +2464,25 @@ let record_preattestations_aggregate ctxt (mode : mode) let open Result_syntax in List.fold_left_e (fun (ctxt, consensus_keys, consensus_power) slot -> - let* {delegate; consensus_pkh; _}, power, _dal_power = + let* { + consensus_key = {delegate; consensus_pkh; _}; + attesting_power; + dal_power = _; + } = find_in_slot_map slot slot_map in let* ctxt = Consensus.record_preattestation ctxt ~initial_slot:slot - ~power + ~power:attesting_power round in let key = ({delegate; consensus_pkh} : Consensus_key.t) in return - (ctxt, (key, power) :: consensus_keys, power + consensus_power)) + ( ctxt, + (key, attesting_power) :: consensus_keys, + attesting_power + consensus_power )) (ctxt, [], 0) committee in @@ -2974,7 +2991,7 @@ let record_attesting_participation ctxt dal_attestation = | Some validators -> Slot.Map.fold_es (fun initial_slot - ((consensus_pk : Consensus_key.pk), power, dal_power) + ({consensus_key; attesting_power; dal_power} : Consensus_key.power) ctxt -> let participation = if Slot.Set.mem initial_slot (Consensus.attestations_seen ctxt) then @@ -2984,13 +3001,13 @@ let record_attesting_participation ctxt dal_attestation = let* ctxt = Delegate.record_attesting_participation ctxt - ~delegate:consensus_pk.delegate + ~delegate:consensus_key.delegate ~participation - ~attesting_power:power + ~attesting_power in Dal_apply.record_participation ctxt - consensus_pk.delegate + consensus_key.delegate initial_slot ~dal_power dal_attestation) diff --git a/src/proto_alpha/lib_protocol/baking.ml b/src/proto_alpha/lib_protocol/baking.ml index 3bad0551af7f..c6237c4c01e4 100644 --- a/src/proto_alpha/lib_protocol/baking.ml +++ b/src/proto_alpha/lib_protocol/baking.ml @@ -108,7 +108,8 @@ let attesting_rights (ctxt : t) level = (ctxt, Signature.Public_key_hash.Map.empty) slots -let attesting_rights_by_first_slot ctxt level = +let attesting_rights_by_first_slot ctxt level : + (t * Consensus_key.power Slot.Map.t) tzresult Lwt.t = let open Lwt_result_syntax in let*? slots = Slot.Range.create ~min:0 ~count:(Constants.consensus_committee_size ctxt) @@ -117,19 +118,19 @@ let attesting_rights_by_first_slot ctxt level = let* ctxt, (_, slots_map) = Slot.Range.fold_es (fun (ctxt, (delegates_map, slots_map)) slot -> - let+ ctxt, consensus_pk = + let+ ctxt, consensus_key = Stake_distribution.slot_owner ctxt level slot in let initial_slot, delegates_map = match Signature.Public_key_hash.Map.find - consensus_pk.delegate + consensus_key.delegate delegates_map with | None -> ( slot, Signature.Public_key_hash.Map.add - consensus_pk.delegate + consensus_key.delegate slot delegates_map ) | Some initial_slot -> (initial_slot, delegates_map) @@ -143,9 +144,22 @@ let attesting_rights_by_first_slot ctxt level = Slot.Map.update initial_slot (function - | None -> Some (consensus_pk, 1, in_dal_committee) - | Some (consensus_pk, count, dal_count) -> - Some (consensus_pk, count + 1, dal_count + in_dal_committee)) + | None -> + Some + { + consensus_key; + attesting_power = 1; + dal_power = in_dal_committee; + } + | Some + ({consensus_key; attesting_power; dal_power} : + Consensus_key.power) -> + Some + { + consensus_key; + attesting_power = attesting_power + 1; + dal_power = dal_power + in_dal_committee; + }) slots_map in (ctxt, (delegates_map, slots_map))) diff --git a/src/proto_alpha/lib_protocol/baking.mli b/src/proto_alpha/lib_protocol/baking.mli index 540ec98a72c9..ed491d8bfaf7 100644 --- a/src/proto_alpha/lib_protocol/baking.mli +++ b/src/proto_alpha/lib_protocol/baking.mli @@ -59,7 +59,7 @@ val attesting_rights : val attesting_rights_by_first_slot : context -> Level.t -> - (context * (Consensus_key.pk * int * int) Slot.Map.t) tzresult Lwt.t + (context * Consensus_key.power Slot.Map.t) tzresult Lwt.t (** Computes the bonus baking reward depending on the attestation power. *) val bonus_baking_reward : context -> attestation_power:int -> Tez.t tzresult diff --git a/src/proto_alpha/lib_protocol/delegate_consensus_key.ml b/src/proto_alpha/lib_protocol/delegate_consensus_key.ml index a8220c2e955b..bac79afbac72 100644 --- a/src/proto_alpha/lib_protocol/delegate_consensus_key.ml +++ b/src/proto_alpha/lib_protocol/delegate_consensus_key.ml @@ -126,6 +126,12 @@ type pk = Raw_context.consensus_pk = { companion_pkh : Bls.Public_key_hash.t option; } +type power = Raw_context.consensus_power = { + consensus_key : pk; + attesting_power : int; + dal_power : int; +} + type t = { delegate : Signature.Public_key_hash.t; consensus_pkh : Signature.Public_key_hash.t; diff --git a/src/proto_alpha/lib_protocol/delegate_consensus_key.mli b/src/proto_alpha/lib_protocol/delegate_consensus_key.mli index 18b7addb9fbb..45ceafd0f645 100644 --- a/src/proto_alpha/lib_protocol/delegate_consensus_key.mli +++ b/src/proto_alpha/lib_protocol/delegate_consensus_key.mli @@ -50,6 +50,13 @@ type pk = Raw_context.consensus_pk = { companion_pkh : Bls.Public_key_hash.t option; } +(** The attesting and dal power related to the associated consensus key *) +type power = Raw_context.consensus_power = { + consensus_key : pk; + attesting_power : int; + dal_power : int; +} + (** The public key hash of a consensus key and the associated delegate. *) type t = { delegate : Signature.Public_key_hash.t; diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index ec2b289a4d2d..3ae47bb0f310 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -91,6 +91,12 @@ let consensus_pk_encoding = (opt "delegate" Signature.Public_key_hash.encoding) (opt "companion_pk" Bls.Public_key.encoding)) +type consensus_power = { + consensus_key : consensus_pk; + attesting_power : int; + dal_power : int; +} + module Raw_consensus = struct (** Consensus operations are indexed by their [initial slots]. Given a delegate, the [initial slot] is the lowest slot assigned to @@ -99,21 +105,20 @@ module Raw_consensus = struct type t = { current_attestation_power : int; (** Number of attestation slots recorded for the current block. *) - allowed_attestations : (consensus_pk * int * int) Slot_repr.Map.t option; + allowed_attestations : consensus_power Slot_repr.Map.t option; (** Attestations rights for the current block. Only an attestation for the lowest slot in the block can be recorded. The map associates to each initial slot the [pkh] associated to this slot with its consensus attestation power and DAL attestation power. This is [None] only in mempool mode. *) - allowed_preattestations : (consensus_pk * int * int) Slot_repr.Map.t option; + allowed_preattestations : consensus_power Slot_repr.Map.t option; (** Preattestations rights for the current block. Only a preattestation for the lowest slot in the block can be recorded. The map associates to each initial slot the [pkh] associated to this slot with its consensus attestation power and DAL attestation power. This is [None] only in mempool mode, or in application mode when there is no locked round (so the block cannot contain any preattestations). *) - allowed_consensus : - (consensus_pk * int * int) Slot_repr.Map.t Level_repr.Map.t option; + allowed_consensus : consensus_power Slot_repr.Map.t Level_repr.Map.t option; (** In mempool mode, hold delegates minimal slots for all allowed levels. [None] in all other modes. *) forbidden_delegates : Signature.Public_key_hash.Set.t; @@ -2141,14 +2146,13 @@ module type CONSENSUS = sig type round - type consensus_pk + type consensus_power - val allowed_attestations : t -> (consensus_pk * int * int) slot_map option + val allowed_attestations : t -> consensus_power slot_map option - val allowed_preattestations : t -> (consensus_pk * int * int) slot_map option + val allowed_preattestations : t -> consensus_power slot_map option - val allowed_consensus : - t -> (consensus_pk * int * int) slot_map level_map option + val allowed_consensus : t -> consensus_power slot_map level_map option val forbidden_delegates : t -> Signature.Public_key_hash.Set.t @@ -2158,9 +2162,9 @@ module type CONSENSUS = sig val initialize_consensus_operation : t -> - allowed_attestations:(consensus_pk * int * int) slot_map option -> - allowed_preattestations:(consensus_pk * int * int) slot_map option -> - allowed_consensus:(consensus_pk * int * int) slot_map level_map option -> + allowed_attestations:consensus_power slot_map option -> + allowed_preattestations:consensus_power slot_map option -> + allowed_consensus:consensus_power slot_map level_map option -> t val record_attestation : t -> initial_slot:slot -> power:int -> t tzresult @@ -2193,7 +2197,7 @@ module Consensus : and type 'a level_map := 'a Level_repr.Map.t and type slot_set := Slot_repr.Set.t and type round := Round_repr.t - and type consensus_pk := consensus_pk = struct + and type consensus_power := consensus_power = struct let[@inline] update_consensus_with ctxt f = {ctxt with back = {ctxt.back with consensus = f ctxt.back.consensus}} diff --git a/src/proto_alpha/lib_protocol/raw_context.mli b/src/proto_alpha/lib_protocol/raw_context.mli index 1c649bd923f3..6fc8a8ccea04 100644 --- a/src/proto_alpha/lib_protocol/raw_context.mli +++ b/src/proto_alpha/lib_protocol/raw_context.mli @@ -355,6 +355,12 @@ module Internal_for_tests : sig val add_cycles : t -> int -> t end +type consensus_power = { + consensus_key : consensus_pk; + attesting_power : int; + dal_power : int; +} + module type CONSENSUS = sig type t @@ -368,21 +374,22 @@ module type CONSENSUS = sig type round - type consensus_pk + (** Info on the power of a given member of the consensus committee. + Contains a consensus_pk, its attesting power and its DAL power. *) + type consensus_power (** Returns a map where from the initial slot of each attester in the TB committee for a given level, to the attester's public key and its consensus power and DAL power. *) - val allowed_attestations : t -> (consensus_pk * int * int) slot_map option + val allowed_attestations : t -> consensus_power slot_map option (** See {!allowed_attestations}. *) - val allowed_preattestations : t -> (consensus_pk * int * int) slot_map option + val allowed_preattestations : t -> consensus_power slot_map option (** Returns a map that associates a level with a slot map. The slot map links a delegate's public key to a tuple containing (minimal_slot, voting_power, dal_power). See {!allowed_attestations} *) - val allowed_consensus : - t -> (consensus_pk * int * int) slot_map level_map option + val allowed_consensus : t -> consensus_power slot_map level_map option (** Returns the set of delegates that are not allowed to bake or attest blocks; i.e., delegates which have zero frozen deposit @@ -401,9 +408,9 @@ module type CONSENSUS = sig operation. *) val initialize_consensus_operation : t -> - allowed_attestations:(consensus_pk * int * int) slot_map option -> - allowed_preattestations:(consensus_pk * int * int) slot_map option -> - allowed_consensus:(consensus_pk * int * int) slot_map level_map option -> + allowed_attestations:consensus_power slot_map option -> + allowed_preattestations:consensus_power slot_map option -> + allowed_consensus:consensus_power slot_map level_map option -> t (** [record_attestation ctx ~initial_slot ~power] records an @@ -465,7 +472,7 @@ module Consensus : and type 'a level_map := 'a Level_repr.Map.t and type slot_set := Slot_repr.Set.t and type round := Round_repr.t - and type consensus_pk := consensus_pk + and type consensus_power := consensus_power module Sc_rollup_in_memory_inbox : sig val current_messages : t -> Sc_rollup_inbox_merkelized_payload_hashes_repr.t diff --git a/src/proto_alpha/lib_protocol/validate.ml b/src/proto_alpha/lib_protocol/validate.ml index 76f9ee5770c7..67c6b58ed95e 100644 --- a/src/proto_alpha/lib_protocol/validate.ml +++ b/src/proto_alpha/lib_protocol/validate.ml @@ -30,10 +30,9 @@ open Alpha_context type consensus_info = { predecessor_level : Raw_level.t; predecessor_round : Round.t; - preattestation_slot_map : (Consensus_key.pk * int * int) Slot.Map.t option; - attestation_slot_map : (Consensus_key.pk * int * int) Slot.Map.t option; - consensus_slot_map : - (Consensus_key.pk * int * int) Slot.Map.t Level.Map.t option; + preattestation_slot_map : Consensus_key.power Slot.Map.t option; + attestation_slot_map : Consensus_key.power Slot.Map.t option; + consensus_slot_map : Consensus_key.power Slot.Map.t Level.Map.t option; } let init_consensus_info ctxt (predecessor_level, predecessor_round) = @@ -604,8 +603,8 @@ module Consensus = struct Returns the corresponding delegate's consensus key and attesting power. *) let check_mempool_consensus vi consensus_info kind {level; slot; _} = - let open Lwt_result_syntax in - let*? () = + let open Result_syntax in + let* () = if Raw_level.(succ level < consensus_info.predecessor_level) then let expected = consensus_info.predecessor_level and provided = level in result_error @@ -621,10 +620,8 @@ module Consensus = struct | None -> tzfail (Consensus.Slot_map_not_found {loc = __LOC__}) | Some level_map -> let slot_map = Level.Map.find level level_map in - let*? consensus_key, attesting_power, _dal_power = - get_delegate_details slot_map kind slot - in - return (consensus_key, attesting_power) + get_delegate_details slot_map kind slot + (* We do not check that the frozen deposits are positive because this only needs to be true in the context of a block that actually contains the operation, which may not be the same as the current @@ -641,7 +638,7 @@ module Consensus = struct let (Single (Preattestation consensus_content)) = operation.protocol_data.contents in - let* consensus_key, attesting_power = + let* {consensus_key; attesting_power; dal_power = _} = match vi.mode with | Application block_info | Partial_validation block_info -> let* () = @@ -650,13 +647,11 @@ module Consensus = struct block_info consensus_content in - let*? consensus_key, voting_power, _dal_power = - get_delegate_details - consensus_info.preattestation_slot_map - Preattestation - consensus_content.slot - in - return (consensus_key, voting_power) + Lwt.return + @@ get_delegate_details + consensus_info.preattestation_slot_map + Preattestation + consensus_content.slot | Construction construction_info -> let* () = check_constructed_block_preattestation @@ -664,19 +659,18 @@ module Consensus = struct construction_info consensus_content in - let*? consensus_key, voting_power, _dal_power = - get_delegate_details - consensus_info.preattestation_slot_map - Preattestation - consensus_content.slot - in - return (consensus_key, voting_power) + Lwt.return + @@ get_delegate_details + consensus_info.preattestation_slot_map + Preattestation + consensus_content.slot | Mempool -> - check_mempool_consensus - vi - consensus_info - Preattestation - consensus_content + Lwt.return + @@ check_mempool_consensus + vi + consensus_info + Preattestation + consensus_content in let* () = match vi.mode with @@ -875,19 +869,19 @@ module Consensus = struct let (Single (Attestation {consensus_content; dal_content})) = operation.protocol_data.contents in - let* consensus_key, attesting_power = + let* {consensus_key; attesting_power; dal_power = _} = match vi.mode with | Application _ | Partial_validation _ | Construction _ -> ( let* () = check_block_attestation vi consensus_info consensus_content in - let*? consensus_key, attesting_power, _dal_power = + let*? details = get_delegate_details consensus_info.attestation_slot_map Attestation consensus_content.slot in - match consensus_key.consensus_pk with + match details.consensus_key.consensus_pk with | Bls _ when Constants.aggregate_attestation vi.ctxt -> (* An attestation with a BLS signature must be included in an Attestations_aggregate, even if there is only one in the block. @@ -895,13 +889,14 @@ module Consensus = struct let hash = Operation.hash operation in tzfail (Unaggregated_eligible_operation {kind = Attestation; hash}) - | _ -> return (consensus_key, attesting_power)) + | _ -> return details) | Mempool -> - check_mempool_consensus - vi - consensus_info - Attestation - consensus_content + Lwt.return + @@ check_mempool_consensus + vi + consensus_info + Attestation + consensus_content in let* () = check_delegate_is_not_forbidden vi.ctxt consensus_key.delegate in let* () = @@ -1318,11 +1313,11 @@ module Consensus = struct | Mempool -> return_unit in (* Retrieve public keys and compute total voting power *) - let* public_keys, voting_power = + let* public_keys, total_voting_power = List.fold_left_es (fun (public_keys, total_voting_power) slot -> (* Lookup the slot owner *) - let*? consensus_key, power, _ = + let*? {consensus_key; attesting_power; dal_power = _} = get_delegate_details consensus_info.preattestation_slot_map Preattestation @@ -1332,7 +1327,9 @@ module Consensus = struct check_delegate_is_not_forbidden info.ctxt consensus_key.delegate in match consensus_key.consensus_pk with - | Bls pk -> return (pk :: public_keys, power + total_voting_power) + | Bls pk -> + return + (pk :: public_keys, attesting_power + total_voting_power) | _ -> tzfail Validate_errors.Consensus.Non_bls_key_in_aggregate) ([], 0) committee @@ -1363,7 +1360,7 @@ module Consensus = struct block_state info.mode {level; round; block_payload_hash; slot = Slot.zero} - voting_power + total_voting_power in return {validation_state with block_state} @@ -1425,7 +1422,7 @@ module Consensus = struct List.fold_left_es (fun (pks, weighted_pks, total_power) (slot, dal) -> (* Lookup the slot owner *) - let*? consensus_key, attesting_power, _dal_power = + let*? {consensus_key; attesting_power; dal_power = _} = get_delegate_details consensus_info.attestation_slot_map Attestation -- GitLab From 544cdb0366a67cbf632e47dd478fe1326e4f3797 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Tue, 29 Jul 2025 16:06:49 +0200 Subject: [PATCH 3/8] =?UTF-8?q?Proto/aba=C3=A6b:=20attestation=20power=20r?= =?UTF-8?q?epr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/proto_alpha/lib_protocol/TEZOS_PROTOCOL | 1 + .../lib_protocol/attestation_power_repr.ml | 22 ++++++++++++++++++ .../lib_protocol/attestation_power_repr.mli | 23 +++++++++++++++++++ src/proto_alpha/lib_protocol/dune | 4 ++++ 4 files changed, 50 insertions(+) create mode 100644 src/proto_alpha/lib_protocol/attestation_power_repr.ml create mode 100644 src/proto_alpha/lib_protocol/attestation_power_repr.mli diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index 1655f02a81bd..12b9e2994017 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -26,6 +26,7 @@ "Cycle_repr", "Tez_repr", "Deposits_repr", + "Attestation_power_repr", "Unstaked_frozen_deposits_repr", "Staking_pseudotoken_repr", "Period_repr", diff --git a/src/proto_alpha/lib_protocol/attestation_power_repr.ml b/src/proto_alpha/lib_protocol/attestation_power_repr.ml new file mode 100644 index 000000000000..33a4d1c4268a --- /dev/null +++ b/src/proto_alpha/lib_protocol/attestation_power_repr.ml @@ -0,0 +1,22 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* SPDX-FileCopyrightText: 2025 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +type t = {slots : int; stake : int64} + +let encoding = + let open Data_encoding in + conv + (fun {slots; stake} -> (slots, stake)) + (fun (slots, stake) -> {slots; stake}) + (obj2 (req "slots" int31) (req "stake" int64)) + +let pp ppf {slots; stake} = + Format.fprintf ppf "(slots:%d, stake:%Ld)" slots stake + +let zero = {slots = 0; stake = 0L} + +let add a b = {slots = a.slots + b.slots; stake = Int64.add a.stake b.stake} diff --git a/src/proto_alpha/lib_protocol/attestation_power_repr.mli b/src/proto_alpha/lib_protocol/attestation_power_repr.mli new file mode 100644 index 000000000000..7684e35d30b9 --- /dev/null +++ b/src/proto_alpha/lib_protocol/attestation_power_repr.mli @@ -0,0 +1,23 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* SPDX-FileCopyrightText: 2025 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** Internal representation of attestation power. + + If the consensus is distributed randomly for 7000 slots, + the (relative) power is the number of slots of the given delegate, + noted in [slots]. Otherwise, if all bakers attest, then its power is its stake + for the cycle in which the rights were distributed, noted in [stake]. *) + +type t = {slots : int; stake : int64} + +val encoding : t Data_encoding.t + +val pp : Format.formatter -> t -> unit + +val zero : t + +val add : t -> t -> t diff --git a/src/proto_alpha/lib_protocol/dune b/src/proto_alpha/lib_protocol/dune index 1a34312188b7..8e2f79df254b 100644 --- a/src/proto_alpha/lib_protocol/dune +++ b/src/proto_alpha/lib_protocol/dune @@ -54,6 +54,7 @@ Cycle_repr Tez_repr Deposits_repr + Attestation_power_repr Unstaked_frozen_deposits_repr Staking_pseudotoken_repr Period_repr @@ -342,6 +343,7 @@ cycle_repr.ml cycle_repr.mli tez_repr.ml tez_repr.mli deposits_repr.ml deposits_repr.mli + attestation_power_repr.ml attestation_power_repr.mli unstaked_frozen_deposits_repr.ml unstaked_frozen_deposits_repr.mli staking_pseudotoken_repr.ml staking_pseudotoken_repr.mli period_repr.ml period_repr.mli @@ -635,6 +637,7 @@ cycle_repr.ml cycle_repr.mli tez_repr.ml tez_repr.mli deposits_repr.ml deposits_repr.mli + attestation_power_repr.ml attestation_power_repr.mli unstaked_frozen_deposits_repr.ml unstaked_frozen_deposits_repr.mli staking_pseudotoken_repr.ml staking_pseudotoken_repr.mli period_repr.ml period_repr.mli @@ -912,6 +915,7 @@ cycle_repr.ml cycle_repr.mli tez_repr.ml tez_repr.mli deposits_repr.ml deposits_repr.mli + attestation_power_repr.ml attestation_power_repr.mli unstaked_frozen_deposits_repr.ml unstaked_frozen_deposits_repr.mli staking_pseudotoken_repr.ml staking_pseudotoken_repr.mli period_repr.ml period_repr.mli -- GitLab From ffb7f5501f42e278640ae74aa434b330717d1c09 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Tue, 29 Jul 2025 17:05:41 +0200 Subject: [PATCH 4/8] =?UTF-8?q?Proto/aba=C3=A6b:=20change=20type=20of=20at?= =?UTF-8?q?testing=20power=20where=20applicable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We also register the staking power, even if unused --- .../lib_client/operation_result.ml | 20 ++++-- src/proto_alpha/lib_plugin/RPC.ml | 4 +- .../lib_protocol/alpha_context.mli | 7 +- src/proto_alpha/lib_protocol/apply.ml | 58 ++++++++++------ src/proto_alpha/lib_protocol/apply_results.ml | 18 ++--- .../lib_protocol/apply_results.mli | 12 ++-- src/proto_alpha/lib_protocol/baking.ml | 17 ++++- src/proto_alpha/lib_protocol/baking.mli | 3 +- .../lib_protocol/delegate_consensus_key.ml | 2 +- .../lib_protocol/delegate_consensus_key.mli | 2 +- .../delegate_missed_attestations_storage.ml | 4 +- .../delegate_missed_attestations_storage.mli | 1 + src/proto_alpha/lib_protocol/raw_context.ml | 66 ++++++++++-------- src/proto_alpha/lib_protocol/raw_context.mli | 17 +++-- .../integration/consensus/test_aggregate.ml | 9 ++- src/proto_alpha/lib_protocol/validate.ml | 69 ++++++++++++------- .../lib_protocol/validate_errors.ml | 13 +++- .../lib_protocol/validate_errors.mli | 1 + tezt/tests/dal.ml | 7 +- .../alpha_machine.real.ml | 6 +- 20 files changed, 220 insertions(+), 116 deletions(-) diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index 200fb656e5fe..70205b0ed8c7 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -982,7 +982,13 @@ let pp_contents_and_result : rewarded_delegate in let pp_committee ppf (delegate, voting_power) = - Format.fprintf ppf "(%a, %d)" Consensus_key.pp delegate voting_power + Format.fprintf + ppf + "(%a, %a)" + Consensus_key.pp + delegate + Attestation_power_repr.pp + voting_power in fun ppf -> function | Seed_nonce_revelation {level; nonce}, Seed_nonce_revelation_result bus -> @@ -1027,13 +1033,14 @@ let pp_contents_and_result : Level: %a@,\ Balance updates:%a@,\ Delegate: %a@,\ - Consensus Power: %d@]" + Consensus Power: %a@]" Raw_level.pp level pp_balance_updates balance_updates Consensus_key.pp {delegate; consensus_pkh = consensus_key} + Attestation_power_repr.pp consensus_power | ( Attestation {consensus_content = {level; _}; dal_content = _}, Attestation_result @@ -1044,13 +1051,14 @@ let pp_contents_and_result : Level: %a@,\ Balance updates:%a@,\ Delegate: %a@,\ - Consensus Power: %d@]" + Consensus Power: %a@]" Raw_level.pp level pp_balance_updates balance_updates Consensus_key.pp {delegate; consensus_pkh = consensus_key} + Attestation_power_repr.pp consensus_power | ( Preattestations_aggregate {consensus_content = {level; _}; _}, Preattestations_aggregate_result @@ -1061,13 +1069,14 @@ let pp_contents_and_result : Level: %a@,\ Balance updates:%a@,\ Delegates: %a@,\ - Consensus Power: %d@]" + Consensus Power: %a@]" Raw_level.pp level pp_balance_updates balance_updates (Format.pp_print_list pp_committee) committee + Attestation_power_repr.pp total_consensus_power | ( Attestations_aggregate {consensus_content = {level; _}; _}, Attestations_aggregate_result @@ -1078,13 +1087,14 @@ let pp_contents_and_result : Level: %a@,\ Balance updates:%a@,\ Delegates: %a@,\ - Consensus Power: %d@]" + Consensus Power: %a@]" Raw_level.pp level pp_balance_updates balance_updates (Format.pp_print_list pp_committee) committee + Attestation_power_repr.pp total_consensus_power | ( Double_consensus_operation_evidence {slot; op1; op2}, Double_consensus_operation_evidence_result double_signing_result ) -> diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index 706e15cc1a9b..d4736610f9f2 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -3906,7 +3906,7 @@ module Attestation_rights = struct companion_pk = _; companion_pkh = _; }; - attesting_power; + attestation_power; dal_power = _; } : Consensus_key.power) @@ -3915,7 +3915,7 @@ module Attestation_rights = struct delegate; consensus_key; first_slot; - attestation_power = attesting_power; + attestation_power = attestation_power.slots; } :: acc) rights diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 2de22af12c8f..e4be93e4708c 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2249,7 +2249,11 @@ module Consensus_key : sig consensus_pkh : Signature.Public_key_hash.t; } - type power = {consensus_key : pk; attesting_power : int; dal_power : int} + type power = { + consensus_key : pk; + attestation_power : Attestation_power_repr.t; + dal_power : int; + } val encoding : t Data_encoding.t @@ -2353,6 +2357,7 @@ module Delegate : sig delegate:public_key_hash -> participation:level_participation -> attesting_power:int -> + staking_weight:Int64.t -> context tzresult Lwt.t val record_dal_participation : diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 6da808a1731b..e2cc11ade727 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -2319,17 +2319,17 @@ let record_preattestation ctxt (mode : mode) (content : consensus_content) : in match mode with | Application _ | Full_construction _ -> - let*? {consensus_key; attesting_power = power; dal_power = _} = + let*? {consensus_key; attestation_power; dal_power = _} = find_in_slot_map content.slot (Consensus.allowed_preattestations ctxt) in let*? ctxt = Consensus.record_preattestation ctxt ~initial_slot:content.slot - ~power + ~power:attestation_power content.round in - return (ctxt, mk_preattestation_result consensus_key power) + return (ctxt, mk_preattestation_result consensus_key attestation_power) | Partial_construction _ -> (* In mempool mode, preattestations are allowed for various levels and rounds. We do not record preattestations because we could get @@ -2342,7 +2342,11 @@ let record_preattestation ctxt (mode : mode) (content : consensus_content) : let level = Level.from_raw ctxt content.level in Stake_distribution.slot_owner ctxt level content.slot in - return (ctxt, mk_preattestation_result consensus_key 0 (* Fake power. *)) + return + ( ctxt, + mk_preattestation_result + consensus_key + Attestation_power_repr.zero (* Fake power. *) ) let record_dal_content ctxt slot ~dal_power = function | None -> Result.return ctxt @@ -2370,17 +2374,17 @@ let record_attestation ctxt (mode : mode) (consensus : consensus_content) in match mode with | Application _ | Full_construction _ -> - let*? {consensus_key; attesting_power; dal_power} = + let*? {consensus_key; attestation_power; dal_power} = find_in_slot_map consensus.slot (Consensus.allowed_attestations ctxt) in let*? ctxt = Consensus.record_attestation ctxt ~initial_slot:consensus.slot - ~power:attesting_power + ~power:attestation_power in let*? ctxt = record_dal_content ctxt consensus.slot ~dal_power dal in - return (ctxt, mk_attestation_result consensus_key attesting_power) + return (ctxt, mk_attestation_result consensus_key attestation_power) | Partial_construction _ -> (* In mempool mode, attestations are allowed for various levels and rounds. We do not record attestations because we could get @@ -2393,7 +2397,11 @@ let record_attestation ctxt (mode : mode) (consensus : consensus_content) let level = Level.from_raw ctxt consensus.level in Stake_distribution.slot_owner ctxt level consensus.slot in - return (ctxt, mk_attestation_result consensus_key 0 (* Fake power. *)) + return + ( ctxt, + mk_attestation_result + consensus_key + Attestation_power_repr.zero (* Fake power. *) ) let record_attestations_aggregate ctxt (mode : mode) committee : (context * Kind.attestations_aggregate contents_result_list) tzresult Lwt.t @@ -2408,7 +2416,7 @@ let record_attestations_aggregate ctxt (mode : mode) committee : (fun (ctxt, consensus_keys, consensus_power) (slot, dal) -> let* { consensus_key = {delegate; consensus_pkh; _}; - attesting_power; + attestation_power; dal_power; } = find_in_slot_map slot slot_map @@ -2417,15 +2425,15 @@ let record_attestations_aggregate ctxt (mode : mode) committee : Consensus.record_attestation ctxt ~initial_slot:slot - ~power:attesting_power + ~power:attestation_power in let* ctxt = record_dal_content ctxt slot ~dal_power dal in let key = ({delegate; consensus_pkh} : Consensus_key.t) in return ( ctxt, - (key, attesting_power) :: consensus_keys, - attesting_power + consensus_power )) - (ctxt, [], 0) + (key, attestation_power) :: consensus_keys, + Attestation_power_repr.add attestation_power consensus_power )) + (ctxt, [], Attestation_power_repr.zero) committee in let result = @@ -2466,7 +2474,7 @@ let record_preattestations_aggregate ctxt (mode : mode) (fun (ctxt, consensus_keys, consensus_power) slot -> let* { consensus_key = {delegate; consensus_pkh; _}; - attesting_power; + attestation_power; dal_power = _; } = find_in_slot_map slot slot_map @@ -2475,15 +2483,15 @@ let record_preattestations_aggregate ctxt (mode : mode) Consensus.record_preattestation ctxt ~initial_slot:slot - ~power:attesting_power + ~power:attestation_power round in let key = ({delegate; consensus_pkh} : Consensus_key.t) in return ( ctxt, - (key, attesting_power) :: consensus_keys, - attesting_power + consensus_power )) - (ctxt, [], 0) + (key, attestation_power) :: consensus_keys, + Attestation_power_repr.add attestation_power consensus_power )) + (ctxt, [], Attestation_power_repr.zero) committee in let result = @@ -2991,7 +2999,8 @@ let record_attesting_participation ctxt dal_attestation = | Some validators -> Slot.Map.fold_es (fun initial_slot - ({consensus_key; attesting_power; dal_power} : Consensus_key.power) + ({consensus_key; attestation_power; dal_power} : + Consensus_key.power) ctxt -> let participation = if Slot.Set.mem initial_slot (Consensus.attestations_seen ctxt) then @@ -3003,7 +3012,8 @@ let record_attesting_participation ctxt dal_attestation = ctxt ~delegate:consensus_key.delegate ~participation - ~attesting_power + ~attesting_power:attestation_power.slots + ~staking_weight:attestation_power.stake in Dal_apply.record_participation ctxt @@ -3237,8 +3247,14 @@ let finalize_application ctxt block_data_contents ~round ~predecessor_hash let* ctxt, reward_bonus = if required_attestations then let* ctxt = record_attesting_participation ctxt dal_attestation in + let all_bakers_attest_enabled = + Stake_distribution.check_all_bakers_attest_at_level ctxt level + in let*? rewards_bonus = - Baking.bonus_baking_reward ctxt ~attestation_power + if all_bakers_attest_enabled then + error Validate_errors.Consensus.All_bakers_attest_not_implemented + (* TODO ABAAB *) + else Baking.bonus_baking_reward ctxt ~attestation_power in return (ctxt, Some rewards_bonus) else return (ctxt, None) diff --git a/src/proto_alpha/lib_protocol/apply_results.ml b/src/proto_alpha/lib_protocol/apply_results.ml index 609d28bdb3c8..b2c614b5a838 100644 --- a/src/proto_alpha/lib_protocol/apply_results.ml +++ b/src/proto_alpha/lib_protocol/apply_results.ml @@ -888,26 +888,26 @@ type 'kind contents_result = balance_updates : Receipt.balance_updates; delegate : Signature.public_key_hash; consensus_key : Signature.public_key_hash; - consensus_power : int; + consensus_power : Attestation_power_repr.t; } -> Kind.preattestation contents_result | Attestation_result : { balance_updates : Receipt.balance_updates; delegate : Signature.public_key_hash; consensus_key : Signature.public_key_hash; - consensus_power : int; + consensus_power : Attestation_power_repr.t; } -> Kind.attestation contents_result | Preattestations_aggregate_result : { balance_updates : Receipt.balance_updates; - committee : (Consensus_key.t * int) list; - total_consensus_power : int; + committee : (Consensus_key.t * Attestation_power_repr.t) list; + total_consensus_power : Attestation_power_repr.t; } -> Kind.preattestations_aggregate contents_result | Attestations_aggregate_result : { balance_updates : Receipt.balance_updates; - committee : (Consensus_key.t * int) list; - total_consensus_power : int; + committee : (Consensus_key.t * Attestation_power_repr.t) list; + total_consensus_power : Attestation_power_repr.t; } -> Kind.attestations_aggregate contents_result | Seed_nonce_revelation_result : @@ -1035,7 +1035,7 @@ module Encoding = struct obj4 (dft "balance_updates" Receipt.balance_updates_encoding []) (req "delegate" Signature.Public_key_hash.encoding) - (req "consensus_power" int31) + (req "consensus_power" Attestation_power_repr.encoding) (req "consensus_key" Signature.Public_key_hash.encoding) let consensus_aggregate_result_encoding = @@ -1047,8 +1047,8 @@ module Encoding = struct (list (merge_objs Consensus_key.encoding - (obj1 (req "consensus_power" int31))))) - (req "total_consensus_power" int31) + (obj1 (req "consensus_power" Attestation_power_repr.encoding))))) + (req "total_consensus_power" Attestation_power_repr.encoding) type case = | Case : { diff --git a/src/proto_alpha/lib_protocol/apply_results.mli b/src/proto_alpha/lib_protocol/apply_results.mli index 6fa6fab25c51..e9f7ec3088df 100644 --- a/src/proto_alpha/lib_protocol/apply_results.mli +++ b/src/proto_alpha/lib_protocol/apply_results.mli @@ -69,26 +69,26 @@ and 'kind contents_result = balance_updates : Receipt.balance_updates; delegate : Signature.public_key_hash; consensus_key : Signature.public_key_hash; - consensus_power : int; + consensus_power : Attestation_power_repr.t; } -> Kind.preattestation contents_result | Attestation_result : { balance_updates : Receipt.balance_updates; delegate : Signature.public_key_hash; consensus_key : Signature.public_key_hash; - consensus_power : int; + consensus_power : Attestation_power_repr.t; } -> Kind.attestation contents_result | Preattestations_aggregate_result : { balance_updates : Receipt.balance_updates; - committee : (Consensus_key.t * int) list; - total_consensus_power : int; + committee : (Consensus_key.t * Attestation_power_repr.t) list; + total_consensus_power : Attestation_power_repr.t; } -> Kind.preattestations_aggregate contents_result | Attestations_aggregate_result : { balance_updates : Receipt.balance_updates; - committee : (Consensus_key.t * int) list; - total_consensus_power : int; + committee : (Consensus_key.t * Attestation_power_repr.t) list; + total_consensus_power : Attestation_power_repr.t; } -> Kind.attestations_aggregate contents_result | Seed_nonce_revelation_result : diff --git a/src/proto_alpha/lib_protocol/baking.ml b/src/proto_alpha/lib_protocol/baking.ml index c6237c4c01e4..d48f92ea39e4 100644 --- a/src/proto_alpha/lib_protocol/baking.ml +++ b/src/proto_alpha/lib_protocol/baking.ml @@ -60,6 +60,8 @@ let () = let bonus_baking_reward ctxt ~attestation_power = let open Result_syntax in + (* TODO ABAAB *) + let attestation_power = attestation_power.Attestation_power_repr.slots in let consensus_threshold_size = Constants.consensus_threshold_size ctxt in let* baking_reward_bonus_per_slot = Delegate.Rewards.baking_reward_bonus_per_slot ctxt @@ -148,16 +150,25 @@ let attesting_rights_by_first_slot ctxt level : Some { consensus_key; - attesting_power = 1; + attestation_power = + { + Attestation_power_repr.slots = 1; + (* TODO *) stake = 0L; + }; dal_power = in_dal_committee; } | Some - ({consensus_key; attesting_power; dal_power} : + ({consensus_key; attestation_power; dal_power} : Consensus_key.power) -> Some { consensus_key; - attesting_power = attesting_power + 1; + attestation_power = + (* TODO *) + { + attestation_power with + slots = attestation_power.slots + 1; + }; dal_power = dal_power + in_dal_committee; }) slots_map diff --git a/src/proto_alpha/lib_protocol/baking.mli b/src/proto_alpha/lib_protocol/baking.mli index ed491d8bfaf7..20cee99b3835 100644 --- a/src/proto_alpha/lib_protocol/baking.mli +++ b/src/proto_alpha/lib_protocol/baking.mli @@ -62,4 +62,5 @@ val attesting_rights_by_first_slot : (context * Consensus_key.power Slot.Map.t) tzresult Lwt.t (** Computes the bonus baking reward depending on the attestation power. *) -val bonus_baking_reward : context -> attestation_power:int -> Tez.t tzresult +val bonus_baking_reward : + context -> attestation_power:Attestation_power_repr.t -> Tez.t tzresult diff --git a/src/proto_alpha/lib_protocol/delegate_consensus_key.ml b/src/proto_alpha/lib_protocol/delegate_consensus_key.ml index bac79afbac72..66deb6f268e6 100644 --- a/src/proto_alpha/lib_protocol/delegate_consensus_key.ml +++ b/src/proto_alpha/lib_protocol/delegate_consensus_key.ml @@ -128,7 +128,7 @@ type pk = Raw_context.consensus_pk = { type power = Raw_context.consensus_power = { consensus_key : pk; - attesting_power : int; + attestation_power : Attestation_power_repr.t; dal_power : int; } diff --git a/src/proto_alpha/lib_protocol/delegate_consensus_key.mli b/src/proto_alpha/lib_protocol/delegate_consensus_key.mli index 45ceafd0f645..7be5382d70e3 100644 --- a/src/proto_alpha/lib_protocol/delegate_consensus_key.mli +++ b/src/proto_alpha/lib_protocol/delegate_consensus_key.mli @@ -53,7 +53,7 @@ type pk = Raw_context.consensus_pk = { (** The attesting and dal power related to the associated consensus key *) type power = Raw_context.consensus_power = { consensus_key : pk; - attesting_power : int; + attestation_power : Attestation_power_repr.t; dal_power : 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 e17b412e2fe4..1d15b7b0989b 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml @@ -62,8 +62,10 @@ type level_participation = Participated | Didn't_participate (* Note that the participation for the last block of a cycle is recorded in the next cycle. *) let record_attesting_participation ctxt ~delegate ~participation - ~attesting_power = + ~attesting_power ~staking_weight = let open Lwt_result_syntax in + ignore staking_weight ; + (* TODO *) match participation with | Participated -> Stake_storage.set_active ctxt delegate | Didn't_participate -> ( 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 ef8366b62c10..fc651f5b2df8 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli @@ -57,6 +57,7 @@ val record_attesting_participation : delegate:Signature.Public_key_hash.t -> participation:level_participation -> attesting_power:int -> + staking_weight:Int64.t -> Raw_context.t tzresult Lwt.t (** Update the participation of a delegate as a DAL attester in the current diff --git a/src/proto_alpha/lib_protocol/raw_context.ml b/src/proto_alpha/lib_protocol/raw_context.ml index 3ae47bb0f310..b86be5abd6db 100644 --- a/src/proto_alpha/lib_protocol/raw_context.ml +++ b/src/proto_alpha/lib_protocol/raw_context.ml @@ -93,7 +93,7 @@ let consensus_pk_encoding = type consensus_power = { consensus_key : consensus_pk; - attesting_power : int; + attestation_power : Attestation_power_repr.t; dal_power : int; } @@ -103,19 +103,20 @@ module Raw_consensus = struct this delegate. *) type t = { - current_attestation_power : int; - (** Number of attestation slots recorded for the current block. *) + current_attestation_power : Attestation_power_repr.t; + (** Number of attestation slots and their related staking power recorded + for the current block. *) allowed_attestations : consensus_power Slot_repr.Map.t option; (** Attestations rights for the current block. Only an attestation for the lowest slot in the block can be recorded. The map associates to each initial slot the [pkh] associated to this slot with its - consensus attestation power and DAL attestation power. This is - [None] only in mempool mode. *) + consensus attestation power, DAL attestation power, and staking power. + This is [None] only in mempool mode. *) allowed_preattestations : consensus_power Slot_repr.Map.t option; (** Preattestations rights for the current block. Only a preattestation for the lowest slot in the block can be recorded. The map associates to each initial slot the [pkh] associated to this slot with its - consensus attestation power and DAL attestation power. This is + consensus attestation power, DAL attestation power and staking power. This is [None] only in mempool mode, or in application mode when there is no locked round (so the block cannot contain any preattestations). *) allowed_consensus : consensus_power Slot_repr.Map.t Level_repr.Map.t option; @@ -130,8 +131,8 @@ module Raw_consensus = struct preattestations_seen : Slot_repr.Set.t; (** Record the preattestations already seen. Only initial slots are indexed. *) - locked_round_evidence : (Round_repr.t * int) option; - (** Record the preattestation power for a locked round. *) + locked_round_evidence : (Round_repr.t * Attestation_power_repr.t) option; + (** Record the preattestation power and staking power for a locked round. *) preattestations_quorum_round : Round_repr.t option; (** in block construction mode, record the round of preattestations included in a block. *) @@ -150,7 +151,7 @@ module Raw_consensus = struct let empty : t = { - current_attestation_power = 0; + current_attestation_power = Attestation_power_repr.zero; allowed_attestations = Some Slot_repr.Map.empty; allowed_preattestations = Some Slot_repr.Map.empty; allowed_consensus = None; @@ -179,20 +180,24 @@ module Raw_consensus = struct let record_attestation t ~initial_slot ~power = let open Result_syntax in - let+ () = + let* () = error_when (Slot_repr.Set.mem initial_slot t.attestations_seen) Double_inclusion_of_consensus_operation in - { - t with - current_attestation_power = t.current_attestation_power + power; - attestations_seen = Slot_repr.Set.add initial_slot t.attestations_seen; - } + let current_attestation_power = + Attestation_power_repr.add power t.current_attestation_power + in + return + { + t with + current_attestation_power; + attestations_seen = Slot_repr.Set.add initial_slot t.attestations_seen; + } let record_preattestation ~initial_slot ~power round t = let open Result_syntax in - let+ () = + let* () = error_when (Slot_repr.Set.mem initial_slot t.preattestations_seen) Double_inclusion_of_consensus_operation @@ -205,14 +210,16 @@ module Raw_consensus = struct It doesn't matter in that case since quorum certificates are not used in mempool. For other cases [Apply.check_round] verifies it. *) - Some (round, evidences + power) + let power = Attestation_power_repr.add power evidences in + Some (round, power) in - { - t with - locked_round_evidence; - preattestations_seen = - Slot_repr.Set.add initial_slot t.preattestations_seen; - } + return + { + t with + locked_round_evidence; + preattestations_seen = + Slot_repr.Set.add initial_slot t.preattestations_seen; + } let set_forbidden_delegates delegates t = {t with forbidden_delegates = delegates} @@ -2158,7 +2165,7 @@ module type CONSENSUS = sig type error += Slot_map_not_found of {loc : string} - val current_attestation_power : t -> int + val current_attestation_power : t -> Attestation_power_repr.t val initialize_consensus_operation : t -> @@ -2167,10 +2174,15 @@ module type CONSENSUS = sig allowed_consensus:consensus_power slot_map level_map option -> t - val record_attestation : t -> initial_slot:slot -> power:int -> t tzresult + val record_attestation : + t -> initial_slot:slot -> power:Attestation_power_repr.t -> t tzresult val record_preattestation : - t -> initial_slot:slot -> power:int -> round -> t tzresult + t -> + initial_slot:slot -> + power:Attestation_power_repr.t -> + round -> + t tzresult val forbid_delegate : t -> Signature.Public_key_hash.t -> t @@ -2182,7 +2194,7 @@ module type CONSENSUS = sig val set_preattestations_quorum_round : t -> round -> t - val locked_round_evidence : t -> (round * int) option + val locked_round_evidence : t -> (round * Attestation_power_repr.t) option val set_attestation_branch : t -> Block_hash.t * Block_payload_hash.t -> t diff --git a/src/proto_alpha/lib_protocol/raw_context.mli b/src/proto_alpha/lib_protocol/raw_context.mli index 6fc8a8ccea04..14d52d2ac6a7 100644 --- a/src/proto_alpha/lib_protocol/raw_context.mli +++ b/src/proto_alpha/lib_protocol/raw_context.mli @@ -357,7 +357,7 @@ end type consensus_power = { consensus_key : consensus_pk; - attesting_power : int; + attestation_power : Attestation_power_repr.t; dal_power : int; } @@ -399,9 +399,9 @@ module type CONSENSUS = sig (** Missing pre-computed map by first slot. This error should not happen. *) type error += Slot_map_not_found of {loc : string} - (** [attestation power ctx] returns the attestation power of the + (** [attestation power ctx] returns the attestation power and stake of the current block. *) - val current_attestation_power : t -> int + val current_attestation_power : t -> Attestation_power_repr.t (** Initializes the map of allowed attestations and preattestations, this function must be called only once and before applying any consensus @@ -419,7 +419,8 @@ module type CONSENSUS = sig The attestation should be valid in the sense that [Int_map.find_opt initial_slot allowed_attestation ctx = Some (pkh, power)]. *) - val record_attestation : t -> initial_slot:slot -> power:int -> t tzresult + val record_attestation : + t -> initial_slot:slot -> power:Attestation_power_repr.t -> t tzresult (** [record_preattestation ctx ~initial_slot ~power round payload_hash power] records a preattestation for a proposal at @@ -429,7 +430,11 @@ module type CONSENSUS = sig [Int_map.find_opt initial_slot allowed_preattestation ctx = Some (pkh, power)]. *) val record_preattestation : - t -> initial_slot:slot -> power:int -> round -> t tzresult + t -> + initial_slot:slot -> + power:Attestation_power_repr.t -> + round -> + t tzresult (** [forbid_delegate ctx delegate] adds [delegate] to the set of forbidden delegates, which prevents this delegate from baking or @@ -457,7 +462,7 @@ module type CONSENSUS = sig (** [locked_round_evidence ctx] returns the round of the recorded preattestations as well as their power. *) - val locked_round_evidence : t -> (round * int) option + val locked_round_evidence : t -> (round * Attestation_power_repr.t) option val set_attestation_branch : t -> Block_hash.t * Block_payload_hash.t -> 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 3cf1c161be52..0cebaf6a384f 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 @@ -108,12 +108,12 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters 0 attesters in - if voting_power = total_consensus_power then return_unit + if voting_power = total_consensus_power.slots then return_unit else Test.fail "Wrong voting power : expected %d, found %d" voting_power - total_consensus_power + total_consensus_power.slots in (* Check committee *) let expected_committee = @@ -123,6 +123,11 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters ({Alpha_context.Consensus_key.delegate; consensus_pkh}, power)) attesters in + let resulting_committee = + List.map + (fun (a, b) -> (a, b.Attestation_power_repr.slots)) + resulting_committee + in if List.equal (fun ( {Alpha_context.Consensus_key.delegate = d1; consensus_pkh = c1}, diff --git a/src/proto_alpha/lib_protocol/validate.ml b/src/proto_alpha/lib_protocol/validate.ml index 67c6b58ed95e..deae3b3cd691 100644 --- a/src/proto_alpha/lib_protocol/validate.ml +++ b/src/proto_alpha/lib_protocol/validate.ml @@ -431,8 +431,8 @@ type block_state = { remaining_block_gas : Gas.Arith.fp; recorded_operations_rev : Operation_hash.t list; last_op_validation_pass : int option; - locked_round_evidence : (Round.t * int) option; - attestation_power : int; + locked_round_evidence : (Round.t * Attestation_power_repr.t) option; + attestation_power : Attestation_power_repr.t; } type validation_state = { @@ -480,7 +480,7 @@ let init_block_state vi = recorded_operations_rev = []; last_op_validation_pass = None; locked_round_evidence = None; - attestation_power = 0; + attestation_power = Attestation_power_repr.zero; } let get_initial_ctxt {info; _} = info.ctxt @@ -638,7 +638,7 @@ module Consensus = struct let (Single (Preattestation consensus_content)) = operation.protocol_data.contents in - let* {consensus_key; attesting_power; dal_power = _} = + let* {consensus_key; attestation_power; dal_power = _} = match vi.mode with | Application block_info | Partial_validation block_info -> let* () = @@ -699,7 +699,7 @@ module Consensus = struct ] else [] in - return (attesting_power, check_signature) + return (attestation_power, check_signature) let check_preattestation_conflict vs oph (op : Kind.preattestation operation) = @@ -751,7 +751,9 @@ module Consensus = struct construction mode. *) Some ( consensus_content.round, - total_attesting_power + attesting_power )) + Attestation_power_repr.add + total_attesting_power + attesting_power )) in {block_state with locked_round_evidence} @@ -869,7 +871,7 @@ module Consensus = struct let (Single (Attestation {consensus_content; dal_content})) = operation.protocol_data.contents in - let* {consensus_key; attesting_power; dal_power = _} = + let* {consensus_key; attestation_power; dal_power = _} = match vi.mode with | Application _ | Partial_validation _ | Construction _ -> ( let* () = @@ -912,7 +914,7 @@ module Consensus = struct [(fun () -> check_attestation_signature vi consensus_key operation)] else [] in - return (attesting_power, check_signature) + return (attestation_power, check_signature) let check_attestation_conflict vs oph (operation : Kind.attestation operation) = @@ -957,7 +959,10 @@ module Consensus = struct | Application _ | Partial_validation _ | Construction _ -> { block_state with - attestation_power = block_state.attestation_power + attesting_power; + attestation_power = + Attestation_power_repr.add + block_state.attestation_power + attesting_power; } (* Hypothesis: this function will only be called in mempool mode *) @@ -1312,12 +1317,12 @@ module Consensus = struct return_unit | Mempool -> return_unit in - (* Retrieve public keys and compute total voting power *) - let* public_keys, total_voting_power = + (* Retrieve public keys and compute total attestation power *) + let* public_keys, total_attestation_power = List.fold_left_es - (fun (public_keys, total_voting_power) slot -> + (fun (public_keys, total_attestation_power) slot -> (* Lookup the slot owner *) - let*? {consensus_key; attesting_power; dal_power = _} = + let*? {consensus_key; attestation_power; dal_power = _} = get_delegate_details consensus_info.preattestation_slot_map Preattestation @@ -1329,9 +1334,12 @@ module Consensus = struct match consensus_key.consensus_pk with | Bls pk -> return - (pk :: public_keys, attesting_power + total_voting_power) + ( pk :: public_keys, + Attestation_power_repr.add + attestation_power + total_attestation_power ) | _ -> tzfail Validate_errors.Consensus.Non_bls_key_in_aggregate) - ([], 0) + ([], Attestation_power_repr.zero) committee in (* Fail on empty committee *) @@ -1360,7 +1368,7 @@ module Consensus = struct block_state info.mode {level; round; block_payload_hash; slot = Slot.zero} - total_voting_power + total_attestation_power in return {validation_state with block_state} @@ -1422,7 +1430,7 @@ module Consensus = struct List.fold_left_es (fun (pks, weighted_pks, total_power) (slot, dal) -> (* Lookup the slot owner *) - let*? {consensus_key; attesting_power; dal_power = _} = + let*? {consensus_key; attestation_power; dal_power = _} = get_delegate_details consensus_info.attestation_slot_map Attestation @@ -1432,7 +1440,9 @@ module Consensus = struct check_delegate_is_not_forbidden info.ctxt consensus_key.delegate in let* () = check_dal_content info level slot consensus_key dal in - let total_power = attesting_power + total_power in + let total_power = + Attestation_power_repr.add attestation_power total_power + in match consensus_key.consensus_pk with | Bls consensus_pk -> ( let pks = consensus_pk :: pks in @@ -1458,7 +1468,7 @@ module Consensus = struct (Missing_companion_key_for_bls_dal (Consensus_key.pkh consensus_key))) | _ -> tzfail Validate_errors.Consensus.Non_bls_key_in_aggregate) - ([], [], 0) + ([], [], Attestation_power_repr.zero) committee in (* Fail on empty committee *) @@ -4019,7 +4029,8 @@ let check_attestation_power vi bs = in if are_attestations_required then let required = Constants.consensus_threshold_size vi.ctxt in - let provided = bs.attestation_power in + (* TODO ABAÆB *) + let provided = bs.attestation_power.slots in fail_unless Compare.Int.(provided >= required) (Not_enough_attestations {required; provided}) @@ -4066,10 +4077,20 @@ let check_preattestation_round_and_power vi vs round = {locked_round = preattestation_round; round}) in let consensus_threshold = Constants.consensus_threshold_size vi.ctxt in - error_when - Compare.Int.(total_attesting_power < consensus_threshold) - (Insufficient_locked_round_evidence - {total_attesting_power; consensus_threshold}) + let all_bakers_attest_enabled = + Stake_distribution.check_all_bakers_attest_at_level + vi.ctxt + vi.current_level + in + if all_bakers_attest_enabled then + error Validate_errors.Consensus.All_bakers_attest_not_implemented + (* TODO ABAAB *) + else + let total_attesting_power = total_attesting_power.slots in + error_when + Compare.Int.(total_attesting_power < consensus_threshold) + (Insufficient_locked_round_evidence + {total_attesting_power; consensus_threshold}) let check_payload_hash block_state ~predecessor_hash (block_header_contents : Block_header.contents) = diff --git a/src/proto_alpha/lib_protocol/validate_errors.ml b/src/proto_alpha/lib_protocol/validate_errors.ml index db5d7c73c924..a89f60292688 100644 --- a/src/proto_alpha/lib_protocol/validate_errors.ml +++ b/src/proto_alpha/lib_protocol/validate_errors.ml @@ -144,6 +144,7 @@ module Consensus = struct hash : Operation_hash.t; } | Empty_aggregation_committee + | All_bakers_attest_not_implemented let () = register_error_kind @@ -464,7 +465,17 @@ module Consensus = struct Format.fprintf ppf "The aggregation committee is empty.") Data_encoding.empty (function Empty_aggregation_committee -> Some () | _ -> None) - (fun () -> Empty_aggregation_committee) + (fun () -> Empty_aggregation_committee) ; + register_error_kind + `Permanent + ~id:"validate.all_bakers_attest_not_implemented" + ~title:"All bakers attest not implemented" + ~description:"All bakers attest is not implemented yet" + ~pp:(fun ppf () -> + Format.fprintf ppf "All bakers attest is not implemented yet") + Data_encoding.empty + (function All_bakers_attest_not_implemented -> Some () | _ -> None) + (fun () -> All_bakers_attest_not_implemented) end module Voting = struct diff --git a/src/proto_alpha/lib_protocol/validate_errors.mli b/src/proto_alpha/lib_protocol/validate_errors.mli index aa1bf223faa1..1fd06f503ed2 100644 --- a/src/proto_alpha/lib_protocol/validate_errors.mli +++ b/src/proto_alpha/lib_protocol/validate_errors.mli @@ -94,6 +94,7 @@ module Consensus : sig hash : Operation_hash.t; } | Empty_aggregation_committee + | All_bakers_attest_not_implemented end (** Errors that may arise while validating a voting operation. *) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 47ebb6ff20a8..23fb0a5c5745 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -9309,7 +9309,7 @@ let create_tz4_accounts_stake_and_wait ~funders ~client ~node nb_to_create = new_tz4_accounts companions -let test_aggregation_required_to_pass_quorum _protocol dal_parameters _cryptobox +let test_aggregation_required_to_pass_quorum protocol dal_parameters _cryptobox node client dal_node = let slot_index = 0 in let* () = Dal_RPC.(call dal_node (patch_profiles [Operator slot_index])) in @@ -9353,7 +9353,10 @@ let test_aggregation_required_to_pass_quorum _protocol dal_parameters _cryptobox let aggregated_attestation_consensus_power = JSON.( aggregated_attestation |-> "contents" |> as_list |> List.hd |-> "metadata" - |-> "total_consensus_power" |> as_int) + |-> "total_consensus_power" + |> fun x -> + if Protocol.number protocol >= 024 then x |-> "slots" |> as_int + else x |> as_int) in let* constants = Node.RPC.call node @@ RPC.get_chain_block_context_constants () diff --git a/teztale/bin_teztale_archiver/alpha_machine.real.ml b/teztale/bin_teztale_archiver/alpha_machine.real.ml index 9b328bcd3f78..9271b7d4db54 100644 --- a/teztale/bin_teztale_archiver/alpha_machine.real.ml +++ b/teztale/bin_teztale_archiver/alpha_machine.real.ml @@ -240,7 +240,7 @@ module Services : Protocol_machinery.PROTOCOL_SERVICES = struct kind; }; delegate = Tezos_crypto.Signature.Of_V2.public_key_hash ck.delegate; - power; + power = power.Protocol.Attestation_power_repr.slots; } :: acc) acc @@ -276,7 +276,7 @@ module Services : Protocol_machinery.PROTOCOL_SERVICES = struct }; delegate = Tezos_crypto.Signature.Of_V2.public_key_hash delegate; - power = consensus_power; + power = consensus_power.slots; } :: acc | Receipt @@ -298,7 +298,7 @@ module Services : Protocol_machinery.PROTOCOL_SERVICES = struct }; delegate = Tezos_crypto.Signature.Of_V2.public_key_hash delegate; - power = consensus_power; + power = consensus_power.slots; } :: acc | Receipt -- GitLab From 01bbc2cb5bc29d9e2efddf5cd8ef2ba04d80b8d6 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 14 May 2025 14:45:26 +0200 Subject: [PATCH 5/8] Proto: attesting_rights_by_first_slot with staking weight --- src/proto_alpha/lib_protocol/baking.ml | 28 +++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_protocol/baking.ml b/src/proto_alpha/lib_protocol/baking.ml index d48f92ea39e4..fd49c03e5bb4 100644 --- a/src/proto_alpha/lib_protocol/baking.ml +++ b/src/proto_alpha/lib_protocol/baking.ml @@ -117,7 +117,7 @@ let attesting_rights_by_first_slot ctxt level : Slot.Range.create ~min:0 ~count:(Constants.consensus_committee_size ctxt) in let number_of_shards = Constants.dal_number_of_shards ctxt in - let* ctxt, (_, slots_map) = + let* ctxt, (delegates_map, slots_map) = Slot.Range.fold_es (fun (ctxt, (delegates_map, slots_map)) slot -> let+ ctxt, consensus_key = @@ -153,7 +153,7 @@ let attesting_rights_by_first_slot ctxt level : attestation_power = { Attestation_power_repr.slots = 1; - (* TODO *) stake = 0L; + (* built at a later step *) stake = 0L; }; dal_power = in_dal_committee; } @@ -164,7 +164,6 @@ let attesting_rights_by_first_slot ctxt level : { consensus_key; attestation_power = - (* TODO *) { attestation_power with slots = attestation_power.slots + 1; @@ -177,4 +176,27 @@ let attesting_rights_by_first_slot ctxt level : (ctxt, (Signature.Public_key_hash.Map.empty, Slot.Map.empty)) slots in + let* ctxt, _, stake_info_list = Stake_distribution.stake_info ctxt level in + let slots_map = + List.fold_left + (fun acc ((consensus_pk, weight) : Consensus_key.pk * Int64.t) -> + match + Signature.Public_key_hash.Map.find consensus_pk.delegate delegates_map + with + | None -> acc + | Some slot -> ( + match Slot.Map.find slot slots_map with + | None -> acc (* Impossible by construction *) + | Some v -> + Slot.Map.add + slot + { + v with + attestation_power = + {v.attestation_power with stake = weight}; + } + acc)) + Slot.Map.empty + stake_info_list + in return (ctxt, slots_map) -- GitLab From 2208c21578f0cef0060b8cf4e8eee4d8c9fff644 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 30 Jul 2025 12:29:53 +0200 Subject: [PATCH 6/8] Proto: update record_attesting_participation with new data --- .../lib_protocol/alpha_context.mli | 1 - src/proto_alpha/lib_protocol/apply.ml | 1 - .../delegate_missed_attestations_storage.ml | 29 +++++++------------ .../delegate_missed_attestations_storage.mli | 1 - 4 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index e4be93e4708c..4965c7c28b66 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2357,7 +2357,6 @@ module Delegate : sig delegate:public_key_hash -> participation:level_participation -> attesting_power:int -> - staking_weight:Int64.t -> context tzresult Lwt.t val record_dal_participation : diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index e2cc11ade727..6b82310a1ff3 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -3013,7 +3013,6 @@ let record_attesting_participation ctxt dal_attestation = ~delegate:consensus_key.delegate ~participation ~attesting_power:attestation_power.slots - ~staking_weight:attestation_power.stake in Dal_apply.record_participation ctxt diff --git a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml index 1d15b7b0989b..6de36bb5fe2f 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.ml @@ -62,10 +62,8 @@ type level_participation = Participated | Didn't_participate (* Note that the participation for the last block of a cycle is recorded in the next cycle. *) let record_attesting_participation ctxt ~delegate ~participation - ~attesting_power ~staking_weight = + ~attesting_power = let open Lwt_result_syntax in - ignore staking_weight ; - (* TODO *) match participation with | Participated -> Stake_storage.set_active ctxt delegate | Didn't_participate -> ( @@ -80,12 +78,16 @@ let record_attesting_participation ctxt ~delegate ~participation {remaining_slots; missed_levels = missed_levels + 1} | None -> ( let level = Level_storage.current ctxt in - let*? stake_distribution = - Raw_context.stake_distribution_for_current_cycle ctxt + let* ctxt, total_active_stake_weight, stake_list = + Delegate_sampler.stake_info ctxt level in - match - Signature.Public_key_hash.Map.find delegate stake_distribution - with + let stake_weight_info = + List.find + (fun (pk, _) -> + Signature.Public_key_hash.equal delegate pk.Raw_context.delegate) + stake_list + in + match stake_weight_info with | None -> (* This happens when the block is the first one in a cycle, and therefore the attestations are for the last @@ -94,17 +96,8 @@ let record_attesting_participation ctxt ~delegate ~participation case its participation is simply ignored. *) assert (Compare.Int32.(level.cycle_position = 0l)) ; return ctxt - | Some active_stake -> - let* total_active_stake = - Stake_storage.get_total_active_stake ctxt level.cycle - in + | Some (_, active_stake_weight) -> let expected_slots = - let active_stake_weight = - Stake_repr.staking_weight active_stake - in - let total_active_stake_weight = - Stake_repr.staking_weight total_active_stake - in expected_slots_for_given_active_stake ctxt ~total_active_stake_weight 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 fc651f5b2df8..ef8366b62c10 100644 --- a/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli +++ b/src/proto_alpha/lib_protocol/delegate_missed_attestations_storage.mli @@ -57,7 +57,6 @@ val record_attesting_participation : delegate:Signature.Public_key_hash.t -> participation:level_participation -> attesting_power:int -> - staking_weight:Int64.t -> Raw_context.t tzresult Lwt.t (** Update the participation of a delegate as a DAL attester in the current -- GitLab From 503af52f4f4dc9be3e2d241b8a6d5b6b1db1d021 Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 30 Jul 2025 12:30:15 +0200 Subject: [PATCH 7/8] Proto/RPC: add and test new stake_info RPC --- docs/protocols/alpha.rst | 4 ++++ src/proto_alpha/lib_plugin/RPC.ml | 18 +++++++++++++++++- tezt/lib_tezos/RPC.ml | 3 +++ tezt/lib_tezos/RPC.mli | 2 ++ tezt/tests/consensus_key.ml | 19 ++++++++++++++----- ... - delegate - consensus - destination).out | 18 ++++++++++++++++++ ...- delegate - consensus -- destination).out | 18 ++++++++++++++++++ ...-- delegate - consensus - destination).out | 18 ++++++++++++++++++ ...- delegate - consensus -- destination).out | 18 ++++++++++++++++++ 9 files changed, 112 insertions(+), 6 deletions(-) diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index 5da70a609501..d7ab696e0b94 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -34,6 +34,10 @@ Breaking Changes RPC Changes ----------- +- Added ``GET /chains//blocks//helpers/stake_info``, + which returns the staking power distribution for all the active delegates + at the current cycle. (MR :gl:`!18019`) + Operation receipts ------------------ diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index d4736610f9f2..cb5df08aaa88 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -4159,6 +4159,14 @@ module S = struct ~query:RPC_query.empty ~output:Data_encoding.int64 RPC_path.(path / "total_baking_power") + + let stake_info = + RPC_service.get_service + ~description:"Returns the stake info." + ~query:RPC_query.empty + ~output: + Data_encoding.(tup2 int64 (list (tup2 Consensus_key.encoding int64))) + RPC_path.(path / "stake_info") end type Environment.Error_monad.error += Negative_level_offset @@ -4220,7 +4228,15 @@ let register () = Registration.register0 ~chunked:false S.total_baking_power (fun ctxt () () -> Stake_distribution.For_RPC.total_baking_power ctxt - (Level.current ctxt).cycle) + (Level.current ctxt).cycle) ; + Registration.register0 ~chunked:false S.stake_info (fun ctxt () () -> + let* _, total_stake, stake_info_list = + Stake_distribution.stake_info ctxt (Level.current ctxt) + in + let stake_info_list = + List.map (fun (x, y) -> (Consensus_key.pkh x, y)) stake_info_list + in + return (total_stake, stake_info_list)) let current_level ctxt ?(offset = 0l) block = RPC_context.make_call0 S.current_level ctxt block {offset} () diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index 649ba8f620f5..1000774b045b 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -2015,3 +2015,6 @@ let get_stake_distribution ?(chain = "main") ?(block = "head") ~cycle () = baking_power = frozen_stake + delegated_stake; }) bakers_with_pow + +let get_stake_info ?(chain = "main") ?(block = "head") () = + make GET ["chains"; chain; "blocks"; block; "helpers"; "stake_info"] Fun.id diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 48daf6e6641f..99491f6869f8 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -1467,3 +1467,5 @@ type baker_with_power = {delegate : string; baking_power : int} val get_stake_distribution : ?chain:string -> ?block:string -> cycle:int -> unit -> baker_with_power list t + +val get_stake_info : ?chain:string -> ?block:string -> unit -> JSON.t t diff --git a/tezt/tests/consensus_key.ml b/tezt/tests/consensus_key.ml index 1d8d9877697f..9868e7ecb635 100644 --- a/tezt/tests/consensus_key.ml +++ b/tezt/tests/consensus_key.ml @@ -819,7 +819,7 @@ let test_revert_to_unique_consensus_key ?(baker = Constant.bootstrap1.alias) let test_drain_delegate_1 ?(baker = Constant.bootstrap1.alias) ~(delegate : Account.key) ~(consensus : Account.key) - ~(destination : Account.key) client = + ~(destination : Account.key) ~protocol client = let* () = update_consensus_key ~baker ~src:delegate ~consensus_key:consensus client in @@ -855,6 +855,11 @@ let test_drain_delegate_1 ?(baker = Constant.bootstrap1.alias) (* In case delegate = baker, use the consensus key updated above *) client in + let* _ = + if Protocol.number protocol >= 024 then + Lwt.map ignore @@ Client.RPC.call ~hooks client @@ RPC.get_stake_info () + else return () + in let* _ = Client.RPC.call ~hooks client @@ RPC.get_chain_block_context_delegate delegate.public_key_hash @@ -999,7 +1004,7 @@ let register ~protocols = let () = register "Test drain delegate with (baker = delegate & consensus = destination)" - (fun _protocol client baker_0 _baker_1 account_0 _account_1 _account_2 -> + (fun protocol client baker_0 _baker_1 account_0 _account_1 _account_2 -> let delegate = baker_0 in let consensus = account_0 in let destination = account_0 in @@ -1008,13 +1013,14 @@ let register ~protocols = ~delegate ~consensus ~destination + ~protocol client) protocols in let () = register "Test drain delegate with (baker = delegate & consensus <> destination)" - (fun _protocol client baker_0 _baker_1 account_0 account_1 _account_2 -> + (fun protocol client baker_0 _baker_1 account_0 account_1 _account_2 -> let delegate = baker_0 in let consensus = account_0 in let destination = account_1 in @@ -1023,13 +1029,14 @@ let register ~protocols = ~delegate ~consensus ~destination + ~protocol client) protocols in let () = register "Test drain delegate with (baker <> delegate & consensus = destination)" - (fun _protocol client baker_0 baker_1 account_0 _account_1 _account_2 -> + (fun protocol client baker_0 baker_1 account_0 _account_1 _account_2 -> let delegate = baker_0 in let consensus = account_0 in let destination = account_0 in @@ -1038,13 +1045,14 @@ let register ~protocols = ~delegate ~consensus ~destination + ~protocol client) protocols in let () = register "Test drain delegate with (baker <> delegate & consensus <> destination)" - (fun _protocol client baker_0 baker_1 account_0 account_1 _account_2 -> + (fun protocol client baker_0 baker_1 account_0 account_1 _account_2 -> let delegate = baker_0 in let consensus = account_0 in let destination = account_1 in @@ -1053,6 +1061,7 @@ let register ~protocols = ~delegate ~consensus ~destination + ~protocol client) protocols in diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus - destination).out b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus - destination).out index c5f7b3f38b51..d88e0964d1d7 100644 --- a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus - destination).out +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus - destination).out @@ -225,6 +225,24 @@ This sequence of operations was run: [PUBLIC_KEY_HASH] ... +ꜩ38000.028561 +./octez-client rpc get /chains/main/blocks/head/helpers/stake_info +[ "7333333414212", + [ [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666747548" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ] ] ] + ./octez-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' { "deactivated": false, "is_forbidden": false, "participation": diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus -- destination).out b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus -- destination).out index 0631ee030dd2..e8cdc200f2c9 100644 --- a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus -- destination).out +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker - delegate - consensus -- destination).out @@ -225,6 +225,24 @@ This sequence of operations was run: [PUBLIC_KEY_HASH] ... +ꜩ38000.028561 +./octez-client rpc get /chains/main/blocks/head/helpers/stake_info +[ "7333333414212", + [ [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666747548" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ] ] ] + ./octez-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' { "deactivated": false, "is_forbidden": false, "participation": diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus - destination).out b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus - destination).out index fb10de9b2e1c..555e2cdd0328 100644 --- a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus - destination).out +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus - destination).out @@ -225,6 +225,24 @@ This sequence of operations was run: [PUBLIC_KEY_HASH] ... +ꜩ38000.025708 +./octez-client rpc get /chains/main/blocks/head/helpers/stake_info +[ "7333333414117", + [ [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666732452" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666681667" ] ] ] + ./octez-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' { "deactivated": false, "is_forbidden": false, "participation": diff --git a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus -- destination).out b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus -- destination).out index 2539b321730e..41f10c2c00ba 100644 --- a/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus -- destination).out +++ b/tezt/tests/expected/consensus_key.ml/Alpha- Test drain delegate with (baker -- delegate - consensus -- destination).out @@ -225,6 +225,24 @@ This sequence of operations was run: [PUBLIC_KEY_HASH] ... +ꜩ38000.025708 +./octez-client rpc get /chains/main/blocks/head/helpers/stake_info +[ "7333333414117", + [ [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666732452" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666666666" ], + [ { "delegate": "[PUBLIC_KEY_HASH]", + "consensus_pkh": "[PUBLIC_KEY_HASH]" }, + "1466666681667" ] ] ] + ./octez-client rpc get '/chains/main/blocks/head/context/delegates/[PUBLIC_KEY_HASH]' { "deactivated": false, "is_forbidden": false, "participation": -- GitLab From fb605034a3c9c037b4041fdca16c9873fc07c44e Mon Sep 17 00:00:00 2001 From: Lucas Randazzo Date: Wed, 30 Jul 2025 13:45:48 +0200 Subject: [PATCH 8/8] Kaitai: update --- .../alpha__operation__data_and_metadata.ksy | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/client-libs/kaitai-struct-files/files/alpha__operation__data_and_metadata.ksy b/client-libs/kaitai-struct-files/files/alpha__operation__data_and_metadata.ksy index bba5364b9023..1511e6169c46 100644 --- a/client-libs/kaitai-struct-files/files/alpha__operation__data_and_metadata.ksy +++ b/client-libs/kaitai-struct-files/files/alpha__operation__data_and_metadata.ksy @@ -1632,7 +1632,7 @@ types: type: public_key_hash doc: A Ed25519, Secp256k1, P256, or BLS public key hash - id: consensus_power - type: int31 + type: consensus_power committee_entries_1: seq: - id: committee_elt @@ -1645,6 +1645,12 @@ types: type: s4be - id: block_payload_hash size: 32 + consensus_power: + seq: + - id: slots + type: int31 + - id: stake + type: s8be contents: seq: - id: contents_entries @@ -2138,7 +2144,7 @@ types: type: public_key_hash doc: A Ed25519, Secp256k1, P256, or BLS public key hash - id: consensus_power - type: int31 + type: consensus_power - id: consensus_key type: public_key_hash doc: A Ed25519, Secp256k1, P256, or BLS public key hash @@ -2149,7 +2155,7 @@ types: - id: committee type: committee_2 - id: total_consensus_power - type: int31 + type: total_consensus_power metadata_1: seq: - id: punished_delegate @@ -3617,6 +3623,12 @@ types: type: n - id: ticket_updates type: ticket_updates_0 + total_consensus_power: + seq: + - id: slots + type: int31 + - id: stake + type: s8be transaction: seq: - id: source -- GitLab