From 566d48bc1fd936bfc8c04bff69b1edfdcc80864c Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 16 May 2025 17:33:48 +0200 Subject: [PATCH 1/6] Proto: update dal_entrapment_evidence type --- .../lib_client/operation_result.ml | 7 +- .../lib_dal/dal_plugin_registration.ml | 4 +- src/proto_alpha/lib_plugin/RPC.ml | 7 +- .../lib_protocol/alpha_context.mli | 3 +- src/proto_alpha/lib_protocol/apply.ml | 22 +++- .../lib_protocol/operation_repr.ml | 121 ++++++++++++++---- .../lib_protocol/operation_repr.mli | 3 +- .../lib_protocol/test/helpers/op.ml | 11 +- src/proto_alpha/lib_protocol/validate.ml | 19 +-- 9 files changed, 152 insertions(+), 45 deletions(-) diff --git a/src/proto_alpha/lib_client/operation_result.ml b/src/proto_alpha/lib_client/operation_result.ml index bf6b77afec1a..147708127644 100644 --- a/src/proto_alpha/lib_client/operation_result.ml +++ b/src/proto_alpha/lib_client/operation_result.ml @@ -1114,7 +1114,12 @@ let pp_contents_and_result : pp_balance_updates balance_updates | ( Dal_entrapment_evidence - {attestation; slot_index = _; shard_with_proof = _}, + { + attestation; + consensus_slot = _; + slot_index = _; + shard_with_proof = _; + }, Dal_entrapment_evidence_result {balance_updates} ) -> Format.fprintf ppf diff --git a/src/proto_alpha/lib_dal/dal_plugin_registration.ml b/src/proto_alpha/lib_dal/dal_plugin_registration.ml index 5b337ed0c5be..bdb5d21a15b6 100644 --- a/src/proto_alpha/lib_dal/dal_plugin_registration.ml +++ b/src/proto_alpha/lib_dal/dal_plugin_registration.ml @@ -116,7 +116,8 @@ module Plugin = struct let shard_with_proof = Dal.Shard_with_proof.{shard; proof} in let protocol_data = operation.protocol_data in match operation.protocol_data.contents with - | Single (Attestation _) -> + | Single (Attestation {consensus_content = {slot = consensus_slot; _}; _}) + -> let attestation : Kind.attestation Alpha_context.operation = {shell = operation.shell; protocol_data} in @@ -125,6 +126,7 @@ module Plugin = struct cpctxt (chain, block) ~branch:block_hash + ~consensus_slot ~attestation ~slot_index ~shard_with_proof diff --git a/src/proto_alpha/lib_plugin/RPC.ml b/src/proto_alpha/lib_plugin/RPC.ml index 5b132b68cd61..cfa7cba8330c 100644 --- a/src/proto_alpha/lib_plugin/RPC.ml +++ b/src/proto_alpha/lib_plugin/RPC.ml @@ -3404,13 +3404,14 @@ module Forge = struct let double_preattestation_evidence ctxt block ~branch ~op1 ~op2 () = operation ctxt block ~branch (Double_preattestation_evidence {op1; op2}) - let dal_entrapment_evidence ctxt block ~branch ~attestation ~slot_index - ~shard_with_proof = + let dal_entrapment_evidence ctxt block ~branch ~attestation ~consensus_slot + ~slot_index ~shard_with_proof = operation ctxt block ~branch - (Dal_entrapment_evidence {attestation; slot_index; shard_with_proof}) + (Dal_entrapment_evidence + {attestation; consensus_slot; slot_index; shard_with_proof}) let empty_proof_of_work_nonce = Bytes.make Constants_repr.proof_of_work_nonce_size '\000' diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 230b0fc3c056..b87acd41d3df 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -4782,7 +4782,8 @@ and _ contents = } -> Kind.double_baking_evidence contents | Dal_entrapment_evidence : { - attestation : Kind.attestation operation; + attestation : 'a Kind.consensus operation; + consensus_slot : Slot.t; slot_index : Dal.Slot_index.t; shard_with_proof : Dal.Shard_with_proof.t; } diff --git a/src/proto_alpha/lib_protocol/apply.ml b/src/proto_alpha/lib_protocol/apply.ml index 84d04f96bae1..2241378890ae 100644 --- a/src/proto_alpha/lib_protocol/apply.ml +++ b/src/proto_alpha/lib_protocol/apply.ml @@ -2643,13 +2643,23 @@ let apply_contents_list (type kind) ctxt chain_id (mode : mode) punish_double_attestation ctxt ~operation_hash ~op1 ~payload_producer | Single (Double_baking_evidence {bh1; bh2 = _}) -> punish_double_baking ctxt ~operation_hash bh1 ~payload_producer - | Single (Dal_entrapment_evidence {attestation; slot_index; _}) -> - let {slot; level = raw_level; _} = - match attestation.protocol_data.contents with - | Single (Attestation {consensus_content; _}) -> consensus_content + | Single + (Dal_entrapment_evidence {attestation; consensus_slot; slot_index; _}) -> + let (Single + (* Note that since the evidence has been successfully + validated, [attestation] cannot be a preattestation or + preattestations aggregate (also [consensus_slot] is + consistent, and [slot_index] is an attested trap, etc.) *) + ( Preattestation {level; _} + | Attestation {consensus_content = {level; _}; _} + | Preattestations_aggregate {consensus_content = {level; _}; _} + | Attestations_aggregate {consensus_content = {level; _}; _} )) = + attestation.protocol_data.contents + in + let level = Level.from_raw ctxt level in + let* ctxt, consensus_pk = + Stake_distribution.slot_owner ctxt level consensus_slot in - let level = Level.from_raw ctxt raw_level in - let* ctxt, consensus_pk = Stake_distribution.slot_owner ctxt level slot in let delegate = consensus_pk.delegate in let*! ctxt, _already_denounced = Dal.Delegate.add_denunciation ctxt delegate level slot_index diff --git a/src/proto_alpha/lib_protocol/operation_repr.ml b/src/proto_alpha/lib_protocol/operation_repr.ml index 6e92f7f03ab8..4a91c31f0884 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.ml +++ b/src/proto_alpha/lib_protocol/operation_repr.ml @@ -324,7 +324,8 @@ and _ contents = } -> Kind.double_baking_evidence contents | Dal_entrapment_evidence : { - attestation : Kind.attestation operation; + attestation : 'a Kind.consensus operation; + consensus_slot : Slot_repr.t; slot_index : Dal_slot_index_repr.t; shard_with_proof : Dal_slot_repr.Shard_with_proof.t; } @@ -1297,6 +1298,54 @@ module Encoding = struct Preattestations_aggregate {consensus_content; committee}); } + type packed_consensus_operation_contents = + | Consensus_op_contents : + 'a Kind.consensus contents + -> packed_consensus_operation_contents + + type packed_consensus_operation = + | Consensus_op : 'a Kind.consensus operation -> packed_consensus_operation + + (* For denunciations *) + let inlined_consensus_operation_encoding = + let make (Case {tag; name; encoding; select; proj; inj}) = + assert (not @@ reserved_tag tag) ; + case + (Tag tag) + name + encoding + (function + | Consensus_op_contents o -> ( + match select (Contents o) with + | None -> None + | Some o -> Some (proj o))) + (fun x -> Consensus_op_contents (inj x)) + in + let consensus_operation_contents_encoding = + def "inlined.consensus_operation.contents" + @@ union + [ + make preattestation_case; + make attestation_case; + make attestation_with_dal_case; + make preattestations_aggregate_case; + make attestations_aggregate_case; + ] + in + def "inlined.consensus_operation" + @@ conv + (fun (Consensus_op + {shell; protocol_data = {contents = Single contents; signature}}) -> + (shell, (Consensus_op_contents contents, signature))) + (fun (shell, (Consensus_op_contents contents, signature)) -> + Consensus_op + {shell; protocol_data = {contents = Single contents; signature}}) + (merge_objs + Operation.shell_header_encoding + (obj2 + (req "operations" consensus_operation_contents_encoding) + (varopt "signature" Signature.encoding))) + let seed_nonce_revelation_case = Case { @@ -1479,8 +1528,11 @@ module Encoding = struct tag = 24; name = "dal_entrapment_evidence"; encoding = - obj3 - (req "attestation" (dynamic_size attestation_encoding)) + obj4 + (req + "attestation" + (dynamic_size inlined_consensus_operation_encoding)) + (req "consensus_slot" Slot_repr.encoding) (req "slot_index" Dal_slot_index_repr.encoding) (req "shard_with_proof" Dal_slot_repr.Shard_with_proof.encoding); select = @@ -1488,11 +1540,18 @@ module Encoding = struct | Contents (Dal_entrapment_evidence _ as op) -> Some op | _ -> None); proj = (fun (Dal_entrapment_evidence - {attestation; slot_index; shard_with_proof}) -> - (attestation, slot_index, shard_with_proof)); + {attestation; consensus_slot; slot_index; shard_with_proof}) -> + ( Consensus_op attestation, + consensus_slot, + slot_index, + shard_with_proof )); inj = - (fun (attestation, slot_index, shard_with_proof) -> - Dal_entrapment_evidence {attestation; slot_index; shard_with_proof}); + (fun ( Consensus_op attestation, + consensus_slot, + slot_index, + shard_with_proof ) -> + Dal_entrapment_evidence + {attestation; consensus_slot; slot_index; shard_with_proof}); } let manager_encoding = @@ -2378,6 +2437,36 @@ let consensus_infos_and_hash_from_block_header (bh : Block_header_repr.t) = type dal_entrapment_info = {level : int32; number_of_attested_slots : int} +let dal_entrapment_info + (Dal_entrapment_evidence {attestation; consensus_slot; _}) = + let level, dal_content = + match attestation.protocol_data.contents with + | Single (Attestation {consensus_content; dal_content}) -> + (consensus_content.level, dal_content) + | Single (Attestations_aggregate {consensus_content; committee}) -> + let dal_content = + List.assoc_opt ~equal:Slot_repr.equal consensus_slot committee + |> Option.join + in + (consensus_content.level, dal_content) + (* Preattestation and Preattestations_aggregate cases should not + be possible for a valid Dal_entrapment_evidence, but these + cases are easy to cover anyway. *) + | Single (Preattestation consensus_content) -> + (consensus_content.level, None) + | Single (Preattestations_aggregate {consensus_content; _}) -> + (consensus_content.level, None) + in + { + level = Raw_level_repr.to_int32 level; + number_of_attested_slots = + Option.fold + ~none:0 + ~some:(fun d -> + Dal_attestation_repr.number_of_attested_slots d.attestation) + dal_content; + } + (** The weight of an operation. Given an operation, its [weight] carries on static information that @@ -2562,21 +2651,9 @@ let weight_of : packed_operation -> operation_weight = consensus_infos_and_hash_from_block_header bh1 in W (Anonymous, Weight_double_baking double_baking_infos) - | Single (Dal_entrapment_evidence {attestation; _}) -> ( - match attestation.protocol_data.contents with - | Single (Attestation {consensus_content; dal_content}) -> - let info = - { - level = Raw_level_repr.to_int32 consensus_content.level; - number_of_attested_slots = - Option.fold - ~none:0 - ~some:(fun d -> - Dal_attestation_repr.number_of_attested_slots d.attestation) - dal_content; - } - in - W (Anonymous, Weight_dal_entrapment_evidence info)) + | Single (Dal_entrapment_evidence _ as contents) -> + let info = dal_entrapment_info contents in + W (Anonymous, Weight_dal_entrapment_evidence info) | Single (Activate_account {id; _}) -> W (Anonymous, Weight_activate_account id) | Single (Drain_delegate {delegate; _}) -> diff --git a/src/proto_alpha/lib_protocol/operation_repr.mli b/src/proto_alpha/lib_protocol/operation_repr.mli index 4ae10f95c8dc..7addb3306a9a 100644 --- a/src/proto_alpha/lib_protocol/operation_repr.mli +++ b/src/proto_alpha/lib_protocol/operation_repr.mli @@ -339,7 +339,8 @@ and _ contents = (* The attester failed to correctly identify a trap when attesting DAL slots. *) | Dal_entrapment_evidence : { - attestation : Kind.attestation operation; + attestation : 'a Kind.consensus operation; + consensus_slot : Slot_repr.t; slot_index : Dal_slot_index_repr.t; shard_with_proof : Dal_slot_repr.Shard_with_proof.t; } diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 6117bf472d83..49aca4c86250 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -895,9 +895,16 @@ let double_baking ctxt bh1 bh2 = protocol_data = Operation_data {contents; signature = None}; } -let dal_entrapment ctxt attestation slot_index shard_with_proof = +let dal_entrapment ctxt (attestation : Kind.attestation operation) slot_index + shard_with_proof = + let (Single (Attestation {consensus_content = {slot = consensus_slot; _}; _})) + = + attestation.protocol_data.contents + in let contents = - Single (Dal_entrapment_evidence {attestation; slot_index; shard_with_proof}) + Single + (Dal_entrapment_evidence + {attestation; consensus_slot; slot_index; shard_with_proof}) in let branch = Context.branch ctxt in { diff --git a/src/proto_alpha/lib_protocol/validate.ml b/src/proto_alpha/lib_protocol/validate.ml index 0c0ff0a33a5b..667137356738 100644 --- a/src/proto_alpha/lib_protocol/validate.ml +++ b/src/proto_alpha/lib_protocol/validate.ml @@ -2276,14 +2276,15 @@ module Anonymous = struct (operation : Kind.dal_entrapment_evidence operation) = let open Lwt_result_syntax in let (Single - (Dal_entrapment_evidence {attestation; slot_index; shard_with_proof})) - = + (Dal_entrapment_evidence + {attestation; consensus_slot = _; slot_index; shard_with_proof})) = operation.protocol_data.contents in let consensus_content, dal_content = match attestation.protocol_data.contents with | Single (Attestation {consensus_content; dal_content}) -> (consensus_content, dal_content) + | _ -> assert false (* Handled in an upcoming commit *) in match dal_content with | None -> @@ -2435,15 +2436,17 @@ module Anonymous = struct let dal_entrapment_evidence_info (operation : Kind.dal_entrapment_evidence operation) = - let (Single (Dal_entrapment_evidence {attestation; _})) = + let (Single (Dal_entrapment_evidence {attestation; consensus_slot; _})) = operation.protocol_data.contents in - let {level; slot; _} = - match attestation.protocol_data.contents with - | Single (Attestation {consensus_content; dal_content = _}) -> - consensus_content + let (Single + ( Preattestation {level; _} + | Attestation {consensus_content = {level; _}; _} + | Preattestations_aggregate {consensus_content = {level; _}; _} + | Attestations_aggregate {consensus_content = {level; _}; _} )) = + attestation.protocol_data.contents in - (level, slot) + (level, consensus_slot) let check_dal_entrapment_evidence_conflict vs oph (operation : Kind.dal_entrapment_evidence operation) = -- GitLab From e517cb97bf285afc0828d0db9cdb411ab8579767 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Mon, 19 May 2025 15:08:18 +0200 Subject: [PATCH 2/6] Proto/validate: update sig check of denounced operation in dal entrapment --- src/proto_alpha/lib_protocol/validate.ml | 222 ++++++++++++++++------- 1 file changed, 154 insertions(+), 68 deletions(-) diff --git a/src/proto_alpha/lib_protocol/validate.ml b/src/proto_alpha/lib_protocol/validate.ml index 667137356738..279560e8545a 100644 --- a/src/proto_alpha/lib_protocol/validate.ml +++ b/src/proto_alpha/lib_protocol/validate.ml @@ -826,6 +826,62 @@ module Consensus = struct consensus_key attestation + let check_attestation_signature vi consensus_key + (operation : Kind.attestation operation) = + let open Result_syntax in + let (Single (Attestation {dal_content; _})) = + operation.protocol_data.contents + in + let* dal_dependent_pk = + match (consensus_key.Consensus_key.consensus_pk, dal_content) with + | Bls consensus_bls_pk, Some {attestation = dal_attestation} + when Constants.aggregate_attestation vi.ctxt -> ( + match consensus_key.companion_pk with + | None -> + tzfail + (Missing_companion_key_for_bls_dal + (Consensus_key.pkh consensus_key)) + | Some companion_pk -> ( + let serialized_op = + Operation.( + serialize_unsigned_operation + bls_mode_unsigned_encoding + operation) + in + let dal_dependent_bls_pk_opt = + Dal.Attestation.Dal_dependent_signing.aggregate_pk + ~subgroup_check:false + (* We disable subgroup check (for better + performances) because the context only contains + valid consensus and companion keys. *) + ~consensus_pk:consensus_bls_pk + ~companion_pk + ~op:serialized_op + dal_attestation + in + match dal_dependent_bls_pk_opt with + | None -> + tzfail + Validate_errors.Consensus.Public_key_aggregation_failure + | Some dal_dependent_bls_pk -> + return + (Signature.Bls dal_dependent_bls_pk + : Signature.Public_key.t))) + | _ -> + (* When the feature flag is not set or the consensus key is + non-BLS, we use the old behavior: the signed content + (which includes the dal_content if any) is signed by the + consensus key alone. + + When the dal_content is None (even with enabled feature + flag and BLS consensus key), it is represented by + [dal_dependent_pk = consensus_pk]. Notably, this allows a + BLS consensus key without any associated companion key to + still issue an attestation without DAL. *) + return consensus_key.consensus_pk + in + Operation.check_signature vi.ctxt dal_dependent_pk vi.chain_id operation + let check_attestation vi ~check_signature (operation : Kind.attestation operation) = let open Lwt_result_syntax in @@ -876,66 +932,7 @@ module Consensus = struct in let check_signature = if check_signature then - [ - (fun () -> - let open Result_syntax in - let* dal_dependent_pk = - match (consensus_key.Consensus_key.consensus_pk, dal_content) with - | Bls consensus_bls_pk, Some {attestation = dal_attestation} - when Constants.aggregate_attestation vi.ctxt -> ( - match consensus_key.companion_pk with - | None -> - tzfail - (Missing_companion_key_for_bls_dal - (Consensus_key.pkh consensus_key)) - | Some companion_pk -> ( - let serialized_op = - Operation.( - serialize_unsigned_operation - bls_mode_unsigned_encoding - operation) - in - let dal_dependent_bls_pk_opt = - Dal.Attestation.Dal_dependent_signing.aggregate_pk - ~subgroup_check:false - (* We disable subgroup check (for better - performances) because the context only - contains valid consensus and companion - keys. *) - ~consensus_pk:consensus_bls_pk - ~companion_pk - ~op:serialized_op - dal_attestation - in - match dal_dependent_bls_pk_opt with - | None -> - tzfail - Validate_errors.Consensus - .Public_key_aggregation_failure - | Some dal_dependent_bls_pk -> - return - (Signature.Bls dal_dependent_bls_pk - : Signature.Public_key.t))) - | _ -> - (* When the feature flag is not set or the consensus key - is non-BLS, we use the old behavior: the signed - content (which includes the dal_content if any) is - signed by the consensus key alone. - - When the dal_content is None (even with enabled - feature flag and BLS consensus key), it is - represented by [dal_dependent_pk = - consensus_pk]. Notably, this allows a BLS consensus - key without any associated companion key to still - issue an attestation without DAL. *) - return consensus_key.consensus_pk - in - Operation.check_signature - vi.ctxt - dal_dependent_pk - vi.chain_id - operation); - ] + [(fun () -> check_attestation_signature vi consensus_key operation)] else [] in return (attesting_power, check_signature) @@ -1948,6 +1945,102 @@ module Anonymous = struct Outdated_dal_denunciation {level = given_level; last_cycle = last_denunciable_cycle}) + (** Checks the signature of the given consensus operation [op]. To + be called on denounced operations. + + [consensus_key] is the consensus key of the denounced delegate: + when [op] is a standalone (pre)attestation, it assumed to be the + key associated with the operation's [slot]. When [op] is an + aggregate, [consensus_key] is not used since the signature + depends on the whole committee. *) + let check_consensus_operation_signature (type a) vi consensus_key + (op : a Kind.consensus Operation.t) = + let open Lwt_result_syntax in + match op.protocol_data.contents with + | Single (Preattestation _) -> + Operation.check_signature + vi.ctxt + consensus_key.Consensus_key.consensus_pk + vi.chain_id + op + |> Lwt.return + | Single (Attestation _) -> + Consensus.check_attestation_signature vi consensus_key op |> Lwt.return + | Single + (Preattestations_aggregate {consensus_content = {level; _}; committee}) + -> + let level = Level.from_raw vi.ctxt level in + let* _ctxt, public_keys = + (* [ctxt] is part of the accumulator so that attesting + rights data for [level] are loaded at most once. *) + List.fold_left_es + (fun (ctxt, public_keys) slot -> + let* ctxt, consensus_key = + Stake_distribution.slot_owner ctxt level slot + in + match consensus_key.consensus_pk with + | Bls pk -> return (ctxt, pk :: public_keys) + | _ -> tzfail Validate_errors.Consensus.Non_bls_key_in_aggregate) + (vi.ctxt, []) + committee + in + Consensus.check_preattestations_aggregate_signature vi public_keys op + | Single + (Attestations_aggregate + {consensus_content = {level; round; block_payload_hash}; committee}) + -> + let serialized_op = + let attestation : Kind.attestation operation = + (* Reconstructing an attestation to match the content signed by + each delegate. Fields 'slot' and 'dal_content' are filled with + dummy values as they are not part of the signed payload *) + let consensus_content = + {slot = Slot.zero; level; round; block_payload_hash} + in + let contents = + Single (Attestation {consensus_content; dal_content = None}) + in + {shell = op.shell; protocol_data = {contents; signature = None}} + in + Operation.( + serialize_unsigned_operation bls_mode_unsigned_encoding attestation) + in + let level = Level.from_raw vi.ctxt level in + let* _ctxt, pks, weighted_pks = + List.fold_left_es + (fun (ctxt, pks, weighted_pks) (slot, dal) -> + let* ctxt, consensus_key = + Stake_distribution.slot_owner ctxt level slot + in + match consensus_key.consensus_pk with + | Bls consensus_pk -> ( + let pks = consensus_pk :: pks in + match (dal, consensus_key.companion_pk) with + | None, _ -> return (ctxt, pks, weighted_pks) + | Some {attestation = dal_attestation}, Some companion_pk -> + let weight = + Dal.Attestation.Dal_dependent_signing.weight + ~consensus_pk + ~companion_pk + ~op:serialized_op + dal_attestation + in + let weighted_pks = + (weight, companion_pk) :: weighted_pks + in + return (ctxt, pks, weighted_pks) + | Some _, None -> + tzfail + (Validate_errors.Consensus + .Missing_companion_key_for_bls_dal + (Consensus_key.pkh consensus_key))) + | _ -> tzfail Validate_errors.Consensus.Non_bls_key_in_aggregate) + (vi.ctxt, [], []) + committee + in + Consensus.check_attestations_aggregate_signature vi pks weighted_pks op + |> Lwt.return + let check_double_attesting_evidence (type kind) vi (op1 : kind Kind.consensus Operation.t) (op2 : kind Kind.consensus Operation.t) = @@ -2401,14 +2494,7 @@ module Anonymous = struct header.commitment shard_with_proof in - let*? () = - Operation.check_signature - vi.ctxt - consensus_key.consensus_pk - vi.chain_id - attestation - in - return_unit + check_consensus_operation_signature vi consensus_key attestation | Some (header, _publisher) -> (* TODO: https://gitlab.com/tezos/tezos/-/issues/7126 Can also fail if `attestation_lag` changes. *) -- GitLab From a7d4b8597b6bf42dc69e868e10ebdb15fd6fbab7 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 16 May 2025 17:33:48 +0200 Subject: [PATCH 3/6] Proto/validate: update validation of dal entrapment --- src/proto_alpha/lib_protocol/validate.ml | 42 ++++++++++++------- .../lib_protocol/validate_errors.ml | 32 ++++++++++++-- .../lib_protocol/validate_errors.mli | 2 + 3 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/proto_alpha/lib_protocol/validate.ml b/src/proto_alpha/lib_protocol/validate.ml index 279560e8545a..e90a97685b19 100644 --- a/src/proto_alpha/lib_protocol/validate.ml +++ b/src/proto_alpha/lib_protocol/validate.ml @@ -2356,9 +2356,12 @@ module Anonymous = struct {given = shard_index; min = 0; max = number_of_shards - 1}) (* This function validates an entrapment evidence by doing the following checks: + - the included attestation is either a standalone attestation for + the included consensus_slot, or an attestations_aggregate whose + committee contains the included consensus_slot + - the included attestation contains a dal_content for + consensus_slot, in which the included slot index is attested - the included slot index and shard index are within bounds - - the included attestation contains a DAL attestation - - the slot was attested by the attester - the level of the faulty attestation is within the slashing period - the included shard is a trap - the delegate has not already been denounced for the same level and slot index @@ -2370,24 +2373,34 @@ module Anonymous = struct let open Lwt_result_syntax in let (Single (Dal_entrapment_evidence - {attestation; consensus_slot = _; slot_index; shard_with_proof})) = + {attestation; consensus_slot; slot_index; shard_with_proof})) = operation.protocol_data.contents in - let consensus_content, dal_content = + let*? level, dal_content = + let open Result_syntax in match attestation.protocol_data.contents with - | Single (Attestation {consensus_content; dal_content}) -> - (consensus_content, dal_content) - | _ -> assert false (* Handled in an upcoming commit *) + | Single (Attestation {consensus_content = {slot; level; _}; dal_content}) + -> + let* () = + error_unless + Slot.(slot = consensus_slot) + Invalid_accusation_inconsistent_consensus_slot + in + return (level, dal_content) + | Single + (Attestations_aggregate {consensus_content = {level; _}; committee}) + -> ( + match List.assoc ~equal:Slot.equal consensus_slot committee with + | None -> tzfail Invalid_accusation_inconsistent_consensus_slot + | Some dal_content -> return (level, dal_content)) + | Single (Preattestation _ | Preattestations_aggregate _) -> + tzfail Invalid_accusation_of_preattestation in match dal_content with | None -> tzfail (Invalid_accusation_no_dal_content - { - tb_slot = consensus_content.slot; - level = consensus_content.level; - slot_index; - }) + {tb_slot = consensus_slot; level; slot_index}) | Some dal_content -> ( let number_of_slots = Constants.dal_number_of_slots vi.ctxt in let*? () = @@ -2398,17 +2411,16 @@ module Anonymous = struct let*? () = check_shard_index_is_in_range ~number_of_shards shard_index in - let level = consensus_content.level in let*? () = error_unless (Dal.Attestation.is_attested dal_content.attestation slot_index) (Invalid_accusation_slot_not_attested - {tb_slot = consensus_content.slot; level; slot_index}) + {tb_slot = consensus_slot; level; slot_index}) in let*? () = check_denunciation_age vi `Dal_denounciation level in let level = Level.from_raw vi.ctxt level in let* ctxt, consensus_key = - Stake_distribution.slot_owner vi.ctxt level consensus_content.slot + Stake_distribution.slot_owner vi.ctxt level consensus_slot in let delegate = consensus_key.delegate in let*! already_denounced = diff --git a/src/proto_alpha/lib_protocol/validate_errors.ml b/src/proto_alpha/lib_protocol/validate_errors.ml index b59b541ba314..4290f992cff2 100644 --- a/src/proto_alpha/lib_protocol/validate_errors.ml +++ b/src/proto_alpha/lib_protocol/validate_errors.ml @@ -1025,6 +1025,8 @@ module Anonymous = struct (fun () -> Aggregate_denunciation_not_implemented) type error += + | Invalid_accusation_inconsistent_consensus_slot + | Invalid_accusation_of_preattestation | Too_early_dal_denunciation of {level : Raw_level.t; current : Raw_level.t} | Outdated_dal_denunciation of {level : Raw_level.t; last_cycle : Cycle.t} | Invalid_shard_index of {given : int; min : int; max : int} @@ -1076,6 +1078,28 @@ module Anonymous = struct let () = let open Data_encoding in + register_error_kind + `Permanent + ~id:"validate.operation.invalid_accusation_inconsistent_consensus_slot" + ~title:"Invalid DAL denunciation: inconsistent consensus slot" + ~description: + "The denounced attestation must be either a standalone attestation for \ + the denounced consensus slot, or an attestations aggregate whose \ + committee includes the denounced consensus slot." + empty + (function + | Invalid_accusation_inconsistent_consensus_slot -> Some () | _ -> None) + (fun () -> Invalid_accusation_inconsistent_consensus_slot) ; + register_error_kind + `Permanent + ~id:"validate.operation.invalid_accusation_of_preattestation" + ~title:"Invalid DAL denunciation of preattestation" + ~description: + "DAL denunciations cannot target preattestations, since they have no \ + DAL content." + empty + (function Invalid_accusation_of_preattestation -> Some () | _ -> None) + (fun () -> Invalid_accusation_of_preattestation) ; register_error_kind `Temporary ~id:"validate.operation.block.too_early_dal_denunciation" @@ -1161,12 +1185,14 @@ module Anonymous = struct ~id:"validate.operation.invalid_accusation_no_dal_content" ~title:"Invalid accusation: no DAL content" ~description: - "Invalid accusation: the attestation operation has no DAL content." + "Invalid accusation: the attestation operation has no DAL content for \ + the denounced consensus slot." ~pp:(fun ppf (tb_slot, level, slot_index) -> Format.fprintf ppf - "Invalid accusation for validator slot %a, level %a, and DAL slot \ - index %a: the attestation operation has no DAL content." + "Invalid accusation for consensus slot %a, level %a, and DAL slot \ + index %a: the attestation operation has no DAL content for this \ + consensus slot." Slot.pp tb_slot Raw_level.pp diff --git a/src/proto_alpha/lib_protocol/validate_errors.mli b/src/proto_alpha/lib_protocol/validate_errors.mli index aa1cc43b28f3..d34bd8761f78 100644 --- a/src/proto_alpha/lib_protocol/validate_errors.mli +++ b/src/proto_alpha/lib_protocol/validate_errors.mli @@ -170,6 +170,8 @@ module Anonymous : sig level : Raw_level.t; last_cycle : Cycle.t; } + | Invalid_accusation_inconsistent_consensus_slot + | Invalid_accusation_of_preattestation | Too_early_dal_denunciation of {level : Raw_level.t; current : Raw_level.t} | Outdated_dal_denunciation of {level : Raw_level.t; last_cycle : Cycle.t} | Invalid_shard_index of {given : int; min : int; max : int} -- GitLab From 901bb0739d6d52a5e235e839049657bb362c5809 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 16 May 2025 17:35:21 +0200 Subject: [PATCH 4/6] Kaitai: update dal_entrapment_evidence to cover attestations aggregate Generated with: dune exec -- client-libs/bin_codec_kaitai/codec.exe dump kaitai specs in client-libs/kaitai-struct-files/files --- .../files/alpha__operation.ksy | 44 ++++++++++++++++++- .../alpha__operation__bls_mode_unsigned.ksy | 44 ++++++++++++++++++- .../files/alpha__operation__contents.ksy | 44 ++++++++++++++++++- .../files/alpha__operation__contents_list.ksy | 44 ++++++++++++++++++- .../files/alpha__operation__protocol_data.ksy | 44 ++++++++++++++++++- .../files/alpha__operation__unsigned.ksy | 44 ++++++++++++++++++- 6 files changed, 252 insertions(+), 12 deletions(-) diff --git a/client-libs/kaitai-struct-files/files/alpha__operation.ksy b/client-libs/kaitai-struct-files/files/alpha__operation.ksy index 8c1c49181d1c..656b7ad70349 100644 --- a/client-libs/kaitai-struct-files/files/alpha__operation.ksy +++ b/client-libs/kaitai-struct-files/files/alpha__operation.ksy @@ -91,6 +91,38 @@ types: - id: attestation_with_dal type: attestation_with_dal if: (alpha__inlined__attestation_mempool__contents_tag == alpha__inlined__attestation_mempool__contents_tag::attestation_with_dal) + alpha__inlined__consensus_operation: + seq: + - id: alpha__inlined__consensus_operation + type: operation__shell_header + - id: operations + type: alpha__inlined__consensus_operation__contents + - id: signature_tag + type: u1 + enum: bool + - id: signature + size-eos: true + if: (signature_tag == bool::true) + alpha__inlined__consensus_operation__contents: + seq: + - id: alpha__inlined__consensus_operation__contents_tag + type: u1 + enum: alpha__inlined__consensus_operation__contents_tag + - id: preattestation + type: preattestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestation) + - id: attestation + type: attestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation) + - id: attestation_with_dal + type: attestation_with_dal + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation_with_dal) + - id: preattestations_aggregate + type: preattestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestations_aggregate) + - id: attestations_aggregate + type: attestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestations_aggregate) alpha__inlined__preattestation: seq: - id: alpha__inlined__preattestation @@ -291,8 +323,8 @@ types: size: 32 attestation_0: seq: - - id: alpha__inlined__attestation - type: alpha__inlined__attestation + - id: alpha__inlined__consensus_operation + type: alpha__inlined__consensus_operation attestation_1: seq: - id: len_attestation @@ -469,6 +501,8 @@ types: seq: - id: attestation type: attestation_1 + - id: consensus_slot + type: u2be - id: slot_index type: u1 - id: shard_with_proof @@ -1649,6 +1683,12 @@ enums: alpha__inlined__attestation_mempool__contents_tag: 21: attestation 23: attestation_with_dal + alpha__inlined__consensus_operation__contents_tag: + 20: preattestation + 21: attestation + 23: attestation_with_dal + 30: preattestations_aggregate + 31: attestations_aggregate alpha__inlined__preattestation__contents_tag: 20: preattestation alpha__michelson__v1__primitives: diff --git a/client-libs/kaitai-struct-files/files/alpha__operation__bls_mode_unsigned.ksy b/client-libs/kaitai-struct-files/files/alpha__operation__bls_mode_unsigned.ksy index d92a100adc72..08c81623cc03 100644 --- a/client-libs/kaitai-struct-files/files/alpha__operation__bls_mode_unsigned.ksy +++ b/client-libs/kaitai-struct-files/files/alpha__operation__bls_mode_unsigned.ksy @@ -91,6 +91,38 @@ types: - id: attestation_with_dal type: attestation_with_dal if: (alpha__inlined__attestation_mempool__contents_tag == alpha__inlined__attestation_mempool__contents_tag::attestation_with_dal) + alpha__inlined__consensus_operation: + seq: + - id: alpha__inlined__consensus_operation + type: operation__shell_header + - id: operations + type: alpha__inlined__consensus_operation__contents + - id: signature_tag + type: u1 + enum: bool + - id: signature + size-eos: true + if: (signature_tag == bool::true) + alpha__inlined__consensus_operation__contents: + seq: + - id: alpha__inlined__consensus_operation__contents_tag + type: u1 + enum: alpha__inlined__consensus_operation__contents_tag + - id: preattestation + type: preattestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestation) + - id: attestation + type: attestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation) + - id: attestation_with_dal + type: attestation_with_dal + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation_with_dal) + - id: preattestations_aggregate + type: preattestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestations_aggregate) + - id: attestations_aggregate + type: attestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestations_aggregate) alpha__inlined__preattestation: seq: - id: alpha__inlined__preattestation @@ -284,8 +316,8 @@ types: size: 32 attestation_0: seq: - - id: alpha__inlined__attestation - type: alpha__inlined__attestation + - id: alpha__inlined__consensus_operation + type: alpha__inlined__consensus_operation attestation_1: seq: - id: len_attestation @@ -470,6 +502,8 @@ types: seq: - id: attestation type: attestation_1 + - id: consensus_slot + type: u2be - id: slot_index type: u1 - id: shard_with_proof @@ -1650,6 +1684,12 @@ enums: alpha__inlined__attestation_mempool__contents_tag: 21: attestation 23: attestation_with_dal + alpha__inlined__consensus_operation__contents_tag: + 20: preattestation + 21: attestation + 23: attestation_with_dal + 30: preattestations_aggregate + 31: attestations_aggregate alpha__inlined__preattestation__contents_tag: 20: preattestation alpha__michelson__v1__primitives: diff --git a/client-libs/kaitai-struct-files/files/alpha__operation__contents.ksy b/client-libs/kaitai-struct-files/files/alpha__operation__contents.ksy index 9461d2da6ad3..e86c7cb8db82 100644 --- a/client-libs/kaitai-struct-files/files/alpha__operation__contents.ksy +++ b/client-libs/kaitai-struct-files/files/alpha__operation__contents.ksy @@ -91,6 +91,38 @@ types: - id: attestation_with_dal type: attestation_with_dal if: (alpha__inlined__attestation_mempool__contents_tag == alpha__inlined__attestation_mempool__contents_tag::attestation_with_dal) + alpha__inlined__consensus_operation: + seq: + - id: alpha__inlined__consensus_operation + type: operation__shell_header + - id: operations + type: alpha__inlined__consensus_operation__contents + - id: signature_tag + type: u1 + enum: bool + - id: signature + size-eos: true + if: (signature_tag == bool::true) + alpha__inlined__consensus_operation__contents: + seq: + - id: alpha__inlined__consensus_operation__contents_tag + type: u1 + enum: alpha__inlined__consensus_operation__contents_tag + - id: preattestation + type: preattestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestation) + - id: attestation + type: attestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation) + - id: attestation_with_dal + type: attestation_with_dal + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation_with_dal) + - id: preattestations_aggregate + type: preattestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestations_aggregate) + - id: attestations_aggregate + type: attestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestations_aggregate) alpha__inlined__preattestation: seq: - id: alpha__inlined__preattestation @@ -280,8 +312,8 @@ types: size: 32 attestation_0: seq: - - id: alpha__inlined__attestation - type: alpha__inlined__attestation + - id: alpha__inlined__consensus_operation + type: alpha__inlined__consensus_operation attestation_1: seq: - id: len_attestation @@ -446,6 +478,8 @@ types: seq: - id: attestation type: attestation_1 + - id: consensus_slot + type: u2be - id: slot_index type: u1 - id: shard_with_proof @@ -1626,6 +1660,12 @@ enums: alpha__inlined__attestation_mempool__contents_tag: 21: attestation 23: attestation_with_dal + alpha__inlined__consensus_operation__contents_tag: + 20: preattestation + 21: attestation + 23: attestation_with_dal + 30: preattestations_aggregate + 31: attestations_aggregate alpha__inlined__preattestation__contents_tag: 20: preattestation alpha__michelson__v1__primitives: diff --git a/client-libs/kaitai-struct-files/files/alpha__operation__contents_list.ksy b/client-libs/kaitai-struct-files/files/alpha__operation__contents_list.ksy index f3ca9c7c3e5a..f3c0647035f7 100644 --- a/client-libs/kaitai-struct-files/files/alpha__operation__contents_list.ksy +++ b/client-libs/kaitai-struct-files/files/alpha__operation__contents_list.ksy @@ -91,6 +91,38 @@ types: - id: attestation_with_dal type: attestation_with_dal if: (alpha__inlined__attestation_mempool__contents_tag == alpha__inlined__attestation_mempool__contents_tag::attestation_with_dal) + alpha__inlined__consensus_operation: + seq: + - id: alpha__inlined__consensus_operation + type: operation__shell_header + - id: operations + type: alpha__inlined__consensus_operation__contents + - id: signature_tag + type: u1 + enum: bool + - id: signature + size-eos: true + if: (signature_tag == bool::true) + alpha__inlined__consensus_operation__contents: + seq: + - id: alpha__inlined__consensus_operation__contents_tag + type: u1 + enum: alpha__inlined__consensus_operation__contents_tag + - id: preattestation + type: preattestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestation) + - id: attestation + type: attestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation) + - id: attestation_with_dal + type: attestation_with_dal + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation_with_dal) + - id: preattestations_aggregate + type: preattestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestations_aggregate) + - id: attestations_aggregate + type: attestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestations_aggregate) alpha__inlined__preattestation: seq: - id: alpha__inlined__preattestation @@ -284,8 +316,8 @@ types: size: 32 attestation_0: seq: - - id: alpha__inlined__attestation - type: alpha__inlined__attestation + - id: alpha__inlined__consensus_operation + type: alpha__inlined__consensus_operation attestation_1: seq: - id: len_attestation @@ -450,6 +482,8 @@ types: seq: - id: attestation type: attestation_1 + - id: consensus_slot + type: u2be - id: slot_index type: u1 - id: shard_with_proof @@ -1630,6 +1664,12 @@ enums: alpha__inlined__attestation_mempool__contents_tag: 21: attestation 23: attestation_with_dal + alpha__inlined__consensus_operation__contents_tag: + 20: preattestation + 21: attestation + 23: attestation_with_dal + 30: preattestations_aggregate + 31: attestations_aggregate alpha__inlined__preattestation__contents_tag: 20: preattestation alpha__michelson__v1__primitives: diff --git a/client-libs/kaitai-struct-files/files/alpha__operation__protocol_data.ksy b/client-libs/kaitai-struct-files/files/alpha__operation__protocol_data.ksy index 6c97b771a311..0d1529b6c4e6 100644 --- a/client-libs/kaitai-struct-files/files/alpha__operation__protocol_data.ksy +++ b/client-libs/kaitai-struct-files/files/alpha__operation__protocol_data.ksy @@ -91,6 +91,38 @@ types: - id: attestation_with_dal type: attestation_with_dal if: (alpha__inlined__attestation_mempool__contents_tag == alpha__inlined__attestation_mempool__contents_tag::attestation_with_dal) + alpha__inlined__consensus_operation: + seq: + - id: alpha__inlined__consensus_operation + type: operation__shell_header + - id: operations + type: alpha__inlined__consensus_operation__contents + - id: signature_tag + type: u1 + enum: bool + - id: signature + size-eos: true + if: (signature_tag == bool::true) + alpha__inlined__consensus_operation__contents: + seq: + - id: alpha__inlined__consensus_operation__contents_tag + type: u1 + enum: alpha__inlined__consensus_operation__contents_tag + - id: preattestation + type: preattestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestation) + - id: attestation + type: attestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation) + - id: attestation_with_dal + type: attestation_with_dal + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation_with_dal) + - id: preattestations_aggregate + type: preattestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestations_aggregate) + - id: attestations_aggregate + type: attestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestations_aggregate) alpha__inlined__preattestation: seq: - id: alpha__inlined__preattestation @@ -291,8 +323,8 @@ types: size: 32 attestation_0: seq: - - id: alpha__inlined__attestation - type: alpha__inlined__attestation + - id: alpha__inlined__consensus_operation + type: alpha__inlined__consensus_operation attestation_1: seq: - id: len_attestation @@ -469,6 +501,8 @@ types: seq: - id: attestation type: attestation_1 + - id: consensus_slot + type: u2be - id: slot_index type: u1 - id: shard_with_proof @@ -1649,6 +1683,12 @@ enums: alpha__inlined__attestation_mempool__contents_tag: 21: attestation 23: attestation_with_dal + alpha__inlined__consensus_operation__contents_tag: + 20: preattestation + 21: attestation + 23: attestation_with_dal + 30: preattestations_aggregate + 31: attestations_aggregate alpha__inlined__preattestation__contents_tag: 20: preattestation alpha__michelson__v1__primitives: diff --git a/client-libs/kaitai-struct-files/files/alpha__operation__unsigned.ksy b/client-libs/kaitai-struct-files/files/alpha__operation__unsigned.ksy index 9839de7519de..2f9a95355340 100644 --- a/client-libs/kaitai-struct-files/files/alpha__operation__unsigned.ksy +++ b/client-libs/kaitai-struct-files/files/alpha__operation__unsigned.ksy @@ -91,6 +91,38 @@ types: - id: attestation_with_dal type: attestation_with_dal if: (alpha__inlined__attestation_mempool__contents_tag == alpha__inlined__attestation_mempool__contents_tag::attestation_with_dal) + alpha__inlined__consensus_operation: + seq: + - id: alpha__inlined__consensus_operation + type: operation__shell_header + - id: operations + type: alpha__inlined__consensus_operation__contents + - id: signature_tag + type: u1 + enum: bool + - id: signature + size-eos: true + if: (signature_tag == bool::true) + alpha__inlined__consensus_operation__contents: + seq: + - id: alpha__inlined__consensus_operation__contents_tag + type: u1 + enum: alpha__inlined__consensus_operation__contents_tag + - id: preattestation + type: preattestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestation) + - id: attestation + type: attestation + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation) + - id: attestation_with_dal + type: attestation_with_dal + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestation_with_dal) + - id: preattestations_aggregate + type: preattestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::preattestations_aggregate) + - id: attestations_aggregate + type: attestations_aggregate + if: (alpha__inlined__consensus_operation__contents_tag == alpha__inlined__consensus_operation__contents_tag::attestations_aggregate) alpha__inlined__preattestation: seq: - id: alpha__inlined__preattestation @@ -287,8 +319,8 @@ types: size: 32 attestation_0: seq: - - id: alpha__inlined__attestation - type: alpha__inlined__attestation + - id: alpha__inlined__consensus_operation + type: alpha__inlined__consensus_operation attestation_1: seq: - id: len_attestation @@ -457,6 +489,8 @@ types: seq: - id: attestation type: attestation_1 + - id: consensus_slot + type: u2be - id: slot_index type: u1 - id: shard_with_proof @@ -1637,6 +1671,12 @@ enums: alpha__inlined__attestation_mempool__contents_tag: 21: attestation 23: attestation_with_dal + alpha__inlined__consensus_operation__contents_tag: + 20: preattestation + 21: attestation + 23: attestation_with_dal + 30: preattestations_aggregate + 31: attestations_aggregate alpha__inlined__preattestation__contents_tag: 20: preattestation alpha__michelson__v1__primitives: -- GitLab From dbedfb94ed673b7571205f7049d102fcf6a17649 Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Fri, 16 May 2025 18:48:37 +0200 Subject: [PATCH 5/6] Tezt: update dal_entrapment_evidence json for alpha --- tezt/lib_tezos/operation_core.ml | 49 +++++++++++++++++++++---------- tezt/lib_tezos/operation_core.mli | 3 +- tezt/tests/dal.ml | 21 ++++++++----- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index 99516f7ed0b3..c8a017de3670 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -593,9 +593,12 @@ module Anonymous = struct } | Dal_entrapment_evidence of { attestation : t * Tezos_crypto.Signature.t; + consensus_slot : int; slot_index : int; shard : Tezos_crypto_dal.Cryptobox.shard; proof : Tezos_crypto_dal.Cryptobox.shard_proof; + protocol : Protocol.t; + (* encoding of Dal_entrapment_evidence has changed in protocol S *) } let double_consensus_evidence ~kind (({kind = op1_kind; _}, _) as op1) @@ -620,12 +623,20 @@ module Anonymous = struct let double_preattestation_evidence = double_consensus_evidence ~kind:Double_preattestation_evidence - let dal_entrapment_evidence ~attestation ~slot_index shard proof = - let {kind = op_kind; _}, _ = attestation in + let dal_entrapment_evidence_standalone_attestation ~protocol ~attestation + ~slot_index shard proof = + let {kind = op_kind; contents; _}, _ = attestation in match op_kind with | Consensus {kind = Attestation _; _} -> - Dal_entrapment_evidence {attestation; slot_index; shard; proof} - | _ -> Test.fail "Invalid arguments to create a dal_entrapment_evidence" + let consensus_slot = + JSON.(annotate ~origin:__LOC__ contents |=> 0 |-> "slot" |> as_int) + in + Dal_entrapment_evidence + {attestation; consensus_slot; slot_index; shard; proof; protocol} + | _ -> + Test.fail + "wrong kind of denounced operation for \ + dal_entrapment_evidence_standalone_attestation" let kind_to_string kind = sf @@ -662,20 +673,26 @@ module Anonymous = struct ("op1", op1); ("op2", op2); ] - | Dal_entrapment_evidence {attestation; slot_index; shard; proof} -> + | Dal_entrapment_evidence + {attestation; consensus_slot; slot_index; shard; proof; protocol} -> let attestation = denunced_op_json attestation in `O - [ - ("kind", Ezjsonm.string "dal_entrapment_evidence"); - ("attestation", attestation); - ("slot_index", json_of_int slot_index); - ( "shard_with_proof", - `O - [ - ("shard", json_of_shard shard); - ("proof", json_of_shard_proof proof); - ] ); - ] + ([ + ("kind", Ezjsonm.string "dal_entrapment_evidence"); + ("attestation", attestation); + ] + @ (if Protocol.(number protocol > number R022) then + [("consensus_slot", json_of_int consensus_slot)] + else []) + @ [ + ("slot_index", json_of_int slot_index); + ( "shard_with_proof", + `O + [ + ("shard", json_of_shard shard); + ("proof", json_of_shard_proof proof); + ] ); + ]) let operation ?branch anonymous_operation client = let json = `A [json anonymous_operation] in diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index ba619b7b5a6d..15e64691bd8d 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -396,7 +396,8 @@ module Anonymous : sig t (** [dal_entrapment_evidence] crafts a DAL entrapment evidence operation. *) - val dal_entrapment_evidence : + val dal_entrapment_evidence_standalone_attestation : + protocol:Protocol.t -> attestation:operation * Tezos_crypto.Signature.t -> slot_index:int -> Tezos_crypto_dal.Cryptobox.shard -> diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 44c482ed3718..7e4109ce482c 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -8517,7 +8517,7 @@ let test_attesters_receive_dal_rewards _protocol dal_parameters _cryptobox node attestation_lag). In protocol S we will not need this restriction. *) -let test_inject_accusation _protocol dal_parameters cryptobox node client +let test_inject_accusation protocol dal_parameters cryptobox node client _bootstrap_key = let slot_index = 0 in let slot_size = dal_parameters.Dal.Parameters.cryptobox.slot_size in @@ -8571,7 +8571,8 @@ let test_inject_accusation _protocol dal_parameters cryptobox node client |> Option.get in let accusation = - Operation.Anonymous.dal_entrapment_evidence + Operation.Anonymous.dal_entrapment_evidence_standalone_attestation + ~protocol ~attestation ~slot_index shard @@ -8852,7 +8853,7 @@ let test_attester_did_not_attest (_protocol : Protocol.t) 2. at the next cycle (expecting delegate already denounced) 3. at the next-next cycle (expecting outdated evidence) *) -let test_duplicate_denunciations _protocol dal_parameters cryptobox node client +let test_duplicate_denunciations protocol dal_parameters cryptobox node client _bootstrap_key = let slot_index = 0 in Log.info "Bake two blocks" ; @@ -8909,7 +8910,8 @@ let test_duplicate_denunciations _protocol dal_parameters cryptobox node client shards_with_proofs |> Option.get in - Operation.Anonymous.dal_entrapment_evidence + Operation.Anonymous.dal_entrapment_evidence_standalone_attestation + ~protocol ~attestation ~slot_index shard1 @@ -8922,7 +8924,8 @@ let test_duplicate_denunciations _protocol dal_parameters cryptobox node client shards_with_proofs |> Option.get in - Operation.Anonymous.dal_entrapment_evidence + Operation.Anonymous.dal_entrapment_evidence_standalone_attestation + ~protocol ~attestation ~slot_index shard2 @@ -8979,7 +8982,7 @@ let test_duplicate_denunciations _protocol dal_parameters cryptobox node client inject an accusation for the first one at cycle `c` and another at for the second one at cycle `c + 1`, both injections are expected to succeed. *) -let test_denunciation_next_cycle _protocol dal_parameters cryptobox node client +let test_denunciation_next_cycle protocol dal_parameters cryptobox node client _bootstrap_key = let* proto_params = Node.RPC.call node @@ RPC.get_chain_block_context_constants () @@ -9060,7 +9063,8 @@ let test_denunciation_next_cycle _protocol dal_parameters cryptobox node client |> Option.get in let accusation = - Operation.Anonymous.dal_entrapment_evidence + Operation.Anonymous.dal_entrapment_evidence_standalone_attestation + ~protocol ~attestation ~slot_index shard @@ -9109,7 +9113,8 @@ let test_denunciation_next_cycle _protocol dal_parameters cryptobox node client |> Option.get in let accusation = - Operation.Anonymous.dal_entrapment_evidence + Operation.Anonymous.dal_entrapment_evidence_standalone_attestation + ~protocol ~attestation ~slot_index shard -- GitLab From a85058583131a3a85fd6f04cdb33e875c95cff2e Mon Sep 17 00:00:00 2001 From: Diane Gallois-Wong Date: Tue, 20 May 2025 16:55:43 +0200 Subject: [PATCH 6/6] Changelog: Dal_entrapment_evidence changes --- docs/protocols/alpha.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/protocols/alpha.rst b/docs/protocols/alpha.rst index 96513186b819..2c3baddfbb29 100644 --- a/docs/protocols/alpha.rst +++ b/docs/protocols/alpha.rst @@ -76,6 +76,16 @@ RPC Changes with the new field ``companion_key`` which returns the active companion key for the given ``delegate`` and ``level``. (MR :gl:`!17703`) +Operations +---------- + +- The ``Dal_entrapment_evidence`` operation has a new + ``consensus_slot`` field, and its ``attestation`` field may now + contain any kind of consensus operation. For the evidence to be + valid, ``attestation`` must be either a standalone attestation for + ``consensus_slot``, or an attestations aggregate whose committee + includes ``consensus_slot``. (MR :gl:`!18073`) + Operation receipts ------------------ -- GitLab