From f3c8dd390a4f7401db713b6504abb874fd6b76cb Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Thu, 15 Dec 2022 17:12:35 +0100 Subject: [PATCH 1/9] DAL/Node: change slot indexes encoding in headers path --- src/bin_dal_node/store.ml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/bin_dal_node/store.ml b/src/bin_dal_node/store.ml index 24806324a565..36c83125a6cf 100644 --- a/src/bin_dal_node/store.ml +++ b/src/bin_dal_node/store.ml @@ -140,9 +140,7 @@ module Legacy = struct let header commitment index = let open Services.Types in let prefix = headers commitment in - prefix - / Int32.to_string index.slot_level - / Int.to_string index.slot_index + prefix / Data_encoding.Binary.to_string_exn slot_id_encoding index let shards commitment = let commitment_repr = Cryptobox.Commitment.to_b58check commitment in -- GitLab From d33da6d6b22ab96f028dd0239467cd36336fc34a Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Thu, 15 Dec 2022 17:14:41 +0100 Subject: [PATCH 2/9] DAL/Node: add_slots_headers: also save info under /commitments --- src/bin_dal_node/store.ml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/bin_dal_node/store.ml b/src/bin_dal_node/store.ml index 36c83125a6cf..7cea93ad7e36 100644 --- a/src/bin_dal_node/store.ml +++ b/src/bin_dal_node/store.ml @@ -269,11 +269,17 @@ module Legacy = struct in (* This invariant should hold. *) assert (Int32.equal published_level block_level) ; + let index = Services.Types.{slot_level = published_level; slot_index} in + let header_path = Path.Commitment.header commitment index in + let* () = + set + ~msg:(Path.to_string ~prefix:"add_slot_headers:" header_path) + slots_store + header_path + "" + in match status with | Dal_plugin.Succeeded -> - let index = - Services.Types.{slot_level = published_level; slot_index} - in let commitment_path = Path.Level.accepted_header_commitment index in let status_path = Path.Level.accepted_header_status index in let data = encode_commitment commitment in @@ -292,9 +298,6 @@ module Legacy = struct (Services.Types.header_attestation_status_to_string `Waiting_for_attestations) | Dal_plugin.Failed -> - let index = - Services.Types.{slot_level = published_level; slot_index} - in let path = Path.Level.other_header_status index commitment in set ~msg:(Path.to_string ~prefix:"add_slot_headers:" path) -- GitLab From 3af5a8f9f8976d59704bfce395c216bc392830aa Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Fri, 16 Dec 2022 12:13:02 +0100 Subject: [PATCH 3/9] DAL/Node: service for GET /slots//headers --- src/lib_dal_node_services/services.ml | 64 ++++++++++++++++++++++++++ src/lib_dal_node_services/services.mli | 29 +++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/src/lib_dal_node_services/services.ml b/src/lib_dal_node_services/services.ml index 07b5e404e551..4b88c4252041 100644 --- a/src/lib_dal_node_services/services.ml +++ b/src/lib_dal_node_services/services.ml @@ -50,22 +50,44 @@ module Types = struct type header_status = [`Not_selected | `Unseen | header_attestation_status] + type slot_header = { + slot_id : slot_id; + commitment : Cryptobox.Commitment.t; + status : header_status; + } + (* TODO: https://gitlab.com/tezos/tezos/-/issues/4442 Add missing profiles. *) type profile = Attestor of Tezos_crypto.Signature.public_key_hash (* Auxiliary functions. *) + let header_attestation_statuses = + [`Waiting_for_attestations; `Attested; `Unattested] + let header_attestation_status_to_string = function | `Waiting_for_attestations -> "waiting_for_attestations" | `Attested -> "attested" | `Unattested -> "unattested" + let header_attestation_status_of_string = function + | "waiting_for_attestations" -> Some `Waiting_for_attestations + | "attested" -> Some `Attested + | "unattested" -> Some `Unattested + | _ -> None + + let header_statuses = `Not_selected :: `Unseen :: header_attestation_statuses + let header_status_to_string = function | `Not_selected -> "not_selected" | `Unseen -> "unseen" | #header_attestation_status as e -> header_attestation_status_to_string e + let header_status_of_string = function + | "not_selected" -> Some `Not_selected + | "unseen" -> Some `Unseen + | s -> header_attestation_status_of_string s + (* Encodings associated to the types. *) let slot_id_encoding = @@ -79,6 +101,22 @@ module Types = struct let slot_encoding = Data_encoding.bytes + let header_status_encoding = + let open Data_encoding in + string_enum + (List.map (fun t -> (header_status_to_string t, t)) header_statuses) + + let slot_header_encoding = + let open Data_encoding in + conv + (fun {slot_id; commitment; status} -> (slot_id, (commitment, status))) + (fun (slot_id, (commitment, status)) -> {slot_id; commitment; status}) + (merge_objs + slot_id_encoding + (obj2 + (req "commitment" Cryptobox.Commitment.encoding) + (req "status" header_status_encoding))) + let equal_profile (Attestor p1) (Attestor p2) = Tezos_crypto.Signature.Public_key_hash.( = ) p1 p2 @@ -97,6 +135,16 @@ module Types = struct (function Attestor attest -> Some ((), attest)) (function (), attest -> Attestor attest); ] + + (* String parameters queries. *) + + let slot_id_query = + let open Tezos_rpc in + let open Query in + query (fun slot_level slot_index -> (slot_level, slot_index)) + |+ opt_field "slot_level" Arg.int32 fst + |+ opt_field "slot_index" Arg.int snd + |> seal end let post_slots : @@ -179,6 +227,22 @@ let get_commitment_by_published_level_and_index : open_root / "levels" /: Tezos_rpc.Arg.int32 / "slot_indices" /: Tezos_rpc.Arg.int / "commitment") +let get_commitment_headers : + < meth : [`GET] + ; input : unit + ; output : Types.slot_header list + ; prefix : unit + ; params : unit * Cryptobox.commitment + ; query : Types.level option * Types.slot_index option > + service = + Tezos_rpc.Service.get_service + ~description: + "Return the known headers for the the slot whose commitment is given." + ~query:Types.slot_id_query + ~output:(Data_encoding.list Types.slot_header_encoding) + Tezos_rpc.Path.( + open_root / "commitments" /: Cryptobox.Commitment.rpc_arg / "headers") + let patch_profile : < meth : [`PATCH] ; input : Types.profile diff --git a/src/lib_dal_node_services/services.mli b/src/lib_dal_node_services/services.mli index 0a489dac7323..7525264f8fec 100644 --- a/src/lib_dal_node_services/services.mli +++ b/src/lib_dal_node_services/services.mli @@ -77,19 +77,36 @@ module Types : sig (** The slot header was successfully included in a block. see {!header_attestation_status} for more details. *) - (** DAL node can track one or many profiles that correspond to various modes + (** DAL node can track one or many profiles that correspond to various modes that the DAL node would operate in *) type profile = Attestor of Tezos_crypto.Signature.public_key_hash + (** Information associated to a slot header in the RPC services of the DAL + node. *) + type slot_header = { + slot_id : slot_id; + commitment : Cryptobox.Commitment.t; + status : header_status; + } + val slot_id_encoding : slot_id Data_encoding.t (** Return the string representation for values of type {!header_attestation_status}. *) val header_attestation_status_to_string : header_attestation_status -> string + (** Convert the string to the correponding value of type + {!header_attestation_status}. Return {!None} in case of mismatch. *) + val header_attestation_status_of_string : + string -> header_attestation_status option + (** Return the string representation for values of type {!header_status}. *) val header_status_to_string : header_status -> string + (** Convert the string to the correponding value of type + {!header_status}. Return {!None} in case of mismatch. *) + val header_status_of_string : string -> header_status option + val profile_encoding : profile Data_encoding.t val equal_profile : profile -> profile -> bool @@ -149,6 +166,16 @@ val get_commitment_by_published_level_and_index : ; query : unit > service +(** Return the known headers for the slot whose commitment is given. *) +val get_commitment_headers : + < meth : [`GET] + ; input : unit + ; output : Types.slot_header list + ; prefix : unit + ; params : unit * Cryptobox.commitment + ; query : Types.level option * Types.slot_index option > + service + (** Update the list of profiles tracked by the DAL node *) val patch_profile : < meth : [`PATCH] -- GitLab From 16d297b1400b6ceab13d7d2adfad4d403c6d47bf Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Thu, 15 Dec 2022 17:45:42 +0100 Subject: [PATCH 4/9] DAL/Node: implement RPC GET /commitments//headers --- src/bin_dal_node/RPC_server.ml | 14 ++++++ src/bin_dal_node/slot_manager.ml | 7 +++ src/bin_dal_node/slot_manager.mli | 10 ++++ src/bin_dal_node/store.ml | 78 +++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) diff --git a/src/bin_dal_node/RPC_server.ml b/src/bin_dal_node/RPC_server.ml index f5b75e17aea6..6988c994b760 100644 --- a/src/bin_dal_node/RPC_server.ml +++ b/src/bin_dal_node/RPC_server.ml @@ -87,6 +87,16 @@ module Slots_handlers = struct | Error (Ok `Not_found) -> return_none | Error (Error e) -> fail e) ctxt + + let get_commitment_headers ctxt commitment (slot_level, slot_index) () = + call_handler + (fun store _cryptobox -> + Slot_manager.get_commitment_headers + commitment + ?slot_level + ?slot_index + store) + ctxt end module Profile_handlers = struct @@ -136,6 +146,10 @@ let register_new : Tezos_rpc.Directory.register0 Services.get_profiles (Profile_handlers.get_profiles ctxt) + |> add_service + Tezos_rpc.Directory.register1 + Services.get_commitment_headers + (Slots_handlers.get_commitment_headers ctxt) let register_legacy ctxt = let open RPC_server_legacy in diff --git a/src/bin_dal_node/slot_manager.ml b/src/bin_dal_node/slot_manager.ml index 993c1e68c0b7..3c677c05b29d 100644 --- a/src/bin_dal_node/slot_manager.ml +++ b/src/bin_dal_node/slot_manager.ml @@ -114,3 +114,10 @@ let get_commitment_by_published_level_and_index ~level ~slot_index node_store = ~level ~slot_index node_store + +let get_commitment_headers commitment ?slot_level ?slot_index node_store = + Store.Legacy.get_commitment_headers + commitment + ?slot_level + ?slot_index + node_store diff --git a/src/bin_dal_node/slot_manager.mli b/src/bin_dal_node/slot_manager.mli index a3df07961a73..2e2015fb9b0e 100644 --- a/src/bin_dal_node/slot_manager.mli +++ b/src/bin_dal_node/slot_manager.mli @@ -104,3 +104,13 @@ val get_commitment_by_published_level_and_index : slot_index:Services.Types.slot_index -> Store.node_store -> (Cryptobox.commitment, [`Not_found] tzresult) result Lwt.t + +(** [get_commitment_headers commitment ?slot_level ?slot_index store] returns + the list of accepted slot headers {!Services.Types.slot_header} that are + known by the DAL together with their respective statuses. *) +val get_commitment_headers : + Cryptobox.commitment -> + ?slot_level:Services.Types.level -> + ?slot_index:Services.Types.slot_index -> + Store.node_store -> + Services.Types.slot_header list tzresult Lwt.t diff --git a/src/bin_dal_node/store.ml b/src/bin_dal_node/store.ml index 7cea93ad7e36..634e35fb227a 100644 --- a/src/bin_dal_node/store.ml +++ b/src/bin_dal_node/store.ml @@ -254,6 +254,9 @@ module Legacy = struct let decode_commitment = Cryptobox.Commitment.of_b58check_opt + let decode_slot_id = + Data_encoding.Binary.of_string_exn Services.Types.slot_id_encoding + let add_slot_headers ~block_level ~block_hash slot_headers node_store = let open Lwt_syntax in let* () = legacy_add_slot_headers ~block_hash slot_headers node_store in @@ -376,4 +379,79 @@ module Legacy = struct node_store.store path "" + + (** Filter the given list of indices according to the values of the given slot + level and index. *) + let filter_indexes = + let keep_field v = function None -> true | Some f -> f = v in + fun ?slot_level ?slot_index indexes -> + List.map (fun (slot_id, _) -> decode_slot_id slot_id) indexes + |> List.filter (fun {Services.Types.slot_level = l; slot_index = i} -> + keep_field l slot_level && keep_field i slot_index) + + let get_accepted_headers_of_commitment commitment indices store accu = + let open Lwt_result_syntax in + let encoded_commitment = encode_commitment commitment in + List.fold_left_es + (fun acc slot_id -> + let commitment_path = Path.Level.accepted_header_commitment slot_id in + let*! commitment_opt = find store commitment_path in + match commitment_opt with + | None -> return acc + | Some read_commitment -> ( + if not @@ String.equal read_commitment encoded_commitment then + return acc + else + let status_path = Path.Level.accepted_header_status slot_id in + let*! status_opt = find store status_path in + match status_opt with + | None -> return acc + | Some status_str -> ( + (* TODO: https://gitlab.com/tezos/tezos/-/issues/4466 + Use more compact encodings to reduce allocated storage. *) + match + Services.Types.header_attestation_status_of_string + status_str + with + | None -> failwith "Attestation status decoding failed" + | Some status -> + return + @@ { + Services.Types.slot_id; + commitment; + status = (status :> Services.Types.header_status); + } + :: acc))) + accu + indices + + let get_other_headers_of_commitment commitment indices store accu = + let open Lwt_result_syntax in + List.fold_left_es + (fun acc slot_id -> + let*! status_opt = + find store @@ Path.Level.other_header_status slot_id commitment + in + match status_opt with + | None -> return acc + | Some status_str -> ( + match Services.Types.header_status_of_string status_str with + | None -> failwith "Attestation status decoding failed" + | Some status -> + return @@ ({Services.Types.slot_id; commitment; status} :: acc))) + accu + indices + + let get_commitment_headers commitment ?slot_level ?slot_index node_store = + let open Lwt_result_syntax in + let store = node_store.store in + (* Get the list of known slot identifiers for [commitment]. *) + let*! indexes = list store @@ Path.Commitment.headers commitment in + (* Filter the list of indices by the values of [slot_level] [slot_index]. *) + let indices = filter_indexes ?slot_level ?slot_index indexes in + (* Retrieve the headers that haven't been "accepted" on L1. *) + let* accu = get_other_headers_of_commitment commitment indices store [] in + (* Retrieve the headers that have "accepted" on L1 (i.e. with + [`Waiting_for_attestation], [`Attested] or [`Unattested] statuses). *) + get_accepted_headers_of_commitment commitment indices store accu end -- GitLab From d84c4f9e40f98a907af9ab3e6c7cdc38ce8f30b7 Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Fri, 16 Dec 2022 12:16:42 +0100 Subject: [PATCH 5/9] Tezt/lib_tezos: bind RPC GET /commitments//headers --- tezt/lib_tezos/rollup.ml | 33 +++++++++++++++++++++++++++++++++ tezt/lib_tezos/rollup.mli | 25 +++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/tezt/lib_tezos/rollup.ml b/tezt/lib_tezos/rollup.ml index 033a79bc4ef7..142a8c0a772c 100644 --- a/tezt/lib_tezos/rollup.ml +++ b/tezt/lib_tezos/rollup.ml @@ -675,6 +675,25 @@ module Dal = struct type profile = Attestor of string + type slot_header = { + slot_level : int; + slot_index : int; + commitment : string; + status : string; + } + + let slot_header_of_json json = + let open JSON in + { + slot_level = json |-> "slot_level" |> as_int; + slot_index = json |-> "slot_index" |> as_int; + commitment = json |-> "commitment" |> as_string; + status = json |-> "status" |> as_string; + } + + let slot_headers_of_json json = + JSON.as_list json |> List.map slot_header_of_json + let as_empty_object_or_fail t = match JSON.as_object t with | [] -> () @@ -737,6 +756,20 @@ module Dal = struct make ~data PATCH ["profiles"] as_empty_object_or_fail let get_profiles () = make GET ["profiles"] profiles_of_json + + let mk_query_arg field v_opt = + Option.fold ~none:[] ~some:(fun v -> [(field, string_of_int v)]) v_opt + + let get_commitment_headers ?slot_level ?slot_index commitment = + let query_string = + mk_query_arg "slot_level" slot_level + @ mk_query_arg "slot_index" slot_index + in + make + ~query_string + GET + ["commitments"; commitment; "headers"] + slot_headers_of_json end let make diff --git a/tezt/lib_tezos/rollup.mli b/tezt/lib_tezos/rollup.mli index 5e5b0fc26b70..245d443499f9 100644 --- a/tezt/lib_tezos/rollup.mli +++ b/tezt/lib_tezos/rollup.mli @@ -297,6 +297,22 @@ module Dal : sig type profile = Attestor of string + (** Information contained in a slot header fetched from the DAL node. *) + type slot_header = { + slot_level : int; + slot_index : int; + commitment : string; + status : string; + } + + (** [slot_header_of_json json] decodes [json] as a slot header. The function + fails if the given [json] cannot be decoded. *) + val slot_header_of_json : JSON.t -> slot_header + + (** [slot_header_of_json json_] similar to {!slot_header_of_json}, but + the input (and output) is expected to be a list. *) + val slot_headers_of_json : JSON.t -> slot_header list + (** Call RPC "POST /slots" to store a slot and retrun the commitment in case of success. *) val post_slot : slot -> (Dal_node.t, commitment) RPC_core.t @@ -332,6 +348,15 @@ module Dal : sig (** Call RPC "GET /profiles" to retrieve the list of profiles tracked by the DAL node. *) val get_profiles : unit -> (Dal_node.t, profile list) RPC_core.t + + (** Call RPC "GET /commitments//headers" to get the header and + status know about the given commitment. The resulting list can be filtered by a + given header publication level and slot index. *) + val get_commitment_headers : + ?slot_level:int -> + ?slot_index:int -> + commitment -> + (Dal_node.t, slot_header list) RPC_core.t end val make : -- GitLab From 5daf630650f08e034bc67e23e255fd70e1a6de51 Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Thu, 15 Dec 2022 17:52:21 +0100 Subject: [PATCH 6/9] Tezt/Dal: introduce dal_attestations and refactor tests. --- tezt/tests/dal.ml | 49 ++++++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 3011f5005180..1c797d83d4ad 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -444,6 +444,14 @@ let dal_attestation ?level ?(force = false) ~signer ~nb_slots availability Operation.Consensus.( inject ~force ~signer (dal_attestation ~level ~attestation) client) +let dal_attestations ?level ?force + ?(signers = Array.to_list Account.Bootstrap.keys) ~nb_slots availability + client = + Lwt_list.map_s + (fun signer -> + dal_attestation ?level ?force ~signer ~nb_slots availability client) + signers + type status = Applied | Failed of {error_id : string} let pp fmt = function @@ -635,14 +643,19 @@ let test_slot_management_logic _protocol parameters cryptobox node client check_manager_operation_status operations_result Applied oph2 ; let nb_slots = parameters.Rollup.Dal.Parameters.number_of_slots in let* _ = - dal_attestation ~nb_slots ~signer:Constant.bootstrap1 [1; 0] client + dal_attestations + ~nb_slots + ~signers:[Constant.bootstrap1; Constant.bootstrap2] + [1; 0] + client in let* _ = - dal_attestation ~nb_slots ~signer:Constant.bootstrap2 [1; 0] client + dal_attestations + ~nb_slots + ~signers:[Constant.bootstrap3; Constant.bootstrap4; Constant.bootstrap5] + [1] + client in - let* _ = dal_attestation ~nb_slots ~signer:Constant.bootstrap3 [1] client in - let* _ = dal_attestation ~nb_slots ~signer:Constant.bootstrap4 [1] client in - let* _ = dal_attestation ~nb_slots ~signer:Constant.bootstrap5 [1] client in let* () = Client.bake_for_and_wait client in let* metadata = RPC.call node (RPC.get_chain_block_metadata ()) in let attestation = @@ -762,15 +775,9 @@ let test_slots_attestation_operation_behavior _protocol parameters cryptobox let* () = Client.bake_for_and_wait client in let now = Node.get_level node in let* attestation_ops = - let open Constant in let level = now + lag in - Lwt_list.map_s - (fun signer -> - let* (`OpHash h) = - dal_attestation ~force:true ~nb_slots ~level ~signer [10] client - in - return h) - [bootstrap1; bootstrap2; bootstrap3; bootstrap4; bootstrap5] + let* hashes = dal_attestations ~force:true ~nb_slots ~level [10] client in + return @@ List.map (fun (`OpHash h) -> h) hashes in let applied = [] in let branch_delayed = attestation_ops in @@ -1341,21 +1348,7 @@ let rollup_node_stores_dal_slots ?expand_test _protocol dal_node sc_rollup_node (* 6. attest only slots 1 and 2. *) let* parameters = Rollup.Dal.Parameters.from_client client in let nb_slots = parameters.number_of_slots in - let* _op_hash = - dal_attestation ~nb_slots ~signer:Constant.bootstrap1 [2; 1] client - in - let* _op_hash = - dal_attestation ~nb_slots ~signer:Constant.bootstrap2 [2; 1] client - in - let* _op_hash = - dal_attestation ~nb_slots ~signer:Constant.bootstrap3 [2; 1] client - in - let* _op_hash = - dal_attestation ~nb_slots ~signer:Constant.bootstrap4 [2; 1] client - in - let* _op_hash = - dal_attestation ~nb_slots ~signer:Constant.bootstrap5 [2; 1] client - in + let* _ops_hashes = dal_attestations ~nb_slots [2; 1] client in let* () = Client.bake_for_and_wait client in let* slot_confirmed_level = Sc_rollup_node.wait_for_level sc_rollup_node (slots_published_level + 1) -- GitLab From 5c63c1e0fda9e15365ac458c37aa890d1315423d Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Fri, 16 Dec 2022 12:00:06 +0100 Subject: [PATCH 7/9] Tezt/Dal: refactor test_dal_node_slots_headers_tracking --- tezt/tests/dal.ml | 57 +++++++++++++++++++---------------------------- 1 file changed, 23 insertions(+), 34 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 1c797d83d4ad..9f3a8cf99af0 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -896,7 +896,7 @@ let publish_and_store_slot ?(fee = 1_200) node client dal_node source index let* _ = publish_slot ~source ~fee ~index ~commitment ~proof node client in return (index, slot_commitment) -let check_get_commitment ~check_result dal_node ~slot_level slots_info = +let check_get_commitment dal_node ~slot_level check_result slots_info = Lwt_list.iter_s (fun (slot_index, commitment') -> let* response = @@ -904,10 +904,21 @@ let check_get_commitment ~check_result dal_node ~slot_level slots_info = dal_node (Rollup.Dal.RPC.get_level_index_commitment ~slot_index ~slot_level) in - check_result commitment' response ; - unit) + return @@ check_result commitment' response) slots_info +let get_commitment_succeeds commitment' response = + let commitment = + JSON.(parse ~origin:__LOC__ response.RPC_core.body |> as_string) + in + Check.(commitment' = commitment) + Check.string + ~error_msg: + "The value of a stored commitment should match the one computed locally \ + (current = %L, expected = %R)" + +let get_commitment_not_found _commit r = RPC.check_string_response ~code:404 r + let test_dal_node_slots_headers_tracking _protocol _parameters _cryptobox node client dal_node = let publish ?fee = publish_and_store_slot ?fee node client dal_node in @@ -937,45 +948,23 @@ let test_dal_node_slots_headers_tracking _protocol _parameters _cryptobox node "Published header is different from stored header (current = %L, \ expected = %R)" ; let slot_level = Node.get_level node in + let check_get_commitment = check_get_commitment dal_node ~slot_level in let ok = [slot0; slot1; slot2_b] in ignore slot2_a ; let ko = slot3 :: List.map (fun (i, c) -> (i + 100, c)) ok in - (* Aux function to check succesful RPC calls. *) - let result_ok commitment' response = - let commitment = - JSON.( - parse - ~origin:"test_dal_node_slots_headers_tracking" - response.RPC_core.body - |> as_string) - in - Check.(commitment' = commitment) - Check.string - ~error_msg: - "The value of a stored commitment should match the one computed \ - locally (current = %L, expected = %R)" - in - (* Aux function to check RPC calls that are expected to fail with 404. *) - let result_ko _commitment' response = - RPC.check_string_response ~code:404 response - in + (* Slots waiting for confirmation. *) - let* () = - check_get_commitment ~check_result:result_ok dal_node ~slot_level ok - in + let* () = check_get_commitment get_commitment_succeeds ok in + (* Slots not selected/accepted. *) - let* () = - check_get_commitment ~check_result:result_ko dal_node ~slot_level ko - in + let* () = check_get_commitment get_commitment_not_found ko in + let* () = Client.bake_for_and_wait client in + (* Slot confirmed. *) - let* () = - check_get_commitment ~check_result:result_ok dal_node ~slot_level ok - in + let* () = check_get_commitment get_commitment_succeeds ok in (* Slots still not selected/accepted. *) - let* () = - check_get_commitment ~check_result:result_ko dal_node ~slot_level ko - in + let* () = check_get_commitment get_commitment_not_found ko in unit let generate_dummy_slot slot_size = -- GitLab From 68df08333d674d888bea71299b5d955e5b3a20af Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Fri, 16 Dec 2022 13:59:23 +0100 Subject: [PATCH 8/9] Tezt/DAL: two auxiliary functions to test get_commitment_headers RPC --- tezt/tests/dal.ml | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index 9f3a8cf99af0..b59c449e6a72 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -919,6 +919,37 @@ let get_commitment_succeeds commitment' response = let get_commitment_not_found _commit r = RPC.check_string_response ~code:404 r +let check_get_commitment_headers dal_node ~slot_level check_result slots_info = + let test check_result ~query_string (slot_index, commit) = + let slot_level, slot_index = + if not query_string then (None, None) + else (Some slot_level, Some slot_index) + in + let* response = + RPC.call_raw + dal_node + (Rollup.Dal.RPC.get_commitment_headers ?slot_index ?slot_level commit) + in + return @@ check_result response + in + let* () = Lwt_list.iter_s (test check_result ~query_string:true) slots_info in + Lwt_list.iter_s (test check_result ~query_string:false) slots_info + +let get_headers_succeeds status response = + let headers = + JSON.( + parse ~origin:"get_headers_succeeds" response.RPC_core.body + |> Rollup.Dal.RPC.slot_headers_of_json) + in + List.iter + (fun header -> + Check.(header.Rollup.Dal.RPC.status = status) + Check.string + ~error_msg: + "The value of the fetched status should match the expected \ + one(current = %L, expected = %R)") + headers + let test_dal_node_slots_headers_tracking _protocol _parameters _cryptobox node client dal_node = let publish ?fee = publish_and_store_slot ?fee node client dal_node in -- GitLab From f1d04f60fef5c80f9981ef9c3e582938aba51050 Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Fri, 16 Dec 2022 14:06:21 +0100 Subject: [PATCH 9/9] Tezt/DAL: add tests for RPC GET /commitments//headers --- tezt/tests/dal.ml | 60 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index b59c449e6a72..50945fb42793 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -907,11 +907,11 @@ let check_get_commitment dal_node ~slot_level check_result slots_info = return @@ check_result commitment' response) slots_info -let get_commitment_succeeds commitment' response = +let get_commitment_succeeds expected_commitment response = let commitment = JSON.(parse ~origin:__LOC__ response.RPC_core.body |> as_string) in - Check.(commitment' = commitment) + Check.(commitment = expected_commitment) Check.string ~error_msg: "The value of a stored commitment should match the one computed locally \ @@ -935,7 +935,7 @@ let check_get_commitment_headers dal_node ~slot_level check_result slots_info = let* () = Lwt_list.iter_s (test check_result ~query_string:true) slots_info in Lwt_list.iter_s (test check_result ~query_string:false) slots_info -let get_headers_succeeds status response = +let get_headers_succeeds expected_status response = let headers = JSON.( parse ~origin:"get_headers_succeeds" response.RPC_core.body @@ -943,14 +943,14 @@ let get_headers_succeeds status response = in List.iter (fun header -> - Check.(header.Rollup.Dal.RPC.status = status) + Check.(header.Rollup.Dal.RPC.status = expected_status) Check.string ~error_msg: "The value of the fetched status should match the expected \ one(current = %L, expected = %R)") headers -let test_dal_node_slots_headers_tracking _protocol _parameters _cryptobox node +let test_dal_node_slots_headers_tracking _protocol parameters _cryptobox node client dal_node = let publish ?fee = publish_and_store_slot ?fee node client dal_node in let* slot0 = publish Constant.bootstrap1 0 "test0" in @@ -979,23 +979,63 @@ let test_dal_node_slots_headers_tracking _protocol _parameters _cryptobox node "Published header is different from stored header (current = %L, \ expected = %R)" ; let slot_level = Node.get_level node in + let check_get_commitment_headers = + check_get_commitment_headers dal_node ~slot_level + in let check_get_commitment = check_get_commitment dal_node ~slot_level in let ok = [slot0; slot1; slot2_b] in - ignore slot2_a ; + let attested = [slot0; slot2_b] in + let unattested = [slot1] in let ko = slot3 :: List.map (fun (i, c) -> (i + 100, c)) ok in - (* Slots waiting for confirmation. *) + (* Slots waiting for attestation. *) let* () = check_get_commitment get_commitment_succeeds ok in - - (* Slots not selected/accepted. *) + let* () = + check_get_commitment_headers + (get_headers_succeeds "waiting_for_attestations") + ok + in + (* slot_2_a is not selected. *) + let* () = + check_get_commitment_headers (get_headers_succeeds "not_selected") [slot2_a] + in + (* Slots not published or not included in blocks. *) let* () = check_get_commitment get_commitment_not_found ko in + (* Attest slots slot0 = (2, 0) and slot2_b = (2,4), bake and wait + two seconds so that the DAL node updates its state. *) + let nb_slots = parameters.Rollup.Dal.Parameters.number_of_slots in + let* _op_hash = dal_attestations ~nb_slots (List.map fst attested) client in let* () = Client.bake_for_and_wait client in + let* () = Lwt_unix.sleep 2.0 in (* Slot confirmed. *) let* () = check_get_commitment get_commitment_succeeds ok in - (* Slots still not selected/accepted. *) + (* Slot that were waiting for attestation and now attested. *) + let* () = + check_get_commitment_headers (get_headers_succeeds "attested") attested + in + (* Slots not published or not included in blocks. *) let* () = check_get_commitment get_commitment_not_found ko in + (* Slot that were waiting for attestation and now unattested. *) + let* () = + check_get_commitment_headers (get_headers_succeeds "unattested") unattested + in + (* slot_2_a is still not selected. *) + let* () = + check_get_commitment_headers (get_headers_succeeds "not_selected") [slot2_a] + in + (* slot_3 never finished in an L1 block, so the DAL node never tracked it + (except when its content has been injected). *) + let* () = + check_get_commitment_headers + (fun response -> + Check.( + (String.trim response.RPC_core.body = "[]") + string + ~error_msg:"Slot3 is not expected to be indexed by DAL node")) + [slot3] + in unit let generate_dummy_slot slot_size = -- GitLab