diff --git a/src/proto_023_PtSeouLo/lib_delegate/baking_lib.ml b/src/proto_023_PtSeouLo/lib_delegate/baking_lib.ml index 4533a854f4e2c6d37e38fef1022bad3d9ec27ee5..45260ca319cc30744331da2a427a101f8d68e5df 100644 --- a/src/proto_023_PtSeouLo/lib_delegate/baking_lib.ml +++ b/src/proto_023_PtSeouLo/lib_delegate/baking_lib.ml @@ -522,20 +522,8 @@ let mk_prequorum state latest_proposal = let {level; round; block_payload_hash} : batch_content = batch.batch_content in - let preattestations : Kind.preattestation operation list = - List.filter_map - (fun op -> - let (Operation_data protocol_data) = - op.signed_operation.protocol_data - in - match protocol_data.contents with - | Single (Preattestation _) -> - let op : Kind.preattestation operation = - {shell = {branch = batch.batch_branch}; protocol_data} - in - Some op - | _ -> assert false) - batch.signed_consensus_votes + let preattestations = + List.map (fun op -> op.signed_operation) batch.signed_consensus_votes in return { diff --git a/src/proto_023_PtSeouLo/lib_delegate/baking_state.ml b/src/proto_023_PtSeouLo/lib_delegate/baking_state.ml index 3e69420fe4c66ce914aa580b807dbad5f48ee684..bee661d3fe7225cce293f0319423eec060f87d6f 100644 --- a/src/proto_023_PtSeouLo/lib_delegate/baking_state.ml +++ b/src/proto_023_PtSeouLo/lib_delegate/baking_state.ml @@ -36,7 +36,7 @@ type prequorum = { level : int32; round : Round.t; block_payload_hash : Block_payload_hash.t; - preattestations : Kind.preattestation operation list; + preattestations : packed_operation list; } type block_info = { @@ -46,7 +46,7 @@ type block_info = { payload_round : Round.t; round : Round.t; prequorum : prequorum option; - quorum : Kind.attestation operation list; + quorum : packed_operation list; payload : Operation_pool.payload; grandparent : Block_hash.t; } @@ -59,15 +59,9 @@ let prequorum_encoding = let open Data_encoding in conv (fun {level; round; block_payload_hash; preattestations} -> - (level, round, block_payload_hash, List.map Operation.pack preattestations)) + (level, round, block_payload_hash, preattestations)) (fun (level, round, block_payload_hash, preattestations) -> - { - level; - round; - block_payload_hash; - preattestations = - List.filter_map Operation_pool.unpack_preattestation preattestations; - }) + {level; round; block_payload_hash; preattestations}) (obj4 (req "level" int32) (req "round" Round.encoding) @@ -94,7 +88,7 @@ let block_info_encoding = payload_round, round, prequorum, - List.map Operation.pack quorum, + quorum, payload, grandparent )) (fun ( hash, @@ -114,7 +108,7 @@ let block_info_encoding = payload_round; round; prequorum; - quorum = List.filter_map Operation_pool.unpack_attestation quorum; + quorum; payload; }) (obj9 diff --git a/src/proto_023_PtSeouLo/lib_delegate/baking_state.mli b/src/proto_023_PtSeouLo/lib_delegate/baking_state.mli index 7e4e6b3eace25dd9ded479fa4d1748474bb8ee58..5c236fbe16b46b55c92dd1e725ee743b1b5df9be 100644 --- a/src/proto_023_PtSeouLo/lib_delegate/baking_state.mli +++ b/src/proto_023_PtSeouLo/lib_delegate/baking_state.mli @@ -199,7 +199,7 @@ type prequorum = { level : int32; round : Round.t; block_payload_hash : Block_payload_hash.t; - preattestations : Kind.preattestation operation list; + preattestations : packed_operation list; } type block_info = { @@ -209,7 +209,7 @@ type block_info = { payload_round : Round.t; round : Round.t; prequorum : prequorum option; - quorum : Kind.attestation operation list; + quorum : packed_operation list; payload : Operation_pool.payload; grandparent : Block_hash.t; } diff --git a/src/proto_023_PtSeouLo/lib_delegate/block_forge.ml b/src/proto_023_PtSeouLo/lib_delegate/block_forge.ml index 1b2279012dd4818bc9013e42a300691586b82285..87395fd12a35ac2a3541400cb8c15ebd0c7a4f3f 100644 --- a/src/proto_023_PtSeouLo/lib_delegate/block_forge.ml +++ b/src/proto_023_PtSeouLo/lib_delegate/block_forge.ml @@ -496,8 +496,12 @@ let aggregate_attestations eligible_attestations = let partition_consensus_operations_on_proposal consensus_operations = let open Operation_pool in Prioritized_operation_set.fold - (fun operation (eligible_attestations, remaining_operations) -> - let {shell; protocol_data = Operation_data protocol_data; _} = + (fun operation + ( attestations_aggregate_opt, + eligible_attestations, + remaining_operations ) -> + let ({shell; protocol_data = Operation_data protocol_data; _} as + packed_operation) = Prioritized_operation.packed operation in match (protocol_data.contents, protocol_data.signature) with @@ -508,10 +512,27 @@ let partition_consensus_operations_on_proposal consensus_operations = let remaining_operations = Prioritized_operation_set.remove operation remaining_operations in - (attestation :: eligible_attestations, remaining_operations) - | _, _ -> (eligible_attestations, remaining_operations)) + ( attestations_aggregate_opt, + attestation :: eligible_attestations, + remaining_operations ) + | ( Single (Attestations_aggregate {consensus_content; committee}), + Some (Bls signature) ) -> + let attestations_aggregate_opt = + Some + (shell, consensus_content, committee, signature, packed_operation) + in + let remaining_operations = + Prioritized_operation_set.remove operation remaining_operations + in + ( attestations_aggregate_opt, + eligible_attestations, + remaining_operations ) + | _, _ -> + ( attestations_aggregate_opt, + eligible_attestations, + remaining_operations )) consensus_operations - ([], consensus_operations) + (None, [], consensus_operations) (* [partition_consensus_operations_on_reproposal consensus_operations] partitions [consensus_operations] as follows : @@ -616,61 +637,42 @@ let filter_best_attestations_per_slot attestations = in SlotMap.fold (fun _slot attestation acc -> attestation :: acc) slot_map [] -(* [aggregate_attestations_on_proposal attestations] replaces all eligible - attestations from [attestations] by a single Attestations_aggregate. - - All attestations are assumed to target the same branch, level, round and - block_payload_hash. *) -let aggregate_attestations_on_proposal attestations = - let open Result_syntax in - let eligible_attestations, remaining_attestations = - partition_consensus_operations_on_proposal attestations - in - let* aggregate_opt = - eligible_attestations |> filter_best_attestations_per_slot - |> aggregate_attestations - in - match aggregate_opt with - | Some aggregate -> - let open Operation_pool in - return - @@ Prioritized_operation_set.add - (Prioritized_operation.extern ~priority:1 aggregate) - remaining_attestations - | None -> return remaining_attestations - module SlotSet : Set.S with type elt = Slot.t = Set.Make (Slot) -let aggregate_preattestations_on_reproposal aggregate_opt - eligible_preattestations = +let aggregate_attestations aggregate_opt eligible_attestations = let open Result_syntax in - match (aggregate_opt, eligible_preattestations) with + let eligible_attestations = + filter_best_attestations_per_slot eligible_attestations + in + match (aggregate_opt, eligible_attestations) with | None, [] -> return_none | None, _ :: _ -> (* The proposal did not contain an aggregate. Since additional eligible - preattestations are available, we must aggregate them and include the + attestations are available, we must aggregate them and include the result in the reproposal. *) - aggregate_preattestations eligible_preattestations + aggregate_attestations eligible_attestations | Some (_, _, _, _, operation), [] -> return_some operation | Some (shell, consensus_content, committee, signature, _), _ :: _ -> ( (* The proposal already contains an aggregate. We must incorporate additional attestations *) let aggregated_slots = (* Build the set of aggregated slots for a logarithmic presence lookup *) - SlotSet.of_list committee + SlotSet.of_list (Operation.committee_slots committee) in (* Gather slots and signatures incorporating fresh attestations. *) let committee, signatures = List.fold_left (fun ((slots, signatures) as acc) - ({protocol_data; _} : Kind.preattestation operation) -> + ({protocol_data; _} : Kind.attestation operation) -> match (protocol_data.contents, protocol_data.signature) with - | Single (Preattestation consensus_content), Some (Bls signature) + | ( Single (Attestation {consensus_content; dal_content}), + Some (Bls signature) ) when not (SlotSet.mem consensus_content.slot aggregated_slots) -> - (consensus_content.slot :: slots, signature :: signatures) + ( (consensus_content.slot, dal_content) :: slots, + signature :: signatures ) | _ -> acc) (committee, [signature]) - eligible_preattestations + eligible_attestations in (* We disable the subgroup check for better performance, as operations come from the mempool where it has already been checked. *) @@ -679,49 +681,68 @@ let aggregate_preattestations_on_reproposal aggregate_opt with | Some signature -> let contents = - Single (Preattestations_aggregate {consensus_content; committee}) + Single (Attestations_aggregate {consensus_content; committee}) in let protocol_data = {contents; signature = Some (Bls signature)} in - let preattestations_aggregate = + let attestations_aggregate = {shell; protocol_data = Operation_data protocol_data} in - return_some preattestations_aggregate + return_some attestations_aggregate | None -> tzfail Baking_errors.Signature_aggregation_failure) -let aggregate_attestations_on_reproposal aggregate_opt eligible_attestations = +(* [aggregate_attestations_on_proposal attestations] replaces all eligible + attestations from [attestations] by a single Attestations_aggregate. + + All attestations are assumed to target the same branch, level, round and + block_payload_hash. *) +let aggregate_attestations_on_proposal attestations = let open Result_syntax in - let eligible_attestations = - filter_best_attestations_per_slot eligible_attestations + let attestations_aggregate_opt, eligible_attestations, remaining_attestations + = + partition_consensus_operations_on_proposal attestations in - match (aggregate_opt, eligible_attestations) with + let* aggregate_opt = + aggregate_attestations attestations_aggregate_opt eligible_attestations + in + match aggregate_opt with + | Some aggregate -> + let open Operation_pool in + return + @@ Prioritized_operation_set.add + (Prioritized_operation.extern ~priority:1 aggregate) + remaining_attestations + | None -> return remaining_attestations + +let aggregate_preattestations_on_reproposal aggregate_opt + eligible_preattestations = + let open Result_syntax in + match (aggregate_opt, eligible_preattestations) with | None, [] -> return_none | None, _ :: _ -> (* The proposal did not contain an aggregate. Since additional eligible - attestations are available, we must aggregate them and include the + preattestations are available, we must aggregate them and include the result in the reproposal. *) - aggregate_attestations eligible_attestations + aggregate_preattestations eligible_preattestations | Some (_, _, _, _, operation), [] -> return_some operation | Some (shell, consensus_content, committee, signature, _), _ :: _ -> ( (* The proposal already contains an aggregate. We must incorporate additional attestations *) let aggregated_slots = (* Build the set of aggregated slots for a logarithmic presence lookup *) - SlotSet.of_list (Operation.committee_slots committee) + SlotSet.of_list committee in (* Gather slots and signatures incorporating fresh attestations. *) let committee, signatures = List.fold_left (fun ((slots, signatures) as acc) - ({protocol_data; _} : Kind.attestation operation) -> + ({protocol_data; _} : Kind.preattestation operation) -> match (protocol_data.contents, protocol_data.signature) with - | ( Single (Attestation {consensus_content; dal_content}), - Some (Bls signature) ) + | Single (Preattestation consensus_content), Some (Bls signature) when not (SlotSet.mem consensus_content.slot aggregated_slots) -> - ( (consensus_content.slot, dal_content) :: slots, - signature :: signatures ) + (consensus_content.slot :: slots, signature :: signatures) | _ -> acc) (committee, [signature]) - eligible_attestations + eligible_preattestations in (* We disable the subgroup check for better performance, as operations come from the mempool where it has already been checked. *) @@ -730,13 +751,13 @@ let aggregate_attestations_on_reproposal aggregate_opt eligible_attestations = with | Some signature -> let contents = - Single (Attestations_aggregate {consensus_content; committee}) + Single (Preattestations_aggregate {consensus_content; committee}) in let protocol_data = {contents; signature = Some (Bls signature)} in - let attestations_aggregate = + let preattestations_aggregate = {shell; protocol_data = Operation_data protocol_data} in - return_some attestations_aggregate + return_some preattestations_aggregate | None -> tzfail Baking_errors.Signature_aggregation_failure) (* [aggregate_consensus_operations_on_reproposal consensus_operations] replaces @@ -756,9 +777,7 @@ let aggregate_consensus_operations_on_reproposal consensus_operations = partition_consensus_operations_on_reproposal consensus_operations in let* attestations_aggregate_opt = - aggregate_attestations_on_reproposal - attestations_aggregate_opt - eligible_attestations + aggregate_attestations attestations_aggregate_opt eligible_attestations in let* preattestations_aggregate_opt = aggregate_preattestations_on_reproposal diff --git a/src/proto_023_PtSeouLo/lib_delegate/node_rpc.ml b/src/proto_023_PtSeouLo/lib_delegate/node_rpc.ml index 57305a1c4099616acab78e46f37ea9b0e9ec6014..92d0e8a2d58e458044fde4975e6d8ec6ba49cf10 100644 --- a/src/proto_023_PtSeouLo/lib_delegate/node_rpc.ml +++ b/src/proto_023_PtSeouLo/lib_delegate/node_rpc.ml @@ -72,19 +72,39 @@ let preapply_block cctxt ~chain ~head ~timestamp ~protocol_data operations = operations ~protocol_data -let extract_prequorum preattestations = +let extract_prequorum (preattestations : packed_operation list) = match preattestations with - | h :: _ -> - let {protocol_data = {contents = Single (Preattestation content); _}; _} = - (h : Kind.preattestation Operation.t) - in - Some - { - level = Raw_level.to_int32 content.level; - round = content.round; - block_payload_hash = content.block_payload_hash; - preattestations; - } + | h :: _ -> ( + match h with + | { + protocol_data = + Operation_data {contents = Single (Preattestation content); _}; + _; + } -> + Some + { + level = Raw_level.to_int32 content.level; + round = content.round; + block_payload_hash = content.block_payload_hash; + preattestations; + } + | { + protocol_data = + Operation_data + { + contents = Single (Preattestations_aggregate {consensus_content; _}); + _; + }; + _; + } -> + Some + { + level = Raw_level.to_int32 consensus_content.level; + round = consensus_content.round; + block_payload_hash = consensus_content.block_payload_hash; + preattestations; + } + | _ -> None) | _ -> None let info_of_header_and_ops ~in_protocol ~grandparent block_hash block_header diff --git a/src/proto_023_PtSeouLo/lib_delegate/operation_pool.ml b/src/proto_023_PtSeouLo/lib_delegate/operation_pool.ml index 8fb6ccba01212ba1cc2ca1959ae68ed1a2afb91e..cf80556c6b0b91244c3326c527a49d4ce28c40d9 100644 --- a/src/proto_023_PtSeouLo/lib_delegate/operation_pool.ml +++ b/src/proto_023_PtSeouLo/lib_delegate/operation_pool.ml @@ -328,15 +328,25 @@ let extract_operations_of_list_list = function | [consensus; votes_payload; anonymous_payload; managers_payload] -> let preattestations, attestations = List.fold_left - (fun ( (preattestations : Kind.preattestation Operation.t list), - (attestations : Kind.attestation Operation.t list) ) + (fun ( (preattestations : packed_operation list), + (attestations : packed_operation list) ) packed_op -> let {shell; protocol_data = Operation_data data} = packed_op in match data with | {contents = Single (Preattestation _); _} -> - ({shell; protocol_data = data} :: preattestations, attestations) + ( Operation.pack {shell; protocol_data = data} :: preattestations, + attestations ) + | {contents = Single (Preattestations_aggregate _); _} -> + ( Operation.pack {shell; protocol_data = data} :: preattestations, + attestations ) | {contents = Single (Attestation _); _} -> - (preattestations, {shell; protocol_data = data} :: attestations) + ( preattestations, + Operation.pack {shell; protocol_data = data} :: attestations + ) + | {contents = Single (Attestations_aggregate _); _} -> + ( preattestations, + Operation.pack {shell; protocol_data = data} :: attestations + ) | _ -> (* unreachable *) (preattestations, attestations)) diff --git a/src/proto_023_PtSeouLo/lib_delegate/operation_pool.mli b/src/proto_023_PtSeouLo/lib_delegate/operation_pool.mli index 547cedf41bc6f332805c2ea4fd9e4e64229fb060..387c62b543069b1db3a68c5757bc9b7c7896754c 100644 --- a/src/proto_023_PtSeouLo/lib_delegate/operation_pool.mli +++ b/src/proto_023_PtSeouLo/lib_delegate/operation_pool.mli @@ -112,10 +112,7 @@ val ordered_of_list_list : packed_operation list list -> ordered_pool option (** [preattestation] <> None => (List.length preattestations > 0) *) val extract_operations_of_list_list : packed_operation list list -> - (Kind.preattestation operation list option - * Kind.attestation operation list - * payload) - option + (packed_operation list option * packed_operation list * payload) option module Prioritized_operation : sig type t diff --git a/src/proto_023_PtSeouLo/lib_delegate/state_transitions.ml b/src/proto_023_PtSeouLo/lib_delegate/state_transitions.ml index 7c99ec4c643123e6bc1e4b09e4f90d2991b56f42..6ba943e12e55e3fdb28dc2ecf14a3fabb3d2d193 100644 --- a/src/proto_023_PtSeouLo/lib_delegate/state_transitions.ml +++ b/src/proto_023_PtSeouLo/lib_delegate/state_transitions.ml @@ -197,32 +197,37 @@ let prepare_consensus_votes state proposal = let extract_pqc state (new_proposal : proposal) = match new_proposal.block.prequorum with | None -> None - | Some pqc -> - let add_voting_power acc (op : Kind.preattestation Operation.t) = - let open Protocol.Alpha_context.Operation in - let { - shell = _; - protocol_data = {contents = Single (Preattestation {slot; _}); _}; - _; - } = - op - in - match - Delegate_slots.voting_power state.level_state.delegate_slots ~slot - with - | None -> - (* cannot happen if the map is correctly populated *) - acc - | Some attesting_power -> acc + attesting_power - in + | Some prequorum -> let voting_power = - List.fold_left add_voting_power 0 pqc.preattestations + let voting_power_of_slot slot = + match + Delegate_slots.voting_power state.level_state.delegate_slots ~slot + with + | Some attesting_power -> attesting_power + | None -> 0 + in + List.fold_left + (fun voting_power op -> + let {protocol_data = Operation_data operation_data; _} = op in + match operation_data with + | {contents = Single (Preattestation {slot; _}); _} -> + voting_power_of_slot slot + voting_power + | {contents = Single (Preattestations_aggregate {committee; _}); _} + -> + List.fold_left + (fun aggregated_voting_power slot -> + voting_power_of_slot slot + aggregated_voting_power) + 0 + committee + | _ -> voting_power) + 0 + prequorum.preattestations in let consensus_threshold = state.global_state.constants.parametric.consensus_threshold_size in if Compare.Int.(voting_power >= consensus_threshold) then - Some (pqc.preattestations, pqc.round) + Some (prequorum.preattestations, prequorum.round) else None let may_update_attestable_payload_with_internal_pqc state @@ -572,9 +577,7 @@ let prepare_block_to_bake ~attestations ?last_proposal in (* 3. Add the additional given [attestations]. N.b. this is a set: there won't be duplicates *) - Operation_pool.add_operations - filtered_mempool - (List.map Operation.pack attestations) + Operation_pool.add_operations filtered_mempool attestations in let kind = Fresh operation_pool in let* () = Events.(emit preparing_fresh_block (delegate, round)) in @@ -652,8 +655,7 @@ let propose_block_action state delegate round ~last_proposal = List.fold_left (fun set op -> Operation_pool.Operation_set.add op set) mempool_consensus_operations - (List.map Operation.pack proposal.block.quorum - @ List.map Operation.pack prequorum.preattestations) + (proposal.block.quorum @ prequorum.preattestations) in let attestation_filter = { @@ -781,7 +783,7 @@ let time_to_prepare_next_level_block state at_round = triggered when we have a slot and an elected block *) assert false | Some elected_block, Some {delegate; _} -> - let attestations = elected_block.attestation_qc in + let attestations = List.map Operation.pack elected_block.attestation_qc in let new_level_state = {state.level_state with next_level_latest_forge_request = Some at_round} in @@ -931,8 +933,9 @@ let prequorum_reached_when_awaiting_preattestations state candidate level = latest_proposal.block.shell.level; round = latest_proposal.block.round; block_payload_hash = latest_proposal.block.payload_hash; - preattestations - (* preattestations may be nil when [consensus_threshold] is 0 *); + preattestations = + List.map Operation.pack preattestations + (* preattestations may be nil when [consensus_threshold] is 0 *); } in let new_attestable_payload = {proposal = latest_proposal; prequorum} in diff --git a/src/proto_023_PtSeouLo/lib_delegate/state_transitions.mli b/src/proto_023_PtSeouLo/lib_delegate/state_transitions.mli index 7ea10de844d0268ae45193ce32cc507c3216fe0f..7fad44c6eead789c5398b2307519f52632a19411 100644 --- a/src/proto_023_PtSeouLo/lib_delegate/state_transitions.mli +++ b/src/proto_023_PtSeouLo/lib_delegate/state_transitions.mli @@ -47,8 +47,7 @@ val may_update_proposal : val preattest : state -> proposal -> (state * action) Lwt.t -val extract_pqc : - state -> proposal -> (Kind.preattestation operation list * Round.t) option +val extract_pqc : state -> proposal -> (packed_operation list * Round.t) option val handle_proposal : is_proposal_applied:bool -> state -> proposal -> (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 4533a854f4e2c6d37e38fef1022bad3d9ec27ee5..45260ca319cc30744331da2a427a101f8d68e5df 100644 --- a/src/proto_alpha/lib_delegate/baking_lib.ml +++ b/src/proto_alpha/lib_delegate/baking_lib.ml @@ -522,20 +522,8 @@ let mk_prequorum state latest_proposal = let {level; round; block_payload_hash} : batch_content = batch.batch_content in - let preattestations : Kind.preattestation operation list = - List.filter_map - (fun op -> - let (Operation_data protocol_data) = - op.signed_operation.protocol_data - in - match protocol_data.contents with - | Single (Preattestation _) -> - let op : Kind.preattestation operation = - {shell = {branch = batch.batch_branch}; protocol_data} - in - Some op - | _ -> assert false) - batch.signed_consensus_votes + let preattestations = + List.map (fun op -> op.signed_operation) batch.signed_consensus_votes in return { diff --git a/src/proto_alpha/lib_delegate/baking_state.ml b/src/proto_alpha/lib_delegate/baking_state.ml index 3e69420fe4c66ce914aa580b807dbad5f48ee684..bee661d3fe7225cce293f0319423eec060f87d6f 100644 --- a/src/proto_alpha/lib_delegate/baking_state.ml +++ b/src/proto_alpha/lib_delegate/baking_state.ml @@ -36,7 +36,7 @@ type prequorum = { level : int32; round : Round.t; block_payload_hash : Block_payload_hash.t; - preattestations : Kind.preattestation operation list; + preattestations : packed_operation list; } type block_info = { @@ -46,7 +46,7 @@ type block_info = { payload_round : Round.t; round : Round.t; prequorum : prequorum option; - quorum : Kind.attestation operation list; + quorum : packed_operation list; payload : Operation_pool.payload; grandparent : Block_hash.t; } @@ -59,15 +59,9 @@ let prequorum_encoding = let open Data_encoding in conv (fun {level; round; block_payload_hash; preattestations} -> - (level, round, block_payload_hash, List.map Operation.pack preattestations)) + (level, round, block_payload_hash, preattestations)) (fun (level, round, block_payload_hash, preattestations) -> - { - level; - round; - block_payload_hash; - preattestations = - List.filter_map Operation_pool.unpack_preattestation preattestations; - }) + {level; round; block_payload_hash; preattestations}) (obj4 (req "level" int32) (req "round" Round.encoding) @@ -94,7 +88,7 @@ let block_info_encoding = payload_round, round, prequorum, - List.map Operation.pack quorum, + quorum, payload, grandparent )) (fun ( hash, @@ -114,7 +108,7 @@ let block_info_encoding = payload_round; round; prequorum; - quorum = List.filter_map Operation_pool.unpack_attestation quorum; + quorum; payload; }) (obj9 diff --git a/src/proto_alpha/lib_delegate/baking_state.mli b/src/proto_alpha/lib_delegate/baking_state.mli index 7e4e6b3eace25dd9ded479fa4d1748474bb8ee58..5c236fbe16b46b55c92dd1e725ee743b1b5df9be 100644 --- a/src/proto_alpha/lib_delegate/baking_state.mli +++ b/src/proto_alpha/lib_delegate/baking_state.mli @@ -199,7 +199,7 @@ type prequorum = { level : int32; round : Round.t; block_payload_hash : Block_payload_hash.t; - preattestations : Kind.preattestation operation list; + preattestations : packed_operation list; } type block_info = { @@ -209,7 +209,7 @@ type block_info = { payload_round : Round.t; round : Round.t; prequorum : prequorum option; - quorum : Kind.attestation operation list; + quorum : packed_operation list; payload : Operation_pool.payload; grandparent : Block_hash.t; } diff --git a/src/proto_alpha/lib_delegate/block_forge.ml b/src/proto_alpha/lib_delegate/block_forge.ml index 1b2279012dd4818bc9013e42a300691586b82285..87395fd12a35ac2a3541400cb8c15ebd0c7a4f3f 100644 --- a/src/proto_alpha/lib_delegate/block_forge.ml +++ b/src/proto_alpha/lib_delegate/block_forge.ml @@ -496,8 +496,12 @@ let aggregate_attestations eligible_attestations = let partition_consensus_operations_on_proposal consensus_operations = let open Operation_pool in Prioritized_operation_set.fold - (fun operation (eligible_attestations, remaining_operations) -> - let {shell; protocol_data = Operation_data protocol_data; _} = + (fun operation + ( attestations_aggregate_opt, + eligible_attestations, + remaining_operations ) -> + let ({shell; protocol_data = Operation_data protocol_data; _} as + packed_operation) = Prioritized_operation.packed operation in match (protocol_data.contents, protocol_data.signature) with @@ -508,10 +512,27 @@ let partition_consensus_operations_on_proposal consensus_operations = let remaining_operations = Prioritized_operation_set.remove operation remaining_operations in - (attestation :: eligible_attestations, remaining_operations) - | _, _ -> (eligible_attestations, remaining_operations)) + ( attestations_aggregate_opt, + attestation :: eligible_attestations, + remaining_operations ) + | ( Single (Attestations_aggregate {consensus_content; committee}), + Some (Bls signature) ) -> + let attestations_aggregate_opt = + Some + (shell, consensus_content, committee, signature, packed_operation) + in + let remaining_operations = + Prioritized_operation_set.remove operation remaining_operations + in + ( attestations_aggregate_opt, + eligible_attestations, + remaining_operations ) + | _, _ -> + ( attestations_aggregate_opt, + eligible_attestations, + remaining_operations )) consensus_operations - ([], consensus_operations) + (None, [], consensus_operations) (* [partition_consensus_operations_on_reproposal consensus_operations] partitions [consensus_operations] as follows : @@ -616,61 +637,42 @@ let filter_best_attestations_per_slot attestations = in SlotMap.fold (fun _slot attestation acc -> attestation :: acc) slot_map [] -(* [aggregate_attestations_on_proposal attestations] replaces all eligible - attestations from [attestations] by a single Attestations_aggregate. - - All attestations are assumed to target the same branch, level, round and - block_payload_hash. *) -let aggregate_attestations_on_proposal attestations = - let open Result_syntax in - let eligible_attestations, remaining_attestations = - partition_consensus_operations_on_proposal attestations - in - let* aggregate_opt = - eligible_attestations |> filter_best_attestations_per_slot - |> aggregate_attestations - in - match aggregate_opt with - | Some aggregate -> - let open Operation_pool in - return - @@ Prioritized_operation_set.add - (Prioritized_operation.extern ~priority:1 aggregate) - remaining_attestations - | None -> return remaining_attestations - module SlotSet : Set.S with type elt = Slot.t = Set.Make (Slot) -let aggregate_preattestations_on_reproposal aggregate_opt - eligible_preattestations = +let aggregate_attestations aggregate_opt eligible_attestations = let open Result_syntax in - match (aggregate_opt, eligible_preattestations) with + let eligible_attestations = + filter_best_attestations_per_slot eligible_attestations + in + match (aggregate_opt, eligible_attestations) with | None, [] -> return_none | None, _ :: _ -> (* The proposal did not contain an aggregate. Since additional eligible - preattestations are available, we must aggregate them and include the + attestations are available, we must aggregate them and include the result in the reproposal. *) - aggregate_preattestations eligible_preattestations + aggregate_attestations eligible_attestations | Some (_, _, _, _, operation), [] -> return_some operation | Some (shell, consensus_content, committee, signature, _), _ :: _ -> ( (* The proposal already contains an aggregate. We must incorporate additional attestations *) let aggregated_slots = (* Build the set of aggregated slots for a logarithmic presence lookup *) - SlotSet.of_list committee + SlotSet.of_list (Operation.committee_slots committee) in (* Gather slots and signatures incorporating fresh attestations. *) let committee, signatures = List.fold_left (fun ((slots, signatures) as acc) - ({protocol_data; _} : Kind.preattestation operation) -> + ({protocol_data; _} : Kind.attestation operation) -> match (protocol_data.contents, protocol_data.signature) with - | Single (Preattestation consensus_content), Some (Bls signature) + | ( Single (Attestation {consensus_content; dal_content}), + Some (Bls signature) ) when not (SlotSet.mem consensus_content.slot aggregated_slots) -> - (consensus_content.slot :: slots, signature :: signatures) + ( (consensus_content.slot, dal_content) :: slots, + signature :: signatures ) | _ -> acc) (committee, [signature]) - eligible_preattestations + eligible_attestations in (* We disable the subgroup check for better performance, as operations come from the mempool where it has already been checked. *) @@ -679,49 +681,68 @@ let aggregate_preattestations_on_reproposal aggregate_opt with | Some signature -> let contents = - Single (Preattestations_aggregate {consensus_content; committee}) + Single (Attestations_aggregate {consensus_content; committee}) in let protocol_data = {contents; signature = Some (Bls signature)} in - let preattestations_aggregate = + let attestations_aggregate = {shell; protocol_data = Operation_data protocol_data} in - return_some preattestations_aggregate + return_some attestations_aggregate | None -> tzfail Baking_errors.Signature_aggregation_failure) -let aggregate_attestations_on_reproposal aggregate_opt eligible_attestations = +(* [aggregate_attestations_on_proposal attestations] replaces all eligible + attestations from [attestations] by a single Attestations_aggregate. + + All attestations are assumed to target the same branch, level, round and + block_payload_hash. *) +let aggregate_attestations_on_proposal attestations = let open Result_syntax in - let eligible_attestations = - filter_best_attestations_per_slot eligible_attestations + let attestations_aggregate_opt, eligible_attestations, remaining_attestations + = + partition_consensus_operations_on_proposal attestations in - match (aggregate_opt, eligible_attestations) with + let* aggregate_opt = + aggregate_attestations attestations_aggregate_opt eligible_attestations + in + match aggregate_opt with + | Some aggregate -> + let open Operation_pool in + return + @@ Prioritized_operation_set.add + (Prioritized_operation.extern ~priority:1 aggregate) + remaining_attestations + | None -> return remaining_attestations + +let aggregate_preattestations_on_reproposal aggregate_opt + eligible_preattestations = + let open Result_syntax in + match (aggregate_opt, eligible_preattestations) with | None, [] -> return_none | None, _ :: _ -> (* The proposal did not contain an aggregate. Since additional eligible - attestations are available, we must aggregate them and include the + preattestations are available, we must aggregate them and include the result in the reproposal. *) - aggregate_attestations eligible_attestations + aggregate_preattestations eligible_preattestations | Some (_, _, _, _, operation), [] -> return_some operation | Some (shell, consensus_content, committee, signature, _), _ :: _ -> ( (* The proposal already contains an aggregate. We must incorporate additional attestations *) let aggregated_slots = (* Build the set of aggregated slots for a logarithmic presence lookup *) - SlotSet.of_list (Operation.committee_slots committee) + SlotSet.of_list committee in (* Gather slots and signatures incorporating fresh attestations. *) let committee, signatures = List.fold_left (fun ((slots, signatures) as acc) - ({protocol_data; _} : Kind.attestation operation) -> + ({protocol_data; _} : Kind.preattestation operation) -> match (protocol_data.contents, protocol_data.signature) with - | ( Single (Attestation {consensus_content; dal_content}), - Some (Bls signature) ) + | Single (Preattestation consensus_content), Some (Bls signature) when not (SlotSet.mem consensus_content.slot aggregated_slots) -> - ( (consensus_content.slot, dal_content) :: slots, - signature :: signatures ) + (consensus_content.slot :: slots, signature :: signatures) | _ -> acc) (committee, [signature]) - eligible_attestations + eligible_preattestations in (* We disable the subgroup check for better performance, as operations come from the mempool where it has already been checked. *) @@ -730,13 +751,13 @@ let aggregate_attestations_on_reproposal aggregate_opt eligible_attestations = with | Some signature -> let contents = - Single (Attestations_aggregate {consensus_content; committee}) + Single (Preattestations_aggregate {consensus_content; committee}) in let protocol_data = {contents; signature = Some (Bls signature)} in - let attestations_aggregate = + let preattestations_aggregate = {shell; protocol_data = Operation_data protocol_data} in - return_some attestations_aggregate + return_some preattestations_aggregate | None -> tzfail Baking_errors.Signature_aggregation_failure) (* [aggregate_consensus_operations_on_reproposal consensus_operations] replaces @@ -756,9 +777,7 @@ let aggregate_consensus_operations_on_reproposal consensus_operations = partition_consensus_operations_on_reproposal consensus_operations in let* attestations_aggregate_opt = - aggregate_attestations_on_reproposal - attestations_aggregate_opt - eligible_attestations + aggregate_attestations attestations_aggregate_opt eligible_attestations in let* preattestations_aggregate_opt = aggregate_preattestations_on_reproposal diff --git a/src/proto_alpha/lib_delegate/node_rpc.ml b/src/proto_alpha/lib_delegate/node_rpc.ml index 57305a1c4099616acab78e46f37ea9b0e9ec6014..3fe3094d37b6742caed48ff508853bd0936e6e99 100644 --- a/src/proto_alpha/lib_delegate/node_rpc.ml +++ b/src/proto_alpha/lib_delegate/node_rpc.ml @@ -72,19 +72,28 @@ let preapply_block cctxt ~chain ~head ~timestamp ~protocol_data operations = operations ~protocol_data -let extract_prequorum preattestations = +let extract_prequorum (preattestations : packed_operation list) = match preattestations with - | h :: _ -> - let {protocol_data = {contents = Single (Preattestation content); _}; _} = - (h : Kind.preattestation Operation.t) - in - Some - { - level = Raw_level.to_int32 content.level; - round = content.round; - block_payload_hash = content.block_payload_hash; - preattestations; - } + | packed_op :: _ -> ( + let (Operation_data protocol_data) = packed_op.protocol_data in + match protocol_data.contents with + | Single (Preattestation content) -> + Some + { + level = Raw_level.to_int32 content.level; + round = content.round; + block_payload_hash = content.block_payload_hash; + preattestations; + } + | Single (Preattestations_aggregate {consensus_content; _}) -> + Some + { + level = Raw_level.to_int32 consensus_content.level; + round = consensus_content.round; + block_payload_hash = consensus_content.block_payload_hash; + preattestations; + } + | _ -> None) | _ -> None let info_of_header_and_ops ~in_protocol ~grandparent block_hash block_header diff --git a/src/proto_alpha/lib_delegate/operation_pool.ml b/src/proto_alpha/lib_delegate/operation_pool.ml index 8fb6ccba01212ba1cc2ca1959ae68ed1a2afb91e..114d82b584759674923db3d0ac9d5e4923afa272 100644 --- a/src/proto_alpha/lib_delegate/operation_pool.ml +++ b/src/proto_alpha/lib_delegate/operation_pool.ml @@ -328,15 +328,19 @@ let extract_operations_of_list_list = function | [consensus; votes_payload; anonymous_payload; managers_payload] -> let preattestations, attestations = List.fold_left - (fun ( (preattestations : Kind.preattestation Operation.t list), - (attestations : Kind.attestation Operation.t list) ) + (fun ( (preattestations : packed_operation list), + (attestations : packed_operation list) ) packed_op -> - let {shell; protocol_data = Operation_data data} = packed_op in - match data with - | {contents = Single (Preattestation _); _} -> - ({shell; protocol_data = data} :: preattestations, attestations) - | {contents = Single (Attestation _); _} -> - (preattestations, {shell; protocol_data = data} :: attestations) + let (Operation_data protocol_data) = packed_op.protocol_data in + match protocol_data.contents with + | Single (Preattestation _) -> + (packed_op :: preattestations, attestations) + | Single (Preattestations_aggregate _) -> + (packed_op :: preattestations, attestations) + | Single (Attestation _) -> + (preattestations, packed_op :: attestations) + | Single (Attestations_aggregate _) -> + (preattestations, packed_op :: attestations) | _ -> (* unreachable *) (preattestations, attestations)) diff --git a/src/proto_alpha/lib_delegate/operation_pool.mli b/src/proto_alpha/lib_delegate/operation_pool.mli index 547cedf41bc6f332805c2ea4fd9e4e64229fb060..387c62b543069b1db3a68c5757bc9b7c7896754c 100644 --- a/src/proto_alpha/lib_delegate/operation_pool.mli +++ b/src/proto_alpha/lib_delegate/operation_pool.mli @@ -112,10 +112,7 @@ val ordered_of_list_list : packed_operation list list -> ordered_pool option (** [preattestation] <> None => (List.length preattestations > 0) *) val extract_operations_of_list_list : packed_operation list list -> - (Kind.preattestation operation list option - * Kind.attestation operation list - * payload) - option + (packed_operation list option * packed_operation list * payload) option module Prioritized_operation : sig type t diff --git a/src/proto_alpha/lib_delegate/state_transitions.ml b/src/proto_alpha/lib_delegate/state_transitions.ml index 7c99ec4c643123e6bc1e4b09e4f90d2991b56f42..fff200ff237c7f39081fa883e7fddc4c0239eba3 100644 --- a/src/proto_alpha/lib_delegate/state_transitions.ml +++ b/src/proto_alpha/lib_delegate/state_transitions.ml @@ -197,32 +197,36 @@ let prepare_consensus_votes state proposal = let extract_pqc state (new_proposal : proposal) = match new_proposal.block.prequorum with | None -> None - | Some pqc -> - let add_voting_power acc (op : Kind.preattestation Operation.t) = - let open Protocol.Alpha_context.Operation in - let { - shell = _; - protocol_data = {contents = Single (Preattestation {slot; _}); _}; - _; - } = - op - in - match - Delegate_slots.voting_power state.level_state.delegate_slots ~slot - with - | None -> - (* cannot happen if the map is correctly populated *) - acc - | Some attesting_power -> acc + attesting_power - in + | Some prequorum -> let voting_power = - List.fold_left add_voting_power 0 pqc.preattestations + let voting_power_of_slot slot = + match + Delegate_slots.voting_power state.level_state.delegate_slots ~slot + with + | Some attesting_power -> attesting_power + | None -> 0 + in + List.fold_left + (fun voting_power op -> + let (Operation_data operation_data) = op.protocol_data in + match operation_data.contents with + | Single (Preattestation {slot; _}) -> + voting_power_of_slot slot + voting_power + | Single (Preattestations_aggregate {committee; _}) -> + List.fold_left + (fun aggregated_voting_power slot -> + voting_power_of_slot slot + aggregated_voting_power) + 0 + committee + | _ -> voting_power) + 0 + prequorum.preattestations in let consensus_threshold = state.global_state.constants.parametric.consensus_threshold_size in if Compare.Int.(voting_power >= consensus_threshold) then - Some (pqc.preattestations, pqc.round) + Some (prequorum.preattestations, prequorum.round) else None let may_update_attestable_payload_with_internal_pqc state @@ -572,9 +576,7 @@ let prepare_block_to_bake ~attestations ?last_proposal in (* 3. Add the additional given [attestations]. N.b. this is a set: there won't be duplicates *) - Operation_pool.add_operations - filtered_mempool - (List.map Operation.pack attestations) + Operation_pool.add_operations filtered_mempool attestations in let kind = Fresh operation_pool in let* () = Events.(emit preparing_fresh_block (delegate, round)) in @@ -652,8 +654,7 @@ let propose_block_action state delegate round ~last_proposal = List.fold_left (fun set op -> Operation_pool.Operation_set.add op set) mempool_consensus_operations - (List.map Operation.pack proposal.block.quorum - @ List.map Operation.pack prequorum.preattestations) + (proposal.block.quorum @ prequorum.preattestations) in let attestation_filter = { @@ -781,7 +782,7 @@ let time_to_prepare_next_level_block state at_round = triggered when we have a slot and an elected block *) assert false | Some elected_block, Some {delegate; _} -> - let attestations = elected_block.attestation_qc in + let attestations = List.map Operation.pack elected_block.attestation_qc in let new_level_state = {state.level_state with next_level_latest_forge_request = Some at_round} in @@ -931,8 +932,9 @@ let prequorum_reached_when_awaiting_preattestations state candidate level = latest_proposal.block.shell.level; round = latest_proposal.block.round; block_payload_hash = latest_proposal.block.payload_hash; - preattestations - (* preattestations may be nil when [consensus_threshold] is 0 *); + preattestations = + List.map Operation.pack preattestations + (* preattestations may be nil when [consensus_threshold] is 0 *); } in let new_attestable_payload = {proposal = latest_proposal; prequorum} in diff --git a/src/proto_alpha/lib_delegate/state_transitions.mli b/src/proto_alpha/lib_delegate/state_transitions.mli index 7ea10de844d0268ae45193ce32cc507c3216fe0f..7fad44c6eead789c5398b2307519f52632a19411 100644 --- a/src/proto_alpha/lib_delegate/state_transitions.mli +++ b/src/proto_alpha/lib_delegate/state_transitions.mli @@ -47,8 +47,7 @@ val may_update_proposal : val preattest : state -> proposal -> (state * action) Lwt.t -val extract_pqc : - state -> proposal -> (Kind.preattestation operation list * Round.t) option +val extract_pqc : state -> proposal -> (packed_operation list * Round.t) option val handle_proposal : is_proposal_applied:bool -> state -> proposal -> (state * action) Lwt.t diff --git a/tezt/tests/baker_test.ml b/tezt/tests/baker_test.ml index ba8570de24ea77abd20b325afe6e57314e663b72..5c64d95ba7dd1401177048dc0e18a0527998d8ce 100644 --- a/tezt/tests/baker_test.ml +++ b/tezt/tests/baker_test.ml @@ -1159,6 +1159,100 @@ let attestations_aggregation_on_reproposal_remote_node = @@ fun protocol -> attestations_aggregation_on_reproposal ~remote_mode:true protocol +let aggregated_operations_retrival_from_block_content = + Protocol.register_test + ~__FILE__ + ~title:"Aggregated operations are retrieved from the block content" + ~tags:[team; "baker"; "aggregation"; "reproposal"; "retrival"] + ~supports:Protocol.(From_protocol 023) + @@ fun protocol -> + log_step 1 "Initialize a node and a client with protocol" ; + let consensus_rights_delay = 1 in + let* parameter_file = + Protocol.write_parameter_file + ~base:(Right (protocol, None)) + [ + (["allow_tz4_delegate_enable"], `Bool true); + (["aggregate_attestation"], `Bool true); + (* Diminish some constants to activate consensus keys faster *) + (["blocks_per_cycle"], `Int 2); + (["nonce_revelation_threshold"], `Int 1); + (["consensus_rights_delay"], `Int consensus_rights_delay); + (["cache_sampler_state_cycles"], `Int (consensus_rights_delay + 3)); + (["cache_stake_distribution_cycles"], `Int (consensus_rights_delay + 3)); + ] + in + let* node, client = + Client.init_with_protocol `Client ~protocol ~parameter_file () + in + log_step 2 "Wait for level 1" ; + let* _ = Node.wait_for_level node 1 in + log_step 3 "Generate fresh BLS consensus keys for bootstrap1 to bootstrap3" ; + let* b1 = Client.update_fresh_consensus_key ~algo:"bls" bootstrap1 client in + let* b2 = Client.update_fresh_consensus_key ~algo:"bls" bootstrap2 client in + let* b3 = Client.update_fresh_consensus_key ~algo:"bls" bootstrap3 client in + let delegates = + Account.Bootstrap.keys |> Array.to_list + |> List.append [b1; b2; b3] + |> List.map (fun (account : Account.key) -> account.Account.alias) + in + (* Expected committee that should be found in aggregations *) + let expected_aggregated_committee = [bootstrap1; bootstrap2; bootstrap3] in + (* Expected delegates that should be found non-aggregated *) + let expected_non_aggregated = [bootstrap4; bootstrap5] in + log_step 4 "Bake for until level 8" ; + (* Baking until level 8 ensures that the BLS consensus keys are activated *) + let* () = Client.bake_for_and_wait ~count:7 ~keys:delegates client in + log_step 5 "Check consensus operations" ; + let* () = + check_consensus_operations + ~expected_attestations_committee:expected_aggregated_committee + ~expected_attestations:expected_non_aggregated + client + in + (* The bake for command bakes a block with handmade (aggregated) attestations + that are not injected in the node. To repropose with these operations, the + baker must retrieve them from the block content. *) + let* () = + Client.repropose_for_and_wait ~key:delegates ~minimal_timestamp:true client + in + let* () = + check_consensus_operations + ~expected_attestations_committee:expected_aggregated_committee + ~expected_attestations:expected_non_aggregated + client + in + let* () = + Client.repropose_for_and_wait + ~key:delegates + ~force_reproposal:true + ~minimal_timestamp:true + client + in + let* () = + check_consensus_operations + ~expected_attestations_committee:expected_aggregated_committee + ~expected_attestations:expected_non_aggregated + ~expected_preattestations_committee:expected_aggregated_committee + ~expected_preattestations:expected_non_aggregated + client + in + (* Same as the bake_for command, the repropose_for ~force_reproposal:true + bakes a block with handmade (aggregated) preattestations. To include them + in a new reproposal, the baker must retrieve them from the block content. *) + let* () = + Client.repropose_for_and_wait ~key:delegates ~minimal_timestamp:true client + in + let* () = + check_consensus_operations + ~expected_attestations_committee:expected_aggregated_committee + ~expected_attestations:expected_non_aggregated + ~expected_preattestations_committee:expected_aggregated_committee + ~expected_preattestations:expected_non_aggregated + client + in + unit + let register ~protocols = check_node_version_check_bypass_test protocols ; check_node_version_allowed_test protocols ; @@ -1175,4 +1269,5 @@ let register ~protocols = simple_attestations_aggregation_remote_node protocols ; prequorum_check_levels protocols ; attestations_aggregation_on_reproposal_local_context protocols ; - attestations_aggregation_on_reproposal_remote_node protocols + attestations_aggregation_on_reproposal_remote_node protocols ; + aggregated_operations_retrival_from_block_content protocols