From 20c1789defb8718eacf0d8dedb6912678e7fa842 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Fri, 7 Feb 2025 15:58:35 +0100 Subject: [PATCH 01/11] DAL/Node: unfold the boolean expression for trap checking --- src/bin_dal_node/RPC_server.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin_dal_node/RPC_server.ml b/src/bin_dal_node/RPC_server.ml index 4d7815813d3d..1f3862348897 100644 --- a/src/bin_dal_node/RPC_server.ml +++ b/src/bin_dal_node/RPC_server.ml @@ -463,8 +463,8 @@ module Profile_handlers = struct List.map_es (fun (slot_id, num_stored) -> let all_stored = num_stored = number_of_assigned_shards in - if (not all_stored) || not proto_parameters.incentives_enable then - return @@ all_stored + if not proto_parameters.incentives_enable then return all_stored + else if not all_stored then return false else is_slot_attestable_with_traps shards_store -- GitLab From c6e571261907e684feae53cde97425e876fdf7fb Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 6 Feb 2025 12:30:38 +0100 Subject: [PATCH 02/11] DAL/Node: use number_of_slots arg instead of full proto parameters for some functions --- src/bin_dal_node/RPC_server.ml | 3 ++- src/bin_dal_node/daemon.ml | 9 ++++++--- src/bin_dal_node/profile_manager.ml | 20 ++++++++++---------- src/bin_dal_node/profile_manager.mli | 18 ++++++++---------- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/bin_dal_node/RPC_server.ml b/src/bin_dal_node/RPC_server.ml index 1f3862348897..dd8d445c644e 100644 --- a/src/bin_dal_node/RPC_server.ml +++ b/src/bin_dal_node/RPC_server.ml @@ -281,10 +281,11 @@ module Profile_handlers = struct |> lwt_map_error (fun e -> `Other e) in let proto_parameters = Node_context.get_proto_parameters ctxt in + let number_of_slots = proto_parameters.Dal_plugin.number_of_slots in match Profile_manager.add_and_register_operator_profile (Node_context.get_profile_ctxt ctxt) - proto_parameters + ~number_of_slots gs_worker operator_profiles with diff --git a/src/bin_dal_node/daemon.ml b/src/bin_dal_node/daemon.ml index dd27d32ef22b..7677c1ad04e8 100644 --- a/src/bin_dal_node/daemon.ml +++ b/src/bin_dal_node/daemon.ml @@ -395,7 +395,7 @@ module Handler = struct in Profile_manager.on_new_head (Node_context.get_profile_ctxt ctxt) - proto_parameters + ~number_of_slots:proto_parameters.number_of_slots (Node_context.get_gs_worker ctxt) committee @@ -1067,7 +1067,10 @@ let update_and_register_profiles ctxt = let gs_worker = Node_context.get_gs_worker ctxt in let proto_parameters = Node_context.get_proto_parameters ctxt in let profile_ctxt = - Profile_manager.register_profile profile_ctxt proto_parameters gs_worker + Profile_manager.register_profile + profile_ctxt + ~number_of_slots:proto_parameters.number_of_slots + gs_worker in let*! () = Node_context.set_profile_ctxt ctxt profile_ctxt in return_unit @@ -1355,7 +1358,7 @@ let run ~data_dir ~configuration_override = let+ profile_ctxt = build_profile_context config in Profile_manager.resolve_random_observer_profile profile_ctxt - proto_parameters + ~number_of_slots:proto_parameters.number_of_slots in let*? () = Profile_manager.validate_slot_indexes diff --git a/src/bin_dal_node/profile_manager.ml b/src/bin_dal_node/profile_manager.ml index 5476dd892af9..801f73cb4e23 100644 --- a/src/bin_dal_node/profile_manager.ml +++ b/src/bin_dal_node/profile_manager.ml @@ -73,7 +73,7 @@ let merge_profiles ~lower_prio ~higher_prio = | Random_observer, ((Operator _ | Bootstrap) as profile) -> profile | (Operator _ | Bootstrap), Random_observer -> Random_observer -let add_and_register_operator_profile t proto_parameters gs_worker +let add_and_register_operator_profile t ~number_of_slots gs_worker (operator_profile : Operator_profile.t) = match t with | Types.Bootstrap -> None @@ -82,7 +82,7 @@ let add_and_register_operator_profile t proto_parameters gs_worker List.iter (fun slot_index -> Join {slot_index; pkh} |> Gossipsub.Worker.(app_input gs_worker)) - Utils.Infix.(0 -- (proto_parameters.Dal_plugin.number_of_slots - 1)) + Utils.Infix.(0 -- (number_of_slots - 1)) in Some Types.( @@ -96,15 +96,15 @@ let add_and_register_operator_profile t proto_parameters gs_worker "Profile_manager.add_and_register_operator_profile: random observer \ should have a slot index assigned at this point" -let resolve_random_observer_profile t proto_parameters = +let resolve_random_observer_profile t ~number_of_slots = match t with | Types.Bootstrap | Operator _ -> t | Random_observer -> - let slot_index = Random.int proto_parameters.Dal_plugin.number_of_slots in + let slot_index = Random.int number_of_slots in let operator_profile = Operator_profile.make ~observers:[slot_index] () in Operator operator_profile -let register_profile t proto_parameters gs_worker = +let register_profile t ~number_of_slots gs_worker = match t with | Types.Bootstrap -> t | Random_observer -> @@ -115,7 +115,7 @@ let register_profile t proto_parameters gs_worker = let t_opt = add_and_register_operator_profile empty - proto_parameters + ~number_of_slots gs_worker operator_profile in @@ -157,9 +157,9 @@ let join_topics_for_operator gs_worker committee slots = (* FIXME: https://gitlab.com/tezos/tezos/-/issues/5934 We need a mechanism to ease the tracking of newly added/removed topics. Especially important for bootstrap nodes as the cross product can grow quite large. *) -let join_topics_for_bootstrap proto_parameters gs_worker committee = +let join_topics_for_bootstrap ~number_of_slots gs_worker committee = (* Join topics for all combinations of (all slots) * (all pkh in comittee) *) - for slot_index = 0 to proto_parameters.Dal_plugin.number_of_slots - 1 do + for slot_index = 0 to number_of_slots - 1 do Signature.Public_key_hash.Map.iter (fun pkh _shards -> let topic = Types.Topic.{slot_index; pkh} in @@ -168,13 +168,13 @@ let join_topics_for_bootstrap proto_parameters gs_worker committee = committee done -let on_new_head t proto_parameters gs_worker committee = +let on_new_head t ~number_of_slots gs_worker committee = match t with | Types.Random_observer -> Stdlib.failwith "Profile_manager.add_operator_profiles: random observer should have a \ slot index assigned at this point" - | Bootstrap -> join_topics_for_bootstrap proto_parameters gs_worker committee + | Bootstrap -> join_topics_for_bootstrap ~number_of_slots gs_worker committee | Operator op -> (* The topics associated to observers and producers can change if there new active bakers. However, for attesters, new slots diff --git a/src/bin_dal_node/profile_manager.mli b/src/bin_dal_node/profile_manager.mli index a4e1a5ce0b15..631896ad580f 100644 --- a/src/bin_dal_node/profile_manager.mli +++ b/src/bin_dal_node/profile_manager.mli @@ -69,7 +69,7 @@ val operator : Operator_profile.t -> t priority. *) val merge_profiles : lower_prio:t -> higher_prio:t -> t -(** [add_and_register_operator_profile t proto_parameters gs_worker +(** [add_and_register_operator_profile t ~number_of_slots gs_worker operator_profile] adds the new [operator_profile] to [t]. It registers any new attester profile within [operator_profile] with gossipsub, that is, it instructs the [gs_worker] to join the corresponding topics. @@ -80,12 +80,12 @@ val merge_profiles : lower_prio:t -> higher_prio:t -> t It assumes the current profile is not a random observer. *) val add_and_register_operator_profile : t -> - Dal_plugin.proto_parameters -> + number_of_slots:int -> Gossipsub.Worker.t -> Operator_profile.t -> t option -(** [register_profile t proto_parameters gs_worker] does the following: +(** [register_profile t ~number_of_slots gs_worker] does the following: - It registers the attester profiles within [t] with gossipsub, that is, it instructs the [gs_worker] to join the corresponding topics. @@ -95,8 +95,7 @@ val add_and_register_operator_profile : slot index. The function returns the updated profile. *) -val register_profile : - t -> Dal_plugin.proto_parameters -> Gossipsub.Worker.t -> t +val register_profile : t -> number_of_slots:int -> Gossipsub.Worker.t -> t (** Checks that each producer profile only refers to slot indexes strictly smaller than [number_of_slots]. This may not be the case when the profile @@ -104,11 +103,11 @@ val register_profile : slots. Returns an [Invalid_slot_index] error if the check fails. *) val validate_slot_indexes : t -> number_of_slots:int -> unit tzresult -(** [on_new_head t proto_parameters gs_worker committee] performs profile-related +(** [on_new_head t ~number_of_slots gs_worker committee] performs profile-related actions that depend on the current head, more precisely on the current committee. *) val on_new_head : t -> - Dal_plugin.proto_parameters -> + number_of_slots:int -> Gossipsub.Worker.t -> Committee_cache.committee -> unit @@ -129,9 +128,8 @@ val get_attested_data_default_store_period : This function is called when generating an observer profile from a random profile before launching a DAL node, as implemented in the - daemon. -*) -val resolve_random_observer_profile : t -> Dal_plugin.proto_parameters -> t + daemon. *) +val resolve_random_observer_profile : t -> number_of_slots:int -> t (** Returns [true] iff the node should support refutation games. *) val supports_refutations : t -> bool -- GitLab From 8d5cdb5f40ebbb133e60b2c1eb07bcec9dc3c453 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Fri, 7 Feb 2025 13:14:22 +0100 Subject: [PATCH 03/11] DAL/Node: provide directly the store and traps_fraction to maybe_register_trap --- src/bin_dal_node/daemon.ml | 13 +++++++++---- src/bin_dal_node/slot_manager.ml | 23 ++++++++++++----------- src/bin_dal_node/slot_manager.mli | 15 +++++++++------ 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/src/bin_dal_node/daemon.ml b/src/bin_dal_node/daemon.ml index 7677c1ad04e8..3c8373a6dec7 100644 --- a/src/bin_dal_node/daemon.ml +++ b/src/bin_dal_node/daemon.ml @@ -248,10 +248,15 @@ module Handler = struct cryptobox message_id) in - if res = `Valid then - Option.iter - (Slot_manager.maybe_register_trap ctxt message_id) - message ; + (if res = `Valid then + let store = Node_context.get_store ctxt in + let traps_store = Store.traps store in + Option.iter + (Slot_manager.maybe_register_trap + traps_store + ~traps_fraction:proto_parameters.traps_fraction + message_id) + message) ; res | other -> (* 4. In the case the message id is not Valid. *) diff --git a/src/bin_dal_node/slot_manager.ml b/src/bin_dal_node/slot_manager.ml index 228c5065e40d..22d1bd5bb1ed 100644 --- a/src/bin_dal_node/slot_manager.ml +++ b/src/bin_dal_node/slot_manager.ml @@ -199,21 +199,13 @@ let commit cryptobox polynomial = (* Main functions *) -let maybe_register_trap ctxt message_id message = - let proto_parameters = Node_context.get_proto_parameters ctxt in +let maybe_register_trap traps_store ~traps_fraction message_id message = let delegate = message_id.Types.Message_id.pkh in let Types.Message.{share; shard_proof} = message in let Types.Message_id.{slot_index; level; shard_index; _} = message_id in - let trap_res = - Trap.share_is_trap - ~traps_fraction:proto_parameters.traps_fraction - delegate - share - in + let trap_res = Trap.share_is_trap ~traps_fraction delegate share in match trap_res with | Ok true -> - let store = Node_context.get_store ctxt in - let traps_store = Store.traps store in let slot_id = Types.Slot_id.{slot_index; slot_level = level} in Store.Traps.add traps_store @@ -317,7 +309,16 @@ let publish_proved_shards ctxt (slot_id : Types.slot_id) ~level_committee pkh; } in - maybe_register_trap ctxt message_id message ; + let store = Node_context.get_store ctxt in + let traps_store = Store.traps store in + let traps_fraction = proto_parameters.traps_fraction in + let () = + maybe_register_trap + traps_store + ~traps_fraction + message_id + message + in Gossipsub.Worker.( Publish_message {message; topic; message_id} |> app_input gs_worker) ; diff --git a/src/bin_dal_node/slot_manager.mli b/src/bin_dal_node/slot_manager.mli index 683d56e42b40..4d415fffe886 100644 --- a/src/bin_dal_node/slot_manager.mli +++ b/src/bin_dal_node/slot_manager.mli @@ -199,10 +199,13 @@ val get_slot_shard : Types.shard_index -> (Cryptobox.shard, [Errors.other | Errors.not_found]) result Lwt.t -(** [maybe_register_trap ctxt message_id message] checks if the given - message is a trap according to [Trap.share_is_trap]. If the share - is identified as a trap, it is stored in the traps cache of the - DAL node store. Otherwise does nothing. -*) +(** [maybe_register_trap traps_store ~traps_fraction message_id message] checks + if the given message is a trap according to [Trap.share_is_trap]. If the + share is identified as a trap, it is stored in the traps cache of the DAL + node store. Otherwise does nothing. *) val maybe_register_trap : - Node_context.t -> Types.Message_id.t -> Types.Message.t -> unit + Store.Traps.t -> + traps_fraction:Q.t -> + Types.Message_id.t -> + Types.Message.t -> + unit -- GitLab From b663003fff7cb01993da8df8625059c8b9b5c8a6 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Fri, 7 Feb 2025 13:59:25 +0100 Subject: [PATCH 04/11] DAL/Node: provide already fetched parameters to connect_gossipsub_with_p2p --- src/bin_dal_node/daemon.ml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bin_dal_node/daemon.ml b/src/bin_dal_node/daemon.ml index 3c8373a6dec7..da9ed58b2055 100644 --- a/src/bin_dal_node/daemon.ml +++ b/src/bin_dal_node/daemon.ml @@ -804,12 +804,11 @@ let update_timing_shard_received node_ctxt shards_timing_table slot_id in timing -let connect_gossipsub_with_p2p gs_worker transport_layer node_store node_ctxt - amplificator = +let connect_gossipsub_with_p2p proto_parameters gs_worker transport_layer + node_store node_ctxt amplificator = let open Gossipsub in - let proto_parameters = Node_context.get_proto_parameters node_ctxt in let timing_table_size = - 2 * proto_parameters.attestation_lag + 2 * proto_parameters.Dal_plugin.attestation_lag * proto_parameters.cryptobox_parameters.number_of_shards * proto_parameters.number_of_slots in @@ -1502,6 +1501,7 @@ let run ~data_dir ~configuration_override = (* Activate the p2p instance. *) let shards_store = Store.shards store in connect_gossipsub_with_p2p + proto_parameters gs_worker transport_layer shards_store -- GitLab From bae0bd30ab344a1f862713d28262e1a3fc5a25f6 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Sun, 9 Feb 2025 08:27:12 +0100 Subject: [PATCH 05/11] DAL/Node: move get_proto_parameters call closer to use --- src/bin_dal_node/RPC_server.ml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin_dal_node/RPC_server.ml b/src/bin_dal_node/RPC_server.ml index dd8d445c644e..768eb9bdd525 100644 --- a/src/bin_dal_node/RPC_server.ml +++ b/src/bin_dal_node/RPC_server.ml @@ -170,7 +170,6 @@ module Slots_handlers = struct return (commitment, commitment_proof) | _ -> let cryptobox = Node_context.get_cryptobox ctxt in - let proto_parameters = Node_context.get_proto_parameters ctxt in let profile = Node_context.get_profile_ctxt ctxt in let* () = if not (Profile_manager.is_prover_profile profile) then @@ -188,6 +187,7 @@ module Slots_handlers = struct (Errors.other [Cannot_publish_on_slot_index slot_index]) | None | Some _ -> return_unit in + let proto_parameters = Node_context.get_proto_parameters ctxt in let slot_size = proto_parameters.cryptobox_parameters.slot_size in let slot_length = String.length slot in let*? slot_bytes = -- GitLab From 930f5057711765fc3436f5df8c74cb1dfc3d370e Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Sun, 9 Feb 2025 08:19:34 +0100 Subject: [PATCH 06/11] DAL/Node: get_proto_parameters gets the parameters via the plugin --- src/bin_dal_node/RPC_server.ml | 15 ++++++++++++--- src/bin_dal_node/accuser.ml | 2 +- src/bin_dal_node/amplificator.ml | 2 +- src/bin_dal_node/daemon.ml | 4 ++-- src/bin_dal_node/node_context.ml | 16 ++++++++++++---- src/bin_dal_node/node_context.mli | 8 ++++++-- src/bin_dal_node/slot_manager.ml | 5 ++++- 7 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/bin_dal_node/RPC_server.ml b/src/bin_dal_node/RPC_server.ml index 768eb9bdd525..131058ef4551 100644 --- a/src/bin_dal_node/RPC_server.ml +++ b/src/bin_dal_node/RPC_server.ml @@ -187,7 +187,10 @@ module Slots_handlers = struct (Errors.other [Cannot_publish_on_slot_index slot_index]) | None | Some _ -> return_unit in - let proto_parameters = Node_context.get_proto_parameters ctxt in + let* proto_parameters = + Node_context.get_proto_parameters ctxt + |> lwt_map_error (fun e -> `Other e) + in let slot_size = proto_parameters.cryptobox_parameters.slot_size in let slot_length = String.length slot in let*? slot_bytes = @@ -280,7 +283,10 @@ module Profile_handlers = struct Node_context.warn_if_attesters_not_delegates ctxt operator_profiles |> lwt_map_error (fun e -> `Other e) in - let proto_parameters = Node_context.get_proto_parameters ctxt in + let* proto_parameters = + Node_context.get_proto_parameters ctxt + |> lwt_map_error (fun e -> `Other e) + in let number_of_slots = proto_parameters.Dal_plugin.number_of_slots in match Profile_manager.add_and_register_operator_profile @@ -501,8 +507,11 @@ module Profile_handlers = struct ~level:attestation_level |> Errors.other_lwt_result in + let* proto_parameters = + Node_context.get_proto_parameters ctxt + |> lwt_map_error (fun e -> `Other e) + in let store = Node_context.get_store ctxt in - let proto_parameters = Node_context.get_proto_parameters ctxt in get_attestable_slots ~shard_indices store diff --git a/src/bin_dal_node/accuser.ml b/src/bin_dal_node/accuser.ml index 5bb89bca60bc..cf3be87061cf 100644 --- a/src/bin_dal_node/accuser.ml +++ b/src/bin_dal_node/accuser.ml @@ -74,7 +74,7 @@ let inject_entrapment_evidences (type block_info) rpc_ctxt block = let open Lwt_result_syntax in let attested_level = (Plugin.block_shell_header block).level in - let proto_parameters = Node_context.get_proto_parameters node_ctxt in + let* proto_parameters = Node_context.get_proto_parameters node_ctxt in when_ proto_parameters.incentives_enable (fun () -> let published_level = (* FIXME: https://gitlab.com/tezos/tezos/-/issues/4612 diff --git a/src/bin_dal_node/amplificator.ml b/src/bin_dal_node/amplificator.ml index de870bb215c2..13697381c3b1 100644 --- a/src/bin_dal_node/amplificator.ml +++ b/src/bin_dal_node/amplificator.ml @@ -475,7 +475,7 @@ let try_amplification commitment slot_metrics slot_id amplificator = let open Lwt_result_syntax in let node_ctxt = amplificator.node_ctxt in let node_store = Node_context.get_store node_ctxt in - let proto_parameters = Node_context.get_proto_parameters node_ctxt in + let* proto_parameters = Node_context.get_proto_parameters node_ctxt in let number_of_shards = proto_parameters.cryptobox_parameters.number_of_shards in diff --git a/src/bin_dal_node/daemon.ml b/src/bin_dal_node/daemon.ml index da9ed58b2055..d1dd1c4fbc91 100644 --- a/src/bin_dal_node/daemon.ml +++ b/src/bin_dal_node/daemon.ml @@ -670,7 +670,7 @@ module Handler = struct let open Lwt_result_syntax in let stream = Crawler.finalized_heads_stream crawler in let rec loop () = - let proto_parameters = Node_context.get_proto_parameters ctxt in + let* proto_parameters = Node_context.get_proto_parameters ctxt in let cryptobox = Node_context.get_cryptobox ctxt in let*! next_final_head = Lwt_stream.get stream in match next_final_head with @@ -1069,7 +1069,7 @@ let update_and_register_profiles ctxt = let open Lwt_result_syntax in let profile_ctxt = Node_context.get_profile_ctxt ctxt in let gs_worker = Node_context.get_gs_worker ctxt in - let proto_parameters = Node_context.get_proto_parameters ctxt in + let* proto_parameters = Node_context.get_proto_parameters ctxt in let profile_ctxt = Profile_manager.register_profile profile_ctxt diff --git a/src/bin_dal_node/node_context.ml b/src/bin_dal_node/node_context.ml index 308268113b97..c565e3ea89e3 100644 --- a/src/bin_dal_node/node_context.ml +++ b/src/bin_dal_node/node_context.ml @@ -76,6 +76,8 @@ let init config profile_ctxt cryptobox shards_proofs_precomputation last_finalized_level; } +let get_tezos_node_cctxt ctxt = ctxt.tezos_node_cctxt + let may_reconstruct ~reconstruct slot_id t = let open Lwt_result_syntax in let p = @@ -113,6 +115,16 @@ let get_all_plugins ctxt = Proto_plugins.to_list ctxt.proto_plugins let set_proto_plugins ctxt proto_plugins = ctxt.proto_plugins <- proto_plugins +let get_proto_parameters ?level ctxt = + let open Lwt_result_syntax in + match level with + | None -> return ctxt.proto_parameters + | Some level -> + (* get the plugin from the plugin cache *) + let*? (module Plugin) = get_plugin_for_level ctxt ~level in + let cctxt = get_tezos_node_cctxt ctxt in + Plugin.get_constants `Main (`Level level) cctxt + let storage_period ctxt proto_parameters = match ctxt.config.history_mode with | Full -> `Always @@ -159,8 +171,6 @@ let get_config ctxt = ctxt.config let get_cryptobox ctxt = ctxt.cryptobox -let get_proto_parameters ctxt = ctxt.proto_parameters - let set_last_finalized_level ctxt level = ctxt.last_finalized_level <- level let get_last_finalized_level ctxt = ctxt.last_finalized_level @@ -171,8 +181,6 @@ let get_store ctxt = ctxt.store let get_gs_worker ctxt = ctxt.gs_worker -let get_tezos_node_cctxt ctxt = ctxt.tezos_node_cctxt - let get_neighbors_cctxts ctxt = ctxt.neighbors_cctxts let get_ongoing_amplifications ctxt = ctxt.ongoing_amplifications diff --git a/src/bin_dal_node/node_context.mli b/src/bin_dal_node/node_context.mli index 5116a7feed9a..088bb3d3a43c 100644 --- a/src/bin_dal_node/node_context.mli +++ b/src/bin_dal_node/node_context.mli @@ -99,8 +99,12 @@ val get_config : t -> Configuration_file.t (** [get_cryptobox ctxt] returns the DAL node's cryptobox *) val get_cryptobox : t -> Cryptobox.t -(** [get_proto_parameters ctxt] returns the DAL node's current protocol parameters. *) -val get_proto_parameters : t -> Dal_plugin.proto_parameters +(** [get_proto_parameters ?level ctxt] returns the DAL node's protocol + parameters stored in the context, when [level] is not provided. If [level] + is provided, then the protocol parameters for that level are fetched via the + relevant plugin. *) +val get_proto_parameters : + ?level:int32 -> t -> Dal_plugin.proto_parameters tzresult Lwt.t (** Update the node's last finalized level. *) val set_last_finalized_level : t -> int32 -> unit diff --git a/src/bin_dal_node/slot_manager.ml b/src/bin_dal_node/slot_manager.ml index 22d1bd5bb1ed..c4d4b9a190e8 100644 --- a/src/bin_dal_node/slot_manager.ml +++ b/src/bin_dal_node/slot_manager.ml @@ -391,7 +391,10 @@ let get_slot_shard (store : Store.t) (slot_id : Types.slot_id) shard_index = let get_slot_pages ~reconstruct_if_missing node_context slot_id = let open Lwt_result_syntax in - let proto_parameters = Node_context.get_proto_parameters node_context in + let* proto_parameters = + Node_context.get_proto_parameters node_context + |> lwt_map_error (fun e -> `Other e) + in let page_size = proto_parameters.cryptobox_parameters.page_size in let* slot = get_slot_content ~reconstruct_if_missing node_context slot_id in (* The slot size `Bytes.length slot` should be an exact multiple of `page_size`. -- GitLab From 723334c85da5123e5a9e6bafc0011201ddca181f Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Mon, 10 Feb 2025 06:19:17 +0100 Subject: [PATCH 07/11] DAL/Node: replace get_constants by get_proto_parameters --- src/bin_dal_node/daemon.ml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/bin_dal_node/daemon.ml b/src/bin_dal_node/daemon.ml index d1dd1c4fbc91..26c1b197246c 100644 --- a/src/bin_dal_node/daemon.ml +++ b/src/bin_dal_node/daemon.ml @@ -404,11 +404,6 @@ module Handler = struct (Node_context.get_gs_worker ctxt) committee - let get_constants ctxt cctxt ~level = - let open Lwt_result_syntax in - let*? (module Plugin) = Node_context.get_plugin_for_level ctxt ~level in - Plugin.get_constants `Main (`Level level) cctxt - let store_skip_list_cells (type block_info) ctxt cctxt dal_constants (block_info : block_info) block_level (module Plugin : Dal_plugin.T with type block_info = block_info) = @@ -424,7 +419,8 @@ module Handler = struct cctxt ~dal_constants ~pred_publication_level_dal_constants: - (lazy (get_constants ctxt cctxt ~level:pred_published_level)) + (lazy + (Node_context.get_proto_parameters ctxt ~level:pred_published_level)) in let cells_of_level = List.map @@ -549,7 +545,9 @@ module Handler = struct Node_context.get_plugin_for_level ctxt ~level:pred_level in let* block_info = Plugin.block_info cctxt ~block ~metadata:`Always in - let* dal_constants = get_constants ctxt cctxt ~level:block_level in + let* dal_constants = + Node_context.get_proto_parameters ctxt ~level:block_level + in let* () = if dal_constants.Dal_plugin.feature_enable then let* slot_headers = Plugin.get_published_slot_headers block_info in @@ -1132,7 +1130,7 @@ let clean_up_store ctxt cctxt ~last_processed_level ~first_seen_level head_level let* block_info = Plugin.block_info cctxt ~block:(`Level level) ~metadata:`Always in - let* dal_constants = Handler.get_constants ctxt cctxt ~level in + let* dal_constants = Node_context.get_proto_parameters ctxt ~level in Handler.store_skip_list_cells ctxt cctxt -- GitLab From 242c59366323313a22525075679f397e8f729708 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Sun, 9 Feb 2025 09:20:45 +0100 Subject: [PATCH 08/11] DAL/Node: use the latest parameters when processing a block --- src/bin_dal_node/daemon.ml | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/bin_dal_node/daemon.ml b/src/bin_dal_node/daemon.ml index 26c1b197246c..4777f2bcf965 100644 --- a/src/bin_dal_node/daemon.ml +++ b/src/bin_dal_node/daemon.ml @@ -251,6 +251,13 @@ module Handler = struct (if res = `Valid then let store = Node_context.get_store ctxt in let traps_store = Store.traps store in + (* TODO: https://gitlab.com/tezos/tezos/-/issues/7742 + The [proto_parameters] are those for the last known finalized + level, which may differ from those of the slot level. This + will be an issue when the value of the [traps_fraction] + changes. (We cannot use {!Node_context.get_proto_parameters}, + as it is not monad-free; we'll need to use mapping from levels + to parameters.) *) Option.iter (Slot_manager.maybe_register_trap traps_store @@ -668,7 +675,6 @@ module Handler = struct let open Lwt_result_syntax in let stream = Crawler.finalized_heads_stream crawler in let rec loop () = - let* proto_parameters = Node_context.get_proto_parameters ctxt in let cryptobox = Node_context.get_cryptobox ctxt in let*! next_final_head = Lwt_stream.get stream in match next_final_head with @@ -676,6 +682,18 @@ module Handler = struct | Some (_finalized_hash, finalized_shell_header) -> let level = finalized_shell_header.level in let () = Node_context.set_last_finalized_level ctxt level in + let* () = + (* FIXME: https://gitlab.com/tezos/tezos/-/issues/7291 + We should use the head level instead. *) + Node_context.may_add_plugin + ctxt + cctxt + ~proto_level:finalized_shell_header.proto_level + ~block_level:level + in + let* proto_parameters = + Node_context.get_proto_parameters ctxt ~level + in (* At each potential published_level [level], we prefetch the committee for its corresponding attestation_level (that is: level + attestation_lag - 1). This is in particular used by GS @@ -695,15 +713,6 @@ module Handler = struct in return_unit in - let* () = - (* FIXME: https://gitlab.com/tezos/tezos/-/issues/7291 - We should use the head level instead. *) - Node_context.may_add_plugin - ctxt - cctxt - ~proto_level:finalized_shell_header.proto_level - ~block_level:level - in Gossipsub.Worker.Validate_message_hook.set (gossipsub_app_messages_validation ctxt -- GitLab From f4b2e3a01b553cd78de76cc54463024b112f0637 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Thu, 6 Feb 2025 18:46:50 +0100 Subject: [PATCH 09/11] DAL/Node: get the protocol parameters at right level for checking traps --- src/bin_dal_node/RPC_server.ml | 106 ++++++++++++++++++++------------- src/bin_dal_node/accuser.ml | 4 +- 2 files changed, 67 insertions(+), 43 deletions(-) diff --git a/src/bin_dal_node/RPC_server.ml b/src/bin_dal_node/RPC_server.ml index 131058ef4551..fca39cdeb20c 100644 --- a/src/bin_dal_node/RPC_server.ml +++ b/src/bin_dal_node/RPC_server.ml @@ -446,51 +446,73 @@ module Profile_handlers = struct attested_level (of_int proto_parameters.Dal_plugin.attestation_lag)) in - let shards_store = Store.shards store in - let number_of_shards_stored slot_index = - let slot_id : Types.slot_id = - {slot_level = published_level; slot_index} + if published_level < 1l then + let slots = + Stdlib.List.init proto_parameters.number_of_slots (fun _ -> false) in - let+ number_stored_shards = - Store.Shards.number_of_shards_available - shards_store - slot_id - shard_indices + return (Types.Attestable_slots {slots; published_level}) + else + (* FIXME: https://gitlab.com/tezos/tezos/-/issues/7291 + + Normally, for checking whether the incentives are enabled we would + use the (parameters at) [attested_level]. However, the attestation + level may be in the future and we may not have the plugin for + it. *) + let* proto_parameters = + Node_context.get_proto_parameters ctxt ~level:published_level |> lwt_map_error (fun e -> `Other e) in - (slot_id, number_stored_shards) - in - let all_slot_indexes = - Utils.Infix.(0 -- (proto_parameters.number_of_slots - 1)) - in - let* number_of_stored_shards_per_slot = - List.map_es number_of_shards_stored all_slot_indexes - in - let* flags = - List.map_es - (fun (slot_id, num_stored) -> - let all_stored = num_stored = number_of_assigned_shards in - if not proto_parameters.incentives_enable then return all_stored - else if not all_stored then return false - else - is_slot_attestable_with_traps - shards_store - proto_parameters.traps_fraction - pkh - shard_indices - slot_id) - number_of_stored_shards_per_slot - in - Lwt.dont_wait - (fun () -> - warn_missing_shards - store - pkh - published_level - number_of_assigned_shards - number_of_stored_shards_per_slot) - (fun _exn -> ()) ; - return (Types.Attestable_slots {slots = flags; published_level}) + + let shards_store = Store.shards store in + let number_of_shards_stored slot_index = + let slot_id : Types.slot_id = + {slot_level = published_level; slot_index} + in + let+ number_stored_shards = + Store.Shards.number_of_shards_available + shards_store + slot_id + shard_indices + |> lwt_map_error (fun e -> `Other e) + in + (slot_id, number_stored_shards) + in + let all_slot_indexes = + Utils.Infix.(0 -- (proto_parameters.number_of_slots - 1)) + in + let* number_of_stored_shards_per_slot = + List.map_es number_of_shards_stored all_slot_indexes + in + let* published_level_parameters = + Node_context.get_proto_parameters ctxt ~level:published_level + |> lwt_map_error (fun e -> `Other e) + in + let* flags = + List.map_es + (fun (slot_id, num_stored) -> + let all_stored = num_stored = number_of_assigned_shards in + if not published_level_parameters.incentives_enable then + return all_stored + else if not all_stored then return false + else + is_slot_attestable_with_traps + shards_store + published_level_parameters.traps_fraction + pkh + shard_indices + slot_id) + number_of_stored_shards_per_slot + in + Lwt.dont_wait + (fun () -> + warn_missing_shards + store + pkh + published_level + number_of_assigned_shards + number_of_stored_shards_per_slot) + (fun _exn -> ()) ; + return (Types.Attestable_slots {slots = flags; published_level}) in call_handler1 (fun () -> let open Lwt_result_syntax in diff --git a/src/bin_dal_node/accuser.ml b/src/bin_dal_node/accuser.ml index cf3be87061cf..5bb5d49d9baf 100644 --- a/src/bin_dal_node/accuser.ml +++ b/src/bin_dal_node/accuser.ml @@ -74,7 +74,9 @@ let inject_entrapment_evidences (type block_info) rpc_ctxt block = let open Lwt_result_syntax in let attested_level = (Plugin.block_shell_header block).level in - let* proto_parameters = Node_context.get_proto_parameters node_ctxt in + let* proto_parameters = + Node_context.get_proto_parameters node_ctxt ~level:attested_level + in when_ proto_parameters.incentives_enable (fun () -> let published_level = (* FIXME: https://gitlab.com/tezos/tezos/-/issues/4612 -- GitLab From cba8eccd2a4fc6d2aff672abe9615033f32e0726 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Mon, 10 Feb 2025 14:51:27 +0100 Subject: [PATCH 10/11] DAL/Node: get the protocol plugin `attestation_lag` levels in the past ... wrt to the head, even when the node does not support refutations. This is because the node may need the protocol parameters for such past levels. --- src/bin_dal_node/daemon.ml | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/bin_dal_node/daemon.ml b/src/bin_dal_node/daemon.ml index 4777f2bcf965..4e632a767ee0 100644 --- a/src/bin_dal_node/daemon.ml +++ b/src/bin_dal_node/daemon.ml @@ -1086,20 +1086,18 @@ let update_and_register_profiles ctxt = let*! () = Node_context.set_profile_ctxt ctxt profile_ctxt in return_unit -(* This function fetches the protocol plugins for levels for which it is needed - to add skip list cells. It starts by computing the oldest level at which it - will be needed to add skip list cells. *) +(* This function fetches the protocol plugins for levels in the past for which + the node may need a plugin, namely for adding skip list cells, or for + obtaining the protocol parameters. + + Concerning the skip list, getting the plugin is (almost) necessary as skip + list cells are stored in the storage for a certain period and + [store_skip_list_cells] needs the L1 context for levels in this period. (It + would actually not be necessary to go as far in the past, because the + protocol parameters and the relevant encodings do not change for now, so the + head plugin could be used). *) let get_proto_plugins cctxt profile_ctxt ~last_processed_level ~first_seen_level head_level proto_parameters = - (* We resolve the plugins for all levels starting with [(max - last_processed_level (head_level - storage_period)], or (max - last_processed_level (head_level - storage_period) - (attestation_lag - - 1))] in case the node supports refutations. This is necessary as skip list - cells are stored for attested levels is this storage period and - [store_skip_list_cells] needs the L1 context for these levels. (It would - actually not be necessary to go as far in the past, because the protocol - parameters and the relevant encodings do not change for now, so the head - plugin could be used). *) let storage_period = get_storage_period profile_ctxt proto_parameters head_level first_seen_level in @@ -1111,7 +1109,10 @@ let get_proto_plugins cctxt profile_ctxt ~last_processed_level ~first_seen_level let first_level = if Profile_manager.supports_refutations profile_ctxt then Int32.sub first_level (Int32.of_int (skip_list_offset proto_parameters)) - else first_level + else + (* The DAL node may need the protocol parameters [attestation_lag] in the + past wrt to the head level. *) + Int32.sub first_level (Int32.of_int proto_parameters.attestation_lag) in let first_level = Int32.(max 1l first_level) in Proto_plugins.initial_plugins cctxt ~first_level ~last_level:head_level -- GitLab From 4f965c2009309b8ba739a29dd15f9f1c625c9676 Mon Sep 17 00:00:00 2001 From: Eugen Zalinescu Date: Fri, 7 Feb 2025 15:28:09 +0100 Subject: [PATCH 11/11] DAL/Tests: update invalid message exchange test We make the sure that the L1 node of the "invalid" DAL node reaches level 2 by connecting it to the L1 node of the other, valid DAL node. --- tezt/tests/dal.ml | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 3f0a368a7d2c..e82e8a4a1b3b 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -3959,7 +3959,7 @@ let test_dal_node_join_topic _protocol parameters _cryptobox _node _client *) let generic_gs_messages_exchange protocol parameters _cryptobox node client dal_node1 ~mk_dal_node2 ~expect_app_notification ~is_first_slot_attestable = - let* dal_node2 = mk_dal_node2 protocol parameters in + let* node2, dal_node2 = mk_dal_node2 protocol parameters in let* () = Dal_common.Helpers.connect_nodes_via_p2p @@ -4041,6 +4041,16 @@ let generic_gs_messages_exchange protocol parameters _cryptobox node client and* () = waiter_receive_shards and* () = waiter_app_notifs in + let* () = + match node2 with + | None -> unit + | Some node2 -> + (* We need that this node reaches level 2; otherwise, the RPC call to + [get_attestable_slots] may fail. *) + let* _level = Node.wait_for_level node2 2 in + unit + in + (* Check that dal_node2 has the shards needed by attester account1/pkh1 to attest the slot with index 0. *) let* res = @@ -4070,13 +4080,14 @@ let test_dal_node_gs_valid_messages_exchange _protocol parameters _cryptobox client dal_node1 ~mk_dal_node2:(fun _protocol _parameters -> - Dal_node.create ~node () |> return) + let dal_node2 = Dal_node.create ~node () in + (None, dal_node2) |> return) ~expect_app_notification:true ~is_first_slot_attestable:true (* Create a DAL node whose DAL parameters are not compatible with those in [parameters]. For that, the redundancy_factor field is multiplied by 2. *) -let make_invalid_dal_node protocol parameters = +let make_invalid_dal_node node1 protocol parameters = (* Create another L1 node with different DAL parameters. *) let* node2, _client2, _xdal_parameters2 = let crypto_params = parameters.Dal.Parameters.cryptobox in @@ -4087,10 +4098,13 @@ let make_invalid_dal_node protocol parameters = in setup_node ~protocol ~parameter_overrides () in + Node.add_peer node2 node1 ; + let* () = Node.terminate node2 in + let* () = Node.run node2 [] in (* Create a second DAL node with node2 and client2 as argument (so different DAL parameters compared to dal_node1. *) let dal_node2 = Dal_node.create ~node:node2 () in - return dal_node2 + return (Some node2, dal_node2) let test_dal_node_gs_invalid_messages_exchange _protocol parameters _cryptobox node client dal_node1 = @@ -4107,7 +4121,7 @@ let test_dal_node_gs_invalid_messages_exchange _protocol parameters _cryptobox node client dal_node1 - ~mk_dal_node2:make_invalid_dal_node + ~mk_dal_node2:(make_invalid_dal_node node) ~expect_app_notification ~is_first_slot_attestable @@ -4149,7 +4163,7 @@ let test_gs_prune_and_ihave protocol parameters _cryptobox node client dal_node1 in (* Create another (invalid) DAL node *) - let* dal_node2 = make_invalid_dal_node protocol parameters in + let* _, dal_node2 = make_invalid_dal_node node protocol parameters in (* Connect the nodes *) let* () = -- GitLab