From b121e62fd2563e673365a73b6f14e1f49e457332 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 21 Jan 2025 17:16:33 +0100 Subject: [PATCH 1/6] Tezt/DAL: add helper function generate_slot --- tezt/lib_tezos/dal_common.ml | 5 +++++ tezt/lib_tezos/dal_common.mli | 4 ++++ tezt/tests/dal.ml | 7 +------ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/tezt/lib_tezos/dal_common.ml b/tezt/lib_tezos/dal_common.ml index 7399379cb8c6..e037abdeb7ba 100644 --- a/tezt/lib_tezos/dal_common.ml +++ b/tezt/lib_tezos/dal_common.ml @@ -674,6 +674,11 @@ module Helpers = struct Data_encoding.Json.pp parameters_json + let generate_slot ~slot_size = + Bytes.init slot_size (fun _ -> + let x = Random.int 26 in + Char.chr (x + Char.code 'a')) + let publish_commitment ?dont_wait ?counter ?force ?source ?fee ?error ~index ~commitment ~proof client = (* We scale the fees to match the actual gas cost of publishing a slot header. diff --git a/tezt/lib_tezos/dal_common.mli b/tezt/lib_tezos/dal_common.mli index a123ce739be9..af50c3abddf0 100644 --- a/tezt/lib_tezos/dal_common.mli +++ b/tezt/lib_tezos/dal_common.mli @@ -97,6 +97,10 @@ module Helpers : sig Cryptobox.parameters -> Cryptobox.t Lwt.t + (** Generates a random string (with chars from 'a' to 'z') of size + [slot_size]. *) + val generate_slot : slot_size:int -> bytes + val publish_commitment : ?dont_wait:bool -> ?counter:int -> diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index bf4508ea224e..0c86797c9ea9 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -7076,11 +7076,6 @@ let dal_crypto_benchmark () = let slot_size = Cli.get_int ~default:126_944 "slot_size" in let redundancy_factor = Cli.get_int ~default:8 "redundancy" in let page_size = Cli.get_int ~default:3967 "page_size" in - let generate_slot ~slot_size = - Bytes.init slot_size (fun _ -> - let x = Random.int 26 in - Char.chr (x + Char.code 'a')) - in let* () = let parameters = {number_of_shards; redundancy_factor; page_size; slot_size} @@ -7131,7 +7126,7 @@ let dal_crypto_benchmark () = in let slot = Profiler.record_f Profiler.main Debug ("slot generation", []) - @@ fun () -> generate_slot ~slot_size + @@ fun () -> Helpers.generate_slot ~slot_size in let*? polynomial = Profiler.record_f Profiler.main Debug ("polynomial from slot", []) -- GitLab From 0a85c2d633c4b42712e08d6a4e0ea61c71cf708d Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Tue, 21 Jan 2025 17:17:26 +0100 Subject: [PATCH 2/6] Tezt/DAL: add helper function to get commitments and shards from slot --- tezt/lib_tezos/dal_common.ml | 24 ++++++++++++++++++++++++ tezt/lib_tezos/dal_common.mli | 7 +++++++ 2 files changed, 31 insertions(+) diff --git a/tezt/lib_tezos/dal_common.ml b/tezt/lib_tezos/dal_common.ml index e037abdeb7ba..3a8cef68a35b 100644 --- a/tezt/lib_tezos/dal_common.ml +++ b/tezt/lib_tezos/dal_common.ml @@ -679,6 +679,30 @@ module Helpers = struct let x = Random.int 26 in Char.chr (x + Char.code 'a')) + let get_commitment_and_shards_with_proofs cryptobox ~slot = + let open Cryptobox in + let ( let*? ) x f = + match x with + | Error err -> Test.fail "Unexpected error:@.%a@." pp_cryptobox_error err + | Ok x -> f x + in + let*? precomputation = precompute_shards_proofs cryptobox in + let*? polynomial = polynomial_from_slot cryptobox slot in + let shards = shards_from_polynomial cryptobox polynomial in + let shard_proofs = + prove_shards cryptobox ~precomputation ~polynomial |> Array.to_seq + in + let*? commitment = commit cryptobox polynomial in + let*? commitment_proof = prove_commitment cryptobox polynomial in + let shards = + Seq.fold_left2 + (fun seq shard proof -> Seq.cons (shard, proof) seq) + Seq.empty + shards + shard_proofs + in + (commitment, commitment_proof, shards) + let publish_commitment ?dont_wait ?counter ?force ?source ?fee ?error ~index ~commitment ~proof client = (* We scale the fees to match the actual gas cost of publishing a slot header. diff --git a/tezt/lib_tezos/dal_common.mli b/tezt/lib_tezos/dal_common.mli index af50c3abddf0..5090dc41b386 100644 --- a/tezt/lib_tezos/dal_common.mli +++ b/tezt/lib_tezos/dal_common.mli @@ -101,6 +101,13 @@ module Helpers : sig [slot_size]. *) val generate_slot : slot_size:int -> bytes + val get_commitment_and_shards_with_proofs : + Cryptobox.t -> + slot:bytes -> + Cryptobox.commitment + * Cryptobox.commitment_proof + * (Cryptobox.shard * Cryptobox.shard_proof) Seq.t + val publish_commitment : ?dont_wait:bool -> ?counter:int -> -- GitLab From 9ddb7ea0417b8f18c74869bfb693ef978c49b5cc Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Fri, 17 Jan 2025 11:23:24 +0100 Subject: [PATCH 3/6] Tezt/Tezos: be able to craft DAL accusations --- tezt/lib_tezos/operation_core.ml | 39 +++++++++++++++++++++++++++++-- tezt/lib_tezos/operation_core.mli | 8 +++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/tezt/lib_tezos/operation_core.ml b/tezt/lib_tezos/operation_core.ml index 0b33a46409fa..50d6dfd937df 100644 --- a/tezt/lib_tezos/operation_core.ml +++ b/tezt/lib_tezos/operation_core.ml @@ -51,6 +51,8 @@ let make ~branch ?signer ~kind contents = let json t = `O [("branch", Ezjsonm.string t.branch); ("contents", t.contents)] +let json_of_int n = Ezjsonm.int n + let raw ?protocol t client = match t.raw with | None -> ( @@ -393,6 +395,12 @@ module Anonymous = struct op1 : t * Tezos_crypto.Signature.t; op2 : t * Tezos_crypto.Signature.t; } + | Dal_entrapment_evidence of { + attestation : t * Tezos_crypto.Signature.t; + slot_index : int; + shard : Tezos_crypto_dal.Cryptobox.shard; + proof : Tezos_crypto_dal.Cryptobox.shard_proof; + } let double_consensus_evidence ~kind (({kind = op1_kind; _}, _) as op1) (({kind = op2_kind; _}, _) as op2) = @@ -414,6 +422,13 @@ 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 + 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 kind_to_string kind = sf "double_%s_evidence" @@ -430,6 +445,14 @@ module Anonymous = struct ("signature", `String (Tezos_crypto.Signature.to_b58check signature)); ] + let json_of_shard shard = + Data_encoding.Json.construct Tezos_crypto_dal.Cryptobox.shard_encoding shard + + let json_of_shard_proof shard_proof = + Data_encoding.Json.construct + Tezos_crypto_dal.Cryptobox.shard_proof_encoding + shard_proof + let json = function | Double_consensus_evidence {kind; op1; op2} -> let op1 = denunced_op_json op1 in @@ -440,6 +463,20 @@ module Anonymous = struct ("op1", op1); ("op2", op2); ] + | Dal_entrapment_evidence {attestation; slot_index; shard; proof} -> + 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); + ] ); + ] let operation ?branch anonymous_operation client = let json = `A [json anonymous_operation] in @@ -551,8 +588,6 @@ module Manager = struct let json_of_int_as_string n = string_of_int n |> Ezjsonm.string - let json_of_int n = float_of_int n |> Ezjsonm.float - let json_of_commitment commitment = Data_encoding.Json.construct Tezos_crypto_dal.Cryptobox.Commitment.encoding diff --git a/tezt/lib_tezos/operation_core.mli b/tezt/lib_tezos/operation_core.mli index 2374fadedb8d..91c9b54f0e25 100644 --- a/tezt/lib_tezos/operation_core.mli +++ b/tezt/lib_tezos/operation_core.mli @@ -354,6 +354,14 @@ module Anonymous : sig operation * Tezos_crypto.Signature.t -> t + (** [dal_entrapment_evidence] crafts a DAL entrapment evidence operation. *) + val dal_entrapment_evidence : + attestation:operation * Tezos_crypto.Signature.t -> + slot_index:int -> + Tezos_crypto_dal.Cryptobox.shard -> + Tezos_crypto_dal.Cryptobox.shard_proof -> + t + (** [kind_to_string kind] return the name of the [kind]. *) val kind_to_string : double_consensus_evidence_kind -> string -- GitLab From 30daa8105326aa574a4fb87230340bf1dd6317e7 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Fri, 17 Jan 2025 11:26:59 +0100 Subject: [PATCH 4/6] Tests/DAL: support changing traps_fraction --- tezt/tests/dal.ml | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 0c86797c9ea9..bee17e082b2f 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -490,7 +490,7 @@ let with_layer1 ?custom_constants ?additional_bootstrap_accounts ?attestation_lag ?slot_size ?number_of_slots ?page_size ?attestation_threshold ?number_of_shards ?redundancy_factor ?commitment_period ?challenge_window ?dal_enable ?incentives_enable - ?dal_rewards_weight ?event_sections_levels ?node_arguments + ?dal_rewards_weight ?traps_fraction ?event_sections_levels ?node_arguments ?activation_timestamp ?dal_bootstrap_peers ?(parameters = []) ?(prover = true) ?smart_rollup_timeout_period_in_blocks ?l1_history_mode f ~protocol = @@ -509,6 +509,7 @@ let with_layer1 ?custom_constants ?additional_bootstrap_accounts @ make_int_parameter ["dal_parametric"; "attestation_threshold"] attestation_threshold + @ make_q_parameter ["dal_parametric"; "traps_fraction"] traps_fraction @ make_int_parameter ["issuance_weights"; "dal_rewards_weight"] dal_rewards_weight @@ -630,7 +631,7 @@ let with_dal_node ?peers ?attester_profiles ?producer_profiles let scenario_with_layer1_node ?regression ?(tags = []) ?additional_bootstrap_accounts ?attestation_lag ?number_of_shards ?number_of_slots ?custom_constants ?commitment_period ?challenge_window - ?(dal_enable = true) ?incentives_enable ?dal_rewards_weight + ?(dal_enable = true) ?incentives_enable ?traps_fraction ?dal_rewards_weight ?event_sections_levels ?node_arguments ?activation_timestamp ?consensus_committee_size ?minimal_block_delay ?delay_increment_per_round variant scenario = @@ -656,6 +657,7 @@ let scenario_with_layer1_node ?regression ?(tags = []) ?number_of_shards ?number_of_slots ?incentives_enable + ?traps_fraction ?dal_rewards_weight ?commitment_period ?challenge_window @@ -670,8 +672,8 @@ let scenario_with_layer1_node ?regression ?(tags = []) let scenario_with_layer1_and_dal_nodes ?regression ?(tags = []) ?(uses = fun _ -> []) ?custom_constants ?minimal_block_delay ?delay_increment_per_round ?redundancy_factor ?slot_size ?number_of_shards - ?number_of_slots ?attestation_lag ?attestation_threshold ?commitment_period - ?challenge_window ?(dal_enable = true) ?incentives_enable + ?number_of_slots ?attestation_lag ?attestation_threshold ?traps_fraction + ?commitment_period ?challenge_window ?(dal_enable = true) ?incentives_enable ?dal_rewards_weight ?activation_timestamp ?bootstrap_profile ?producer_profiles ?history_mode ?prover ?l1_history_mode variant scenario = let description = "Testing DAL node" in @@ -703,6 +705,7 @@ let scenario_with_layer1_and_dal_nodes ?regression ?(tags = []) ?number_of_shards ?attestation_lag ?attestation_threshold + ?traps_fraction ?incentives_enable ?dal_rewards_weight ?commitment_period -- GitLab From 91be70663997c7f6fd318d6c2db1a931733dd820 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Fri, 17 Jan 2025 11:29:15 +0100 Subject: [PATCH 5/6] Tests/DAL: inject_dal_attestation also returns the op --- tezt/tests/dal.ml | 50 ++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index bee17e082b2f..8d8beb859c0e 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -873,19 +873,18 @@ let inject_dal_attestation ?level ?(round = 0) ?payload_level ?force ?error in Operation.Consensus.get_block_payload_hash ~block client in - Operation.Consensus.inject - ?force - ?error - ?request - ~signer - (Operation.Consensus.attestation - ~level - ~round - ~dal_attestation - ~slot - ~block_payload_hash - ()) - client + let attestation = + Operation.Consensus.attestation + ~level + ~round + ~dal_attestation + ~slot + ~block_payload_hash + () + in + let* op = Operation.Consensus.operation ~signer attestation client in + let* op_hash = Operation.inject ?force ?error ?request op client in + return (op, op_hash) let inject_dal_attestations ?payload_level ?level ?round ?force ?(signers = Array.to_list Account.Bootstrap.keys) ~nb_slots availability @@ -909,7 +908,7 @@ let inject_dal_attestations_and_bake node client ~number_of_slots indexes = baker_for_round_zero node ~level:(level + 1) in let signers = different_delegates baker in - let* _op_hashes = + let* _op_and_op_hash_list = inject_dal_attestations ~signers ~nb_slots:number_of_slots indexes client in bake_for ~delegates:(`For [baker]) client @@ -1253,14 +1252,17 @@ let test_slots_attestation_operation_behavior _protocol parameters _cryptobox let lag = parameters.attestation_lag in assert (lag > 1) ; let attest ?payload_level ?(signer = Constant.bootstrap2) ~level () = - inject_dal_attestation - ?payload_level - ~force:true - ~nb_slots - ~level - ~signer - (Slots [0]) - client + let* _op, op_hash = + inject_dal_attestation + ?payload_level + ~force:true + ~nb_slots + ~level + ~signer + (Slots [0]) + client + in + return op_hash in let mempool_is ~__LOC__ expected_mempool = let* mempool = Mempool.get_mempool client in @@ -1439,7 +1441,7 @@ let test_slots_attestation_operation_dal_committee_membership_check _protocol Log.info "number_of_shards = %d" number_of_shards ; let* () = bake_for client in let* level = Client.level client in - let* (`OpHash _oph) = + let* _op, `OpHash _oph = inject_dal_attestation ~nb_slots ~level @@ -1505,7 +1507,7 @@ let test_slots_attestation_operation_dal_committee_membership_check _protocol let* () = check_in_TB_committee ~__LOC__ node new_account.public_key_hash ~level in - let* (`OpHash _oph) = + let* _op, `OpHash _oph = inject_dal_attestation ~error:Operation.dal_data_availibility_attester_not_in_committee ~nb_slots -- GitLab From 56b82839bf25dc0ab5e38b5ef48e6b0769a736b4 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Fri, 17 Jan 2025 11:40:43 +0100 Subject: [PATCH 6/6] Tests/DAL: add test for injecting accusations --- tezt/tests/dal.ml | 82 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 8d8beb859c0e..2cbf97595a06 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -8286,6 +8286,82 @@ let test_attesters_receive_dal_rewards protocol dal_parameters _cryptobox node ~error_msg:"Unexpected delegate to lose DAL rewards (got %R expected %L)" ; unit +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 + let number_of_slots = dal_parameters.number_of_slots in + let lag = dal_parameters.attestation_lag in + let slot = Helpers.generate_slot ~slot_size in + let commitment, proof, shards_with_proofs = + Helpers.get_commitment_and_shards_with_proofs cryptobox ~slot + in + Log.info "Bake two blocks" ; + (* 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* () = bake_for ~count:2 client in + let* _op_hash = + Helpers.publish_commitment + ~source:Constant.bootstrap2 + ~index:slot_index + ~commitment + ~proof + client + in + (* We need to bake exactly [lag] blocks so that we can inject an attestation + at the right level (that attests the published slot). *) + let* () = bake_for ~count:lag client in + Log.info "Inject an attestation" ; + let availability = Slots [slot_index] in + let signer = Constant.bootstrap2 in + let* attestation, _op_hash = + inject_dal_attestation ~signer ~nb_slots:number_of_slots availability client + in + let* signature = Operation.sign attestation client in + let attestation = (attestation, signature) in + let* shard_assignments = + Node.RPC.call node + @@ RPC.get_chain_block_context_dal_shards + ~delegates:[signer.public_key_hash] + () + in + let shard_index = + JSON.( + shard_assignments |> as_list |> List.hd |-> "indexes" |> as_list + |> List.hd |> as_int) + in + Log.info "First shard index of the attester is %d" shard_index ; + let shard, proof = + Seq.find + (fun (Cryptobox.{index; _}, _proof) -> index = shard_index) + shards_with_proofs + |> Option.get + in + let accusation = + Operation.Anonymous.dal_entrapment_evidence + ~attestation + ~slot_index + shard + proof + in + Log.info "Inject an accusation" ; + let* _op_hash = Operation.Anonymous.inject accusation client in + let* () = bake_for client in + let* ops = + Node.RPC.call node + @@ RPC.get_chain_block_operations_validation_pass + ~block:"head" + ~validation_pass:2 + () + in + Check.(List.length (JSON.as_list ops) = 1) + ~__LOC__ + Check.(int) + ~error_msg:"Expected exactly one anonymous op. Got: %L" ; + unit + let register ~protocols = (* Tests with Layer1 node only *) scenario_with_layer1_node @@ -8322,6 +8398,12 @@ let register ~protocols = "one_committee_per_level" test_one_committee_per_level protocols ; + scenario_with_layer1_node + ~incentives_enable:true + ~traps_fraction:Q.one + "inject accusation" + test_inject_accusation + (List.filter (fun p -> Protocol.number p >= 022) protocols) ; (* Tests with layer1 and dal nodes *) test_dal_node_startup protocols ; -- GitLab