From 30a986943be6861712a3058ee285b2dfa6eaafd6 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 14 Jan 2025 06:23:20 +0100 Subject: [PATCH 1/2] Tests/Alpha: add function to create a DAL entrapment op --- src/proto_alpha/lib_protocol/test/helpers/op.ml | 10 ++++++++++ src/proto_alpha/lib_protocol/test/helpers/op.mli | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.ml b/src/proto_alpha/lib_protocol/test/helpers/op.ml index 7a9ea8c4d771..c63336d56ada 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/op.ml @@ -809,6 +809,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 contents = + Single (Dal_entrapment_evidence {attestation; slot_index; shard_with_proof}) + in + let branch = Context.branch ctxt in + { + shell = {branch}; + protocol_data = Operation_data {contents; signature = None}; + } + let seed_nonce_revelation ctxt level nonce = { shell = {branch = Context.branch ctxt}; diff --git a/src/proto_alpha/lib_protocol/test/helpers/op.mli b/src/proto_alpha/lib_protocol/test/helpers/op.mli index ab6b5477f890..a216caf786c6 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/op.mli +++ b/src/proto_alpha/lib_protocol/test/helpers/op.mli @@ -362,6 +362,13 @@ val double_baking : Block_header.block_header -> Operation.packed +val dal_entrapment : + Context.t -> + Kind.attestation operation -> + Dal.Slot_index.t -> + Dal.Shard_with_proof.t -> + Operation.packed + val activation : Context.t -> Signature.Public_key_hash.t -> -- GitLab From c84ee83ca292f29558de96fd4fa646eabe44fee1 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 14 Jan 2025 06:24:22 +0100 Subject: [PATCH 2/2] Tests/Alpha: add some unit tests for DAL accusations --- manifest/product_octez.ml | 1 + .../test/integration/consensus/dune | 3 +- .../consensus/test_dal_entrapment.ml | 193 ++++++++++++++++++ 3 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml diff --git a/manifest/product_octez.ml b/manifest/product_octez.ml index 923d21f972eb..742995edacf6 100644 --- a/manifest/product_octez.ml +++ b/manifest/product_octez.ml @@ -5524,6 +5524,7 @@ end = struct ("test_preendorsement", N.(number <= 017)); ("test_seed", true); ("test_aggregate", N.(number >= 022)); + ("test_dal_entrapment", N.(number >= 022)); ] |> conditional_list in diff --git a/src/proto_alpha/lib_protocol/test/integration/consensus/dune b/src/proto_alpha/lib_protocol/test/integration/consensus/dune index 7003ee398802..cf3e97f12b7b 100644 --- a/src/proto_alpha/lib_protocol/test/integration/consensus/dune +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/dune @@ -42,7 +42,8 @@ test_preattestation_functor test_preattestation test_seed - test_aggregate)) + test_aggregate + test_dal_entrapment)) (executable (name main) 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 new file mode 100644 index 000000000000..7c00e6c2acff --- /dev/null +++ b/src/proto_alpha/lib_protocol/test/integration/consensus/test_dal_entrapment.ml @@ -0,0 +1,193 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* SPDX-FileCopyrightText: 2025 Nomadic Labs, *) +(* *) +(*****************************************************************************) + +(** Testing + ------- + Component: Protocol (double baking) + Invocation: dune exec src/proto_alpha/lib_protocol/test/integration/consensus/main.exe \ + -- --file test_dal_entrapment.ml + + Subject: A DAL entrapment operation may be injected when it has been observed that + a baker has attested a slot for which one the shards is a trap. +*) + +open Protocol +open Alpha_context + +let commitment_and_proofs_cache = ref None + +(** Check various accusation operation injection scenarios. *) +let test_accusation_injection ?(initial_blocks_to_bake = 2) ?expect_failure + ?(publish_slot = true) ?(with_dal_content = true) ?(attest_slot = true) () = + let open Lwt_result_syntax in + let c = Default_parameters.constants_test in + let dal = {c.dal with incentives_enable = true; traps_fraction = Q.one} in + let cryptobox_parameters = dal.cryptobox_parameters in + let number_of_slots = dal.number_of_slots in + let lag = dal.attestation_lag in + let slot_size = cryptobox_parameters.slot_size in + let* cryptobox = Dal_helpers.mk_cryptobox cryptobox_parameters in + let constants = + { + c with + dal; + consensus_committee_size = cryptobox_parameters.number_of_shards; + consensus_threshold_size = 0; + } + in + let slot_index = + Dal.Slot_index.of_int_opt ~number_of_slots 3 |> Stdlib.Option.get + in + let other_slot_index = + Dal.Slot_index.of_int_opt ~number_of_slots 4 |> Stdlib.Option.get + in + let commitment, commitment_proof, shards_with_proofs = + match !commitment_and_proofs_cache with + | Some result -> result + | None -> + Log.info "generate slot and compute commitments and shards" ; + let slot = Tezt_tezos.Dal_common.Helpers.generate_slot ~slot_size in + let result = + Tezt_tezos.Dal_common.Helpers.get_commitment_and_shards_with_proofs + cryptobox + ~slot + in + (* Cache the result *) + commitment_and_proofs_cache := Some result ; + result + in + let* genesis, contract = Context.init_with_constants1 constants in + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7686 + We bake two blocks because we need the accusation to be introduced at level + at least 10 (2 = 10 - attestation_lag). In protocol S we will not need this + restriction. *) + let* blk = Block.bake_n initial_blocks_to_bake genesis in + let slot_header = + Dal.Operations.Publish_commitment.{slot_index; commitment; commitment_proof} + in + let* op = Op.dal_publish_commitment (B genesis) contract slot_header in + let* blk = + if publish_slot then Block.bake blk ~operation:op else Block.bake blk + in + let* blk = Block.bake_n (lag - 1) blk in + let dal_content = + if with_dal_content then + let attestation = + if attest_slot then Dal.Attestation.(commit empty slot_index) + else Dal.Attestation.(commit empty other_slot_index) + in + Some {attestation} + else None + in + let* attestation = Op.raw_attestation blk ?dal_content in + let (shard, proof), _ = Seq.uncons shards_with_proofs |> Stdlib.Option.get in + let shard_with_proof = Dal.Shard_with_proof.{shard; proof} in + let operation = + Op.dal_entrapment (B blk) attestation slot_index shard_with_proof + in + match expect_failure with + | None -> + let* _blk_final = Block.bake ~operation blk in + return_unit + | Some f -> + let expect_failure = f blk in + let* ctxt = Incremental.begin_construction blk in + let* _ = Incremental.add_operation ctxt operation ~expect_failure in + return_unit + +let test_invalid_accusation_too_close_to_migration = + let expect_failure blk = function + | [ + Environment.Ecoproto_error + (Validate_errors.Anonymous + .Denunciations_not_allowed_just_after_migration {level; _}); + ] + when Raw_level.to_int32 level = blk.Block.header.shell.level -> + Lwt_result_syntax.return_unit + | errs -> + failwith + "Error trace:@, %a does not match the expected one" + Error_monad.pp_print_trace + errs + in + test_accusation_injection ~initial_blocks_to_bake:1 ~expect_failure + +let test_invalid_accusation_no_dal_content = + let expect_failure blk = function + | [ + Environment.Ecoproto_error + (Validate_errors.Anonymous.Invalid_accusation_no_dal_content + {level; _}); + ] + when Raw_level.to_int32 level = blk.Block.header.shell.level -> + Lwt_result_syntax.return_unit + | errs -> + failwith + "Error trace:@, %a does not match the expected one" + Error_monad.pp_print_trace + errs + in + test_accusation_injection ~with_dal_content:false ~expect_failure + +let test_invalid_accusation_slot_not_attested = + let expect_failure blk = function + | [ + Environment.Ecoproto_error + (Validate_errors.Anonymous.Invalid_accusation_slot_not_attested + {level; _}); + ] + when Raw_level.to_int32 level = blk.Block.header.shell.level -> + Lwt_result_syntax.return_unit + | errs -> + failwith + "Error trace:@, %a does not match the expected one" + Error_monad.pp_print_trace + errs + in + test_accusation_injection ~attest_slot:false ~expect_failure + +let test_invalid_accusation_slot_not_published = + let expect_failure blk = function + | [ + Environment.Ecoproto_error + (Validate_errors.Anonymous.Invalid_accusation_slot_not_published + {level; _}); + ] + when Raw_level.to_int32 level = blk.Block.header.shell.level -> + Lwt_result_syntax.return_unit + | errs -> + failwith + "Error trace:@, %a does not match the expected one" + Error_monad.pp_print_trace + errs + in + test_accusation_injection ~publish_slot:false ~expect_failure + +let tests = + [ + Tztest.tztest "test valid accusation" `Quick test_accusation_injection; + Tztest.tztest + "test invalid accusation (too_close_to_migration)" + `Quick + test_invalid_accusation_too_close_to_migration; + Tztest.tztest + "test invalid accusation (no_dal_content)" + `Quick + test_invalid_accusation_no_dal_content; + Tztest.tztest + "test invalid accusation (slot_not_attested)" + `Quick + test_invalid_accusation_slot_not_attested; + Tztest.tztest + "test invalid accusation (slot_not_published)" + `Quick + test_invalid_accusation_slot_not_published; + ] + +let () = + Alcotest_lwt.run ~__FILE__ Protocol.name [("DAL entrapment", tests)] + |> Lwt_main.run -- GitLab