diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 8b470d30c5cc4ef77ec23161776ce41bd9823c1b..6174e25f02c6e6a8b6649e4a1c3a034393dec351 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -3000,6 +3000,12 @@ module Dal : sig (Slot.Header.t * Contract.t * Attestation.attestation_status) list -> (t * History_cache.t) tzresult + val is_commitment_attested : + attestation_threshold_percent:int option -> + restricted_commitments_publishers:Contract.t list option -> + cell_content -> + Slot.Commitment.t option + type proof end diff --git a/src/proto_alpha/lib_protocol/dal_slot_repr.ml b/src/proto_alpha/lib_protocol/dal_slot_repr.ml index 004243b64b37b8e9b019786692f082f4258de0d4..7f7be599947e12713cd94b95b34bf01b91f23e7a 100644 --- a/src/proto_alpha/lib_protocol/dal_slot_repr.ml +++ b/src/proto_alpha/lib_protocol/dal_slot_repr.ml @@ -1120,6 +1120,44 @@ module History = struct page_size = Bytes.length data; } + let is_attestation_threshold_reached ~attestation_threshold_percent + ~attested_shards ~total_shards = + Compare.Int.( + 100 * attested_shards >= attestation_threshold_percent * total_shards) + + let allowed_commitments_publisher publisher + restricted_commitments_publishers = + match restricted_commitments_publishers with + | None -> true + | Some whitelist -> List.exists (Contract_repr.equal publisher) whitelist + + let is_commitment_attested ~attestation_threshold_percent + ~restricted_commitments_publishers cell_content = + let open Content_v2 in + match (cell_content, attestation_threshold_percent) with + | Unpublished _, _ -> None + | Published {header = {commitment; id = _}; is_proto_attested; _}, None -> + if is_proto_attested then Some commitment else None + | ( Published + { + header = {commitment; id = _}; + attested_shards; + total_shards; + publisher; + _; + }, + Some attestation_threshold_percent ) -> + if + is_attestation_threshold_reached + ~attestation_threshold_percent + ~attested_shards + ~total_shards + && allowed_commitments_publisher + publisher + restricted_commitments_publishers + then Some commitment + else None + (** The [produce_proof_repr] function assumes that some invariants hold, such as: - The DAL has been activated, - The level of [page_id] is after the DAL activation level. diff --git a/src/proto_alpha/lib_protocol/dal_slot_repr.mli b/src/proto_alpha/lib_protocol/dal_slot_repr.mli index 1ba5443571240e338ae3d5638e4a38a59c7e28b6..e0b6efb1ec944a26c184774962ff65c2d6e658c4 100644 --- a/src/proto_alpha/lib_protocol/dal_slot_repr.mli +++ b/src/proto_alpha/lib_protocol/dal_slot_repr.mli @@ -380,6 +380,20 @@ module History : sig print the serialized version of the proof (i.e. a sequence of bytes). *) val pp_proof : serialized:bool -> Format.formatter -> proof -> unit + (** This function returns some commitment if and only if the skip list cell + whose content is given is supposed to be attested. + + Attestation status is either checked by inspecting the protocol's boolean + flag stored in the content if [attestation_threshold_percent] is None + (Regular DAL), or by checking that attestation threshold is reached and + the publisher is whitelisted, if [restricted_commitments_publishers] is + set to some whitelist, when using Adjustable DAL. *) + val is_commitment_attested : + attestation_threshold_percent:int option -> + restricted_commitments_publishers:Contract_repr.t list option -> + cell_content -> + Commitment.t option + (** [produce_proof dal_parameters page_id page_info ~get_history slots_hist] produces a proof that either: - there exists a confirmed slot in the skip list that contains 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 75730f1cfd5d5feeed84f13da13f5c898ee4e819..98a289fee361625d23f9f4657add0908db061022 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 @@ -202,17 +202,19 @@ let dal_skip_list_cell_content_of_slot_id node_ctxt Block_hash.pp_short got_hash)) -let slot_proto_attestation_status node_ctxt dal_constants slot_id = +let slot_attestation_status ?attestation_threshold_percent + ?restricted_commitments_publishers node_ctxt dal_constants slot_id = let open Lwt_result_syntax in - let* res = + let* cell_content = dal_skip_list_cell_content_of_slot_id node_ctxt dal_constants slot_id in - match res with - | Dal.Slots_history.Unpublished _ - | Dal.Slots_history.Published {is_proto_attested = false; _} -> - return `Unattested - | Dal.Slots_history.Published {is_proto_attested = true; _} -> - return `Attested + let commitment_opt = + Dal.Slots_history.is_commitment_attested + ~attestation_threshold_percent + ~restricted_commitments_publishers + cell_content + in + return @@ if Option.is_some commitment_opt then `Attested else `Unattested let get_page node_ctxt ~inbox_level page_id = let open Lwt_result_syntax in @@ -295,9 +297,7 @@ let slot_pages slot_id then return_none else - let* status = - slot_proto_attestation_status node_ctxt dal_constants slot_id - in + let* status = slot_attestation_status node_ctxt dal_constants slot_id in match status with | `Attested -> let index = Sc_rollup_proto_types.Dal.Slot_index.to_octez index in @@ -309,8 +309,9 @@ let slot_pages 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 = + ~dal_activation_level ~inbox_level node_ctxt ~attestation_threshold_percent + ~restricted_commitments_publishers page_id ~dal_attested_slots_validity_lag + = let open Lwt_result_syntax in let Node_context.{genesis_info = {level = origination_level; _}; _} = node_ctxt @@ -327,7 +328,9 @@ let page_content then return_none else let* status = - slot_proto_attestation_status + slot_attestation_status + ?attestation_threshold_percent + ?restricted_commitments_publishers node_ctxt dal_constants page_id.Dal.Page.slot_id 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 254157d26e4def2b626108dc60ef9fdb60f6b42f..f52b2cc3b987716d193d0d5ac93b49660f4ba784 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 @@ -64,19 +64,36 @@ val slot_pages : (** Retrieve the content of the page identified by the given ID from the store. - The function returns [Dal_slot_not_found_in_store] if no entry is found in - the store for the given ID. It returns [None] in case the level of the - requested page is out of bounds (e.g. in the future). Said otherwise, - some content is only returned for confirmed pages (slots) for - which the content has already been downloaded and saved to 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: - [dal_attestation_lag] is used to retrieve the correct entry in [store]. + - 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. + + - The slot is too old (i.e., its level is beyond + [dal_attested_slots_validity_lag]). *) 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 e627cec3385e64c75919c71e1ebb04e6035c3c22..e5b28435bb4884c72ad56484052e59235bbe144f 100644 --- a/src/proto_alpha/lib_sc_rollup_node/fueled_pvm.ml +++ b/src/proto_alpha/lib_sc_rollup_node/fueled_pvm.ml @@ -140,7 +140,26 @@ module Make_fueled (F : Fuel.S) : FUELED_PVM with type fuel = F.t = struct (Data_encoding.Binary.to_string_exn Sc_rollup.Metadata.encoding metadata) - | Request_dal_page dal_page -> ( + | (Request_dal_page _ | Request_adal_page _) as xdal_request -> ( + let ( dal_page, + attestation_threshold_percent, + restricted_commitments_publishers ) = + 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 ) + | _ -> + (* This case is not reachable because we know that [xdal_request] + is either [Request_dal_page] or [Request_adal_page] *) + assert false + in let*! content = Dal_pages_request.page_content constants.dal @@ -148,6 +167,8 @@ 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 @@ -168,11 +189,6 @@ module Make_fueled (F : Fuel.S) : FUELED_PVM with type fuel = F.t = struct (Data_encoding.Binary.to_string_exn Sc_rollup.Dal_parameters.encoding dal_parameters) - | Request_adal_page _ -> - (* ADAL/FIXME: https://gitlab.com/tezos/tezos/-/milestones/410 - - To be implemented. *) - assert false in let eval_tick_consume_fuel fuel failing_ticks state = @@ -279,7 +295,27 @@ module Make_fueled (F : Fuel.S) : FUELED_PVM with type fuel = F.t = struct PVM_mut_state.set_input (Reveal (Metadata metadata)) state in go fuel (Int64.succ current_tick) failing_ticks state) - | Needs_reveal (Request_dal_page page_id) -> ( + | Needs_reveal + ((Request_dal_page _ | Request_adal_page _) as xdal_request) -> ( + let ( page_id, + attestation_threshold_percent, + restricted_commitments_publishers ) = + 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 ) + | _ -> + (* This case is not reachable because we know that [xdal_request] + is either [Request_dal_page] or [Request_adal_page] *) + assert false + in match F.consume F.one_tick_consumption fuel with | None -> abort fuel current_tick | Some fuel -> @@ -290,6 +326,8 @@ 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*! () = @@ -310,11 +348,6 @@ module Make_fueled (F : Fuel.S) : FUELED_PVM with type fuel = F.t = struct go fuel (Int64.succ current_tick) failing_ticks state) | Initial | First_after _ -> return @@ Completed {fuel; current_tick; failing_ticks} - | Needs_reveal (Request_adal_page _) -> - (* ADAL/FIXME: https://gitlab.com/tezos/tezos/-/milestones/410 - - to be implemented. *) - assert false in go fuel start_tick failing_ticks state