diff --git a/src/kernel_dal_echo/kernel/src/lib.rs b/src/kernel_dal_echo/kernel/src/lib.rs index 7efaee46e297ae14e4527e142c5bbb5ebbcbd70f..f1086996ed2c099419cebcaeb389193c4cdd6e31 100644 --- a/src/kernel_dal_echo/kernel/src/lib.rs +++ b/src/kernel_dal_echo/kernel/src/lib.rs @@ -99,16 +99,20 @@ pub fn entry(host: &mut impl Runtime) { match host.read_input() { Ok(Some(message)) => { let level = message.level; - let published_level = (level as i32) - (attestation_lag as i32); - let num_pages = (slot_size / page_size) as usize; - for slot_index in slot_indexes { - process_slot( - host, - published_level, - num_pages, - page_size as usize, - slot_index, - ); + // Before importing a slot, we wait 2 blocks for finality + 1 block for DAL node processing + let import_extra_delay = 3; + let published_level = (level as i32) - (attestation_lag as i32) - import_extra_delay; + if published_level > 0 { + let num_pages = (slot_size / page_size) as usize; + for slot_index in slot_indexes { + process_slot( + host, + published_level, + num_pages, + page_size as usize, + slot_index, + ); + } } } Ok(None) => { diff --git a/src/kernel_tx_demo/kernel/src/lib.rs b/src/kernel_tx_demo/kernel/src/lib.rs index 76ac692f30680fef152bc020edf2b928159486fa..35a370356ecce7d5fee7f7996d731345a9127870 100644 --- a/src/kernel_tx_demo/kernel/src/lib.rs +++ b/src/kernel_tx_demo/kernel/src/lib.rs @@ -211,7 +211,9 @@ fn filter_inbox_message<'a, Host: Runtime>( let slot_size = 32768; let page_size = 128; let num_pages = slot_size / page_size; - let published_level = (_inbox_level - attestation_lag) as i32; + // Before importing a slot, we wait 2 blocks for finality + 1 block for DAL node processing + let import_extra_delay = 3; + let published_level = (_inbox_level - attestation_lag - import_extra_delay) as i32; // TODO: https://gitlab.com/tezos/tezos/-/issues/6400 // Make it possible to track multiple slot indexes. let slot_index = storage::dal::get_or_set_slot_index(host, 0 as u8)?; diff --git a/src/lib_dal_node/dal_node_client.ml b/src/lib_dal_node/dal_node_client.ml index dc8fd5100a58f7e155f39547ce0f67c117a28f66..2ba1a8dff8e018ba4fabdd5b72efa637d8187eab 100644 --- a/src/lib_dal_node/dal_node_client.ml +++ b/src/lib_dal_node/dal_node_client.ml @@ -81,3 +81,11 @@ let post_slot cctxt ?slot_index slot = () query slot [@profiler.aggregate_s {verbosity = Notice} "post_slot"]) + +let get_slot_status cctxt (slot_id : Types.slot_id) = + call + cctxt + Services.get_slot_status + (((), slot_id.slot_level), slot_id.slot_index) + () + () diff --git a/src/lib_dal_node/dal_node_client.mli b/src/lib_dal_node/dal_node_client.mli index 813ae1c8cf876b3b43a7607a8ae812aadefcc65d..39c4a3cbff7e6ba599389c101100a222f22c6b34 100644 --- a/src/lib_dal_node/dal_node_client.mli +++ b/src/lib_dal_node/dal_node_client.mli @@ -59,3 +59,10 @@ val post_slot : ?slot_index:Tezos_dal_node_services.Types.slot_index -> string -> (Cryptobox.commitment * Cryptobox.commitment_proof) tzresult Lwt.t + +(** [get_slot_status cctxt slot_id] returns the attestation + info (status and lag) of the slot whose id is given. *) +val get_slot_status : + cctxt -> + Tezos_dal_node_services.Types.slot_id -> + Tezos_dal_node_services.Types.header_status tzresult Lwt.t diff --git a/src/lib_dal_node/store.ml b/src/lib_dal_node/store.ml index 416504cf6bbc45ce93d5663c9daea8fd719aabe6..adcb2996fb73eecf1901126e3fa5c1f671efec89 100644 --- a/src/lib_dal_node/store.ml +++ b/src/lib_dal_node/store.ml @@ -28,13 +28,7 @@ module Profiler = (val Profiler.wrap Dal_profiler.dal_profiler) (** FIFO-keyed map with slot_id as keys. *) module Slot_map = Aches.Vache.Map (Aches.Vache.FIFO_Precise) (Aches.Vache.Strong) - (struct - type t = Types.Slot_id.t - - let equal = Types.Slot_id.equal - - let hash = Types.Slot_id.hash - end) + (Types.Slot_id) module Version = struct type t = int diff --git a/src/proto_alpha/lib_protocol/sc_rollup_arith.ml b/src/proto_alpha/lib_protocol/sc_rollup_arith.ml index dd654b2eeee0ef31a21c183ad5f49ed3e79f6918..cd74a5390e2871bf8c39db2843d817218c02afe4 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_arith.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_arith.ml @@ -1200,8 +1200,14 @@ module Make (Context : Sc_rollup_PVM_sig.Generic_pvm_context_sig) : let inbox_level = Raw_level_repr.to_int32 inbox_level in (* the [published_level]'s pages to request is [inbox_level - attestation_lag - 1]. *) + (* Before importing a slot, we wait 2 blocks for finality + 1 block + for DAL node processing, + 1 block because PVM arith requests DAL + slots at start of level internal message. *) + let import_extra_delay = 4l in let lvl = - Int32.sub (Int32.sub inbox_level dal_params.attestation_lag) 1l + Int32.sub + (Int32.sub inbox_level dal_params.attestation_lag) + import_extra_delay in match Raw_level_repr.of_int32 lvl with | Error _ -> diff --git a/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.ml b/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.ml index 20baa611e01a64862a0d09119dd72e5ad436efb3..888a1298e2d34b9afdf23d8a2698947653638efc 100644 --- a/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.ml +++ b/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.ml @@ -25,6 +25,7 @@ open Protocol open Alpha_context +module Slot_id = Tezos_dal_node_services.Types.Slot_id (** If a slot, published at some level L, is expected to be confirmed at level L+D then, once the confirmation level is over, the rollup node is supposed to: @@ -33,7 +34,13 @@ open Alpha_context - Add entries [None] for the slot's pages in the store, if the slot is not confirmed. *) -type Environment.Error_monad.error += Dal_invalid_page_for_slot of Dal.Page.t +type Environment.Error_monad.error += + | No_dal_node_provided + | Dal_invalid_page_for_slot of Dal.Page.t + | Dal_attestation_status_not_final of { + published_level : int32; + slot_index : int; + } let () = let open Environment.Error_monad in @@ -48,6 +55,48 @@ let () = (function Dal_invalid_page_for_slot page_id -> Some page_id | _ -> None) (fun page_id -> Dal_invalid_page_for_slot page_id) +let () = + let open Environment.Error_monad in + register_error_kind + `Temporary + ~id:"dal_pages_request.attestation_status_not_final" + ~title:"DAL attestation status is not final" + ~description: + "The DAL attestation status for the requested slot is not final yet. We \ + cannot decide whether it is legitimate for the rollup node to import \ + it." + ~pp:(fun ppf (published_level, slot_index) -> + Format.fprintf + ppf + "DAL attestation status not final for slot %d published at level %ld. \ + We cannot decide yet if it is legitimate for the rollup node to \ + import it." + slot_index + published_level) + Data_encoding.( + obj2 + (req "published_level" Data_encoding.int32) + (req "slot_index" Data_encoding.uint8)) + (function + | Dal_attestation_status_not_final {published_level; slot_index} -> + Some (published_level, slot_index) + | _ -> None) + (fun (published_level, slot_index) -> + Dal_attestation_status_not_final {published_level; slot_index}) + +let () = + let open Environment.Error_monad in + register_error_kind + `Permanent + ~id:"dal_pages_request.no_dal_node_provided" + ~title:"No DAL node provided" + ~description:"No DAL node was provided" + ~pp:(fun ppf () -> + Format.fprintf ppf "No DAL node provided to fetch slot pages.") + Data_encoding.unit + (function No_dal_node_provided -> Some () | _ -> None) + (fun () -> No_dal_node_provided) + module Event = struct include Internal_event.Simple @@ -81,136 +130,71 @@ module Event = struct ("inbox_level", Data_encoding.int32) ("content", Data_encoding.bytes) ~pp5:pp_content_elipsis -end - -module Slot_id = struct - include Tezos_dal_node_services.Types.Slot_id - - let equal id1 id2 = Comparable.compare id1 id2 = 0 - let hash id = Hashtbl.hash id + let pages_reveal_failed = + declare_4 + ~section + ~name:"dal_pages_reveal_failed" + ~msg: + "Fetching pages at inbox level {inbox_level} of slot index \ + {slot_index} published at level {published_level} failed with {error}" + ~level:Error + ("inbox_level", Data_encoding.int32) + ("slot_index", Data_encoding.int31) + ("published_level", Data_encoding.int32) + ~pp4:Error_monad.pp_print_trace + ("error", Error_monad.trace_encoding) end -(* The cache allows to not fetch pages on the DAL node more than necessary. *) -module Pages_cache = - Aches_lwt.Lache.Make (Aches.Rache.Transfer (Aches.Rache.LRU) (Slot_id)) - -let get_slot_pages = - let pages_cache = - Pages_cache.create 16 - (* 130MB *) - in - fun dal_cctxt slot_id -> - Pages_cache.bind_or_put - pages_cache - slot_id - (Dal_node_client.get_slot_pages dal_cctxt) - Lwt.return - -let download_confirmed_slot_pages {Node_context.dal_cctxt; _} ~published_level - ~index = - let dal_cctxt = WithExceptions.Option.get ~loc:__LOC__ dal_cctxt in - (* DAL must be configured for this point to be reached *) - get_slot_pages - dal_cctxt - {slot_level = Raw_level.to_int32 published_level; slot_index = index} - -module Slots_statuses_cache = - Aches.Vache.Map (Aches.Vache.FIFO_Precise) (Aches.Vache.Strong) - (struct - type t = Dal.Slot.Header.id - - let equal = Dal.Slot.Header.slot_id_equal - - let hash id = Hashtbl.hash id - end) - -let download_skip_list_cells_of_level node_ctxt ~attested_level = - Plugin.RPC.Dal.skip_list_cells_of_level - (new Protocol_client_context.wrap_full node_ctxt.Node_context.cctxt) - (`Main, `Level attested_level) - () - -(* We have currently 32 slots per level. We retain the information for 32 levels - (assuming no reorgs with different payload occur). *) -let skip_list_cells_content_cache = - (* Attestation lag * number of slots * 32 retention levels, assuming no - reorgs. *) - let attestation_lag = 8 in - let number_of_slots = 32 in - let retention_levels = 32 in - Slots_statuses_cache.create - (attestation_lag * number_of_slots * retention_levels) +module Slot_id_cache = + Aches.Vache.Map (Aches.Vache.FIFO_Precise) (Aches.Vache.Strong) (Slot_id) -let dal_skip_list_cell_content_of_slot_id node_ctxt - (dal_constants : Octez_smart_rollup.Rollup_constants.dal_constants) slot_id - = +let download_confirmed_slot_pages = let open Lwt_result_syntax in - let attested_level = - Int32.add - (Raw_level.to_int32 slot_id.Dal.Slot.Header.published_level) - (Int32.of_int dal_constants.attestation_lag) - in - let* attested_level_hash = - Node_context.hash_of_level node_ctxt attested_level - in - match Slots_statuses_cache.find_opt skip_list_cells_content_cache slot_id with - | Some (cell_content, block_hash) - when Block_hash.equal attested_level_hash block_hash -> - return cell_content - | None | Some _ -> ( - let* hash_with_cells = - download_skip_list_cells_of_level node_ctxt ~attested_level - in - List.iter - (fun (_hash, cell) -> - let content = Dal.Slots_history.content cell in - Slots_statuses_cache.replace - skip_list_cells_content_cache - (Dal.Slots_history.content_id content).header_id - (content, attested_level_hash)) - hash_with_cells ; - (* The [find] below validates the fact that we fetched the info of - commitments published at level [slot_id.published_level]. *) - match - Slots_statuses_cache.find_opt skip_list_cells_content_cache slot_id - with - | Some (cell_content, block_hash) - when Block_hash.equal attested_level_hash block_hash -> - return cell_content - | None -> - Stdlib.failwith - (Format.asprintf - "Unreachable: We expect to find some data for slot %a, but got \ - none" - Dal.Slot.Header.pp_id - slot_id) - | Some (_, got_hash) -> - Stdlib.failwith - (Format.asprintf - "Unreachable: We expect to find some data for slot %a \ - associated to block hash %a, but got data associated to block \ - hash %a" - Dal.Slot.Header.pp_id - slot_id - Block_hash.pp_short - attested_level_hash - Block_hash.pp_short - got_hash)) + (* The size below was chosen arbitrarily, but it should be sufficient for + Etherlink, given that slots are pulled and processed in some order and only + once. In general a kernel may request data it previously processed during + normal operation (i.e., not for refutation games). This size can then be + adapted as needed. *) + let cache = Slot_id_cache.create 16 in + fun dal_cctxt ~published_level ~index -> + let slot_id = + Slot_id. + {slot_level = Raw_level.to_int32 published_level; slot_index = index} + in + match Slot_id_cache.find_opt cache slot_id with + | Some pages -> return pages + | None -> + let+ res = Dal_node_client.get_slot_pages dal_cctxt slot_id in + Slot_id_cache.replace cache slot_id res ; + res -let slot_attestation_status ?attestation_threshold_percent - ?restricted_commitments_publishers node_ctxt dal_constants slot_id = +(* Adaptive DAL is not supported anymore *) +let get_slot_header_attestation_info = let open Lwt_result_syntax in - let* cell_content = - dal_skip_list_cell_content_of_slot_id node_ctxt dal_constants slot_id - in - let commitment_res = - Dal.Slots_history.is_commitment_attested - ~attestation_threshold_percent - ~restricted_commitments_publishers - cell_content - in - return @@ if Option.is_some commitment_res then `Attested else `Unattested + (* The size was chosen arbitrarily, but it should be sufficient for Etherlink, + given that slots statuses are pulled and processed in some order and only + once. In general a kernel may request data it previously processed during + normal operation (i.e., not for refutation games). This size can then be + adapted as needed. *) + let cache = Slot_id_cache.create 16 in + fun dal_cctxt ~published_level ~index -> + let slot_id = + Slot_id. + { + slot_level = Raw_level.to_int32 published_level; + slot_index = Dal.Slot_index.to_int index; + } + in + match Slot_id_cache.find_opt cache slot_id with + | Some pages -> return pages + | None -> + let+ res = Dal_node_client.get_slot_status dal_cctxt slot_id in + (match res with + | `Attested _ | `Unattested | `Unpublished -> + Slot_id_cache.replace cache slot_id res + | `Waiting_attestation -> ()) ; + res let get_page node_ctxt ~inbox_level page_id = let open Environment.Error_monad.Lwt_result_syntax in @@ -236,8 +220,7 @@ let get_page node_ctxt ~inbox_level page_id = in Lwt.return @@ Environment.wrap_tzresult res -let slot_id_is_valid chain_id - (dal_constants : Octez_smart_rollup.Rollup_constants.dal_constants) +let slot_id_is_valid chain_id ~dal_attestation_lag ~number_of_slots ~dal_activation_level ~origination_level ~inbox_level slot_id ~dal_attested_slots_validity_lag = let open Alpha_context in @@ -253,9 +236,7 @@ let slot_id_is_valid chain_id else dal_activation_level in Result.is_ok - (Dal.Slot_index.check_is_in_range - ~number_of_slots:dal_constants.number_of_slots - slot_id.Dal.index) + (Dal.Slot_index.check_is_in_range ~number_of_slots slot_id.Dal.index) && let origination_level_res = Raw_level.of_int32 origination_level in let commit_inbox_level_res = Raw_level.of_int32 inbox_level in @@ -263,32 +244,48 @@ let slot_id_is_valid chain_id | Ok origination_level, Ok commit_inbox_level -> Alpha_context.Sc_rollup.Proof.Dal_helpers.import_level_is_valid ~dal_activation_level - ~dal_attestation_lag:dal_constants.attestation_lag + ~dal_attestation_lag ~origination_level ~commit_inbox_level ~dal_attested_slots_validity_lag ~published_level:slot_id.published_level | _ -> false -let page_id_is_valid chain_id - (dal_constants : Octez_smart_rollup.Rollup_constants.dal_constants) - ~dal_activation_level ~origination_level ~inbox_level +let page_id_is_valid chain_id ~dal_attestation_lag ~number_of_slots + ~number_of_pages ~dal_activation_level ~origination_level ~inbox_level Dal.Page.{slot_id; page_index} ~dal_attested_slots_validity_lag = - Result.is_ok - (Dal.Page.Index.check_is_in_range - ~number_of_pages: - (Dal.Page.pages_per_slot dal_constants.cryptobox_parameters) - page_index) + Result.is_ok (Dal.Page.Index.check_is_in_range ~number_of_pages page_index) && slot_id_is_valid chain_id - dal_constants + ~dal_attestation_lag + ~number_of_slots ~dal_activation_level ~origination_level ~inbox_level slot_id ~dal_attested_slots_validity_lag -let slot_pages +let attestation_status_not_final published_level slot_index = + let open Environment.Error_monad.Lwt_result_syntax in + let*! res = + tzfail + @@ Dal_attestation_status_not_final + { + published_level = Raw_level.to_int32 published_level; + slot_index = Sc_rollup_proto_types.Dal.Slot_index.to_octez slot_index; + } + in + Environment.wrap_tzresult res |> Lwt.return + +let get_dal_node cctxt_opt = + let open Environment.Error_monad.Lwt_result_syntax in + match cctxt_opt with + | Some res -> return res + | None -> + let*! err = tzfail No_dal_node_provided in + Environment.wrap_tzresult err |> Lwt.return + +let slot_pages_int (dal_constants : Octez_smart_rollup.Rollup_constants.dal_constants) ~dal_activation_level ~inbox_level node_ctxt slot_id ~dal_attested_slots_validity_lag = @@ -297,59 +294,105 @@ let slot_pages node_ctxt in let* chain_id = Layer1.get_chain_id l1_ctxt in + let* dal_cctxt = get_dal_node node_ctxt.dal_cctxt in let Dal.Slot.Header.{published_level; index} = slot_id in - if - not - @@ slot_id_is_valid - chain_id - dal_constants - ~dal_activation_level - ~origination_level - ~inbox_level - ~dal_attested_slots_validity_lag - slot_id - then return_none - else - let* status = slot_attestation_status node_ctxt dal_constants slot_id in - match status with - | `Attested -> + let* status = + get_slot_header_attestation_info dal_cctxt ~published_level ~index + in + match status with + | `Attested attestation_lag -> + if + not + @@ slot_id_is_valid + chain_id + ~dal_attestation_lag:attestation_lag + ~number_of_slots:dal_constants.number_of_slots + ~dal_activation_level + ~origination_level + ~inbox_level + ~dal_attested_slots_validity_lag + slot_id + then return_none + else let index = Sc_rollup_proto_types.Dal.Slot_index.to_octez index in let* pages = - download_confirmed_slot_pages node_ctxt ~published_level ~index + download_confirmed_slot_pages dal_cctxt ~published_level ~index in return (Some pages) - | `Unattested -> return_none + | `Unattested | `Unpublished -> return_none + | `Waiting_attestation -> attestation_status_not_final published_level index -let page_content +let page_content_int (dal_constants : Octez_smart_rollup.Rollup_constants.dal_constants) - ~dal_activation_level ~inbox_level node_ctxt ~attestation_threshold_percent - ~restricted_commitments_publishers page_id ~dal_attested_slots_validity_lag - = + ~dal_activation_level ~inbox_level node_ctxt page_id + ~dal_attested_slots_validity_lag = let open Lwt_result_syntax in let Node_context.{genesis_info = {level = origination_level; _}; l1_ctxt; _} = node_ctxt in let* chain_id = Layer1.get_chain_id l1_ctxt in - if - not - @@ page_id_is_valid - chain_id - dal_constants - ~dal_activation_level - ~origination_level - ~inbox_level - ~dal_attested_slots_validity_lag - page_id - then return_none - else - let* status = - slot_attestation_status - ?attestation_threshold_percent - ?restricted_commitments_publishers - node_ctxt - dal_constants - page_id.Dal.Page.slot_id - in - match status with - | `Attested -> get_page node_ctxt ~inbox_level page_id - | `Unattested -> return_none + let* dal_cctxt = get_dal_node node_ctxt.dal_cctxt in + let Dal.Slot.Header.{published_level; index} = page_id.Dal.Page.slot_id in + let* status = + get_slot_header_attestation_info dal_cctxt ~published_level ~index + in + match status with + | `Attested attestation_lag -> + if + not + @@ page_id_is_valid + chain_id + ~dal_attestation_lag:attestation_lag + ~number_of_slots:dal_constants.number_of_slots + ~number_of_pages: + (Dal.Page.pages_per_slot dal_constants.cryptobox_parameters) + ~dal_activation_level + ~origination_level + ~inbox_level + ~dal_attested_slots_validity_lag + page_id + then return_none + else get_page dal_cctxt ~inbox_level page_id + | `Unattested | `Unpublished -> return_none + | `Waiting_attestation -> attestation_status_not_final published_level index + +let with_errors_logging ~inbox_level slot_id f = + let open Lwt_syntax in + let* res = f in + let+ () = + match res with + | Ok _ -> return_unit + | Error err -> + Event.(emit pages_reveal_failed) + ( inbox_level, + Dal.(Slot_index.to_int slot_id.index), + Raw_level.to_int32 slot_id.published_level, + err ) + in + res + +let page_content + (dal_constants : Octez_smart_rollup.Rollup_constants.dal_constants) + ~dal_activation_level ~inbox_level node_ctxt page_id + ~dal_attested_slots_validity_lag = + with_errors_logging ~inbox_level page_id.Dal.Page.slot_id + @@ page_content_int + dal_constants + ~dal_activation_level + ~inbox_level + node_ctxt + page_id + ~dal_attested_slots_validity_lag + +let slot_pages + (dal_constants : Octez_smart_rollup.Rollup_constants.dal_constants) + ~dal_activation_level ~inbox_level node_ctxt slot_id + ~dal_attested_slots_validity_lag = + with_errors_logging ~inbox_level slot_id + @@ slot_pages_int + dal_constants + ~dal_activation_level + ~inbox_level + node_ctxt + slot_id + ~dal_attested_slots_validity_lag diff --git a/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.mli b/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.mli index f52b2cc3b987716d193d0d5ac93b49660f4ba784..18b1b9abd5efea4ab23f3d66dd3170e45e93a501 100644 --- a/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.mli +++ b/src/proto_alpha/lib_sc_rollup_node/dal_pages_request.mli @@ -30,29 +30,30 @@ open Alpha_context Rework the interface of dal_pages_request.mli (see the issue for details). *) -(** Access DAL slots and pages content. - - This module is a wrapper on top of {!Store.Dal_slot_pages} module to - access DAL slots and pages' data that have been previously fetched by - the rollup node. -*) - -(** Retrieve the pages' content of the given slot ID's from the store. - - The function returns [Dal_slot_not_found_in_store] if no entry is found in - the store for the given ID (i.e. no page is registered with or without content). - - If the returned value is [Some pages], the slot whose ID is given is - supposed to be confirmed and [pages] correspond to the pages of the slot. - Otherwise [None] is returned. - - The function relies on {!Store.Dal_slot_pages}'s invariants to guarantee that: - - the pages are returned in increasing order w.r.t. their indexes in the slot; - - the size of the list, in case it is not empty, is equal to the expected - number of pages in a slot. - - [dal_attestation_lag] is used to retrieve the correct entry in [store]. -*) +(** Access DAL slots and page contents. + + This module exposes helpers to retrieve DAL slot/page data for a rollup, + validating import conditions against the DAL attestation lag and the + rollup's context. It queries a DAL node to obtain the slot status and, when + appropriate, to download page contents. *) + +(** Retrieve the pages of the given slot. + + The function queries the DAL node for the slot's attestation status: + - If the slot is [Attested lag], the function checks that importing the slot + at [inbox_level] is valid given: + - the DAL activation level, + - the rollup origination level, + - the attested slots validity lag, and + - index bounds (number of slots). + If valid, it downloads and returns [Some pages]; otherwise returns [None]. + - If the slot is [Unattested] or [Unpublished], returns [None]. + - If the status is [Waiting_attestation], the function returns an error + ([Dal_attestation_status_not_final]). + + The returned pages, when present, satisfy: + - pages are ordered by increasing page index within the slot, + - the list length equals the expected number of pages for the slot. *) val slot_pages : Octez_smart_rollup.Rollup_constants.dal_constants -> dal_activation_level:Raw_level.t option -> @@ -62,38 +63,14 @@ val slot_pages : dal_attested_slots_validity_lag:int -> Dal.Page.content list option tzresult Lwt.t -(** Retrieve the content of the page identified by the given ID from the store. - - This function checks the attestation status of the page's slot by inspecting - the skip list cells stored on L1 at the slot's attested level. A slot is - considered attested if either one of the following conditions is met: - - - The [is_proto_attested] field in the content of the cell is true, and - attestation_threshold_percent is None (default DAL behavior). - - - The attestation_threshold_percent is set to a specific threshold, the slot - meets or exceeds this threshold, and the publisher is authorized, provided a - whitelist is specified in [restricted_commitments_publishers]. - - If the slot of the page is attested, the data is retrieved from the DAL node - and returned. Otherwise, the function returns None. It also returns None if - the page_id or slot_id is invalid (or no longer valid). This includes cases - where: - - - Indices are out of range. - - - The rollup was originated after the slot's publication. +(** Retrieve the content of a single page. - - The slot is too old (i.e., its level is beyond - [dal_attested_slots_validity_lag]). -*) + Same as {!slot_pages}, but for a single page. *) val page_content : Octez_smart_rollup.Rollup_constants.dal_constants -> dal_activation_level:Raw_level.t option -> inbox_level:int32 -> _ Node_context.t -> - attestation_threshold_percent:int option -> - restricted_commitments_publishers:Contract.t list option -> Dal.Page.t -> dal_attested_slots_validity_lag:int -> Dal.Page.content option tzresult Lwt.t diff --git a/src/proto_alpha/lib_sc_rollup_node/fueled_pvm.ml b/src/proto_alpha/lib_sc_rollup_node/fueled_pvm.ml index 4ddc7d5713d1ad874263da9e49bb447de2b67c69..a972ac75826632f3ffdfbd7d73a1c792cdc50c2f 100644 --- a/src/proto_alpha/lib_sc_rollup_node/fueled_pvm.ml +++ b/src/proto_alpha/lib_sc_rollup_node/fueled_pvm.ml @@ -141,20 +141,10 @@ module Make_fueled (F : Fuel.S) : FUELED_PVM with type fuel = F.t = struct Sc_rollup.Metadata.encoding metadata) | (Request_dal_page _ | Request_adal_page _) as xdal_request -> ( - let ( dal_page, - attestation_threshold_percent, - restricted_commitments_publishers ) = + let dal_page = match xdal_request with - | Request_dal_page dal_page -> (dal_page, None, None) - | Request_adal_page - { - page_id; - attestation_threshold_percent; - restricted_commitments_publishers; - } -> - ( page_id, - Some attestation_threshold_percent, - restricted_commitments_publishers ) + | Request_dal_page dal_page -> dal_page + | Request_adal_page _ -> Stdlib.failwith "Not_implemented" | _ -> (* This case is not reachable because we know that [xdal_request] is either [Request_dal_page] or [Request_adal_page] *) @@ -167,8 +157,6 @@ module Make_fueled (F : Fuel.S) : FUELED_PVM with type fuel = F.t = struct ~dal_attested_slots_validity_lag ~inbox_level:(Int32.of_int level) node_ctxt - ~attestation_threshold_percent - ~restricted_commitments_publishers dal_page in match content with @@ -308,20 +296,10 @@ module Make_fueled (F : Fuel.S) : FUELED_PVM with type fuel = F.t = struct go fuel (Int64.succ current_tick) failing_ticks state) | Needs_reveal ((Request_dal_page _ | Request_adal_page _) as xdal_request) -> ( - let ( page_id, - attestation_threshold_percent, - restricted_commitments_publishers ) = + let page_id = match xdal_request with - | Request_dal_page page_id -> (page_id, None, None) - | Request_adal_page - { - page_id; - attestation_threshold_percent; - restricted_commitments_publishers; - } -> - ( page_id, - Some attestation_threshold_percent, - restricted_commitments_publishers ) + | Request_dal_page page_id -> page_id + | Request_adal_page _ -> Stdlib.failwith "Not_implemented" | _ -> (* This case is not reachable because we know that [xdal_request] is either [Request_dal_page] or [Request_adal_page] *) @@ -337,8 +315,6 @@ module Make_fueled (F : Fuel.S) : FUELED_PVM with type fuel = F.t = struct ~dal_activation_level ~dal_attested_slots_validity_lag node_ctxt - ~attestation_threshold_percent - ~restricted_commitments_publishers page_id in let*! () = diff --git a/tezt/tests/dal.ml b/tezt/tests/dal.ml index f6bd83e73add0008f6eedfe82bcfa86232f39c3e..64f7a7627e8590ba04dd4ba28192e438460eafcc 100644 --- a/tezt/tests/dal.ml +++ b/tezt/tests/dal.ml @@ -2689,6 +2689,12 @@ let test_reveal_dal_page_in_fast_exec_wasm_pvm protocol parameters dal_node Check.((Some [|true|] = dal_attestation) (option (array bool))) ~error_msg:"Unexpected DAL attestations: expected %L, got %R" ; Log.info "Wait for the rollup node to catch up to the latest level." ; + + (* Before importing a slot, we wait 2 blocks for finality + 1 block for DAL + node processing *) + let* () = bake_for ~count:3 client in + let* _level = Sc_rollup_node.wait_sync ~timeout:10. sc_rollup_node in + let* _ = Sc_rollup_node.wait_for_level ~timeout:3. sc_rollup_node level in Log.info "Read and assert against value written in durable storage." ; let key = "/output/slot-0" in @@ -7999,6 +8005,12 @@ module Tx_kernel_e2e = struct ~attestation_lag:parameters.attestation_lag ~number_of_slots:parameters.number_of_slots in + (* Before importing a slot, we wait 2 blocks for finality + 1 block for DAL + node processing. *) + let* () = bake_for client in + let* () = bake_for client in + let* () = bake_for client in + Log.info "Wait for the rollup node to catch up." ; let* current_level = Node.get_level node in let* _level = @@ -8069,9 +8081,14 @@ module Tx_kernel_e2e = struct ~attestation_lag:parameters.attestation_lag ~number_of_slots:parameters.number_of_slots in - Log.info "Wait for the rollup node to catch up." ; + + (* Before importing a slot, we wait 2 blocks for finality + 1 block for DAL + node processing *) + let* () = repeat 3 (fun () -> bake_for client) in + let* _level = Sc_rollup_node.wait_sync ~timeout:10. sc_rollup_node in + Log.info "Wait for the rollup node to catch up at level %d." target_level ; let* _level = - Sc_rollup_node.wait_for_level ~timeout:30. sc_rollup_node target_level + Sc_rollup_node.wait_for_level ~timeout:60. sc_rollup_node target_level in let key = "/output/slot-0" in let* value_written =