diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index 800049857342fc344e6dcfdff0f0a7206cef67b5..36f7d0ca3ff2502def69a7cadd4ac9c677cf86fc 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -50,11 +50,11 @@ Breaking Changes 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). - Also include a new field for delegates, ``attesting_power``, with their attesting power - for the level. - (MR :gl:`!18931`, :gl:`!18959`) + list contains the fields present in the previous version of this RPC: ``delegate``, "slots" + which have been renamed to ``rounds``, ``consensus_key``, and ``companion_key`` (optional). + Also include new fields for delegates, ``attesting_power``, with their attesting power + for the level, and ``attestation_slot``, their slot for the given level. + (MR :gl:`!18931`, :gl:`!18959`, :gl:`!18984`) - Updated ``GET /chains//blocks//context/issuance/expected_issuance``, changing ``baking_reward_bonus_per_slot`` with ``baking_reward_bonus_per_block``, and diff --git a/src/proto_alpha/lib_delegate/baking_actions.ml b/src/proto_alpha/lib_delegate/baking_actions.ml index c661272ac463bf28e0fe92428fd908027850bd75..0d616aac9debffe54843a27c13e4248f1ef9ea85 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.ml +++ b/src/proto_alpha/lib_delegate/baking_actions.ml @@ -146,8 +146,8 @@ and level_update = { new_level_proposal : proposal; compute_new_state : current_round:Round.t -> - delegate_slots:delegate_slots -> - next_level_delegate_slots:delegate_slots -> + delegate_infos:delegate_infos -> + next_level_delegate_infos:delegate_infos -> dal_attestable_slots:dal_attestable_slots -> next_level_dal_attestable_slots:dal_attestable_slots -> (state * action) Lwt.t; @@ -1022,13 +1022,13 @@ let inject_block ?(force_injection = false) ?(asynchronous = true) state let prepare_waiting_for_quorum state = let consensus_threshold = - Delegate_slots.consensus_threshold state.level_state.delegate_slots + Delegate_infos.consensus_threshold state.level_state.delegate_infos in let consensus_committee = - Delegate_slots.consensus_committee state.level_state.delegate_slots + Delegate_infos.consensus_committee state.level_state.delegate_infos in let get_slot_voting_power ~slot = - Delegate_slots.voting_power state.level_state.delegate_slots ~slot + Delegate_infos.voting_power state.level_state.delegate_infos ~slot in let latest_proposal = state.level_state.latest_proposal.block in (* assert (latest_proposal.block.round = state.round_state.current_round) ; *) @@ -1084,15 +1084,15 @@ let compute_round (proposal : proposal) round_durations = ~predecessor_round:predecessor_block.round ~timestamp -let notice_delegates_without_slots all_delegates delegate_slots level = +let notice_delegates_without_slots all_delegates delegate_infos level = let delegates_without_slots = List.filter (fun {Baking_state_types.Key.id; _} -> not @@ List.exists - (fun ({delegate = {consensus_key; _}; _} : delegate_slot) -> + (fun ({delegate = {consensus_key; _}; _} : delegate_info) -> id = consensus_key.id) - (Baking_state.Delegate_slots.own_delegates delegate_slots)) + (Baking_state.Delegate_infos.own_delegates delegate_infos)) all_delegates in match delegates_without_slots with @@ -1112,11 +1112,11 @@ let update_to_level state level_update = | Node -> Lwt.return_unit | Local index -> index.sync_fun () in - let* delegate_slots = + let* delegate_infos = if Int32.(new_level = succ state.level_state.current_level) then - return state.level_state.next_level_delegate_slots + return state.level_state.next_level_delegate_infos else - Baking_state.compute_delegate_slots + Baking_state.compute_delegate_infos cctxt delegates ~level:new_level @@ -1124,8 +1124,8 @@ let update_to_level state level_update = [@profiler.record_s {verbosity = Debug} "compute predecessor delegate slots"] in - let* next_level_delegate_slots = - (Baking_state.compute_delegate_slots + let* next_level_delegate_infos = + (Baking_state.compute_delegate_infos cctxt delegates ~level:(Int32.succ new_level) @@ -1133,7 +1133,7 @@ let update_to_level state level_update = [@profiler.record_s {verbosity = Debug} "compute current delegate slots"]) in let*! () = - notice_delegates_without_slots delegates delegate_slots new_level + notice_delegates_without_slots delegates delegate_infos new_level in let round_durations = state.global_state.round_durations in let*? current_round = @@ -1153,21 +1153,21 @@ let update_to_level state level_update = Node_rpc.dal_attestable_slots dal_node_rpc_ctxt ~attestation_level:new_level - (Delegate_slots.own_delegates delegate_slots) + (Delegate_infos.own_delegates delegate_infos) in let next_level_dal_attestable_slots = Node_rpc.dal_attestable_slots dal_node_rpc_ctxt ~attestation_level:(Int32.succ new_level) - (Delegate_slots.own_delegates next_level_delegate_slots) + (Delegate_infos.own_delegates next_level_delegate_infos) in Lwt.return (dal_attestable_slots, next_level_dal_attestable_slots)) in let*! new_state = (compute_new_state ~current_round - ~delegate_slots - ~next_level_delegate_slots + ~delegate_infos + ~next_level_delegate_infos ~dal_attestable_slots ~next_level_dal_attestable_slots [@profiler.record_s {verbosity = Debug} "compute new state"]) diff --git a/src/proto_alpha/lib_delegate/baking_actions.mli b/src/proto_alpha/lib_delegate/baking_actions.mli index 45cc85c6d6c15ed185dd0e14515f11dce494a9cd..7d9c90697d851ccdf7651c2a00e048594b3445c8 100644 --- a/src/proto_alpha/lib_delegate/baking_actions.mli +++ b/src/proto_alpha/lib_delegate/baking_actions.mli @@ -54,8 +54,8 @@ and level_update = { new_level_proposal : proposal; compute_new_state : current_round:Round.t -> - delegate_slots:delegate_slots -> - next_level_delegate_slots:delegate_slots -> + delegate_infos:delegate_infos -> + next_level_delegate_infos:delegate_infos -> dal_attestable_slots:dal_attestable_slots -> next_level_dal_attestable_slots:dal_attestable_slots -> (state * action) Lwt.t; diff --git a/src/proto_alpha/lib_delegate/baking_lib.ml b/src/proto_alpha/lib_delegate/baking_lib.ml index 6ec89e5070e98828e21eccc7eb25a285bded7dc8..a71be658395fbe6192560140b9be9fb3d7becac4 100644 --- a/src/proto_alpha/lib_delegate/baking_lib.ml +++ b/src/proto_alpha/lib_delegate/baking_lib.ml @@ -235,7 +235,7 @@ let first_automaton_event state = let attestations_attesting_power state attestations = let get_attestation_voting_power {slot; _} = match - Delegate_slots.voting_power state.level_state.delegate_slots ~slot + Delegate_infos.voting_power state.level_state.delegate_infos ~slot with | None -> 0L (* cannot happen *) | Some attesting_power -> attesting_power @@ -349,7 +349,7 @@ let propose_at_next_level ~minimal_timestamp state = let attestation_quorum state = let power, attestations = state_attesting_power state in let consensus_threshold = - Delegate_slots.consensus_threshold state.level_state.delegate_slots + Delegate_infos.consensus_threshold state.level_state.delegate_infos in if Compare.Int64.(power >= consensus_threshold) then Some (power, attestations) else None @@ -709,7 +709,7 @@ let rec baking_minimal_timestamp ~count state |> attestations_attesting_power state in let consensus_threshold = - Delegate_slots.consensus_threshold state.level_state.delegate_slots + Delegate_infos.consensus_threshold state.level_state.delegate_infos in let* () = if Compare.Int64.(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 c4dbd2ccb539b4b0f24251e1e8f75e7de19fdcd8..6e194048aded9c2296f688844914ded27bb6bdf4 100644 --- a/src/proto_alpha/lib_delegate/baking_scheduling.ml +++ b/src/proto_alpha/lib_delegate/baking_scheduling.ml @@ -296,21 +296,19 @@ let first_potential_round ~committee_size ~owned_slots ~earliest_round = within the range [0 ... committee_size], look for the first subsequent slot we own, and finally translate it back to a round by restoring the original offset. *) - (* TODO https://gitlab.com/tezos/tezos/-/issues/7931 - The use of Round.to_slot should be avoided *) - let*? earliest_slot = Round.to_slot ~committee_size earliest_round in - let*? earliest_round = Round.to_int earliest_round in - let period_offset = earliest_round / committee_size in - match Delegate_slots.find_first_slot_from owned_slots ~slot:earliest_slot with - | Some (slot, delegate) -> - let slot = Slot.to_int slot in - let*? round = Round.of_int (slot + (committee_size * period_offset)) in + let*? earliest_round_int = Round.to_int earliest_round in + let period_offset = earliest_round_int / committee_size in + let*? round_rem = Round.of_int (earliest_round_int mod committee_size) in + match Delegate_infos.find_first_round_from owned_slots ~round:round_rem with + | Some (round, delegate) -> + let*? round = Round.to_int round in + let*? round = Round.of_int (round + (committee_size * period_offset)) in Some (round, delegate.delegate) | None -> - let* slot, delegate = Delegate_slots.min_slot owned_slots in - let slot = Slot.to_int slot in + let* round, delegate = Delegate_infos.min_round owned_slots in + let*? round = Round.to_int round in let*? round = - Round.of_int (slot + (committee_size * (1 + period_offset))) + Round.of_int (round + (committee_size * (1 + period_offset))) in Some (round, delegate.delegate) @@ -318,14 +316,14 @@ let first_potential_round_at_next_level state ~earliest_round = let committee_size = state.global_state.constants.Constants.parametric.consensus_committee_size in - let owned_slots = state.level_state.next_level_delegate_slots in + let owned_slots = state.level_state.next_level_delegate_infos in first_potential_round ~committee_size ~owned_slots ~earliest_round let first_potential_round_at_current_level state ~earliest_round = let committee_size = state.global_state.constants.Constants.parametric.consensus_committee_size in - let owned_slots = state.level_state.delegate_slots in + let owned_slots = state.level_state.delegate_infos in first_potential_round ~committee_size ~owned_slots ~earliest_round (** [current_round_at_next_level] converts the current system timestamp @@ -674,15 +672,15 @@ let create_initial_state cctxt ?dal_node_rpc_ctxt ?(synchronize = true) ~chain } ; let chain = `Hash chain_id in let current_level = current_proposal.block.shell.level in - let* delegate_slots = - Baking_state.compute_delegate_slots + let* delegate_infos = + Baking_state.compute_delegate_infos cctxt delegates ~level:current_level ~chain in - let* next_level_delegate_slots = - Baking_state.compute_delegate_slots + let* next_level_delegate_infos = + Baking_state.compute_delegate_infos cctxt delegates ~level:(Int32.succ current_level) @@ -703,7 +701,7 @@ let create_initial_state cctxt ?dal_node_rpc_ctxt ?(synchronize = true) ~chain Node_rpc.dal_attestable_slots dal_node_rpc_ctxt ~attestation_level:current_level - (Delegate_slots.own_delegates delegate_slots)) + (Delegate_infos.own_delegates delegate_infos)) dal_node_rpc_ctxt in let next_level_dal_attestable_slots = @@ -713,7 +711,7 @@ let create_initial_state cctxt ?dal_node_rpc_ctxt ?(synchronize = true) ~chain Node_rpc.dal_attestable_slots dal_node_rpc_ctxt ~attestation_level:(Int32.succ current_level) - (Delegate_slots.own_delegates next_level_delegate_slots)) + (Delegate_infos.own_delegates next_level_delegate_infos)) dal_node_rpc_ctxt in let level_state = @@ -725,8 +723,8 @@ let create_initial_state cctxt ?dal_node_rpc_ctxt ?(synchronize = true) ~chain locked_round = None; attestable_payload = None; elected_block; - delegate_slots; - next_level_delegate_slots; + delegate_infos; + next_level_delegate_infos; next_level_latest_forge_request = None; dal_attestable_slots; next_level_dal_attestable_slots; @@ -944,8 +942,9 @@ let try_resolve_consensus_keys cctxt key = delegate; consensus_key = _; companion_key = _; - slots = _; + rounds = _; attesting_power = _; + attestation_slot = _; } :: _; _; diff --git a/src/proto_alpha/lib_delegate/baking_state.ml b/src/proto_alpha/lib_delegate/baking_state.ml index de5a2c43012bc6a50d53c3c703005f7347387364..76111296ef38dd4e566a6b1db944a541d18e6243 100644 --- a/src/proto_alpha/lib_delegate/baking_state.ml +++ b/src/proto_alpha/lib_delegate/baking_state.ml @@ -126,24 +126,25 @@ let block_info_encoding = module SlotMap : Map.S with type key = Slot.t = Map.Make (Slot) -type delegate_slot = { +module RoundMap : Map.S with type key = Round.t = Map.Make (Round) + +type delegate_info = { delegate : Delegate.t; - first_slot : Slot.t; + attestation_slot : Slot.t; attesting_power : int64; } -module Delegate_slots = struct - (* Note that we also use the delegate slots as proposal slots. *) +module Delegate_infos = struct type t = { - own_delegates : delegate_slot list; - own_delegate_slots : delegate_slot SlotMap.t; - (* This map cannot have as keys just the first slot of delegates, + own_delegates : delegate_info list; + own_delegate_rounds : delegate_info RoundMap.t; + (* This map cannot have as keys just the first round of delegates, because it is used in [round_proposer] for which we need all slots, as the round can be arbitrary. *) all_delegate_voting_power : int64 SlotMap.t; - (* This is a map having as keys the first slot of all delegates, and as + (* This is a map having as keys the attestation slot of all delegates, and as values their attesting power. - This map contains just the first slot for a delegate, because it is + Without all bakers attest, this map contains just the first slot for a delegate, because it is only used in [slot_voting_power] which is about (pre)attestations, not proposals. Indeed, only (pre)attestations that use the delegate's first slot are valid for inclusion in a block and count toward the @@ -155,31 +156,29 @@ module Delegate_slots = struct consensus_committee : int64; } - let own_delegates slots = slots.own_delegates - - let own_slot_owner slots ~slot = SlotMap.find slot slots.own_delegate_slots - - let find_first_slot_from slots ~slot = - SlotMap.find_first (fun s -> Slot.(s >= slot)) slots.own_delegate_slots - - let min_slot slots = SlotMap.min_binding slots.own_delegate_slots + let own_delegates t = t.own_delegates - let own_round_owner slots ~committee_size ~round = + let own_round_owner t ~committee_size ~round = let open Result_syntax in - let* slot = - Round.to_slot ~committee_size round |> Environment.wrap_tzresult + let* round_int = Round.to_int round |> Environment.wrap_tzresult in + let* round_rem = + Round.of_int (round_int mod committee_size) |> Environment.wrap_tzresult in - return @@ SlotMap.find slot slots.own_delegate_slots + return @@ RoundMap.find round_rem t.own_delegate_rounds - let voting_power slots ~slot = - SlotMap.find slot slots.all_delegate_voting_power + let find_first_round_from t ~round = + RoundMap.find_first (fun s -> Round.(s >= round)) t.own_delegate_rounds + + let min_round t = RoundMap.min_binding t.own_delegate_rounds + + let voting_power t ~slot = SlotMap.find slot t.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 +type delegate_infos = Delegate_infos.t type dal_attestable_slots = (Delegate_id.t @@ -241,7 +240,7 @@ type prepared_block = { baking_votes : Per_block_votes_repr.per_block_votes; } -(* The fields {current_level}, {delegate_slots}, {next_level_delegate_slots}, +(* The fields {current_level}, {delegate_infos}, {next_level_delegate_infos}, {next_level_latest_forge_request}, {dal_attestable_slots}, {next_level_dal_attestable_slots} are updated only when we receive a block at a different level than {current_level}. Note that this means that there is @@ -257,8 +256,8 @@ type level_state = { attestable_payload : attestable_payload option; (* Block for which we've seen 2f+1 attestations and that we may bake onto *) elected_block : elected_block option; - delegate_slots : delegate_slots; - next_level_delegate_slots : delegate_slots; + delegate_infos : delegate_infos; + next_level_delegate_infos : delegate_infos; next_level_latest_forge_request : Round.t option; dal_attestable_slots : dal_attestable_slots; next_level_dal_attestable_slots : dal_attestable_slots; @@ -942,7 +941,7 @@ let may_load_attestable_data state = (* Helpers *) -let delegate_slots attesting_rights delegates = +let delegate_infos attesting_rights delegates = let open Lwt_syntax in let known_keys = Key.Set.of_list delegates in match attesting_rights with @@ -956,44 +955,51 @@ let delegate_slots attesting_rights delegates = }; ] -> let* ( own_delegate_first_slots, - own_delegate_slots, + own_delegate_rounds, all_delegate_voting_power ) = Lwt_list.fold_left_s (fun (own_list, own_map, all_map) validator -> - let {Plugin.RPC.Validators.slots; attesting_power; _} = validator in - let first_slot = Stdlib.List.hd slots in - let attesting_power = attesting_power in - let all_map = SlotMap.add first_slot attesting_power all_map in + let { + Plugin.RPC.Validators.rounds; + attesting_power; + attestation_slot; + _; + } = + validator + in + let all_map = + SlotMap.add attestation_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} + {delegate; attestation_slot; attesting_power} in return ( attesting_slot :: own_list, List.fold_left - (fun own_map slot -> - SlotMap.add slot attesting_slot own_map) + (fun own_map round -> + RoundMap.add round attesting_slot own_map) own_map - slots ) + rounds ) in return (own_list, own_map, all_map)) - ([], SlotMap.empty, SlotMap.empty) + ([], RoundMap.empty, SlotMap.empty) attesting_rights in return { - Delegate_slots.own_delegates = own_delegate_first_slots; - own_delegate_slots; + Delegate_infos.own_delegates = own_delegate_first_slots; + own_delegate_rounds; all_delegate_voting_power; consensus_threshold; consensus_committee; } -let compute_delegate_slots (cctxt : Protocol_client_context.full) +let compute_delegate_infos (cctxt : Protocol_client_context.full) ?(block = `Head 0) ~level ~chain delegates = let open Lwt_result_syntax in let*? level = Environment.wrap_tzresult (Raw_level.of_int32 level) in @@ -1004,23 +1010,23 @@ let compute_delegate_slots (cctxt : Protocol_client_context.full) ~levels:[level] [@profiler.record_s {verbosity = Debug} "RPC: get attesting rights"]) in - let*! delegate_slots = - (delegate_slots + let*! delegate_infos = + (delegate_infos attesting_rights - delegates [@profiler.record_f {verbosity = Debug} "delegate_slots"]) + delegates [@profiler.record_f {verbosity = Debug} "delegate_infos"]) in - return delegate_slots + return delegate_infos let round_proposer state ~level round = let slots = match level with - | `Current -> state.level_state.delegate_slots - | `Next -> state.level_state.next_level_delegate_slots + | `Current -> state.level_state.delegate_infos + | `Next -> state.level_state.next_level_delegate_infos in let committee_size = state.global_state.constants.parametric.consensus_committee_size in - match Delegate_slots.own_round_owner slots ~round ~committee_size with + match Delegate_infos.own_round_owner slots ~round ~committee_size with | Error _ -> None | Ok owner -> owner @@ -1173,52 +1179,59 @@ let pp_elected_block fmt {proposal; attestation_qc} = proposal.block (List.length attestation_qc) -let pp_delegate_slot fmt {delegate; first_slot; attesting_power} = +let pp_delegate_info fmt {delegate; attestation_slot; attesting_power} = Format.fprintf fmt - "slots: @[first_slot: %a@],@ delegate: %a,@ attesting_power: %Ld" + "slots: @[attestation_slot: %a@],@ delegate: %a,@ attesting_power: %Ld" Slot.pp - first_slot + attestation_slot Delegate.pp delegate attesting_power (* this type is only used below for pretty-printing *) -type delegate_slots_for_pp = {attester : Delegate.t; all_slots : Slot.t list} +type delegate_infos_for_pp = {attester : Delegate.t; all_rounds : Round.t list} -let delegate_slots_for_pp delegate_slot_map = - SlotMap.fold - (fun slot {delegate; first_slot; attesting_power = _} acc -> - match SlotMap.find first_slot acc with +let delegate_infos_for_pp delegate_info_map = + RoundMap.fold + (fun round {delegate; attestation_slot; attesting_power = _} acc -> + match SlotMap.find attestation_slot acc with | None -> - SlotMap.add first_slot {attester = delegate; all_slots = [slot]} acc - | Some {attester; all_slots} -> - SlotMap.add first_slot {attester; all_slots = slot :: all_slots} acc) - delegate_slot_map + SlotMap.add + attestation_slot + {attester = delegate; all_rounds = [round]} + acc + | Some {attester; all_rounds} -> + SlotMap.add + attestation_slot + {attester; all_rounds = round :: all_rounds} + acc) + delegate_info_map SlotMap.empty - |> SlotMap.map (fun {attester; all_slots} -> - {attester; all_slots = List.rev all_slots}) + |> SlotMap.map (fun {attester; all_rounds} -> + {attester; all_rounds = List.rev all_rounds}) -let pp_delegate_slots fmt (Delegate_slots.{own_delegate_slots; _} as t) = +let pp_delegate_infos fmt (Delegate_infos.{own_delegate_rounds; _} as t) = Format.fprintf fmt "@[%a@]" Format.( pp_print_list ~pp_sep:pp_print_cut - (fun fmt (first_slot, {attester; all_slots}) -> + (fun fmt (first_slot, {attester; all_rounds}) -> Format.fprintf fmt "attester: %a, power: %Ld, first 10 slots: %a" Delegate.pp attester (Option.value ~default:0L - @@ Delegate_slots.voting_power t ~slot:first_slot) + @@ Delegate_infos.voting_power t ~slot:first_slot) (Format.pp_print_list ~pp_sep:(fun fmt () -> Format.pp_print_string fmt ",") - Slot.pp) - (List.filteri (fun i _ -> i < 10) all_slots))) - (SlotMap.bindings (delegate_slots_for_pp own_delegate_slots)) + pp_print_int) + (List.filteri (fun i _ -> i < 10) all_rounds + |> List.map (fun x -> Round.to_int32 x |> Int32.to_int)))) + (SlotMap.bindings (delegate_infos_for_pp own_delegate_rounds)) let pp_prepared_block fmt {signed_block_header; delegate; _} = Format.fprintf @@ -1240,8 +1253,8 @@ let pp_level_state fmt locked_round; attestable_payload; elected_block; - delegate_slots; - next_level_delegate_slots; + delegate_infos; + next_level_delegate_infos; next_level_latest_forge_request; dal_attestable_slots = _; next_level_dal_attestable_slots = _; @@ -1250,7 +1263,7 @@ let pp_level_state fmt fmt "@[Level state:@ current level: %ld@ @[proposal (applied:%b):@ \ %a@]@ locked round: %a@ attestable payload: %a@ elected block: %a@ @[own delegate slots:@ %a@]@ @[next level own delegate slots:@ %a@]@ \ + 2>own delegate infos:@ %a@]@ @[next level own delegate infos:@ %a@]@ \ next level proposed round: %a@]" current_level is_latest_proposal_applied @@ -1262,10 +1275,10 @@ let pp_level_state fmt attestable_payload (pp_option pp_elected_block) elected_block - pp_delegate_slots - delegate_slots - pp_delegate_slots - next_level_delegate_slots + pp_delegate_infos + delegate_infos + pp_delegate_infos + next_level_delegate_infos (pp_option Round.pp) next_level_latest_forge_request diff --git a/src/proto_alpha/lib_delegate/baking_state.mli b/src/proto_alpha/lib_delegate/baking_state.mli index 6d0cad992c4e13cd1c1b9bbf420eb9b38fb62854..02bee5b64cc841cf1b19d957ca0aaa35ff7fb6b4 100644 --- a/src/proto_alpha/lib_delegate/baking_state.mli +++ b/src/proto_alpha/lib_delegate/baking_state.mli @@ -29,44 +29,40 @@ open Baking_state_types (** A delegate slot consists of the delegate's consensus key, its public key hash, its first slot, and its attesting power at some level. *) -type delegate_slot = { +type delegate_info = { delegate : Delegate.t; - first_slot : Slot.t; + attestation_slot : Slot.t; attesting_power : int64; } -val pp_delegate_slot : Format.formatter -> delegate_slot -> unit +val pp_delegate_info : Format.formatter -> delegate_info -> unit -module Delegate_slots : sig +module Delegate_infos : sig (** Information regarding the slot distribution at some level. *) type t (** Returns the list of our own delegates that have at least a slot. There are no duplicates, the associated slot is the first one. *) - val own_delegates : t -> delegate_slot list - - (** Returns, among our *own* delegates, the delegate (together with its - first attesting slot) that owns the given slot, if any (even if the - given slot is not the delegate's first slot). *) - val own_slot_owner : t -> slot:Slot.t -> delegate_slot option + val own_delegates : t -> delegate_info list (** Returns, among our *own* delegates, the delegate (together with its first attesting slot) that owns the given round, if any. *) val own_round_owner : - t -> committee_size:int -> round:Round.t -> delegate_slot option tzresult + t -> committee_size:int -> round:Round.t -> delegate_info option tzresult (** Returns the voting power of the delegate whose first slot is the given slot. Returns [None] if the slot is not the first slot of any delegate. *) val voting_power : t -> slot:Slot.t -> int64 option - (** Finds the first slot greater than or equal to [slot]. Returns the - corresponding (slot, delegate) pair if found, or [None] if no such slot + (** Finds the first round greater than or equal to [round]. Returns the + corresponding (round, delegate) pair if found, or [None] if no such round exist. *) - val find_first_slot_from : t -> slot:Slot.t -> (Slot.t * delegate_slot) option + val find_first_round_from : + t -> round:Round.t -> (Round.t * delegate_info) option - (** Returns the slot with the smallest index, along with its associated + (** Returns the round 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 + val min_round : t -> (Round.t * delegate_info) option (** Returns the consensus threshold at the level the slots were computed *) val consensus_threshold : t -> int64 @@ -75,20 +71,20 @@ module Delegate_slots : sig val consensus_committee : t -> int64 end -type delegate_slots = Delegate_slots.t +type delegate_infos = Delegate_infos.t -val pp_delegate_slots : Format.formatter -> delegate_slots -> unit +val pp_delegate_infos : Format.formatter -> delegate_infos -> unit -(** [compute_delegate_slots cctxt ?block ~level ~chain delegates] computes the +(** [compute_delegate_infos cctxt ?block ~level ~chain delegates] computes the delegate slots of the given [delegates] for the [level] @param block default to [`Head 0]*) -val compute_delegate_slots : +val compute_delegate_infos : Protocol_client_context.full -> ?block:Block_services.block -> level:int32 -> chain:Shell_services.chain -> Key.t list -> - delegate_slots tzresult Lwt.t + delegate_infos tzresult Lwt.t (** {2 Consensus operations types functions} *) @@ -319,10 +315,10 @@ type level_state = { round. *) elected_block : elected_block option; (** A quorum has been reached on an applied proposal. *) - delegate_slots : delegate_slots; - (** Delegate slots for the baker delegates at the current level *) - next_level_delegate_slots : delegate_slots; - (** Delegate slots for the baker delegates at the next level *) + delegate_infos : delegate_infos; + (** Delegate infos for the baker delegates at the current level *) + next_level_delegate_infos : delegate_infos; + (** Delegate infos for the baker delegates at the next level *) next_level_latest_forge_request : Round.t option; (** Some if a forge request has been sent for the next level on the given round *) @@ -504,7 +500,7 @@ val update_current_phase : t -> phase -> t that has a proposer slot at the given round and the current or next level, if any. *) val round_proposer : - state -> level:[`Current | `Next] -> Round.t -> delegate_slot option + state -> level:[`Current | `Next] -> Round.t -> delegate_info option (** Memoization wrapper for {!Round.timestamp_of_round}. *) val timestamp_of_round : diff --git a/src/proto_alpha/lib_delegate/baking_state_types.ml b/src/proto_alpha/lib_delegate/baking_state_types.ml index e52b533842cb2e905cb43f1c31f47144d2322a32..b0d676f9af03dcd484ceb24ea0907d6b1796e343 100644 --- a/src/proto_alpha/lib_delegate/baking_state_types.ml +++ b/src/proto_alpha/lib_delegate/baking_state_types.ml @@ -182,8 +182,9 @@ module Delegate = struct Plugin.RPC.Validators.consensus_key = consensus_pkh; companion_key = companion_bls_pkh_opt; delegate = manager_pkh; - slots = _; + rounds = _; attesting_power = _; + attestation_slot = _; } = let open Lwt_syntax in match Key.Set.find_pkh consensus_pkh known_keys with diff --git a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml index fd954d79f6bc0bf2ebd0ef35d86ef5daf0f5d4c4..b4db64cd265a919947b9ca614fa50d2b9a7c6f70 100644 --- a/src/proto_alpha/lib_delegate/client_baking_denunciation.ml +++ b/src/proto_alpha/lib_delegate/client_baking_denunciation.ml @@ -195,11 +195,10 @@ let get_validator_rights state cctxt level = | [{delegates = validators; _}] -> let validators = List.fold_left - (fun acc ({consensus_key; slots; _} : RPC.Validators.delegate) -> - List.fold_left - (fun acc slot -> Slot.Map.add slot consensus_key acc) - acc - slots) + (fun acc + ({consensus_key; attestation_slot; _} : + RPC.Validators.delegate) + -> Slot.Map.add attestation_slot consensus_key acc) Slot.Map.empty validators in diff --git a/src/proto_alpha/lib_delegate/node_rpc.ml b/src/proto_alpha/lib_delegate/node_rpc.ml index 1a25d4f10f068bafb88dcf564033fa3e68248074..a54bb32cd117b2eb234cb76b07786d3caadaa160 100644 --- a/src/proto_alpha/lib_delegate/node_rpc.ml +++ b/src/proto_alpha/lib_delegate/node_rpc.ml @@ -421,16 +421,16 @@ let get_attestable_slots dal_node_rpc_ctxt delegate_id ~attested_level = () let dal_attestable_slots (dal_node_rpc_ctxt : Tezos_rpc.Context.generic) - ~attestation_level delegate_slots = + ~attestation_level delegate_infos = let attested_level = Int32.succ attestation_level in List.map - (fun (delegate_slot : delegate_slot) -> + (fun (delegate_info : delegate_info) -> let delegate_id = - Baking_state_types.Delegate.delegate_id delegate_slot.delegate + Baking_state_types.Delegate.delegate_id delegate_info.delegate in ( delegate_id, get_attestable_slots dal_node_rpc_ctxt delegate_id ~attested_level )) - delegate_slots + delegate_infos let get_dal_profiles dal_node_rpc_ctxt = Tezos_rpc.Context.make_call diff --git a/src/proto_alpha/lib_delegate/node_rpc.mli b/src/proto_alpha/lib_delegate/node_rpc.mli index e8385790e8617f95f2d3a8b30606210442791a89..a45fe3666095b8434bd43d1f67ee03be5cd498ca 100644 --- a/src/proto_alpha/lib_delegate/node_rpc.mli +++ b/src/proto_alpha/lib_delegate/node_rpc.mli @@ -88,12 +88,12 @@ val fetch_dal_config : (** [dal_attestable_slots ctxt ~attestation_level delegates_slots] calls the DAL node RPC GET /profiles//attested_levels//attestable_slots/ - for each of the delegates in [delegate_slots] and returns the corresponding + for each of the delegates in [delegate_infos] and returns the corresponding promises. *) val dal_attestable_slots : Tezos_rpc.Context.generic -> attestation_level:int32 -> - Baking_state.delegate_slot list -> + Baking_state.delegate_info list -> Baking_state.dal_attestable_slots (** [get_dal_profiles ctxt delegates] calls the DAL node RPC GET diff --git a/src/proto_alpha/lib_delegate/state_transitions.ml b/src/proto_alpha/lib_delegate/state_transitions.ml index 53bb4d06942108637fc4e1b2a891fc2588a2ff72..070bc81e19c0d00a3e66fbe561342358699e9a3b 100644 --- a/src/proto_alpha/lib_delegate/state_transitions.ml +++ b/src/proto_alpha/lib_delegate/state_transitions.ml @@ -93,9 +93,9 @@ let make_consensus_vote_batch state proposal kind = let batch_content = {level; round; block_payload_hash} in let delegates_and_slots = List.map - (fun (delegate_slot : delegate_slot) -> - (delegate_slot.delegate, delegate_slot.first_slot)) - (Delegate_slots.own_delegates state.level_state.delegate_slots) + (fun (delegate_info : delegate_info) -> + (delegate_info.delegate, delegate_info.attestation_slot)) + (Delegate_infos.own_delegates state.level_state.delegate_infos) in (* The branch is the latest finalized block. *) let batch_branch = @@ -201,7 +201,7 @@ let extract_pqc state (new_proposal : proposal) = let voting_power = let voting_power_of_slot slot = match - Delegate_slots.voting_power state.level_state.delegate_slots ~slot + Delegate_infos.voting_power state.level_state.delegate_infos ~slot with | Some attesting_power -> attesting_power | None -> 0L @@ -225,7 +225,7 @@ let extract_pqc state (new_proposal : proposal) = prequorum.preattestations in let consensus_threshold = - Delegate_slots.consensus_threshold state.level_state.delegate_slots + Delegate_infos.consensus_threshold state.level_state.delegate_infos in if Compare.Int64.(voting_power >= consensus_threshold) then Some (prequorum.preattestations, prequorum.round) @@ -425,8 +425,8 @@ let rec handle_proposal ~is_proposal_applied state (new_proposal : proposal) = This is where we update our [level_state] (and our [round_state]) *) let* () = Events.(emit new_head_with_increasing_level ()) in let new_level = new_proposal.block.shell.level in - let compute_new_state ~current_round ~delegate_slots - ~next_level_delegate_slots ~dal_attestable_slots + let compute_new_state ~current_round ~delegate_infos + ~next_level_delegate_infos ~dal_attestable_slots ~next_level_dal_attestable_slots = let round_state = { @@ -446,8 +446,8 @@ let rec handle_proposal ~is_proposal_applied state (new_proposal : proposal) = locked_round = None; attestable_payload = None; elected_block = None; - delegate_slots; - next_level_delegate_slots; + delegate_infos; + next_level_delegate_infos; next_level_latest_forge_request = None; dal_attestable_slots; next_level_dal_attestable_slots; diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index ead141d208a21ed495e19ec8c429a8c252b13d11..0bc8f11ebd18f76f9892fc54459822825b3598a3 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -3987,8 +3987,9 @@ module Validators = struct delegate : Signature.Public_key_hash.t; consensus_key : Signature.public_key_hash; companion_key : Bls.Public_key_hash.t option; - slots : Slot.t list; + rounds : Round.t list; attesting_power : int64; + attestation_slot : Slot.t; } type t = { @@ -4001,16 +4002,43 @@ module Validators = struct let delegate_encoding = let open Data_encoding in conv - (fun {delegate; consensus_key; companion_key; slots; attesting_power} -> - (delegate, slots, consensus_key, companion_key, attesting_power)) - (fun (delegate, slots, consensus_key, companion_key, attesting_power) -> - {delegate; consensus_key; companion_key; slots; attesting_power}) - (obj5 + (fun { + delegate; + consensus_key; + companion_key; + rounds; + attesting_power; + attestation_slot; + } + -> + ( delegate, + rounds, + consensus_key, + companion_key, + attesting_power, + attestation_slot )) + (fun ( delegate, + rounds, + consensus_key, + companion_key, + attesting_power, + attestation_slot ) + -> + { + delegate; + consensus_key; + companion_key; + rounds; + attesting_power; + attestation_slot; + }) + (obj6 (req "delegate" Signature.Public_key_hash.encoding) - (req "slots" (list Slot.encoding)) + (req "rounds" (list Round.encoding)) (req "consensus_key" Signature.Public_key_hash.encoding) (opt "companion_key" Bls.Public_key_hash.encoding) - (req "attesting_power" int64)) + (req "attesting_power" int64) + (req "attestation_slot" Slot.encoding)) let encoding = let open Data_encoding in @@ -4077,8 +4105,9 @@ module Validators = struct Baking.delegate; consensus_key; companion_key; - slots; + rounds; attesting_power; + attestation_slot; } acc -> @@ -4087,7 +4116,14 @@ module Validators = struct | Bls _ when aggregate_attestation -> companion_key | _ -> None in - {delegate; consensus_key; companion_key; slots; attesting_power} + { + delegate; + consensus_key; + companion_key; + rounds; + attesting_power; + attestation_slot; + } :: acc) rights [] ) diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 31ca9f43f47aa93684afcf04de2281f59fa3ff76..21684e110eecc30cbe5ced0f06d1b5b4ca5e6125 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -338,6 +338,8 @@ module Round : sig val to_slot : t -> committee_size:int -> Slot.t tzresult + val of_slot : Slot.t -> t tzresult + val pp : Format.formatter -> t -> unit val encoding : t Data_encoding.t diff --git a/src/proto_alpha/lib_protocol/baking.ml b/src/proto_alpha/lib_protocol/baking.ml index 7a57ac6e8dd99556224b6d9c734e75aa00a58201..8964820680f3979af41d3acf363d81cf535fa479 100644 --- a/src/proto_alpha/lib_protocol/baking.ml +++ b/src/proto_alpha/lib_protocol/baking.ml @@ -102,8 +102,9 @@ type ordered_slots = { delegate : Signature.public_key_hash; consensus_key : Signature.public_key_hash; companion_key : Bls.Public_key_hash.t option; - slots : Slot.t list; + rounds : Round.t list; attesting_power : int64; + attestation_slot : Slot.t; } (* Slots returned by this function are assumed by consumers to be in increasing @@ -115,20 +116,25 @@ let attesting_rights (ctxt : t) level = in let open Lwt_result_syntax in let* ctxt, _, delegates = Stake_distribution.stake_info ctxt level in - let* attesting_power_map = + let* attesting_power_map, _ = List.fold_left_es - (fun acc_map ((consensus_pk : Consensus_key.pk), power) -> + (fun (acc_map, i) ((consensus_pk : Consensus_key.pk), power) -> let acc_map = - Signature.Public_key_hash.Map.add consensus_pk.delegate power acc_map + Signature.Public_key_hash.Map.add + consensus_pk.delegate + (power, i, consensus_pk) + acc_map in - return acc_map) - Signature.Public_key_hash.Map.empty + let*? succ_i = Slot.succ i in + return (acc_map, succ_i)) + (Signature.Public_key_hash.Map.empty, Slot.zero) delegates in let*? slots = Slot.Range.create ~min:0 ~count:consensus_committee_size in let* ctxt, map = Slot.Range.rev_fold_es (fun (ctxt, map) slot -> + let*? round = Round.of_slot slot in let* ctxt, consensus_pk = Stake_distribution.slot_owner ctxt level slot in @@ -142,11 +148,18 @@ let attesting_rights (ctxt : t) level = delegate = consensus_pk.delegate; consensus_key = consensus_pk.consensus_pkh; companion_key = consensus_pk.companion_pkh; - slots = [slot]; + rounds = [round]; attesting_power = 0L; (* Updated after, once all the slots are attributed *) + attestation_slot = slot; } - | Some slots -> Some {slots with slots = slot :: slots.slots}) + | Some info -> + Some + { + info with + rounds = round :: info.rounds; + attestation_slot = slot; + }) map in return (ctxt, map)) @@ -155,16 +168,48 @@ let attesting_rights (ctxt : t) level = in let map = Signature.Public_key_hash.Map.map - (fun ({slots; delegate; _} as t) -> + (fun ({rounds; delegate; _} as t) -> if all_bakers_attest_enabled then - let attesting_power = - Option.value ~default:0L - @@ Signature.Public_key_hash.Map.find delegate attesting_power_map - in - {t with attesting_power} - else {t with attesting_power = List.length slots |> Int64.of_int}) + match + Signature.Public_key_hash.Map.find delegate attesting_power_map + with + | Some (attesting_power, attestation_slot, _) -> + (* We override the attestation slot to be accurate wrt the feature flag *) + {t with attesting_power; attestation_slot} + | None -> t + else + (* The attestation slot already has the correct value *) + {t with attesting_power = List.length rounds |> Int64.of_int}) map in + (* Add delegates without rounds *) + let map = + if all_bakers_attest_enabled then + Signature.Public_key_hash.Map.fold + (fun pkh + ( attesting_power, + attestation_slot, + (consensus_pk : Consensus_key.pk) ) + acc + -> + match Signature.Public_key_hash.Map.find pkh map with + | Some _ -> acc + | None -> + Signature.Public_key_hash.Map.add + pkh + { + delegate = consensus_pk.delegate; + consensus_key = consensus_pk.consensus_pkh; + companion_key = consensus_pk.companion_pkh; + rounds = []; + attesting_power; + attestation_slot; + } + acc) + attesting_power_map + map + else map + in return (ctxt, map) let incr_slot att_rights = @@ -231,28 +276,52 @@ let attesting_rights_by_first_slot ctxt level : (ctxt, (Signature.Public_key_hash.Map.empty, Slot.Map.empty)) slots in + let all_bakers_attest_enabled = + Attesting_power.check_all_bakers_attest_at_level ctxt level + 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) -> + let* slots_map, _ = + List.fold_left_es + (fun (acc, i) ((consensus_key, weight) : Consensus_key.pk * Int64.t) -> match - Signature.Public_key_hash.Map.find consensus_pk.delegate delegates_map + Signature.Public_key_hash.Map.find + consensus_key.delegate + delegates_map with - | None -> acc + | None -> + if all_bakers_attest_enabled then + (* The delegate doesn't have a round, but under all bakers attest, + it is still added to the map *) + let*? succ_i = Slot.succ i in + return + ( Slot.Map.add + i + { + Consensus_key.consensus_key; + attesting_power = + Attesting_power.make ~slots:0 ~stake:weight; + dal_power = 0; + } + acc, + succ_i ) + else return (acc, i) | Some slot -> ( match Slot.Map.find slot slots_map with - | None -> acc (* Impossible by construction *) + | None -> return (acc, i) (* Impossible by construction *) | Some v -> - Slot.Map.add - slot + let v = { v with attesting_power = Attesting_power.( add (make ~slots:0 ~stake:weight) v.attesting_power); } - acc)) - Slot.Map.empty + in + if all_bakers_attest_enabled then + let*? succ_i = Slot.succ i in + return (Slot.Map.add i v acc, succ_i) + else return (Slot.Map.add slot v acc, i))) + (Slot.Map.empty, Slot.zero) stake_info_list in return (ctxt, slots_map) diff --git a/src/proto_alpha/lib_protocol/baking.mli b/src/proto_alpha/lib_protocol/baking.mli index b1f113c8eaeb1c09e07d055cc6eb4b5c1b2e2619..dc5c687d1df610aeeec69d353d921b93d09efdae 100644 --- a/src/proto_alpha/lib_protocol/baking.mli +++ b/src/proto_alpha/lib_protocol/baking.mli @@ -37,8 +37,9 @@ type ordered_slots = private { delegate : Signature.public_key_hash; consensus_key : Signature.public_key_hash; companion_key : Bls.Public_key_hash.t option; - slots : Slot.t list; + rounds : Round.t list; attesting_power : int64; + attestation_slot : Slot.t; } (** For a given level computes who has the right to include an attestation in diff --git a/src/proto_alpha/lib_protocol/round_repr.ml b/src/proto_alpha/lib_protocol/round_repr.ml index ddb00e16c405147f2f79b478508b014a1253b26e..0084ef5c1ce8ecc7dcf4cd5f231d25aefae0b8c0 100644 --- a/src/proto_alpha/lib_protocol/round_repr.ml +++ b/src/proto_alpha/lib_protocol/round_repr.ml @@ -106,6 +106,10 @@ let to_slot round ~committee_size = let slot = r mod committee_size in Slot_repr.of_int slot +let of_slot slot = + let s = Slot_repr.to_int slot in + of_int s + let encoding = Data_encoding.conv_with_guard (fun i -> i) diff --git a/src/proto_alpha/lib_protocol/round_repr.mli b/src/proto_alpha/lib_protocol/round_repr.mli index 3adef4ec00c4f82ab0192291c2886d3f2b3b6ef9..7d705b8f9b1bb5ad038b86fef42093e201b8be4d 100644 --- a/src/proto_alpha/lib_protocol/round_repr.mli +++ b/src/proto_alpha/lib_protocol/round_repr.mli @@ -72,6 +72,9 @@ val to_int : t -> int tzresult mod committee_size]. *) val to_slot : t -> committee_size:int -> Slot_repr.t tzresult +(** Returns the round corresponding to the given slot *) +val of_slot : Slot_repr.t -> t tzresult + (** Round encoding. Be aware that decoding a negative 32 bit integer would lead to an exception. *) diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.ml b/src/proto_alpha/lib_protocol/test/helpers/context.ml index c5c92552035c3e7839b6ea94b9ba5c23c9d55255..df8b519e6e3544f674144a2e10824b89a35c462e 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/context.ml @@ -139,8 +139,9 @@ 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; + rounds : Round.t list; attesting_power : int64; + attestation_slot : Slot.t; } let get_attesters ctxt = @@ -174,7 +175,8 @@ let get_attester_n ctxt n = let attester = WithExceptions.Option.get ~loc:__LOC__ @@ List.nth attesters n in - (attester.consensus_key, attester.slots) + (* TODO ABAAB: check the rounds are used as rounds, not as attestation slots *) + (attester.consensus_key, attester.rounds) let attester_has_bls_key {consensus_key; _} = Signature.Public_key_hash.is_bls consensus_key @@ -198,10 +200,10 @@ let get_attesting_power_for_delegate ctxt ?level pkh = match attesters with | [{delegates = attesters; _}] -> let rec find_slots_for_delegate = function - | [] -> return 0 - | {Plugin.RPC.Validators.delegate; slots; _} :: t -> + | [] -> return 0L + | {Plugin.RPC.Validators.delegate; attesting_power; _} :: t -> if Signature.Public_key_hash.equal delegate pkh then - return (List.length slots) + return attesting_power else find_slots_for_delegate t in find_slots_for_delegate attesters @@ -212,8 +214,8 @@ let get_cumulated_attesting_power_for_delegate ctxt ~levels pkh = List.fold_left_es (fun accu level -> let+ power = get_attesting_power_for_delegate ctxt ~level pkh in - accu + power) - 0 + Int64.add accu power) + 0L levels let get_current_voting_power = Delegate_services.current_voting_power rpc_ctxt diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.mli b/src/proto_alpha/lib_protocol/test/helpers/context.mli index b5d3f229a0a2b98239032ce4742b2c90bd187451..7d9677cf8d1d6e65d014dc1c41b8cdcb4db8214c 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/context.mli @@ -43,8 +43,9 @@ 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; + rounds : Round.t list; attesting_power : int64; + attestation_slot : Slot.t; } (** Retrieves the attesting rights at the level of the given context @@ -63,7 +64,7 @@ val get_attester : ?manager_pkh:public_key_hash -> t -> attester 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 +val get_attester_n : t -> int -> (public_key_hash * Round.t list) tzresult Lwt.t (** Whether the {!type-attester}'s **consensus key** is a BLS key. *) val attester_has_bls_key : attester -> bool @@ -80,12 +81,12 @@ val get_attester_with_bls_key : t -> attester tzresult Lwt.t in the requested level. If ommited, [level] defaults to the next level. *) val get_attesting_power_for_delegate : - t -> ?level:Raw_level.t -> public_key_hash -> int tzresult Lwt.t + t -> ?level:Raw_level.t -> public_key_hash -> int64 tzresult Lwt.t (** Sums the result of [get_attesting_power_for_delegate] over a list of levels. *) val get_cumulated_attesting_power_for_delegate : - t -> levels:Raw_level.t list -> public_key_hash -> int tzresult Lwt.t + t -> levels:Raw_level.t list -> public_key_hash -> int64 tzresult Lwt.t val get_current_voting_power : t -> public_key_hash -> int64 Environment.Error_monad.shell_tzresult Lwt.t diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 6d1a9d935608041f91142ebb0c9badcf3694bbbc..144df38520e5666cad8b810a2169ca5fcc20fd47 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -115,9 +115,9 @@ let mk_block_payload_hash (b : Block.t) = type attesting_slot = {slot : Slot.t; consensus_pkh : public_key_hash} -let attesting_slot_of_attester {Plugin.RPC.Validators.consensus_key; slots; _} = - let slot = List.hd slots |> WithExceptions.Option.get ~loc:__LOC__ in - {slot; consensus_pkh = consensus_key} +let attesting_slot_of_attester + {Plugin.RPC.Validators.consensus_key; attestation_slot; _} = + {slot = attestation_slot; consensus_pkh = consensus_key} let get_attesting_slot ~attested_block = let open Lwt_result_syntax in @@ -159,18 +159,23 @@ let get_different_attesting_slot ~consensus_pkh_to_avoid ~attested_block = in return (attesting_slot_of_attester attester) -let non_canonical_attesting_slot_of_attester {Context.consensus_key; slots; _} = - let slot = - match slots with - | _ :: non_canonical_slot :: _ -> non_canonical_slot +let non_canonical_attesting_slot_of_attester {Context.consensus_key; rounds; _} + = + let open Lwt_result_wrap_syntax in + let* slot = + match rounds with + | _ :: non_canonical_slot :: _ -> + let*?@ round_int = Round.to_int non_canonical_slot in + let*?@ slot = Slot.of_int round_int in + return slot | _ -> Test.fail ~__LOC__ "Expected attester to have at least two slots" in - {slot; consensus_pkh = consensus_key} + return {slot; consensus_pkh = consensus_key} let get_non_canonical_attesting_slot ~attested_block = let open Lwt_result_syntax in let* attester = Context.get_attester (B attested_block) in - return (non_canonical_attesting_slot_of_attester attester) + non_canonical_attesting_slot_of_attester attester let default_committee ~attested_block = let open Lwt_result_syntax in diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 519a98ac79f8559c2476a782353778d7848b8548..e3e0b2c87786b205af09a83732672e4d81fffb90 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -91,7 +91,7 @@ val get_different_attesting_slot : its second-smallest slot (that is, a non-canonical slot that still belongs to the attester). *) val non_canonical_attesting_slot_of_attester : - Context.attester -> attesting_slot + Context.attester -> attesting_slot tzresult Lwt.t (** Retrieves the first attester returned by {!Plugin.RPC.Validators.S.validators} and builds a non-canonical 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 e056452294e09afa2be7b1e3d4d82ae223bd81d9..ec7e1f8f1a0faf556342c65dc16f11c657b88782 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 @@ -74,7 +74,8 @@ type 'kind aggregate = | Preattestation : Alpha_context.Kind.preattestations_aggregate aggregate | Attestation : Alpha_context.Kind.attestations_aggregate aggregate -let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters +let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters ~ctxt + ~level (result : kind Tezos_protocol_alpha__Protocol.Apply_results.contents_result) = let open Lwt_result_syntax in @@ -104,31 +105,37 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters let voting_power = List.fold_left (fun acc (delegate : RPC.Validators.delegate) -> - List.length delegate.slots + acc) - 0 + Int64.add delegate.attesting_power acc) + 0L attesters in let total_consensus_power = - Alpha_context.Attesting_power.get_slots total_consensus_power + Alpha_context.Attesting_power.get ctxt level total_consensus_power in - if voting_power = total_consensus_power then return_unit + if Int64.equal voting_power total_consensus_power then return_unit else Test.fail - "Wrong voting power : expected %d, found %d" + "Wrong voting power : expected %Ld, found %Ld" voting_power total_consensus_power in (* Check committee *) let expected_committee = List.map - (fun {Context.delegate; consensus_key = consensus_pkh; slots; _} -> - let power = List.length slots in - ({Alpha_context.Consensus_key.delegate; consensus_pkh}, power)) + (fun { + Context.delegate; + consensus_key = consensus_pkh; + attesting_power; + _; + } + -> + ( {Alpha_context.Consensus_key.delegate; consensus_pkh}, + attesting_power )) attesters in let resulting_committee = List.map - (fun (a, b) -> (a, Alpha_context.Attesting_power.get_slots b)) + (fun (a, b) -> (a, Alpha_context.Attesting_power.get ctxt level b)) resulting_committee in if @@ -139,7 +146,7 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters -> Signature.Public_key_hash.equal d1 d2 && Signature.Public_key_hash.equal c1 c2 - && Int.equal power1 power2) + && Int64.equal power1 power2) resulting_committee expected_committee then return_unit @@ -148,7 +155,7 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters Format.pp_print_list (fun fmt (consensus_key, power) -> Format.fprintf fmt - "%a with power %d" + "%a with power %Ld" Alpha_context.Consensus_key.pp consensus_key power) @@ -229,8 +236,14 @@ let check_preattestations_aggregate_validation_and_application ~loc ~attesters in match error with | None -> - let*? block_with_metadata = res in - check_after_preattestations_aggregate ~attesters block_with_metadata + let*? ((b, _) as block_with_metadata) = res in + let* ctxt = Block.get_alpha_ctxt b in + let level = Alpha_context.Level.current ctxt in + check_after_preattestations_aggregate + ~attesters + ~ctxt + ~level + block_with_metadata | Some error -> Assert.proto_error ~loc res error (** Tests the validation and application of an attestations_aggregate. @@ -256,9 +269,11 @@ let check_attestations_aggregate_validation_and_application ~loc ~attesters | None -> List.map Op.attesting_slot_of_attester attesters in let* operation = Op.attestations_aggregate ~committee attested_block in + let* ctxt = Block.get_alpha_ctxt attested_block in + let level = Alpha_context.Level.current ctxt in let check_after_block_mode = match error with - | None -> Some (check_after_attestations_aggregate ~attesters) + | None -> Some (check_after_attestations_aggregate ~ctxt ~level ~attesters) | Some _ -> None in Op.check_validation_and_application_all_modes_different_outcomes @@ -382,7 +397,7 @@ let test_non_canonical_slot () = | x1 :: x2 :: _ -> (x1, x2) | _ -> Test.fail ~__LOC__ "Expected at least two attesters with BLS key" in - let non_canonical_attesting_slot = + let* non_canonical_attesting_slot = Op.non_canonical_attesting_slot_of_attester attester in let other_attesters_canonical_slot = @@ -438,8 +453,7 @@ let test_not_owned_slot () = let wrong_attesting_slot = { Op.consensus_pkh = attester.consensus_key; - slot = - WithExceptions.Option.get ~loc:__LOC__ (List.hd third_attester.slots); + slot = third_attester.attestation_slot; } in let other_attesters_canonical_slot = @@ -982,15 +996,20 @@ let test_preattestation_signature_for_attestation_bls () = test_preattestation_signature_for_attestation ~attesting_slot ~attested_block let test_signature_bls_attestation_with_different_slot () = - let open Lwt_result_syntax in + let open Lwt_result_wrap_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* attester = Context.get_attester_with_bls_key (B block) in let consensus_pkh = attester.consensus_key in - let slot1, slot2 = - match attester.slots with - | slot1 :: slot2 :: _ -> (slot1, slot2) + let* csts = Context.get_constants (B block) in + let committee_size = csts.parametric.consensus_committee_size in + let* slot1, slot2 = + match attester.rounds with + | round1 :: round2 :: _ -> + let*?@ slot1 = Alpha_context.Round.to_slot ~committee_size round1 in + let*?@ slot2 = Alpha_context.Round.to_slot ~committee_size round2 in + return (slot1, slot2) | _ -> Test.fail ~__LOC__ "Delegate must have at least two slots" in let* op_attestation1 = diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_attestation.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_attestation.ml index cba4bd040123b92b46c35775d35b9ab0b2c4e1db..1ec4b0405ad5619fa0b742b237c0ff8ccaff59ae 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_attestation.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_attestation.ml @@ -103,26 +103,32 @@ let test_fitness_gap () = (** Return a delegate and its second smallest slot for the level of [block]. *) let delegate_and_second_slot block = - let open Lwt_result_syntax in + let open Lwt_result_wrap_syntax in let* attesters = Context.get_attesters (B block) in - let delegate, slots = - (* Find an attester with more than 1 slot. *) + let* csts = Context.get_constants (B block) in + let committee_size = csts.parametric.consensus_committee_size in + let delegate, rounds = + (* Find an attester with more than 1 round. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map - (fun {RPC.Validators.delegate; slots; _} -> - if Compare.List_length_with.(slots > 1) then Some (delegate, slots) + (fun {RPC.Validators.delegate; rounds; _} -> + if Compare.List_length_with.(rounds > 1) then Some (delegate, rounds) else None) attesters) in - (* Check that the slots are sorted and have no duplicates. *) + (* Check that the rounds are sorted and have no duplicates. *) let rec check_sorted = function | [] | [_] -> true - | x :: (y :: _ as t) -> Slot.compare x y < 0 && check_sorted t + | x :: (y :: _ as t) -> Round.compare x y < 0 && check_sorted t in - assert (check_sorted slots) ; - let slot = - match slots with [] | [_] -> assert false | _ :: slot :: _ -> slot + assert (check_sorted rounds) ; + let* slot = + match rounds with + | [] | [_] -> assert false + | _ :: round :: _ -> + let*?@ slot = Round.to_slot ~committee_size round in + return slot in return (delegate, slot) @@ -179,9 +185,8 @@ let attesting_slot_with_someone_elses_slot block = let* attesters = Context.get_attesters (B block) in match attesters with | [] | [_] -> Test.fail ~__LOC__ "Expected at least two delegates with rights" - | {consensus_key = consensus_pkh; _} :: {slots; _} :: _ -> - let slot = WithExceptions.Option.get ~loc:__LOC__ (List.hd slots) in - return {Op.slot; consensus_pkh} + | {consensus_key = consensus_pkh; _} :: {attestation_slot; _} :: _ -> + return {Op.slot = attestation_slot; consensus_pkh} (** Attestation with a slot that does not belong to the delegate. *) let test_not_own_slot () = @@ -591,17 +596,19 @@ let test_attestation_threshold ~sufficient_threshold () = about 1 slot so we can get closer to the limit of [consensus_threshold_size]: we check that a block with attesting power [consensus_threshold_size - 1] won't be baked. *) + (* TODO ABAAB: adapt test with new threshold under flag *) let* genesis, _contracts = Context.init_n 10 () in let* b = Block.bake genesis in let* {parametric = {consensus_threshold_size; _}; _} = Context.get_constants (B b) in + let consensus_threshold_size = Int64.of_int consensus_threshold_size in let* attesters = Context.get_attesters (B b) in let*?@ round = Block.get_round b in let* _, attestations = List.fold_left_es (fun (counter, attestations) (attester : Context.attester) -> - let new_counter = counter + List.length attester.slots in + let new_counter = Int64.add counter attester.attesting_power in if (sufficient_threshold && counter < consensus_threshold_size) || (not sufficient_threshold) @@ -611,7 +618,7 @@ let test_attestation_threshold ~sufficient_threshold () = let* attestation = Op.attestation ~attesting_slot ~round b in return (new_counter, attestation :: attestations) else return (counter, attestations)) - (0, []) + (0L, []) attesters in let*! b = Block.bake ~operations:attestations b in diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_baking.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_baking.ml index 6e2ffa90f1462563c3b6c841e2902778b0b2ff78..2adc411ee8c650a37627661ce72931312dd41922 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_baking.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_baking.ml @@ -237,8 +237,8 @@ let test_rewards_block_and_payload_producer () = let attesting_power = List.fold_left (fun acc attester -> - acc + List.length attester.Plugin.RPC.Validators.slots) - 0 + Int64.add acc attester.Plugin.RPC.Validators.attesting_power) + 0L attesters in let fee = Tez.one in @@ -255,6 +255,8 @@ let test_rewards_block_and_payload_producer () = Context.Delegate.current_frozen_deposits (B b2) baker_b2 in let* baking_reward = Context.get_baking_reward_fixed_portion (B b2) in + (* TODO ABAAB: get correct rewards *) + let attesting_power = Int64.to_int attesting_power in let* bonus_reward = Context.get_bonus_reward (B b2) ~attesting_power in let* reward_for_b1 = if Signature.Public_key_hash.equal baker_b2 baker_b1 then 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 0d5b249897a7c99a70a39677d7b969fdfefdffd9..1d5a7797bb6e5eb3fb22a725c46236bffeba512d 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 @@ -254,21 +254,27 @@ let test_different_branch () = operations have distinct slots (that both belong to the delegate) and are otherwise identical. *) let test_different_slots () = - let open Lwt_result_syntax in + let open Lwt_result_wrap_syntax in + (* TODO ABAAB: doesn't work with ABAAB *) let* genesis, _contracts = Context.init2 ~consensus_threshold_size:0 () in let* blk = Block.bake genesis in let* attesters = Context.get_attesters (B blk) in - let consensus_pkh, slot1, slot2 = + let* csts = Context.get_constants (B blk) in + let committee_size = csts.parametric.consensus_committee_size in + let consensus_pkh, round1, round2 = (* Find an attester with more than 1 slot. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map (fun (attester : RPC.Validators.delegate) -> - match attester.slots with - | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) + match attester.rounds with + | round1 :: round2 :: _ -> + Some (attester.consensus_key, round1, round2) | _ -> None) attesters) in + let*?@ slot1 = Round.to_slot ~committee_size round1 in + let*?@ slot2 = Round.to_slot ~committee_size round2 in let attesting_slot1 = {Op.slot = slot1; consensus_pkh} in let attesting_slot2 = {Op.slot = slot2; consensus_pkh} in let* attestation1 = Op.raw_attestation ~attesting_slot:attesting_slot1 blk in @@ -977,23 +983,29 @@ let test_two_double_attestation_evidences_leads_to_duplicate_denunciation () = feature flag when operations have distinct slots and are otherwise identical. *) let different_slots_under_feature_flag () = - let open Lwt_result_syntax in + let open Lwt_result_wrap_syntax in + (* TODO ABAAB: doesn't work with ABAAB *) let* genesis, _ = Context.init2 ~consensus_threshold_size:0 ~aggregate_attestation:true () in let* block = Block.bake genesis in let* attesters = Context.get_attesters (B block) in - let consensus_pkh, slot1, slot2 = + let* csts = Context.get_constants (B block) in + let committee_size = csts.parametric.consensus_committee_size in + let consensus_pkh, round1, round2 = (* Find an attester with more than 1 slot. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map (fun (attester : RPC.Validators.delegate) -> - match attester.slots with - | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) + match attester.rounds with + | round1 :: round2 :: _ -> + Some (attester.consensus_key, round1, round2) | _ -> None) attesters) in + let*?@ slot1 = Round.to_slot ~committee_size round1 in + let*?@ slot2 = Round.to_slot ~committee_size round2 in let attesting_slot1 = {Op.slot = slot1; consensus_pkh} in let attesting_slot2 = {Op.slot = slot2; consensus_pkh} in let* attestation1 = diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_baking.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_baking.ml index eb8e115a343d437abda12c3536281a2d24c6eee5..a50a0e6132bca545e24f27b2522326d5d9cb847b 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_baking.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_baking.ml @@ -356,17 +356,12 @@ let test_payload_producer_gets_evidence_rewards () = Block.bake ~policy:(By_account baker2) ~operation:db_evidence b1 in let* attesters = Context.get_attesters (B b_with_evidence) in - let* preattesters = - List.map_es - (function - | {Plugin.RPC.Validators.delegate; slots; _} -> return (delegate, slots)) - attesters - in let* preattestations = List.map_ep - (fun (attester, _slots) -> - Op.preattestation ~manager_pkh:attester b_with_evidence) - preattesters + (function + | {Plugin.RPC.Validators.delegate; _} -> + Op.preattestation ~manager_pkh:delegate b_with_evidence) + attesters in let* b' = Block.bake 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 cb2a0c622aa57d986ffa93359fcffd80b60daf12..f83b8b3b00b7a56ca1a59a827089e63432b5d647 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 @@ -396,23 +396,29 @@ end = struct aggregate_attestation feature flag when operations have distinct slots and are otherwise identical. *) let different_slots_under_feature_flag () = - let open Lwt_result_syntax in + let open Lwt_result_wrap_syntax in + (* TODO ABAAB: doesn't work with ABAAB *) let* genesis, _ = Context.init2 ~consensus_threshold_size:0 ~aggregate_attestation:true () in let* block = Block.bake genesis in let* attesters = Context.get_attesters (B block) in - let consensus_pkh, slot1, slot2 = + let* csts = Context.get_constants (B block) in + let committee_size = csts.parametric.consensus_committee_size in + let consensus_pkh, round1, round2 = (* Find an attester with more than 1 slot. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map (fun (attester : RPC.Validators.delegate) -> - match attester.slots with - | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) + match attester.rounds with + | round1 :: round2 :: _ -> + Some (attester.consensus_key, round1, round2) | _ -> None) attesters) in + let*?@ slot1 = Round.to_slot ~committee_size round1 in + let*?@ slot2 = Round.to_slot ~committee_size round2 in let attesting_slot1 = {Op.slot = slot1; consensus_pkh} in let attesting_slot2 = {Op.slot = slot2; consensus_pkh} in let* preattestation1 = diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_participation.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_participation.ml index 4af8cdbba735949138a66caec44a7e152270ed2a..2bbc631f088f69bede8b781f824ae5e9a8d75a9a 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_participation.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_participation.ml @@ -98,8 +98,9 @@ let test_participation ~sufficient_participation () = let attester, new_attesting_power = if sufficient_participation - && attesting_power < minimal_nb_active_slots - then (del2, attesting_power + attesting_power_for_level) + && Compare.Int64.( + attesting_power < Int64.of_int minimal_nb_active_slots) + then (del2, Int64.add attesting_power attesting_power_for_level) else (del1, attesting_power) in let* b, (metadata, _) = @@ -107,7 +108,7 @@ let test_participation ~sufficient_participation () = in let autostaked = Block.autostaked_opt del2 metadata in return (b_crt, b, new_attesting_power, autostaked)) - (b0, b1, 0, None) + (b0, b1, 0L, None) (2 -- (blocks_per_cycle - 1)) in let* bal2_at_pred_b = @@ -243,7 +244,8 @@ let test_participation_rpc () = let* () = Assert.equal_int ~loc:__LOC__ info.missed_levels (level_int - 1) in - let missed_slots = total_attesting_power in + (* TODO ABAAB: cannot be cast to an int *) + let missed_slots = Int64.to_int total_attesting_power in let* () = Assert.equal_int ~loc:__LOC__ info.missed_slots missed_slots in @@ -272,8 +274,8 @@ let test_participation_rpc () = let* attesting_power = Context.get_attesting_power_for_delegate (B b_crt) ~level del2 in - return (b_crt, b, total_attesting_power + attesting_power)) - (b0, b1, 0) + return (b_crt, b, Int64.add total_attesting_power attesting_power)) + (b0, b1, 0L) (1 -- (blocks_per_cycle - 2)) in return_unit diff --git a/src/proto_alpha/lib_protocol/test/integration/validate/validate_helpers.ml b/src/proto_alpha/lib_protocol/test/integration/validate/validate_helpers.ml index c1f94115b43c69fa29e2b924a5fc03b5f4855ffb..d8e397293b4380f270b45955d56071b974823950 100644 --- a/src/proto_alpha/lib_protocol/test/integration/validate/validate_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/integration/validate/validate_helpers.ml @@ -373,8 +373,8 @@ let delegates_of_block block = let open Lwt_result_syntax in let+ validators = Context.get_attesters (B block) in List.map - (fun Plugin.RPC.Validators.{consensus_key; slots; _} -> - (consensus_key, slots)) + (fun Plugin.RPC.Validators.{consensus_key; attestation_slot; _} -> + (consensus_key, attestation_slot)) validators (** Sequential validation of an operation list. *) diff --git a/tezt/lib_tezos/RPC.ml b/tezt/lib_tezos/RPC.ml index dd14c9062f75cdd88106706a7cb2fb5d0dbd1622..c7ea26ba8d609e7ec9eae98fb13ea668c72f97d5 100644 --- a/tezt/lib_tezos/RPC.ml +++ b/tezt/lib_tezos/RPC.ml @@ -876,10 +876,11 @@ let get_chain_block_helper_attestation_rights ?(chain = "main") Fun.id let get_chain_block_helper_validators ?(chain = "main") ?(block = "head") - ?delegate ?level () = + ?delegate ?consensus_key ?level () = let query_string = Query_arg.opt "delegate" Fun.id delegate @ Query_arg.opt "level" Int.to_string level + @ Query_arg.opt "consensus_key" Fun.id consensus_key in make ~query_string diff --git a/tezt/lib_tezos/RPC.mli b/tezt/lib_tezos/RPC.mli index 81be3ede19654dd9d00bca961084ae246c35b8f6..7d74d6dfe54f657d825783607d305a06eb211508 100644 --- a/tezt/lib_tezos/RPC.mli +++ b/tezt/lib_tezos/RPC.mli @@ -799,6 +799,7 @@ val get_chain_block_helper_validators : ?chain:string -> ?block:string -> ?delegate:string -> + ?consensus_key:string -> ?level:int -> unit -> JSON.t t diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index 7e6bcffdb09df9fe30f096028b907824fefa04a5..75b2cc190af5c9ae159660caf2e45a3443ba7387 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -507,7 +507,7 @@ module Consensus = struct in inject ?request ?force ?error ~protocol op client - let get_slots ~level ~protocol client = + let get_rounds ~level ~protocol client = let* rpc_json = Client.RPC.call client @@ RPC.get_chain_block_helper_validators ~level () in @@ -519,38 +519,66 @@ module Consensus = struct | [rpc_json] -> as_list (rpc_json |-> "delegates") else as_list rpc_json in + let rounds_name = + if Protocol.number protocol >= 024 then "rounds" else "slots" + in return @@ List.map (fun json -> let delegate = json |-> "delegate" |> as_string in - let slots = json |-> "slots" |> as_list |> List.map as_int in + let slots = json |-> rounds_name |> as_list |> List.map as_int in (delegate, slots)) list - let get_slots_by_consensus_key ~level ~protocol client = + let get_attestation_slot_opt ~level ~protocol ?(delegate : Account.key option) + ?(consensus_key : Account.key option) client = + let () = + match (delegate, consensus_key) with + | Some _, Some _ -> + Test.fail + "get_attestation_slot: Cannot call function with both delegate and \ + consensus key arguments" + | None, None -> + Test.fail + "get_attestation_slot: Must call function with either delegate or \ + consensus key argument" + | Some _, None | None, Some _ -> () + in + let get_pkh (x : Account.key) = x.public_key_hash in + let delegate = Option.map get_pkh delegate in + let consensus_key = Option.map get_pkh consensus_key in let* rpc_json = - Client.RPC.call client @@ RPC.get_chain_block_helper_validators ~level () + Client.RPC.call client + @@ RPC.get_chain_block_helper_validators + ~level + ?delegate + ?consensus_key + () in - let open JSON in - let list = + try 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 + return + @@ Some + JSON.( + rpc_json |=> 0 |-> "delegates" |=> 0 |-> "attestation_slot" + |> as_int) + else return @@ Some JSON.(rpc_json |=> 0 |-> "slots" |=> 0 |> as_int) + with _ -> return None + + let get_attestation_slot ~level ~protocol ?(delegate : Account.key option) + ?(consensus_key : Account.key option) client = + let* r_opt = + get_attestation_slot_opt ~level ~protocol ?delegate ?consensus_key client 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)) - list - - let first_slot ~slots (delegate : Account.key) = - match List.assoc_opt delegate.public_key_hash slots with - | Some slots -> List.hd slots - | None -> Test.fail "No slots found for %s" delegate.public_key_hash + match r_opt with + | Some r -> return r + | None -> + let pkh = + let open Option in + if is_some delegate then (get delegate).public_key_hash + else (get consensus_key).public_key_hash + in + Test.fail "No slots found for %s" pkh let get_block_payload_hash ?block client = let* block_header = diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index 5777ea7e89cf1b50c7e6d4836a540d644da17d4c..119375d2513a8c142a570c9e3f24161932ce85b9 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -309,28 +309,37 @@ module Consensus : sig Client.t -> [`OpHash of string] Lwt.t - (** Retrieves the attestation slots at [level] by calling the + (** Retrieves the attestation rounds at [level] by calling the [GET /chains//blocks//helpers/validators] RPC. Returns an association list that maps a public key hash to - the owned slot list *) - val get_slots : + the owned rounds list *) + val get_rounds : 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 : + (** Returns the attestation slot of the provided delegate. + + Causes the test to fail if the delegate is not found. *) + val get_attestation_slot : level:int -> protocol:Protocol.t -> + ?delegate:Account.key -> + ?consensus_key:Account.key -> Client.t -> - (string * int list) list Lwt.t + int Lwt.t - (** Returns the first slot of the provided delegate in the [slots] - association list that describes all attestation rights at some level. + (** Returns the attestation slot of the provided delegate. - Causes the test to fail if the delegate is not found. *) - val first_slot : slots:(string * int list) list -> Account.key -> int + Returns None if the delegate is not found. *) + val get_attestation_slot_opt : + level:int -> + protocol:Protocol.t -> + ?delegate:Account.key -> + ?consensus_key:Account.key -> + Client.t -> + int option Lwt.t (** Calls the [GET /chains//blocks//header] RPC and extracts the head block's payload hash from the result. *) diff --git a/tezt/tests/baker_test.ml b/tezt/tests/baker_test.ml index e1e38ea956398e8a0f372c652b2fd1cc44fe12fb..234c363bc5109cbace02f66a1496ee39ed8a3aa0 100644 --- a/tezt/tests/baker_test.ml +++ b/tezt/tests/baker_test.ml @@ -802,8 +802,9 @@ let prequorum_check_levels = return @@ JSON.(json |-> "payload_hash" |> as_string) in let preattest_for ~delegate level = - let* slots = Operation.Consensus.get_slots ~level ~protocol client in - let slot = Operation.Consensus.first_slot ~slots delegate in + let* slot = + Operation.Consensus.get_attestation_slot ~level ~protocol ~delegate client + in let* _ = Operation.Consensus.preattest_for ~slot @@ -969,12 +970,6 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = let base_level = 9 in (* 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 - ~protocol - client - in let* round = fetch_round client in let* branch = Operation.Consensus.get_branch ~attested_level:base_level client @@ -991,7 +986,13 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = let dal_attestation = Array.init 16 (fun _ -> true) in let* () = Operation.Consensus.( - let slot = first_slot ~slots consensus_key1 in + let* slot = + get_attestation_slot + ~level:base_level + ~protocol + ~consensus_key:consensus_key1 + client + in let* _ = preattest_for ~protocol @@ -1037,8 +1038,15 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = let* () = Lwt_list.iter_s Operation.Consensus.( - fun ((delegate, companion_key) : Account.key * Account.key option) -> - let slot = first_slot ~slots delegate in + fun ((consensus_key, companion_key) : Account.key * Account.key option) + -> + let* slot = + get_attestation_slot + ~level:base_level + ~protocol + ~consensus_key + client + in let* _ = attest_for ~protocol @@ -1049,7 +1057,7 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = ~block_payload_hash ~dal_attestation ?companion_key - delegate + consensus_key client in unit) @@ -1069,12 +1077,6 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = power to trigger a prequorum. Consequently, the baker is expected to lock on the preattested payload and only bake reproposals. *) let* () = - let* slots = - Operation.Consensus.get_slots_by_consensus_key - ~level:(base_level + 1) - ~protocol - client - in let* round = fetch_round client in let* branch = Operation.Consensus.get_branch ~attested_level:(base_level + 1) client @@ -1089,8 +1091,14 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = branch ; Lwt_list.iter_s Operation.Consensus.( - fun (delegate : Account.key) -> - let slot = first_slot ~slots delegate in + fun (consensus_key : Account.key) -> + let* slot = + get_attestation_slot + ~level:(base_level + 1) + ~protocol + ~consensus_key + client + in let* _ = preattest_for ~protocol @@ -1099,7 +1107,7 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = ~level:(base_level + 1) ~round ~block_payload_hash - delegate + consensus_key client in unit) @@ -1113,8 +1121,15 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = let* () = Lwt_list.iter_s Operation.Consensus.( - fun ((delegate, companion_key) : Account.key * Account.key option) -> - let slot = first_slot ~slots delegate in + fun ((consensus_key, companion_key) : Account.key * Account.key option) + -> + let* slot = + get_attestation_slot + ~level:base_level + ~protocol + ~consensus_key + client + in let* _ = attest_for ~protocol @@ -1125,7 +1140,7 @@ let attestations_aggregation_on_reproposal ~remote_mode protocol = ~block_payload_hash ~dal_attestation ?companion_key - delegate + consensus_key client in unit) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 87512f4f3d8adde626a41333159385ee4134241b..f0ed370a440c0d83b9983d4656859b8f0b563d09 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -888,44 +888,30 @@ let craft_dal_attestation ~protocol ?level ?round ?payload_level ~signer let* level = match level with Some level -> return level | None -> Client.level client in - let* json = - Client.RPC.call_via_endpoint client - @@ RPC.get_chain_block_helper_validators - ~level - ~delegate:signer.Account.public_key_hash - () + let* block_payload_hash, round = + let block = Option.value payload_level ~default:level |> string_of_int in + let* block_payload_hash = + Operation.Consensus.get_block_payload_hash ~block client + in + let* round = + match round with + | None -> + Client.RPC.call_via_endpoint client + @@ RPC.get_chain_block_helper_round ~block () + | Some round -> return round + in + return (block_payload_hash, round) in - let slots = - if Protocol.number protocol >= 024 then - JSON.(json |> as_list |> List.hd |-> "delegates" |> as_list) - else JSON.as_list json + let* slot = + Operation.Consensus.get_attestation_slot_opt + ~level + ~delegate:signer + ~protocol + client in - match slots with - | [] -> - Log.info - "[craft_dal_attestation] %s not in TB committee at level %d" - signer.public_key_hash - level ; - none - | [validator] -> - let slots = JSON.(validator |-> "slots" |> as_list) in - let slot = List.hd slots |> JSON.as_int in - let* block_payload_hash, round = - let block = - Option.value payload_level ~default:level |> string_of_int - in - let* block_payload_hash = - Operation.Consensus.get_block_payload_hash ~block client - in - let* round = - match round with - | None -> - Client.RPC.call_via_endpoint client - @@ RPC.get_chain_block_helper_round ~block () - | Some round -> return round - in - return (block_payload_hash, round) - in + match slot with + | None -> none + | Some slot -> let* op = Operation.Consensus.operation ~signer @@ -939,10 +925,6 @@ let craft_dal_attestation ~protocol ?level ?round ?payload_level ~signer client in some op - | _ -> - Test.fail - ~__LOC__ - "Unexpected format for get_chain_block_helper_validators RPC" let craft_dal_attestation_exn ~protocol ?level ?round ?payload_level ~signer ~nb_slots availability client = @@ -9479,9 +9461,6 @@ 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 ~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 = @@ -9496,7 +9475,13 @@ let test_inject_accusation_aggregated_attestation nb_attesting_tz4 protocol let* () = Lwt_list.iter_s (fun {delegate_key; companion_key} -> - let first_slot = Operation.Consensus.first_slot ~slots delegate_key in + let* first_slot = + Operation.Consensus.get_attestation_slot + ~level + ~protocol + ~delegate:delegate_key + client + in let attestation = Operation.Consensus.attestation ~dal_attestation diff --git a/tezt/tests/double_consensus.ml b/tezt/tests/double_consensus.ml index 928e6f026b255800913ec0d09436aea7be41393a..aae6c91de7d243217f99aa923be3c26faeb31676 100644 --- a/tezt/tests/double_consensus.ml +++ b/tezt/tests/double_consensus.ml @@ -107,7 +107,7 @@ let double_consensus_init (if Protocol.number protocol >= 024 then JSON.( slots |> as_list |> List.hd |-> "delegates" |> as_list |> List.hd - |-> "slots" |> as_list) + |-> "rounds" |> as_list) else JSON.(slots |> as_list |> List.hd |-> "slots" |> as_list)) in Log.info "Inject valid %s." consensus_name ; @@ -395,7 +395,7 @@ let operation_too_far_in_future = (if Protocol.number protocol >= 024 then JSON.( slots |> as_list |> List.hd |-> "delegates" |> as_list |> List.hd - |-> "slots" |> as_list) + |-> "rounds" |> as_list) else JSON.(slots |> as_list |> List.hd |-> "slots" |> as_list)) in Log.info @@ -571,8 +571,9 @@ 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 ~protocol client in - let slot = first_slot ~slots ck1 in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck1 client + in let* branch = get_branch ~attested_level:level client in let* bph_level_4 = get_block_payload_hash ~block:"4" client in attest_for @@ -599,12 +600,13 @@ 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 ~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 *) let* (`OpHash _) = - let slot = first_slot ~slots ck1 in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck1 client + in attest_for ~error:delegate_forbidden_error ~protocol @@ -618,7 +620,9 @@ let attestation_and_aggregation_wrong_payload_hash = in (* Attest for bootstrap2 and expect a success *) let* (`OpHash _) = - let slot = first_slot ~slots ck2 in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck2 client + in attest_for ~protocol ~branch @@ -737,12 +741,13 @@ 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 ~protocol client1 in (* Attest with the double attesting keys and check that they are forbidden *) let* () = Lwt_list.iter_s (fun ck -> - let slot = first_slot ~slots ck in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck client1 + in let* (`OpHash _) = attest_for ~error:delegate_forbidden_error @@ -762,7 +767,9 @@ let double_aggregation_wrong_payload_hash = let* () = Lwt_list.iter_s (fun ck -> - let slot = first_slot ~slots ck in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck client1 + in let* (`OpHash _) = attest_for ~protocol @@ -912,14 +919,15 @@ 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 ~protocol client in Log.info "preattesting level %d round 1 for bootstrap1, bootstrap2 and bootstrap4" level ; let* () = Lwt_list.iter_s (fun ck -> - let slot = first_slot ~slots ck in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck client + in let* (`OpHash _) = preattest_for ~protocol @@ -965,11 +973,12 @@ 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 ~protocol client in let* () = Lwt_list.iter_s (fun ck -> - let slot = first_slot ~slots ck in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck client + in let* (`OpHash _) = attest_for ~error:delegate_forbidden_error @@ -987,7 +996,9 @@ let preattestation_and_aggregation_wrong_payload_hash = in (* Attest with a non-misbehaving key and expect a success *) let* (`OpHash _) = - let slot = first_slot ~slots ck3 in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck3 client + in attest_for ~protocol ~branch @@ -1128,12 +1139,13 @@ 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 ~protocol client1 in (* Attest with the double preattesting keys and check that they are forbidden *) let* () = Lwt_list.iter_s (fun ck -> - let slot = first_slot ~slots ck in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck client1 + in let* (`OpHash _) = attest_for ~error:delegate_forbidden_error @@ -1151,7 +1163,9 @@ let double_preattestation_aggregation_wrong_payload_hash = in (* Attest with a non-misbehaving key and expect a success *) let* (`OpHash _) = - let slot = first_slot ~slots ck3 in + let* slot = + get_attestation_slot ~level ~protocol ~consensus_key:ck3 client1 + in attest_for ~protocol ~branch diff --git a/tezt/tests/prevalidator.ml b/tezt/tests/prevalidator.ml index 2ddad0bad453b3cc103deaa090f9a6b0fe8e0924..82cf58e1fbd6824934f180e3460f7b126266ea03 100644 --- a/tezt/tests/prevalidator.ml +++ b/tezt/tests/prevalidator.ml @@ -1908,11 +1908,17 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation (delegate : Account.key) = + let* slot = + Operation.Consensus.get_attestation_slot + ~level + ~protocol + ~delegate + client + in Operation.Consensus.inject (Operation.Consensus.attestation - ~slot:(Operation.Consensus.first_slot ~slots delegate) + ~slot ~level ~round:0 ~block_payload_hash @@ -2159,12 +2165,18 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation (delegate : Account.key) = + let* slot = + Operation.Consensus.get_attestation_slot + ~level + ~protocol + ~delegate + client + in let* op = Operation.Consensus.operation (Operation.Consensus.attestation - ~slot:(Operation.Consensus.first_slot ~slots delegate) + ~slot ~level ~round:0 ~block_payload_hash @@ -2421,11 +2433,17 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation (account : Account.key) = + let* slot = + Operation.Consensus.get_attestation_slot + ~level + ~protocol + ~delegate:account + client + in Operation.Consensus.inject (Operation.Consensus.attestation - ~slot:(Operation.Consensus.first_slot ~slots account) + ~slot ~level ~round:0 ~block_payload_hash @@ -2534,11 +2552,17 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation (account : Account.key) = + let* slot = + Operation.Consensus.get_attestation_slot + ~level + ~protocol + ~delegate:account + client + in Operation.Consensus.inject (Operation.Consensus.attestation - ~slot:(Operation.Consensus.first_slot ~slots account) + ~slot ~level ~round:0 ~block_payload_hash @@ -2666,11 +2690,17 @@ module Revamped = struct let* block_payload_hash = Operation.Consensus.get_block_payload_hash client in - let* slots = Operation.Consensus.get_slots ~level ~protocol client in let inject_attestation ~(account : Account.key) ~(signer : Account.key) = + let* slot = + Operation.Consensus.get_attestation_slot + ~level + ~protocol + ~delegate:account + client + in Operation.Consensus.inject (Operation.Consensus.attestation - ~slot:(Operation.Consensus.first_slot ~slots account) + ~slot ~level ~round:0 ~block_payload_hash @@ -3809,8 +3839,10 @@ module Revamped = struct Lwt_list.fold_left_s (fun (validated, refused) level -> let* attesting_rights = - Operation.Consensus.get_slots ~level ~protocol client + Operation.Consensus.get_rounds ~level ~protocol client in + (* TODO ABAAB: this test assumes the rounds are attestation slots, this needs + to be updated with the flag status *) (* Look for a delegate that has more than one slot *) let delegate, slots = let delegate_opt =