From d7145892241b6cb6181ef700abdd3f6db4eb02f5 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 14 Dec 2023 10:40:52 +0100 Subject: [PATCH 1/4] Proto/Alpha: do not use prefix with open module --- src/proto_alpha/lib_protocol/TEZOS_PROTOCOL | 2 +- src/proto_alpha/lib_protocol/mempool_validation.ml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index 9077f84ff78a..11216be38d1c 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -284,7 +284,7 @@ "Delegate_services", "Voting_services", "Dal_services", - "Adaptive_issuance_services", + "Adaptive_issuance_services", "Alpha_services", "Main" diff --git a/src/proto_alpha/lib_protocol/mempool_validation.ml b/src/proto_alpha/lib_protocol/mempool_validation.ml index e816542c8086..3978dd6d2dba 100644 --- a/src/proto_alpha/lib_protocol/mempool_validation.ml +++ b/src/proto_alpha/lib_protocol/mempool_validation.ml @@ -32,7 +32,7 @@ type t = { operations : packed_operation Operation_hash.Map.t; } -type validation_info = Validate.info +type validation_info = info type add_result = Added | Replaced of {removed : Operation_hash.t} | Unchanged @@ -58,7 +58,7 @@ let encoding : t Data_encoding.t = {predecessor_hash; operation_state; operations}) @@ obj3 (req "predecessor_hash" Block_hash.encoding) - (req "operation_state" Validate.operation_conflict_state_encoding) + (req "operation_state" operation_conflict_state_encoding) (req "operations" (Operation_hash.Map.encoding -- GitLab From 99c281336150acb6bb5b2190eaebce141770a87d Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 14 Dec 2023 17:10:04 +0100 Subject: [PATCH 2/4] Proto/Alpha: add comment about consensus op conflicts in mempool mode --- src/proto_alpha/lib_protocol/validate.ml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/proto_alpha/lib_protocol/validate.ml b/src/proto_alpha/lib_protocol/validate.ml index 122f37adbbea..843b83f1eaf3 100644 --- a/src/proto_alpha/lib_protocol/validate.ml +++ b/src/proto_alpha/lib_protocol/validate.ml @@ -41,11 +41,15 @@ let init_consensus_info ctxt (predecessor_level, predecessor_round) = attestation_slot_map = Consensus.allowed_attestations ctxt; } -(** Map used to detect consensus operation conflicts. Each delegate - may (pre)attest at most once for each level and round, so two - attestations (resp. two preattestations) conflict when they have +(** Map used to detect consensus operation conflicts. Each delegate may + (pre)attest at most once for each level and round, so two attestations + (resp. two DAL attestations or two preattestations) conflict when they have the same slot, level, and round. + Note that when validating the mempool, several (DAL/pre)attestations by the + same delegate at the same level and round would not conflict if they have + different Tenderbake slots. + Note that when validating a block, all attestations (resp. all preattestations) must have the same level and round anyway, so only the slot is relevant. Taking the level and round into account is -- GitLab From afb26cb6dfee570c21233658951f7d6baf3df1ca Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Mon, 18 Dec 2023 11:23:47 +0100 Subject: [PATCH 3/4] DAL/Test: build DAL attestation using RPC instead of context --- .../lib_protocol/test/helpers/context.ml | 4 ++ .../lib_protocol/test/helpers/context.mli | 8 ++++ .../lib_protocol/test/helpers/op.ml | 39 +++++++++++++++ .../lib_protocol/test/helpers/op.mli | 21 ++++++++ .../validate/generator_descriptors.ml | 48 +------------------ 5 files changed, 73 insertions(+), 47 deletions(-) diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.ml b/src/proto_alpha/lib_protocol/test/helpers/context.ml index 2597c295a8fa..db0915524e47 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/context.ml @@ -330,6 +330,10 @@ let get_ai_expected_issuance ctxt = let get_denunciations ctxt = Alpha_services.Denunciations.denunciations rpc_ctxt ctxt +module Dal = struct + let shards ctxt = Plugin.RPC.Dal.dal_shards rpc_ctxt ctxt +end + (* Voting *) module Vote = struct diff --git a/src/proto_alpha/lib_protocol/test/helpers/context.mli b/src/proto_alpha/lib_protocol/test/helpers/context.mli index f3bd07584935..f11ba7002be5 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/context.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/context.mli @@ -182,6 +182,14 @@ module Vote : sig val get_delegate_proposal_count : t -> public_key_hash -> int tzresult Lwt.t end +module Dal : sig + val shards : + t -> + ?level:Raw_level.t -> + unit -> + (Signature.Public_key_hash.t * (int * int)) list tzresult Lwt.t +end + module Contract : sig val pp : Format.formatter -> Contract.t -> unit diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 1ee5db7cea78..4c4dae662449 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -133,6 +133,45 @@ let attestation ?delegate ?slot ?level ?round ?block_payload_hash ?branch in return (Operation.pack op) +let raw_dal_attestation ?delegate ?attestation block = + let open Lwt_result_wrap_syntax in + let ctxt = Context.B block in + let*? level = Context.get_level ctxt in + let* committee = Context.Dal.shards ctxt () in + let delegate = + match delegate with None -> Stdlib.List.hd committee |> fst | Some d -> d + in + match + List.assoc ~equal:Signature.Public_key_hash.equal delegate committee + with + | None -> return_none + | Some _interval -> ( + let* slots = Context.get_attester_slot ctxt delegate in + match slots with + | None -> return_none + | Some slots -> ( + match List.hd slots with + | None -> assert false + | Some slot -> + let attestation = + Option.value attestation ~default:Dal.Attestation.empty + in + let branch = block.Block.header.shell.predecessor in + let* signer = Account.find delegate in + let op = Single (Dal_attestation {attestation; level; slot}) in + sign + ~watermark: + Operation.(to_watermark (Dal_attestation Chain_id.zero)) + signer.sk + branch + op + |> return_some)) + +let dal_attestation ?delegate ?attestation block = + let open Lwt_result_wrap_syntax in + let* op = raw_dal_attestation ?delegate ?attestation block in + return (Option.map Operation.pack op) + let raw_preattestation ?delegate ?slot ?level ?round ?block_payload_hash ?branch attested_block = let open Lwt_result_syntax in diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index 32d215b5e27f..adea59f7c646 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -97,6 +97,27 @@ val attestation : Block.t -> Operation.packed tzresult Lwt.t +(** Build a DAL attestation for the given [delegate] and the given [block]'s + level (to be included in the block at the next level), if + possible. Otherwise returns [None]. It is possible to build one if: + [delegate] is part of the DAL committee for the current epoch, and + [delegate] is part of the TB committee for the current level. Recall that + the slot to be included in the attestation is the delegate's first TB slot + at the current level. *) +val raw_dal_attestation : + ?delegate:public_key_hash -> + ?attestation:Dal.Attestation.t -> + Block.t -> + Kind.dal_attestation Operation.t option tzresult Lwt.t + +(** Create a packed DAL attestation that is expected for a given + [Block.t] by packing the result of {!raw_dal_attestation}. *) +val dal_attestation : + ?delegate:public_key_hash -> + ?attestation:Dal.Attestation.t -> + Block.t -> + Operation.packed option tzresult Lwt.t + (** Create a packed preattestation that is expected for a given [Block.t] by packing the result of {!raw_preattestation}. *) val preattestation : 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 be69874a7883..1581845e7cde 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 @@ -633,46 +633,6 @@ let attestation_descriptor = List.filter_map_es gen state.delegates); } -(* TODO: #4917 remove direct dependency of the alpha_context. *) -(* Build a DAL attestation for the given [delegate] and the given [block]'s - level (to be included in the block at the next level), if possible. Otherwise - returns [None]. It is possible to build one if: [delegate] is part of the DAL - committee for the current epoch, and [delegate] is part of the TB committee - for the current level. Recall that the slot to be included in the attestation - is the delegate's first TB slot at the current level. *) -let dal_attestation ctxt delegate block = - let open Lwt_result_wrap_syntax in - let*? level = Context.get_level (B block) in - let*@ committee = - Alpha_context.Level.from_raw ctxt level |> Dal_apply.compute_committee ctxt - in - match - Environment.Signature.Public_key_hash.Map.find - delegate - committee.pkh_to_shards - with - | None -> return_none - | Some _interval -> ( - let* slots = Context.get_attester_slot (B block) delegate in - match slots with - | None -> return_none - | Some slots -> ( - match List.hd slots with - | None -> assert false - | Some slot -> - (* The content of the attestation does not matter for covalidity. *) - let attestation = Dal.Attestation.empty in - let branch = block.Block.header.shell.predecessor in - let* signer = Account.find delegate in - let op = Single (Dal_attestation {attestation; level; slot}) in - Op.sign - ~watermark: - Operation.(to_watermark (Dal_attestation Chain_id.zero)) - signer.sk - branch - (Contents_list op) - |> return_some)) - let dal_attestation_descriptor = let open Lwt_result_syntax in { @@ -687,13 +647,7 @@ let dal_attestation_descriptor = opt_prelude = None; candidates_generator = (fun state -> - let gen (delegate, _) = - let* ctxt = - let+ incr = Incremental.begin_construction state.block in - Incremental.alpha_ctxt incr - in - dal_attestation ctxt delegate state.block - in + let gen (delegate, _) = Op.dal_attestation ~delegate state.block in List.filter_map_es gen state.delegates); } -- GitLab From 2c04d37852817a7db2ea94d293873731bfc71413 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 14 Dec 2023 20:47:40 +0100 Subject: [PATCH 4/4] DAL/Test: add test for double attestation in block --- .../integration/consensus/test_attestation.ml | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) 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 00de79d18983..1ef41b60577b 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 @@ -36,9 +36,11 @@ open Protocol open Alpha_context -let init_genesis ?policy () = +let init_genesis ?policy ?dal_enable () = let open Lwt_result_syntax in - let* genesis, _contracts = Context.init_n ~consensus_threshold:0 5 () in + let* genesis, _contracts = + Context.init_n ?dal_enable ~consensus_threshold:0 5 () + in let* b = Block.bake ?policy genesis in return (genesis, b) @@ -646,6 +648,35 @@ let test_attestation_threshold ~sufficient_threshold () = | Validate_errors.Block.Not_enough_attestations _ -> true | _ -> false) +let test_two_dal_attestations_with_same_attester () = + let open Lwt_result_syntax in + let* _genesis, attested_block = init_genesis ~dal_enable:true () in + let* op1 = Op.raw_dal_attestation attested_block in + let op1 = Stdlib.Option.get op1 in + let attestation = + Dal.Attestation.commit Dal.Attestation.empty Dal.Slot_index.zero + in + let* op2 = Op.raw_dal_attestation ~attestation attested_block in + let op2 = Stdlib.Option.get op2 in + let*! res = + Block.bake + ~baking_mode:Application + ~operations:[Operation.pack op1; Operation.pack op2] + attested_block + in + let error = function + | Validate_errors.( + Consensus.Conflicting_consensus_operation + { + kind = Dal_attestation; + conflict = Operation_conflict {existing; new_operation}; + }) -> + Operation_hash.equal existing (Operation.hash op1) + && Operation_hash.equal new_operation (Operation.hash op2) + | _ -> false + in + Assert.proto_error ~loc:__LOC__ res error + let tests = [ (* Positive tests *) @@ -697,6 +728,10 @@ let tests = "insufficient attestation threshold" `Quick (test_attestation_threshold ~sufficient_threshold:false); + Tztest.tztest + "two DAL attestations with same attester in a block" + `Quick + test_two_dal_attestations_with_same_attester; ] let () = -- GitLab