From a76b85412645eda792e9c3085d9e0b96e8c4deee Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Tue, 8 Jul 2025 12:14:21 +0200 Subject: [PATCH 01/11] Proto/test: add various dal contents --- .../lib_protocol/test/helpers/dal_helpers.ml | 49 +++++++++++++++++++ .../lib_protocol/test/helpers/dal_helpers.mli | 27 ++++++++++ .../integration/consensus/test_aggregate.ml | 10 +--- 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.ml index cf87061cb600..03ee524583ba 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.ml @@ -319,3 +319,52 @@ let dal_content_of_int ~loc n = (Alpha_context.Dal.Attestation.Internal_for_tests.of_z (Z.of_int n)) in Alpha_context.{attestation} + +let dal_content_of_int_list + ?(number_of_slots = Default_parameters.constants_test.dal.number_of_slots) + attested_slots = + let open Alpha_context in + let dal_attestation = + List.fold_left + (fun dal_attestation slot -> + match Dal.Slot_index.of_int ~number_of_slots slot with + | Ok slot_index -> Dal.Attestation.commit dal_attestation slot_index + | Error err -> + Test.fail ~__LOC__ "%a" Environment.Error_monad.pp_trace err) + Dal.Attestation.empty + attested_slots + in + {attestation = dal_attestation} + +let various_dal_contents = + let number_of_slots = Default_parameters.constants_test.dal.number_of_slots in + None + :: List.map + (fun l -> Some (dal_content_of_int_list ~number_of_slots l)) + [[]; [0]; [1; 3]; Misc.(0 --> (number_of_slots - 1))] + +(* Associates each committee member with an element of + dal_content_list in order, going back to the beginning of + dal_content_list if dal_content_list is shorter. In other words, + the member at position i in committee receives the dal_content in + dal_content_list at position (i modulo (length of + dal_content_list)). *) +let committee_with_cycling_dal_contents + (dal_content_list : Alpha_context.dal_content option list) + (committee : 'a list) : ('a * Alpha_context.dal_content option) list = + let rec aux acc remaining_dal_contents_to_pick committee = + match (committee, remaining_dal_contents_to_pick) with + | [], _ -> List.rev acc + | _, [] -> + (* We have gone through the whole dal_content_list and there + are still committee members waiting to receive a dal + content: reset remaining_dal_contents_to_pick to + dal_content_list. *) + aux acc dal_content_list committee + | member :: rest_committee, dal :: rest_dal -> + aux ((member, dal) :: acc) rest_dal rest_committee + in + aux [] dal_content_list committee + +let committee_with_various_dal_contents committee = + committee_with_cycling_dal_contents various_dal_contents committee diff --git a/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.mli b/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.mli index c3373f3c3a04..286de68b6c8f 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.mli @@ -205,3 +205,30 @@ end Raises an exception when the given argument is negative. *) val dal_content_of_int : loc:string -> int -> Alpha_context.dal_content + +(** Builds a {!Alpha_context.type-dal_content} from a list of attested + slots. + + @param [number_of_slots] defaults to + {!Default_parameters.constants_test.dal.number_of_slots}. + + Fails when any of the attested slots is negative or greater than + or equal to [number_of_slots]. *) +val dal_content_of_int_list : + ?number_of_slots:int -> int list -> Alpha_context.dal_content + +(** A list of varied dal_content options, for tests where we want to + build attestations with different dal contents. *) +val various_dal_contents : Alpha_context.dal_content option list + +(** Transform a list of committee members into a list of [(member, + dal)] where [dal] is picked successively from + {!various_dal_contents} (going back to the beginning of + {!various_dal_contents} if it is shorter than the provided + committee. + + Depending on when this function is called, ['a] may be e.g. the + {!Signature.public_key_hash} of delegates or their consensus key, + or {!Op.attesting_slot}. *) +val committee_with_various_dal_contents : + 'a list -> ('a * Alpha_context.dal_content option) list 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 747310115979..18ac290b3dbe 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 @@ -540,15 +540,7 @@ let test_attestations_aggregate_non_bls_delegate () = ~predecessor:block operation in - let dal_contents_to_test = - [ - None; - Some Alpha_context.{attestation = Dal.Attestation.empty}; - Some (Dal_helpers.dal_content_of_int ~loc:__LOC__ 1); - Some (Dal_helpers.dal_content_of_int ~loc:__LOC__ 255); - ] - in - List.iter_es check_non_bls_aggregate_refused dal_contents_to_test + List.iter_es check_non_bls_aggregate_refused Dal_helpers.various_dal_contents let test_multiple_aggregates_per_block_forbidden () = let open Lwt_result_syntax in -- GitLab From 03573865955f359f2cd3ece884dc89e917c44778 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Thu, 3 Jul 2025 16:26:44 +0200 Subject: [PATCH 02/11] Proto/test: attestations_aggregate helper's committee includes dal contents --- src/proto_alpha/lib_protocol/test/helpers/op.ml | 11 ++++++----- .../lib_protocol/test/helpers/op.mli | 2 +- .../test/helpers/scenario_attestation.ml | 17 ++++++----------- .../integration/consensus/test_aggregate.ml | 9 ++++++--- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index aac02aafdb4d..5b7f4332a850 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -250,17 +250,18 @@ let attestations_aggregate ?committee ?level ?round ?block_payload_hash ?branch let* attesters = Context.get_attesters (B attested_block) in return @@ List.filter_map - (fun attester -> - match attester.Plugin.RPC.Validators.consensus_key with - | Bls _ -> Some attester.delegate - | _ -> None) + (fun {Plugin.RPC.Validators.consensus_key; _} -> + if Signature.Public_key_hash.is_bls consensus_key then + Some (consensus_key, None) + else None) attesters in let* attestations = List.map_es - (fun delegate -> + (fun (delegate, dal_content) -> raw_attestation ~delegate + ?dal_content ?level ?round ?block_payload_hash diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 69816f16141f..5cfb700c1c59 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -110,7 +110,7 @@ val attestation : [Block.t]. Block context is expected to include at least one delegate with a BLS key (or a registered consensus keys). *) val attestations_aggregate : - ?committee:public_key_hash list -> + ?committee:(public_key_hash * dal_content option) list -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> diff --git a/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml b/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml index fff25a068d8c..927baa9eb1de 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml @@ -299,25 +299,20 @@ let attest_aggreg_with (delegates : string list) : (t, t) scenarios = let consensus_key_pkh = consensus_key_info.active.consensus_key_pkh in + let* () = + if Signature.Public_key_hash.is_bls consensus_key_pkh then + return_unit + else failwith "Cannot aggregate with non-BLS key" + in (* Update the activity of the committee *) let state = update_activity delegate_name block state in return ( state, - consensus_key_pkh :: committee, + (consensus_key_pkh, None) :: committee, (delegate.pkh, consensus_key_pkh) :: delegate_and_ck )) (state, [], []) delegates in - let* () = - if - not - @@ List.for_all - (function - | (Bls _ : Signature.public_key_hash) -> true | _ -> false) - committee - then failwith "Cannot aggregate non-BLS attestation" - else return_unit - in (* Fails to produce an attestation if one of the delegates has no slot for the block *) let* op = Op.attestations_aggregate ~committee block in (* Check metadata *) 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 18ac290b3dbe..a6d23353fda8 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 @@ -389,7 +389,7 @@ let test_attestations_aggregate_invalid_signature () = in (* Craft an aggregate with a single attestation signed by this delegate *) let* aggregate = - Op.attestations_aggregate ~committee:[attester.consensus_key] block + Op.attestations_aggregate ~committee:[(attester.consensus_key, None)] block in (* Swap the signature for Signature.Bls.zero *) match aggregate.protocol_data with @@ -554,7 +554,9 @@ let test_multiple_aggregates_per_block_forbidden () = let* aggregates = List.map_es (fun (_, (delegate : RPC.Validators.t)) -> - Op.attestations_aggregate ~committee:[delegate.consensus_key] block) + Op.attestations_aggregate + ~committee:[(delegate.consensus_key, None)] + block) bls_delegates_with_slots in (* Bake a block containing the multiple aggregates and expect an error *) @@ -711,7 +713,8 @@ let test_metadata_committee_is_correctly_ordered () = let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in let committee = List.map - (fun (_slot, (delegate : RPC.Validators.t)) -> delegate.consensus_key) + (fun (_slot, (delegate : RPC.Validators.t)) -> + (delegate.consensus_key, None)) bls_delegates_with_slots in assert (List.length committee > 2) ; -- GitLab From 2b41aafabf7836d05eb24a5a1ccf398cb73395e9 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Mon, 7 Jul 2025 14:20:08 +0200 Subject: [PATCH 03/11] Proto/test: craft aggregations directly from committee --- .../lib_protocol/test/helpers/op.ml | 26 +- .../lib_protocol/test/helpers/op.mli | 44 +-- .../test/helpers/scenario_attestation.ml | 364 ++++++++---------- .../integration/consensus/test_aggregate.ml | 55 +-- .../consensus/test_double_attestation.ml | 33 +- .../consensus/test_double_preattestation.ml | 17 +- .../consensus/test_scenario_attestation.ml | 25 +- .../validate/generator_descriptors.ml | 42 +- 8 files changed, 255 insertions(+), 351 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 5b7f4332a850..85f6db13d9e3 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -186,9 +186,6 @@ let raw_aggregate attestations = let protocol_data = {contents; signature = Some (Bls signature)} in ({shell; protocol_data} : Kind.attestations_aggregate operation) -let aggregate attestations = - Option.map Operation.pack (raw_aggregate attestations) - let raw_aggregate_preattestations preattestations = let aggregate_content = List.fold_left @@ -221,9 +218,6 @@ let raw_aggregate_preattestations preattestations = let protocol_data = {contents; signature = Some (Bls signature)} in ({shell; protocol_data} : Kind.preattestations_aggregate operation) -let aggregate_preattestations preattestations = - Option.map Operation.pack (raw_aggregate_preattestations preattestations) - let attestation ?delegate ?slot ?level ?round ?block_payload_hash ?dal_content ?branch attested_block = let open Lwt_result_syntax in @@ -240,8 +234,8 @@ let attestation ?delegate ?slot ?level ?round ?block_payload_hash ?dal_content in return (Operation.pack op) -let attestations_aggregate ?committee ?level ?round ?block_payload_hash ?branch - attested_block = +let raw_attestations_aggregate ?committee ?level ?round ?block_payload_hash + ?branch attested_block = let open Lwt_result_syntax in let* committee = match committee with @@ -269,10 +263,24 @@ let attestations_aggregate ?committee ?level ?round ?block_payload_hash ?branch attested_block) committee in - match aggregate attestations with + match raw_aggregate attestations with | Some aggregate_attestation -> return aggregate_attestation | None -> failwith "no Bls delegate found" +let attestations_aggregate ?committee ?level ?round ?block_payload_hash ?branch + attested_block = + let open Lwt_result_syntax in + let* op = + raw_attestations_aggregate + ?committee + ?level + ?round + ?block_payload_hash + ?branch + attested_block + in + return (Operation.pack op) + let raw_preattestation ?delegate ?slot ?level ?round ?block_payload_hash ?branch 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 5cfb700c1c59..5c4552f15813 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -106,9 +106,21 @@ val attestation : Block.t -> Operation.packed tzresult Lwt.t -(** Create a packed attestations_aggregate that is expected for a given - [Block.t]. Block context is expected to include at least one delegate with a - BLS key (or a registered consensus keys). *) +(** Crafts an {!Attestations_aggregate} operation pointing to the + given {!Block.t}. Block context is expected to include at least + one delegate with a BLS consensus key, otherwise this function + will return an error. *) +val raw_attestations_aggregate : + ?committee:(public_key_hash * dal_content option) list -> + ?level:Raw_level.t -> + ?round:Round.t -> + ?block_payload_hash:Block_payload_hash.t -> + ?branch:Block_hash.t -> + Block.t -> + Kind.attestations_aggregate Operation.t tzresult Lwt.t + +(** Same as {!raw_preattestations_aggregate} but returns the packed + operation. *) val attestations_aggregate : ?committee:(public_key_hash * dal_content option) list -> ?level:Raw_level.t -> @@ -118,19 +130,6 @@ val attestations_aggregate : Block.t -> Operation.packed tzresult Lwt.t -(** Aggregate a list of attestations in a single Attestations_aggregate. - Attestations signed by non-bls delegates are ignored. Evaluates to {!None} if - no bls-signed attestations are found or if signature_aggregation failed - (due to unreadable signature representation). *) -val raw_aggregate : - Kind.attestation_consensus_kind Kind.consensus operation trace -> - Kind.attestations_aggregate operation option - -(** Same as {!raw_aggregate} but returns the packed operation. *) -val aggregate : - Kind.attestation_consensus_kind Kind.consensus operation trace -> - Operation.packed option - (** Create a packed preattestation that is expected for a given [Block.t] by packing the result of {!raw_preattestation}. *) val preattestation : @@ -166,19 +165,6 @@ val preattestations_aggregate : Block.t -> Operation.packed tzresult Lwt.t -(** Aggregate a list of preattestations in a single Preattestations_aggregate. - Preattestations signed by non-bls delegates are ignored. Evaluates to {!None} if - no bls-signed attestations are found or if signature_aggregation failed. *) -val raw_aggregate_preattestations : - Kind.preattestation_consensus_kind Kind.consensus operation trace -> - Kind.preattestations_aggregate operation option - -(** Same as {!raw_aggregate_preattestations} but returns the packed - operation. *) -val aggregate_preattestations : - Kind.preattestation_consensus_kind Kind.consensus operation trace -> - Operation.packed option - type gas_limit = | Max (** Max corresponds to the [max_gas_limit_per_operation] constant. *) | High diff --git a/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml b/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml index 927baa9eb1de..d8b9b34ffe54 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml @@ -94,7 +94,8 @@ let check_attestation_metadata ?(check_not_found = false) ~kind delegate_pkh consensus_key_pkh let check_attestation_aggregate_metadata ?(check_not_found = false) ~kind - committee_expect : Block.full_metadata -> t -> unit tzresult Lwt.t = + ?(expect_same_order = true) committee_expect : + Block.full_metadata -> t -> unit tzresult Lwt.t = fun (_block_header_metadata, op_metadata) (_block, _state) -> let open Lwt_result_syntax in Log.debug ~color:low_debug_color "Check metadata: aggregated attestation" ; @@ -102,6 +103,15 @@ let check_attestation_aggregate_metadata ?(check_not_found = false) ~kind if check_not_found then (not, "Not expected but found in metadata") else (Fun.id, "Expected but not found in metadata") in + let may_sort committee = + if expect_same_order then committee + else + List.sort + (fun {Alpha_context.Consensus_key.delegate = d1; _} {delegate = d2; _} -> + Signature.Public_key_hash.compare d1 d2) + committee + in + let committee_expect = may_sort committee_expect in if id_or_not @@ List.exists @@ -133,19 +143,19 @@ let check_attestation_aggregate_metadata ?(check_not_found = false) ~kind total_consensus_power = _; }); } ) -> - let committee = - List.map - (fun ((ck : Protocol.Alpha_context.Consensus_key.t), _) -> - ck.delegate) - committee - |> List.sort Signature.Public_key_hash.compare - in - let committee_expect = - List.map fst committee_expect - |> List.sort Signature.Public_key_hash.compare - in + let committee = List.map fst committee |> may_sort in + Log.debug + "@[Actual committee:@,%a@]" + (Format.pp_print_list Alpha_context.Consensus_key.pp) + committee ; List.equal - Signature.Public_key_hash.equal + (fun { + Alpha_context.Consensus_key.delegate = d1; + consensus_pkh = c1; + } + {delegate = d2; consensus_pkh = c2} -> + Signature.Public_key_hash.equal d1 d2 + && Signature.Public_key_hash.equal c1 c2) committee committee_expect | _ -> false) @@ -159,8 +169,8 @@ let check_attestation_aggregate_metadata ?(check_not_found = false) ~kind Format.( pp_print_list ~pp_sep:(fun fmt () -> fprintf fmt "; ") - Signature.Public_key_hash.pp) - (List.map fst committee_expect) + Alpha_context.Consensus_key.pp) + committee_expect let check_attestation_rewards ?(check_not_found = false) delegate_name : Block.full_metadata -> t -> unit tzresult Lwt.t = @@ -287,29 +297,33 @@ let attest_aggreg_with (delegates : string list) : (t, t) scenarios = if state.force_attest_all then failwith "Cannot manually attest if force_attest_all is true" else - let* state, committee, delegate_and_ck_committee = + let* state, committee, expected_metadata_committee = List.fold_left_es - (fun (state, committee, delegate_and_ck) delegate_name -> + (fun (state, committee, expected_metadata_committee) delegate_name -> let delegate = State.find_account delegate_name state in let* consensus_key_info = Context.Delegate.consensus_key (B state.grandparent) delegate.pkh in - let consensus_key_pkh = - consensus_key_info.active.consensus_key_pkh - in + let consensus_pkh = consensus_key_info.active.consensus_key_pkh in let* () = - if Signature.Public_key_hash.is_bls consensus_key_pkh then + if Signature.Public_key_hash.is_bls consensus_pkh then return_unit else failwith "Cannot aggregate with non-BLS key" in (* Update the activity of the committee *) let state = update_activity delegate_name block state in + let key_in_metadata = + { + Alpha_context.Consensus_key.delegate = delegate.pkh; + consensus_pkh; + } + in return ( state, - (consensus_key_pkh, None) :: committee, - (delegate.pkh, consensus_key_pkh) :: delegate_and_ck )) + (consensus_pkh, None) :: committee, + key_in_metadata :: expected_metadata_committee )) (state, [], []) delegates in @@ -320,12 +334,16 @@ let attest_aggreg_with (delegates : string list) : (t, t) scenarios = State.add_current_block_check (check_attestation_aggregate_metadata ~kind - delegate_and_ck_committee) + expected_metadata_committee) state in let state = State.add_pending_operations [op] state in return (block, state)) +let key_for_metadata_of_delegate_rights + {RPC.Attestation_rights.delegate; consensus_key; _} = + {Alpha_context.Consensus_key.delegate; consensus_pkh = consensus_key} + let attest_with_all_ : t -> t tzresult Lwt.t = let open Lwt_result_syntax in fun (block, state) -> @@ -340,12 +358,12 @@ let attest_with_all_ : t -> t tzresult Lwt.t = so the returned list should only contain one element. *) assert false in - let* dlgs = - List.map + let* non_forbidden_delegates_rights = + List.filter_es (fun { - Plugin.RPC.Attestation_rights.delegate; + RPC.Attestation_rights.delegate; consensus_key = _; - first_slot; + first_slot = _; attestation_power; } -> Tezt.Check.( @@ -353,88 +371,67 @@ let attest_with_all_ : t -> t tzresult Lwt.t = int ~__LOC__ ~error_msg:"Attestation power should be greater than 0, got %L") ; - (delegate, first_slot)) + let* is_forbidden = + Context.Delegate.is_forbidden (B block) delegate + in + return (not is_forbidden)) delegates_rights - |> List.filter_es (fun (delegate, _slot) -> - let* is_forbidden = - Context.Delegate.is_forbidden (B block) delegate - in - return (not is_forbidden)) in - let* to_aggregate, ops = + let* state, bls_committee = List.fold_left_es - (fun (to_aggregate, regular) (delegate, slot) -> - let* consensus_key_info = - Context.Delegate.consensus_key (B state.grandparent) delegate - in - let consensus_key = consensus_key_info.active in - let* consensus_key = Account.find consensus_key.consensus_key_pkh in - let* op = - Op.raw_attestation ~delegate:consensus_key.pkh ~slot block - in - match (state.constants.aggregate_attestation, consensus_key.pk) with - | true, Bls _ -> - return ((op, delegate, consensus_key.pkh) :: to_aggregate, regular) - | _ -> - return - ( to_aggregate, - ( Protocol.Alpha_context.Operation.pack op, - delegate, - consensus_key.pkh ) - :: regular )) - ([], []) - dlgs - in - let aggregated = - Op.aggregate (List.map (fun (x, _, _) -> x) to_aggregate) - in - let state = - match aggregated with - | None -> state - | Some op -> - (* Update the activity of the committee *) - let state, delegate_and_ck_committee = - List.fold_left - (fun (state, delegate_and_ck) (_, delegate_pkh, consensus_key_pkh) -> - let delegate_name, _ = - State.find_account_from_pkh delegate_pkh state - in - ( update_activity delegate_name block state, - (delegate_pkh, consensus_key_pkh) :: delegate_and_ck )) - (state, []) - to_aggregate - in - (* Check metadata *) - let state = - State.add_current_block_check - (check_attestation_aggregate_metadata - ~kind - delegate_and_ck_committee) - state - in - let state = State.add_pending_operations [op] state in - state - in - (* Update the activity of the rest of the committee, and check metadata *) - let state = - List.fold_left - (fun state (_, delegate_pkh, consensus_key_pkh) -> + (fun (state, bls_committee) + ({ + RPC.Attestation_rights.delegate = manager_pkh; + consensus_key; + first_slot = slot; + attestation_power = _; + } as delegate_rights) -> + (* Update delegate activity in any case. *) let delegate_name, _ = - State.find_account_from_pkh delegate_pkh state + State.find_account_from_pkh manager_pkh state in let state = update_activity delegate_name block state in - (* Check metadata *) - let state = - State.add_current_block_check - (check_attestation_metadata ~kind delegate_pkh consensus_key_pkh) - state - in - state) - state - ops + if + state.constants.aggregate_attestation + && Signature.Public_key_hash.is_bls consensus_key + then + (* Just add the delegate to the committee; aggregation and + metadata check will be handled below. *) + return (state, delegate_rights :: bls_committee) + else + (* Add standalone attestation and metadata check. *) + let* op = Op.attestation ~delegate:consensus_key ~slot block in + let state = State.add_pending_operations [op] state in + let state = + State.add_current_block_check + (check_attestation_metadata ~kind manager_pkh consensus_key) + state + in + return (state, bls_committee)) + (state, []) + non_forbidden_delegates_rights in - let state = - State.add_pending_operations (List.map (fun (x, _, _) -> x) ops) state + let* state = + if List.is_empty bls_committee then return state + else + (* Add aggregated attestation and metadata check. *) + let committee = + List.map + (fun {RPC.Attestation_rights.consensus_key; _} -> + (consensus_key, None)) + bls_committee + in + let* op = Op.attestations_aggregate ~committee block in + let state = State.add_pending_operations [op] state in + let expected_committee = + List.map key_for_metadata_of_delegate_rights bls_committee + in + let state = + State.add_current_block_check + (check_attestation_aggregate_metadata ~kind expected_committee) + state + in + return state in return (block, state) @@ -518,16 +515,14 @@ let preattest_aggreg_with ?payload_round (delegates : string list) : else let kind = Preattestation in let* fake_block = make_fake_block ?payload_round incr in - let* state, committee, delegate_and_ck_committee = + let* state, committee, expected_metadata_committee = List.fold_left_es - (fun (state, committee, delegate_and_ck) delegate_name -> + (fun (state, committee, expected_metadata_committee) delegate_name -> let delegate = State.find_account delegate_name state in let* consensus_key_info = Context.Delegate.consensus_key (I incr) delegate.pkh in - let consensus_key_pkh = - consensus_key_info.active.consensus_key_pkh - in + let consensus_pkh = consensus_key_info.active.consensus_key_pkh in (* Update the activity of the committee *) let state = update_activity @@ -535,10 +530,16 @@ let preattest_aggreg_with ?payload_round (delegates : string list) : (Incremental.predecessor incr) state in + let key_for_metadata = + { + Alpha_context.Consensus_key.delegate = delegate.pkh; + consensus_pkh; + } + in return ( state, - consensus_key_pkh :: committee, - (delegate.pkh, consensus_key_pkh) :: delegate_and_ck )) + consensus_pkh :: committee, + key_for_metadata :: expected_metadata_committee )) (state, [], []) delegates in @@ -559,7 +560,7 @@ let preattest_aggreg_with ?payload_round (delegates : string list) : State.add_current_block_check (check_attestation_aggregate_metadata ~kind - delegate_and_ck_committee) + expected_metadata_committee) state in let* incr = Incremental.add_operation incr op in @@ -580,12 +581,12 @@ let preattest_with_all_ ?payload_round : t_incr -> t_incr tzresult Lwt.t = so the returned list should only contain one element. *) assert false in - let* dlgs = - List.map + let* non_forbidden_delegates_rights = + List.filter_es (fun { Plugin.RPC.Attestation_rights.delegate; consensus_key = _; - first_slot; + first_slot = _; attestation_power; } -> Tezt.Check.( @@ -593,95 +594,64 @@ let preattest_with_all_ ?payload_round : t_incr -> t_incr tzresult Lwt.t = int ~__LOC__ ~error_msg:"Attestation power should be greater than 0, got %L") ; - (delegate, first_slot)) + let* is_forbidden = Context.Delegate.is_forbidden (I incr) delegate in + return (not is_forbidden)) delegates_rights - |> List.filter_es (fun (delegate, _slot) -> - let* is_forbidden = - Context.Delegate.is_forbidden (I incr) delegate - in - return (not is_forbidden)) in - let* to_aggregate, ops = + let* incr, state, bls_committee = List.fold_left_es - (fun (to_aggregate, regular) (delegate, slot) -> - let* consensus_key_info = - Context.Delegate.consensus_key (I incr) delegate - in - let consensus_key = consensus_key_info.active in - let* consensus_key = Account.find consensus_key.consensus_key_pkh in - let* op = - Op.raw_preattestation ~delegate:consensus_key.pkh ~slot fake_block - in - match (state.constants.aggregate_attestation, consensus_key.pk) with - | true, Bls _ -> - return ((op, delegate, consensus_key.pkh) :: to_aggregate, regular) - | _ -> - return - ( to_aggregate, - ( Protocol.Alpha_context.Operation.pack op, - delegate, - consensus_key.pkh ) - :: regular )) - ([], []) - dlgs - in - let aggregated = - Op.aggregate_preattestations (List.map (fun (x, _, _) -> x) to_aggregate) - in - let* incr, state = - match aggregated with - | None -> return (incr, state) - | Some op -> - (* Update the activity of the committee *) - let state, delegate_and_ck_committee = - List.fold_left - (fun (state, delegate_and_ck) (_, delegate_pkh, consensus_key_pkh) -> - let delegate_name, _ = - State.find_account_from_pkh delegate_pkh state - in - ( update_activity - delegate_name - (Incremental.predecessor incr) - state, - (delegate_pkh, consensus_key_pkh) :: delegate_and_ck )) - (state, []) - to_aggregate - in - (* Check metadata *) - let state = - State.add_current_block_check - (check_attestation_aggregate_metadata - ~kind - delegate_and_ck_committee) - state - in - let* incr = Incremental.add_operation incr op in - return (incr, state) - in - (* Update the activity of the rest of the committee, and check metadata *) - let state = - List.fold_left - (fun state (_, delegate_pkh, consensus_key_pkh) -> + (fun (incr, state, bls_committee) + ({ + Plugin.RPC.Attestation_rights.delegate = manager_pkh; + consensus_key; + first_slot = slot; + attestation_power = _; + } as delegate_rights) -> + (* Update delegate activity in any case. *) let delegate_name, _ = - State.find_account_from_pkh delegate_pkh state + State.find_account_from_pkh manager_pkh state in let state = update_activity delegate_name (Incremental.predecessor incr) state in - (* Check metadata *) - let state = - State.add_current_block_check - (check_attestation_metadata ~kind delegate_pkh consensus_key_pkh) - state - in - state) - state - ops - in - let* incr = - List.fold_left_es - Incremental.add_operation - incr - (List.map (fun (x, _, _) -> x) ops) + if + state.constants.aggregate_attestation + && Signature.Public_key_hash.is_bls consensus_key + then + (* Just add the delegate to the committee; aggregation and + metadata check will be handled below. *) + return (incr, state, delegate_rights :: bls_committee) + else + (* Add standalone attestation and metadata check. *) + let* op = + Op.preattestation ~delegate:consensus_key ~slot fake_block + in + let* incr = Incremental.add_operation incr op in + let state = + State.add_current_block_check + (check_attestation_metadata ~kind manager_pkh consensus_key) + state + in + return (incr, state, bls_committee)) + (incr, state, []) + non_forbidden_delegates_rights in - return (incr, state) + if List.is_empty bls_committee then return (incr, state) + else + (* Add aggregated attestation and metadata check. *) + let committee = + List.map + (fun {RPC.Attestation_rights.consensus_key; _} -> consensus_key) + bls_committee + in + let* op = Op.preattestations_aggregate ~committee fake_block in + let* incr = Incremental.add_operation incr op in + let expected_committee = + List.map key_for_metadata_of_delegate_rights bls_committee + in + let state = + State.add_current_block_check + (check_attestation_aggregate_metadata ~kind expected_committee) + state + in + return (incr, state) 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 a6d23353fda8..2d01b8d01c2c 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 @@ -261,16 +261,13 @@ let test_attestations_aggregate_with_a_single_delegate () = in let* attesters = Context.get_attesters (B block) in (* Find an attester with a BLS consensus key. *) - let attester, slot = + let attester, _slot = WithExceptions.Option.get ~loc:__LOC__ (find_attester_with_bls_key attesters) in - let* attestation = - Op.raw_attestation ~delegate:attester.RPC.Validators.delegate ~slot block - in - let operation = - WithExceptions.Option.get ~loc:__LOC__ (Op.aggregate [attestation]) + let* operation = + Op.attestations_aggregate ~committee:[(attester.consensus_key, None)] block in let* _, (_, receipt) = Block.bake_with_metadata ~operation block in let result = find_attestations_aggregate_result receipt in @@ -284,21 +281,13 @@ let test_preattestations_aggregate_with_a_single_delegate () = let* block' = Block.bake block in let* attesters = Context.get_attesters (B block') in (* Find an attester with a BLS consensus key. *) - let attester, slot = + let attester, _slot = WithExceptions.Option.get ~loc:__LOC__ (find_attester_with_bls_key attesters) in let* operation = - let* preattestation = - Op.raw_preattestation - ~delegate:attester.RPC.Validators.delegate - ~slot - block' - in - return - @@ WithExceptions.Option.get ~loc:__LOC__ - @@ Op.aggregate_preattestations [preattestation] + Op.preattestations_aggregate ~committee:[attester.consensus_key] block' in let* _, (_, receipt) = let round_zero = Alpha_context.Round.zero in @@ -320,21 +309,13 @@ let test_attestations_aggregate_with_multiple_delegates () = let* attesters = Context.get_attesters (B block) in (* Filter delegates with BLS keys that have at least one slot *) let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in - let* attestations = - List.map_es - (fun (slot, delegate) -> - Op.raw_attestation - ~delegate:delegate.RPC.Validators.delegate - ~slot - block) + let committee = + List.map + (fun (_slot, delegate) -> (delegate.RPC.Validators.consensus_key, None)) bls_delegates_with_slots in - let aggregation = - WithExceptions.Option.get ~loc:__LOC__ (Op.aggregate attestations) - in - let* _, (_, receipt) = - Block.bake_with_metadata ~operation:aggregation block - in + let* operation = Op.attestations_aggregate ~committee block in + let* _, (_, receipt) = Block.bake_with_metadata ~operation block in let result = find_attestations_aggregate_result receipt in let delegates = List.map snd bls_delegates_with_slots in check_attestations_aggregate_result ~committee:delegates result @@ -348,20 +329,12 @@ let test_preattestations_aggregate_with_multiple_delegates () = let* attesters = Context.get_attesters (B block') in (* Filter delegates with BLS keys that have at least one slot *) let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in - let* preattestations = - List.map_es - (fun (slot, delegate) -> - Op.raw_preattestation - ~delegate:delegate.RPC.Validators.delegate - ~slot - block') + let committee = + List.map + (fun (_slot, delegate) -> delegate.RPC.Validators.consensus_key) bls_delegates_with_slots in - let operation = - WithExceptions.Option.get - ~loc:__LOC__ - (Op.aggregate_preattestations preattestations) - in + let* operation = Op.preattestations_aggregate ~committee block' in let* _, (_, receipt) = let round_zero = Alpha_context.Round.zero in Block.bake_with_metadata 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 83c5e4da1437..813866b25ba8 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 @@ -620,16 +620,12 @@ let test_invalid_double_attestation_duplicate_in_committee () = ~loc:__LOC__ (Test_aggregate.find_attester_with_bls_key attesters) in - let* op1 = - Op.raw_attestation ~delegate:attester.RPC.Validators.delegate ~slot blk_a - in - let* op2_standalone = - Op.raw_attestation ~delegate:attester.RPC.Validators.delegate ~slot blk_b - in - let op2 = - WithExceptions.Option.get - ~loc:__LOC__ - (Op.raw_aggregate [op2_standalone; op2_standalone]) + let* op1 = Op.raw_attestation ~delegate:attester.consensus_key ~slot blk_a in + let* op2 = + Op.raw_attestations_aggregate + ~committee: + [(attester.consensus_key, None); (attester.consensus_key, None)] + blk_b in let op = let contents = @@ -653,7 +649,7 @@ let test_invalid_double_attestation_duplicate_in_committee () = op in (* Also check with duplicate slots with different dal contents *) - let* op2_standalone' = + let* op2 = let number_of_slots = Default_parameters.constants_test.dal.number_of_slots in @@ -661,17 +657,14 @@ let test_invalid_double_attestation_duplicate_in_committee () = let dal_content = {attestation = Dal.Attestation.(commit empty slot_index)} in - Op.raw_attestation - ~delegate:attester.RPC.Validators.delegate - ~slot - ~dal_content + Op.raw_attestations_aggregate + ~committee: + [ + (attester.consensus_key, None); + (attester.consensus_key, Some dal_content); + ] blk_b in - let op2 = - WithExceptions.Option.get - ~loc:__LOC__ - (Op.raw_aggregate [op2_standalone; op2_standalone']) - in let op = let contents = if Operation_hash.(Operation.hash op1 < Operation.hash op2) then 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 ceb59129d324..f4a4379dee5d 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 @@ -457,22 +457,13 @@ end = struct (Test_aggregate.find_attester_with_bls_key attesters) in let* op1 = - Op.raw_preattestation - ~delegate:attester.RPC.Validators.delegate - ~slot - blk_a + Op.raw_preattestation ~delegate:attester.consensus_key ~slot blk_a in - let* op2_standalone = - Op.raw_preattestation - ~delegate:attester.RPC.Validators.delegate - ~slot + let* op2 = + Op.raw_preattestations_aggregate + ~committee:[attester.consensus_key; attester.consensus_key] blk_b in - let op2 = - WithExceptions.Option.get - ~loc:__LOC__ - (Op.raw_aggregate_preattestations [op2_standalone; op2_standalone]) - in let op = let contents = if Operation_hash.(Operation.hash op1 < Operation.hash op2) then diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_scenario_attestation.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_scenario_attestation.ml index aa3ddcc07fd1..7b26f64ff26e 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_scenario_attestation.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_scenario_attestation.ml @@ -54,18 +54,35 @@ let check_aggregated_committee ~check_not_found ~kind delegates = List.map_es (fun delegate_name -> let delegate = State.find_account delegate_name state in + let block_at_attested_level = + match kind with + | Preattestation -> + block + (* The preattested block is a block at the same + level as [block] but an earlier round. For + retrieving the appropriate consensus_key we only + care about the level so we can use [block]. *) + | Attestation -> state.grandparent (* [block]'s predecessor *) + in let* consensus_key_info = - Context.Delegate.consensus_key (B state.grandparent) delegate.pkh + Context.Delegate.consensus_key + (B block_at_attested_level) + delegate.pkh in - let consensus_key = consensus_key_info.active in - let* consensus_key = Account.find consensus_key.consensus_key_pkh in - return (delegate.pkh, consensus_key.pkh)) + return + { + Protocol.Alpha_context.Consensus_key.delegate = delegate.pkh; + consensus_pkh = consensus_key_info.active.consensus_key_pkh; + }) delegates in let metadata = Stdlib.Option.get state.previous_metadata in check_attestation_aggregate_metadata ~check_not_found ~kind + ~expect_same_order:false + (* Delegates are provided manually and may not be sorted the + same way as when construction the aggregation. *) delegates metadata (block, state)) diff --git a/src/proto_alpha/lib_protocol/test/integration/validate/generator_descriptors.ml b/src/proto_alpha/lib_protocol/test/integration/validate/generator_descriptors.ml index b4c6e2c00da8..3b2c86b9e070 100644 --- a/src/proto_alpha/lib_protocol/test/integration/validate/generator_descriptors.ml +++ b/src/proto_alpha/lib_protocol/test/integration/validate/generator_descriptors.ml @@ -655,25 +655,8 @@ let attestations_aggregate_descriptor = opt_prelude = None; candidates_generator = (fun state -> - let open Lwt_result_syntax in - let* attestations = - List.filter_map_es - (fun (delegate, consensus_key_opt) -> - let* slots_opt = - Context.get_attester_slot (B state.block) delegate - in - let delegate = Option.value ~default:delegate consensus_key_opt in - let* signer = Account.find delegate in - match (slots_opt, signer.sk) with - | Some (_ :: _), Bls _ -> - let* op = Op.raw_attestation ~delegate state.block in - return (Some op) - | _, _ -> return_none) - state.delegates - in - match Op.aggregate attestations with - | Some op -> return [op] - | None -> return_nil); + let* op = Op.attestations_aggregate state.block in + return [op]); } let preattestations_aggregate_descriptor = @@ -686,25 +669,8 @@ let preattestations_aggregate_descriptor = opt_prelude = None; candidates_generator = (fun state -> - let open Lwt_result_syntax in - let* preattestations = - List.filter_map_es - (fun (delegate, consensus_key_opt) -> - let* slots_opt = - Context.get_attester_slot (B state.block) delegate - in - let delegate = Option.value ~default:delegate consensus_key_opt in - let* signer = Account.find delegate in - match (slots_opt, signer.sk) with - | Some (_ :: _), Bls _ -> - let* op = Op.raw_preattestation ~delegate state.block in - return (Some op) - | _, _ -> return_none) - state.delegates - in - match Op.aggregate_preattestations preattestations with - | Some op -> return [op] - | None -> return_nil); + let* op = Op.preattestations_aggregate state.block in + return [op]); } module Manager = Manager_operation_helpers -- GitLab From 0f4aa7064d9bfc2f04e21a6effbdbf2b709fe18c Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Mon, 7 Jul 2025 19:38:14 +0200 Subject: [PATCH 04/11] Proto/test: introduce attesting_slot in helpers --- .../test/helpers/consensus_helpers.ml | 68 +-- .../lib_protocol/test/helpers/context.ml | 52 ++- .../lib_protocol/test/helpers/context.mli | 47 +- .../lib_protocol/test/helpers/op.ml | 166 +++++--- .../lib_protocol/test/helpers/op.mli | 116 ++++- .../test/helpers/scenario_attestation.ml | 69 +-- .../lib_protocol/test/helpers/scenario_op.ml | 11 +- .../integration/consensus/test_aggregate.ml | 400 +++++++----------- .../integration/consensus/test_attestation.ml | 72 ++-- .../test/integration/consensus/test_baking.ml | 27 +- .../consensus/test_consensus_key.ml | 11 +- .../consensus/test_dal_entrapment.ml | 15 +- .../consensus/test_double_attestation.ml | 166 +++----- .../consensus/test_double_baking.ml | 10 +- .../consensus/test_double_preattestation.ml | 68 ++- .../consensus/test_frozen_deposits.ml | 8 +- .../consensus/test_participation.ml | 24 +- .../consensus/test_preattestation.ml | 12 +- .../consensus/test_preattestation_functor.ml | 55 +-- .../test/integration/consensus/test_seed.ml | 5 +- .../operations/test_origination.ml | 9 - .../validate/generator_descriptors.ml | 61 +-- .../integration/validate/validate_helpers.ml | 8 - 23 files changed, 722 insertions(+), 758 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/consensus_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/consensus_helpers.ml index e4c9820d26a2..40ecfd7c0fe2 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/consensus_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/consensus_helpers.ml @@ -23,9 +23,6 @@ (* *) (*****************************************************************************) -open Protocol -open Alpha_context - type kind = Preattestation | Attestation | Aggregate (** Crafts a consensus operation. @@ -39,13 +36,12 @@ type kind = Preattestation | Attestation | Aggregate its branch is the predecessor of that block. Optional arguments allow to override these default parameters. *) -let craft_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash +let craft_consensus_operation ?attesting_slot ?level ?round ?block_payload_hash ?branch ~attested_block kind = match kind with | Preattestation -> Op.preattestation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -53,8 +49,7 @@ let craft_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash attested_block | Attestation -> Op.attestation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -68,14 +63,13 @@ let craft_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash ?branch attested_block -let test_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash +let test_consensus_operation ?attesting_slot ?level ?round ?block_payload_hash ?branch ~attested_block ?(predecessor = attested_block) ?error ~loc kind mode = let open Lwt_result_syntax in let* operation = craft_consensus_operation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -85,15 +79,14 @@ let test_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash in Op.check_validation_and_application ~loc ?error ~predecessor mode operation -let test_consensus_operation_all_modes_different_outcomes ?delegate ?slot ?level +let test_consensus_operation_all_modes_different_outcomes ?attesting_slot ?level ?round ?block_payload_hash ?branch ~attested_block ?(predecessor = attested_block) ~loc ?application_error ?construction_error ?mempool_error kind = let open Lwt_result_syntax in let* operation = craft_consensus_operation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -109,14 +102,13 @@ let test_consensus_operation_all_modes_different_outcomes ?delegate ?slot ?level ~predecessor operation -let test_consensus_operation_all_modes ?delegate ?slot ?level ?round +let test_consensus_operation_all_modes ?attesting_slot ?level ?round ?block_payload_hash ?branch ~attested_block ?(predecessor = attested_block) ?error ~loc kind = let open Lwt_result_syntax in let* operation = craft_consensus_operation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -130,36 +122,12 @@ let test_consensus_operation_all_modes ?delegate ?slot ?level ?round ~predecessor operation -let delegate_of_first_slot b = - let open Lwt_result_syntax in - let module V = Plugin.RPC.Validators in - let+ attesters = Context.get_attesters b in - match attesters with - | {V.consensus_key; slots = s :: _; _} :: _ -> (consensus_key, s) - | _ -> assert false - -let delegate_of_slot ?(different_slot = false) slot b = - let open Lwt_result_syntax in - let module V = Plugin.RPC.Validators in - let+ attesters = Context.get_attesters b in - List.find_map - (function - | {V.consensus_key; slots = s :: _; _} - when if different_slot then not (Slot.equal s slot) - else Slot.equal s slot -> - Some consensus_key - | _ -> None) - attesters - |> function - | None -> assert false - | Some d -> d - let test_consensus_op_for_next ~genesis ~kind ~next = let open Lwt_result_syntax in - let dorsement ~attested_block ~delegate = + let consensus_op ~attested_block ~attesting_slot = match kind with - | `Preattestation -> Op.preattestation ~delegate attested_block - | `Attestation -> Op.attestation ~delegate attested_block + | `Preattestation -> Op.preattestation ~attesting_slot attested_block + | `Attestation -> Op.attestation ~attesting_slot attested_block in let* b1 = Block.bake genesis in let* b2 = @@ -168,10 +136,14 @@ let test_consensus_op_for_next ~genesis ~kind ~next = | `Round -> Block.bake ~policy:(By_round 1) genesis in let* inc = Incremental.begin_construction ~mempool_mode:true b1 in - let* delegate, slot = delegate_of_first_slot (B b1) in - let* operation = dorsement ~attested_block:b1 ~delegate in + let* attesting_slot = Op.get_attesting_slot ~attested_block:b1 in + let* operation = consensus_op ~attested_block:b1 ~attesting_slot in let* inc = Incremental.add_operation inc operation in - let* delegate = delegate_of_slot ~different_slot:true slot (B b2) in - let* operation = dorsement ~attested_block:b2 ~delegate in + let* attesting_slot = + Op.get_different_attesting_slot + ~consensus_pkh_to_avoid:attesting_slot.consensus_pkh + ~attested_block:b2 + in + let* operation = consensus_op ~attested_block:b2 ~attesting_slot in let* (_ : Incremental.t) = Incremental.add_operation inc operation in return_unit diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.ml b/src/proto_alpha/lib_protocol/test/helpers/context.ml index b9ded8633ee6..ce9dffd30a49 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/context.ml @@ -135,28 +135,33 @@ let rpc_ctxt = | I bl -> Incremental.rpc_ctxt#call_proto_service3 s bl a b c q i end -let get_attesters ctxt = Plugin.RPC.Validators.get rpc_ctxt ctxt +type attester = Plugin.RPC.Validators.t = { + level : Raw_level.t; + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; + companion_key : Signature.Bls.Public_key_hash.t option; + slots : Slot.t list; +} -let get_first_different_attesters ctxt = - let open Lwt_result_syntax in - let+ attesters = get_attesters ctxt in - match attesters with x :: y :: _ -> (x, y) | _ -> assert false +let get_attesters ctxt = Plugin.RPC.Validators.get rpc_ctxt ctxt -let get_attester ctxt = +let get_attester ?manager_pkh ctxt = let open Lwt_result_syntax in - let+ attesters = get_attesters ctxt in - let attester = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd attesters in - (attester.consensus_key, attester.slots) + let* attesters = get_attesters ctxt in + match manager_pkh with + | None -> return (WithExceptions.Option.get ~loc:__LOC__ (List.hd attesters)) + | Some manager_pkh -> + List.find_opt + (fun {delegate; _} -> + Signature.Public_key_hash.equal delegate manager_pkh) + attesters + |> WithExceptions.Option.get ~loc:__LOC__ + |> return -let get_attester_slot ctxt pkh = +let get_first_different_attesters ctxt = let open Lwt_result_syntax in let+ attesters = get_attesters ctxt in - List.find_map - (function - | {Plugin.RPC.Validators.consensus_key; slots; _} -> - if Signature.Public_key_hash.(consensus_key = pkh) then Some slots - else None) - attesters + match attesters with x :: y :: _ -> (x, y) | _ -> assert false let get_attester_n ctxt n = let open Lwt_result_syntax in @@ -166,6 +171,21 @@ let get_attester_n ctxt n = in (attester.consensus_key, attester.slots) +let attester_has_bls_key {consensus_key; _} = + Signature.Public_key_hash.is_bls consensus_key + +let get_attesters_with_bls_key ctxt = + let open Lwt_result_syntax in + let* attesters = get_attesters ctxt in + return (List.filter attester_has_bls_key attesters) + +let get_attester_with_bls_key ctxt = + let open Lwt_result_syntax in + let* attesters = get_attesters ctxt in + List.find_opt attester_has_bls_key attesters + |> WithExceptions.Option.get ~loc:__LOC__ + |> return + let get_attesting_power_for_delegate ctxt ?level pkh = let open Lwt_result_syntax in let levels = Option.map (fun level -> [level]) level in diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.mli b/src/proto_alpha/lib_protocol/test/helpers/context.mli index 233758e14d2b..9140e1c1d5b3 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/context.mli @@ -38,30 +38,45 @@ val pred_branch : t -> Block_hash.t val get_level : t -> Raw_level.t tzresult -(** Given a context, returns the list of attesters charactized by - the [level], the public key hash of the [delegate], its [consensus_key] - and its assigned [slots]. - see {! Plugin.RPC.Validator.t}. *) -val get_attesters : t -> Plugin.RPC.Validators.t list tzresult Lwt.t +(** A delegate's keys and attesting slots at a given level. *) +type attester = Plugin.RPC.Validators.t = { + level : Raw_level.t; + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; + companion_key : Signature.Bls.Public_key_hash.t option; + slots : Slot.t list; +} + +(** Retrieves the attesting rights at the level of the given context + by calling {!Plugin.RPC.Validators.S.validators}. *) +val get_attesters : t -> attester list tzresult Lwt.t + +(** Returns an attester at the level of the given context. + + If [manager_pkh] is provided, returns the attester with this + manager key ({!field-delegate}) and fails if there is no such + attester. If [manager_pkh] is omitted, returns the first element + of the output of {!get_attesters}. *) +val get_attester : ?manager_pkh:public_key_hash -> t -> attester tzresult Lwt.t (** Return the two first elements of the list returns by [get_attesters]. *) val get_first_different_attesters : t -> (Plugin.RPC.Validators.t * Plugin.RPC.Validators.t) tzresult Lwt.t -(** Return the first element [delegate,slot] of the list returns by - [get_attesters], where [delegate] is the [consensus key] when - is set. *) -val get_attester : t -> (public_key_hash * Slot.t list) tzresult Lwt.t - -(** Given a [delegate], and a context [ctxt], if [delegate] is in - [get_attesters ctxt] returns the [slots] of [delegate] otherwise - return [None]. *) -val get_attester_slot : - t -> public_key_hash -> Slot.t list option 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 +(** Whether the {!type-attester}'s **consensus key** is a BLS key. *) +val attester_has_bls_key : attester -> bool + +(** Same as {!get_attesters} but returns only attesters with a BLS + consensus key. *) +val get_attesters_with_bls_key : t -> attester list tzresult Lwt.t + +(** Returns an attester with a BLS consensus key (the first eligible + attester returned by {!get_attesters}). *) +val get_attester_with_bls_key : t -> attester tzresult Lwt.t + (** Counts the number of attesting slots that the given delegate has in the requested level. If ommited, [level] defaults to the next level. *) diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 85f6db13d9e3..1fc86ef84eae 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -80,30 +80,93 @@ let mk_block_payload_hash (b : Block.t) = ~payload_round hashes -let mk_consensus_content_signer_and_branch ?delegate ?slot ?level ?round - ?block_payload_hash ?branch attested_block = +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 get_attesting_slot ~attested_block = + let open Lwt_result_syntax in + let* attester = Context.get_attester (B attested_block) in + return (attesting_slot_of_attester attester) + +let get_attesting_slot_of_delegate ~manager_pkh ~attested_block = + let open Lwt_result_syntax in + let* attester = Context.get_attester ~manager_pkh (B attested_block) in + return (attesting_slot_of_attester attester) + +let get_different_attesting_slot ~consensus_pkh_to_avoid ~attested_block = + let open Lwt_result_syntax in + let* attesters = Context.get_attesters (B attested_block) in + let attester = + List.find_opt + (fun {Plugin.RPC.Validators.consensus_key; _} -> + not + (Signature.Public_key_hash.equal consensus_key consensus_pkh_to_avoid)) + attesters + |> WithExceptions.Option.get ~loc:__LOC__ + 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 + | _ -> Test.fail ~__LOC__ "Expected attester to have at least two slots" + in + {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) + +let default_committee ~attested_block = + let open Lwt_result_syntax in + let* attesters_with_bls_key = + Context.get_attesters_with_bls_key (B attested_block) + in + return (List.map attesting_slot_of_attester attesters_with_bls_key) + +let get_attesting_slot_with_bls_key ~attested_block = + let open Lwt_result_syntax in + let* attester = Context.get_attester_with_bls_key (B attested_block) in + return (attesting_slot_of_attester attester) + +let get_attesting_slot_with_non_bls_key ~attested_block = + let open Lwt_result_syntax in + let* attesters = Context.get_attesters (B attested_block) in + let attester = + List.find_opt + (fun attester -> not (Context.attester_has_bls_key attester)) + attesters + |> WithExceptions.Option.get ~loc:__LOC__ + in + return (attesting_slot_of_attester attester) + +let attesting_slot_of_delegate_rights + {RPC.Attestation_rights.consensus_key; first_slot; _} = + {slot = first_slot; consensus_pkh = consensus_key} + +let mk_consensus_content_signer_and_branch ?attesting_slot ?manager_pkh ?level + ?round ?block_payload_hash ?branch attested_block = let open Lwt_result_wrap_syntax in let branch = match branch with | None -> attested_block.Block.header.shell.predecessor | Some branch -> branch in - let* delegate_pkh, slots = - match delegate with - | None -> Context.get_attester (B attested_block) - | Some del -> ( - let* slots = Context.get_attester_slot (B attested_block) del in - match slots with - | None -> return (del, []) - | Some slots -> return (del, slots)) - in - let* slot = - match slot with - | None -> ( - match List.hd slots with - | Some s -> return s - | None -> tzfail (Block.No_slots_found_for delegate_pkh)) - | Some slot -> return slot + let* {slot; consensus_pkh} = + match (attesting_slot, manager_pkh) with + | Some attesting_slot, None -> return attesting_slot + | None, None -> get_attesting_slot ~attested_block + | None, Some manager_pkh -> + get_attesting_slot_of_delegate ~manager_pkh ~attested_block + | Some _, Some _ -> + Test.fail + ~__LOC__ + "Cannot provide both ~attesting_slot and ~manager_pkh" in let* level = match level with @@ -125,16 +188,16 @@ let mk_consensus_content_signer_and_branch ?delegate ?slot ?level ?round | Some block_payload_hash -> block_payload_hash in let consensus_content = {slot; level; round; block_payload_hash} in - let* signer = Account.find delegate_pkh in + let* signer = Account.find consensus_pkh in return (consensus_content, signer.sk, branch) -let raw_attestation ?delegate ?slot ?level ?round ?block_payload_hash - ?dal_content ?branch attested_block = +let raw_attestation ?attesting_slot ?manager_pkh ?level ?round + ?block_payload_hash ?dal_content ?branch attested_block = let open Lwt_result_syntax in let* consensus_content, signer, branch = mk_consensus_content_signer_and_branch - ?delegate - ?slot + ?attesting_slot + ?manager_pkh ?level ?round ?block_payload_hash @@ -156,7 +219,7 @@ let raw_aggregate attestations = match (contents, signature) with | ( Single (Attestation {consensus_content; dal_content}), Some (Bls bls_sig) ) -> ( - let {slot; _} = consensus_content in + let ({slot; _} : consensus_content) = consensus_content in match acc with | Some (shell, proposal, slots, signatures) -> Some @@ -192,7 +255,7 @@ let raw_aggregate_preattestations preattestations = (fun acc ({shell; protocol_data = {contents; signature}} : _ Operation.t) -> match (contents, signature) with | Single (Preattestation consensus_content), Some (Bls bls_sig) -> ( - let {slot; _} = consensus_content in + let ({slot; _} : consensus_content) = consensus_content in match acc with | Some (shell, proposal, slots, signatures) -> Some (shell, proposal, slot :: slots, bls_sig :: signatures) @@ -218,13 +281,13 @@ let raw_aggregate_preattestations preattestations = let protocol_data = {contents; signature = Some (Bls signature)} in ({shell; protocol_data} : Kind.preattestations_aggregate operation) -let attestation ?delegate ?slot ?level ?round ?block_payload_hash ?dal_content - ?branch attested_block = +let attestation ?attesting_slot ?manager_pkh ?level ?round ?block_payload_hash + ?dal_content ?branch attested_block = let open Lwt_result_syntax in let* op = raw_attestation - ?delegate - ?slot + ?attesting_slot + ?manager_pkh ?level ?round ?block_payload_hash @@ -241,20 +304,17 @@ let raw_attestations_aggregate ?committee ?level ?round ?block_payload_hash match committee with | Some committee -> return committee | None -> - let* attesters = Context.get_attesters (B attested_block) in + let* attesting_slots = default_committee ~attested_block in return - @@ List.filter_map - (fun {Plugin.RPC.Validators.consensus_key; _} -> - if Signature.Public_key_hash.is_bls consensus_key then - Some (consensus_key, None) - else None) - attesters + (List.map + (fun attesting_slot -> (attesting_slot, None)) + attesting_slots) in let* attestations = List.map_es - (fun (delegate, dal_content) -> + (fun (attesting_slot, dal_content) -> raw_attestation - ~delegate + ~attesting_slot ?dal_content ?level ?round @@ -281,13 +341,13 @@ let attestations_aggregate ?committee ?level ?round ?block_payload_hash ?branch in return (Operation.pack op) -let raw_preattestation ?delegate ?slot ?level ?round ?block_payload_hash ?branch - attested_block = +let raw_preattestation ?attesting_slot ?manager_pkh ?level ?round + ?block_payload_hash ?branch attested_block = let open Lwt_result_syntax in let* consensus_content, signer, branch = mk_consensus_content_signer_and_branch - ?delegate - ?slot + ?attesting_slot + ?manager_pkh ?level ?round ?block_payload_hash @@ -302,13 +362,13 @@ let raw_preattestation ?delegate ?slot ?level ?round ?block_payload_hash ?branch branch contents -let preattestation ?delegate ?slot ?level ?round ?block_payload_hash ?branch - attested_block = +let preattestation ?attesting_slot ?manager_pkh ?level ?round + ?block_payload_hash ?branch attested_block = let open Lwt_result_syntax in let* op = raw_preattestation - ?delegate - ?slot + ?attesting_slot + ?manager_pkh ?level ?round ?block_payload_hash @@ -323,21 +383,13 @@ let raw_preattestations_aggregate ?committee ?level ?round ?block_payload_hash let* committee = match committee with | Some committee -> return committee - | None -> - let* attesters = Context.get_attesters (B attested_block) in - return - @@ List.filter_map - (fun attester -> - match attester.Plugin.RPC.Validators.consensus_key with - | Bls _ -> Some attester.delegate - | _ -> None) - attesters + | None -> default_committee ~attested_block in let* preattestations = List.map_es - (fun delegate -> + (fun attesting_slot -> raw_preattestation - ~delegate + ~attesting_slot ?level ?round ?block_payload_hash diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 5c4552f15813..3740c186b144 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -58,19 +58,89 @@ val sign : val create_proof : Signature.secret_key -> Signature.Bls.t option +(** Information needed on the author of a (pre)attestation: slot + (written into the (pre)attestation) and consensus key (required + for signing). *) +type attesting_slot = {slot : Slot.t; consensus_pkh : public_key_hash} + +(** Builds an {!attesting_slot} with the attester's consensus key and + canonical slot, that is, its first slot. *) +val attesting_slot_of_attester : Context.attester -> attesting_slot + +(** Returns the canonical {!attesting_slot} of the first attester + returned by {!Plugin.RPC.Validators.S.validators}. *) +val get_attesting_slot : attested_block:Block.t -> attesting_slot tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} of delegate [manager_pkh] + for [attested_block]. Fails if it doesn't have any attesting + rights for this block. *) +val get_attesting_slot_of_delegate : + manager_pkh:public_key_hash -> + attested_block:Block.t -> + attesting_slot tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} of the first attester + returned by {!Plugin.RPC.Validators.S.validators} whose consensus + key is different from [consensus_pkh_to_avoid]. *) +val get_different_attesting_slot : + consensus_pkh_to_avoid:public_key_hash -> + attested_block:Block.t -> + attesting_slot tzresult Lwt.t + +(** Builds an {!attesting_slot} with the attester's consensus key and + 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 + +(** Retrieves the first attester returned by + {!Plugin.RPC.Validators.S.validators} and builds a non-canonical + {!attesting_slot} for it, where {!field-slot} is its + second-smallest slot. *) +val get_non_canonical_attesting_slot : + attested_block:Block.t -> attesting_slot tzresult Lwt.t + +(** Default committee for a (pre)attestations aggregate, that is, the + canonical attesting slots of all delegates with attesting rights + on [attested_block] whose consensus keys are BLS keys. *) +val default_committee : + attested_block:Block.t -> attesting_slot list tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} of the first attester + returned by {!Plugin.RPC.Validators.S.validators} whose consensus + key is a BLS key. *) +val get_attesting_slot_with_bls_key : + attested_block:Block.t -> attesting_slot tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} of the first attester + returned by {!Plugin.RPC.Validators.S.validators} whose consensus + key is a non-BLS key. *) +val get_attesting_slot_with_non_bls_key : + attested_block:Block.t -> attesting_slot tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} corresponding to a + {!RPC.Attestation_rights.delegate_rights}. *) +val attesting_slot_of_delegate_rights : + RPC.Attestation_rights.delegate_rights -> attesting_slot + (** Create an unpacked attestation that is expected for given [Block.t]. Optional parameters allow to specify the attested values: [level], [round], [block_payload_hash], and/or [dal_content]. - They also allow to specify the attester ([delegate]), and/or the - [slot]. These default to the first slot and its delegate. + The consensus slot and signer are the ones from [attesting_slot] + if provided, otherwise the canonical ones for the delegate with + [manager_pkh] if provided (and the function fails if [manager_pkh] + is not the manager key of a delegate with attesting rights at the + given [Block.t]'s level); otherwise, they default to the attesting + slot returned by {!get_attesting_slot}. The function fails if both + [attesting_slot] and [manager_pkh] are provided. Finally, the operation [branch] can be specified. It defaults to the predecessor of the attested block. *) val raw_attestation : - ?delegate:public_key_hash -> - ?slot:Slot.t -> + ?attesting_slot:attesting_slot -> + ?manager_pkh:public_key_hash -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -84,8 +154,8 @@ val raw_attestation : Optional parameters are the same than {!raw_attestation}. *) val raw_preattestation : - ?delegate:public_key_hash -> - ?slot:Slot.t -> + ?attesting_slot:attesting_slot -> + ?manager_pkh:public_key_hash -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -96,8 +166,8 @@ val raw_preattestation : (** Create a packed attestation that is expected for a given [Block.t] by packing the result of {!raw_attestation}. *) val attestation : - ?delegate:public_key_hash -> - ?slot:Slot.t -> + ?attesting_slot:attesting_slot -> + ?manager_pkh:public_key_hash -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -109,9 +179,14 @@ val attestation : (** Crafts an {!Attestations_aggregate} operation pointing to the given {!Block.t}. Block context is expected to include at least one delegate with a BLS consensus key, otherwise this function - will return an error. *) + will return an error. + + [committee] defaults to {!default_committee} with [dal_content = + None] for each member. + + Other parameters are the same as in {!raw_attestation}. *) val raw_attestations_aggregate : - ?committee:(public_key_hash * dal_content option) list -> + ?committee:(attesting_slot * dal_content option) list -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -122,7 +197,7 @@ val raw_attestations_aggregate : (** Same as {!raw_preattestations_aggregate} but returns the packed operation. *) val attestations_aggregate : - ?committee:(public_key_hash * dal_content option) list -> + ?committee:(attesting_slot * dal_content option) list -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -133,8 +208,8 @@ val attestations_aggregate : (** Create a packed preattestation that is expected for a given [Block.t] by packing the result of {!raw_preattestation}. *) val preattestation : - ?delegate:public_key_hash -> - ?slot:Slot.t -> + ?attesting_slot:attesting_slot -> + ?manager_pkh:public_key_hash -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -142,11 +217,16 @@ val preattestation : Block.t -> Operation.packed tzresult Lwt.t -(** Create a packed preattestations_aggregate that is expected for a given - [Block.t]. Block context is expected to include at least one delegate with a - BLS key (or a registered consensus keys). *) +(** Crafts a {!Preattestations_aggregate} operation pointing to the + given {!Block.t}. Block context is expected to include at least + one delegate with a BLS consensus key, otherwise this function + will return an error. + + [committee] defaults to {!default_committee}. + + Other parameters are the same as in {!raw_attestation}. *) val raw_preattestations_aggregate : - ?committee:public_key_hash list -> + ?committee:attesting_slot list -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -157,7 +237,7 @@ val raw_preattestations_aggregate : (** Same as {!raw_preattestations_aggregate} but returns the packed operation. *) val preattestations_aggregate : - ?committee:public_key_hash list -> + ?committee:attesting_slot list -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> diff --git a/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml b/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml index d8b9b34ffe54..31cb50100bc8 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml @@ -267,9 +267,7 @@ let attest_with ?dal_content (delegate_name : string) : (t, t) scenarios = Option.map (fun i -> Alpha_context.{attestation = i}) dal_content in (* Fails to produce an attestation if the delegate has no slot for the block *) - let* op = - Op.attestation ?dal_content ~delegate:consensus_key.pkh block - in + let* op = Op.attestation ?dal_content ~manager_pkh:delegate.pkh block in (* Update the activity of the delegate *) let state = update_activity delegate_name block state in let state = State.add_pending_operations [op] state in @@ -314,6 +312,11 @@ let attest_aggreg_with (delegates : string list) : (t, t) scenarios = in (* Update the activity of the committee *) let state = update_activity delegate_name block state in + let* attesting_slot = + Op.get_attesting_slot_of_delegate + ~manager_pkh:delegate.pkh + ~attested_block:block + in let key_in_metadata = { Alpha_context.Consensus_key.delegate = delegate.pkh; @@ -322,7 +325,7 @@ let attest_aggreg_with (delegates : string list) : (t, t) scenarios = in return ( state, - (consensus_pkh, None) :: committee, + (attesting_slot, None) :: committee, key_in_metadata :: expected_metadata_committee )) (state, [], []) delegates @@ -382,7 +385,7 @@ let attest_with_all_ : t -> t tzresult Lwt.t = (fun (state, bls_committee) ({ RPC.Attestation_rights.delegate = manager_pkh; - consensus_key; + consensus_key = consensus_pkh; first_slot = slot; attestation_power = _; } as delegate_rights) -> @@ -393,18 +396,19 @@ let attest_with_all_ : t -> t tzresult Lwt.t = let state = update_activity delegate_name block state in if state.constants.aggregate_attestation - && Signature.Public_key_hash.is_bls consensus_key + && Signature.Public_key_hash.is_bls consensus_pkh then (* Just add the delegate to the committee; aggregation and metadata check will be handled below. *) return (state, delegate_rights :: bls_committee) else (* Add standalone attestation and metadata check. *) - let* op = Op.attestation ~delegate:consensus_key ~slot block in + let attesting_slot = {Op.slot; consensus_pkh} in + let* op = Op.attestation ~attesting_slot block in let state = State.add_pending_operations [op] state in let state = State.add_current_block_check - (check_attestation_metadata ~kind manager_pkh consensus_key) + (check_attestation_metadata ~kind manager_pkh consensus_pkh) state in return (state, bls_committee)) @@ -417,8 +421,8 @@ let attest_with_all_ : t -> t tzresult Lwt.t = (* Add aggregated attestation and metadata check. *) let committee = List.map - (fun {RPC.Attestation_rights.consensus_key; _} -> - (consensus_key, None)) + (fun delegate_rights -> + (Op.attesting_slot_of_delegate_rights delegate_rights, None)) bls_committee in let* op = Op.attestations_aggregate ~committee block in @@ -483,7 +487,7 @@ let preattest_with ?payload_round (delegate_name : string) : let consensus_key = consensus_key_info.active in let* consensus_key = Account.find consensus_key.consensus_key_pkh in (* Fails to produce an attestation if the delegate has no slot for the block *) - let* op = Op.preattestation ~delegate:consensus_key.pkh fake_block in + let* op = Op.preattestation ~manager_pkh:delegate.pkh fake_block in (* Update the activity of the delegate *) let state = update_activity delegate_name (Incremental.predecessor incr) state @@ -523,6 +527,11 @@ let preattest_aggreg_with ?payload_round (delegates : string list) : Context.Delegate.consensus_key (I incr) delegate.pkh in let consensus_pkh = consensus_key_info.active.consensus_key_pkh in + let* () = + if Signature.Public_key_hash.is_bls consensus_pkh then + return_unit + else failwith "Cannot aggregate non-BLS preattestation" + in (* Update the activity of the committee *) let state = update_activity @@ -530,6 +539,12 @@ let preattest_aggreg_with ?payload_round (delegates : string list) : (Incremental.predecessor incr) state in + (* Fails if the delegate has no slot for the block *) + let* attesting_slot = + Op.get_attesting_slot_of_delegate + ~manager_pkh:delegate.pkh + ~attested_block:fake_block + in let key_for_metadata = { Alpha_context.Consensus_key.delegate = delegate.pkh; @@ -538,22 +553,11 @@ let preattest_aggreg_with ?payload_round (delegates : string list) : in return ( state, - consensus_pkh :: committee, + attesting_slot :: committee, key_for_metadata :: expected_metadata_committee )) (state, [], []) delegates in - let* () = - if - not - @@ List.for_all - (function - | (Bls _ : Signature.public_key_hash) -> true | _ -> false) - committee - then failwith "Cannot aggregate non-BLS preattestation" - else return_unit - in - (* Fails to produce a preattestation if one of the delegates has no slot for the block *) let* op = Op.preattestations_aggregate ~committee fake_block in (* Check metadata *) let state = @@ -603,7 +607,7 @@ let preattest_with_all_ ?payload_round : t_incr -> t_incr tzresult Lwt.t = (fun (incr, state, bls_committee) ({ Plugin.RPC.Attestation_rights.delegate = manager_pkh; - consensus_key; + consensus_key = consensus_pkh; first_slot = slot; attestation_power = _; } as delegate_rights) -> @@ -616,20 +620,19 @@ let preattest_with_all_ ?payload_round : t_incr -> t_incr tzresult Lwt.t = in if state.constants.aggregate_attestation - && Signature.Public_key_hash.is_bls consensus_key + && Signature.Public_key_hash.is_bls consensus_pkh then (* Just add the delegate to the committee; aggregation and metadata check will be handled below. *) return (incr, state, delegate_rights :: bls_committee) else - (* Add standalone attestation and metadata check. *) - let* op = - Op.preattestation ~delegate:consensus_key ~slot fake_block - in + (* Add standalone preattestation and metadata check. *) + let attesting_slot = {Op.slot; consensus_pkh} in + let* op = Op.preattestation ~attesting_slot fake_block in let* incr = Incremental.add_operation incr op in let state = State.add_current_block_check - (check_attestation_metadata ~kind manager_pkh consensus_key) + (check_attestation_metadata ~kind manager_pkh consensus_pkh) state in return (incr, state, bls_committee)) @@ -638,11 +641,9 @@ let preattest_with_all_ ?payload_round : t_incr -> t_incr tzresult Lwt.t = in if List.is_empty bls_committee then return (incr, state) else - (* Add aggregated attestation and metadata check. *) + (* Add aggregated preattestation and metadata check. *) let committee = - List.map - (fun {RPC.Attestation_rights.consensus_key; _} -> consensus_key) - bls_committee + List.map Op.attesting_slot_of_delegate_rights bls_committee in let* op = Op.preattestations_aggregate ~committee fake_block in let* incr = Incremental.add_operation incr op in diff --git a/src/proto_alpha/lib_protocol/test/helpers/scenario_op.ml b/src/proto_alpha/lib_protocol/test/helpers/scenario_op.ml index 5100c97640d6..3bc5841f2f3e 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/scenario_op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/scenario_op.ml @@ -471,8 +471,9 @@ let double_attest_op ?other_bakers ~op ~op_evidence ~kind delegate_names let* main_branch, state = bake (block, state) in List.fold_left_es (fun (main_branch, state) delegate -> - let* attestation_a = op ~delegate:delegate.pkh forked_block in - let* attestation_b = op ~delegate:delegate.pkh main_branch in + let manager_pkh = delegate.pkh in + let* attestation_a = op ~manager_pkh ~attested_block:forked_block in + let* attestation_b = op ~manager_pkh ~attested_block:main_branch in let evidence = op_evidence attestation_a attestation_b in let dss = { @@ -493,7 +494,8 @@ let double_attest_op ?other_bakers ~op ~op_evidence ~kind delegate_names let double_attest_ = double_attest_op - ~op:(fun ~delegate block -> Op.raw_attestation ~delegate block) + ~op:(fun ~manager_pkh ~attested_block -> + Op.raw_attestation ~manager_pkh attested_block) ~op_evidence:op_double_attestation ~kind:Double_attesting @@ -506,7 +508,8 @@ let double_attest ?other_bakers delegate_name : (t, t) scenarios = let double_preattest_ = double_attest_op - ~op:(fun ~delegate block -> Op.raw_preattestation ~delegate block) + ~op:(fun ~manager_pkh ~attested_block -> + Op.raw_preattestation ~manager_pkh attested_block) ~op_evidence:op_double_preattestation ~kind:Double_preattesting 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 2d01b8d01c2c..11e8d54b4f70 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 @@ -110,7 +110,7 @@ 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) ~committee +let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters (result : kind Tezos_protocol_alpha__Protocol.Apply_results.contents_result) = let open Lwt_result_syntax in @@ -135,14 +135,14 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~committee | [] -> return_unit | _ -> Test.fail "Unexpected non-empty balance updates list" in - (* Check voting power *) + (* Check total voting power *) let* () = let voting_power = List.fold_left (fun acc (delegate : RPC.Validators.t) -> List.length delegate.slots + acc) 0 - committee + attesters in if voting_power = total_consensus_power then return_unit else @@ -152,83 +152,66 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~committee total_consensus_power in (* Check committee *) - let committee_pkhs = + let expected_committee = List.map - (fun (consensus_key : RPC.Validators.t) -> consensus_key.delegate) - committee - in - let resulting_committee_pkhs = - List.map - (fun ((attester : Alpha_context.Consensus_key.t), _) -> - attester.delegate) - resulting_committee + (fun {Context.delegate; consensus_key = consensus_pkh; slots; _} -> + let power = List.length slots in + ({Alpha_context.Consensus_key.delegate; consensus_pkh}, power)) + attesters in if List.equal - Tezos_crypto.Signature.Public_key_hash.equal - resulting_committee_pkhs - committee_pkhs + (fun ( {Alpha_context.Consensus_key.delegate = d1; consensus_pkh = c1}, + power1 ) + ({delegate = d2; consensus_pkh = c2}, power2) -> + Signature.Public_key_hash.equal d1 d2 + && Signature.Public_key_hash.equal c1 c2 + && Int.equal power1 power2) + resulting_committee + expected_committee then return_unit else let pp = - Format.( - pp_print_list - ~pp_sep:pp_print_cut - Tezos_crypto.Signature.Public_key_hash.pp) + Format.pp_print_list (fun fmt (consensus_key, power) -> + Format.fprintf + fmt + "%a with power %d" + Alpha_context.Consensus_key.pp + consensus_key + power) in Test.fail - "@[Wrong commitee@,@[expected:@,%a@]@,@[found:@,%a@]@]" + "@[Wrong committee@,\ + @[expected:@,\ + %a@]@,\ + @[found:@,\ + %a@]@]" pp - committee_pkhs + expected_committee pp - resulting_committee_pkhs + resulting_committee (* [check_preattestations_aggregate_result ~committee result] verifies that [result] has the following properties: - [balance_update] is empty; - [voting_power] equals the sum of slots owned by attesters in [committee]; - the public key hashes in [result] committee match those of [committee]. *) -let check_preattestations_aggregate_result ~committee +let check_preattestations_aggregate_result ~attesters (result : Alpha_context.Kind.preattestations_aggregate Tezos_protocol_alpha__Protocol.Apply_results.contents_result) = - check_aggregate_result Preattestation ~committee result + check_aggregate_result Preattestation ~attesters result (* [check_attestations_aggregate_result ~committee result] verifies that [result] has the following properties: - [balance_update] is empty; - [voting_power] equals the sum of slots owned by attesters in [committee]; - the public key hashes in [result] committee match those of [committee]. *) -let check_attestations_aggregate_result ~committee +let check_attestations_aggregate_result ~attesters (result : Alpha_context.Kind.attestations_aggregate Tezos_protocol_alpha__Protocol.Apply_results.contents_result) = - check_aggregate_result Attestation ~committee result - -(* [find_attester_with_bls_key attesters] returns the first attester with a BLS - key, if any. *) -let find_attester_with_bls_key = - List.find_map (fun (attester : RPC.Validators.t) -> - match (attester.consensus_key, attester.slots) with - | Bls _, slot :: _ -> Some (attester, slot) - | _ -> None) - -(* [find_attester_with_non_bls_key attesters] returns the first attester - with a non-BLS key, if any. *) -let find_attester_with_non_bls_key = - List.find_map (fun (attester : RPC.Validators.t) -> - match (attester.consensus_key, attester.slots) with - | (Ed25519 _ | Secp256k1 _ | P256 _), slot :: _ -> Some (attester, slot) - | _ -> None) - -(* [filter_attesters_with_bls_key attesters] filters attesters with a BLS - consensus key and at least one slot, returning a list of - (minimal slot, attester) pairs. *) -let filter_attesters_with_bls_key = - List.filter_map (fun (attester : RPC.Validators.t) -> - match (attester.consensus_key, attester.slots) with - | Bls _, slot :: _ -> Some (slot, attester) - | _ -> None) + check_aggregate_result Attestation ~attesters result let test_aggregate_feature_flag_enabled () = let open Lwt_result_syntax in @@ -256,22 +239,17 @@ let test_aggregate_feature_flag_disabled () = let test_attestations_aggregate_with_a_single_delegate () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - (* Find an attester with a BLS consensus key. *) - let attester, _slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in + let* attester = Context.get_attester_with_bls_key (B attested_block) in + let attesting_slot = Op.attesting_slot_of_attester attester in let* operation = - Op.attestations_aggregate ~committee:[(attester.consensus_key, None)] block + Op.attestations_aggregate ~committee:[(attesting_slot, None)] attested_block in - let* _, (_, receipt) = Block.bake_with_metadata ~operation block in + let* _, (_, receipt) = Block.bake_with_metadata ~operation attested_block in let result = find_attestations_aggregate_result receipt in - check_attestations_aggregate_result ~committee:[attester] result + check_attestations_aggregate_result ~attesters:[attester] result let test_preattestations_aggregate_with_a_single_delegate () = let open Lwt_result_syntax in @@ -279,15 +257,10 @@ let test_preattestations_aggregate_with_a_single_delegate () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in - (* Find an attester with a BLS consensus key. *) - let attester, _slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in + let* attester = Context.get_attester_with_bls_key (B block') in + let attesting_slot = Op.attesting_slot_of_attester attester in let* operation = - Op.preattestations_aggregate ~committee:[attester.consensus_key] block' + Op.preattestations_aggregate ~committee:[attesting_slot] block' in let* _, (_, receipt) = let round_zero = Alpha_context.Round.zero in @@ -299,26 +272,23 @@ let test_preattestations_aggregate_with_a_single_delegate () = block in let result = find_preattestations_aggregate_result receipt in - check_preattestations_aggregate_result ~committee:[attester] result + check_preattestations_aggregate_result ~attesters:[attester] result let test_attestations_aggregate_with_multiple_delegates () = let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - (* Filter delegates with BLS keys that have at least one slot *) - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in + let* attesters = Context.get_attesters_with_bls_key (B block) in let committee = List.map - (fun (_slot, delegate) -> (delegate.RPC.Validators.consensus_key, None)) - bls_delegates_with_slots + (fun attester -> (Op.attesting_slot_of_attester attester, None)) + attesters in let* operation = Op.attestations_aggregate ~committee block in let* _, (_, receipt) = Block.bake_with_metadata ~operation block in let result = find_attestations_aggregate_result receipt in - let delegates = List.map snd bls_delegates_with_slots in - check_attestations_aggregate_result ~committee:delegates result + check_attestations_aggregate_result ~attesters result let test_preattestations_aggregate_with_multiple_delegates () = let open Lwt_result_syntax in @@ -326,14 +296,8 @@ let test_preattestations_aggregate_with_multiple_delegates () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in - (* Filter delegates with BLS keys that have at least one slot *) - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in - let committee = - List.map - (fun (_slot, delegate) -> delegate.RPC.Validators.consensus_key) - bls_delegates_with_slots - in + let* attesters = Context.get_attesters_with_bls_key (B block') in + let committee = List.map Op.attesting_slot_of_attester attesters in let* operation = Op.preattestations_aggregate ~committee block' in let* _, (_, receipt) = let round_zero = Alpha_context.Round.zero in @@ -345,25 +309,14 @@ let test_preattestations_aggregate_with_multiple_delegates () = block in let result = find_preattestations_aggregate_result receipt in - let delegates = List.map snd bls_delegates_with_slots in - check_preattestations_aggregate_result ~committee:delegates result + check_preattestations_aggregate_result ~attesters result let test_attestations_aggregate_invalid_signature () = let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - (* Find an attester with a BLS consensus key. *) - let attester, _ = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in - (* Craft an aggregate with a single attestation signed by this delegate *) - let* aggregate = - Op.attestations_aggregate ~committee:[(attester.consensus_key, None)] block - in + let* aggregate = Op.attestations_aggregate block in (* Swap the signature for Signature.Bls.zero *) match aggregate.protocol_data with | Operation_data {contents; _} -> @@ -386,17 +339,7 @@ let test_preattestations_aggregate_invalid_signature () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block) in - (* Find an attester with a BLS consensus key. *) - let attester, _ = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in - (* Craft a preattestations_aggregate with this delegate *) - let* aggregate = - Op.preattestations_aggregate ~committee:[attester.consensus_key] block' - in + let* aggregate = Op.preattestations_aggregate block' in (* Swap the aggregate signature for Signature.Bls.zero *) match aggregate.protocol_data with | Operation_data {contents; _} -> @@ -425,20 +368,14 @@ let test_preattestations_aggregate_non_bls_delegate () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in (* Find an attester with a non-BLS consensus key. *) - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_non_bls_key attesters) + let* attesting_slot = + Op.get_attesting_slot_with_non_bls_key ~attested_block:block' in (* Craft a preattestation for this attester to retrieve a signature and a triplet {level, round, block_payload_hash} *) let* {shell; protocol_data = {contents; signature}} = - Op.raw_preattestation - ~delegate:attester.RPC.Validators.delegate - ~slot - block' + Op.raw_preattestation ~attesting_slot block' in match contents with | Single (Preattestation consensus_content) -> @@ -452,7 +389,8 @@ let test_preattestations_aggregate_non_bls_delegate () = in let contents : _ Alpha_context.contents_list = Single - (Preattestations_aggregate {consensus_content; committee = [slot]}) + (Preattestations_aggregate + {consensus_content; committee = [attesting_slot.slot]}) in let operation : operation = {shell; protocol_data = Operation_data {contents; signature}} @@ -474,17 +412,14 @@ let test_attestations_aggregate_non_bls_delegate () = let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in (* Find an attester with a non-BLS consensus key. *) - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_non_bls_key attesters) + let* attesting_slot = + Op.get_attesting_slot_with_non_bls_key ~attested_block:block in (* Craft an attestation for this attester to retrieve a signature and a triplet {level, round, block_payload_hash} *) let* {shell; protocol_data = {contents; signature}} = - Op.raw_attestation ~delegate:attester.RPC.Validators.delegate ~slot block + Op.raw_attestation ~attesting_slot block in let (Single (Attestation @@ -500,7 +435,7 @@ let test_attestations_aggregate_non_bls_delegate () = let contents : _ Alpha_context.contents_list = Single (Attestations_aggregate - {consensus_content; committee = [(slot, dal_content)]}) + {consensus_content; committee = [(attesting_slot.slot, dal_content)]}) in let operation : operation = {shell; protocol_data = Operation_data {contents; signature}} @@ -520,17 +455,14 @@ let test_multiple_aggregates_per_block_forbidden () = let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - (* Filter delegates with BLS keys that have at least one slot *) - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in + (* Retrieve delegates with BLS keys that have at least one slot *) + let* committee = Op.default_committee ~attested_block:block in (* Craft one attestations_aggregate per attester *) let* aggregates = List.map_es - (fun (_, (delegate : RPC.Validators.t)) -> - Op.attestations_aggregate - ~committee:[(delegate.consensus_key, None)] - block) - bls_delegates_with_slots + (fun attesting_slot -> + Op.attestations_aggregate ~committee:[(attesting_slot, None)] block) + committee in (* Bake a block containing the multiple aggregates and expect an error *) let*! res = Block.bake ~operations:aggregates block in @@ -543,11 +475,12 @@ let test_multiple_aggregates_per_block_forbidden () = in (* Craft one preattestations_aggregate per attester *) let* block' = Block.bake block in + let* committee = Op.default_committee ~attested_block:block' in let* aggregates = List.map_es - (fun (_, (delegate : RPC.Validators.t)) -> - Op.preattestations_aggregate ~committee:[delegate.consensus_key] block') - bls_delegates_with_slots + (fun attesting_slot -> + Op.preattestations_aggregate ~committee:[attesting_slot] block') + committee in (* Bake a block containing the multiple aggregates and expect an error *) let round_zero = Alpha_context.Round.zero in @@ -571,58 +504,52 @@ let test_eligible_preattestation_must_be_aggregated () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in - let attester = find_attester_with_bls_key attesters in - match attester with - | Some (attester, _) -> - let* operation = - Op.preattestation ~delegate:attester.consensus_key block' - in - (* Operation is valid in the Mempool *) - let* inc = Incremental.begin_construction ~mempool_mode:true block in - let* inc = Incremental.add_operation inc operation in - let* _ = Incremental.finalize_block inc in - (* Operation is invalid in a block *) - let*! res = - let round_zero = Alpha_context.Round.zero in - Block.bake - ~policy:(By_round 1) - ~payload_round:round_zero - ~locked_round:round_zero - ~operation - block - in - Assert.proto_error - ~loc:__LOC__ - res - (unaggregated_eligible_attestation - ~kind:Validate_errors.Consensus.Preattestation) - | _ -> assert false + let* attesting_slot = + Op.get_attesting_slot_with_bls_key ~attested_block:block' + in + let* operation = Op.preattestation ~attesting_slot block' in + (* Operation is valid in the Mempool *) + let* inc = Incremental.begin_construction ~mempool_mode:true block in + let* inc = Incremental.add_operation inc operation in + let* _ = Incremental.finalize_block inc in + (* Operation is invalid in a block *) + let*! res = + let round_zero = Alpha_context.Round.zero in + Block.bake + ~policy:(By_round 1) + ~payload_round:round_zero + ~locked_round:round_zero + ~operation + block + in + Assert.proto_error + ~loc:__LOC__ + res + (unaggregated_eligible_attestation + ~kind:Validate_errors.Consensus.Preattestation) let test_eligible_attestation_must_be_aggregated () = let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - let attester = find_attester_with_bls_key attesters in - match attester with - | Some (attester, _) -> - let* operation = Op.attestation ~delegate:attester.consensus_key block in - (* Operation is valid in the Mempool *) - let* inc = Incremental.begin_construction ~mempool_mode:true block in - let* inc = Incremental.add_operation inc operation in - let* _ = Incremental.finalize_block inc in - (* Operation is invalid in a block *) - let*! res = Block.bake ~operation block in - Assert.proto_error - ~loc:__LOC__ - res - (unaggregated_eligible_attestation - ~kind:Validate_errors.Consensus.Attestation) - (* TODO: https://gitlab.com/tezos/tezos/-/issues/7827 - Also test this behaviour for attestations with DAL contents. *) - | _ -> assert false + let* attesting_slot = + Op.get_attesting_slot_with_bls_key ~attested_block:block + in + let* operation = Op.attestation ~attesting_slot block in + (* Operation is valid in the Mempool *) + let* inc = Incremental.begin_construction ~mempool_mode:true block in + let* inc = Incremental.add_operation inc operation in + let* _ = Incremental.finalize_block inc in + (* Operation is invalid in a block *) + let*! res = Block.bake ~operation block in + Assert.proto_error + ~loc:__LOC__ + res + (unaggregated_eligible_attestation + ~kind:Validate_errors.Consensus.Attestation) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/7827 + Also test this behaviour for attestations with DAL contents. *) let test_empty_committee () = let open Lwt_result_syntax in @@ -682,31 +609,21 @@ let test_metadata_committee_is_correctly_ordered () = in (* Craft an attestations_aggregate including at least 3 delegates *) let* attestations, attestation_committee = - let* attesters = Context.get_attesters (B block) in - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in + let* attesting_slots = Op.default_committee ~attested_block:block in let committee = - List.map - (fun (_slot, (delegate : RPC.Validators.t)) -> - (delegate.consensus_key, None)) - bls_delegates_with_slots + List.map (fun attesting_slot -> (attesting_slot, None)) attesting_slots in assert (List.length committee > 2) ; let* aggregate = Op.attestations_aggregate ~committee block in - return (aggregate, bls_delegates_with_slots) + return (aggregate, attesting_slots) in (* Craft a preattestations_aggregate including at least 3 delegates *) let* preattestations, preattestation_committee = let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in - let committee = - List.map - (fun (_slot, (delegate : RPC.Validators.t)) -> delegate.consensus_key) - bls_delegates_with_slots - in + let* committee = Op.default_committee ~attested_block:block' in assert (List.length committee > 2) ; let* aggregate = Op.preattestations_aggregate ~committee block' in - return (aggregate, bls_delegates_with_slots) + return (aggregate, committee) in (* Bake a block including both aggregates *) let* _, (_, receipt) = @@ -751,12 +668,12 @@ let test_metadata_committee_is_correctly_ordered () = (fun (slot, _) -> let owner = WithExceptions.Option.get ~loc:__LOC__ - @@ List.assoc - ~equal:Alpha_context.Slot.equal - slot + @@ List.find_opt + (fun attesting_slot -> + Alpha_context.Slot.equal attesting_slot.Op.slot slot) attestation_committee in - owner.consensus_key) + owner.consensus_pkh) committee in check_committees ~loc:__LOC__ committee result_committee @@ -776,12 +693,12 @@ let test_metadata_committee_is_correctly_ordered () = (fun slot -> let owner = WithExceptions.Option.get ~loc:__LOC__ - @@ List.assoc - ~equal:Alpha_context.Slot.equal - slot + @@ List.find_opt + (fun attesting_slot -> + Alpha_context.Slot.equal attesting_slot.Op.slot slot) preattestation_committee in - owner.consensus_key) + owner.consensus_pkh) committee in check_committees ~loc:__LOC__ committee result_committee @@ -789,17 +706,18 @@ let test_metadata_committee_is_correctly_ordered () = in return_unit -let test_preattestation_signature_for_attestation ~block ~delegate = +let test_preattestation_signature_for_attestation ~attested_block + ~attesting_slot = let open Lwt_result_syntax in - let* op_preattestation = Op.preattestation ~delegate block in - let* op_attestation = Op.attestation ~delegate block in + let* op_preattestation = Op.preattestation ~attesting_slot attested_block in + let* op_attestation = Op.attestation ~attesting_slot attested_block in let op_attestation_with_preattestation_signature = Op.copy_op_signature ~src:op_preattestation ~dst:op_attestation in let* () = Op.check_validation_and_application ~loc:__LOC__ - ~predecessor:block + ~predecessor:attested_block ~error:signature_invalid_error Mempool op_attestation_with_preattestation_signature @@ -810,7 +728,7 @@ let test_preattestation_signature_for_attestation ~block ~delegate = let* () = Op.check_validation_and_application ~loc:__LOC__ - ~predecessor:block + ~predecessor:attested_block ~error:signature_invalid_error Mempool op_preattestation_with_attestation_signature @@ -820,54 +738,37 @@ let test_preattestation_signature_for_attestation ~block ~delegate = let test_preattestation_signature_for_attestation_non_bls () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in - let* block = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B block) in - test_preattestation_signature_for_attestation ~delegate ~block + let* attested_block = Block.bake genesis in + let* attesting_slot = + Op.get_attesting_slot_with_non_bls_key ~attested_block + in + test_preattestation_signature_for_attestation ~attesting_slot ~attested_block let test_preattestation_signature_for_attestation_bls () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - let delegate, _slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in - test_preattestation_signature_for_attestation - ~delegate:delegate.delegate - ~block + let* attesting_slot = Op.get_attesting_slot_with_bls_key ~attested_block in + test_preattestation_signature_for_attestation ~attesting_slot ~attested_block let test_signature_bls_attestation_with_different_slot () = - let find_attester_slots_with_bls_key attesters = - List.find_map - (fun (attester : RPC.Validators.t) -> - match attester.consensus_key with - | Bls _ -> Some (attester, attester.slots) - | _ -> None) - attesters - in let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - let delegate, slots = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_slots_with_bls_key attesters) - in + let* attester = Context.get_attester_with_bls_key (B block) in + let consensus_pkh = attester.consensus_key in let slot1, slot2 = - match slots with + match attester.slots with | slot1 :: slot2 :: _ -> (slot1, slot2) | _ -> Test.fail ~__LOC__ "Delegate must have at least two slots" in let* op_attestation1 = - Op.attestation ~slot:slot1 ~delegate:delegate.delegate block + Op.attestation ~attesting_slot:{slot = slot1; consensus_pkh} block in let* op_attestation2 = - Op.attestation ~slot:slot2 ~delegate:delegate.delegate block + Op.attestation ~attesting_slot:{slot = slot2; consensus_pkh} block in Assert.equal ~loc:__LOC__ @@ -879,22 +780,17 @@ let test_signature_bls_attestation_with_different_slot () = let test_signature_bls_attestation_with_different_level () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - let delegate, _slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in - let*? level1 = Context.get_level (B block) in + let* attesting_slot = Op.get_attesting_slot_with_bls_key ~attested_block in + let*? level1 = Context.get_level (B attested_block) in let level2 = Alpha_context.Raw_level.add level1 1 in let* op_attestation1 = - Op.attestation ~level:level1 ~delegate:delegate.delegate block + Op.attestation ~level:level1 ~attesting_slot attested_block in let* op_attestation2 = - Op.attestation ~level:level2 ~delegate:delegate.delegate block + Op.attestation ~level:level2 ~attesting_slot attested_block in Assert.not_equal ~loc:__LOC__ 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 4e96d8c7aa11..7ae0cad56f70 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 @@ -143,13 +143,15 @@ let test_negative_slot () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in + let* attester = Context.get_attester (B b) in Lwt.catch (fun () -> let* (_ : packed_operation) = + let slot = + Slot.Internal_for_tests.of_int_unsafe_only_use_for_tests (-1) + in Op.attestation - ~delegate - ~slot:(Slot.Internal_for_tests.of_int_unsafe_only_use_for_tests (-1)) + ~attesting_slot:{slot; consensus_pkh = attester.consensus_key} b in failwith "negative slot should not be accepted by the binary format") @@ -162,38 +164,34 @@ let test_negative_slot () = let test_not_smallest_slot () = let open Lwt_result_syntax in let* _genesis, b = init_genesis () in - let* delegate, slot = delegate_and_second_slot b in + let* attesting_slot = Op.get_non_canonical_attesting_slot ~attested_block:b in Consensus_helpers.test_consensus_operation_all_modes_different_outcomes ~loc:__LOC__ ~attested_block:b - ~delegate - ~slot + ~attesting_slot ~application_error:error_wrong_slot ~construction_error:error_wrong_slot ~mempool_error:error_wrong_slot Attestation -let delegate_and_someone_elses_slot block = +let attesting_slot_with_someone_elses_slot block = let open Lwt_result_syntax in let* attesters = Context.get_attesters (B block) in - let delegate, other_delegate_slot = - match attesters with - | [] | [_] -> assert false (* at least two delegates with rights *) - | {delegate; _} :: {slots; _} :: _ -> - (delegate, WithExceptions.Option.get ~loc:__LOC__ (List.hd slots)) - in - return (delegate, other_delegate_slot) + 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} (** Attestation with a slot that does not belong to the delegate. *) let test_not_own_slot () = let open Lwt_result_syntax in let* _genesis, b = init_genesis () in - let* delegate, other_delegate_slot = delegate_and_someone_elses_slot b in + let* attesting_slot = attesting_slot_with_someone_elses_slot b in Consensus_helpers.test_consensus_operation_all_modes ~loc:__LOC__ ~attested_block:b - ~delegate - ~slot:other_delegate_slot + ~attesting_slot ~error:(function | Alpha_context.Operation.Invalid_signature -> true | _ -> false) Attestation @@ -206,12 +204,11 @@ let test_mempool_not_own_slot () = let* predecessor = Block.bake grandparent ~policy:(By_round 1) in let* future_block = Block.bake predecessor in let check_not_own_slot_fails loc b = - let* delegate, other_delegate_slot = delegate_and_someone_elses_slot b in + let* attesting_slot = attesting_slot_with_someone_elses_slot b in Consensus_helpers.test_consensus_operation ~loc ~attested_block:b - ~delegate - ~slot:other_delegate_slot + ~attesting_slot ~error:(function | Alpha_context.Operation.Invalid_signature -> true | _ -> false) Attestation @@ -599,22 +596,23 @@ let test_attestation_threshold ~sufficient_threshold () = let* {parametric = {consensus_threshold_size; _}; _} = Context.get_constants (B b) in - let* attesters_list = Context.get_attesters (B b) 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) {Plugin.RPC.Validators.delegate; slots; _} -> - let new_counter = counter + List.length slots in + (fun (counter, attestations) (attester : Context.attester) -> + let new_counter = counter + List.length attester.slots in if (sufficient_threshold && counter < consensus_threshold_size) || (not sufficient_threshold) && new_counter < consensus_threshold_size then - let* attestation = Op.attestation ~round ~delegate b in + let attesting_slot = Op.attesting_slot_of_attester attester in + let* attestation = Op.attestation ~attesting_slot ~round b in return (new_counter, attestation :: attestations) else return (counter, attestations)) (0, []) - attesters_list + attesters in let*! b = Block.bake ~operations:attestations b in if sufficient_threshold then return_unit @@ -699,7 +697,7 @@ let test_attester_with_no_assigned_shards () = let* has_assigned_shards = Dal_helpers.has_assigned_shards (B b) pkh in if in_committee && not has_assigned_shards then let dal_content = {attestation = Dal.Attestation.empty} in - let* op = Op.attestation ~delegate:pkh ~dal_content b in + let* op = Op.attestation ~manager_pkh:pkh ~dal_content b in let* ctxt = Incremental.begin_construction b in let expect_apply_failure = function | [ @@ -769,7 +767,7 @@ let test_dal_attestation_threshold () = List.fold_left_es (fun (acc_ops, acc_power) ({delegate; indexes} : RPC.Dal.S.shards_assignment) -> - let* op = Op.attestation ~delegate ~dal_content b in + let* op = Op.attestation ~manager_pkh:delegate ~dal_content b in let ops = op :: acc_ops in let power = acc_power + List.length indexes in let* _b, (metadata, _ops) = @@ -797,8 +795,10 @@ let slot_substitution_do_not_affect_signature_check () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in - let* signer = Account.find delegate in + let* {Context.consensus_key = consensus_pkh; _} = + Context.get_attester (B b) + in + let* signer = Account.find consensus_pkh in let watermark = Operation.to_watermark (Attestation Chain_id.zero) in let slot_swap_and_check_signature slot ({shell = {branch}; protocol_data = {contents; _}} : @@ -831,7 +831,7 @@ let slot_substitution_do_not_affect_signature_check () = else Test.fail "Unexpected signature check failure" in let* attestation_without_dal = - Op.raw_attestation ~delegate ~slot:Slot.zero b + Op.raw_attestation ~attesting_slot:{slot = Slot.zero; consensus_pkh} b in let* () = slot_swap_and_check_signature @@ -841,9 +841,8 @@ let slot_substitution_do_not_affect_signature_check () = let* attestation_with_dal = (* attestation with dal signed with slot zero *) Op.raw_attestation + ~attesting_slot:{slot = Slot.zero; consensus_pkh} ~dal_content:{attestation = Dal.Attestation.empty} - ~delegate - ~slot:Slot.zero b in let* () = @@ -860,8 +859,8 @@ let encoding_incompatibility () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in - let* signer = Account.find delegate in + let* attester = Context.get_attester (B b) in + let* signer = Account.find attester.consensus_key in let check_encodings_incompatibily ({shell = {branch}; protocol_data = {contents; signature = _}} : Kind.attestation operation) = @@ -920,12 +919,13 @@ let encoding_incompatibility () = then Test.fail "Unexpected signature check success (bytes_without_slot)" else return_unit in - let* raw_attestation_without_dal = Op.raw_attestation ~delegate b in + let attesting_slot = Op.attesting_slot_of_attester attester in + let* raw_attestation_without_dal = Op.raw_attestation ~attesting_slot b in let* () = check_encodings_incompatibily raw_attestation_without_dal in let* raw_attestation_with_dal = Op.raw_attestation + ~attesting_slot ~dal_content:{attestation = Dal.Attestation.empty} - ~delegate b in let* () = check_encodings_incompatibily raw_attestation_with_dal 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 241b99a71b04..6e2ffa90f146 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 @@ -221,12 +221,6 @@ let test_rewards_block_and_payload_producer () = let* baker_b1_contract = get_contract_for_pkh contracts baker_b1 in let* b1 = Block.bake ~policy:(By_round 0) genesis in let* attesters = Context.get_attesters (B b1) in - let* attesters = - List.map_es - (function - | {Plugin.RPC.Validators.delegate; slots; _} -> return (delegate, slots)) - attesters - in (* We let just a part of the attesters vote; we assume here that 5 of 10 attesters will have together at least one slot (to pass the threshold), but not all slots (to make the test more interesting, otherwise we know the @@ -234,12 +228,16 @@ let test_rewards_block_and_payload_producer () = let attesters = List.take_n 5 attesters in let* attestations = List.map_ep - (fun (attester, _slots) -> Op.attestation ~delegate:attester b1) + (fun attester -> + Op.attestation + ~attesting_slot:(Op.attesting_slot_of_attester attester) + b1) attesters in let attesting_power = List.fold_left - (fun acc (_pkh, slots) -> acc + List.length slots) + (fun acc attester -> + acc + List.length attester.Plugin.RPC.Validators.slots) 0 attesters in @@ -276,16 +274,13 @@ let test_rewards_block_and_payload_producer () = correspond to a slot of [baker_b2] and it includes the PQC for [b2]. We check that the fixed baking reward goes to the payload producer [baker_b2], while the bonus goes to the the block producer (aka baker) [baker_b2']. *) - let* attesters = Context.get_attesters (B b2) in - let* preattesters = - List.map_es - (function - | {Plugin.RPC.Validators.delegate; slots; _} -> return (delegate, slots)) - attesters - in + let* preattesters = Context.get_attesters (B b2) in let* preattestations = List.map_ep - (fun (attester, _slots) -> Op.preattestation ~delegate:attester b2) + (fun attester -> + Op.preattestation + ~attesting_slot:(Op.attesting_slot_of_attester attester) + b2) preattesters in let* baker_b2 = Context.get_baker (B b1) ~round:Round.zero in diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_consensus_key.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_consensus_key.ml index 15c44c695276..80c6e9f7fe92 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_consensus_key.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_consensus_key.ml @@ -351,8 +351,8 @@ let test_consensus_key_with_unused_proof () = let test_attestation_with_consensus_key () = let open Lwt_result_wrap_syntax in - let* genesis, contracts = Context.init_with_constants1 constants in - let account1_pkh = Context.Contract.pkh contracts in + let* genesis, contract = Context.init_with_constants1 constants in + let account1_pkh = Context.Contract.pkh contract in let consensus_account = Account.new_account () in let delegate = account1_pkh in let consensus_pk = consensus_account.pk in @@ -362,15 +362,18 @@ let test_attestation_with_consensus_key () = in let* b_pre = update_consensus_key blk' delegate consensus_pk in let* b = Block.bake b_pre in + (* There is only one delegate, so its minimal slot is zero. *) let*?@ slot = Slot.of_int 0 in - let* attestation = Op.attestation ~delegate:account1_pkh ~slot b in + let* attestation = + Op.attestation ~attesting_slot:{slot; consensus_pkh = account1_pkh} b + in let*! res = Block.bake ~operation:attestation b in let* () = Assert.proto_error ~loc:__LOC__ res (function | Operation.Invalid_signature -> true | _ -> false) in - let* attestation = Op.attestation ~delegate:consensus_pkh ~slot b in + let* attestation = Op.attestation ~attesting_slot:{slot; consensus_pkh} b in let* (_good_block : Block.t) = Block.bake ~operation:attestation b in return_unit diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml index a0db6cc95f49..eeb8ffa8159f 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml @@ -196,18 +196,11 @@ let test_accusation_injection ?initial_blocks_to_bake ?expect_failure | None -> Test.fail ~__LOC__ "Unexpected case: there are no delegates" | Some (pkh, _) -> pkh in - let* attestation = Op.raw_attestation blk ~delegate ?dal_content in + let* attester = Context.get_attester ~manager_pkh:delegate (B blk) in + let attesting_slot = Op.attesting_slot_of_attester attester in + let* attestation = Op.raw_attestation blk ~attesting_slot ?dal_content in + let consensus_slot = attesting_slot.slot in let attestation_level = blk.header.shell.level in - let* consensus_slot = - let+ all_slots = Context.get_attester_slot (B blk) delegate in - let fst_slot = Option.bind all_slots List.hd in - match fst_slot with - | None -> - Test.fail - ~__LOC__ - "Unexpected case: delegate is not in attestation committee" - | Some slot -> slot - in let* blk = let blocks_to_bake = 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 813866b25ba8..507a6062bc7b 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 @@ -117,9 +117,9 @@ let test_valid_double_attestation_evidence () = are identical. *) let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* bakers = Context.get_bakers (B blk_a) in let baker = Context.get_first_different_baker delegate bakers in @@ -233,16 +233,16 @@ let test_different_branch () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init2 ~consensus_threshold_size:0 () in let* blk = Block.bake genesis in - let* attester, _slots = Context.get_attester (B blk) in - let* attestation_a = Op.raw_attestation ~delegate:attester blk in + let* {Context.delegate = manager_pkh; _} = Context.get_attester (B blk) in + let* attestation_a = Op.raw_attestation ~manager_pkh blk in let* attestation_b = - Op.raw_attestation ~branch:Block_hash.zero ~delegate:attester blk + Op.raw_attestation ~branch:Block_hash.zero ~manager_pkh blk in let operation = double_attestation (B blk) attestation_a attestation_b in let* _blk = Block.bake ~operation blk in - let* preattestation_a = Op.raw_preattestation ~delegate:attester blk in + let* preattestation_a = Op.raw_preattestation ~manager_pkh blk in let* preattestation_b = - Op.raw_preattestation ~branch:Block_hash.zero ~delegate:attester blk + Op.raw_preattestation ~branch:Block_hash.zero ~manager_pkh blk in let operation = double_preattestation (B blk) preattestation_a preattestation_b @@ -258,24 +258,30 @@ let test_different_slots () = 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 delegate, slot1, slot2 = + let consensus_pkh, slot1, slot2 = (* Find an attester with more than 1 slot. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map (fun (attester : RPC.Validators.t) -> match attester.slots with - | slot1 :: slot2 :: _ -> Some (attester.delegate, slot1, slot2) + | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) | _ -> None) attesters) in - let* attestation1 = Op.raw_attestation ~delegate ~slot:slot1 blk in - let* attestation2 = Op.raw_attestation ~delegate ~slot:slot2 blk 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 + let* attestation2 = Op.raw_attestation ~attesting_slot:attesting_slot2 blk in let double_attestation = double_attestation (B blk) attestation1 attestation2 in - let* preattestation1 = Op.raw_preattestation ~delegate ~slot:slot1 blk in - let* preattestation2 = Op.raw_preattestation ~delegate ~slot:slot2 blk in + let* preattestation1 = + Op.raw_preattestation ~attesting_slot:attesting_slot1 blk + in + let* preattestation2 = + Op.raw_preattestation ~attesting_slot:attesting_slot2 blk + in let double_preattestation = double_preattestation (B blk) preattestation1 preattestation2 in @@ -309,9 +315,9 @@ let test_two_double_attestation_evidences_leadsto_no_bake () = let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* bakers = Context.get_bakers (B blk_a) in let baker = Context.get_first_different_baker delegate bakers in @@ -324,8 +330,8 @@ let test_two_double_attestation_evidences_leadsto_no_bake () = let* blk_30, blk_40 = block_fork ~excluding:[delegate] blk_with_evidence1 in let* blk_3 = Block.bake ~policy:(Excluding [delegate]) blk_30 in let* blk_4 = Block.bake ~policy:(Excluding [delegate]) blk_40 in - let* attestation_3 = Op.raw_attestation ~delegate blk_3 in - let* attestation_4 = Op.raw_attestation ~delegate blk_4 in + let* attestation_3 = Op.raw_attestation ~manager_pkh:delegate blk_3 in + let* attestation_4 = Op.raw_attestation ~manager_pkh:delegate blk_4 in let operation = double_attestation (B blk_with_evidence1) attestation_3 attestation_4 in @@ -418,9 +424,9 @@ let test_two_double_attestation_evidences_staggered () = let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* bakers = Context.get_bakers (B blk_a) in let baker = Context.get_first_different_baker delegate bakers in @@ -434,8 +440,8 @@ let test_two_double_attestation_evidences_staggered () = let* blk_30, blk_40 = block_fork ~excluding:[delegate] blk_with_evidence1 in let* blk_3 = Block.bake ~policy:(Excluding [delegate]) blk_30 in let* blk_4 = Block.bake ~policy:(Excluding [delegate]) blk_40 in - let* attestation_3 = Op.raw_attestation ~delegate blk_3 in - let* attestation_4 = Op.raw_attestation ~delegate blk_4 in + let* attestation_3 = Op.raw_attestation ~manager_pkh:delegate blk_3 in + let* attestation_4 = Op.raw_attestation ~manager_pkh:delegate blk_4 in let operation_evidence2 = double_attestation (B blk_with_evidence1) attestation_3 attestation_4 in @@ -493,9 +499,9 @@ let test_two_double_attestation_evidences_consecutive_cycles () = let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* bakers = Context.get_bakers (B blk_a) in let baker = Context.get_first_different_baker delegate bakers in @@ -520,8 +526,8 @@ let test_two_double_attestation_evidences_consecutive_cycles () = let* blk_30, blk_40 = block_fork ~excluding:[delegate] blk_new_cycle in let* blk_3 = Block.bake ~policy:(Excluding [delegate]) blk_30 in let* blk_4 = Block.bake ~policy:(Excluding [delegate]) blk_40 in - let* attestation_3 = Op.raw_attestation ~delegate blk_3 in - let* attestation_4 = Op.raw_attestation ~delegate blk_4 in + let* attestation_3 = Op.raw_attestation ~manager_pkh:delegate blk_3 in + let* attestation_4 = Op.raw_attestation ~manager_pkh:delegate blk_4 in let operation = double_attestation (B blk_new_cycle) attestation_3 attestation_4 in @@ -614,19 +620,16 @@ let test_invalid_double_attestation_duplicate_in_committee () = let* blk_1, blk_2 = block_fork b in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* attesters = Context.get_attesters (B blk_a) in - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (Test_aggregate.find_attester_with_bls_key attesters) + let* attesting_slot = + Op.get_attesting_slot_with_bls_key ~attested_block:blk_a in - let* op1 = Op.raw_attestation ~delegate:attester.consensus_key ~slot blk_a in + let* op1 = Op.raw_attestation ~attesting_slot blk_a in let* op2 = Op.raw_attestations_aggregate - ~committee: - [(attester.consensus_key, None); (attester.consensus_key, None)] + ~committee:[(attesting_slot, None); (attesting_slot, None)] blk_b in + let slot = attesting_slot.slot in let op = let contents = if Operation_hash.(Operation.hash op1 < Operation.hash op2) then @@ -658,11 +661,7 @@ let test_invalid_double_attestation_duplicate_in_committee () = {attestation = Dal.Attestation.(commit empty slot_index)} in Op.raw_attestations_aggregate - ~committee: - [ - (attester.consensus_key, None); - (attester.consensus_key, Some dal_content); - ] + ~committee:[(attesting_slot, None); (attesting_slot, Some dal_content)] blk_b in let op = @@ -737,8 +736,16 @@ let test_different_delegates () = let* attester_a, attester_b = Context.get_first_different_attesters (B blk_b) in - let* e_a = Op.raw_attestation ~delegate:attester_a.delegate blk_a in - let* e_b = Op.raw_attestation ~delegate:attester_b.delegate blk_b in + let* e_a = + Op.raw_attestation + ~attesting_slot:(Op.attesting_slot_of_attester attester_a) + blk_a + in + let* e_b = + Op.raw_attestation + ~attesting_slot:(Op.attesting_slot_of_attester attester_b) + blk_b + in let* (_ : Block.t) = Block.bake ~operation:(Operation.pack e_b) blk_b in double_attestation (B blk_b) e_a e_b |> fun operation -> let*! res = Block.bake ~operation blk_b in @@ -748,46 +755,8 @@ let test_different_delegates () = true | _ -> false) -(** Check that a double attestation evidence that exposes a ill-formed - attestation fails. *) -let test_wrong_delegate () = - let open Lwt_result_syntax in - let* genesis, _contracts = Context.init2 ~consensus_threshold_size:0 () in - let* blk_1, blk_2 = block_fork genesis in - let* blk_a = Block.bake blk_1 in - let* blk_b = Block.bake blk_2 in - let* attester_a, _a_slots = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate:attester_a blk_a in - let* attester0, _slots0 = Context.get_attester_n (B blk_b) 0 in - let* attester1, _slots1 = Context.get_attester_n (B blk_b) 1 in - let attester_b = - if Signature.Public_key_hash.equal attester_a attester0 then attester1 - else attester0 - in - let* attestation_b = Op.raw_attestation ~delegate:attester_b blk_b in - double_attestation (B blk_b) attestation_a attestation_b |> fun operation -> - let*! res = Block.bake ~operation blk_b in - Assert.proto_error ~loc:__LOC__ res (function - | Validate_errors.Anonymous.Invalid_denunciation - Misbehaviour.Double_attesting -> - true - | _ -> false) - let test_freeze_more_with_low_balance = let open Lwt_result_syntax in - let get_attesting_slots_for_account ctxt account = - (* Get the slots of the given account in the given context. *) - let* attesters_list = Context.get_attesters ctxt in - match attesters_list with - | [d1; d2] -> - return - (if Signature.Public_key_hash.equal account d1.delegate then d1 - else if Signature.Public_key_hash.equal account d2.delegate then d2 - else assert false) - .slots - | _ -> assert false - (* there are exactly two attesters for this test. *) - in let double_attest_and_punish b2 account1 = let open Lwt_result_syntax in (* Bake a block on top of [b2] that includes a double-attestation @@ -795,16 +764,8 @@ let test_freeze_more_with_low_balance = let* blk_d1, blk_d2 = block_fork b2 in let* blk_a = Block.bake ~policy:(Block.By_account account1) blk_d1 in let* blk_b = Block.bake ~policy:(Block.By_account account1) blk_d2 in - let* slots_a = get_attesting_slots_for_account (B blk_a) account1 in - let slot = - match List.hd slots_a with None -> assert false | Some s -> s - in - let* attestation_a = Op.raw_attestation ~delegate:account1 ~slot blk_a in - let* slots_b = get_attesting_slots_for_account (B blk_b) account1 in - let slot = - match List.hd slots_b with None -> assert false | Some s -> s - in - let* attestation_b = Op.raw_attestation ~delegate:account1 ~slot blk_b in + let* attestation_a = Op.raw_attestation ~manager_pkh:account1 blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:account1 blk_b in let denunciation = double_attestation (B b2) attestation_a attestation_b in let* b = Block.bake ~policy:(Excluding [account1]) b2 ~operations:[denunciation] @@ -976,9 +937,9 @@ let test_two_double_attestation_evidences_leads_to_duplicate_denunciation () = let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let operation2 = double_attestation (B genesis) attestation_b attestation_a in let* bakers = Context.get_bakers (B blk_a) in @@ -1021,19 +982,25 @@ let different_slots_under_feature_flag () = in let* block = Block.bake genesis in let* attesters = Context.get_attesters (B block) in - let delegate, slot1, slot2 = + let consensus_pkh, slot1, slot2 = (* Find an attester with more than 1 slot. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map (fun (attester : RPC.Validators.t) -> match attester.slots with - | slot1 :: slot2 :: _ -> Some (attester.delegate, slot1, slot2) + | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) | _ -> None) attesters) in - let* attestation1 = Op.raw_attestation ~delegate ~slot:slot1 block in - let* attestation2 = Op.raw_attestation ~delegate ~slot:slot2 block 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 block + in + let* attestation2 = + Op.raw_attestation ~attesting_slot:attesting_slot2 block + in let double_attestation_evidence = double_attestation (B block) attestation1 attestation2 in @@ -1100,7 +1067,6 @@ let tests = `Quick test_too_late_double_attestation_evidence; Tztest.tztest "different delegates" `Quick test_different_delegates; - Tztest.tztest "wrong delegate" `Quick test_wrong_delegate; Tztest.tztest "different slots under feature flag" `Quick 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 26a45df62358..4bcd4910b345 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 @@ -193,8 +193,8 @@ let test_valid_double_baking_followed_by_double_attesting () = if Signature.Public_key_hash.( = ) e1.delegate baker1 then e1.delegate else e2.delegate in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* blk_final = Block.bake ~policy:(By_account baker2) ~operation blk_with_db_evidence @@ -271,8 +271,8 @@ let test_valid_double_attesting_followed_by_double_baking () = if Signature.Public_key_hash.( = ) e1.delegate baker1 then e1.delegate else e2.delegate in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* blk_with_de_evidence = Block.bake ~policy:(By_account baker2) ~operation blk_a @@ -365,7 +365,7 @@ let test_payload_producer_gets_evidence_rewards () = let* preattestations = List.map_ep (fun (attester, _slots) -> - Op.preattestation ~delegate:attester b_with_evidence) + Op.preattestation ~manager_pkh:attester b_with_evidence) preattesters in let* b' = 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 f4a4379dee5d..471ec9d11086 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 @@ -57,15 +57,6 @@ end = struct (** Helper function for illformed denunciations construction *) - let pick_attesters ctxt = - let open Lwt_result_syntax in - let module V = Plugin.RPC.Validators in - let* validators_list = Context.get_attesters ctxt in - match validators_list with - | a :: b :: _ -> - return ((a.V.delegate, a.V.slots), (b.V.delegate, b.V.slots)) - | _ -> assert false - let invalid_denunciation loc res = Assert.proto_error ~loc res (function | Validate_errors.Anonymous.Invalid_denunciation @@ -209,11 +200,7 @@ end = struct let generic_double_preattestation_denunciation ~nb_blocks_before_double ~nb_blocks_before_denunciation ~test_expected_ok ?(test_expected_ko = fun _loc _res -> Lwt_result_syntax.return_unit) - ?(pick_attesters = - let open Lwt_result_syntax in - fun ctxt -> - let* a, _b = pick_attesters ctxt in - return (a, a)) ~loc () = + ?(different_attesters = false) ~loc () = let open Lwt_result_syntax in let* genesis, contracts = Context.init_n @@ -232,10 +219,19 @@ end = struct let* trans = Op.transaction (B genesis) addr addr Tez.one_mutez in let* head_A = bake ~policy:(By_round 0) blk in let* head_B = bake ~policy:(By_round 0) blk ~operations:[trans] in - let* (d1, _slots1), (d2, _slots2) = pick_attesters (B head_A) in - (* default: d1 = d2 *) - let* op1 = Op.raw_preattestation ~delegate:d1 head_A in - let* op2 = Op.raw_preattestation ~delegate:d2 head_B in + (* By default, [different_attesters] is false so [d1 = d2]. *) + let* d1, d2 = + if different_attesters then + let* attester1, attester2 = + Context.get_first_different_attesters (B head_A) + in + return (attester1.delegate, attester2.delegate) + else + let* attester = Context.get_attester (B head_A) in + return (attester.delegate, attester.delegate) + in + let* op1 = Op.raw_preattestation ~manager_pkh:d1 head_A in + let* op2 = Op.raw_preattestation ~manager_pkh:d2 head_B in let op1, op2 = order_preattestations ~correct_order:true op1 op2 in (* bake `nb_blocks_before_denunciation` before double preattestation denunciation *) let* blk = bake_n nb_blocks_before_denunciation blk in @@ -302,7 +298,7 @@ end = struct ~nb_blocks_before_denunciation:2 ~test_expected_ok:unexpected_success ~test_expected_ko:invalid_denunciation - ~pick_attesters (* pick different attesters *) + ~different_attesters:true ~loc:__LOC__ () @@ -361,9 +357,9 @@ end = struct let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* preattestation_a = Op.raw_preattestation ~delegate blk_a in - let* preattestation_b = Op.raw_preattestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* preattestation_a = Op.raw_preattestation ~manager_pkh:delegate blk_a in + let* preattestation_b = Op.raw_preattestation ~manager_pkh:delegate blk_b in let operation = double_preattestation (B genesis) preattestation_a preattestation_b in @@ -406,19 +402,25 @@ end = struct in let* block = Block.bake genesis in let* attesters = Context.get_attesters (B block) in - let delegate, slot1, slot2 = + let consensus_pkh, slot1, slot2 = (* Find an attester with more than 1 slot. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map (fun (attester : RPC.Validators.t) -> match attester.slots with - | slot1 :: slot2 :: _ -> Some (attester.delegate, slot1, slot2) + | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) | _ -> None) attesters) in - let* preattestation1 = Op.raw_preattestation ~delegate ~slot:slot1 block in - let* preattestation2 = Op.raw_preattestation ~delegate ~slot:slot2 block in + let attesting_slot1 = {Op.slot = slot1; consensus_pkh} in + let attesting_slot2 = {Op.slot = slot2; consensus_pkh} in + let* preattestation1 = + Op.raw_preattestation ~attesting_slot:attesting_slot1 block + in + let* preattestation2 = + Op.raw_preattestation ~attesting_slot:attesting_slot2 block + in let double_preattestation_evidence = double_preattestation (B block) preattestation1 preattestation2 in @@ -450,20 +452,16 @@ end = struct let* blk_1, blk_2 = block_fork b in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* attesters = Context.get_attesters (B blk_a) in - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (Test_aggregate.find_attester_with_bls_key attesters) - in - let* op1 = - Op.raw_preattestation ~delegate:attester.consensus_key ~slot blk_a + let* attesting_slot = + Op.get_attesting_slot_with_bls_key ~attested_block:blk_a in + let* op1 = Op.raw_preattestation ~attesting_slot blk_a in let* op2 = Op.raw_preattestations_aggregate - ~committee:[attester.consensus_key; attester.consensus_key] + ~committee:[attesting_slot; attesting_slot] blk_b in + let slot = attesting_slot.slot in let op = let contents = if Operation_hash.(Operation.hash op1 < Operation.hash op2) then diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_frozen_deposits.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_frozen_deposits.ml index 8b0dfd2d8359..76472a5fc825 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_frozen_deposits.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_frozen_deposits.ml @@ -278,10 +278,10 @@ let test_may_not_bake_again_after_full_deposit_slash () = in let* blk_b = Block.bake ~policy:(By_account slashed_account) genesis in let* preattestation1 = - Op.raw_preattestation ~delegate:slashed_account blk_a + Op.raw_preattestation ~manager_pkh:slashed_account blk_a in let* preattestation2 = - Op.raw_preattestation ~delegate:slashed_account blk_b + Op.raw_preattestation ~manager_pkh:slashed_account blk_b in let preattestation1, preattestation2 = order_ops preattestation1 preattestation2 @@ -307,8 +307,8 @@ let test_may_not_bake_again_after_full_deposit_slash () = in let* blk_a = Block.bake ~policy:(By_account slashed_account) ~operation b in let* blk_b = Block.bake ~policy:(By_account slashed_account) b in - let* attestation1 = Op.raw_attestation ~delegate:slashed_account blk_a in - let* attestation2 = Op.raw_attestation ~delegate:slashed_account blk_b in + let* attestation1 = Op.raw_attestation ~manager_pkh:slashed_account blk_a in + let* attestation2 = Op.raw_attestation ~manager_pkh:slashed_account blk_b in let attestation1, attestation2 = order_ops attestation1 attestation2 in let double_attestation_op = Op.double_attestation (B blk_a) attestation1 attestation2 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 bded22a0a32a..5d60622bfa3c 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 @@ -37,24 +37,12 @@ open Alpha_context (** [baker] bakes and [attester] attests *) let bake_and_attest_once (_b_pred, b_cur) baker attester = let open Lwt_result_wrap_syntax in - let open Context in - let* attesters_list = Context.get_attesters (B b_cur) in - List.find_map - (function - | {Plugin.RPC.Validators.delegate; slots; _} -> - if Signature.Public_key_hash.equal delegate attester then - Some (delegate, slots) - else None) - attesters_list - |> function - | None -> assert false - | Some (delegate, _slots) -> - let*?@ round = Block.get_round b_cur in - let* attestation = Op.attestation ~round ~delegate b_cur in - Block.bake_with_metadata - ~policy:(By_account baker) - ~operation:attestation - b_cur + let*?@ round = Block.get_round b_cur in + let* attestation = Op.attestation ~manager_pkh:attester ~round b_cur in + Block.bake_with_metadata + ~policy:(By_account baker) + ~operation:attestation + b_cur (** We test that: - a delegate that participates enough, gets its attesting rewards at the end of the cycle, diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_preattestation.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_preattestation.ml index 3acbfc097665..136fab27d32d 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_preattestation.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_preattestation.ml @@ -201,9 +201,10 @@ let slot_substitution_does_not_affect_bytes () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in + let* attester = Context.get_attester (B b) in + let consensus_pkh = attester.consensus_key in let* {shell = {branch}; protocol_data = {contents; _}} = - Op.raw_preattestation ~delegate ~slot:Slot.zero b + Op.raw_preattestation ~attesting_slot:{slot = Slot.zero; consensus_pkh} b in match contents with | Single (Preattestation consensus_content) -> @@ -230,10 +231,11 @@ let encoding_incompatibility () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in - let* signer = Account.find delegate in + let* attester = Context.get_attester (B b) in + let* signer = Account.find attester.consensus_key in let* {shell = {branch}; protocol_data = {contents; signature = _}} = - Op.raw_preattestation ~delegate b + let attesting_slot = Op.attesting_slot_of_attester attester in + Op.raw_preattestation ~attesting_slot b in let bytes_without_slot = Data_encoding.Binary.to_bytes_exn diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_preattestation_functor.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_preattestation_functor.ml index 8637a9c24c9a..a190ceea269a 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_preattestation_functor.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_preattestation_functor.ml @@ -53,8 +53,8 @@ end = struct ?(preattestation_round = Round.zero) ?(preattested_block = fun _predpred _pred curr -> curr) ?(mk_ops = fun op -> [op]) - ?(get_delegate_and_slot = - fun _predpred _pred _curr -> Lwt_result_syntax.return (None, None)) + ?(get_attesting_slot = + fun ~attested_block:_ -> Lwt_result_syntax.return_none) ?(post_process = Ok (fun _ -> Lwt_result_syntax.return_unit)) ~loc () = let open Lwt_result_syntax in let* genesis, _contracts = @@ -64,11 +64,10 @@ end = struct let* attestation = Op.attestation b1 in let* b2 = bake b1 ~operations:[attestation] in let attested_block = preattested_block genesis b1 b2 in - let* delegate, slot = get_delegate_and_slot genesis b1 b2 in + let* attesting_slot = get_attesting_slot ~attested_block in let* p = Op.preattestation - ?delegate - ?slot + ?attesting_slot ~round:preattestation_round attested_block in @@ -162,30 +161,17 @@ end = struct (** OK: explicit the correct attester and preattesting slot in the test *) let preattestation_in_block_with_good_slot () = - let open Lwt_result_syntax in - aux_simple_preattestation_inclusion - ~get_delegate_and_slot:(fun _predpred _pred curr -> - let module V = Plugin.RPC.Validators in - let* validators = Context.get_attesters (B curr) in - match validators with - | {V.delegate; slots = s :: _; _} :: _ -> return (Some delegate, Some s) - | _ -> assert false - (* there is at least one attester with a slot *)) - ~loc:__LOC__ - () + aux_simple_preattestation_inclusion ~loc:__LOC__ () (** KO: the used slot for injecting the attestation is not the canonical one *) let preattestation_in_block_with_wrong_slot () = let open Lwt_result_syntax in aux_simple_preattestation_inclusion - ~get_delegate_and_slot:(fun _predpred _pred curr -> - let module V = Plugin.RPC.Validators in - let* validators = Context.get_attesters (B curr) in - match validators with - | {V.delegate; V.slots = _ :: non_canonical_slot :: _; _} :: _ -> - return (Some delegate, Some non_canonical_slot) - | _ -> assert false - (* there is at least one attester with a slot *)) + ~get_attesting_slot:(fun ~attested_block -> + let* attesting_slot = + Op.get_non_canonical_attesting_slot ~attested_block + in + return_some attesting_slot) ~loc:__LOC__ ~post_process: (Error @@ -201,15 +187,18 @@ end = struct let preattestation_in_block_with_wrong_signature () = let open Lwt_result_syntax in aux_simple_preattestation_inclusion - ~get_delegate_and_slot:(fun _predpred _pred curr -> - let module V = Plugin.RPC.Validators in - let* validators = Context.get_attesters (B curr) in - match validators with - | {V.delegate; _} :: {V.slots = s :: _; _} :: _ -> - (* the canonical slot s is not owned by the delegate "delegate" !*) - return (Some delegate, Some s) - | _ -> assert false - (* there is at least one attester with a slot *)) + ~get_attesting_slot:(fun ~attested_block -> + let* attester = Context.get_attester (B attested_block) in + let* another_delegates_attesting_slot = + Op.get_different_attesting_slot + ~consensus_pkh_to_avoid:attester.consensus_key + ~attested_block + in + return_some + { + Op.slot = another_delegates_attesting_slot.slot; + consensus_pkh = attester.consensus_key; + }) ~loc:__LOC__ ~post_process: (Error diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/test_seed.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_seed.ml index 1cf0f2df6104..8f8fe0675277 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/test_seed.ml +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_seed.ml @@ -329,8 +329,9 @@ let test_unrevealed () = let* slots = Context.get_attesters (B b) in let* attestations = List.map_es - (fun {Plugin.RPC.Validators.consensus_key; _} -> - Op.attestation ~delegate:consensus_key b) + (fun attester -> + let attesting_slot = Op.attesting_slot_of_attester attester in + Op.attestation ~attesting_slot b) slots in Block.bake ?policy ~operations:attestations b diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_origination.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_origination.ml index 69d4c194fa85..b26afe03687f 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_origination.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_origination.ml @@ -189,15 +189,6 @@ let test_not_tez_in_contract_to_pay_fee () = let*! inc = Incremental.add_operation inc op in Assert.proto_error_with_info ~loc:__LOC__ inc "Balance too low" -(* Set the attester of the block as manager/delegate of the originated - account. *) -let register_contract_get_attester () = - let open Lwt_result_syntax in - let* b, contract = Context.init1 () in - let* inc = Incremental.begin_construction b in - let+ account_attester, _slots = Context.get_attester (I inc) in - (inc, contract, account_attester) - (* Create multiple originated contracts and ask contract to pay the fee. *) let n_originations n ?credit ?fee () = let open Lwt_result_syntax in diff --git a/src/proto_alpha/lib_protocol/test/integration/validate/generator_descriptors.ml b/src/proto_alpha/lib_protocol/test/integration/validate/generator_descriptors.ml index 3b2c86b9e070..03f1e3974417 100644 --- a/src/proto_alpha/lib_protocol/test/integration/validate/generator_descriptors.ml +++ b/src/proto_alpha/lib_protocol/test/integration/validate/generator_descriptors.ml @@ -355,9 +355,9 @@ let dbl_attestation_prelude state = match heads with | None -> return ([], state) | Some (b1, b2) -> - let* delegate1, delegate2 = pick_two_attesters (B b1) in - let* op1 = Op.raw_preattestation ~delegate:delegate1 b1 in - let* op2 = Op.raw_preattestation ~delegate:delegate1 b2 in + let* attesting_slot = Op.get_attesting_slot ~attested_block:b1 in + let* op1 = Op.raw_preattestation ~attesting_slot b1 in + let* op2 = Op.raw_preattestation ~attesting_slot b2 in let op1, op2 = let comp = Operation_hash.compare (Operation.hash op1) (Operation.hash op2) @@ -368,8 +368,13 @@ let dbl_attestation_prelude state = let slashable_preattestations = (op1, op2) :: state.dbl_attestation.slashable_preattestations in - let* op3 = Op.raw_attestation ~delegate:delegate2 b1 in - let* op4 = Op.raw_attestation ~delegate:delegate2 b2 in + let* attesting_slot' = + Op.get_different_attesting_slot + ~consensus_pkh_to_avoid:attesting_slot.consensus_pkh + ~attested_block:b1 + in + let* op3 = Op.raw_attestation ~attesting_slot:attesting_slot' b1 in + let* op4 = Op.raw_attestation ~attesting_slot:attesting_slot' b2 in let op3, op4 = let comp = Operation_hash.compare (Operation.hash op3) (Operation.hash op4) @@ -604,17 +609,18 @@ let preattestation_descriptor = candidates_generator = (fun state -> let open Lwt_result_syntax in - let gen (delegate, ck_opt) = - let* slots_opt = Context.get_attester_slot (B state.block) delegate in - let delegate = Option.value ~default:delegate ck_opt in - match slots_opt with - | None -> return_none - | Some slots -> ( - match slots with - | [] -> return_none - | _ :: _ -> - let* op = Op.preattestation ~delegate state.block in - return_some op) + let gen (manager_pkh, _ck_opt) = + let* attesters = Context.get_attesters (B state.block) in + if + List.exists + (fun {Context.delegate; _} -> + Signature.Public_key_hash.equal delegate manager_pkh) + attesters + then + (* The manager key has attesting rights on this block *) + let* op = Op.preattestation ~manager_pkh state.block in + return_some op + else return_none in List.filter_map_es gen state.delegates); } @@ -630,17 +636,18 @@ let attestation_descriptor = candidates_generator = (fun state -> let open Lwt_result_syntax in - let gen (delegate, ck_opt) = - let* slots_opt = Context.get_attester_slot (B state.block) delegate in - let delegate = Option.value ~default:delegate ck_opt in - match slots_opt with - | None -> return_none - | Some slots -> ( - match slots with - | [] -> return_none - | _ :: _ -> - let* op = Op.attestation ~delegate state.block in - return_some op) + let gen (manager_pkh, _ck_opt) = + let* attesters = Context.get_attesters (B state.block) in + if + List.exists + (fun {Context.delegate; _} -> + Signature.Public_key_hash.equal delegate manager_pkh) + attesters + then + (* The manager key has attesting rights on this block *) + let* op = Op.attestation ~manager_pkh state.block in + return_some op + else return_none in List.filter_map_es gen state.delegates); } 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 e3c03c8090bc..c1f94115b43c 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 @@ -359,14 +359,6 @@ let secrets = (** {3 Context Manipulations } *) -let pick_two_attesters ctxt = - let open Lwt_result_syntax in - let module V = Plugin.RPC.Validators in - let* attesters = Context.get_attesters ctxt in - match attesters with - | a :: b :: _ -> return (a.V.consensus_key, b.V.consensus_key) - | _ -> assert false - let pick_addr_attester ctxt = let open Lwt_result_syntax in let module V = Plugin.RPC.Validators in -- GitLab From 1af6d35482c0db7395fe3d3715fa5f4fc714ab0c Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Wed, 9 Jul 2025 15:54:28 +0200 Subject: [PATCH 05/11] Proto/test: move error checkers to Error_helpers --- .../test/helpers/error_helpers.ml | 32 ++++++++ .../integration/consensus/test_aggregate.ml | 82 +++++++------------ 2 files changed, 60 insertions(+), 54 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml index 2625057541b6..7eb0b079591f 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml @@ -184,3 +184,35 @@ let expect_missing_bls_proof ~loc ~kind_pk ~pk ~source_pkh errs = && Signature.Public_key.(err_pk = pk) && Signature.Public_key_hash.(err_source = source_pkh) | _ -> false) + +let invalid_signature = function + | Operation_repr.Invalid_signature -> true + | _ -> false + +let conflicting_consensus_operation ?kind = function + | Validate_errors.Consensus.Conflicting_consensus_operation {kind = kind'; _} + -> + Option.fold ~none:true ~some:(fun kind -> kind = kind') kind + | _ -> false + +let aggregate_disabled = function + | Validate_errors.Consensus.Aggregate_disabled -> true + | _ -> false + +let aggregate_in_mempool = function + | Validate_errors.Consensus.Aggregate_in_mempool -> true + | _ -> false + +let non_bls_key_in_aggregate = function + | Validate_errors.Consensus.Non_bls_key_in_aggregate -> true + | _ -> false + +let unaggregated_eligible_attestation ?kind = function + | Validate_errors.Consensus.Unaggregated_eligible_operation {kind = kind'; _} + -> + Option.fold ~none:true ~some:(fun kind -> kind = kind') kind + | _ -> false + +let empty_aggregation_committee = function + | Validate_errors.Consensus.Empty_aggregation_committee -> true + | _ -> false 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 11e8d54b4f70..715c97262084 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 @@ -36,42 +36,6 @@ let init_genesis_with_some_bls_accounts ?policy ?dal_enable let* b = Block.bake ?policy genesis in return (genesis, b) -let aggregate_in_mempool_error = function - | Validate_errors.Consensus.Aggregate_in_mempool -> true - | _ -> false - -let aggregate_disabled_error = function - | Validate_errors.Consensus.Aggregate_disabled -> true - | _ -> false - -let aggregate_unimplemented_error = function - | Validate_errors.Consensus.Aggregate_not_implemented -> true - | _ -> false - -let signature_invalid_error = function - | Operation_repr.Invalid_signature -> true - | _ -> false - -let non_bls_in_aggregate = function - | Validate_errors.Consensus.Non_bls_key_in_aggregate -> true - | _ -> false - -let conflicting_consensus_operation ?kind = function - | Validate_errors.Consensus.Conflicting_consensus_operation {kind = kind'; _} - -> - Option.fold ~none:true ~some:(fun kind -> kind = kind') kind - | _ -> false - -let unaggregated_eligible_attestation ?kind = function - | Validate_errors.Consensus.Unaggregated_eligible_operation {kind = kind'; _} - -> - Option.fold ~none:true ~some:(fun kind -> kind = kind') kind - | _ -> false - -let empty_aggregation_committee = function - | Validate_errors.Consensus.Empty_aggregation_committee -> true - | _ -> false - let find_preattestations_aggregate_result receipt = let result_opt = List.find_map @@ -221,7 +185,7 @@ let test_aggregate_feature_flag_enabled () = Consensus_helpers.test_consensus_operation_all_modes_different_outcomes ~loc:__LOC__ ~attested_block - ~mempool_error:aggregate_in_mempool_error + ~mempool_error:Error_helpers.aggregate_in_mempool Aggregate let test_aggregate_feature_flag_disabled () = @@ -232,9 +196,9 @@ let test_aggregate_feature_flag_disabled () = Consensus_helpers.test_consensus_operation_all_modes_different_outcomes ~loc:__LOC__ ~attested_block - ~application_error:aggregate_disabled_error - ~construction_error:aggregate_disabled_error - ~mempool_error:aggregate_in_mempool_error + ~application_error:Error_helpers.aggregate_disabled + ~construction_error:Error_helpers.aggregate_disabled + ~mempool_error:Error_helpers.aggregate_in_mempool Aggregate let test_attestations_aggregate_with_a_single_delegate () = @@ -331,7 +295,7 @@ let test_attestations_aggregate_invalid_signature () = let*! res = Block.bake ~operation:aggregate_with_incorrect_signature block in - Assert.proto_error ~loc:__LOC__ res signature_invalid_error + Assert.proto_error ~loc:__LOC__ res Error_helpers.invalid_signature let test_preattestations_aggregate_invalid_signature () = let open Lwt_result_syntax in @@ -360,7 +324,7 @@ let test_preattestations_aggregate_invalid_signature () = ~operation:aggregate_with_incorrect_signature block in - Assert.proto_error ~loc:__LOC__ res signature_invalid_error + Assert.proto_error ~loc:__LOC__ res Error_helpers.invalid_signature let test_preattestations_aggregate_non_bls_delegate () = let open Lwt_result_syntax in @@ -405,7 +369,7 @@ let test_preattestations_aggregate_non_bls_delegate () = ~operation block in - Assert.proto_error ~loc:__LOC__ res non_bls_in_aggregate + Assert.proto_error ~loc:__LOC__ res Error_helpers.non_bls_key_in_aggregate let test_attestations_aggregate_non_bls_delegate () = let open Lwt_result_syntax in @@ -442,9 +406,9 @@ let test_attestations_aggregate_non_bls_delegate () = in Op.check_validation_and_application_all_modes_different_outcomes ~loc:__LOC__ - ~application_error:non_bls_in_aggregate - ~construction_error:non_bls_in_aggregate - ~mempool_error:aggregate_in_mempool_error + ~application_error:Error_helpers.non_bls_key_in_aggregate + ~construction_error:Error_helpers.non_bls_key_in_aggregate + ~mempool_error:Error_helpers.aggregate_in_mempool ~predecessor:block operation in @@ -470,7 +434,7 @@ let test_multiple_aggregates_per_block_forbidden () = Assert.proto_error ~loc:__LOC__ res - (conflicting_consensus_operation + (Error_helpers.conflicting_consensus_operation ~kind:Validate_errors.Consensus.Attestations_aggregate) in (* Craft one preattestations_aggregate per attester *) @@ -495,7 +459,7 @@ let test_multiple_aggregates_per_block_forbidden () = Assert.proto_error ~loc:__LOC__ res - (conflicting_consensus_operation + (Error_helpers.conflicting_consensus_operation ~kind:Validate_errors.Consensus.Preattestations_aggregate) let test_eligible_preattestation_must_be_aggregated () = @@ -525,7 +489,7 @@ let test_eligible_preattestation_must_be_aggregated () = Assert.proto_error ~loc:__LOC__ res - (unaggregated_eligible_attestation + (Error_helpers.unaggregated_eligible_attestation ~kind:Validate_errors.Consensus.Preattestation) let test_eligible_attestation_must_be_aggregated () = @@ -546,7 +510,7 @@ let test_eligible_attestation_must_be_aggregated () = Assert.proto_error ~loc:__LOC__ res - (unaggregated_eligible_attestation + (Error_helpers.unaggregated_eligible_attestation ~kind:Validate_errors.Consensus.Attestation) (* TODO: https://gitlab.com/tezos/tezos/-/issues/7827 Also test this behaviour for attestations with DAL contents. *) @@ -573,7 +537,12 @@ let test_empty_committee () = let operation = Op.pack_operation (B block) signature (Single contents) in (* Baking with the attestations_aggregate and expecting an error *) let*! res = Block.bake ~operation block in - let* () = Assert.proto_error ~loc:__LOC__ res empty_aggregation_committee in + let* () = + Assert.proto_error + ~loc:__LOC__ + res + Error_helpers.empty_aggregation_committee + in (* Crafting a preattestations_aggregate with an empty committee *) let* consensus_content = let* block = Block.bake block in @@ -599,7 +568,12 @@ let test_empty_committee () = ~operation block in - let* () = Assert.proto_error ~loc:__LOC__ res empty_aggregation_committee in + let* () = + Assert.proto_error + ~loc:__LOC__ + res + Error_helpers.empty_aggregation_committee + in return_unit let test_metadata_committee_is_correctly_ordered () = @@ -718,7 +692,7 @@ let test_preattestation_signature_for_attestation ~attested_block Op.check_validation_and_application ~loc:__LOC__ ~predecessor:attested_block - ~error:signature_invalid_error + ~error:Error_helpers.invalid_signature Mempool op_attestation_with_preattestation_signature in @@ -729,7 +703,7 @@ let test_preattestation_signature_for_attestation ~attested_block Op.check_validation_and_application ~loc:__LOC__ ~predecessor:attested_block - ~error:signature_invalid_error + ~error:Error_helpers.invalid_signature Mempool op_preattestation_with_attestation_signature in -- GitLab From 04f3ed98368d037113e1f34eb64f75a40ab2c127 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Wed, 9 Jul 2025 15:46:11 +0200 Subject: [PATCH 06/11] Proto/test: expend check_validation_and_application with check_after --- .../lib_protocol/test/helpers/block.ml | 2 + .../lib_protocol/test/helpers/block.mli | 9 +-- .../lib_protocol/test/helpers/op.ml | 59 +++++++++++++------ .../lib_protocol/test/helpers/op.mli | 20 +++++-- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.ml b/src/proto_alpha/lib_protocol/test/helpers/block.ml index d2c0b1e3952d..5221e801f1c6 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/block.ml @@ -43,6 +43,8 @@ type block = t type full_metadata = block_header_metadata * operation_receipt list +type block_with_metadata = block * full_metadata + let get_alpha_ctxt b = let open Lwt_result_wrap_syntax in let*@ ctxt, _migration_balance_updates, _migration_operation_results = diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.mli b/src/proto_alpha/lib_protocol/test/helpers/block.mli index f5312d01f162..1248e8632cb6 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/block.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/block.mli @@ -41,6 +41,8 @@ type block = t type full_metadata = block_header_metadata * operation_receipt list +type block_with_metadata = block * full_metadata + (** Not the same as [Context.get_alpha_ctxt] as it does not construct a new block *) val get_alpha_ctxt : t -> context tzresult Lwt.t @@ -252,7 +254,7 @@ val bake_with_metadata : ?liquidity_baking_toggle_vote:Per_block_votes.per_block_vote -> ?adaptive_issuance_vote:Per_block_votes.per_block_vote -> t -> - (t * (block_header_metadata * operation_receipt list)) tzresult Lwt.t + block_with_metadata tzresult Lwt.t (** Bakes [n] blocks. *) val bake_n : @@ -324,11 +326,10 @@ val bake_n_with_metadata : ?adaptive_issuance_vote:Per_block_votes_repr.per_block_vote -> int -> block -> - (block * (block_header_metadata * operation_receipt list)) tzresult Lwt.t + block_with_metadata tzresult Lwt.t val get_balance_updates_from_metadata : - block_header_metadata * operation_receipt list -> - Alpha_context.Receipt.balance_updates + full_metadata -> Alpha_context.Receipt.balance_updates (** Bake blocks while a predicate over the block holds. The returned block is the last one for which the predicate holds; in case the diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 1fc86ef84eae..b1708cde8ade 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -1399,58 +1399,79 @@ let show_mode = function | Construction -> "Construction" | Mempool -> "Mempool" -let check_validation_and_application ~loc ?error ~predecessor mode operation = +let check_validation_and_application ~loc ?check_after ?error ~predecessor mode + operation = let open Lwt_result_syntax in - let check_error res = - match error with - | Some error -> Assert.proto_error ~loc res error - | None -> + let check_res res = + match (check_after, error) with + | None, None -> (* assert success *) - let*? (_ : Block.t) = res in + let*? (_ : Block.block_with_metadata) = res in return_unit + | Some check_after, None -> + let*? block_with_metadata = res in + check_after block_with_metadata + | None, Some error -> Assert.proto_error ~loc res error + | Some _, Some _ -> + Test.fail + "Op.check_validation_and_application: cannot provide both \ + [check_after] and [error] (called from: %s)" + loc in match mode with | Application -> let*! result = - Block.bake ~baking_mode:Application ~operation predecessor + Block.bake_with_metadata ~baking_mode:Application ~operation predecessor in - check_error result + check_res result | Construction -> - let*! result = Block.bake ~baking_mode:Baking ~operation predecessor in - check_error result + let*! result = + Block.bake_with_metadata ~baking_mode:Baking ~operation predecessor + in + check_res result | Mempool -> let*! res = let* inc = Incremental.begin_construction ~mempool_mode:true predecessor in - let* inc = Incremental.add_operation inc operation in + let* inc, op_receipt = + Incremental.add_operation_with_metadata inc operation + in (* Finalization doesn't do much in mempool mode, but some RPCs still call it, so we check that it doesn't fail unexpectedly. *) - Incremental.finalize_block inc + let* block, header_metadata = + Incremental.finalize_block_with_metadata inc + in + return (block, (header_metadata, [op_receipt])) in - check_error res + check_res res let check_validation_and_application_all_modes_different_outcomes ~loc + ?check_after_application ?check_after_construction ?check_after_mempool ?application_error ?construction_error ?mempool_error ~predecessor operation = List.iter_es - (fun (mode, error) -> + (fun (mode, check_after, error) -> check_validation_and_application ~loc:(Format.sprintf "%s (%s mode)" loc (show_mode mode)) + ?check_after ?error ~predecessor mode operation) [ - (Application, application_error); - (Construction, construction_error); - (Mempool, mempool_error); + (Application, check_after_application, application_error); + (Construction, check_after_construction, construction_error); + (Mempool, check_after_mempool, mempool_error); ] -let check_validation_and_application_all_modes ~loc ?error ~predecessor - operation = +let check_validation_and_application_all_modes ~loc ?check_after ?error + ~predecessor operation = check_validation_and_application_all_modes_different_outcomes ~loc + ?check_after_application:check_after + ?check_after_construction:check_after + ?check_after_mempool:check_after ?application_error:error ?construction_error:error ?mempool_error:error diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 3740c186b144..14c043b9f3eb 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -853,14 +853,17 @@ type tested_mode = Application | Construction | Mempool - When [tested_mode] is [Mempool], a mempool is initialized using [predecessor] as head, then {!Incremental.add_operation} is called - on [operation]. + on [operation], then {!Incremental.finalize_block_with_metadata}. - When [error] is [None], we check that everything succeeds, - otherwise we check that the error identified by [error] is - returned. + When [check_after] is provided, it is called on the resulting + block. When [error] is provided, we check that an error identified + by [error] is returned. When neither is provided, we return unit + if there the validation and application returned [Ok], or the + unchanged error. When both are provided, the function fails. *) val check_validation_and_application : loc:string -> + ?check_after:(Block.block_with_metadata -> unit tzresult Lwt.t) -> ?error:(Environment.Error_monad.error -> bool) -> predecessor:Block.t -> tested_mode -> @@ -868,9 +871,12 @@ val check_validation_and_application : unit tzresult Lwt.t (** Calls {!check_validation_and_application} on all {!tested_mode}s - successively, with respective errors. *) + successively, with respective checks or errors. *) val check_validation_and_application_all_modes_different_outcomes : loc:string -> + ?check_after_application:(Block.block_with_metadata -> unit tzresult Lwt.t) -> + ?check_after_construction:(Block.block_with_metadata -> unit tzresult Lwt.t) -> + ?check_after_mempool:(Block.block_with_metadata -> unit tzresult Lwt.t) -> ?application_error:(Environment.Error_monad.error -> bool) -> ?construction_error:(Environment.Error_monad.error -> bool) -> ?mempool_error:(Environment.Error_monad.error -> bool) -> @@ -879,9 +885,11 @@ val check_validation_and_application_all_modes_different_outcomes : unit tzresult Lwt.t (** Calls {!check_validation_and_application} on all {!tested_mode}s - successively, with the same [error] provided for each mode. *) + successively, with the same [check_after] or [error] provided for + each mode. *) val check_validation_and_application_all_modes : loc:string -> + ?check_after:(Block.block_with_metadata -> unit tzresult Lwt.t) -> ?error:(Environment.Error_monad.error -> bool) -> predecessor:Block.t -> t -> -- GitLab From b930db6175fa9daf4f41ee07cf7014cc48ff419c Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Wed, 9 Jul 2025 17:38:17 +0200 Subject: [PATCH 07/11] Proto/test: some factorization --- .../integration/consensus/test_aggregate.ml | 193 ++++++++++-------- 1 file changed, 103 insertions(+), 90 deletions(-) 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 715c97262084..09713ff1fbee 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 @@ -177,6 +177,60 @@ let check_attestations_aggregate_result ~attesters Tezos_protocol_alpha__Protocol.Apply_results.contents_result) = check_aggregate_result Attestation ~attesters result +let check_after_preattestations_aggregate + ((_, (_, op_receipts)) : Block.block_with_metadata) = + check_preattestations_aggregate_result + (find_preattestations_aggregate_result op_receipts) + +let check_after_attestations_aggregate + ((_, (_, op_receipts)) : Block.block_with_metadata) = + check_attestations_aggregate_result + (find_attestations_aggregate_result op_receipts) + +(** Tests the validation and application of a preattestations_aggregate. + + Unlike {!check_attestations_aggregate_validation_and_application}, + only tests in application mode because making a context that + accepts preattestations is slightly more complicated. *) +let check_preattestations_aggregate_validation_and_application ~attesters + ~preattested_block ~preattested_block_predecessor = + let open Lwt_result_syntax in + let committee = List.map Op.attesting_slot_of_attester attesters in + let* operation = Op.preattestations_aggregate ~committee preattested_block in + let* block_with_metadata = + Block.bake_with_metadata + ~policy:(By_round 1) + ~payload_round:Alpha_context.Round.zero + ~locked_round:Alpha_context.Round.zero + ~operation + preattested_block_predecessor + in + check_after_preattestations_aggregate ~attesters block_with_metadata + +(** Tests the validation and application of an attestations_aggregate. + + In mempool mode, always expects + {!Error_helpers.aggregate_in_mempool}. In block modes, performs + {!check_attestations_aggregate_result}. *) +let check_attestations_aggregate_validation_and_application ~loc ~attesters + ~attested_block = + let open Lwt_result_syntax in + let attesting_slots = List.map Op.attesting_slot_of_attester attesters in + let committee = + (* It would be nice to test with various DAL contents, but this + would require setting up delegates with companion keys. *) + List.map (fun attesting_slot -> (attesting_slot, None)) attesting_slots + in + let* operation = Op.attestations_aggregate ~committee attested_block in + let check_after_block_mode = check_after_attestations_aggregate ~attesters in + Op.check_validation_and_application_all_modes_different_outcomes + ~loc + ~check_after_application:check_after_block_mode + ~check_after_construction:check_after_block_mode + ~mempool_error:Error_helpers.aggregate_in_mempool + ~predecessor:attested_block + operation + let test_aggregate_feature_flag_enabled () = let open Lwt_result_syntax in let* _genesis, attested_block = @@ -207,95 +261,62 @@ let test_attestations_aggregate_with_a_single_delegate () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* attester = Context.get_attester_with_bls_key (B attested_block) in - let attesting_slot = Op.attesting_slot_of_attester attester in - let* operation = - Op.attestations_aggregate ~committee:[(attesting_slot, None)] attested_block - in - let* _, (_, receipt) = Block.bake_with_metadata ~operation attested_block in - let result = find_attestations_aggregate_result receipt in - check_attestations_aggregate_result ~attesters:[attester] result + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters:[attester] + ~attested_block let test_preattestations_aggregate_with_a_single_delegate () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, preattested_block_predecessor = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* block' = Block.bake block in - let* attester = Context.get_attester_with_bls_key (B block') in - let attesting_slot = Op.attesting_slot_of_attester attester in - let* operation = - Op.preattestations_aggregate ~committee:[attesting_slot] block' - in - let* _, (_, receipt) = - let round_zero = Alpha_context.Round.zero in - Block.bake_with_metadata - ~policy:(By_round 1) - ~payload_round:round_zero - ~locked_round:round_zero - ~operation - block - in - let result = find_preattestations_aggregate_result receipt in - check_preattestations_aggregate_result ~attesters:[attester] result + let* preattested_block = Block.bake preattested_block_predecessor in + let* attester = Context.get_attester_with_bls_key (B preattested_block) in + check_preattestations_aggregate_validation_and_application + ~attesters:[attester] + ~preattested_block + ~preattested_block_predecessor let test_attestations_aggregate_with_multiple_delegates () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters_with_bls_key (B block) in - let committee = - List.map - (fun attester -> (Op.attesting_slot_of_attester attester, None)) - attesters - in - let* operation = Op.attestations_aggregate ~committee block in - let* _, (_, receipt) = Block.bake_with_metadata ~operation block in - let result = find_attestations_aggregate_result receipt in - check_attestations_aggregate_result ~attesters result + let* attesters = Context.get_attesters_with_bls_key (B attested_block) in + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attested_block let test_preattestations_aggregate_with_multiple_delegates () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, preattested_block_predecessor = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* block' = Block.bake block in - let* attesters = Context.get_attesters_with_bls_key (B block') in - let committee = List.map Op.attesting_slot_of_attester attesters in - let* operation = Op.preattestations_aggregate ~committee block' in - let* _, (_, receipt) = - let round_zero = Alpha_context.Round.zero in - Block.bake_with_metadata - ~policy:(By_round 1) - ~payload_round:round_zero - ~locked_round:round_zero - ~operation - block - in - let result = find_preattestations_aggregate_result receipt in - check_preattestations_aggregate_result ~attesters result + let* preattested_block = Block.bake preattested_block_predecessor in + let* attesters = Context.get_attesters_with_bls_key (B preattested_block) in + check_preattestations_aggregate_validation_and_application + ~attesters + ~preattested_block + ~preattested_block_predecessor let test_attestations_aggregate_invalid_signature () = let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* aggregate = Op.attestations_aggregate block in - (* Swap the signature for Signature.Bls.zero *) - match aggregate.protocol_data with - | Operation_data {contents; _} -> - let aggregate_with_incorrect_signature = - { - aggregate with - protocol_data = - Operation_data {contents; signature = Some (Bls Signature.Bls.zero)}; - } - in - (* Bake a block containing this operation and expect an error *) - let*! res = - Block.bake ~operation:aggregate_with_incorrect_signature block - in - Assert.proto_error ~loc:__LOC__ res Error_helpers.invalid_signature + let* op = Op.attestations_aggregate block in + let op_with_signature_zero = + Op.set_op_signature op (Some (Bls Signature.Bls.zero)) + in + Op.check_validation_and_application_all_modes_different_outcomes + ~loc:__LOC__ + ~application_error:Error_helpers.invalid_signature + ~construction_error:Error_helpers.invalid_signature + ~mempool_error:Error_helpers.aggregate_in_mempool + ~predecessor:block + op_with_signature_zero let test_preattestations_aggregate_invalid_signature () = let open Lwt_result_syntax in @@ -303,28 +324,20 @@ let test_preattestations_aggregate_invalid_signature () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* block' = Block.bake block in - let* aggregate = Op.preattestations_aggregate block' in - (* Swap the aggregate signature for Signature.Bls.zero *) - match aggregate.protocol_data with - | Operation_data {contents; _} -> - let aggregate_with_incorrect_signature = - { - aggregate with - protocol_data = - Operation_data {contents; signature = Some (Bls Signature.Bls.zero)}; - } - in - (* Bake a block containing this operation and expect an error *) - let*! res = - let round_zero = Alpha_context.Round.zero in - Block.bake - ~policy:(By_round 1) - ~payload_round:round_zero - ~locked_round:round_zero - ~operation:aggregate_with_incorrect_signature - block - in - Assert.proto_error ~loc:__LOC__ res Error_helpers.invalid_signature + let* op = Op.preattestations_aggregate block' in + let op_with_signature_zero = + Op.set_op_signature op (Some (Bls Signature.Bls.zero)) + in + let*! res = + let round_zero = Alpha_context.Round.zero in + Block.bake + ~policy:(By_round 1) + ~payload_round:round_zero + ~locked_round:round_zero + ~operation:op_with_signature_zero + block + in + Assert.proto_error ~loc:__LOC__ res Error_helpers.invalid_signature let test_preattestations_aggregate_non_bls_delegate () = let open Lwt_result_syntax in -- GitLab From 06127bdb04c12e126ef70f11416b5977f4db7ee5 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Wed, 9 Jul 2025 18:51:09 +0200 Subject: [PATCH 08/11] Proto/test: feature flag tests also on preattestations --- .../integration/consensus/test_aggregate.ml | 89 ++++++++++++++----- 1 file changed, 67 insertions(+), 22 deletions(-) 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 09713ff1fbee..e5f3c43ca225 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 @@ -189,15 +189,20 @@ let check_after_attestations_aggregate (** Tests the validation and application of a preattestations_aggregate. + When [error] is [None], performs + {!check_preattestations_aggregate_result} on the operation's + metadata, otherwise checks that the error identified by [error] is + returned. + Unlike {!check_attestations_aggregate_validation_and_application}, only tests in application mode because making a context that accepts preattestations is slightly more complicated. *) -let check_preattestations_aggregate_validation_and_application ~attesters - ~preattested_block ~preattested_block_predecessor = +let check_preattestations_aggregate_validation_and_application ~loc ~attesters + ~preattested_block ~preattested_block_predecessor ?error () = let open Lwt_result_syntax in let committee = List.map Op.attesting_slot_of_attester attesters in let* operation = Op.preattestations_aggregate ~committee preattested_block in - let* block_with_metadata = + let*! res = Block.bake_with_metadata ~policy:(By_round 1) ~payload_round:Alpha_context.Round.zero @@ -205,15 +210,23 @@ let check_preattestations_aggregate_validation_and_application ~attesters ~operation preattested_block_predecessor in - check_after_preattestations_aggregate ~attesters block_with_metadata + match error with + | None -> + let*? block_with_metadata = res in + check_after_preattestations_aggregate ~attesters block_with_metadata + | Some error -> Assert.proto_error ~loc res error (** Tests the validation and application of an attestations_aggregate. In mempool mode, always expects - {!Error_helpers.aggregate_in_mempool}. In block modes, performs - {!check_attestations_aggregate_result}. *) + {!Error_helpers.aggregate_in_mempool}. + + In block modes: when [error] is [None], performs + {!check_attestations_aggregate_result} on the operation's + metadata, otherwise checks that the error identified by [error] is + returned. *) let check_attestations_aggregate_validation_and_application ~loc ~attesters - ~attested_block = + ~attested_block ?error () = let open Lwt_result_syntax in let attesting_slots = List.map Op.attesting_slot_of_attester attesters in let committee = @@ -222,38 +235,64 @@ let check_attestations_aggregate_validation_and_application ~loc ~attesters List.map (fun attesting_slot -> (attesting_slot, None)) attesting_slots in let* operation = Op.attestations_aggregate ~committee attested_block in - let check_after_block_mode = check_after_attestations_aggregate ~attesters in + let check_after_block_mode = + match error with + | None -> Some (check_after_attestations_aggregate ~attesters) + | Some _ -> None + in Op.check_validation_and_application_all_modes_different_outcomes ~loc - ~check_after_application:check_after_block_mode - ~check_after_construction:check_after_block_mode + ?check_after_application:check_after_block_mode + ?check_after_construction:check_after_block_mode + ?application_error:error + ?construction_error:error ~mempool_error:Error_helpers.aggregate_in_mempool ~predecessor:attested_block operation let test_aggregate_feature_flag_enabled () = let open Lwt_result_syntax in - let* _genesis, attested_block = + let* _genesis, b1 = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - Consensus_helpers.test_consensus_operation_all_modes_different_outcomes + let* b2 = Block.bake b1 in + let* attesters = Context.get_attesters_with_bls_key (B b2) in + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~preattested_block:b2 + ~preattested_block_predecessor:b1 + () + in + check_attestations_aggregate_validation_and_application ~loc:__LOC__ - ~attested_block - ~mempool_error:Error_helpers.aggregate_in_mempool - Aggregate + ~attesters + ~attested_block:b2 + () let test_aggregate_feature_flag_disabled () = let open Lwt_result_syntax in - let* _genesis, attested_block = + let* _genesis, b1 = init_genesis_with_some_bls_accounts ~aggregate_attestation:false () in - Consensus_helpers.test_consensus_operation_all_modes_different_outcomes + let* b2 = Block.bake b1 in + let* attesters = Context.get_attesters_with_bls_key (B b2) in + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~preattested_block:b2 + ~preattested_block_predecessor:b1 + ~error:Error_helpers.aggregate_disabled + () + in + check_attestations_aggregate_validation_and_application ~loc:__LOC__ - ~attested_block - ~application_error:Error_helpers.aggregate_disabled - ~construction_error:Error_helpers.aggregate_disabled - ~mempool_error:Error_helpers.aggregate_in_mempool - Aggregate + ~attesters + ~attested_block:b2 + ~error:Error_helpers.aggregate_disabled + () let test_attestations_aggregate_with_a_single_delegate () = let open Lwt_result_syntax in @@ -265,6 +304,7 @@ let test_attestations_aggregate_with_a_single_delegate () = ~loc:__LOC__ ~attesters:[attester] ~attested_block + () let test_preattestations_aggregate_with_a_single_delegate () = let open Lwt_result_syntax in @@ -274,9 +314,11 @@ let test_preattestations_aggregate_with_a_single_delegate () = let* preattested_block = Block.bake preattested_block_predecessor in let* attester = Context.get_attester_with_bls_key (B preattested_block) in check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ ~attesters:[attester] ~preattested_block ~preattested_block_predecessor + () let test_attestations_aggregate_with_multiple_delegates () = let open Lwt_result_syntax in @@ -288,6 +330,7 @@ let test_attestations_aggregate_with_multiple_delegates () = ~loc:__LOC__ ~attesters ~attested_block + () let test_preattestations_aggregate_with_multiple_delegates () = let open Lwt_result_syntax in @@ -297,9 +340,11 @@ let test_preattestations_aggregate_with_multiple_delegates () = let* preattested_block = Block.bake preattested_block_predecessor in let* attesters = Context.get_attesters_with_bls_key (B preattested_block) in check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ ~attesters ~preattested_block ~preattested_block_predecessor + () let test_attestations_aggregate_invalid_signature () = let open Lwt_result_syntax in -- GitLab From e55e5df4f3e82290e43fabc983d5ca03ce8b29bd Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Wed, 9 Jul 2025 19:15:05 +0200 Subject: [PATCH 09/11] Proto/test: add new slot-related tests --- .../test/helpers/error_helpers.ml | 12 ++ .../integration/consensus/test_aggregate.ml | 181 +++++++++++++++++- 2 files changed, 189 insertions(+), 4 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml index 7eb0b079591f..c0fcd2001c29 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml @@ -216,3 +216,15 @@ let unaggregated_eligible_attestation ?kind = function let empty_aggregation_committee = function | Validate_errors.Consensus.Empty_aggregation_committee -> true | _ -> false + +let wrong_slot_used_for_preattestation = function + | Validate_errors.Consensus.Wrong_slot_used_for_consensus_operation + {kind = Preattestation} -> + true + | _ -> false + +let wrong_slot_used_for_attestation = function + | Validate_errors.Consensus.Wrong_slot_used_for_consensus_operation + {kind = Attestation} -> + true + | _ -> false 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 e5f3c43ca225..acaee5de49c8 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 @@ -189,6 +189,9 @@ let check_after_attestations_aggregate (** Tests the validation and application of a preattestations_aggregate. + [attesting_slots] defaults to the respective canonical slots of + [attesters]. + When [error] is [None], performs {!check_preattestations_aggregate_result} on the operation's metadata, otherwise checks that the error identified by [error] is @@ -198,9 +201,14 @@ let check_after_attestations_aggregate only tests in application mode because making a context that accepts preattestations is slightly more complicated. *) let check_preattestations_aggregate_validation_and_application ~loc ~attesters - ~preattested_block ~preattested_block_predecessor ?error () = + ?attesting_slots ~preattested_block ~preattested_block_predecessor ?error () + = let open Lwt_result_syntax in - let committee = List.map Op.attesting_slot_of_attester attesters in + let committee = + match attesting_slots with + | Some v -> v + | None -> List.map Op.attesting_slot_of_attester attesters + in let* operation = Op.preattestations_aggregate ~committee preattested_block in let*! res = Block.bake_with_metadata @@ -218,6 +226,9 @@ let check_preattestations_aggregate_validation_and_application ~loc ~attesters (** Tests the validation and application of an attestations_aggregate. + [attesting_slots] defaults to the respective canonical slots of + [attesters]. + In mempool mode, always expects {!Error_helpers.aggregate_in_mempool}. @@ -226,9 +237,13 @@ let check_preattestations_aggregate_validation_and_application ~loc ~attesters metadata, otherwise checks that the error identified by [error] is returned. *) let check_attestations_aggregate_validation_and_application ~loc ~attesters - ~attested_block ?error () = + ?attesting_slots ~attested_block ?error () = let open Lwt_result_syntax in - let attesting_slots = List.map Op.attesting_slot_of_attester attesters in + let attesting_slots = + match attesting_slots with + | Some v -> v + | None -> List.map Op.attesting_slot_of_attester attesters + in let committee = (* It would be nice to test with various DAL contents, but this would require setting up delegates with companion keys. *) @@ -346,6 +361,161 @@ let test_preattestations_aggregate_with_multiple_delegates () = ~preattested_block_predecessor () +(* Preattestations/atttestations aggregate where one of the slots is + not the first slot of its delegate (but still belongs to the + delegate). *) +let test_non_canonical_slot () = + let open Lwt_result_syntax in + let* _genesis, attested_block_predecessor = + init_genesis_with_some_bls_accounts ~aggregate_attestation:true () + in + let* attested_block = Block.bake attested_block_predecessor in + let* attesters = Context.get_attesters_with_bls_key (B attested_block) in + let attester, other_attester = + match attesters with + | x1 :: x2 :: _ -> (x1, x2) + | _ -> Test.fail ~__LOC__ "Expected at least two attesters with BLS key" + in + let non_canonical_attesting_slot = + Op.non_canonical_attesting_slot_of_attester attester + in + let other_attesters_canonical_slot = + Op.attesting_slot_of_attester other_attester + in + let attesters_and_slots_to_test = + [ + (* Problematic slot alone *) + ([attester], [non_canonical_attesting_slot]); + (* Problematic slot first then normal slot *) + ( [attester; other_attester], + [non_canonical_attesting_slot; other_attesters_canonical_slot] ); + (* Problematic slot last *) + ( [other_attester; attester], + [other_attesters_canonical_slot; non_canonical_attesting_slot] ); + ] + in + List.iter_es + (fun (attesters, attesting_slots) -> + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attesting_slots + ~preattested_block:attested_block + ~preattested_block_predecessor:attested_block_predecessor + ~error:Error_helpers.wrong_slot_used_for_preattestation + () + in + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attesting_slots + ~attested_block + ~error:Error_helpers.wrong_slot_used_for_attestation + ()) + attesters_and_slots_to_test + +(* Preattestations/atttestations aggregate where a delegate uses a + slot that does not belong to it. *) +let test_not_owned_slot () = + let open Lwt_result_syntax in + let* _genesis, attested_block_predecessor = + init_genesis_with_some_bls_accounts ~aggregate_attestation:true () + in + let* attested_block = Block.bake attested_block_predecessor in + let* attesters = Context.get_attesters_with_bls_key (B attested_block) in + let attester, other_attester, third_attester = + match attesters with + | x1 :: x2 :: x3 :: _ -> (x1, x2, x3) + | _ -> Test.fail ~__LOC__ "Expected at least three attesters with BLS key" + in + let wrong_attesting_slot = + { + Op.consensus_pkh = attester.consensus_key; + slot = + WithExceptions.Option.get ~loc:__LOC__ (List.hd third_attester.slots); + } + in + let other_attesters_canonical_slot = + Op.attesting_slot_of_attester other_attester + in + let attesters_and_slots_to_test = + [ + (* Problematic slot alone *) + ([attester], [wrong_attesting_slot]); + (* Problematic slot first then normal slot *) + ( [attester; other_attester], + [wrong_attesting_slot; other_attesters_canonical_slot] ); + (* Problematic slot last *) + ( [other_attester; attester], + [other_attesters_canonical_slot; wrong_attesting_slot] ); + ] + in + List.iter_es + (fun (attesters, attesting_slots) -> + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attesting_slots + ~preattested_block:attested_block + ~preattested_block_predecessor:attested_block_predecessor + ~error:Error_helpers.invalid_signature + () + in + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attesting_slots + ~attested_block + ~error:Error_helpers.invalid_signature + ()) + attesters_and_slots_to_test + +(* Preattestations/atttestations aggregate with a duplicate slot. *) +let test_duplicate_slot () = + let open Lwt_result_syntax in + let* _genesis, attested_block_predecessor = + init_genesis_with_some_bls_accounts ~aggregate_attestation:true () + in + let* attested_block = Block.bake attested_block_predecessor in + let* attesters = Context.get_attesters_with_bls_key (B attested_block) in + let attester, other_attester = + match attesters with + | x1 :: x2 :: _ -> (x1, x2) + | _ -> Test.fail ~__LOC__ "Expected at least two attesters with BLS key" + in + let attesters_to_test = + [ + (* Only duplicate slot *) + [attester; attester]; + (* Duplicate slot first then normal slot *) + [attester; attester; other_attester]; + (* Duplicate slot last *) + [other_attester; attester; attester]; + (* Duplicate slot before and after normal slot *) + [attester; other_attester; attester]; + ] + in + List.iter_es + (fun attesters -> + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~preattested_block:attested_block + ~preattested_block_predecessor:attested_block_predecessor + ~error:Error_helpers.conflicting_consensus_operation + () + in + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attested_block + ~error:Error_helpers.conflicting_consensus_operation + ()) + attesters_to_test + let test_attestations_aggregate_invalid_signature () = let open Lwt_result_syntax in let* _genesis, block = @@ -858,6 +1028,9 @@ let tests = "test_attestations_aggregate_with_multiple_delegates" `Quick test_attestations_aggregate_with_multiple_delegates; + Tztest.tztest "KO non canonical slot" `Quick test_non_canonical_slot; + Tztest.tztest "KO not owned slot" `Quick test_not_owned_slot; + Tztest.tztest "KO duplicate slot" `Quick test_duplicate_slot; Tztest.tztest "test_preattestations_aggregate_invalid_signature" `Quick -- GitLab From 03a4480cfab3a7504feedc1d237630f7c8b9a430 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Thu, 10 Jul 2025 15:35:03 +0200 Subject: [PATCH 10/11] Proto/test: add test attestations aggregate with DAL missing companion key --- .../test/helpers/error_helpers.ml | 4 +++ .../integration/consensus/test_aggregate.ml | 26 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml index c0fcd2001c29..9dcba93712c0 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml @@ -228,3 +228,7 @@ let wrong_slot_used_for_attestation = function {kind = Attestation} -> true | _ -> false + +let missing_companion_key_for_bls_dal = function + | Validate_errors.Consensus.Missing_companion_key_for_bls_dal _ -> true + | _ -> false 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 acaee5de49c8..3cf1c161be52 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 @@ -642,6 +642,28 @@ let test_attestations_aggregate_non_bls_delegate () = in List.iter_es check_non_bls_aggregate_refused Dal_helpers.various_dal_contents +let test_attestations_aggregate_dal_without_companion_key () = + let open Lwt_result_syntax in + let* _genesis, attested_block = + init_genesis_with_some_bls_accounts ~aggregate_attestation:true () + in + let* attesting_slot = Op.get_attesting_slot_with_bls_key ~attested_block in + List.iter_es + (fun dal_content -> + let* op = + Op.attestations_aggregate + ~committee:[(attesting_slot, dal_content)] + attested_block + in + Op.check_validation_and_application_all_modes_different_outcomes + ~loc:__LOC__ + ~application_error:Error_helpers.missing_companion_key_for_bls_dal + ~construction_error:Error_helpers.missing_companion_key_for_bls_dal + ~mempool_error:Error_helpers.aggregate_in_mempool + ~predecessor:attested_block + op) + (List.filter Option.is_some Dal_helpers.various_dal_contents) + let test_multiple_aggregates_per_block_forbidden () = let open Lwt_result_syntax in let* _genesis, block = @@ -1047,6 +1069,10 @@ let tests = "test_attestations_aggregate_non_bls_delegate" `Quick test_attestations_aggregate_non_bls_delegate; + Tztest.tztest + "KO DAL without companion key" + `Quick + test_attestations_aggregate_dal_without_companion_key; Tztest.tztest "test_multiple_aggregates_per_block_forbidden" `Quick -- GitLab From 5513c9bf79b9284e3f98cfe432852248462cb8a4 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 25 Jul 2025 18:52:33 +0200 Subject: [PATCH 11/11] Seoul/Proto/test: backport !18604 --- .../lib_protocol/test/helpers/block.ml | 2 + .../lib_protocol/test/helpers/block.mli | 9 +- .../test/helpers/consensus_helpers.ml | 68 +- .../lib_protocol/test/helpers/context.ml | 52 +- .../lib_protocol/test/helpers/context.mli | 47 +- .../lib_protocol/test/helpers/dal_helpers.ml | 49 + .../lib_protocol/test/helpers/dal_helpers.mli | 27 + .../test/helpers/error_helpers.ml | 48 + .../lib_protocol/test/helpers/op.ml | 250 +++-- .../lib_protocol/test/helpers/op.mli | 176 +++- .../test/helpers/scenario_attestation.ml | 404 ++++---- .../lib_protocol/test/helpers/scenario_op.ml | 11 +- .../integration/consensus/test_aggregate.ml | 905 ++++++++++-------- .../integration/consensus/test_attestation.ml | 72 +- .../test/integration/consensus/test_baking.ml | 27 +- .../consensus/test_consensus_key.ml | 11 +- .../consensus/test_dal_entrapment.ml | 15 +- .../consensus/test_double_attestation.ml | 183 ++-- .../consensus/test_double_baking.ml | 10 +- .../consensus/test_double_preattestation.ml | 81 +- .../consensus/test_frozen_deposits.ml | 8 +- .../consensus/test_participation.ml | 24 +- .../consensus/test_preattestation.ml | 12 +- .../consensus/test_preattestation_functor.ml | 55 +- .../consensus/test_scenario_attestation.ml | 25 +- .../test/integration/consensus/test_seed.ml | 5 +- .../operations/test_origination.ml | 9 - .../validate/generator_descriptors.ml | 103 +- .../integration/validate/validate_helpers.ml | 8 - 29 files changed, 1471 insertions(+), 1225 deletions(-) diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/block.ml b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/block.ml index 8c4e11fa5710..40d26075574a 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/block.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/block.ml @@ -43,6 +43,8 @@ type block = t type full_metadata = block_header_metadata * operation_receipt list +type block_with_metadata = block * full_metadata + let get_alpha_ctxt b = let open Lwt_result_wrap_syntax in let*@ ctxt, _migration_balance_updates, _migration_operation_results = diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/block.mli b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/block.mli index f5312d01f162..1248e8632cb6 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/block.mli +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/block.mli @@ -41,6 +41,8 @@ type block = t type full_metadata = block_header_metadata * operation_receipt list +type block_with_metadata = block * full_metadata + (** Not the same as [Context.get_alpha_ctxt] as it does not construct a new block *) val get_alpha_ctxt : t -> context tzresult Lwt.t @@ -252,7 +254,7 @@ val bake_with_metadata : ?liquidity_baking_toggle_vote:Per_block_votes.per_block_vote -> ?adaptive_issuance_vote:Per_block_votes.per_block_vote -> t -> - (t * (block_header_metadata * operation_receipt list)) tzresult Lwt.t + block_with_metadata tzresult Lwt.t (** Bakes [n] blocks. *) val bake_n : @@ -324,11 +326,10 @@ val bake_n_with_metadata : ?adaptive_issuance_vote:Per_block_votes_repr.per_block_vote -> int -> block -> - (block * (block_header_metadata * operation_receipt list)) tzresult Lwt.t + block_with_metadata tzresult Lwt.t val get_balance_updates_from_metadata : - block_header_metadata * operation_receipt list -> - Alpha_context.Receipt.balance_updates + full_metadata -> Alpha_context.Receipt.balance_updates (** Bake blocks while a predicate over the block holds. The returned block is the last one for which the predicate holds; in case the diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/consensus_helpers.ml b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/consensus_helpers.ml index e4c9820d26a2..40ecfd7c0fe2 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/consensus_helpers.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/consensus_helpers.ml @@ -23,9 +23,6 @@ (* *) (*****************************************************************************) -open Protocol -open Alpha_context - type kind = Preattestation | Attestation | Aggregate (** Crafts a consensus operation. @@ -39,13 +36,12 @@ type kind = Preattestation | Attestation | Aggregate its branch is the predecessor of that block. Optional arguments allow to override these default parameters. *) -let craft_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash +let craft_consensus_operation ?attesting_slot ?level ?round ?block_payload_hash ?branch ~attested_block kind = match kind with | Preattestation -> Op.preattestation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -53,8 +49,7 @@ let craft_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash attested_block | Attestation -> Op.attestation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -68,14 +63,13 @@ let craft_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash ?branch attested_block -let test_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash +let test_consensus_operation ?attesting_slot ?level ?round ?block_payload_hash ?branch ~attested_block ?(predecessor = attested_block) ?error ~loc kind mode = let open Lwt_result_syntax in let* operation = craft_consensus_operation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -85,15 +79,14 @@ let test_consensus_operation ?delegate ?slot ?level ?round ?block_payload_hash in Op.check_validation_and_application ~loc ?error ~predecessor mode operation -let test_consensus_operation_all_modes_different_outcomes ?delegate ?slot ?level +let test_consensus_operation_all_modes_different_outcomes ?attesting_slot ?level ?round ?block_payload_hash ?branch ~attested_block ?(predecessor = attested_block) ~loc ?application_error ?construction_error ?mempool_error kind = let open Lwt_result_syntax in let* operation = craft_consensus_operation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -109,14 +102,13 @@ let test_consensus_operation_all_modes_different_outcomes ?delegate ?slot ?level ~predecessor operation -let test_consensus_operation_all_modes ?delegate ?slot ?level ?round +let test_consensus_operation_all_modes ?attesting_slot ?level ?round ?block_payload_hash ?branch ~attested_block ?(predecessor = attested_block) ?error ~loc kind = let open Lwt_result_syntax in let* operation = craft_consensus_operation - ?delegate - ?slot + ?attesting_slot ?level ?round ?block_payload_hash @@ -130,36 +122,12 @@ let test_consensus_operation_all_modes ?delegate ?slot ?level ?round ~predecessor operation -let delegate_of_first_slot b = - let open Lwt_result_syntax in - let module V = Plugin.RPC.Validators in - let+ attesters = Context.get_attesters b in - match attesters with - | {V.consensus_key; slots = s :: _; _} :: _ -> (consensus_key, s) - | _ -> assert false - -let delegate_of_slot ?(different_slot = false) slot b = - let open Lwt_result_syntax in - let module V = Plugin.RPC.Validators in - let+ attesters = Context.get_attesters b in - List.find_map - (function - | {V.consensus_key; slots = s :: _; _} - when if different_slot then not (Slot.equal s slot) - else Slot.equal s slot -> - Some consensus_key - | _ -> None) - attesters - |> function - | None -> assert false - | Some d -> d - let test_consensus_op_for_next ~genesis ~kind ~next = let open Lwt_result_syntax in - let dorsement ~attested_block ~delegate = + let consensus_op ~attested_block ~attesting_slot = match kind with - | `Preattestation -> Op.preattestation ~delegate attested_block - | `Attestation -> Op.attestation ~delegate attested_block + | `Preattestation -> Op.preattestation ~attesting_slot attested_block + | `Attestation -> Op.attestation ~attesting_slot attested_block in let* b1 = Block.bake genesis in let* b2 = @@ -168,10 +136,14 @@ let test_consensus_op_for_next ~genesis ~kind ~next = | `Round -> Block.bake ~policy:(By_round 1) genesis in let* inc = Incremental.begin_construction ~mempool_mode:true b1 in - let* delegate, slot = delegate_of_first_slot (B b1) in - let* operation = dorsement ~attested_block:b1 ~delegate in + let* attesting_slot = Op.get_attesting_slot ~attested_block:b1 in + let* operation = consensus_op ~attested_block:b1 ~attesting_slot in let* inc = Incremental.add_operation inc operation in - let* delegate = delegate_of_slot ~different_slot:true slot (B b2) in - let* operation = dorsement ~attested_block:b2 ~delegate in + let* attesting_slot = + Op.get_different_attesting_slot + ~consensus_pkh_to_avoid:attesting_slot.consensus_pkh + ~attested_block:b2 + in + let* operation = consensus_op ~attested_block:b2 ~attesting_slot in let* (_ : Incremental.t) = Incremental.add_operation inc operation in return_unit diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/context.ml b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/context.ml index c5f1b93d78bf..574929baf20d 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/context.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/context.ml @@ -135,28 +135,33 @@ let rpc_ctxt = | I bl -> Incremental.rpc_ctxt#call_proto_service3 s bl a b c q i end -let get_attesters ctxt = Plugin.RPC.Validators.get rpc_ctxt ctxt +type attester = Plugin.RPC.Validators.t = { + level : Raw_level.t; + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; + companion_key : Signature.Bls.Public_key_hash.t option; + slots : Slot.t list; +} -let get_first_different_attesters ctxt = - let open Lwt_result_syntax in - let+ attesters = get_attesters ctxt in - match attesters with x :: y :: _ -> (x, y) | _ -> assert false +let get_attesters ctxt = Plugin.RPC.Validators.get rpc_ctxt ctxt -let get_attester ctxt = +let get_attester ?manager_pkh ctxt = let open Lwt_result_syntax in - let+ attesters = get_attesters ctxt in - let attester = WithExceptions.Option.get ~loc:__LOC__ @@ List.hd attesters in - (attester.consensus_key, attester.slots) + let* attesters = get_attesters ctxt in + match manager_pkh with + | None -> return (WithExceptions.Option.get ~loc:__LOC__ (List.hd attesters)) + | Some manager_pkh -> + List.find_opt + (fun {delegate; _} -> + Signature.Public_key_hash.equal delegate manager_pkh) + attesters + |> WithExceptions.Option.get ~loc:__LOC__ + |> return -let get_attester_slot ctxt pkh = +let get_first_different_attesters ctxt = let open Lwt_result_syntax in let+ attesters = get_attesters ctxt in - List.find_map - (function - | {Plugin.RPC.Validators.consensus_key; slots; _} -> - if Signature.Public_key_hash.(consensus_key = pkh) then Some slots - else None) - attesters + match attesters with x :: y :: _ -> (x, y) | _ -> assert false let get_attester_n ctxt n = let open Lwt_result_syntax in @@ -166,6 +171,21 @@ let get_attester_n ctxt n = in (attester.consensus_key, attester.slots) +let attester_has_bls_key {consensus_key; _} = + Signature.Public_key_hash.is_bls consensus_key + +let get_attesters_with_bls_key ctxt = + let open Lwt_result_syntax in + let* attesters = get_attesters ctxt in + return (List.filter attester_has_bls_key attesters) + +let get_attester_with_bls_key ctxt = + let open Lwt_result_syntax in + let* attesters = get_attesters ctxt in + List.find_opt attester_has_bls_key attesters + |> WithExceptions.Option.get ~loc:__LOC__ + |> return + let get_attesting_power_for_delegate ctxt ?level pkh = let open Lwt_result_syntax in let levels = Option.map (fun level -> [level]) level in diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/context.mli b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/context.mli index 233758e14d2b..9140e1c1d5b3 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/context.mli +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/context.mli @@ -38,30 +38,45 @@ val pred_branch : t -> Block_hash.t val get_level : t -> Raw_level.t tzresult -(** Given a context, returns the list of attesters charactized by - the [level], the public key hash of the [delegate], its [consensus_key] - and its assigned [slots]. - see {! Plugin.RPC.Validator.t}. *) -val get_attesters : t -> Plugin.RPC.Validators.t list tzresult Lwt.t +(** A delegate's keys and attesting slots at a given level. *) +type attester = Plugin.RPC.Validators.t = { + level : Raw_level.t; + delegate : Signature.public_key_hash; + consensus_key : Signature.public_key_hash; + companion_key : Signature.Bls.Public_key_hash.t option; + slots : Slot.t list; +} + +(** Retrieves the attesting rights at the level of the given context + by calling {!Plugin.RPC.Validators.S.validators}. *) +val get_attesters : t -> attester list tzresult Lwt.t + +(** Returns an attester at the level of the given context. + + If [manager_pkh] is provided, returns the attester with this + manager key ({!field-delegate}) and fails if there is no such + attester. If [manager_pkh] is omitted, returns the first element + of the output of {!get_attesters}. *) +val get_attester : ?manager_pkh:public_key_hash -> t -> attester tzresult Lwt.t (** Return the two first elements of the list returns by [get_attesters]. *) val get_first_different_attesters : t -> (Plugin.RPC.Validators.t * Plugin.RPC.Validators.t) tzresult Lwt.t -(** Return the first element [delegate,slot] of the list returns by - [get_attesters], where [delegate] is the [consensus key] when - is set. *) -val get_attester : t -> (public_key_hash * Slot.t list) tzresult Lwt.t - -(** Given a [delegate], and a context [ctxt], if [delegate] is in - [get_attesters ctxt] returns the [slots] of [delegate] otherwise - return [None]. *) -val get_attester_slot : - t -> public_key_hash -> Slot.t list option 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 +(** Whether the {!type-attester}'s **consensus key** is a BLS key. *) +val attester_has_bls_key : attester -> bool + +(** Same as {!get_attesters} but returns only attesters with a BLS + consensus key. *) +val get_attesters_with_bls_key : t -> attester list tzresult Lwt.t + +(** Returns an attester with a BLS consensus key (the first eligible + attester returned by {!get_attesters}). *) +val get_attester_with_bls_key : t -> attester tzresult Lwt.t + (** Counts the number of attesting slots that the given delegate has in the requested level. If ommited, [level] defaults to the next level. *) diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/dal_helpers.ml b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/dal_helpers.ml index cf87061cb600..03ee524583ba 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/dal_helpers.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/dal_helpers.ml @@ -319,3 +319,52 @@ let dal_content_of_int ~loc n = (Alpha_context.Dal.Attestation.Internal_for_tests.of_z (Z.of_int n)) in Alpha_context.{attestation} + +let dal_content_of_int_list + ?(number_of_slots = Default_parameters.constants_test.dal.number_of_slots) + attested_slots = + let open Alpha_context in + let dal_attestation = + List.fold_left + (fun dal_attestation slot -> + match Dal.Slot_index.of_int ~number_of_slots slot with + | Ok slot_index -> Dal.Attestation.commit dal_attestation slot_index + | Error err -> + Test.fail ~__LOC__ "%a" Environment.Error_monad.pp_trace err) + Dal.Attestation.empty + attested_slots + in + {attestation = dal_attestation} + +let various_dal_contents = + let number_of_slots = Default_parameters.constants_test.dal.number_of_slots in + None + :: List.map + (fun l -> Some (dal_content_of_int_list ~number_of_slots l)) + [[]; [0]; [1; 3]; Misc.(0 --> (number_of_slots - 1))] + +(* Associates each committee member with an element of + dal_content_list in order, going back to the beginning of + dal_content_list if dal_content_list is shorter. In other words, + the member at position i in committee receives the dal_content in + dal_content_list at position (i modulo (length of + dal_content_list)). *) +let committee_with_cycling_dal_contents + (dal_content_list : Alpha_context.dal_content option list) + (committee : 'a list) : ('a * Alpha_context.dal_content option) list = + let rec aux acc remaining_dal_contents_to_pick committee = + match (committee, remaining_dal_contents_to_pick) with + | [], _ -> List.rev acc + | _, [] -> + (* We have gone through the whole dal_content_list and there + are still committee members waiting to receive a dal + content: reset remaining_dal_contents_to_pick to + dal_content_list. *) + aux acc dal_content_list committee + | member :: rest_committee, dal :: rest_dal -> + aux ((member, dal) :: acc) rest_dal rest_committee + in + aux [] dal_content_list committee + +let committee_with_various_dal_contents committee = + committee_with_cycling_dal_contents various_dal_contents committee diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/dal_helpers.mli b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/dal_helpers.mli index c3373f3c3a04..286de68b6c8f 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/dal_helpers.mli +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/dal_helpers.mli @@ -205,3 +205,30 @@ end Raises an exception when the given argument is negative. *) val dal_content_of_int : loc:string -> int -> Alpha_context.dal_content + +(** Builds a {!Alpha_context.type-dal_content} from a list of attested + slots. + + @param [number_of_slots] defaults to + {!Default_parameters.constants_test.dal.number_of_slots}. + + Fails when any of the attested slots is negative or greater than + or equal to [number_of_slots]. *) +val dal_content_of_int_list : + ?number_of_slots:int -> int list -> Alpha_context.dal_content + +(** A list of varied dal_content options, for tests where we want to + build attestations with different dal contents. *) +val various_dal_contents : Alpha_context.dal_content option list + +(** Transform a list of committee members into a list of [(member, + dal)] where [dal] is picked successively from + {!various_dal_contents} (going back to the beginning of + {!various_dal_contents} if it is shorter than the provided + committee. + + Depending on when this function is called, ['a] may be e.g. the + {!Signature.public_key_hash} of delegates or their consensus key, + or {!Op.attesting_slot}. *) +val committee_with_various_dal_contents : + 'a list -> ('a * Alpha_context.dal_content option) list diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/error_helpers.ml b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/error_helpers.ml index 2625057541b6..9dcba93712c0 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/error_helpers.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/error_helpers.ml @@ -184,3 +184,51 @@ let expect_missing_bls_proof ~loc ~kind_pk ~pk ~source_pkh errs = && Signature.Public_key.(err_pk = pk) && Signature.Public_key_hash.(err_source = source_pkh) | _ -> false) + +let invalid_signature = function + | Operation_repr.Invalid_signature -> true + | _ -> false + +let conflicting_consensus_operation ?kind = function + | Validate_errors.Consensus.Conflicting_consensus_operation {kind = kind'; _} + -> + Option.fold ~none:true ~some:(fun kind -> kind = kind') kind + | _ -> false + +let aggregate_disabled = function + | Validate_errors.Consensus.Aggregate_disabled -> true + | _ -> false + +let aggregate_in_mempool = function + | Validate_errors.Consensus.Aggregate_in_mempool -> true + | _ -> false + +let non_bls_key_in_aggregate = function + | Validate_errors.Consensus.Non_bls_key_in_aggregate -> true + | _ -> false + +let unaggregated_eligible_attestation ?kind = function + | Validate_errors.Consensus.Unaggregated_eligible_operation {kind = kind'; _} + -> + Option.fold ~none:true ~some:(fun kind -> kind = kind') kind + | _ -> false + +let empty_aggregation_committee = function + | Validate_errors.Consensus.Empty_aggregation_committee -> true + | _ -> false + +let wrong_slot_used_for_preattestation = function + | Validate_errors.Consensus.Wrong_slot_used_for_consensus_operation + {kind = Preattestation} -> + true + | _ -> false + +let wrong_slot_used_for_attestation = function + | Validate_errors.Consensus.Wrong_slot_used_for_consensus_operation + {kind = Attestation} -> + true + | _ -> false + +let missing_companion_key_for_bls_dal = function + | Validate_errors.Consensus.Missing_companion_key_for_bls_dal _ -> true + | _ -> false diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/op.ml b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/op.ml index aac02aafdb4d..b1708cde8ade 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/op.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/op.ml @@ -80,30 +80,93 @@ let mk_block_payload_hash (b : Block.t) = ~payload_round hashes -let mk_consensus_content_signer_and_branch ?delegate ?slot ?level ?round - ?block_payload_hash ?branch attested_block = +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 get_attesting_slot ~attested_block = + let open Lwt_result_syntax in + let* attester = Context.get_attester (B attested_block) in + return (attesting_slot_of_attester attester) + +let get_attesting_slot_of_delegate ~manager_pkh ~attested_block = + let open Lwt_result_syntax in + let* attester = Context.get_attester ~manager_pkh (B attested_block) in + return (attesting_slot_of_attester attester) + +let get_different_attesting_slot ~consensus_pkh_to_avoid ~attested_block = + let open Lwt_result_syntax in + let* attesters = Context.get_attesters (B attested_block) in + let attester = + List.find_opt + (fun {Plugin.RPC.Validators.consensus_key; _} -> + not + (Signature.Public_key_hash.equal consensus_key consensus_pkh_to_avoid)) + attesters + |> WithExceptions.Option.get ~loc:__LOC__ + 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 + | _ -> Test.fail ~__LOC__ "Expected attester to have at least two slots" + in + {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) + +let default_committee ~attested_block = + let open Lwt_result_syntax in + let* attesters_with_bls_key = + Context.get_attesters_with_bls_key (B attested_block) + in + return (List.map attesting_slot_of_attester attesters_with_bls_key) + +let get_attesting_slot_with_bls_key ~attested_block = + let open Lwt_result_syntax in + let* attester = Context.get_attester_with_bls_key (B attested_block) in + return (attesting_slot_of_attester attester) + +let get_attesting_slot_with_non_bls_key ~attested_block = + let open Lwt_result_syntax in + let* attesters = Context.get_attesters (B attested_block) in + let attester = + List.find_opt + (fun attester -> not (Context.attester_has_bls_key attester)) + attesters + |> WithExceptions.Option.get ~loc:__LOC__ + in + return (attesting_slot_of_attester attester) + +let attesting_slot_of_delegate_rights + {RPC.Attestation_rights.consensus_key; first_slot; _} = + {slot = first_slot; consensus_pkh = consensus_key} + +let mk_consensus_content_signer_and_branch ?attesting_slot ?manager_pkh ?level + ?round ?block_payload_hash ?branch attested_block = let open Lwt_result_wrap_syntax in let branch = match branch with | None -> attested_block.Block.header.shell.predecessor | Some branch -> branch in - let* delegate_pkh, slots = - match delegate with - | None -> Context.get_attester (B attested_block) - | Some del -> ( - let* slots = Context.get_attester_slot (B attested_block) del in - match slots with - | None -> return (del, []) - | Some slots -> return (del, slots)) - in - let* slot = - match slot with - | None -> ( - match List.hd slots with - | Some s -> return s - | None -> tzfail (Block.No_slots_found_for delegate_pkh)) - | Some slot -> return slot + let* {slot; consensus_pkh} = + match (attesting_slot, manager_pkh) with + | Some attesting_slot, None -> return attesting_slot + | None, None -> get_attesting_slot ~attested_block + | None, Some manager_pkh -> + get_attesting_slot_of_delegate ~manager_pkh ~attested_block + | Some _, Some _ -> + Test.fail + ~__LOC__ + "Cannot provide both ~attesting_slot and ~manager_pkh" in let* level = match level with @@ -125,16 +188,16 @@ let mk_consensus_content_signer_and_branch ?delegate ?slot ?level ?round | Some block_payload_hash -> block_payload_hash in let consensus_content = {slot; level; round; block_payload_hash} in - let* signer = Account.find delegate_pkh in + let* signer = Account.find consensus_pkh in return (consensus_content, signer.sk, branch) -let raw_attestation ?delegate ?slot ?level ?round ?block_payload_hash - ?dal_content ?branch attested_block = +let raw_attestation ?attesting_slot ?manager_pkh ?level ?round + ?block_payload_hash ?dal_content ?branch attested_block = let open Lwt_result_syntax in let* consensus_content, signer, branch = mk_consensus_content_signer_and_branch - ?delegate - ?slot + ?attesting_slot + ?manager_pkh ?level ?round ?block_payload_hash @@ -156,7 +219,7 @@ let raw_aggregate attestations = match (contents, signature) with | ( Single (Attestation {consensus_content; dal_content}), Some (Bls bls_sig) ) -> ( - let {slot; _} = consensus_content in + let ({slot; _} : consensus_content) = consensus_content in match acc with | Some (shell, proposal, slots, signatures) -> Some @@ -186,16 +249,13 @@ let raw_aggregate attestations = let protocol_data = {contents; signature = Some (Bls signature)} in ({shell; protocol_data} : Kind.attestations_aggregate operation) -let aggregate attestations = - Option.map Operation.pack (raw_aggregate attestations) - let raw_aggregate_preattestations preattestations = let aggregate_content = List.fold_left (fun acc ({shell; protocol_data = {contents; signature}} : _ Operation.t) -> match (contents, signature) with | Single (Preattestation consensus_content), Some (Bls bls_sig) -> ( - let {slot; _} = consensus_content in + let ({slot; _} : consensus_content) = consensus_content in match acc with | Some (shell, proposal, slots, signatures) -> Some (shell, proposal, slot :: slots, bls_sig :: signatures) @@ -221,16 +281,13 @@ let raw_aggregate_preattestations preattestations = let protocol_data = {contents; signature = Some (Bls signature)} in ({shell; protocol_data} : Kind.preattestations_aggregate operation) -let aggregate_preattestations preattestations = - Option.map Operation.pack (raw_aggregate_preattestations preattestations) - -let attestation ?delegate ?slot ?level ?round ?block_payload_hash ?dal_content - ?branch attested_block = +let attestation ?attesting_slot ?manager_pkh ?level ?round ?block_payload_hash + ?dal_content ?branch attested_block = let open Lwt_result_syntax in let* op = raw_attestation - ?delegate - ?slot + ?attesting_slot + ?manager_pkh ?level ?round ?block_payload_hash @@ -240,27 +297,25 @@ let attestation ?delegate ?slot ?level ?round ?block_payload_hash ?dal_content in return (Operation.pack op) -let attestations_aggregate ?committee ?level ?round ?block_payload_hash ?branch - attested_block = +let raw_attestations_aggregate ?committee ?level ?round ?block_payload_hash + ?branch attested_block = let open Lwt_result_syntax in let* committee = match committee with | Some committee -> return committee | None -> - let* attesters = Context.get_attesters (B attested_block) in + let* attesting_slots = default_committee ~attested_block in return - @@ List.filter_map - (fun attester -> - match attester.Plugin.RPC.Validators.consensus_key with - | Bls _ -> Some attester.delegate - | _ -> None) - attesters + (List.map + (fun attesting_slot -> (attesting_slot, None)) + attesting_slots) in let* attestations = List.map_es - (fun delegate -> + (fun (attesting_slot, dal_content) -> raw_attestation - ~delegate + ~attesting_slot + ?dal_content ?level ?round ?block_payload_hash @@ -268,17 +323,31 @@ let attestations_aggregate ?committee ?level ?round ?block_payload_hash ?branch attested_block) committee in - match aggregate attestations with + match raw_aggregate attestations with | Some aggregate_attestation -> return aggregate_attestation | None -> failwith "no Bls delegate found" -let raw_preattestation ?delegate ?slot ?level ?round ?block_payload_hash ?branch +let attestations_aggregate ?committee ?level ?round ?block_payload_hash ?branch attested_block = let open Lwt_result_syntax in + let* op = + raw_attestations_aggregate + ?committee + ?level + ?round + ?block_payload_hash + ?branch + attested_block + in + return (Operation.pack op) + +let raw_preattestation ?attesting_slot ?manager_pkh ?level ?round + ?block_payload_hash ?branch attested_block = + let open Lwt_result_syntax in let* consensus_content, signer, branch = mk_consensus_content_signer_and_branch - ?delegate - ?slot + ?attesting_slot + ?manager_pkh ?level ?round ?block_payload_hash @@ -293,13 +362,13 @@ let raw_preattestation ?delegate ?slot ?level ?round ?block_payload_hash ?branch branch contents -let preattestation ?delegate ?slot ?level ?round ?block_payload_hash ?branch - attested_block = +let preattestation ?attesting_slot ?manager_pkh ?level ?round + ?block_payload_hash ?branch attested_block = let open Lwt_result_syntax in let* op = raw_preattestation - ?delegate - ?slot + ?attesting_slot + ?manager_pkh ?level ?round ?block_payload_hash @@ -314,21 +383,13 @@ let raw_preattestations_aggregate ?committee ?level ?round ?block_payload_hash let* committee = match committee with | Some committee -> return committee - | None -> - let* attesters = Context.get_attesters (B attested_block) in - return - @@ List.filter_map - (fun attester -> - match attester.Plugin.RPC.Validators.consensus_key with - | Bls _ -> Some attester.delegate - | _ -> None) - attesters + | None -> default_committee ~attested_block in let* preattestations = List.map_es - (fun delegate -> + (fun attesting_slot -> raw_preattestation - ~delegate + ~attesting_slot ?level ?round ?block_payload_hash @@ -1338,58 +1399,79 @@ let show_mode = function | Construction -> "Construction" | Mempool -> "Mempool" -let check_validation_and_application ~loc ?error ~predecessor mode operation = +let check_validation_and_application ~loc ?check_after ?error ~predecessor mode + operation = let open Lwt_result_syntax in - let check_error res = - match error with - | Some error -> Assert.proto_error ~loc res error - | None -> + let check_res res = + match (check_after, error) with + | None, None -> (* assert success *) - let*? (_ : Block.t) = res in + let*? (_ : Block.block_with_metadata) = res in return_unit + | Some check_after, None -> + let*? block_with_metadata = res in + check_after block_with_metadata + | None, Some error -> Assert.proto_error ~loc res error + | Some _, Some _ -> + Test.fail + "Op.check_validation_and_application: cannot provide both \ + [check_after] and [error] (called from: %s)" + loc in match mode with | Application -> let*! result = - Block.bake ~baking_mode:Application ~operation predecessor + Block.bake_with_metadata ~baking_mode:Application ~operation predecessor in - check_error result + check_res result | Construction -> - let*! result = Block.bake ~baking_mode:Baking ~operation predecessor in - check_error result + let*! result = + Block.bake_with_metadata ~baking_mode:Baking ~operation predecessor + in + check_res result | Mempool -> let*! res = let* inc = Incremental.begin_construction ~mempool_mode:true predecessor in - let* inc = Incremental.add_operation inc operation in + let* inc, op_receipt = + Incremental.add_operation_with_metadata inc operation + in (* Finalization doesn't do much in mempool mode, but some RPCs still call it, so we check that it doesn't fail unexpectedly. *) - Incremental.finalize_block inc + let* block, header_metadata = + Incremental.finalize_block_with_metadata inc + in + return (block, (header_metadata, [op_receipt])) in - check_error res + check_res res let check_validation_and_application_all_modes_different_outcomes ~loc + ?check_after_application ?check_after_construction ?check_after_mempool ?application_error ?construction_error ?mempool_error ~predecessor operation = List.iter_es - (fun (mode, error) -> + (fun (mode, check_after, error) -> check_validation_and_application ~loc:(Format.sprintf "%s (%s mode)" loc (show_mode mode)) + ?check_after ?error ~predecessor mode operation) [ - (Application, application_error); - (Construction, construction_error); - (Mempool, mempool_error); + (Application, check_after_application, application_error); + (Construction, check_after_construction, construction_error); + (Mempool, check_after_mempool, mempool_error); ] -let check_validation_and_application_all_modes ~loc ?error ~predecessor - operation = +let check_validation_and_application_all_modes ~loc ?check_after ?error + ~predecessor operation = check_validation_and_application_all_modes_different_outcomes ~loc + ?check_after_application:check_after + ?check_after_construction:check_after + ?check_after_mempool:check_after ?application_error:error ?construction_error:error ?mempool_error:error diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/op.mli b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/op.mli index 69816f16141f..14c043b9f3eb 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/op.mli +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/op.mli @@ -58,19 +58,89 @@ val sign : val create_proof : Signature.secret_key -> Signature.Bls.t option +(** Information needed on the author of a (pre)attestation: slot + (written into the (pre)attestation) and consensus key (required + for signing). *) +type attesting_slot = {slot : Slot.t; consensus_pkh : public_key_hash} + +(** Builds an {!attesting_slot} with the attester's consensus key and + canonical slot, that is, its first slot. *) +val attesting_slot_of_attester : Context.attester -> attesting_slot + +(** Returns the canonical {!attesting_slot} of the first attester + returned by {!Plugin.RPC.Validators.S.validators}. *) +val get_attesting_slot : attested_block:Block.t -> attesting_slot tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} of delegate [manager_pkh] + for [attested_block]. Fails if it doesn't have any attesting + rights for this block. *) +val get_attesting_slot_of_delegate : + manager_pkh:public_key_hash -> + attested_block:Block.t -> + attesting_slot tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} of the first attester + returned by {!Plugin.RPC.Validators.S.validators} whose consensus + key is different from [consensus_pkh_to_avoid]. *) +val get_different_attesting_slot : + consensus_pkh_to_avoid:public_key_hash -> + attested_block:Block.t -> + attesting_slot tzresult Lwt.t + +(** Builds an {!attesting_slot} with the attester's consensus key and + 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 + +(** Retrieves the first attester returned by + {!Plugin.RPC.Validators.S.validators} and builds a non-canonical + {!attesting_slot} for it, where {!field-slot} is its + second-smallest slot. *) +val get_non_canonical_attesting_slot : + attested_block:Block.t -> attesting_slot tzresult Lwt.t + +(** Default committee for a (pre)attestations aggregate, that is, the + canonical attesting slots of all delegates with attesting rights + on [attested_block] whose consensus keys are BLS keys. *) +val default_committee : + attested_block:Block.t -> attesting_slot list tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} of the first attester + returned by {!Plugin.RPC.Validators.S.validators} whose consensus + key is a BLS key. *) +val get_attesting_slot_with_bls_key : + attested_block:Block.t -> attesting_slot tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} of the first attester + returned by {!Plugin.RPC.Validators.S.validators} whose consensus + key is a non-BLS key. *) +val get_attesting_slot_with_non_bls_key : + attested_block:Block.t -> attesting_slot tzresult Lwt.t + +(** Returns the canonical {!attesting_slot} corresponding to a + {!RPC.Attestation_rights.delegate_rights}. *) +val attesting_slot_of_delegate_rights : + RPC.Attestation_rights.delegate_rights -> attesting_slot + (** Create an unpacked attestation that is expected for given [Block.t]. Optional parameters allow to specify the attested values: [level], [round], [block_payload_hash], and/or [dal_content]. - They also allow to specify the attester ([delegate]), and/or the - [slot]. These default to the first slot and its delegate. + The consensus slot and signer are the ones from [attesting_slot] + if provided, otherwise the canonical ones for the delegate with + [manager_pkh] if provided (and the function fails if [manager_pkh] + is not the manager key of a delegate with attesting rights at the + given [Block.t]'s level); otherwise, they default to the attesting + slot returned by {!get_attesting_slot}. The function fails if both + [attesting_slot] and [manager_pkh] are provided. Finally, the operation [branch] can be specified. It defaults to the predecessor of the attested block. *) val raw_attestation : - ?delegate:public_key_hash -> - ?slot:Slot.t -> + ?attesting_slot:attesting_slot -> + ?manager_pkh:public_key_hash -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -84,8 +154,8 @@ val raw_attestation : Optional parameters are the same than {!raw_attestation}. *) val raw_preattestation : - ?delegate:public_key_hash -> - ?slot:Slot.t -> + ?attesting_slot:attesting_slot -> + ?manager_pkh:public_key_hash -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -96,8 +166,8 @@ val raw_preattestation : (** Create a packed attestation that is expected for a given [Block.t] by packing the result of {!raw_attestation}. *) val attestation : - ?delegate:public_key_hash -> - ?slot:Slot.t -> + ?attesting_slot:attesting_slot -> + ?manager_pkh:public_key_hash -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -106,11 +176,28 @@ val attestation : Block.t -> Operation.packed tzresult Lwt.t -(** Create a packed attestations_aggregate that is expected for a given - [Block.t]. Block context is expected to include at least one delegate with a - BLS key (or a registered consensus keys). *) +(** Crafts an {!Attestations_aggregate} operation pointing to the + given {!Block.t}. Block context is expected to include at least + one delegate with a BLS consensus key, otherwise this function + will return an error. + + [committee] defaults to {!default_committee} with [dal_content = + None] for each member. + + Other parameters are the same as in {!raw_attestation}. *) +val raw_attestations_aggregate : + ?committee:(attesting_slot * dal_content option) list -> + ?level:Raw_level.t -> + ?round:Round.t -> + ?block_payload_hash:Block_payload_hash.t -> + ?branch:Block_hash.t -> + Block.t -> + Kind.attestations_aggregate Operation.t tzresult Lwt.t + +(** Same as {!raw_preattestations_aggregate} but returns the packed + operation. *) val attestations_aggregate : - ?committee:public_key_hash list -> + ?committee:(attesting_slot * dal_content option) list -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -118,24 +205,11 @@ val attestations_aggregate : Block.t -> Operation.packed tzresult Lwt.t -(** Aggregate a list of attestations in a single Attestations_aggregate. - Attestations signed by non-bls delegates are ignored. Evaluates to {!None} if - no bls-signed attestations are found or if signature_aggregation failed - (due to unreadable signature representation). *) -val raw_aggregate : - Kind.attestation_consensus_kind Kind.consensus operation trace -> - Kind.attestations_aggregate operation option - -(** Same as {!raw_aggregate} but returns the packed operation. *) -val aggregate : - Kind.attestation_consensus_kind Kind.consensus operation trace -> - Operation.packed option - (** Create a packed preattestation that is expected for a given [Block.t] by packing the result of {!raw_preattestation}. *) val preattestation : - ?delegate:public_key_hash -> - ?slot:Slot.t -> + ?attesting_slot:attesting_slot -> + ?manager_pkh:public_key_hash -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -143,11 +217,16 @@ val preattestation : Block.t -> Operation.packed tzresult Lwt.t -(** Create a packed preattestations_aggregate that is expected for a given - [Block.t]. Block context is expected to include at least one delegate with a - BLS key (or a registered consensus keys). *) +(** Crafts a {!Preattestations_aggregate} operation pointing to the + given {!Block.t}. Block context is expected to include at least + one delegate with a BLS consensus key, otherwise this function + will return an error. + + [committee] defaults to {!default_committee}. + + Other parameters are the same as in {!raw_attestation}. *) val raw_preattestations_aggregate : - ?committee:public_key_hash list -> + ?committee:attesting_slot list -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -158,7 +237,7 @@ val raw_preattestations_aggregate : (** Same as {!raw_preattestations_aggregate} but returns the packed operation. *) val preattestations_aggregate : - ?committee:public_key_hash list -> + ?committee:attesting_slot list -> ?level:Raw_level.t -> ?round:Round.t -> ?block_payload_hash:Block_payload_hash.t -> @@ -166,19 +245,6 @@ val preattestations_aggregate : Block.t -> Operation.packed tzresult Lwt.t -(** Aggregate a list of preattestations in a single Preattestations_aggregate. - Preattestations signed by non-bls delegates are ignored. Evaluates to {!None} if - no bls-signed attestations are found or if signature_aggregation failed. *) -val raw_aggregate_preattestations : - Kind.preattestation_consensus_kind Kind.consensus operation trace -> - Kind.preattestations_aggregate operation option - -(** Same as {!raw_aggregate_preattestations} but returns the packed - operation. *) -val aggregate_preattestations : - Kind.preattestation_consensus_kind Kind.consensus operation trace -> - Operation.packed option - type gas_limit = | Max (** Max corresponds to the [max_gas_limit_per_operation] constant. *) | High @@ -787,14 +853,17 @@ type tested_mode = Application | Construction | Mempool - When [tested_mode] is [Mempool], a mempool is initialized using [predecessor] as head, then {!Incremental.add_operation} is called - on [operation]. + on [operation], then {!Incremental.finalize_block_with_metadata}. - When [error] is [None], we check that everything succeeds, - otherwise we check that the error identified by [error] is - returned. + When [check_after] is provided, it is called on the resulting + block. When [error] is provided, we check that an error identified + by [error] is returned. When neither is provided, we return unit + if there the validation and application returned [Ok], or the + unchanged error. When both are provided, the function fails. *) val check_validation_and_application : loc:string -> + ?check_after:(Block.block_with_metadata -> unit tzresult Lwt.t) -> ?error:(Environment.Error_monad.error -> bool) -> predecessor:Block.t -> tested_mode -> @@ -802,9 +871,12 @@ val check_validation_and_application : unit tzresult Lwt.t (** Calls {!check_validation_and_application} on all {!tested_mode}s - successively, with respective errors. *) + successively, with respective checks or errors. *) val check_validation_and_application_all_modes_different_outcomes : loc:string -> + ?check_after_application:(Block.block_with_metadata -> unit tzresult Lwt.t) -> + ?check_after_construction:(Block.block_with_metadata -> unit tzresult Lwt.t) -> + ?check_after_mempool:(Block.block_with_metadata -> unit tzresult Lwt.t) -> ?application_error:(Environment.Error_monad.error -> bool) -> ?construction_error:(Environment.Error_monad.error -> bool) -> ?mempool_error:(Environment.Error_monad.error -> bool) -> @@ -813,9 +885,11 @@ val check_validation_and_application_all_modes_different_outcomes : unit tzresult Lwt.t (** Calls {!check_validation_and_application} on all {!tested_mode}s - successively, with the same [error] provided for each mode. *) + successively, with the same [check_after] or [error] provided for + each mode. *) val check_validation_and_application_all_modes : loc:string -> + ?check_after:(Block.block_with_metadata -> unit tzresult Lwt.t) -> ?error:(Environment.Error_monad.error -> bool) -> predecessor:Block.t -> t -> diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/scenario_attestation.ml b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/scenario_attestation.ml index fff25a068d8c..31cb50100bc8 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/scenario_attestation.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/scenario_attestation.ml @@ -94,7 +94,8 @@ let check_attestation_metadata ?(check_not_found = false) ~kind delegate_pkh consensus_key_pkh let check_attestation_aggregate_metadata ?(check_not_found = false) ~kind - committee_expect : Block.full_metadata -> t -> unit tzresult Lwt.t = + ?(expect_same_order = true) committee_expect : + Block.full_metadata -> t -> unit tzresult Lwt.t = fun (_block_header_metadata, op_metadata) (_block, _state) -> let open Lwt_result_syntax in Log.debug ~color:low_debug_color "Check metadata: aggregated attestation" ; @@ -102,6 +103,15 @@ let check_attestation_aggregate_metadata ?(check_not_found = false) ~kind if check_not_found then (not, "Not expected but found in metadata") else (Fun.id, "Expected but not found in metadata") in + let may_sort committee = + if expect_same_order then committee + else + List.sort + (fun {Alpha_context.Consensus_key.delegate = d1; _} {delegate = d2; _} -> + Signature.Public_key_hash.compare d1 d2) + committee + in + let committee_expect = may_sort committee_expect in if id_or_not @@ List.exists @@ -133,19 +143,19 @@ let check_attestation_aggregate_metadata ?(check_not_found = false) ~kind total_consensus_power = _; }); } ) -> - let committee = - List.map - (fun ((ck : Protocol.Alpha_context.Consensus_key.t), _) -> - ck.delegate) - committee - |> List.sort Signature.Public_key_hash.compare - in - let committee_expect = - List.map fst committee_expect - |> List.sort Signature.Public_key_hash.compare - in + let committee = List.map fst committee |> may_sort in + Log.debug + "@[Actual committee:@,%a@]" + (Format.pp_print_list Alpha_context.Consensus_key.pp) + committee ; List.equal - Signature.Public_key_hash.equal + (fun { + Alpha_context.Consensus_key.delegate = d1; + consensus_pkh = c1; + } + {delegate = d2; consensus_pkh = c2} -> + Signature.Public_key_hash.equal d1 d2 + && Signature.Public_key_hash.equal c1 c2) committee committee_expect | _ -> false) @@ -159,8 +169,8 @@ let check_attestation_aggregate_metadata ?(check_not_found = false) ~kind Format.( pp_print_list ~pp_sep:(fun fmt () -> fprintf fmt "; ") - Signature.Public_key_hash.pp) - (List.map fst committee_expect) + Alpha_context.Consensus_key.pp) + committee_expect let check_attestation_rewards ?(check_not_found = false) delegate_name : Block.full_metadata -> t -> unit tzresult Lwt.t = @@ -257,9 +267,7 @@ let attest_with ?dal_content (delegate_name : string) : (t, t) scenarios = Option.map (fun i -> Alpha_context.{attestation = i}) dal_content in (* Fails to produce an attestation if the delegate has no slot for the block *) - let* op = - Op.attestation ?dal_content ~delegate:consensus_key.pkh block - in + let* op = Op.attestation ?dal_content ~manager_pkh:delegate.pkh block in (* Update the activity of the delegate *) let state = update_activity delegate_name block state in let state = State.add_pending_operations [op] state in @@ -287,37 +295,41 @@ let attest_aggreg_with (delegates : string list) : (t, t) scenarios = if state.force_attest_all then failwith "Cannot manually attest if force_attest_all is true" else - let* state, committee, delegate_and_ck_committee = + let* state, committee, expected_metadata_committee = List.fold_left_es - (fun (state, committee, delegate_and_ck) delegate_name -> + (fun (state, committee, expected_metadata_committee) delegate_name -> let delegate = State.find_account delegate_name state in let* consensus_key_info = Context.Delegate.consensus_key (B state.grandparent) delegate.pkh in - let consensus_key_pkh = - consensus_key_info.active.consensus_key_pkh + let consensus_pkh = consensus_key_info.active.consensus_key_pkh in + let* () = + if Signature.Public_key_hash.is_bls consensus_pkh then + return_unit + else failwith "Cannot aggregate with non-BLS key" in (* Update the activity of the committee *) let state = update_activity delegate_name block state in + let* attesting_slot = + Op.get_attesting_slot_of_delegate + ~manager_pkh:delegate.pkh + ~attested_block:block + in + let key_in_metadata = + { + Alpha_context.Consensus_key.delegate = delegate.pkh; + consensus_pkh; + } + in return ( state, - consensus_key_pkh :: committee, - (delegate.pkh, consensus_key_pkh) :: delegate_and_ck )) + (attesting_slot, None) :: committee, + key_in_metadata :: expected_metadata_committee )) (state, [], []) delegates in - let* () = - if - not - @@ List.for_all - (function - | (Bls _ : Signature.public_key_hash) -> true | _ -> false) - committee - then failwith "Cannot aggregate non-BLS attestation" - else return_unit - in (* Fails to produce an attestation if one of the delegates has no slot for the block *) let* op = Op.attestations_aggregate ~committee block in (* Check metadata *) @@ -325,12 +337,16 @@ let attest_aggreg_with (delegates : string list) : (t, t) scenarios = State.add_current_block_check (check_attestation_aggregate_metadata ~kind - delegate_and_ck_committee) + expected_metadata_committee) state in let state = State.add_pending_operations [op] state in return (block, state)) +let key_for_metadata_of_delegate_rights + {RPC.Attestation_rights.delegate; consensus_key; _} = + {Alpha_context.Consensus_key.delegate; consensus_pkh = consensus_key} + let attest_with_all_ : t -> t tzresult Lwt.t = let open Lwt_result_syntax in fun (block, state) -> @@ -345,12 +361,12 @@ let attest_with_all_ : t -> t tzresult Lwt.t = so the returned list should only contain one element. *) assert false in - let* dlgs = - List.map + let* non_forbidden_delegates_rights = + List.filter_es (fun { - Plugin.RPC.Attestation_rights.delegate; + RPC.Attestation_rights.delegate; consensus_key = _; - first_slot; + first_slot = _; attestation_power; } -> Tezt.Check.( @@ -358,88 +374,68 @@ let attest_with_all_ : t -> t tzresult Lwt.t = int ~__LOC__ ~error_msg:"Attestation power should be greater than 0, got %L") ; - (delegate, first_slot)) + let* is_forbidden = + Context.Delegate.is_forbidden (B block) delegate + in + return (not is_forbidden)) delegates_rights - |> List.filter_es (fun (delegate, _slot) -> - let* is_forbidden = - Context.Delegate.is_forbidden (B block) delegate - in - return (not is_forbidden)) in - let* to_aggregate, ops = + let* state, bls_committee = List.fold_left_es - (fun (to_aggregate, regular) (delegate, slot) -> - let* consensus_key_info = - Context.Delegate.consensus_key (B state.grandparent) delegate - in - let consensus_key = consensus_key_info.active in - let* consensus_key = Account.find consensus_key.consensus_key_pkh in - let* op = - Op.raw_attestation ~delegate:consensus_key.pkh ~slot block - in - match (state.constants.aggregate_attestation, consensus_key.pk) with - | true, Bls _ -> - return ((op, delegate, consensus_key.pkh) :: to_aggregate, regular) - | _ -> - return - ( to_aggregate, - ( Protocol.Alpha_context.Operation.pack op, - delegate, - consensus_key.pkh ) - :: regular )) - ([], []) - dlgs - in - let aggregated = - Op.aggregate (List.map (fun (x, _, _) -> x) to_aggregate) - in - let state = - match aggregated with - | None -> state - | Some op -> - (* Update the activity of the committee *) - let state, delegate_and_ck_committee = - List.fold_left - (fun (state, delegate_and_ck) (_, delegate_pkh, consensus_key_pkh) -> - let delegate_name, _ = - State.find_account_from_pkh delegate_pkh state - in - ( update_activity delegate_name block state, - (delegate_pkh, consensus_key_pkh) :: delegate_and_ck )) - (state, []) - to_aggregate - in - (* Check metadata *) - let state = - State.add_current_block_check - (check_attestation_aggregate_metadata - ~kind - delegate_and_ck_committee) - state - in - let state = State.add_pending_operations [op] state in - state - in - (* Update the activity of the rest of the committee, and check metadata *) - let state = - List.fold_left - (fun state (_, delegate_pkh, consensus_key_pkh) -> + (fun (state, bls_committee) + ({ + RPC.Attestation_rights.delegate = manager_pkh; + consensus_key = consensus_pkh; + first_slot = slot; + attestation_power = _; + } as delegate_rights) -> + (* Update delegate activity in any case. *) let delegate_name, _ = - State.find_account_from_pkh delegate_pkh state + State.find_account_from_pkh manager_pkh state in let state = update_activity delegate_name block state in - (* Check metadata *) - let state = - State.add_current_block_check - (check_attestation_metadata ~kind delegate_pkh consensus_key_pkh) - state - in - state) - state - ops + if + state.constants.aggregate_attestation + && Signature.Public_key_hash.is_bls consensus_pkh + then + (* Just add the delegate to the committee; aggregation and + metadata check will be handled below. *) + return (state, delegate_rights :: bls_committee) + else + (* Add standalone attestation and metadata check. *) + let attesting_slot = {Op.slot; consensus_pkh} in + let* op = Op.attestation ~attesting_slot block in + let state = State.add_pending_operations [op] state in + let state = + State.add_current_block_check + (check_attestation_metadata ~kind manager_pkh consensus_pkh) + state + in + return (state, bls_committee)) + (state, []) + non_forbidden_delegates_rights in - let state = - State.add_pending_operations (List.map (fun (x, _, _) -> x) ops) state + let* state = + if List.is_empty bls_committee then return state + else + (* Add aggregated attestation and metadata check. *) + let committee = + List.map + (fun delegate_rights -> + (Op.attesting_slot_of_delegate_rights delegate_rights, None)) + bls_committee + in + let* op = Op.attestations_aggregate ~committee block in + let state = State.add_pending_operations [op] state in + let expected_committee = + List.map key_for_metadata_of_delegate_rights bls_committee + in + let state = + State.add_current_block_check + (check_attestation_aggregate_metadata ~kind expected_committee) + state + in + return state in return (block, state) @@ -491,7 +487,7 @@ let preattest_with ?payload_round (delegate_name : string) : let consensus_key = consensus_key_info.active in let* consensus_key = Account.find consensus_key.consensus_key_pkh in (* Fails to produce an attestation if the delegate has no slot for the block *) - let* op = Op.preattestation ~delegate:consensus_key.pkh fake_block in + let* op = Op.preattestation ~manager_pkh:delegate.pkh fake_block in (* Update the activity of the delegate *) let state = update_activity delegate_name (Incremental.predecessor incr) state @@ -523,15 +519,18 @@ let preattest_aggreg_with ?payload_round (delegates : string list) : else let kind = Preattestation in let* fake_block = make_fake_block ?payload_round incr in - let* state, committee, delegate_and_ck_committee = + let* state, committee, expected_metadata_committee = List.fold_left_es - (fun (state, committee, delegate_and_ck) delegate_name -> + (fun (state, committee, expected_metadata_committee) delegate_name -> let delegate = State.find_account delegate_name state in let* consensus_key_info = Context.Delegate.consensus_key (I incr) delegate.pkh in - let consensus_key_pkh = - consensus_key_info.active.consensus_key_pkh + let consensus_pkh = consensus_key_info.active.consensus_key_pkh in + let* () = + if Signature.Public_key_hash.is_bls consensus_pkh then + return_unit + else failwith "Cannot aggregate non-BLS preattestation" in (* Update the activity of the committee *) let state = @@ -540,31 +539,32 @@ let preattest_aggreg_with ?payload_round (delegates : string list) : (Incremental.predecessor incr) state in + (* Fails if the delegate has no slot for the block *) + let* attesting_slot = + Op.get_attesting_slot_of_delegate + ~manager_pkh:delegate.pkh + ~attested_block:fake_block + in + let key_for_metadata = + { + Alpha_context.Consensus_key.delegate = delegate.pkh; + consensus_pkh; + } + in return ( state, - consensus_key_pkh :: committee, - (delegate.pkh, consensus_key_pkh) :: delegate_and_ck )) + attesting_slot :: committee, + key_for_metadata :: expected_metadata_committee )) (state, [], []) delegates in - let* () = - if - not - @@ List.for_all - (function - | (Bls _ : Signature.public_key_hash) -> true | _ -> false) - committee - then failwith "Cannot aggregate non-BLS preattestation" - else return_unit - in - (* Fails to produce a preattestation if one of the delegates has no slot for the block *) let* op = Op.preattestations_aggregate ~committee fake_block in (* Check metadata *) let state = State.add_current_block_check (check_attestation_aggregate_metadata ~kind - delegate_and_ck_committee) + expected_metadata_committee) state in let* incr = Incremental.add_operation incr op in @@ -585,12 +585,12 @@ let preattest_with_all_ ?payload_round : t_incr -> t_incr tzresult Lwt.t = so the returned list should only contain one element. *) assert false in - let* dlgs = - List.map + let* non_forbidden_delegates_rights = + List.filter_es (fun { Plugin.RPC.Attestation_rights.delegate; consensus_key = _; - first_slot; + first_slot = _; attestation_power; } -> Tezt.Check.( @@ -598,95 +598,61 @@ let preattest_with_all_ ?payload_round : t_incr -> t_incr tzresult Lwt.t = int ~__LOC__ ~error_msg:"Attestation power should be greater than 0, got %L") ; - (delegate, first_slot)) + let* is_forbidden = Context.Delegate.is_forbidden (I incr) delegate in + return (not is_forbidden)) delegates_rights - |> List.filter_es (fun (delegate, _slot) -> - let* is_forbidden = - Context.Delegate.is_forbidden (I incr) delegate - in - return (not is_forbidden)) in - let* to_aggregate, ops = + let* incr, state, bls_committee = List.fold_left_es - (fun (to_aggregate, regular) (delegate, slot) -> - let* consensus_key_info = - Context.Delegate.consensus_key (I incr) delegate - in - let consensus_key = consensus_key_info.active in - let* consensus_key = Account.find consensus_key.consensus_key_pkh in - let* op = - Op.raw_preattestation ~delegate:consensus_key.pkh ~slot fake_block - in - match (state.constants.aggregate_attestation, consensus_key.pk) with - | true, Bls _ -> - return ((op, delegate, consensus_key.pkh) :: to_aggregate, regular) - | _ -> - return - ( to_aggregate, - ( Protocol.Alpha_context.Operation.pack op, - delegate, - consensus_key.pkh ) - :: regular )) - ([], []) - dlgs - in - let aggregated = - Op.aggregate_preattestations (List.map (fun (x, _, _) -> x) to_aggregate) - in - let* incr, state = - match aggregated with - | None -> return (incr, state) - | Some op -> - (* Update the activity of the committee *) - let state, delegate_and_ck_committee = - List.fold_left - (fun (state, delegate_and_ck) (_, delegate_pkh, consensus_key_pkh) -> - let delegate_name, _ = - State.find_account_from_pkh delegate_pkh state - in - ( update_activity - delegate_name - (Incremental.predecessor incr) - state, - (delegate_pkh, consensus_key_pkh) :: delegate_and_ck )) - (state, []) - to_aggregate - in - (* Check metadata *) - let state = - State.add_current_block_check - (check_attestation_aggregate_metadata - ~kind - delegate_and_ck_committee) - state - in - let* incr = Incremental.add_operation incr op in - return (incr, state) - in - (* Update the activity of the rest of the committee, and check metadata *) - let state = - List.fold_left - (fun state (_, delegate_pkh, consensus_key_pkh) -> + (fun (incr, state, bls_committee) + ({ + Plugin.RPC.Attestation_rights.delegate = manager_pkh; + consensus_key = consensus_pkh; + first_slot = slot; + attestation_power = _; + } as delegate_rights) -> + (* Update delegate activity in any case. *) let delegate_name, _ = - State.find_account_from_pkh delegate_pkh state + State.find_account_from_pkh manager_pkh state in let state = update_activity delegate_name (Incremental.predecessor incr) state in - (* Check metadata *) - let state = - State.add_current_block_check - (check_attestation_metadata ~kind delegate_pkh consensus_key_pkh) - state - in - state) - state - ops - in - let* incr = - List.fold_left_es - Incremental.add_operation - incr - (List.map (fun (x, _, _) -> x) ops) + if + state.constants.aggregate_attestation + && Signature.Public_key_hash.is_bls consensus_pkh + then + (* Just add the delegate to the committee; aggregation and + metadata check will be handled below. *) + return (incr, state, delegate_rights :: bls_committee) + else + (* Add standalone preattestation and metadata check. *) + let attesting_slot = {Op.slot; consensus_pkh} in + let* op = Op.preattestation ~attesting_slot fake_block in + let* incr = Incremental.add_operation incr op in + let state = + State.add_current_block_check + (check_attestation_metadata ~kind manager_pkh consensus_pkh) + state + in + return (incr, state, bls_committee)) + (incr, state, []) + non_forbidden_delegates_rights in - return (incr, state) + if List.is_empty bls_committee then return (incr, state) + else + (* Add aggregated preattestation and metadata check. *) + let committee = + List.map Op.attesting_slot_of_delegate_rights bls_committee + in + let* op = Op.preattestations_aggregate ~committee fake_block in + let* incr = Incremental.add_operation incr op in + let expected_committee = + List.map key_for_metadata_of_delegate_rights bls_committee + in + let state = + State.add_current_block_check + (check_attestation_aggregate_metadata ~kind expected_committee) + state + in + return (incr, state) diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/scenario_op.ml b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/scenario_op.ml index 5100c97640d6..3bc5841f2f3e 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/helpers/scenario_op.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/helpers/scenario_op.ml @@ -471,8 +471,9 @@ let double_attest_op ?other_bakers ~op ~op_evidence ~kind delegate_names let* main_branch, state = bake (block, state) in List.fold_left_es (fun (main_branch, state) delegate -> - let* attestation_a = op ~delegate:delegate.pkh forked_block in - let* attestation_b = op ~delegate:delegate.pkh main_branch in + let manager_pkh = delegate.pkh in + let* attestation_a = op ~manager_pkh ~attested_block:forked_block in + let* attestation_b = op ~manager_pkh ~attested_block:main_branch in let evidence = op_evidence attestation_a attestation_b in let dss = { @@ -493,7 +494,8 @@ let double_attest_op ?other_bakers ~op ~op_evidence ~kind delegate_names let double_attest_ = double_attest_op - ~op:(fun ~delegate block -> Op.raw_attestation ~delegate block) + ~op:(fun ~manager_pkh ~attested_block -> + Op.raw_attestation ~manager_pkh attested_block) ~op_evidence:op_double_attestation ~kind:Double_attesting @@ -506,7 +508,8 @@ let double_attest ?other_bakers delegate_name : (t, t) scenarios = let double_preattest_ = double_attest_op - ~op:(fun ~delegate block -> Op.raw_preattestation ~delegate block) + ~op:(fun ~manager_pkh ~attested_block -> + Op.raw_preattestation ~manager_pkh attested_block) ~op_evidence:op_double_preattestation ~kind:Double_preattesting diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_aggregate.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_aggregate.ml index 3c768c1a97c7..0b904cb2d8dd 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_aggregate.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_aggregate.ml @@ -36,42 +36,6 @@ let init_genesis_with_some_bls_accounts ?policy ?dal_enable let* b = Block.bake ?policy genesis in return (genesis, b) -let aggregate_in_mempool_error = function - | Validate_errors.Consensus.Aggregate_in_mempool -> true - | _ -> false - -let aggregate_disabled_error = function - | Validate_errors.Consensus.Aggregate_disabled -> true - | _ -> false - -let aggregate_unimplemented_error = function - | Validate_errors.Consensus.Aggregate_not_implemented -> true - | _ -> false - -let signature_invalid_error = function - | Operation_repr.Invalid_signature -> true - | _ -> false - -let non_bls_in_aggregate = function - | Validate_errors.Consensus.Non_bls_key_in_aggregate -> true - | _ -> false - -let conflicting_consensus_operation ?kind = function - | Validate_errors.Consensus.Conflicting_consensus_operation {kind = kind'; _} - -> - Option.fold ~none:true ~some:(fun kind -> kind = kind') kind - | _ -> false - -let unaggregated_eligible_attestation ?kind = function - | Validate_errors.Consensus.Unaggregated_eligible_operation {kind = kind'; _} - -> - Option.fold ~none:true ~some:(fun kind -> kind = kind') kind - | _ -> false - -let empty_aggregation_committee = function - | Validate_errors.Consensus.Empty_aggregation_committee -> true - | _ -> false - let find_preattestations_aggregate_result receipt = let result_opt = List.find_map @@ -110,7 +74,7 @@ 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) ~committee +let check_aggregate_result (type kind) (kind : kind aggregate) ~attesters (result : kind Tezos_protocol_023_PtSeouLo__Protocol.Apply_results.contents_result) = @@ -136,14 +100,14 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~committee | [] -> return_unit | _ -> Test.fail "Unexpected non-empty balance updates list" in - (* Check voting power *) + (* Check total voting power *) let* () = let voting_power = List.fold_left (fun acc (delegate : RPC.Validators.t) -> List.length delegate.slots + acc) 0 - committee + attesters in if voting_power = total_consensus_power then return_unit else @@ -153,260 +117,422 @@ let check_aggregate_result (type kind) (kind : kind aggregate) ~committee total_consensus_power in (* Check committee *) - let committee_pkhs = + let expected_committee = List.map - (fun (consensus_key : RPC.Validators.t) -> consensus_key.delegate) - committee - in - let resulting_committee_pkhs = - List.map - (fun ((attester : Alpha_context.Consensus_key.t), _) -> - attester.delegate) - resulting_committee + (fun {Context.delegate; consensus_key = consensus_pkh; slots; _} -> + let power = List.length slots in + ({Alpha_context.Consensus_key.delegate; consensus_pkh}, power)) + attesters in if List.equal - Tezos_crypto.Signature.Public_key_hash.equal - resulting_committee_pkhs - committee_pkhs + (fun ( {Alpha_context.Consensus_key.delegate = d1; consensus_pkh = c1}, + power1 ) + ({delegate = d2; consensus_pkh = c2}, power2) -> + Signature.Public_key_hash.equal d1 d2 + && Signature.Public_key_hash.equal c1 c2 + && Int.equal power1 power2) + resulting_committee + expected_committee then return_unit else let pp = - Format.( - pp_print_list - ~pp_sep:pp_print_cut - Tezos_crypto.Signature.Public_key_hash.pp) + Format.pp_print_list (fun fmt (consensus_key, power) -> + Format.fprintf + fmt + "%a with power %d" + Alpha_context.Consensus_key.pp + consensus_key + power) in Test.fail - "@[Wrong commitee@,@[expected:@,%a@]@,@[found:@,%a@]@]" + "@[Wrong committee@,\ + @[expected:@,\ + %a@]@,\ + @[found:@,\ + %a@]@]" pp - committee_pkhs + expected_committee pp - resulting_committee_pkhs + resulting_committee (* [check_preattestations_aggregate_result ~committee result] verifies that [result] has the following properties: - [balance_update] is empty; - [voting_power] equals the sum of slots owned by attesters in [committee]; - the public key hashes in [result] committee match those of [committee]. *) -let check_preattestations_aggregate_result ~committee +let check_preattestations_aggregate_result ~attesters (result : Alpha_context.Kind.preattestations_aggregate Tezos_protocol_023_PtSeouLo__Protocol.Apply_results.contents_result) = - check_aggregate_result Preattestation ~committee result + check_aggregate_result Preattestation ~attesters result (* [check_attestations_aggregate_result ~committee result] verifies that [result] has the following properties: - [balance_update] is empty; - [voting_power] equals the sum of slots owned by attesters in [committee]; - the public key hashes in [result] committee match those of [committee]. *) -let check_attestations_aggregate_result ~committee +let check_attestations_aggregate_result ~attesters (result : Alpha_context.Kind.attestations_aggregate Tezos_protocol_023_PtSeouLo__Protocol.Apply_results.contents_result) = - check_aggregate_result Attestation ~committee result - -(* [find_attester_with_bls_key attesters] returns the first attester with a BLS - key, if any. *) -let find_attester_with_bls_key = - List.find_map (fun (attester : RPC.Validators.t) -> - match (attester.consensus_key, attester.slots) with - | Bls _, slot :: _ -> Some (attester, slot) - | _ -> None) - -(* [find_attester_with_non_bls_key attesters] returns the first attester - with a non-BLS key, if any. *) -let find_attester_with_non_bls_key = - List.find_map (fun (attester : RPC.Validators.t) -> - match (attester.consensus_key, attester.slots) with - | (Ed25519 _ | Secp256k1 _ | P256 _), slot :: _ -> Some (attester, slot) - | _ -> None) - -(* [filter_attesters_with_bls_key attesters] filters attesters with a BLS - consensus key and at least one slot, returning a list of - (minimal slot, attester) pairs. *) -let filter_attesters_with_bls_key = - List.filter_map (fun (attester : RPC.Validators.t) -> - match (attester.consensus_key, attester.slots) with - | Bls _, slot :: _ -> Some (slot, attester) - | _ -> None) + check_aggregate_result Attestation ~attesters result + +let check_after_preattestations_aggregate + ((_, (_, op_receipts)) : Block.block_with_metadata) = + check_preattestations_aggregate_result + (find_preattestations_aggregate_result op_receipts) + +let check_after_attestations_aggregate + ((_, (_, op_receipts)) : Block.block_with_metadata) = + check_attestations_aggregate_result + (find_attestations_aggregate_result op_receipts) + +(** Tests the validation and application of a preattestations_aggregate. + + [attesting_slots] defaults to the respective canonical slots of + [attesters]. + + When [error] is [None], performs + {!check_preattestations_aggregate_result} on the operation's + metadata, otherwise checks that the error identified by [error] is + returned. + + Unlike {!check_attestations_aggregate_validation_and_application}, + only tests in application mode because making a context that + accepts preattestations is slightly more complicated. *) +let check_preattestations_aggregate_validation_and_application ~loc ~attesters + ?attesting_slots ~preattested_block ~preattested_block_predecessor ?error () + = + let open Lwt_result_syntax in + let committee = + match attesting_slots with + | Some v -> v + | None -> List.map Op.attesting_slot_of_attester attesters + in + let* operation = Op.preattestations_aggregate ~committee preattested_block in + let*! res = + Block.bake_with_metadata + ~policy:(By_round 1) + ~payload_round:Alpha_context.Round.zero + ~locked_round:Alpha_context.Round.zero + ~operation + preattested_block_predecessor + in + match error with + | None -> + let*? block_with_metadata = res in + check_after_preattestations_aggregate ~attesters block_with_metadata + | Some error -> Assert.proto_error ~loc res error + +(** Tests the validation and application of an attestations_aggregate. + + [attesting_slots] defaults to the respective canonical slots of + [attesters]. + + In mempool mode, always expects + {!Error_helpers.aggregate_in_mempool}. + + In block modes: when [error] is [None], performs + {!check_attestations_aggregate_result} on the operation's + metadata, otherwise checks that the error identified by [error] is + returned. *) +let check_attestations_aggregate_validation_and_application ~loc ~attesters + ?attesting_slots ~attested_block ?error () = + let open Lwt_result_syntax in + let attesting_slots = + match attesting_slots with + | Some v -> v + | None -> List.map Op.attesting_slot_of_attester attesters + in + let committee = + (* It would be nice to test with various DAL contents, but this + would require setting up delegates with companion keys. *) + List.map (fun attesting_slot -> (attesting_slot, None)) attesting_slots + in + let* operation = Op.attestations_aggregate ~committee attested_block in + let check_after_block_mode = + match error with + | None -> Some (check_after_attestations_aggregate ~attesters) + | Some _ -> None + in + Op.check_validation_and_application_all_modes_different_outcomes + ~loc + ?check_after_application:check_after_block_mode + ?check_after_construction:check_after_block_mode + ?application_error:error + ?construction_error:error + ~mempool_error:Error_helpers.aggregate_in_mempool + ~predecessor:attested_block + operation let test_aggregate_feature_flag_enabled () = let open Lwt_result_syntax in - let* _genesis, attested_block = + let* _genesis, b1 = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - Consensus_helpers.test_consensus_operation_all_modes_different_outcomes + let* b2 = Block.bake b1 in + let* attesters = Context.get_attesters_with_bls_key (B b2) in + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~preattested_block:b2 + ~preattested_block_predecessor:b1 + () + in + check_attestations_aggregate_validation_and_application ~loc:__LOC__ - ~attested_block - ~mempool_error:aggregate_in_mempool_error - Aggregate + ~attesters + ~attested_block:b2 + () let test_aggregate_feature_flag_disabled () = let open Lwt_result_syntax in - let* _genesis, attested_block = + let* _genesis, b1 = init_genesis_with_some_bls_accounts ~aggregate_attestation:false () in - Consensus_helpers.test_consensus_operation_all_modes_different_outcomes + let* b2 = Block.bake b1 in + let* attesters = Context.get_attesters_with_bls_key (B b2) in + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~preattested_block:b2 + ~preattested_block_predecessor:b1 + ~error:Error_helpers.aggregate_disabled + () + in + check_attestations_aggregate_validation_and_application ~loc:__LOC__ - ~attested_block - ~application_error:aggregate_disabled_error - ~construction_error:aggregate_disabled_error - ~mempool_error:aggregate_in_mempool_error - Aggregate + ~attesters + ~attested_block:b2 + ~error:Error_helpers.aggregate_disabled + () let test_attestations_aggregate_with_a_single_delegate () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - (* Find an attester with a BLS consensus key. *) - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) + let* attester = Context.get_attester_with_bls_key (B attested_block) in + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters:[attester] + ~attested_block + () + +let test_preattestations_aggregate_with_a_single_delegate () = + let open Lwt_result_syntax in + let* _genesis, preattested_block_predecessor = + init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attestation = - Op.raw_attestation ~delegate:attester.RPC.Validators.delegate ~slot block + let* preattested_block = Block.bake preattested_block_predecessor in + let* attester = Context.get_attester_with_bls_key (B preattested_block) in + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters:[attester] + ~preattested_block + ~preattested_block_predecessor + () + +let test_attestations_aggregate_with_multiple_delegates () = + let open Lwt_result_syntax in + let* _genesis, attested_block = + init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let operation = - WithExceptions.Option.get ~loc:__LOC__ (Op.aggregate [attestation]) + let* attesters = Context.get_attesters_with_bls_key (B attested_block) in + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attested_block + () + +let test_preattestations_aggregate_with_multiple_delegates () = + let open Lwt_result_syntax in + let* _genesis, preattested_block_predecessor = + init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* _, (_, receipt) = Block.bake_with_metadata ~operation block in - let result = find_attestations_aggregate_result receipt in - check_attestations_aggregate_result ~committee:[attester] result + let* preattested_block = Block.bake preattested_block_predecessor in + let* attesters = Context.get_attesters_with_bls_key (B preattested_block) in + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~preattested_block + ~preattested_block_predecessor + () -let test_preattestations_aggregate_with_a_single_delegate () = +(* Preattestations/atttestations aggregate where one of the slots is + not the first slot of its delegate (but still belongs to the + delegate). *) +let test_non_canonical_slot () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block_predecessor = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in - (* Find an attester with a BLS consensus key. *) - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in - let* operation = - let* preattestation = - Op.raw_preattestation - ~delegate:attester.RPC.Validators.delegate - ~slot - block' - in - return - @@ WithExceptions.Option.get ~loc:__LOC__ - @@ Op.aggregate_preattestations [preattestation] + let* attested_block = Block.bake attested_block_predecessor in + let* attesters = Context.get_attesters_with_bls_key (B attested_block) in + let attester, other_attester = + match attesters with + | x1 :: x2 :: _ -> (x1, x2) + | _ -> Test.fail ~__LOC__ "Expected at least two attesters with BLS key" in - let* _, (_, receipt) = - let round_zero = Alpha_context.Round.zero in - Block.bake_with_metadata - ~policy:(By_round 1) - ~payload_round:round_zero - ~locked_round:round_zero - ~operation - block + let non_canonical_attesting_slot = + Op.non_canonical_attesting_slot_of_attester attester + in + let other_attesters_canonical_slot = + Op.attesting_slot_of_attester other_attester + in + let attesters_and_slots_to_test = + [ + (* Problematic slot alone *) + ([attester], [non_canonical_attesting_slot]); + (* Problematic slot first then normal slot *) + ( [attester; other_attester], + [non_canonical_attesting_slot; other_attesters_canonical_slot] ); + (* Problematic slot last *) + ( [other_attester; attester], + [other_attesters_canonical_slot; non_canonical_attesting_slot] ); + ] in - let result = find_preattestations_aggregate_result receipt in - check_preattestations_aggregate_result ~committee:[attester] result + List.iter_es + (fun (attesters, attesting_slots) -> + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attesting_slots + ~preattested_block:attested_block + ~preattested_block_predecessor:attested_block_predecessor + ~error:Error_helpers.wrong_slot_used_for_preattestation + () + in + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attesting_slots + ~attested_block + ~error:Error_helpers.wrong_slot_used_for_attestation + ()) + attesters_and_slots_to_test -let test_attestations_aggregate_with_multiple_delegates () = +(* Preattestations/atttestations aggregate where a delegate uses a + slot that does not belong to it. *) +let test_not_owned_slot () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block_predecessor = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - (* Filter delegates with BLS keys that have at least one slot *) - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in - let* attestations = - List.map_es - (fun (slot, delegate) -> - Op.raw_attestation - ~delegate:delegate.RPC.Validators.delegate - ~slot - block) - bls_delegates_with_slots + let* attested_block = Block.bake attested_block_predecessor in + let* attesters = Context.get_attesters_with_bls_key (B attested_block) in + let attester, other_attester, third_attester = + match attesters with + | x1 :: x2 :: x3 :: _ -> (x1, x2, x3) + | _ -> Test.fail ~__LOC__ "Expected at least three attesters with BLS key" in - let aggregation = - WithExceptions.Option.get ~loc:__LOC__ (Op.aggregate attestations) + let wrong_attesting_slot = + { + Op.consensus_pkh = attester.consensus_key; + slot = + WithExceptions.Option.get ~loc:__LOC__ (List.hd third_attester.slots); + } in - let* _, (_, receipt) = - Block.bake_with_metadata ~operation:aggregation block + let other_attesters_canonical_slot = + Op.attesting_slot_of_attester other_attester in - let result = find_attestations_aggregate_result receipt in - let delegates = List.map snd bls_delegates_with_slots in - check_attestations_aggregate_result ~committee:delegates result + let attesters_and_slots_to_test = + [ + (* Problematic slot alone *) + ([attester], [wrong_attesting_slot]); + (* Problematic slot first then normal slot *) + ( [attester; other_attester], + [wrong_attesting_slot; other_attesters_canonical_slot] ); + (* Problematic slot last *) + ( [other_attester; attester], + [other_attesters_canonical_slot; wrong_attesting_slot] ); + ] + in + List.iter_es + (fun (attesters, attesting_slots) -> + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attesting_slots + ~preattested_block:attested_block + ~preattested_block_predecessor:attested_block_predecessor + ~error:Error_helpers.invalid_signature + () + in + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attesting_slots + ~attested_block + ~error:Error_helpers.invalid_signature + ()) + attesters_and_slots_to_test -let test_preattestations_aggregate_with_multiple_delegates () = +(* Preattestations/atttestations aggregate with a duplicate slot. *) +let test_duplicate_slot () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block_predecessor = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in - (* Filter delegates with BLS keys that have at least one slot *) - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in - let* preattestations = - List.map_es - (fun (slot, delegate) -> - Op.raw_preattestation - ~delegate:delegate.RPC.Validators.delegate - ~slot - block') - bls_delegates_with_slots - in - let operation = - WithExceptions.Option.get - ~loc:__LOC__ - (Op.aggregate_preattestations preattestations) + let* attested_block = Block.bake attested_block_predecessor in + let* attesters = Context.get_attesters_with_bls_key (B attested_block) in + let attester, other_attester = + match attesters with + | x1 :: x2 :: _ -> (x1, x2) + | _ -> Test.fail ~__LOC__ "Expected at least two attesters with BLS key" in - let* _, (_, receipt) = - let round_zero = Alpha_context.Round.zero in - Block.bake_with_metadata - ~policy:(By_round 1) - ~payload_round:round_zero - ~locked_round:round_zero - ~operation - block + let attesters_to_test = + [ + (* Only duplicate slot *) + [attester; attester]; + (* Duplicate slot first then normal slot *) + [attester; attester; other_attester]; + (* Duplicate slot last *) + [other_attester; attester; attester]; + (* Duplicate slot before and after normal slot *) + [attester; other_attester; attester]; + ] in - let result = find_preattestations_aggregate_result receipt in - let delegates = List.map snd bls_delegates_with_slots in - check_preattestations_aggregate_result ~committee:delegates result + List.iter_es + (fun attesters -> + let* () = + check_preattestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~preattested_block:attested_block + ~preattested_block_predecessor:attested_block_predecessor + ~error:Error_helpers.conflicting_consensus_operation + () + in + check_attestations_aggregate_validation_and_application + ~loc:__LOC__ + ~attesters + ~attested_block + ~error:Error_helpers.conflicting_consensus_operation + ()) + attesters_to_test let test_attestations_aggregate_invalid_signature () = let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - (* Find an attester with a BLS consensus key. *) - let attester, _ = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in - (* Craft an aggregate with a single attestation signed by this delegate *) - let* aggregate = - Op.attestations_aggregate ~committee:[attester.consensus_key] block + let* op = Op.attestations_aggregate block in + let op_with_signature_zero = + Op.set_op_signature op (Some (Bls Signature.Bls.zero)) in - (* Swap the signature for Signature.Bls.zero *) - match aggregate.protocol_data with - | Operation_data {contents; _} -> - let aggregate_with_incorrect_signature = - { - aggregate with - protocol_data = - Operation_data {contents; signature = Some (Bls Signature.Bls.zero)}; - } - in - (* Bake a block containing this operation and expect an error *) - let*! res = - Block.bake ~operation:aggregate_with_incorrect_signature block - in - Assert.proto_error ~loc:__LOC__ res signature_invalid_error + Op.check_validation_and_application_all_modes_different_outcomes + ~loc:__LOC__ + ~application_error:Error_helpers.invalid_signature + ~construction_error:Error_helpers.invalid_signature + ~mempool_error:Error_helpers.aggregate_in_mempool + ~predecessor:block + op_with_signature_zero let test_preattestations_aggregate_invalid_signature () = let open Lwt_result_syntax in @@ -414,38 +540,20 @@ let test_preattestations_aggregate_invalid_signature () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block) in - (* Find an attester with a BLS consensus key. *) - let attester, _ = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) + let* op = Op.preattestations_aggregate block' in + let op_with_signature_zero = + Op.set_op_signature op (Some (Bls Signature.Bls.zero)) in - (* Craft a preattestations_aggregate with this delegate *) - let* aggregate = - Op.preattestations_aggregate ~committee:[attester.consensus_key] block' + let*! res = + let round_zero = Alpha_context.Round.zero in + Block.bake + ~policy:(By_round 1) + ~payload_round:round_zero + ~locked_round:round_zero + ~operation:op_with_signature_zero + block in - (* Swap the aggregate signature for Signature.Bls.zero *) - match aggregate.protocol_data with - | Operation_data {contents; _} -> - let aggregate_with_incorrect_signature = - { - aggregate with - protocol_data = - Operation_data {contents; signature = Some (Bls Signature.Bls.zero)}; - } - in - (* Bake a block containing this operation and expect an error *) - let*! res = - let round_zero = Alpha_context.Round.zero in - Block.bake - ~policy:(By_round 1) - ~payload_round:round_zero - ~locked_round:round_zero - ~operation:aggregate_with_incorrect_signature - block - in - Assert.proto_error ~loc:__LOC__ res signature_invalid_error + Assert.proto_error ~loc:__LOC__ res Error_helpers.invalid_signature let test_preattestations_aggregate_non_bls_delegate () = let open Lwt_result_syntax in @@ -453,20 +561,14 @@ let test_preattestations_aggregate_non_bls_delegate () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in (* Find an attester with a non-BLS consensus key. *) - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_non_bls_key attesters) + let* attesting_slot = + Op.get_attesting_slot_with_non_bls_key ~attested_block:block' in (* Craft a preattestation for this attester to retrieve a signature and a triplet {level, round, block_payload_hash} *) let* {shell; protocol_data = {contents; signature}} = - Op.raw_preattestation - ~delegate:attester.RPC.Validators.delegate - ~slot - block' + Op.raw_preattestation ~attesting_slot block' in match contents with | Single (Preattestation consensus_content) -> @@ -480,7 +582,8 @@ let test_preattestations_aggregate_non_bls_delegate () = in let contents : _ Alpha_context.contents_list = Single - (Preattestations_aggregate {consensus_content; committee = [slot]}) + (Preattestations_aggregate + {consensus_content; committee = [attesting_slot.slot]}) in let operation : operation = {shell; protocol_data = Operation_data {contents; signature}} @@ -495,24 +598,21 @@ let test_preattestations_aggregate_non_bls_delegate () = ~operation block in - Assert.proto_error ~loc:__LOC__ res non_bls_in_aggregate + Assert.proto_error ~loc:__LOC__ res Error_helpers.non_bls_key_in_aggregate let test_attestations_aggregate_non_bls_delegate () = let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in (* Find an attester with a non-BLS consensus key. *) - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_non_bls_key attesters) + let* attesting_slot = + Op.get_attesting_slot_with_non_bls_key ~attested_block:block in (* Craft an attestation for this attester to retrieve a signature and a triplet {level, round, block_payload_hash} *) let* {shell; protocol_data = {contents; signature}} = - Op.raw_attestation ~delegate:attester.RPC.Validators.delegate ~slot block + Op.raw_attestation ~attesting_slot block in let (Single (Attestation @@ -528,43 +628,56 @@ let test_attestations_aggregate_non_bls_delegate () = let contents : _ Alpha_context.contents_list = Single (Attestations_aggregate - {consensus_content; committee = [(slot, dal_content)]}) + {consensus_content; committee = [(attesting_slot.slot, dal_content)]}) in let operation : operation = {shell; protocol_data = Operation_data {contents; signature}} in Op.check_validation_and_application_all_modes_different_outcomes ~loc:__LOC__ - ~application_error:non_bls_in_aggregate - ~construction_error:non_bls_in_aggregate - ~mempool_error:aggregate_in_mempool_error + ~application_error:Error_helpers.non_bls_key_in_aggregate + ~construction_error:Error_helpers.non_bls_key_in_aggregate + ~mempool_error:Error_helpers.aggregate_in_mempool ~predecessor:block operation in - let dal_contents_to_test = - [ - None; - Some Alpha_context.{attestation = Dal.Attestation.empty}; - Some (Dal_helpers.dal_content_of_int ~loc:__LOC__ 1); - Some (Dal_helpers.dal_content_of_int ~loc:__LOC__ 255); - ] + List.iter_es check_non_bls_aggregate_refused Dal_helpers.various_dal_contents + +let test_attestations_aggregate_dal_without_companion_key () = + let open Lwt_result_syntax in + let* _genesis, attested_block = + init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - List.iter_es check_non_bls_aggregate_refused dal_contents_to_test + let* attesting_slot = Op.get_attesting_slot_with_bls_key ~attested_block in + List.iter_es + (fun dal_content -> + let* op = + Op.attestations_aggregate + ~committee:[(attesting_slot, dal_content)] + attested_block + in + Op.check_validation_and_application_all_modes_different_outcomes + ~loc:__LOC__ + ~application_error:Error_helpers.missing_companion_key_for_bls_dal + ~construction_error:Error_helpers.missing_companion_key_for_bls_dal + ~mempool_error:Error_helpers.aggregate_in_mempool + ~predecessor:attested_block + op) + (List.filter Option.is_some Dal_helpers.various_dal_contents) let test_multiple_aggregates_per_block_forbidden () = let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - (* Filter delegates with BLS keys that have at least one slot *) - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in + (* Retrieve delegates with BLS keys that have at least one slot *) + let* committee = Op.default_committee ~attested_block:block in (* Craft one attestations_aggregate per attester *) let* aggregates = List.map_es - (fun (_, (delegate : RPC.Validators.t)) -> - Op.attestations_aggregate ~committee:[delegate.consensus_key] block) - bls_delegates_with_slots + (fun attesting_slot -> + Op.attestations_aggregate ~committee:[(attesting_slot, None)] block) + committee in (* Bake a block containing the multiple aggregates and expect an error *) let*! res = Block.bake ~operations:aggregates block in @@ -572,16 +685,17 @@ let test_multiple_aggregates_per_block_forbidden () = Assert.proto_error ~loc:__LOC__ res - (conflicting_consensus_operation + (Error_helpers.conflicting_consensus_operation ~kind:Validate_errors.Consensus.Attestations_aggregate) in (* Craft one preattestations_aggregate per attester *) let* block' = Block.bake block in + let* committee = Op.default_committee ~attested_block:block' in let* aggregates = List.map_es - (fun (_, (delegate : RPC.Validators.t)) -> - Op.preattestations_aggregate ~committee:[delegate.consensus_key] block') - bls_delegates_with_slots + (fun attesting_slot -> + Op.preattestations_aggregate ~committee:[attesting_slot] block') + committee in (* Bake a block containing the multiple aggregates and expect an error *) let round_zero = Alpha_context.Round.zero in @@ -596,7 +710,7 @@ let test_multiple_aggregates_per_block_forbidden () = Assert.proto_error ~loc:__LOC__ res - (conflicting_consensus_operation + (Error_helpers.conflicting_consensus_operation ~kind:Validate_errors.Consensus.Preattestations_aggregate) let test_eligible_preattestation_must_be_aggregated () = @@ -605,58 +719,52 @@ let test_eligible_preattestation_must_be_aggregated () = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in - let attester = find_attester_with_bls_key attesters in - match attester with - | Some (attester, _) -> - let* operation = - Op.preattestation ~delegate:attester.consensus_key block' - in - (* Operation is valid in the Mempool *) - let* inc = Incremental.begin_construction ~mempool_mode:true block in - let* inc = Incremental.add_operation inc operation in - let* _ = Incremental.finalize_block inc in - (* Operation is invalid in a block *) - let*! res = - let round_zero = Alpha_context.Round.zero in - Block.bake - ~policy:(By_round 1) - ~payload_round:round_zero - ~locked_round:round_zero - ~operation - block - in - Assert.proto_error - ~loc:__LOC__ - res - (unaggregated_eligible_attestation - ~kind:Validate_errors.Consensus.Preattestation) - | _ -> assert false + let* attesting_slot = + Op.get_attesting_slot_with_bls_key ~attested_block:block' + in + let* operation = Op.preattestation ~attesting_slot block' in + (* Operation is valid in the Mempool *) + let* inc = Incremental.begin_construction ~mempool_mode:true block in + let* inc = Incremental.add_operation inc operation in + let* _ = Incremental.finalize_block inc in + (* Operation is invalid in a block *) + let*! res = + let round_zero = Alpha_context.Round.zero in + Block.bake + ~policy:(By_round 1) + ~payload_round:round_zero + ~locked_round:round_zero + ~operation + block + in + Assert.proto_error + ~loc:__LOC__ + res + (Error_helpers.unaggregated_eligible_attestation + ~kind:Validate_errors.Consensus.Preattestation) let test_eligible_attestation_must_be_aggregated () = let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - let attester = find_attester_with_bls_key attesters in - match attester with - | Some (attester, _) -> - let* operation = Op.attestation ~delegate:attester.consensus_key block in - (* Operation is valid in the Mempool *) - let* inc = Incremental.begin_construction ~mempool_mode:true block in - let* inc = Incremental.add_operation inc operation in - let* _ = Incremental.finalize_block inc in - (* Operation is invalid in a block *) - let*! res = Block.bake ~operation block in - Assert.proto_error - ~loc:__LOC__ - res - (unaggregated_eligible_attestation - ~kind:Validate_errors.Consensus.Attestation) - (* TODO: https://gitlab.com/tezos/tezos/-/issues/7827 - Also test this behaviour for attestations with DAL contents. *) - | _ -> assert false + let* attesting_slot = + Op.get_attesting_slot_with_bls_key ~attested_block:block + in + let* operation = Op.attestation ~attesting_slot block in + (* Operation is valid in the Mempool *) + let* inc = Incremental.begin_construction ~mempool_mode:true block in + let* inc = Incremental.add_operation inc operation in + let* _ = Incremental.finalize_block inc in + (* Operation is invalid in a block *) + let*! res = Block.bake ~operation block in + Assert.proto_error + ~loc:__LOC__ + res + (Error_helpers.unaggregated_eligible_attestation + ~kind:Validate_errors.Consensus.Attestation) +(* TODO: https://gitlab.com/tezos/tezos/-/issues/7827 + Also test this behaviour for attestations with DAL contents. *) let test_empty_committee () = let open Lwt_result_syntax in @@ -680,7 +788,12 @@ let test_empty_committee () = let operation = Op.pack_operation (B block) signature (Single contents) in (* Baking with the attestations_aggregate and expecting an error *) let*! res = Block.bake ~operation block in - let* () = Assert.proto_error ~loc:__LOC__ res empty_aggregation_committee in + let* () = + Assert.proto_error + ~loc:__LOC__ + res + Error_helpers.empty_aggregation_committee + in (* Crafting a preattestations_aggregate with an empty committee *) let* consensus_content = let* block = Block.bake block in @@ -706,7 +819,12 @@ let test_empty_committee () = ~operation block in - let* () = Assert.proto_error ~loc:__LOC__ res empty_aggregation_committee in + let* () = + Assert.proto_error + ~loc:__LOC__ + res + Error_helpers.empty_aggregation_committee + in return_unit let test_metadata_committee_is_correctly_ordered () = @@ -716,30 +834,21 @@ let test_metadata_committee_is_correctly_ordered () = in (* Craft an attestations_aggregate including at least 3 delegates *) let* attestations, attestation_committee = - let* attesters = Context.get_attesters (B block) in - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in + let* attesting_slots = Op.default_committee ~attested_block:block in let committee = - List.map - (fun (_slot, (delegate : RPC.Validators.t)) -> delegate.consensus_key) - bls_delegates_with_slots + List.map (fun attesting_slot -> (attesting_slot, None)) attesting_slots in assert (List.length committee > 2) ; let* aggregate = Op.attestations_aggregate ~committee block in - return (aggregate, bls_delegates_with_slots) + return (aggregate, attesting_slots) in (* Craft a preattestations_aggregate including at least 3 delegates *) let* preattestations, preattestation_committee = let* block' = Block.bake block in - let* attesters = Context.get_attesters (B block') in - let bls_delegates_with_slots = filter_attesters_with_bls_key attesters in - let committee = - List.map - (fun (_slot, (delegate : RPC.Validators.t)) -> delegate.consensus_key) - bls_delegates_with_slots - in + let* committee = Op.default_committee ~attested_block:block' in assert (List.length committee > 2) ; let* aggregate = Op.preattestations_aggregate ~committee block' in - return (aggregate, bls_delegates_with_slots) + return (aggregate, committee) in (* Bake a block including both aggregates *) let* _, (_, receipt) = @@ -784,12 +893,12 @@ let test_metadata_committee_is_correctly_ordered () = (fun (slot, _) -> let owner = WithExceptions.Option.get ~loc:__LOC__ - @@ List.assoc - ~equal:Alpha_context.Slot.equal - slot + @@ List.find_opt + (fun attesting_slot -> + Alpha_context.Slot.equal attesting_slot.Op.slot slot) attestation_committee in - owner.consensus_key) + owner.consensus_pkh) committee in check_committees ~loc:__LOC__ committee result_committee @@ -809,12 +918,12 @@ let test_metadata_committee_is_correctly_ordered () = (fun slot -> let owner = WithExceptions.Option.get ~loc:__LOC__ - @@ List.assoc - ~equal:Alpha_context.Slot.equal - slot + @@ List.find_opt + (fun attesting_slot -> + Alpha_context.Slot.equal attesting_slot.Op.slot slot) preattestation_committee in - owner.consensus_key) + owner.consensus_pkh) committee in check_committees ~loc:__LOC__ committee result_committee @@ -822,18 +931,19 @@ let test_metadata_committee_is_correctly_ordered () = in return_unit -let test_preattestation_signature_for_attestation ~block ~delegate = +let test_preattestation_signature_for_attestation ~attested_block + ~attesting_slot = let open Lwt_result_syntax in - let* op_preattestation = Op.preattestation ~delegate block in - let* op_attestation = Op.attestation ~delegate block in + let* op_preattestation = Op.preattestation ~attesting_slot attested_block in + let* op_attestation = Op.attestation ~attesting_slot attested_block in let op_attestation_with_preattestation_signature = Op.copy_op_signature ~src:op_preattestation ~dst:op_attestation in let* () = Op.check_validation_and_application ~loc:__LOC__ - ~predecessor:block - ~error:signature_invalid_error + ~predecessor:attested_block + ~error:Error_helpers.invalid_signature Mempool op_attestation_with_preattestation_signature in @@ -843,8 +953,8 @@ let test_preattestation_signature_for_attestation ~block ~delegate = let* () = Op.check_validation_and_application ~loc:__LOC__ - ~predecessor:block - ~error:signature_invalid_error + ~predecessor:attested_block + ~error:Error_helpers.invalid_signature Mempool op_preattestation_with_attestation_signature in @@ -853,54 +963,37 @@ let test_preattestation_signature_for_attestation ~block ~delegate = let test_preattestation_signature_for_attestation_non_bls () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in - let* block = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B block) in - test_preattestation_signature_for_attestation ~delegate ~block + let* attested_block = Block.bake genesis in + let* attesting_slot = + Op.get_attesting_slot_with_non_bls_key ~attested_block + in + test_preattestation_signature_for_attestation ~attesting_slot ~attested_block let test_preattestation_signature_for_attestation_bls () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - let delegate, _slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in - test_preattestation_signature_for_attestation - ~delegate:delegate.delegate - ~block + let* attesting_slot = Op.get_attesting_slot_with_bls_key ~attested_block in + test_preattestation_signature_for_attestation ~attesting_slot ~attested_block let test_signature_bls_attestation_with_different_slot () = - let find_attester_slots_with_bls_key attesters = - List.find_map - (fun (attester : RPC.Validators.t) -> - match attester.consensus_key with - | Bls _ -> Some (attester, attester.slots) - | _ -> None) - attesters - in let open Lwt_result_syntax in let* _genesis, block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - let delegate, slots = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_slots_with_bls_key attesters) - in + let* attester = Context.get_attester_with_bls_key (B block) in + let consensus_pkh = attester.consensus_key in let slot1, slot2 = - match slots with + match attester.slots with | slot1 :: slot2 :: _ -> (slot1, slot2) | _ -> Test.fail ~__LOC__ "Delegate must have at least two slots" in let* op_attestation1 = - Op.attestation ~slot:slot1 ~delegate:delegate.delegate block + Op.attestation ~attesting_slot:{slot = slot1; consensus_pkh} block in let* op_attestation2 = - Op.attestation ~slot:slot2 ~delegate:delegate.delegate block + Op.attestation ~attesting_slot:{slot = slot2; consensus_pkh} block in Assert.equal ~loc:__LOC__ @@ -912,22 +1005,17 @@ let test_signature_bls_attestation_with_different_slot () = let test_signature_bls_attestation_with_different_level () = let open Lwt_result_syntax in - let* _genesis, block = + let* _genesis, attested_block = init_genesis_with_some_bls_accounts ~aggregate_attestation:true () in - let* attesters = Context.get_attesters (B block) in - let delegate, _slot = - WithExceptions.Option.get - ~loc:__LOC__ - (find_attester_with_bls_key attesters) - in - let*? level1 = Context.get_level (B block) in + let* attesting_slot = Op.get_attesting_slot_with_bls_key ~attested_block in + let*? level1 = Context.get_level (B attested_block) in let level2 = Alpha_context.Raw_level.add level1 1 in let* op_attestation1 = - Op.attestation ~level:level1 ~delegate:delegate.delegate block + Op.attestation ~level:level1 ~attesting_slot attested_block in let* op_attestation2 = - Op.attestation ~level:level2 ~delegate:delegate.delegate block + Op.attestation ~level:level2 ~attesting_slot attested_block in Assert.not_equal ~loc:__LOC__ @@ -963,6 +1051,9 @@ let tests = "test_attestations_aggregate_with_multiple_delegates" `Quick test_attestations_aggregate_with_multiple_delegates; + Tztest.tztest "KO non canonical slot" `Quick test_non_canonical_slot; + Tztest.tztest "KO not owned slot" `Quick test_not_owned_slot; + Tztest.tztest "KO duplicate slot" `Quick test_duplicate_slot; Tztest.tztest "test_preattestations_aggregate_invalid_signature" `Quick @@ -979,6 +1070,10 @@ let tests = "test_attestations_aggregate_non_bls_delegate" `Quick test_attestations_aggregate_non_bls_delegate; + Tztest.tztest + "KO DAL without companion key" + `Quick + test_attestations_aggregate_dal_without_companion_key; Tztest.tztest "test_multiple_aggregates_per_block_forbidden" `Quick diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_attestation.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_attestation.ml index 4bb92874260c..971d9c7b2cdd 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_attestation.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_attestation.ml @@ -143,13 +143,15 @@ let test_negative_slot () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in + let* attester = Context.get_attester (B b) in Lwt.catch (fun () -> let* (_ : packed_operation) = + let slot = + Slot.Internal_for_tests.of_int_unsafe_only_use_for_tests (-1) + in Op.attestation - ~delegate - ~slot:(Slot.Internal_for_tests.of_int_unsafe_only_use_for_tests (-1)) + ~attesting_slot:{slot; consensus_pkh = attester.consensus_key} b in failwith "negative slot should not be accepted by the binary format") @@ -162,38 +164,34 @@ let test_negative_slot () = let test_not_smallest_slot () = let open Lwt_result_syntax in let* _genesis, b = init_genesis () in - let* delegate, slot = delegate_and_second_slot b in + let* attesting_slot = Op.get_non_canonical_attesting_slot ~attested_block:b in Consensus_helpers.test_consensus_operation_all_modes_different_outcomes ~loc:__LOC__ ~attested_block:b - ~delegate - ~slot + ~attesting_slot ~application_error:error_wrong_slot ~construction_error:error_wrong_slot ~mempool_error:error_wrong_slot Attestation -let delegate_and_someone_elses_slot block = +let attesting_slot_with_someone_elses_slot block = let open Lwt_result_syntax in let* attesters = Context.get_attesters (B block) in - let delegate, other_delegate_slot = - match attesters with - | [] | [_] -> assert false (* at least two delegates with rights *) - | {delegate; _} :: {slots; _} :: _ -> - (delegate, WithExceptions.Option.get ~loc:__LOC__ (List.hd slots)) - in - return (delegate, other_delegate_slot) + 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} (** Attestation with a slot that does not belong to the delegate. *) let test_not_own_slot () = let open Lwt_result_syntax in let* _genesis, b = init_genesis () in - let* delegate, other_delegate_slot = delegate_and_someone_elses_slot b in + let* attesting_slot = attesting_slot_with_someone_elses_slot b in Consensus_helpers.test_consensus_operation_all_modes ~loc:__LOC__ ~attested_block:b - ~delegate - ~slot:other_delegate_slot + ~attesting_slot ~error:(function | Alpha_context.Operation.Invalid_signature -> true | _ -> false) Attestation @@ -206,12 +204,11 @@ let test_mempool_not_own_slot () = let* predecessor = Block.bake grandparent ~policy:(By_round 1) in let* future_block = Block.bake predecessor in let check_not_own_slot_fails loc b = - let* delegate, other_delegate_slot = delegate_and_someone_elses_slot b in + let* attesting_slot = attesting_slot_with_someone_elses_slot b in Consensus_helpers.test_consensus_operation ~loc ~attested_block:b - ~delegate - ~slot:other_delegate_slot + ~attesting_slot ~error:(function | Alpha_context.Operation.Invalid_signature -> true | _ -> false) Attestation @@ -599,22 +596,23 @@ let test_attestation_threshold ~sufficient_threshold () = let* {parametric = {consensus_threshold_size; _}; _} = Context.get_constants (B b) in - let* attesters_list = Context.get_attesters (B b) 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) {Plugin.RPC.Validators.delegate; slots; _} -> - let new_counter = counter + List.length slots in + (fun (counter, attestations) (attester : Context.attester) -> + let new_counter = counter + List.length attester.slots in if (sufficient_threshold && counter < consensus_threshold_size) || (not sufficient_threshold) && new_counter < consensus_threshold_size then - let* attestation = Op.attestation ~round ~delegate b in + let attesting_slot = Op.attesting_slot_of_attester attester in + let* attestation = Op.attestation ~attesting_slot ~round b in return (new_counter, attestation :: attestations) else return (counter, attestations)) (0, []) - attesters_list + attesters in let*! b = Block.bake ~operations:attestations b in if sufficient_threshold then return_unit @@ -700,7 +698,7 @@ let test_attester_with_no_assigned_shards () = let* has_assigned_shards = Dal_helpers.has_assigned_shards (B b) pkh in if in_committee && not has_assigned_shards then let dal_content = {attestation = Dal.Attestation.empty} in - let* op = Op.attestation ~delegate:pkh ~dal_content b in + let* op = Op.attestation ~manager_pkh:pkh ~dal_content b in let* ctxt = Incremental.begin_construction b in let expect_apply_failure = function | [ @@ -770,7 +768,7 @@ let test_dal_attestation_threshold () = List.fold_left_es (fun (acc_ops, acc_power) ({delegate; indexes} : RPC.Dal.S.shards_assignment) -> - let* op = Op.attestation ~delegate ~dal_content b in + let* op = Op.attestation ~manager_pkh:delegate ~dal_content b in let ops = op :: acc_ops in let power = acc_power + List.length indexes in let* _b, (metadata, _ops) = @@ -798,8 +796,10 @@ let slot_substitution_do_not_affect_signature_check () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in - let* signer = Account.find delegate in + let* {Context.consensus_key = consensus_pkh; _} = + Context.get_attester (B b) + in + let* signer = Account.find consensus_pkh in let watermark = Operation.to_watermark (Attestation Chain_id.zero) in let slot_swap_and_check_signature slot ({shell = {branch}; protocol_data = {contents; _}} : @@ -832,7 +832,7 @@ let slot_substitution_do_not_affect_signature_check () = else Test.fail "Unexpected signature check failure" in let* attestation_without_dal = - Op.raw_attestation ~delegate ~slot:Slot.zero b + Op.raw_attestation ~attesting_slot:{slot = Slot.zero; consensus_pkh} b in let* () = slot_swap_and_check_signature @@ -842,9 +842,8 @@ let slot_substitution_do_not_affect_signature_check () = let* attestation_with_dal = (* attestation with dal signed with slot zero *) Op.raw_attestation + ~attesting_slot:{slot = Slot.zero; consensus_pkh} ~dal_content:{attestation = Dal.Attestation.empty} - ~delegate - ~slot:Slot.zero b in let* () = @@ -861,8 +860,8 @@ let encoding_incompatibility () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in - let* signer = Account.find delegate in + let* attester = Context.get_attester (B b) in + let* signer = Account.find attester.consensus_key in let check_encodings_incompatibily ({shell = {branch}; protocol_data = {contents; signature = _}} : Kind.attestation operation) = @@ -921,12 +920,13 @@ let encoding_incompatibility () = then Test.fail "Unexpected signature check success (bytes_without_slot)" else return_unit in - let* raw_attestation_without_dal = Op.raw_attestation ~delegate b in + let attesting_slot = Op.attesting_slot_of_attester attester in + let* raw_attestation_without_dal = Op.raw_attestation ~attesting_slot b in let* () = check_encodings_incompatibily raw_attestation_without_dal in let* raw_attestation_with_dal = Op.raw_attestation + ~attesting_slot ~dal_content:{attestation = Dal.Attestation.empty} - ~delegate b in let* () = check_encodings_incompatibily raw_attestation_with_dal in diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_baking.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_baking.ml index 6f176e366bc2..35e7eda876b3 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_baking.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_baking.ml @@ -221,12 +221,6 @@ let test_rewards_block_and_payload_producer () = let* baker_b1_contract = get_contract_for_pkh contracts baker_b1 in let* b1 = Block.bake ~policy:(By_round 0) genesis in let* attesters = Context.get_attesters (B b1) in - let* attesters = - List.map_es - (function - | {Plugin.RPC.Validators.delegate; slots; _} -> return (delegate, slots)) - attesters - in (* We let just a part of the attesters vote; we assume here that 5 of 10 attesters will have together at least one slot (to pass the threshold), but not all slots (to make the test more interesting, otherwise we know the @@ -234,12 +228,16 @@ let test_rewards_block_and_payload_producer () = let attesters = List.take_n 5 attesters in let* attestations = List.map_ep - (fun (attester, _slots) -> Op.attestation ~delegate:attester b1) + (fun attester -> + Op.attestation + ~attesting_slot:(Op.attesting_slot_of_attester attester) + b1) attesters in let attesting_power = List.fold_left - (fun acc (_pkh, slots) -> acc + List.length slots) + (fun acc attester -> + acc + List.length attester.Plugin.RPC.Validators.slots) 0 attesters in @@ -276,16 +274,13 @@ let test_rewards_block_and_payload_producer () = correspond to a slot of [baker_b2] and it includes the PQC for [b2]. We check that the fixed baking reward goes to the payload producer [baker_b2], while the bonus goes to the the block producer (aka baker) [baker_b2']. *) - let* attesters = Context.get_attesters (B b2) in - let* preattesters = - List.map_es - (function - | {Plugin.RPC.Validators.delegate; slots; _} -> return (delegate, slots)) - attesters - in + let* preattesters = Context.get_attesters (B b2) in let* preattestations = List.map_ep - (fun (attester, _slots) -> Op.preattestation ~delegate:attester b2) + (fun attester -> + Op.preattestation + ~attesting_slot:(Op.attesting_slot_of_attester attester) + b2) preattesters in let* baker_b2 = Context.get_baker (B b1) ~round:Round.zero in diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_consensus_key.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_consensus_key.ml index 7e9fcdf580e7..7d3b84bb82a9 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_consensus_key.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_consensus_key.ml @@ -351,8 +351,8 @@ let test_consensus_key_with_unused_proof () = let test_attestation_with_consensus_key () = let open Lwt_result_wrap_syntax in - let* genesis, contracts = Context.init_with_constants1 constants in - let account1_pkh = Context.Contract.pkh contracts in + let* genesis, contract = Context.init_with_constants1 constants in + let account1_pkh = Context.Contract.pkh contract in let consensus_account = Account.new_account () in let delegate = account1_pkh in let consensus_pk = consensus_account.pk in @@ -362,15 +362,18 @@ let test_attestation_with_consensus_key () = in let* b_pre = update_consensus_key blk' delegate consensus_pk in let* b = Block.bake b_pre in + (* There is only one delegate, so its minimal slot is zero. *) let*?@ slot = Slot.of_int 0 in - let* attestation = Op.attestation ~delegate:account1_pkh ~slot b in + let* attestation = + Op.attestation ~attesting_slot:{slot; consensus_pkh = account1_pkh} b + in let*! res = Block.bake ~operation:attestation b in let* () = Assert.proto_error ~loc:__LOC__ res (function | Operation.Invalid_signature -> true | _ -> false) in - let* attestation = Op.attestation ~delegate:consensus_pkh ~slot b in + let* attestation = Op.attestation ~attesting_slot:{slot; consensus_pkh} b in let* (_good_block : Block.t) = Block.bake ~operation:attestation b in return_unit diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_dal_entrapment.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_dal_entrapment.ml index 63b659c1f999..4a6917e44a97 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_dal_entrapment.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_dal_entrapment.ml @@ -196,18 +196,11 @@ let test_accusation_injection ?initial_blocks_to_bake ?expect_failure | None -> Test.fail ~__LOC__ "Unexpected case: there are no delegates" | Some (pkh, _) -> pkh in - let* attestation = Op.raw_attestation blk ~delegate ?dal_content in + let* attester = Context.get_attester ~manager_pkh:delegate (B blk) in + let attesting_slot = Op.attesting_slot_of_attester attester in + let* attestation = Op.raw_attestation blk ~attesting_slot ?dal_content in + let consensus_slot = attesting_slot.slot in let attestation_level = blk.header.shell.level in - let* consensus_slot = - let+ all_slots = Context.get_attester_slot (B blk) delegate in - let fst_slot = Option.bind all_slots List.hd in - match fst_slot with - | None -> - Test.fail - ~__LOC__ - "Unexpected case: delegate is not in attestation committee" - | Some slot -> slot - in let* blk = let blocks_to_bake = diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_attestation.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_attestation.ml index 6b7de5ae18dc..0ff785e2607c 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_attestation.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_attestation.ml @@ -117,9 +117,9 @@ let test_valid_double_attestation_evidence () = are identical. *) let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* bakers = Context.get_bakers (B blk_a) in let baker = Context.get_first_different_baker delegate bakers in @@ -233,16 +233,16 @@ let test_different_branch () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init2 ~consensus_threshold_size:0 () in let* blk = Block.bake genesis in - let* attester, _slots = Context.get_attester (B blk) in - let* attestation_a = Op.raw_attestation ~delegate:attester blk in + let* {Context.delegate = manager_pkh; _} = Context.get_attester (B blk) in + let* attestation_a = Op.raw_attestation ~manager_pkh blk in let* attestation_b = - Op.raw_attestation ~branch:Block_hash.zero ~delegate:attester blk + Op.raw_attestation ~branch:Block_hash.zero ~manager_pkh blk in let operation = double_attestation (B blk) attestation_a attestation_b in let* _blk = Block.bake ~operation blk in - let* preattestation_a = Op.raw_preattestation ~delegate:attester blk in + let* preattestation_a = Op.raw_preattestation ~manager_pkh blk in let* preattestation_b = - Op.raw_preattestation ~branch:Block_hash.zero ~delegate:attester blk + Op.raw_preattestation ~branch:Block_hash.zero ~manager_pkh blk in let operation = double_preattestation (B blk) preattestation_a preattestation_b @@ -258,24 +258,30 @@ let test_different_slots () = 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 delegate, slot1, slot2 = + let consensus_pkh, slot1, slot2 = (* Find an attester with more than 1 slot. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map (fun (attester : RPC.Validators.t) -> match attester.slots with - | slot1 :: slot2 :: _ -> Some (attester.delegate, slot1, slot2) + | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) | _ -> None) attesters) in - let* attestation1 = Op.raw_attestation ~delegate ~slot:slot1 blk in - let* attestation2 = Op.raw_attestation ~delegate ~slot:slot2 blk 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 + let* attestation2 = Op.raw_attestation ~attesting_slot:attesting_slot2 blk in let double_attestation = double_attestation (B blk) attestation1 attestation2 in - let* preattestation1 = Op.raw_preattestation ~delegate ~slot:slot1 blk in - let* preattestation2 = Op.raw_preattestation ~delegate ~slot:slot2 blk in + let* preattestation1 = + Op.raw_preattestation ~attesting_slot:attesting_slot1 blk + in + let* preattestation2 = + Op.raw_preattestation ~attesting_slot:attesting_slot2 blk + in let double_preattestation = double_preattestation (B blk) preattestation1 preattestation2 in @@ -309,9 +315,9 @@ let test_two_double_attestation_evidences_leadsto_no_bake () = let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* bakers = Context.get_bakers (B blk_a) in let baker = Context.get_first_different_baker delegate bakers in @@ -324,8 +330,8 @@ let test_two_double_attestation_evidences_leadsto_no_bake () = let* blk_30, blk_40 = block_fork ~excluding:[delegate] blk_with_evidence1 in let* blk_3 = Block.bake ~policy:(Excluding [delegate]) blk_30 in let* blk_4 = Block.bake ~policy:(Excluding [delegate]) blk_40 in - let* attestation_3 = Op.raw_attestation ~delegate blk_3 in - let* attestation_4 = Op.raw_attestation ~delegate blk_4 in + let* attestation_3 = Op.raw_attestation ~manager_pkh:delegate blk_3 in + let* attestation_4 = Op.raw_attestation ~manager_pkh:delegate blk_4 in let operation = double_attestation (B blk_with_evidence1) attestation_3 attestation_4 in @@ -418,9 +424,9 @@ let test_two_double_attestation_evidences_staggered () = let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* bakers = Context.get_bakers (B blk_a) in let baker = Context.get_first_different_baker delegate bakers in @@ -434,8 +440,8 @@ let test_two_double_attestation_evidences_staggered () = let* blk_30, blk_40 = block_fork ~excluding:[delegate] blk_with_evidence1 in let* blk_3 = Block.bake ~policy:(Excluding [delegate]) blk_30 in let* blk_4 = Block.bake ~policy:(Excluding [delegate]) blk_40 in - let* attestation_3 = Op.raw_attestation ~delegate blk_3 in - let* attestation_4 = Op.raw_attestation ~delegate blk_4 in + let* attestation_3 = Op.raw_attestation ~manager_pkh:delegate blk_3 in + let* attestation_4 = Op.raw_attestation ~manager_pkh:delegate blk_4 in let operation_evidence2 = double_attestation (B blk_with_evidence1) attestation_3 attestation_4 in @@ -493,9 +499,9 @@ let test_two_double_attestation_evidences_consecutive_cycles () = let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* bakers = Context.get_bakers (B blk_a) in let baker = Context.get_first_different_baker delegate bakers in @@ -520,8 +526,8 @@ let test_two_double_attestation_evidences_consecutive_cycles () = let* blk_30, blk_40 = block_fork ~excluding:[delegate] blk_new_cycle in let* blk_3 = Block.bake ~policy:(Excluding [delegate]) blk_30 in let* blk_4 = Block.bake ~policy:(Excluding [delegate]) blk_40 in - let* attestation_3 = Op.raw_attestation ~delegate blk_3 in - let* attestation_4 = Op.raw_attestation ~delegate blk_4 in + let* attestation_3 = Op.raw_attestation ~manager_pkh:delegate blk_3 in + let* attestation_4 = Op.raw_attestation ~manager_pkh:delegate blk_4 in let operation = double_attestation (B blk_new_cycle) attestation_3 attestation_4 in @@ -614,23 +620,16 @@ let test_invalid_double_attestation_duplicate_in_committee () = let* blk_1, blk_2 = block_fork b in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* attesters = Context.get_attesters (B blk_a) in - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (Test_aggregate.find_attester_with_bls_key attesters) - in - let* op1 = - Op.raw_attestation ~delegate:attester.RPC.Validators.delegate ~slot blk_a + let* attesting_slot = + Op.get_attesting_slot_with_bls_key ~attested_block:blk_a in - let* op2_standalone = - Op.raw_attestation ~delegate:attester.RPC.Validators.delegate ~slot blk_b - in - let op2 = - WithExceptions.Option.get - ~loc:__LOC__ - (Op.raw_aggregate [op2_standalone; op2_standalone]) + let* op1 = Op.raw_attestation ~attesting_slot blk_a in + let* op2 = + Op.raw_attestations_aggregate + ~committee:[(attesting_slot, None); (attesting_slot, None)] + blk_b in + let slot = attesting_slot.slot in let op = let contents = if Operation_hash.(Operation.hash op1 < Operation.hash op2) then @@ -653,7 +652,7 @@ let test_invalid_double_attestation_duplicate_in_committee () = op in (* Also check with duplicate slots with different dal contents *) - let* op2_standalone' = + let* op2 = let number_of_slots = Default_parameters.constants_test.dal.number_of_slots in @@ -661,17 +660,10 @@ let test_invalid_double_attestation_duplicate_in_committee () = let dal_content = {attestation = Dal.Attestation.(commit empty slot_index)} in - Op.raw_attestation - ~delegate:attester.RPC.Validators.delegate - ~slot - ~dal_content + Op.raw_attestations_aggregate + ~committee:[(attesting_slot, None); (attesting_slot, Some dal_content)] blk_b in - let op2 = - WithExceptions.Option.get - ~loc:__LOC__ - (Op.raw_aggregate [op2_standalone; op2_standalone']) - in let op = let contents = if Operation_hash.(Operation.hash op1 < Operation.hash op2) then @@ -744,8 +736,16 @@ let test_different_delegates () = let* attester_a, attester_b = Context.get_first_different_attesters (B blk_b) in - let* e_a = Op.raw_attestation ~delegate:attester_a.delegate blk_a in - let* e_b = Op.raw_attestation ~delegate:attester_b.delegate blk_b in + let* e_a = + Op.raw_attestation + ~attesting_slot:(Op.attesting_slot_of_attester attester_a) + blk_a + in + let* e_b = + Op.raw_attestation + ~attesting_slot:(Op.attesting_slot_of_attester attester_b) + blk_b + in let* (_ : Block.t) = Block.bake ~operation:(Operation.pack e_b) blk_b in double_attestation (B blk_b) e_a e_b |> fun operation -> let*! res = Block.bake ~operation blk_b in @@ -755,46 +755,8 @@ let test_different_delegates () = true | _ -> false) -(** Check that a double attestation evidence that exposes a ill-formed - attestation fails. *) -let test_wrong_delegate () = - let open Lwt_result_syntax in - let* genesis, _contracts = Context.init2 ~consensus_threshold_size:0 () in - let* blk_1, blk_2 = block_fork genesis in - let* blk_a = Block.bake blk_1 in - let* blk_b = Block.bake blk_2 in - let* attester_a, _a_slots = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate:attester_a blk_a in - let* attester0, _slots0 = Context.get_attester_n (B blk_b) 0 in - let* attester1, _slots1 = Context.get_attester_n (B blk_b) 1 in - let attester_b = - if Signature.Public_key_hash.equal attester_a attester0 then attester1 - else attester0 - in - let* attestation_b = Op.raw_attestation ~delegate:attester_b blk_b in - double_attestation (B blk_b) attestation_a attestation_b |> fun operation -> - let*! res = Block.bake ~operation blk_b in - Assert.proto_error ~loc:__LOC__ res (function - | Validate_errors.Anonymous.Invalid_denunciation - Misbehaviour.Double_attesting -> - true - | _ -> false) - let test_freeze_more_with_low_balance = let open Lwt_result_syntax in - let get_attesting_slots_for_account ctxt account = - (* Get the slots of the given account in the given context. *) - let* attesters_list = Context.get_attesters ctxt in - match attesters_list with - | [d1; d2] -> - return - (if Signature.Public_key_hash.equal account d1.delegate then d1 - else if Signature.Public_key_hash.equal account d2.delegate then d2 - else assert false) - .slots - | _ -> assert false - (* there are exactly two attesters for this test. *) - in let double_attest_and_punish b2 account1 = let open Lwt_result_syntax in (* Bake a block on top of [b2] that includes a double-attestation @@ -802,16 +764,8 @@ let test_freeze_more_with_low_balance = let* blk_d1, blk_d2 = block_fork b2 in let* blk_a = Block.bake ~policy:(Block.By_account account1) blk_d1 in let* blk_b = Block.bake ~policy:(Block.By_account account1) blk_d2 in - let* slots_a = get_attesting_slots_for_account (B blk_a) account1 in - let slot = - match List.hd slots_a with None -> assert false | Some s -> s - in - let* attestation_a = Op.raw_attestation ~delegate:account1 ~slot blk_a in - let* slots_b = get_attesting_slots_for_account (B blk_b) account1 in - let slot = - match List.hd slots_b with None -> assert false | Some s -> s - in - let* attestation_b = Op.raw_attestation ~delegate:account1 ~slot blk_b in + let* attestation_a = Op.raw_attestation ~manager_pkh:account1 blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:account1 blk_b in let denunciation = double_attestation (B b2) attestation_a attestation_b in let* b = Block.bake ~policy:(Excluding [account1]) b2 ~operations:[denunciation] @@ -983,9 +937,9 @@ let test_two_double_attestation_evidences_leads_to_duplicate_denunciation () = let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let operation2 = double_attestation (B genesis) attestation_b attestation_a in let* bakers = Context.get_bakers (B blk_a) in @@ -1028,19 +982,25 @@ let different_slots_under_feature_flag () = in let* block = Block.bake genesis in let* attesters = Context.get_attesters (B block) in - let delegate, slot1, slot2 = + let consensus_pkh, slot1, slot2 = (* Find an attester with more than 1 slot. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map (fun (attester : RPC.Validators.t) -> match attester.slots with - | slot1 :: slot2 :: _ -> Some (attester.delegate, slot1, slot2) + | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) | _ -> None) attesters) in - let* attestation1 = Op.raw_attestation ~delegate ~slot:slot1 block in - let* attestation2 = Op.raw_attestation ~delegate ~slot:slot2 block 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 block + in + let* attestation2 = + Op.raw_attestation ~attesting_slot:attesting_slot2 block + in let double_attestation_evidence = double_attestation (B block) attestation1 attestation2 in @@ -1107,7 +1067,6 @@ let tests = `Quick test_too_late_double_attestation_evidence; Tztest.tztest "different delegates" `Quick test_different_delegates; - Tztest.tztest "wrong delegate" `Quick test_wrong_delegate; Tztest.tztest "different slots under feature flag" `Quick diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_baking.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_baking.ml index 9861c08b0d94..f0b748e59b82 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_baking.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_baking.ml @@ -193,8 +193,8 @@ let test_valid_double_baking_followed_by_double_attesting () = if Signature.Public_key_hash.( = ) e1.delegate baker1 then e1.delegate else e2.delegate in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* blk_final = Block.bake ~policy:(By_account baker2) ~operation blk_with_db_evidence @@ -271,8 +271,8 @@ let test_valid_double_attesting_followed_by_double_baking () = if Signature.Public_key_hash.( = ) e1.delegate baker1 then e1.delegate else e2.delegate in - let* attestation_a = Op.raw_attestation ~delegate blk_a in - let* attestation_b = Op.raw_attestation ~delegate blk_b in + let* attestation_a = Op.raw_attestation ~manager_pkh:delegate blk_a in + let* attestation_b = Op.raw_attestation ~manager_pkh:delegate blk_b in let operation = double_attestation (B genesis) attestation_a attestation_b in let* blk_with_de_evidence = Block.bake ~policy:(By_account baker2) ~operation blk_a @@ -365,7 +365,7 @@ let test_payload_producer_gets_evidence_rewards () = let* preattestations = List.map_ep (fun (attester, _slots) -> - Op.preattestation ~delegate:attester b_with_evidence) + Op.preattestation ~manager_pkh:attester b_with_evidence) preattesters in let* b' = diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_preattestation.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_preattestation.ml index 30f50193066e..a58fdff69ec8 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_preattestation.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_double_preattestation.ml @@ -57,15 +57,6 @@ end = struct (** Helper function for illformed denunciations construction *) - let pick_attesters ctxt = - let open Lwt_result_syntax in - let module V = Plugin.RPC.Validators in - let* validators_list = Context.get_attesters ctxt in - match validators_list with - | a :: b :: _ -> - return ((a.V.delegate, a.V.slots), (b.V.delegate, b.V.slots)) - | _ -> assert false - let invalid_denunciation loc res = Assert.proto_error ~loc res (function | Validate_errors.Anonymous.Invalid_denunciation @@ -209,11 +200,7 @@ end = struct let generic_double_preattestation_denunciation ~nb_blocks_before_double ~nb_blocks_before_denunciation ~test_expected_ok ?(test_expected_ko = fun _loc _res -> Lwt_result_syntax.return_unit) - ?(pick_attesters = - let open Lwt_result_syntax in - fun ctxt -> - let* a, _b = pick_attesters ctxt in - return (a, a)) ~loc () = + ?(different_attesters = false) ~loc () = let open Lwt_result_syntax in let* genesis, contracts = Context.init_n @@ -232,10 +219,19 @@ end = struct let* trans = Op.transaction (B genesis) addr addr Tez.one_mutez in let* head_A = bake ~policy:(By_round 0) blk in let* head_B = bake ~policy:(By_round 0) blk ~operations:[trans] in - let* (d1, _slots1), (d2, _slots2) = pick_attesters (B head_A) in - (* default: d1 = d2 *) - let* op1 = Op.raw_preattestation ~delegate:d1 head_A in - let* op2 = Op.raw_preattestation ~delegate:d2 head_B in + (* By default, [different_attesters] is false so [d1 = d2]. *) + let* d1, d2 = + if different_attesters then + let* attester1, attester2 = + Context.get_first_different_attesters (B head_A) + in + return (attester1.delegate, attester2.delegate) + else + let* attester = Context.get_attester (B head_A) in + return (attester.delegate, attester.delegate) + in + let* op1 = Op.raw_preattestation ~manager_pkh:d1 head_A in + let* op2 = Op.raw_preattestation ~manager_pkh:d2 head_B in let op1, op2 = order_preattestations ~correct_order:true op1 op2 in (* bake `nb_blocks_before_denunciation` before double preattestation denunciation *) let* blk = bake_n nb_blocks_before_denunciation blk in @@ -302,7 +298,7 @@ end = struct ~nb_blocks_before_denunciation:2 ~test_expected_ok:unexpected_success ~test_expected_ko:invalid_denunciation - ~pick_attesters (* pick different attesters *) + ~different_attesters:true ~loc:__LOC__ () @@ -361,9 +357,9 @@ end = struct let* blk_1, blk_2 = block_fork genesis in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* delegate, _ = Context.get_attester (B blk_a) in - let* preattestation_a = Op.raw_preattestation ~delegate blk_a in - let* preattestation_b = Op.raw_preattestation ~delegate blk_b in + let* {Context.delegate; _} = Context.get_attester (B blk_a) in + let* preattestation_a = Op.raw_preattestation ~manager_pkh:delegate blk_a in + let* preattestation_b = Op.raw_preattestation ~manager_pkh:delegate blk_b in let operation = double_preattestation (B genesis) preattestation_a preattestation_b in @@ -406,19 +402,25 @@ end = struct in let* block = Block.bake genesis in let* attesters = Context.get_attesters (B block) in - let delegate, slot1, slot2 = + let consensus_pkh, slot1, slot2 = (* Find an attester with more than 1 slot. *) WithExceptions.Option.get ~loc:__LOC__ (List.find_map (fun (attester : RPC.Validators.t) -> match attester.slots with - | slot1 :: slot2 :: _ -> Some (attester.delegate, slot1, slot2) + | slot1 :: slot2 :: _ -> Some (attester.consensus_key, slot1, slot2) | _ -> None) attesters) in - let* preattestation1 = Op.raw_preattestation ~delegate ~slot:slot1 block in - let* preattestation2 = Op.raw_preattestation ~delegate ~slot:slot2 block in + let attesting_slot1 = {Op.slot = slot1; consensus_pkh} in + let attesting_slot2 = {Op.slot = slot2; consensus_pkh} in + let* preattestation1 = + Op.raw_preattestation ~attesting_slot:attesting_slot1 block + in + let* preattestation2 = + Op.raw_preattestation ~attesting_slot:attesting_slot2 block + in let double_preattestation_evidence = double_preattestation (B block) preattestation1 preattestation2 in @@ -450,29 +452,16 @@ end = struct let* blk_1, blk_2 = block_fork b in let* blk_a = Block.bake blk_1 in let* blk_b = Block.bake blk_2 in - let* attesters = Context.get_attesters (B blk_a) in - let attester, slot = - WithExceptions.Option.get - ~loc:__LOC__ - (Test_aggregate.find_attester_with_bls_key attesters) - in - let* op1 = - Op.raw_preattestation - ~delegate:attester.RPC.Validators.delegate - ~slot - blk_a + let* attesting_slot = + Op.get_attesting_slot_with_bls_key ~attested_block:blk_a in - let* op2_standalone = - Op.raw_preattestation - ~delegate:attester.RPC.Validators.delegate - ~slot + let* op1 = Op.raw_preattestation ~attesting_slot blk_a in + let* op2 = + Op.raw_preattestations_aggregate + ~committee:[attesting_slot; attesting_slot] blk_b in - let op2 = - WithExceptions.Option.get - ~loc:__LOC__ - (Op.raw_aggregate_preattestations [op2_standalone; op2_standalone]) - in + let slot = attesting_slot.slot in let op = let contents = if Operation_hash.(Operation.hash op1 < Operation.hash op2) then diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_frozen_deposits.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_frozen_deposits.ml index ebc314886157..34a662fa743e 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_frozen_deposits.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_frozen_deposits.ml @@ -278,10 +278,10 @@ let test_may_not_bake_again_after_full_deposit_slash () = in let* blk_b = Block.bake ~policy:(By_account slashed_account) genesis in let* preattestation1 = - Op.raw_preattestation ~delegate:slashed_account blk_a + Op.raw_preattestation ~manager_pkh:slashed_account blk_a in let* preattestation2 = - Op.raw_preattestation ~delegate:slashed_account blk_b + Op.raw_preattestation ~manager_pkh:slashed_account blk_b in let preattestation1, preattestation2 = order_ops preattestation1 preattestation2 @@ -307,8 +307,8 @@ let test_may_not_bake_again_after_full_deposit_slash () = in let* blk_a = Block.bake ~policy:(By_account slashed_account) ~operation b in let* blk_b = Block.bake ~policy:(By_account slashed_account) b in - let* attestation1 = Op.raw_attestation ~delegate:slashed_account blk_a in - let* attestation2 = Op.raw_attestation ~delegate:slashed_account blk_b in + let* attestation1 = Op.raw_attestation ~manager_pkh:slashed_account blk_a in + let* attestation2 = Op.raw_attestation ~manager_pkh:slashed_account blk_b in let attestation1, attestation2 = order_ops attestation1 attestation2 in let double_attestation_op = Op.double_attestation (B blk_a) attestation1 attestation2 diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_participation.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_participation.ml index a156cc546b9f..6b3a3167bedc 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_participation.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_participation.ml @@ -37,24 +37,12 @@ open Alpha_context (** [baker] bakes and [attester] attests *) let bake_and_attest_once (_b_pred, b_cur) baker attester = let open Lwt_result_wrap_syntax in - let open Context in - let* attesters_list = Context.get_attesters (B b_cur) in - List.find_map - (function - | {Plugin.RPC.Validators.delegate; slots; _} -> - if Signature.Public_key_hash.equal delegate attester then - Some (delegate, slots) - else None) - attesters_list - |> function - | None -> assert false - | Some (delegate, _slots) -> - let*?@ round = Block.get_round b_cur in - let* attestation = Op.attestation ~round ~delegate b_cur in - Block.bake_with_metadata - ~policy:(By_account baker) - ~operation:attestation - b_cur + let*?@ round = Block.get_round b_cur in + let* attestation = Op.attestation ~manager_pkh:attester ~round b_cur in + Block.bake_with_metadata + ~policy:(By_account baker) + ~operation:attestation + b_cur (** We test that: - a delegate that participates enough, gets its attesting rewards at the end of the cycle, diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_preattestation.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_preattestation.ml index 882ede9a1b97..2c8b6dcf6617 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_preattestation.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_preattestation.ml @@ -201,9 +201,10 @@ let slot_substitution_does_not_affect_bytes () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in + let* attester = Context.get_attester (B b) in + let consensus_pkh = attester.consensus_key in let* {shell = {branch}; protocol_data = {contents; _}} = - Op.raw_preattestation ~delegate ~slot:Slot.zero b + Op.raw_preattestation ~attesting_slot:{slot = Slot.zero; consensus_pkh} b in match contents with | Single (Preattestation consensus_content) -> @@ -230,10 +231,11 @@ let encoding_incompatibility () = let open Lwt_result_syntax in let* genesis, _contracts = Context.init_n 5 ~aggregate_attestation:true () in let* b = Block.bake genesis in - let* delegate, _slots = Context.get_attester (B b) in - let* signer = Account.find delegate in + let* attester = Context.get_attester (B b) in + let* signer = Account.find attester.consensus_key in let* {shell = {branch}; protocol_data = {contents; signature = _}} = - Op.raw_preattestation ~delegate b + let attesting_slot = Op.attesting_slot_of_attester attester in + Op.raw_preattestation ~attesting_slot b in let bytes_without_slot = Data_encoding.Binary.to_bytes_exn diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_preattestation_functor.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_preattestation_functor.ml index 8637a9c24c9a..a190ceea269a 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_preattestation_functor.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_preattestation_functor.ml @@ -53,8 +53,8 @@ end = struct ?(preattestation_round = Round.zero) ?(preattested_block = fun _predpred _pred curr -> curr) ?(mk_ops = fun op -> [op]) - ?(get_delegate_and_slot = - fun _predpred _pred _curr -> Lwt_result_syntax.return (None, None)) + ?(get_attesting_slot = + fun ~attested_block:_ -> Lwt_result_syntax.return_none) ?(post_process = Ok (fun _ -> Lwt_result_syntax.return_unit)) ~loc () = let open Lwt_result_syntax in let* genesis, _contracts = @@ -64,11 +64,10 @@ end = struct let* attestation = Op.attestation b1 in let* b2 = bake b1 ~operations:[attestation] in let attested_block = preattested_block genesis b1 b2 in - let* delegate, slot = get_delegate_and_slot genesis b1 b2 in + let* attesting_slot = get_attesting_slot ~attested_block in let* p = Op.preattestation - ?delegate - ?slot + ?attesting_slot ~round:preattestation_round attested_block in @@ -162,30 +161,17 @@ end = struct (** OK: explicit the correct attester and preattesting slot in the test *) let preattestation_in_block_with_good_slot () = - let open Lwt_result_syntax in - aux_simple_preattestation_inclusion - ~get_delegate_and_slot:(fun _predpred _pred curr -> - let module V = Plugin.RPC.Validators in - let* validators = Context.get_attesters (B curr) in - match validators with - | {V.delegate; slots = s :: _; _} :: _ -> return (Some delegate, Some s) - | _ -> assert false - (* there is at least one attester with a slot *)) - ~loc:__LOC__ - () + aux_simple_preattestation_inclusion ~loc:__LOC__ () (** KO: the used slot for injecting the attestation is not the canonical one *) let preattestation_in_block_with_wrong_slot () = let open Lwt_result_syntax in aux_simple_preattestation_inclusion - ~get_delegate_and_slot:(fun _predpred _pred curr -> - let module V = Plugin.RPC.Validators in - let* validators = Context.get_attesters (B curr) in - match validators with - | {V.delegate; V.slots = _ :: non_canonical_slot :: _; _} :: _ -> - return (Some delegate, Some non_canonical_slot) - | _ -> assert false - (* there is at least one attester with a slot *)) + ~get_attesting_slot:(fun ~attested_block -> + let* attesting_slot = + Op.get_non_canonical_attesting_slot ~attested_block + in + return_some attesting_slot) ~loc:__LOC__ ~post_process: (Error @@ -201,15 +187,18 @@ end = struct let preattestation_in_block_with_wrong_signature () = let open Lwt_result_syntax in aux_simple_preattestation_inclusion - ~get_delegate_and_slot:(fun _predpred _pred curr -> - let module V = Plugin.RPC.Validators in - let* validators = Context.get_attesters (B curr) in - match validators with - | {V.delegate; _} :: {V.slots = s :: _; _} :: _ -> - (* the canonical slot s is not owned by the delegate "delegate" !*) - return (Some delegate, Some s) - | _ -> assert false - (* there is at least one attester with a slot *)) + ~get_attesting_slot:(fun ~attested_block -> + let* attester = Context.get_attester (B attested_block) in + let* another_delegates_attesting_slot = + Op.get_different_attesting_slot + ~consensus_pkh_to_avoid:attester.consensus_key + ~attested_block + in + return_some + { + Op.slot = another_delegates_attesting_slot.slot; + consensus_pkh = attester.consensus_key; + }) ~loc:__LOC__ ~post_process: (Error diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_scenario_attestation.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_scenario_attestation.ml index aa3ddcc07fd1..7b26f64ff26e 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_scenario_attestation.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_scenario_attestation.ml @@ -54,18 +54,35 @@ let check_aggregated_committee ~check_not_found ~kind delegates = List.map_es (fun delegate_name -> let delegate = State.find_account delegate_name state in + let block_at_attested_level = + match kind with + | Preattestation -> + block + (* The preattested block is a block at the same + level as [block] but an earlier round. For + retrieving the appropriate consensus_key we only + care about the level so we can use [block]. *) + | Attestation -> state.grandparent (* [block]'s predecessor *) + in let* consensus_key_info = - Context.Delegate.consensus_key (B state.grandparent) delegate.pkh + Context.Delegate.consensus_key + (B block_at_attested_level) + delegate.pkh in - let consensus_key = consensus_key_info.active in - let* consensus_key = Account.find consensus_key.consensus_key_pkh in - return (delegate.pkh, consensus_key.pkh)) + return + { + Protocol.Alpha_context.Consensus_key.delegate = delegate.pkh; + consensus_pkh = consensus_key_info.active.consensus_key_pkh; + }) delegates in let metadata = Stdlib.Option.get state.previous_metadata in check_attestation_aggregate_metadata ~check_not_found ~kind + ~expect_same_order:false + (* Delegates are provided manually and may not be sorted the + same way as when construction the aggregation. *) delegates metadata (block, state)) diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_seed.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_seed.ml index 21ee2d9eb8e1..480e70935c10 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_seed.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/consensus/test_seed.ml @@ -329,8 +329,9 @@ let test_unrevealed () = let* slots = Context.get_attesters (B b) in let* attestations = List.map_es - (fun {Plugin.RPC.Validators.consensus_key; _} -> - Op.attestation ~delegate:consensus_key b) + (fun attester -> + let attesting_slot = Op.attesting_slot_of_attester attester in + Op.attestation ~attesting_slot b) slots in Block.bake ?policy ~operations:attestations b diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/operations/test_origination.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/operations/test_origination.ml index 50d7f01905c0..ad67e9c479c1 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/operations/test_origination.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/operations/test_origination.ml @@ -189,15 +189,6 @@ let test_not_tez_in_contract_to_pay_fee () = let*! inc = Incremental.add_operation inc op in Assert.proto_error_with_info ~loc:__LOC__ inc "Balance too low" -(* Set the attester of the block as manager/delegate of the originated - account. *) -let register_contract_get_attester () = - let open Lwt_result_syntax in - let* b, contract = Context.init1 () in - let* inc = Incremental.begin_construction b in - let+ account_attester, _slots = Context.get_attester (I inc) in - (inc, contract, account_attester) - (* Create multiple originated contracts and ask contract to pay the fee. *) let n_originations n ?credit ?fee () = let open Lwt_result_syntax in diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/validate/generator_descriptors.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/validate/generator_descriptors.ml index b4c6e2c00da8..03f1e3974417 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/validate/generator_descriptors.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/validate/generator_descriptors.ml @@ -355,9 +355,9 @@ let dbl_attestation_prelude state = match heads with | None -> return ([], state) | Some (b1, b2) -> - let* delegate1, delegate2 = pick_two_attesters (B b1) in - let* op1 = Op.raw_preattestation ~delegate:delegate1 b1 in - let* op2 = Op.raw_preattestation ~delegate:delegate1 b2 in + let* attesting_slot = Op.get_attesting_slot ~attested_block:b1 in + let* op1 = Op.raw_preattestation ~attesting_slot b1 in + let* op2 = Op.raw_preattestation ~attesting_slot b2 in let op1, op2 = let comp = Operation_hash.compare (Operation.hash op1) (Operation.hash op2) @@ -368,8 +368,13 @@ let dbl_attestation_prelude state = let slashable_preattestations = (op1, op2) :: state.dbl_attestation.slashable_preattestations in - let* op3 = Op.raw_attestation ~delegate:delegate2 b1 in - let* op4 = Op.raw_attestation ~delegate:delegate2 b2 in + let* attesting_slot' = + Op.get_different_attesting_slot + ~consensus_pkh_to_avoid:attesting_slot.consensus_pkh + ~attested_block:b1 + in + let* op3 = Op.raw_attestation ~attesting_slot:attesting_slot' b1 in + let* op4 = Op.raw_attestation ~attesting_slot:attesting_slot' b2 in let op3, op4 = let comp = Operation_hash.compare (Operation.hash op3) (Operation.hash op4) @@ -604,17 +609,18 @@ let preattestation_descriptor = candidates_generator = (fun state -> let open Lwt_result_syntax in - let gen (delegate, ck_opt) = - let* slots_opt = Context.get_attester_slot (B state.block) delegate in - let delegate = Option.value ~default:delegate ck_opt in - match slots_opt with - | None -> return_none - | Some slots -> ( - match slots with - | [] -> return_none - | _ :: _ -> - let* op = Op.preattestation ~delegate state.block in - return_some op) + let gen (manager_pkh, _ck_opt) = + let* attesters = Context.get_attesters (B state.block) in + if + List.exists + (fun {Context.delegate; _} -> + Signature.Public_key_hash.equal delegate manager_pkh) + attesters + then + (* The manager key has attesting rights on this block *) + let* op = Op.preattestation ~manager_pkh state.block in + return_some op + else return_none in List.filter_map_es gen state.delegates); } @@ -630,17 +636,18 @@ let attestation_descriptor = candidates_generator = (fun state -> let open Lwt_result_syntax in - let gen (delegate, ck_opt) = - let* slots_opt = Context.get_attester_slot (B state.block) delegate in - let delegate = Option.value ~default:delegate ck_opt in - match slots_opt with - | None -> return_none - | Some slots -> ( - match slots with - | [] -> return_none - | _ :: _ -> - let* op = Op.attestation ~delegate state.block in - return_some op) + let gen (manager_pkh, _ck_opt) = + let* attesters = Context.get_attesters (B state.block) in + if + List.exists + (fun {Context.delegate; _} -> + Signature.Public_key_hash.equal delegate manager_pkh) + attesters + then + (* The manager key has attesting rights on this block *) + let* op = Op.attestation ~manager_pkh state.block in + return_some op + else return_none in List.filter_map_es gen state.delegates); } @@ -655,25 +662,8 @@ let attestations_aggregate_descriptor = opt_prelude = None; candidates_generator = (fun state -> - let open Lwt_result_syntax in - let* attestations = - List.filter_map_es - (fun (delegate, consensus_key_opt) -> - let* slots_opt = - Context.get_attester_slot (B state.block) delegate - in - let delegate = Option.value ~default:delegate consensus_key_opt in - let* signer = Account.find delegate in - match (slots_opt, signer.sk) with - | Some (_ :: _), Bls _ -> - let* op = Op.raw_attestation ~delegate state.block in - return (Some op) - | _, _ -> return_none) - state.delegates - in - match Op.aggregate attestations with - | Some op -> return [op] - | None -> return_nil); + let* op = Op.attestations_aggregate state.block in + return [op]); } let preattestations_aggregate_descriptor = @@ -686,25 +676,8 @@ let preattestations_aggregate_descriptor = opt_prelude = None; candidates_generator = (fun state -> - let open Lwt_result_syntax in - let* preattestations = - List.filter_map_es - (fun (delegate, consensus_key_opt) -> - let* slots_opt = - Context.get_attester_slot (B state.block) delegate - in - let delegate = Option.value ~default:delegate consensus_key_opt in - let* signer = Account.find delegate in - match (slots_opt, signer.sk) with - | Some (_ :: _), Bls _ -> - let* op = Op.raw_preattestation ~delegate state.block in - return (Some op) - | _, _ -> return_none) - state.delegates - in - match Op.aggregate_preattestations preattestations with - | Some op -> return [op] - | None -> return_nil); + let* op = Op.preattestations_aggregate state.block in + return [op]); } module Manager = Manager_operation_helpers diff --git a/src/proto_023_PtSeouLo/lib_protocol/test/integration/validate/validate_helpers.ml b/src/proto_023_PtSeouLo/lib_protocol/test/integration/validate/validate_helpers.ml index bcf19871b566..1edee592eabb 100644 --- a/src/proto_023_PtSeouLo/lib_protocol/test/integration/validate/validate_helpers.ml +++ b/src/proto_023_PtSeouLo/lib_protocol/test/integration/validate/validate_helpers.ml @@ -359,14 +359,6 @@ let secrets = (** {3 Context Manipulations } *) -let pick_two_attesters ctxt = - let open Lwt_result_syntax in - let module V = Plugin.RPC.Validators in - let* attesters = Context.get_attesters ctxt in - match attesters with - | a :: b :: _ -> return (a.V.consensus_key, b.V.consensus_key) - | _ -> assert false - let pick_addr_attester ctxt = let open Lwt_result_syntax in let module V = Plugin.RPC.Validators in -- GitLab