From 8345b4eeeed3fdf251c63cc3089587c0fa11d420 Mon Sep 17 00:00:00 2001 From: Guillaume Genestier Date: Thu, 20 Nov 2025 14:24:40 +0100 Subject: [PATCH 1/6] Clic: Add arg_26 --- src/lib_clic/tezos_clic.ml | 38 +++++++++++++++++++++++++ src/lib_clic/tezos_clic.mli | 57 +++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/src/lib_clic/tezos_clic.ml b/src/lib_clic/tezos_clic.ml index 464f57356bf8..c5bf916031ce 100644 --- a/src/lib_clic/tezos_clic.ml +++ b/src/lib_clic/tezos_clic.ml @@ -1102,6 +1102,44 @@ let args25 a b c d e f g h i j k l m n o p q r s t u v w x y = y )) (args2 (args16 a b c d e f g h i j k l m n o p) (args9 q r s t u v w x y)) +let args26 a b c d e f g h i j k l m n o p q r s t u v w x y z = + map_arg + ~f:(fun + _ + ( (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p), + (q, r, s, t, u, v, w, x, y, z) ) + -> + Lwt_result_syntax.return + ( a, + b, + c, + d, + e, + f, + g, + h, + i, + j, + k, + l, + m, + n, + o, + p, + q, + r, + s, + t, + u, + v, + w, + x, + y, + z )) + (args2 + (args16 a b c d e f g h i j k l m n o p) + (args10 q r s t u v w x y z)) + let switch ~doc ?short ~long () = Switch {doc; label = {long; short}} type occurrence = Occ_empty | Occ_with_value of string diff --git a/src/lib_clic/tezos_clic.mli b/src/lib_clic/tezos_clic.mli index 849940a8a65f..b96aca210cc7 100644 --- a/src/lib_clic/tezos_clic.mli +++ b/src/lib_clic/tezos_clic.mli @@ -793,6 +793,63 @@ val args25 : 'ctx ) options +(** Include 26 optional parameters *) +val args26 : + ('a, 'ctx) arg -> + ('b, 'ctx) arg -> + ('c, 'ctx) arg -> + ('d, 'ctx) arg -> + ('e, 'ctx) arg -> + ('f, 'ctx) arg -> + ('g, 'ctx) arg -> + ('h, 'ctx) arg -> + ('i, 'ctx) arg -> + ('j, 'ctx) arg -> + ('k, 'ctx) arg -> + ('l, 'ctx) arg -> + ('m, 'ctx) arg -> + ('n, 'ctx) arg -> + ('o, 'ctx) arg -> + ('p, 'ctx) arg -> + ('q, 'ctx) arg -> + ('r, 'ctx) arg -> + ('s, 'ctx) arg -> + ('t, 'ctx) arg -> + ('u, 'ctx) arg -> + ('v, 'ctx) arg -> + ('w, 'ctx) arg -> + ('x, 'ctx) arg -> + ('y, 'ctx) arg -> + ('z, 'ctx) arg -> + ( 'a + * 'b + * 'c + * 'd + * 'e + * 'f + * 'g + * 'h + * 'i + * 'j + * 'k + * 'l + * 'm + * 'n + * 'o + * 'p + * 'q + * 'r + * 's + * 't + * 'u + * 'v + * 'w + * 'x + * 'y + * 'z, + 'ctx ) + options + (** Aggregate a set of options into a single value. *) val aggregate : ('a, 'ctx) options -> ('a, 'ctx) arg -- GitLab From ceba8ab3fe02cebc9802ae4bb1c2148cad95d1dc Mon Sep 17 00:00:00 2001 From: Guillaume Genestier Date: Fri, 21 Nov 2025 14:56:42 +0100 Subject: [PATCH 2/6] DAL: Factor out a slot_production module DAL/Opentelemetry: Add the open telemetry function on whole function in the RPC server Bla --- src/lib_dal_node/RPC_server.ml | 213 +++------------------------ src/lib_dal_node/slot_production.ml | 200 +++++++++++++++++++++++++ src/lib_dal_node/slot_production.mli | 21 +++ 3 files changed, 243 insertions(+), 191 deletions(-) create mode 100644 src/lib_dal_node/slot_production.ml create mode 100644 src/lib_dal_node/slot_production.mli diff --git a/src/lib_dal_node/RPC_server.ml b/src/lib_dal_node/RPC_server.ml index 54337a2dc066..f9b105aaffb3 100644 --- a/src/lib_dal_node/RPC_server.ml +++ b/src/lib_dal_node/RPC_server.ml @@ -31,8 +31,6 @@ let call_handler1 handler = handler () |> Errors.to_option_tzresult type error += | Cryptobox_error of string * string - | Post_slot_too_large of {expected : int; got : int} - | No_prover_profile | Cannot_publish_on_slot_index of Types.slot_index let () = @@ -50,31 +48,6 @@ let () = Data_encoding.(obj2 (req "function_name" string) (req "explanation" string)) (function Cryptobox_error (f, msg) -> Some (f, msg) | _ -> None) (fun (f, msg) -> Cryptobox_error (f, msg)) ; - register_error_kind - `Permanent - ~id:"post_slot_too_large" - ~title:"Post slot too large" - ~description: - "The length of posted data exceeds the expected size of DAL slots." - ~pp:(fun fmt (expected, got) -> - Format.fprintf - fmt - "The RPC expects a slot_size of at most '%d'. Got: '%d' expected got" - expected - got) - Data_encoding.(obj2 (req "expected" int31) (req "got" int31)) - (function - | Post_slot_too_large {expected; got} -> Some (expected, got) | _ -> None) - (fun (expected, got) -> Post_slot_too_large {expected; got}) ; - register_error_kind - `Permanent - ~id:"no_prover_profile" - ~title:"No prover profile" - ~description: - "The DAL node does not have a prover profile to accept slots injection." - Data_encoding.unit - (function No_prover_profile -> Some () | _ -> None) - (fun () -> No_prover_profile) ; register_error_kind `Permanent ~id:"cannot_publish_on_slot_index" @@ -93,25 +66,6 @@ module Slots_handlers = struct let slot_id : Types.slot_id = {slot_level; slot_index} in Slot_manager.get_slot_content ~reconstruct_if_missing:true ctxt slot_id) - let commitment_proof_from_polynomial cryptobox polynomial = - let open Result_syntax in - match Cryptobox.prove_commitment cryptobox polynomial with - (* [polynomial] was produced with the parameters from - [cryptobox], thus we can always compute the proof from - [polynomial] except if an error happens with the loading of the SRS. *) - | Error - (`Invalid_degree_strictly_less_than_expected _ | `Prover_SRS_not_loaded) - -> - Error - (Errors.other - [ - Cryptobox_error - ( "prove_commitment", - "Unexpected error. Maybe an issue with the SRS from the DAL \ - node." ); - ]) - | Ok proof -> return proof - let get_slot_page_proof ctxt slot_level slot_index page_index () () = call_handler1 (fun () -> let open Lwt_result_syntax in @@ -142,158 +96,35 @@ module Slots_handlers = struct in fail (Errors.other [Cryptobox_error ("get_slot_page_proof", msg)])) - (* This module is used below to maintain a bounded cache of recently injected - slots to quickly return the commitment and commitment_proof of an already - known slot. *) - module Injected_slots_cache = - Aches.Vache.Map (Aches.Vache.FIFO_Precise) (Aches.Vache.Strong) - (struct - type t = string - - let equal = String.equal - - let hash = Hashtbl.hash - end) - let error_pp ppf (slot : [`Not_found | `Other of error trace]) = match slot with | `Not_found -> Format.pp_print_string ppf "slot not found" | `Other errors -> pp_print_trace ppf errors let post_slot = - let slots_cache = - Injected_slots_cache.create Constants.not_yet_published_cache_size + fun ctxt query slot -> + call_handler1 @@ fun () -> + let open Lwt_result_syntax in + let profile = Node_context.get_profile_ctxt ctxt in + let* () = + match query#slot_index with + | Some slot_index + when not (Profile_manager.can_publish_on_slot_index slot_index profile) + -> + fail (Errors.other [Cannot_publish_on_slot_index slot_index]) + | None | Some _ -> return_unit in - fun ctxt query slot -> - call_handler1 (fun () -> - let open Lwt_result_syntax in - let store = Node_context.get_store ctxt in - match Injected_slots_cache.find_opt slots_cache slot with - | Some (commitment, commitment_proof) - when Option.is_some - (Store.Commitment_indexed_cache.find_opt - (Store.not_yet_published_cache store) - commitment) -> - return (commitment, commitment_proof) - | _ -> - (let cryptobox = Node_context.get_cryptobox ctxt in - let profile = Node_context.get_profile_ctxt ctxt in - let* () = - if not (Profile_manager.is_prover_profile profile) then - fail (Errors.other [No_prover_profile]) - else return_unit - in - let* () = - match query#slot_index with - | Some slot_index - when not - (Profile_manager.can_publish_on_slot_index - slot_index - profile) -> - fail - (Errors.other [Cannot_publish_on_slot_index slot_index]) - | None | Some _ -> return_unit - in - let* proto_parameters = - (Node_context.get_proto_parameters ctxt ~level:`Last_proto - |> Lwt.return - |> lwt_map_error (fun e -> `Other e)) - [@profiler.wrap_f - {driver_ids = [Opentelemetry]} - (Opentelemetry_helpers.trace_slot_no_commitment - ~slot - ~name:"get_proto_parameters")] - in - let slot_size = - proto_parameters.cryptobox_parameters.slot_size - in - let slot_length = String.length slot in - let*? slot_bytes = - (if slot_length > slot_size then - Error - (Errors.other - [ - Post_slot_too_large - {expected = slot_size; got = slot_length}; - ]) - else if slot_length = slot_size then Ok (Bytes.of_string slot) - else - let padding = - String.make (slot_size - slot_length) query#padding - in - Ok (Bytes.of_string (slot ^ padding))) - [@profiler.wrap_f - {driver_ids = [Opentelemetry]} - (Opentelemetry_helpers.trace_slot_no_commitment - ~attrs:[] - ~slot - ~name:"padding_slot")] - in - let*? polynomial = - (Slot_manager.polynomial_from_slot - cryptobox - slot_bytes - [@profiler.wrap_f - {driver_ids = [Opentelemetry]} - (Opentelemetry_helpers.trace_slot_no_commitment - ~slot - ~name:"computing_polynomial")]) - in - let*? commitment = - (Slot_manager.commit - cryptobox - polynomial - [@profiler.wrap_f - {driver_ids = [Opentelemetry]} - (Opentelemetry_helpers.trace_slot_no_commitment - ~slot - ~name:"computing_commitment")]) - in - let*? commitment_proof = - (commitment_proof_from_polynomial - cryptobox - polynomial - [@profiler.wrap_f - {driver_ids = [Opentelemetry]} - (Opentelemetry_helpers.trace_slot_no_commitment - ~slot - ~name:"computing_commitment_proof")]) - in - let shards_proofs_precomputation = - (Node_context.get_shards_proofs_precomputation - ctxt - [@profiler.wrap_f - {driver_ids = [Opentelemetry]} - (Opentelemetry_helpers.trace_slot_no_commitment - ~slot - ~name:"shard_proof_precomputation")]) - in - let* () = - (Slot_manager.add_commitment_shards - ~shards_proofs_precomputation - store - cryptobox - commitment - slot_bytes - polynomial - [@profiler.wrap_f - {driver_ids = [Opentelemetry]} - (Opentelemetry_helpers.trace_slot_no_commitment - ~slot - ~name:"add_commitment_s_shards")]) - in - Injected_slots_cache.replace - slots_cache - slot - (commitment, commitment_proof) ; - return (commitment, commitment_proof)) - [@profiler.wrap_f - {driver_ids = [Opentelemetry]} - (Opentelemetry_helpers.trace_slot_after_es - ~name:"inject_slot" - ?slot_index:query#slot_index - ~error_pp - ~commitment_of_result:fst)]) + (Slot_production.produce_commitment_and_proof + ctxt + query#padding + slot + [@profiler.wrap_f + {driver_ids = [Opentelemetry]} + (Opentelemetry_helpers.trace_slot_after_es + ~name:"inject_slot" + ?slot_index:query#slot_index + ~error_pp + ~commitment_of_result:fst)]) let get_slot_commitment ctxt slot_level slot_index () () = call_handler1 (fun () -> diff --git a/src/lib_dal_node/slot_production.ml b/src/lib_dal_node/slot_production.ml new file mode 100644 index 000000000000..834c068dfa2f --- /dev/null +++ b/src/lib_dal_node/slot_production.ml @@ -0,0 +1,200 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +type error += + | Cryptobox_proof_error of string + | Post_slot_too_large of {expected : int; got : int} + | No_prover_profile + +let () = + register_error_kind + `Permanent + ~id:"cryptobox_proof_error" + ~title:"cryptobox error" + ~description:"A wrapper around an error raised by the cryptobox of the DAL." + ~pp:(fun fmt msg -> + Format.fprintf + fmt + "The DAL cryptobox proof_from_polynomial failed with:@.'%s'" + msg) + Data_encoding.(obj1 (req "explanation" string)) + (function Cryptobox_proof_error msg -> Some msg | _ -> None) + (fun msg -> Cryptobox_proof_error msg) ; + register_error_kind + `Permanent + ~id:"post_slot_too_large" + ~title:"Post slot too large" + ~description: + "The length of posted data exceeds the expected size of DAL slots." + ~pp:(fun fmt (expected, got) -> + Format.fprintf + fmt + "The RPC expects a slot_size of at most '%d'. Got: '%d' expected got" + expected + got) + Data_encoding.(obj2 (req "expected" int31) (req "got" int31)) + (function + | Post_slot_too_large {expected; got} -> Some (expected, got) | _ -> None) + (fun (expected, got) -> Post_slot_too_large {expected; got}) ; + register_error_kind + `Permanent + ~id:"no_prover_profile" + ~title:"No prover profile" + ~description: + "The DAL node does not have a prover profile to accept slots injection." + Data_encoding.unit + (function No_prover_profile -> Some () | _ -> None) + (fun () -> No_prover_profile) + +(* This module is used below to maintain a bounded cache of recently injected + slots to quickly return the commitment and commitment_proof of an already + known slot. *) +module Injected_slots_cache = + Aches.Vache.Map (Aches.Vache.FIFO_Precise) (Aches.Vache.Strong) + (struct + type t = string + + let equal = String.equal + + let hash = Hashtbl.hash + end) + +let commitment_proof_from_polynomial cryptobox polynomial = + let open Result_syntax in + match Cryptobox.prove_commitment cryptobox polynomial with + (* [polynomial] was produced with the parameters from + [cryptobox], thus we can always compute the proof from + [polynomial] except if an error happens with the loading of the SRS. *) + | Error + (`Invalid_degree_strictly_less_than_expected _ | `Prover_SRS_not_loaded) + -> + Error + (Errors.other + [ + Cryptobox_proof_error + "Unexpected error. Maybe an issue with the SRS from the DAL \ + node."; + ]) + | Ok proof -> return proof + +let produce_commitment_and_proof = + let slots_cache = + Injected_slots_cache.create Constants.not_yet_published_cache_size + in + fun ctxt padding slot -> + let open Lwt_result_syntax in + let store = Node_context.get_store ctxt in + match Injected_slots_cache.find_opt slots_cache slot with + | Some (commitment, commitment_proof) + when Option.is_some + (Store.Commitment_indexed_cache.find_opt + (Store.not_yet_published_cache store) + commitment) -> + return (commitment, commitment_proof) + | _ -> + let cryptobox = Node_context.get_cryptobox ctxt in + let profile = Node_context.get_profile_ctxt ctxt in + let* () = + if not (Profile_manager.is_prover_profile profile) then + fail (Errors.other [No_prover_profile]) + else return_unit + in + let* proto_parameters = + (Node_context.get_proto_parameters ctxt ~level:`Last_proto + |> Lwt.return + |> lwt_map_error (fun e -> `Other e)) + [@profiler.wrap_f + {driver_ids = [Opentelemetry]} + (Opentelemetry_helpers.trace_slot_no_commitment + ~slot + ~name:"get_proto_parameters")] + in + let slot_size = proto_parameters.cryptobox_parameters.slot_size in + let slot_length = String.length slot in + let*? slot_bytes = + (if slot_length > slot_size then + Error + (Errors.other + [ + Post_slot_too_large {expected = slot_size; got = slot_length}; + ]) + else if slot_length = slot_size then Ok (Bytes.of_string slot) + else + let padding = String.make (slot_size - slot_length) padding in + Ok (Bytes.of_string (slot ^ padding))) + [@profiler.wrap_f + {driver_ids = [Opentelemetry]} + (Opentelemetry_helpers.trace_slot_no_commitment + ~attrs:[] + ~slot + ~name:"padding_slot")] + in + let*? polynomial = + (Slot_manager.polynomial_from_slot + cryptobox + slot_bytes + [@profiler.wrap_f + {driver_ids = [Opentelemetry]} + (Opentelemetry_helpers.trace_slot_no_commitment + ~slot + ~name:"computing_polynomial")]) + in + let*? commitment = + (Slot_manager.commit + cryptobox + polynomial + [@profiler.wrap_f + {driver_ids = [Opentelemetry]} + (Opentelemetry_helpers.trace_slot_no_commitment + ~slot + ~name:"computing_commitment")]) + in + let*? commitment_proof = + (commitment_proof_from_polynomial + cryptobox + polynomial + [@profiler.wrap_f + {driver_ids = [Opentelemetry]} + (Opentelemetry_helpers.trace_slot_no_commitment + ~slot + ~name:"computing_commitment_proof")]) + in + let shards_proofs_precomputation = + (Node_context.get_shards_proofs_precomputation + ctxt + [@profiler.wrap_f + {driver_ids = [Opentelemetry]} + (Opentelemetry_helpers.trace_slot_no_commitment + ~slot + ~name:"shard_proof_precomputation")]) + in + let* () = + (Slot_manager.add_commitment_shards + ~shards_proofs_precomputation + store + cryptobox + commitment + slot_bytes + polynomial + [@profiler.wrap_f + {driver_ids = [Opentelemetry]} + (Opentelemetry_helpers.trace_slot_no_commitment + ~slot + ~name:"add_commitment_s_shards")]) + in + let () = + (Injected_slots_cache.replace + slots_cache + slot + (commitment, commitment_proof) + [@profiler.wrap_f + {driver_ids = [Opentelemetry]} + (Opentelemetry_helpers.trace_slot_no_commitment + ~slot + ~name:"store_shards_in_cache")]) + in + return (commitment, commitment_proof) diff --git a/src/lib_dal_node/slot_production.mli b/src/lib_dal_node/slot_production.mli new file mode 100644 index 000000000000..db0ea2870107 --- /dev/null +++ b/src/lib_dal_node/slot_production.mli @@ -0,0 +1,21 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2025 Nomadic Labs. *) +(* *) +(*****************************************************************************) + +type error += + | Cryptobox_proof_error of string + | Post_slot_too_large of {expected : int; got : int} + | No_prover_profile + +(** [produce_commitment_and_proof ctxt padding msg] computes the commitment and + proof associated to the slot containing [msg] padded with character + [padding]. *) +val produce_commitment_and_proof : + Node_context.t -> + char -> + string -> + (Cryptobox.commitment * Cryptobox.commitment_proof, [> Errors.other]) result + Lwt.t -- GitLab From ea0dadee27ab4f3705e36c5c3424307427dbdcbe Mon Sep 17 00:00:00 2001 From: Guillaume Genestier Date: Thu, 20 Nov 2025 15:21:43 +0100 Subject: [PATCH 3/6] DAL/Plugin: Add a publish function which emits a publication on the L1 --- src/lib_dal_node/dal_plugin.ml | 11 ++++ src/lib_dal_node/dal_plugin.mli | 14 +++++ .../lib_dal/dal_plugin_registration.ml | 23 +++++++- .../lib_dal/dal_plugin_registration.ml | 23 ++++++++ .../lib_dal/dal_plugin_registration.ml | 55 +++++++++++++++++++ .../lib_dal/dal_plugin_registration.ml | 55 +++++++++++++++++++ .../lib_dal/dal_plugin_registration.ml | 55 +++++++++++++++++++ 7 files changed, 235 insertions(+), 1 deletion(-) diff --git a/src/lib_dal_node/dal_plugin.ml b/src/lib_dal_node/dal_plugin.ml index c124d70f1402..ff6fa1438b58 100644 --- a/src/lib_dal_node/dal_plugin.ml +++ b/src/lib_dal_node/dal_plugin.ml @@ -97,6 +97,17 @@ module type T = sig tb_slot:tb_slot -> unit tzresult Lwt.t + val publish : + Tezos_rpc.Context.generic -> + block_level:int32 -> + source:Signature.Public_key_hash.t -> + slot_index:slot_index -> + commitment:Tezos_crypto_dal.Cryptobox.commitment -> + commitment_proof:Tezos_crypto_dal.Cryptobox.commitment_proof -> + src_sk:Signature.Secret_key.t -> + unit -> + Operation_hash.t tzresult Lwt.t + val is_delegate : Tezos_rpc.Context.generic -> pkh:Signature.Public_key_hash.t -> diff --git a/src/lib_dal_node/dal_plugin.mli b/src/lib_dal_node/dal_plugin.mli index 8b0dc0d9799a..29f8704477f2 100644 --- a/src/lib_dal_node/dal_plugin.mli +++ b/src/lib_dal_node/dal_plugin.mli @@ -136,6 +136,20 @@ module type T = sig tb_slot:tb_slot -> unit tzresult Lwt.t + (** This function constructs and injects the L1 publication operation. + It is meant to be used in a test context, as it requires the explicit + provision of the secret key, which is not desirable in production. *) + val publish : + Tezos_rpc.Context.generic -> + block_level:int32 -> + source:Signature.Public_key_hash.t -> + slot_index:slot_index -> + commitment:Tezos_crypto_dal.Cryptobox.commitment -> + commitment_proof:Tezos_crypto_dal.Cryptobox.commitment_proof -> + src_sk:Signature.Secret_key.t -> + unit -> + Operation_hash.t tzresult Lwt.t + val is_delegate : Tezos_rpc.Context.generic -> pkh:Signature.Public_key_hash.t -> diff --git a/src/proto_021_PsQuebec/lib_dal/dal_plugin_registration.ml b/src/proto_021_PsQuebec/lib_dal/dal_plugin_registration.ml index 7ba64e712cc0..4dc61c02cfa7 100644 --- a/src/proto_021_PsQuebec/lib_dal/dal_plugin_registration.ml +++ b/src/proto_021_PsQuebec/lib_dal/dal_plugin_registration.ml @@ -79,7 +79,7 @@ module Plugin = struct minimal_block_delay = Period.to_seconds parametric.minimal_block_delay; } - type error += DAL_accusation_not_available + type error += DAL_accusation_not_available | DAL_publication_not_available let () = register_error_kind @@ -93,12 +93,33 @@ module Plugin = struct (function DAL_accusation_not_available -> Some () | _ -> None) (fun () -> DAL_accusation_not_available) + let () = + register_error_kind + `Permanent + ~id:"dal_publications_not_available_quebec" + ~title:"DAL publication not available on Quebec" + ~description: + "Publication from DAL node is not implemented in protocol Quebec" + ~pp:(fun fmt () -> + Format.fprintf + fmt + "Publication from DAL node is not implemented in protocol Quebec") + Data_encoding.unit + (function DAL_publication_not_available -> Some () | _ -> None) + (fun () -> DAL_publication_not_available) + let inject_entrapment_evidence _cctxt ~attested_level:_ _attestation ~slot_index:_ ~shard:_ ~proof:_ ~tb_slot:_ = let open Lwt_result_syntax in (* This is supposed to be dead code, but we implement a fallback to be defensive. *) fail [DAL_accusation_not_available] + let publish _cctxt ~block_level:_ ~source:_ ~slot_index:_ ~commitment:_ + ~commitment_proof:_ ~src_sk:_ () = + let open Lwt_result_syntax in + (* This is supposed to be dead code, but we implement a fallback to be defensive. *) + fail [DAL_publication_not_available] + let block_info ?chain ?block ~operations_metadata ctxt = let cpctxt = new Protocol_client_context.wrap_rpc_context ctxt in Protocol_client_context.Alpha_block_services.info diff --git a/src/proto_022_PsRiotum/lib_dal/dal_plugin_registration.ml b/src/proto_022_PsRiotum/lib_dal/dal_plugin_registration.ml index d8591e76193e..1bf36f85f575 100644 --- a/src/proto_022_PsRiotum/lib_dal/dal_plugin_registration.ml +++ b/src/proto_022_PsRiotum/lib_dal/dal_plugin_registration.ml @@ -138,6 +138,29 @@ module Plugin = struct let* _op_hash = Shell_services.Injection.operation cctxt ~chain bytes in return_unit + type error += DAL_publication_not_available + + let () = + register_error_kind + `Permanent + ~id:"dal_publications_not_available_rio" + ~title:"DAL publication not available on Rio" + ~description: + "Publication from DAL node is not implemented in protocol Rio" + ~pp:(fun fmt () -> + Format.fprintf + fmt + "Publication from DAL node is not implemented in protocol Rio") + Data_encoding.unit + (function DAL_publication_not_available -> Some () | _ -> None) + (fun () -> DAL_publication_not_available) + + let publish _cctxt ~block_level:_ ~source:_ ~slot_index:_ ~commitment:_ + ~commitment_proof:_ ~src_sk:_ () = + let open Lwt_result_syntax in + (* This is supposed to be dead code, but we implement a fallback to be defensive. *) + fail [DAL_publication_not_available] + let block_info ?chain ?block ~operations_metadata ctxt = let cpctxt = new Protocol_client_context.wrap_rpc_context ctxt in Protocol_client_context.Alpha_block_services.info diff --git a/src/proto_023_PtSeouLo/lib_dal/dal_plugin_registration.ml b/src/proto_023_PtSeouLo/lib_dal/dal_plugin_registration.ml index 08de5ea63589..d15aa56d5aea 100644 --- a/src/proto_023_PtSeouLo/lib_dal/dal_plugin_registration.ml +++ b/src/proto_023_PtSeouLo/lib_dal/dal_plugin_registration.ml @@ -135,6 +135,61 @@ module Plugin = struct let* _op_hash = Shell_services.Injection.operation cctxt ~chain bytes in return_unit + let publish cctxt ~block_level ~source ~slot_index ~commitment + ~commitment_proof ~src_sk () = + let open Lwt_result_syntax in + let chain = `Main in + let block = `Level block_level in + let cpctxt = new Protocol_client_context.wrap_rpc_context cctxt in + let* {dal = {number_of_slots; _}; _} = + Plugin.Constants_services.parametric cpctxt (chain, block) + in + let*? slot_index = + Dal.Slot_index.of_int ~number_of_slots slot_index + |> Environment.wrap_tzresult + in + let* block_hash = + Protocol_client_context.Alpha_block_services.hash cctxt ~chain ~block () + in + let* counter = + let* pcounter = + Plugin.Alpha_services.Contract.counter cpctxt (chain, `Head 0) source + in + return (Manager_counter.succ pcounter) + in + let operation = + Dal_publish_commitment {slot_index; commitment; commitment_proof} + in + let operation = + (* A dry-run of the "publish dal commitment" command for each tz kinds outputs: + - tz1: fees of 513µtz and 1333 gas consumed + - tz2: fees of 514µtz and 1318 gas consumed + - tz3: fees of 543µtz and 1607 gas consumed + - tz4: fees of 700µtz and 2837 gas consumed + We added a margin to it. + The storage limit value has been selected purely arbitrarily + (it worked with this value when I experimented, so I did not change it). *) + Alpha_context.( + Manager_operation + { + source; + fee = Tez.of_mutez_exn (Int64.of_int 750); + counter; + operation; + gas_limit = Gas.Arith.integral_of_int_exn 3000; + storage_limit = Z.of_int 100; + }) + in + let bytes = + Data_encoding.Binary.to_bytes_exn + Operation.unsigned_encoding + ({branch = block_hash}, Contents_list (Single operation)) + in + let bytes = + Signature.append ~watermark:Signature.Generic_operation src_sk bytes + in + Shell_services.Injection.operation cctxt ~chain bytes + let block_info ?chain ?block ~operations_metadata ctxt = let cpctxt = new Protocol_client_context.wrap_rpc_context ctxt in Protocol_client_context.Alpha_block_services.info diff --git a/src/proto_024_PtTALLiN/lib_dal/dal_plugin_registration.ml b/src/proto_024_PtTALLiN/lib_dal/dal_plugin_registration.ml index 86c4fc76c71b..5e90316f1b94 100644 --- a/src/proto_024_PtTALLiN/lib_dal/dal_plugin_registration.ml +++ b/src/proto_024_PtTALLiN/lib_dal/dal_plugin_registration.ml @@ -152,6 +152,61 @@ module Plugin = struct let* _op_hash = Shell_services.Injection.operation cctxt ~chain bytes in return_unit + let publish cctxt ~block_level ~source ~slot_index ~commitment + ~commitment_proof ~src_sk () = + let open Lwt_result_syntax in + let chain = `Main in + let block = `Level block_level in + let cpctxt = new Protocol_client_context.wrap_rpc_context cctxt in + let* {dal = {number_of_slots; _}; _} = + Plugin.Constants_services.parametric cpctxt (chain, block) + in + let*? slot_index = + Dal.Slot_index.of_int ~number_of_slots slot_index + |> Environment.wrap_tzresult + in + let* block_hash = + Protocol_client_context.Alpha_block_services.hash cctxt ~chain ~block () + in + let* counter = + let* pcounter = + Plugin.Alpha_services.Contract.counter cpctxt (chain, `Head 0) source + in + return (Manager_counter.succ pcounter) + in + let operation = + Dal_publish_commitment {slot_index; commitment; commitment_proof} + in + let operation = + (* A dry-run of the "publish dal commitment" command for each tz kinds outputs: + - tz1: fees of 513µtz and 1333 gas consumed + - tz2: fees of 514µtz and 1318 gas consumed + - tz3: fees of 543µtz and 1607 gas consumed + - tz4: fees of 700µtz and 2837 gas consumed + We added a margin to it. + The storage limit value has been selected purely arbitrarily + (it worked with this value when I experimented, so I did not change it). *) + Alpha_context.( + Manager_operation + { + source; + fee = Tez.of_mutez_exn (Int64.of_int 750); + counter; + operation; + gas_limit = Gas.Arith.integral_of_int_exn 3000; + storage_limit = Z.of_int 100; + }) + in + let bytes = + Data_encoding.Binary.to_bytes_exn + Operation.unsigned_encoding + ({branch = block_hash}, Contents_list (Single operation)) + in + let bytes = + Signature.append ~watermark:Signature.Generic_operation src_sk bytes + in + Shell_services.Injection.operation cctxt ~chain bytes + let block_info ?chain ?block ~operations_metadata ctxt = let cpctxt = new Protocol_client_context.wrap_rpc_context ctxt in Protocol_client_context.Alpha_block_services.info diff --git a/src/proto_alpha/lib_dal/dal_plugin_registration.ml b/src/proto_alpha/lib_dal/dal_plugin_registration.ml index 210ba2cfe25f..0b7b44cba22c 100644 --- a/src/proto_alpha/lib_dal/dal_plugin_registration.ml +++ b/src/proto_alpha/lib_dal/dal_plugin_registration.ml @@ -188,6 +188,61 @@ module Plugin = struct let* _op_hash = Shell_services.Injection.operation cctxt ~chain bytes in return_unit + let publish cctxt ~block_level ~source ~slot_index ~commitment + ~commitment_proof ~src_sk () = + let open Lwt_result_syntax in + let chain = `Main in + let block = `Level block_level in + let cpctxt = new Protocol_client_context.wrap_rpc_context cctxt in + let* {dal = {number_of_slots; _}; _} = + Plugin.Constants_services.parametric cpctxt (chain, block) + in + let*? slot_index = + Dal.Slot_index.of_int ~number_of_slots slot_index + |> Environment.wrap_tzresult + in + let* block_hash = + Protocol_client_context.Alpha_block_services.hash cctxt ~chain ~block () + in + let* counter = + let* pcounter = + Plugin.Alpha_services.Contract.counter cpctxt (chain, `Head 0) source + in + return (Manager_counter.succ pcounter) + in + let operation = + Dal_publish_commitment {slot_index; commitment; commitment_proof} + in + let operation = + (* A dry-run of the "publish dal commitment" command for each tz kinds outputs: + - tz1: fees of 513µtz and 1333 gas consumed + - tz2: fees of 514µtz and 1318 gas consumed + - tz3: fees of 543µtz and 1607 gas consumed + - tz4: fees of 700µtz and 2837 gas consumed + We added a margin to it. + The storage limit value has been selected purely arbitrarily + (it worked with this value when I experimented, so I did not change it). *) + Alpha_context.( + Manager_operation + { + source; + fee = Tez.of_mutez_exn (Int64.of_int 750); + counter; + operation; + gas_limit = Gas.Arith.integral_of_int_exn 3000; + storage_limit = Z.of_int 100; + }) + in + let bytes = + Data_encoding.Binary.to_bytes_exn + Operation.unsigned_encoding + ({branch = block_hash}, Contents_list (Single operation)) + in + let bytes = + Signature.append ~watermark:Signature.Generic_operation src_sk bytes + in + Shell_services.Injection.operation cctxt ~chain bytes + let block_info ?chain ?block ~operations_metadata ctxt = let cpctxt = new Protocol_client_context.wrap_rpc_context ctxt in Protocol_client_context.Alpha_block_services.info -- GitLab From 4cec99a77e09a4da96f5c1d1f2e787439fba45df Mon Sep 17 00:00:00 2001 From: Guillaume Genestier Date: Thu, 20 Nov 2025 14:35:41 +0100 Subject: [PATCH 4/6] DAL: Add the Command line option --publish-slots-regularly --- src/lib_agnostic_baker/commands.ml | 9 ++- src/lib_dal_node/cli.ml | 75 +++++++++++++++++++++++-- src/lib_dal_node/cli.mli | 4 ++ src/lib_dal_node/configuration_file.ml | 36 ++++++++++-- src/lib_dal_node/configuration_file.mli | 7 +++ 5 files changed, 121 insertions(+), 10 deletions(-) diff --git a/src/lib_agnostic_baker/commands.ml b/src/lib_agnostic_baker/commands.ml index 7f836a152baf..50c90e9f7475 100644 --- a/src/lib_agnostic_baker/commands.ml +++ b/src/lib_agnostic_baker/commands.ml @@ -89,6 +89,8 @@ module Dal = struct let batching_configuration = arg_to_clic batching_configuration_arg + let publish_slots_regularly = arg_to_clic publish_slots_regularly_arg + let commands = let open Tezos_clic in let group = {name = "dal"; title = "Commands related to the DAL daemon."} in @@ -105,7 +107,7 @@ module Dal = struct let run = let open Tezos_clic in let args = - Tezos_clic.args25 + Tezos_clic.args26 data_dir config_file rpc_addr @@ -131,6 +133,7 @@ module Dal = struct disable_amplification ignore_topics batching_configuration + publish_slots_regularly in command ~group @@ -161,7 +164,8 @@ module Dal = struct ignore_l1_config_peers, disable_amplification, ignore_topics, - batching_configuration ) + batching_configuration, + publish_slots_regularly ) _cctxt -> Cli.Action.run @@ -190,6 +194,7 @@ module Dal = struct ~disable_amplification ?ignore_topics ?batching_configuration + ?publish_slots_regularly ()) in let mk_config_command ~prefix:p ~desc action = diff --git a/src/lib_dal_node/cli.ml b/src/lib_dal_node/cli.ml index 42d15c80d544..23d7d060909d 100644 --- a/src/lib_dal_node/cli.ml +++ b/src/lib_dal_node/cli.ml @@ -49,6 +49,13 @@ let env_var_ignore_topics = "TEZOS_IGNORE_TOPICS_I_KNOW_WHAT_I_AM_DOING" let env_ignore_topics = env_value_starts_with_yes ~env_var:env_var_ignore_topics +(** This variable is used to instruct the DAL node to publish dummy data regularly. *) +let allow_publication_regularly = + "TEZOS_DAL_PUBLISH_REGULARLY_I_KNOW_WHAT_I_AM_DOING" + +let env_publication_regularly = + env_value_starts_with_yes ~env_var:allow_publication_regularly + let merge_experimental_features _ _configuration = () let override_conf ?data_dir ?rpc_addr ?expected_pow ?listen_addr ?public_addr @@ -56,7 +63,8 @@ let override_conf ?data_dir ?rpc_addr ?expected_pow ?listen_addr ?public_addr ?metrics_addr ?profile ?(peers = []) ?history_mode ?service_name ?service_namespace ?experimental_features ?fetch_trusted_setup ?(verbose = false) ?(ignore_l1_config_peers = false) - ?(disable_amplification = false) ?batching_configuration configuration = + ?(disable_amplification = false) ?batching_configuration + ?publish_slots_regularly configuration = let profile = match profile with | None -> configuration.Configuration_file.profile @@ -108,6 +116,11 @@ let override_conf ?data_dir ?rpc_addr ?expected_pow ?listen_addr ?public_addr Option.value ~default:configuration.batching_configuration batching_configuration; + publish_slots_regularly = + Option.fold + ~none:configuration.publish_slots_regularly + ~some:Option.some + publish_slots_regularly; } let profile ?attesters ?operators ?observers ?(bootstrap = false) () = @@ -617,6 +630,39 @@ module Term = struct "batching-time-interval" let batching_configuration = arg_to_cmdliner batching_configuration_arg + + let publish_slots_regularly_arg = + let open Configuration_file in + let pp fmt {frequency; slot_index; secret_key} = + Format.fprintf + fmt + "%d-%d-%a" + frequency + slot_index + Signature.Secret_key.pp + secret_key + in + let parse str = + match String.split_on_char '-' str with + | [frequency; slot_index; secret_key] -> + Ok + { + frequency = int_of_string frequency; + slot_index = int_of_string slot_index; + secret_key = Signature.Secret_key.of_b58check_exn secret_key; + } + | _ -> Error "Unrecognized argument" + in + make_arg + ~parse + ~doc: + "The frequency of the publication of blocks, the slot on which blocks \ + are published and the secret key used to publish those blocks." + ~placeholder:"INT-INT-STR" + ~pp + "publish-slots-regularly" + + let publish_slots_regularly = arg_to_cmdliner publish_slots_regularly_arg end (** [wrap_with_error main_promise] wraps a promise that returns a tzresult @@ -677,7 +723,8 @@ module Run = struct ignore_l1_config_peers disable_amplification ignore_topics - batching_configuration -> + batching_configuration + publish_slots_regularly -> let open Lwt_result_syntax in let data_dir = Option.value ~default:Configuration_file.default.data_dir data_dir @@ -710,6 +757,7 @@ module Run = struct ~ignore_l1_config_peers ~disable_amplification ?batching_configuration + ?publish_slots_regularly in let* () = if env_disable_shard_validation && not disable_shard_validation then @@ -738,6 +786,23 @@ module Run = struct env_var_ignore_topics else return ignore_topics in + let* () = + if env_publication_regularly && Option.is_none publish_slots_regularly + then + failwith + "The environment variable to produce regularly %s was set, but the \ + option '--publish-slots-regularly' was not provided." + allow_publication_regularly + else if + (not env_publication_regularly) + && Option.is_some publish_slots_regularly + then + failwith + "The option '--publish-slots-regularly' was provided, but the \ + environment variable to allow regular production %s was not set." + allow_publication_regularly + else return_unit + in Daemon.run ~disable_shard_validation ~ignore_pkhs @@ -757,7 +822,8 @@ module Run = struct $ operator_profile $ observer_profile $ bootstrap_profile $ peers $ history_mode $ service_name $ service_namespace $ fetch_trusted_setup $ disable_shard_validation $ verbose $ ignore_l1_config_peers - $ disable_amplification $ ignore_topics $ batching_configuration)) + $ disable_amplification $ ignore_topics $ batching_configuration + $ publish_slots_regularly)) let cmd = Cmdliner.Cmd.v info term end @@ -994,7 +1060,7 @@ module Action = struct ?service_namespace ?fetch_trusted_setup ?(disable_shard_validation = false) ?(verbose = false) ?(ignore_l1_config_peers = false) ?(disable_amplification = false) - ?ignore_topics ?batching_configuration () = + ?ignore_topics ?batching_configuration ?publish_slots_regularly () = Run.action data_dir config_file @@ -1021,6 +1087,7 @@ module Action = struct disable_amplification ignore_topics batching_configuration + publish_slots_regularly let mk_config_action action = fun ?data_dir diff --git a/src/lib_dal_node/cli.mli b/src/lib_dal_node/cli.mli index 766319d13ae0..94057388a124 100644 --- a/src/lib_dal_node/cli.mli +++ b/src/lib_dal_node/cli.mli @@ -115,6 +115,9 @@ module Term : sig (** The configuration used for batching verification of received shards via GossipSub to save cryptographic computation. *) val batching_configuration_arg : Configuration_file.batching_configuration arg + + val publish_slots_regularly_arg : + Configuration_file.publish_slots_regularly arg end (** {2 Command-line subcommands} *) @@ -148,6 +151,7 @@ module Action : sig ?disable_amplification:bool -> ?ignore_topics:Signature.public_key_hash list -> ?batching_configuration:Configuration_file.batching_configuration -> + ?publish_slots_regularly:Configuration_file.publish_slots_regularly -> unit -> (unit, Error_monad.tztrace) result Lwt.t diff --git a/src/lib_dal_node/configuration_file.ml b/src/lib_dal_node/configuration_file.ml index fb43e51c9114..c84131baf17d 100644 --- a/src/lib_dal_node/configuration_file.ml +++ b/src/lib_dal_node/configuration_file.ml @@ -37,6 +37,12 @@ type batching_configuration = Disabled | Enabled of {time_interval : int} type experimental_features = unit +type publish_slots_regularly = { + frequency : int; + slot_index : int; + secret_key : Signature.Secret_key.t; +} + let history_mode_encoding = let open Data_encoding in union @@ -87,6 +93,18 @@ let batching_configuration_encoding = (fun time_interval -> Enabled {time_interval}); ] +let publish_slots_regularly_encoding = + let open Data_encoding in + conv + (fun {frequency; slot_index; secret_key} -> + (frequency, slot_index, secret_key)) + (fun (frequency, slot_index, secret_key) -> + {frequency; slot_index; secret_key}) + (obj3 + (req "frequency" uint16) + (req "slot_index" uint16) + (req "secret_key" Signature.Secret_key.encoding)) + type t = { data_dir : string; rpc_addr : P2p_point.Id.t; @@ -109,6 +127,7 @@ type t = { ignore_l1_config_peers : bool; disable_amplification : bool; batching_configuration : batching_configuration; + publish_slots_regularly : publish_slots_regularly option; } let default_data_dir = Filename.concat (Sys.getenv "HOME") ".tezos-dal-node" @@ -187,6 +206,7 @@ let default = ignore_l1_config_peers = false; disable_amplification = false; batching_configuration = default_batching_configuration; + publish_slots_regularly = None; } let uri_encoding : Uri.t Data_encoding.t = @@ -231,6 +251,7 @@ let encoding : t Data_encoding.t = ignore_l1_config_peers; disable_amplification; batching_configuration; + publish_slots_regularly; } -> ( ( ( data_dir, @@ -253,7 +274,7 @@ let encoding : t Data_encoding.t = verbose, ignore_l1_config_peers, disable_amplification ) ), - batching_configuration )) + (batching_configuration, publish_slots_regularly) )) (fun ( ( ( data_dir, rpc_addr, listen_addr, @@ -274,7 +295,7 @@ let encoding : t Data_encoding.t = verbose, ignore_l1_config_peers, disable_amplification ) ), - batching_configuration ) + (batching_configuration, publish_slots_regularly) ) -> { data_dir; @@ -298,6 +319,7 @@ let encoding : t Data_encoding.t = ignore_l1_config_peers; disable_amplification; batching_configuration; + publish_slots_regularly; }) (merge_objs (merge_objs @@ -403,12 +425,18 @@ let encoding : t Data_encoding.t = ~description:"Disable amplification" bool default.disable_amplification))) - (obj1 + (obj2 (dft "batching_configuration" ~description:"Set the batching delay for shard verification" batching_configuration_encoding - default.batching_configuration))) + default.batching_configuration) + (opt + "publish_slots_regularly" + ~description: + "Set the frequency, the slot and the secret key used for \ + automatic production" + publish_slots_regularly_encoding))) type error += DAL_node_unable_to_write_configuration_file of string diff --git a/src/lib_dal_node/configuration_file.mli b/src/lib_dal_node/configuration_file.mli index 92aa24545dda..8f54a2c33766 100644 --- a/src/lib_dal_node/configuration_file.mli +++ b/src/lib_dal_node/configuration_file.mli @@ -47,6 +47,12 @@ type batching_configuration = compatibility guarantees. *) type experimental_features = unit +type publish_slots_regularly = { + frequency : int; + slot_index : int; + secret_key : Signature.Secret_key.t; +} + type t = { data_dir : string; (** The path to the DAL node data directory. *) rpc_addr : P2p_point.Id.t; @@ -85,6 +91,7 @@ type t = { batching_configuration : batching_configuration; (** The configuration of the batching of the shards. The default is [Enabled{time_interval=100}]. *) + publish_slots_regularly : publish_slots_regularly option; } (** [default] is the default configuration. *) -- GitLab From 334d41e44d97a59d88f20cf6987769e23aa64f85 Mon Sep 17 00:00:00 2001 From: Guillaume Genestier Date: Fri, 21 Nov 2025 14:57:45 +0100 Subject: [PATCH 5/6] DAL: Inject regularly slot publication when instructed to --- src/lib_dal_node/block_handler.ml | 17 ++++++++++++++++ src/lib_dal_node/event.ml | 25 ++++++++++++++++++++++++ src/lib_dal_node/slot_production.ml | 29 ++++++++++++++++++++++++++++ src/lib_dal_node/slot_production.mli | 15 ++++++++++++++ 4 files changed, 86 insertions(+) diff --git a/src/lib_dal_node/block_handler.ml b/src/lib_dal_node/block_handler.ml index f15f21d160ee..25c3d91c8037 100644 --- a/src/lib_dal_node/block_handler.ml +++ b/src/lib_dal_node/block_handler.ml @@ -582,6 +582,23 @@ let process_finalized_block_data ctxt cctxt store ~prev_proto_parameters Plugin.tb_slot_to_int [@profiler.record_s {verbosity = Notice} "check_attesters_attested"]) in + let* () = + Option.fold + ~none:return_unit + ~some:(fun Configuration_file.{frequency; slot_index; secret_key} -> + if Int32.rem block_level (Int32.of_int frequency) = Int32.zero then + Slot_production.Tests.publish_slot_using_client + ctxt + cctxt + block_level + slot_index + secret_key + (Format.asprintf "%d:%d" (Int32.to_int block_level) slot_index) + (module Plugin : Dal_plugin.T) + else return_unit) + (Node_context.get_config ctxt).publish_slots_regularly + |> Errors.to_tzresult + in (Accuser.inject_entrapment_evidences (module Plugin) attestations diff --git a/src/lib_dal_node/event.ml b/src/lib_dal_node/event.ml index 043fd74f4569..00930553bc0c 100644 --- a/src/lib_dal_node/event.ml +++ b/src/lib_dal_node/event.ml @@ -1285,6 +1285,25 @@ open struct ~level:Error ~pp1:Error_monad.pp_print_trace ("error", Error_monad.trace_encoding) + + let publication = + declare_2 + ~section + ~name:"publication" + ~msg:"Publication operation {op_hash} at level {block_level} injected" + ~level:Info + ("op_hash", Operation_hash.encoding) + ("block_level", Data_encoding.int32) + + let publication_failed = + declare_2 + ~section + ~name:"publication_failed" + ~msg:"Publication at level {block_level} failed with error: {error}" + ~level:Warning + ("block_level", Data_encoding.int32) + ~pp2:Error_monad.pp_print_trace + ("error", Error_monad.trace_encoding) end (* DAL node event emission functions *) @@ -1650,3 +1669,9 @@ let emit_reception_of_shard_detailed ~level ~slot_index ~shard_index ~sender = let emit_skip_attesting_shards ~level = emit skip_attesting_shards level let emit_backfill_error ~error = emit backfill_error error + +let emit_publication ~block_level ~op_hash = + emit publication (op_hash, block_level) + +let emit_publication_failed ~block_level ~error = + emit publication_failed (block_level, error) diff --git a/src/lib_dal_node/slot_production.ml b/src/lib_dal_node/slot_production.ml index 834c068dfa2f..890a8076d5da 100644 --- a/src/lib_dal_node/slot_production.ml +++ b/src/lib_dal_node/slot_production.ml @@ -198,3 +198,32 @@ let produce_commitment_and_proof = ~name:"store_shards_in_cache")]) in return (commitment, commitment_proof) + +module Tests = struct + let publish_slot_using_client ctxt cctxt block_level slot_index secret_key + slot_content (module Plugin : Dal_plugin.T) = + let open Lwt_result_syntax in + let* commitment, commitment_proof = + produce_commitment_and_proof ctxt '\000' slot_content + in + let source = + Signature.Public_key.hash @@ Signature.Secret_key.to_public_key secret_key + in + let*! res = + Plugin.publish + cctxt + ~block_level + ~source + ~slot_index + ~commitment + ~commitment_proof + ~src_sk:secret_key + () + in + let*! () = + match res with + | Ok op_hash -> Event.emit_publication ~block_level ~op_hash + | Error error -> Event.emit_publication_failed ~block_level ~error + in + return_unit +end diff --git a/src/lib_dal_node/slot_production.mli b/src/lib_dal_node/slot_production.mli index db0ea2870107..3223c21ba96d 100644 --- a/src/lib_dal_node/slot_production.mli +++ b/src/lib_dal_node/slot_production.mli @@ -19,3 +19,18 @@ val produce_commitment_and_proof : string -> (Cryptobox.commitment * Cryptobox.commitment_proof, [> Errors.other]) result Lwt.t + +module Tests : sig + (** [publish_slot_using_client ctxt rpc_ctxt block_level slot_index secret_key + msg Plugin] uses the layer 1 node accessible through [rpc_ctxt] to inject a + dal_publish operation of [msg] on [slot_index] signed with [secret_key]. *) + val publish_slot_using_client : + Node_context.t -> + Tezos_rpc.Context.generic -> + int32 -> + int -> + Signature.secret_key -> + string -> + (module Dal_plugin.T) -> + (unit, [> Errors.other]) result Lwt.t +end -- GitLab From 6ad6e970801e0330c523d4e3509fbc052e170594 Mon Sep 17 00:00:00 2001 From: Guillaume Genestier Date: Wed, 26 Nov 2025 14:16:17 +0100 Subject: [PATCH 6/6] DAL: Add the identity in the context and put it in automaticaly produced slots --- src/lib_dal_node/block_handler.ml | 7 ++++++- src/lib_dal_node/daemon.ml | 3 ++- src/lib_dal_node/node_context.ml | 6 +++++- src/lib_dal_node/node_context.mli | 4 ++++ 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/lib_dal_node/block_handler.ml b/src/lib_dal_node/block_handler.ml index 25c3d91c8037..f8e720333dc6 100644 --- a/src/lib_dal_node/block_handler.ml +++ b/src/lib_dal_node/block_handler.ml @@ -593,7 +593,12 @@ let process_finalized_block_data ctxt cctxt store ~prev_proto_parameters block_level slot_index secret_key - (Format.asprintf "%d:%d" (Int32.to_int block_level) slot_index) + (Format.asprintf + "%d:%d:%a" + (Int32.to_int block_level) + slot_index + P2p_peer.Id.pp + (Node_context.get_identity ctxt).peer_id) (module Plugin : Dal_plugin.T) else return_unit) (Node_context.get_config ctxt).publish_slots_regularly diff --git a/src/lib_dal_node/daemon.ml b/src/lib_dal_node/daemon.ml index 40795aae62c6..0deb89edca20 100644 --- a/src/lib_dal_node/daemon.ml +++ b/src/lib_dal_node/daemon.ml @@ -536,6 +536,7 @@ let run ?(disable_shard_validation = false) ~ignore_pkhs ~data_dir ~config_file profile_ctxt ~number_of_slots:proto_parameters.number_of_slots in + let identity = p2p_config.P2p.identity in (* Create and start a GS worker *) let gs_worker = let rng = @@ -575,7 +576,6 @@ let run ?(disable_shard_validation = false) ~ignore_pkhs ~data_dir ~config_file } else limits in - let identity = p2p_config.P2p.identity in (* Initialize the OpenTelemetry profiler only when identity is available, to allow discriminating the different services. *) () @@ -687,6 +687,7 @@ let run ?(disable_shard_validation = false) ~ignore_pkhs ~data_dir ~config_file let ctxt = Node_context.init config + ~identity profile_ctxt cryptobox shards_proofs_precomputation diff --git a/src/lib_dal_node/node_context.ml b/src/lib_dal_node/node_context.ml index 68446d1f8406..995a56f5617f 100644 --- a/src/lib_dal_node/node_context.ml +++ b/src/lib_dal_node/node_context.ml @@ -26,6 +26,7 @@ type t = { config : Configuration_file.t; + identity : P2p_identity.t; network_name : Distributed_db_version.Name.t; cryptobox : Cryptobox.t; shards_proofs_precomputation : Cryptobox.shards_proofs_precomputation option; @@ -50,12 +51,13 @@ type t = { mutable attestable_slots_watcher_table : Attestable_slots_watcher_table.t; } -let init config ~network_name profile_ctxt cryptobox +let init config ~identity ~network_name profile_ctxt cryptobox shards_proofs_precomputation proto_plugins store gs_worker transport_layer cctxt ~last_finalized_level ?(disable_shard_validation = false) ~ignore_pkhs () = { config; + identity; network_name; cryptobox; shards_proofs_precomputation; @@ -81,6 +83,8 @@ let init config ~network_name profile_ctxt cryptobox let get_tezos_node_cctxt ctxt = ctxt.tezos_node_cctxt +let get_identity ctxt = ctxt.identity + let set_l1_crawler_status ctxt status = if ctxt.l1_crawler_status <> status then ( ctxt.l1_crawler_status <- status ; diff --git a/src/lib_dal_node/node_context.mli b/src/lib_dal_node/node_context.mli index e1249655537c..7b7de8fb90ce 100644 --- a/src/lib_dal_node/node_context.mli +++ b/src/lib_dal_node/node_context.mli @@ -31,6 +31,7 @@ type t (** [init] creates a [t] value based on the given arguments. *) val init : Configuration_file.t -> + identity:P2p_identity.t -> network_name:Distributed_db_version.Name.t -> Profile_manager.t -> Cryptobox.t -> @@ -101,6 +102,9 @@ val may_reconstruct : t -> (bytes, Errors.other) result Lwt.t +(** Returns the identity of the node. *) +val get_identity : t -> P2p_identity.t + (** Returns the status of the L1 crawler currently stored in the node context. *) val get_l1_crawler_status : t -> L1_crawler_status.t -- GitLab