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 8c4e11fa5710d93c07f1103f1be88cbfab00dca0..40d26075574ab05de4783c5edcdc31cad1410425 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 f5312d01f1625aaa84537b45823cd579241866d4..1248e8632cb688f24480eff17905688309bb3fb9 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 e4c9820d26a246a9d7fee3145265bd06d741226f..40ecfd7c0fe27989968ceac939371f8ea4f0750c 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 c5f1b93d78bf9f2843434bf7bbe0853bf9fea252..574929baf20dd6320071b23935c25056c380d3ef 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 233758e14d2b15cbfa7a3f98bb35bf28cb507c5d..9140e1c1d5b31790b3c8e1b9fcccf83301a7af7a 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 cf87061cb6005cd5144e0a8d47806ace31a625b5..03ee524583ba386d9ec692c7b152a64353318a41 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 c3373f3c3a0415c670cae2eda17a47926d36e528..286de68b6c8f76396a71af073595a6d746006d70 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 2625057541b60ae0b6d6b8cf7959307089c0abf4..9dcba93712c0d74af9b1f7d903cc87a6ec73c2ae 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 aac02aafdb4db8c1b4a4ed171962e0f6ff4ce597..b1708cde8ade98cdb0553e14e795cadc593ed516 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 69816f16141f8791139ba1783e7ba8f1837d8dfa..14c043b9f3ebb38a40f5d7a6e454209bf99bba92 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 fff25a068d8c4bf64401a38baffa8001657e321e..31cb50100bc8cd59f2cb5dac8526996c87e2bc7b 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 5100c97640d6ffb60cb87500bfc15b5a6150dfdf..3bc5841f2f3e7d014650c83906c9b6309c95b6d7 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 3c768c1a97c715912475106c6162c86bb50610cf..0b904cb2d8ddd5d6975fad50b940160ce879f45d 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 4bb92874260cab6910c381516f89e46c24dd673f..971d9c7b2cdd31e4c6c7e7a4401aae33e82e0c8f 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 6f176e366bc242c7ff3112fa3f9e9475d9c03ee7..35e7eda876b3071e3c534eb1f88199ca70b202cb 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 7e9fcdf580e7a6d8047e28856013cd0928f3ed06..7d3b84bb82a9ea83de106e04e1d614c2dc0ff434 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 63b659c1f999dcdb6488a1065f146110c288b78c..4a6917e44a97e93ffdff4d38e0915c1f7c7db806 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 6b7de5ae18dc131b442fb335205ea112d098b371..0ff785e2607c4f9dedf7cced932a8d8454eba5b2 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 9861c08b0d943087280c8cfc42d1620f83eaa7b1..f0b748e59b82156259d51414880a3be3dfa79bf5 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 30f50193066ee784f91654744a14957481809b4a..a58fdff69ec8d29953739806f63840b4b5251029 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 ebc314886157637b3008d6c31bb679a8db04cd4f..34a662fa743edf3fa0da3d8d03d039e69a0df5f4 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 a156cc546b9f5b5eca928925e3bb14df5b49f403..6b3a3167bedc9207459088d3f43b134a30087e87 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 882ede9a1b97d6cb14e9a605c37fc2134e269f2e..2c8b6dcf66179d60200722a444f185a360a5e748 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 8637a9c24c9a315563e9fc9140e66c5ae66df541..a190ceea269a5b5e83f08abb79d0059147f7afc4 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 aa3ddcc07fd1ef2bb90950c624b3456dfa32b5b6..7b26f64ff26e9830f86e18b3ba846ff667fdc724 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 21ee2d9eb8e133bbd122b1567d3521e0ff6d3b22..480e70935c103b27482b1f86f816f9d8ad7515e7 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 50d7f01905c0811390c36afb4dfdbe6a44c762ea..ad67e9c479c1be905d3b6faa5dd51b5118565c85 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 b4c6e2c00da8809ce02fcd2a45390c68526512d4..03f1e3974417e45cebebec09e0719861c9291cec 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 bcf19871b566bdfbb3429675f28902e8d57cd6c6..1edee592eabbd74770756b6eb9b8c32eb6a40631 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 diff --git a/src/proto_alpha/lib_protocol/test/helpers/block.ml b/src/proto_alpha/lib_protocol/test/helpers/block.ml index d2c0b1e3952d199d9cbf19fcba7fcf9395a0cae9..5221e801f1c6e104344c38ea2321446bcfc581b0 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 f5312d01f1625aaa84537b45823cd579241866d4..1248e8632cb688f24480eff17905688309bb3fb9 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/consensus_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/consensus_helpers.ml index e4c9820d26a246a9d7fee3145265bd06d741226f..40ecfd7c0fe27989968ceac939371f8ea4f0750c 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 b9ded8633ee6a1ee35e89580d0a85644c76f2142..ce9dffd30a497dc0edaaa65fb417709ec725528d 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 233758e14d2b15cbfa7a3f98bb35bf28cb507c5d..9140e1c1d5b31790b3c8e1b9fcccf83301a7af7a 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/dal_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.ml index cf87061cb6005cd5144e0a8d47806ace31a625b5..03ee524583ba386d9ec692c7b152a64353318a41 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 c3373f3c3a0415c670cae2eda17a47926d36e528..286de68b6c8f76396a71af073595a6d746006d70 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/helpers/error_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/error_helpers.ml index 2625057541b60ae0b6d6b8cf7959307089c0abf4..9dcba93712c0d74af9b1f7d903cc87a6ec73c2ae 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,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_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index aac02aafdb4db8c1b4a4ed171962e0f6ff4ce597..b1708cde8ade98cdb0553e14e795cadc593ed516 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 @@ -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_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 69816f16141f8791139ba1783e7ba8f1837d8dfa..14c043b9f3ebb38a40f5d7a6e454209bf99bba92 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 -> @@ -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_alpha/lib_protocol/test/helpers/scenario_attestation.ml b/src/proto_alpha/lib_protocol/test/helpers/scenario_attestation.ml index fff25a068d8c4bf64401a38baffa8001657e321e..31cb50100bc8cd59f2cb5dac8526996c87e2bc7b 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 = @@ -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_alpha/lib_protocol/test/helpers/scenario_op.ml b/src/proto_alpha/lib_protocol/test/helpers/scenario_op.ml index 5100c97640d6ffb60cb87500bfc15b5a6150dfdf..3bc5841f2f3e7d014650c83906c9b6309c95b6d7 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 747310115979ca0e2a548924cda0052ea596e593..3cf1c161be520eb533d5596f3085f1e3a1c66716 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 @@ -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_alpha__Protocol.Apply_results.contents_result) = let open Lwt_result_syntax in @@ -135,14 +99,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,260 +116,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_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 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 @@ -413,38 +539,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 @@ -452,20 +560,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) -> @@ -479,7 +581,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}} @@ -494,24 +597,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 @@ -527,43 +627,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 @@ -571,16 +684,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 @@ -595,7 +709,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 () = @@ -604,58 +718,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 @@ -679,7 +787,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 @@ -705,7 +818,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 () = @@ -715,30 +833,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) = @@ -783,12 +892,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 @@ -808,12 +917,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 @@ -821,18 +930,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 @@ -842,8 +952,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 @@ -852,54 +962,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__ @@ -911,22 +1004,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__ @@ -962,6 +1050,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 @@ -978,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 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 4e96d8c7aa1199beeee89a1924c11bff53ea8c47..7ae0cad56f7065fcc98356c64fa038af456089d1 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 241b99a71b042732d312cae4588ed5b4e101ea25..6e2ffa90f1462563c3b6c841e2902778b0b2ff78 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 15c44c695276ba2117384f84193d15b398643d0d..80c6e9f7fe923fb82dbfcd9c38552f43cdc448b7 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 a0db6cc95f49922ec8d64a088f81af29fc119970..eeb8ffa8159fcfc4389628d957ba5ec7a8ea0eff 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 83c5e4da143777976e2104f35d330ad843518558..507a6062bc7b68194c97a6a40672e40d279d334d 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,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_alpha/lib_protocol/test/integration/consensus/test_double_baking.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_double_baking.ml index 26a45df6235832f15110e21fca0c0973a0ce4655..4bcd4910b345e595d6b05ec2cb7e5b233b4b3101 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 ceb59129d324b72bd8b4dc13c8bdfffb48503293..471ec9d11086b474ee0f4877b992dfde4bfa056c 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,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_alpha/lib_protocol/test/integration/consensus/test_frozen_deposits.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_frozen_deposits.ml index 8b0dfd2d83599164a972df9040c5f2815c553f3e..76472a5fc825e7816fc80f6435a8b5a6580b8b6d 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 bded22a0a32ad1758706d5aa3383d4e10304e661..5d60622bfa3c9026c22fd401269faa4105f5258d 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 3acbfc097665e9c87c6e14c637035e879608cc16..136fab27d32dc61b08b28a779f327f991f4c4a2b 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 8637a9c24c9a315563e9fc9140e66c5ae66df541..a190ceea269a5b5e83f08abb79d0059147f7afc4 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_scenario_attestation.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_scenario_attestation.ml index aa3ddcc07fd1ef2bb90950c624b3456dfa32b5b6..7b26f64ff26e9830f86e18b3ba846ff667fdc724 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/consensus/test_seed.ml b/src/proto_alpha/lib_protocol/test/integration/consensus/test_seed.ml index 1cf0f2df61046eaaeec60e27953fa12fa394b33e..8f8fe06752776afaf17847e9e0e5ee62e784adc7 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 69d4c194fa85ef41fa3afb431a4898861157dbc6..b26afe03687f7f5753e407c87173721589022067 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 b4c6e2c00da8809ce02fcd2a45390c68526512d4..03f1e3974417e45cebebec09e0719861c9291cec 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); } @@ -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_alpha/lib_protocol/test/integration/validate/validate_helpers.ml b/src/proto_alpha/lib_protocol/test/integration/validate/validate_helpers.ml index e3c03c8090bc47757885d04328641565a4a3512e..c1f94115b43c69fa29e2b924a5fc03b5f4855ffb 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