diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 418391a21e13b46d232c2a7e9bd5f0ee060a7cbb..26f7b439bb0c42f9d4c64640e84b1360d3e267a0 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -4223,7 +4223,7 @@ module Sc_rollup : sig dal_activation_level:Raw_level.t option -> dal_attestation_lag:int -> origination_level:Raw_level.t -> - commit_inbox_level:Raw_level.t -> + import_inbox_level:Raw_level.t -> published_level:Raw_level.t -> dal_attested_slots_validity_lag:int -> bool diff --git a/src/proto_alpha/lib_protocol/dal_slot_repr.ml b/src/proto_alpha/lib_protocol/dal_slot_repr.ml index f5b0ee753607185d25dcca8597f62e3fde5b643c..1abeaf33c273ba70070a6ddfaab25812b0a16d0d 100644 --- a/src/proto_alpha/lib_protocol/dal_slot_repr.ml +++ b/src/proto_alpha/lib_protocol/dal_slot_repr.ml @@ -1047,6 +1047,32 @@ module History = struct that level are not valid to be imported by the DAL anymore) should be handled by the caller. In fact, the [proof_repr] type here only covers levels where a new cell has been added to the skip list. *) + | Invalid_page_id of { + target_cell_and_inc_proof : (history * inclusion_proof) option; + (** There are two kinds of invalidity: + + - It is not possible to get a target cell, and it is clear + from the given inputs that the page ID is either in the future + or far in the past (TTL expired) w.r.t. our max attestation + lag value; this case is represented by [None]. + + - We can access the target cell of the page ID (thus we + provide it with the inclusion proof above), and validating the + page with the attestation lag of that cell tells us that the + page is invalid. *) + attestation_threshold_percent : int option; + (** In case of Adjustable DAL, [attestation_threshold_percent] is set + to some attestation threshold defined by the rollup kernel. For + regular DAL, it's set to None. *) + restricted_commitments_publishers : Contract_repr.t list option; + (** In case of Adjustable DAL, [restricted_commitments_publishers] + is set to the rollup's list of authorized addresses, if + any. For regular DAL, it's set to None. *) + } + (** This case covers situations where the requested/imported page's ID + is either in the future w.r.t. attestation lag, in the past + w.r.t. (attested) slots validity window, or in the past w.r.t. + DAL activation level / rollup origination level. *) let proof_repr_encoding = let open Data_encoding in @@ -1141,8 +1167,45 @@ module History = struct restricted_commitments_publishers; }) in - - union [case_page_confirmed; case_page_unconfirmed] + let case_invalid_page_id = + case + ~title:"invalid page id representation" + (Tag 2) + (obj4 + (req "kind" (constant "invalid_page_id")) + (opt + "target_cell_and_inc_proof" + (tup2 history_encoding (list history_encoding))) + (opt "attestation_threshold_percent" uint8) + (opt + "restricted_commitments_publishers" + (list Contract_repr.encoding))) + (function + | Invalid_page_id + { + target_cell_and_inc_proof; + attestation_threshold_percent; + restricted_commitments_publishers; + } -> + Some + ( (), + target_cell_and_inc_proof, + attestation_threshold_percent, + restricted_commitments_publishers ) + | _ -> None) + (fun ( (), + target_cell_and_inc_proof, + attestation_threshold_percent, + restricted_commitments_publishers ) + -> + Invalid_page_id + { + target_cell_and_inc_proof; + attestation_threshold_percent; + restricted_commitments_publishers; + }) + in + union [case_page_confirmed; case_page_unconfirmed; case_invalid_page_id] (** Proof's type is set to bytes and not a structural datatype because when a proof appears in a tezos operation or in an rpc, a user can not @@ -1254,6 +1317,34 @@ module History = struct (Format.pp_print_option Format.pp_print_int) attestation_threshold_percent pp_whitelist + restricted_commitments_publishers + | Invalid_page_id + { + target_cell_and_inc_proof; + attestation_threshold_percent; + restricted_commitments_publishers; + } -> + let pp_target_and_proof fmt = function + | None -> Format.fprintf fmt "pp_target_and_proof = " + | Some (target_cell, inc_proof) -> + Format.fprintf + fmt + "target_cell = %a | inc_proof:[size=%d@ | path=%a]@" + pp_history + target_cell + (List.length inc_proof) + pp_inclusion_proof + inc_proof + in + Format.fprintf + fmt + "Page_unconfirmed (%a attestation_threshold_percent:%a@ \ + commitment_publisher:%a)" + pp_target_and_proof + target_cell_and_inc_proof + (Format.pp_print_option Format.pp_print_int) + attestation_threshold_percent + pp_whitelist restricted_commitments_publishers) type error += @@ -1371,9 +1462,9 @@ module History = struct Under these assumptions, we recall that we maintain an invariant ensuring that we a have a cell per slot index in the skip list at every level after DAL activation. *) - let produce_proof_repr dal_params ~attestation_threshold_percent - ~restricted_commitments_publishers page_id ~page_info ~get_history - slots_hist = + let produce_proof_repr dal_params ~page_id_is_valid + ~attestation_threshold_percent ~restricted_commitments_publishers + page_id ~page_info ~get_history slots_hist = let open Lwt_result_syntax in let Page.{slot_id = target_slot_id; page_index = _} = page_id in (* We first search for the slots attested at level [published_level]. *) @@ -1385,10 +1476,45 @@ module History = struct {!produce_proof_repr}. *) match search_result.Skip_list.last_cell with | Deref_returned_none -> - tzfail - @@ dal_proof_error - "Skip_list.search returned 'Deref_returned_none': Slots history \ - cache is ill-formed or has too few entries." + (* We do not know the exact attestation lag here and we failed to + fetch the target cell from the skip-list DB. To decide whether the + page id could still be valid, we conservatively consider the whole + interval of possible attestation lags, from [0] up to + [legacy_attestation_lag] (our historical upper bound): + + - If [page_id_is_valid] holds either with [~dal_attestation_lag = + 0] or with [~dal_attestation_lag = legacy_attestation_lag], then + there exists at least one admissible lag for which the page id may + still be valid. In that case, the failure is possibly due to + missing skip-list cells in the operator's context. We cannot safely + produce a proof: the operator must first fetch and store the + missing cells. Later, the proof may still be requalified as + [Invalid_page_id] if the actual attestation lag rules it out; see + the second call to [page_id_is_valid] below. + + - If [page_id_is_valid] does not hold for either extremal value, + the page id is definitely invalid for any lag in the admissible + range, and returning [Invalid_page_id] is sound. *) + let max_attestation_lag = legacy_attestation_lag in + if + page_id_is_valid ~dal_attestation_lag:max_attestation_lag page_id + || page_id_is_valid ~dal_attestation_lag:0 page_id + then + (* Page id may be valid, but we are missing skip-list cells. *) + tzfail + @@ dal_proof_error + "Skip_list.search returned 'Deref_returned_none': Slots \ + history cache is ill-formed or has too few entries." + else + (* Page id is definitely invalid, even under the upper bound. *) + return + ( Invalid_page_id + { + target_cell_and_inc_proof = None; + attestation_threshold_percent; + restricted_commitments_publishers; + }, + None ) | No_exact_or_lower_ptr -> tzfail @@ dal_proof_error @@ -1406,79 +1532,92 @@ module History = struct | Found target_cell -> let* proof, page_opt = let inc_proof = List.rev search_result.Skip_list.rev_path in + let target_cell_content = Skip_list.content target_cell in let is_commitment_attested = - Skip_list.content target_cell - |> is_commitment_attested - ~attestation_threshold_percent - ~restricted_commitments_publishers + is_commitment_attested + ~attestation_threshold_percent + ~restricted_commitments_publishers + target_cell_content + in + let {attestation_lag; header_id = _} = + Content.content_id target_cell_content in - match (page_info, is_commitment_attested) with - | Some (page_data, page_proof), Some commitment -> - (* The case where the slot to which the page is supposed to belong + let dal_attestation_lag = attestation_lag_value attestation_lag in + if not (page_id_is_valid ~dal_attestation_lag page_id) then + return + ( Invalid_page_id + { + target_cell_and_inc_proof = Some (target_cell, inc_proof); + attestation_threshold_percent; + restricted_commitments_publishers; + }, + None ) + else + match (page_info, is_commitment_attested) with + | Some (page_data, page_proof), Some commitment -> + (* The case where the slot to which the page is supposed to belong is found and the page's information are given. *) - let*? () = - (* We check the page's proof against the commitment. *) - check_page_proof - dal_params - page_proof - page_data - page_id - commitment - in - (* All checks succeeded. We return a `Page_confirmed` proof. *) - return - ( Page_confirmed - { - target_cell; - inc_proof; - page_data; - page_proof; - attestation_threshold_percent; - restricted_commitments_publishers; - }, - Some page_data ) - | None, None -> - (* The slot corresponding to the given page's index is not found in + let*? () = + (* We check the page's proof against the commitment. *) + check_page_proof + dal_params + page_proof + page_data + page_id + commitment + in + (* All checks succeeded. We return a `Page_confirmed` proof. *) + return + ( Page_confirmed + { + target_cell; + inc_proof; + page_data; + page_proof; + attestation_threshold_percent; + restricted_commitments_publishers; + }, + Some page_data ) + | None, None -> + (* The slot corresponding to the given page's index is not found in the attested slots of the page's level, and no information is given for that page. So, we produce a proof that the page is not attested. *) - return - ( Page_unconfirmed - { - target_cell; - inc_proof; - attestation_threshold_percent; - restricted_commitments_publishers; - }, - None ) - | None, Some _ -> - (* Mismatch: case where no page information are given, but the + return + ( Page_unconfirmed + { + target_cell; + inc_proof; + attestation_threshold_percent; + restricted_commitments_publishers; + }, + None ) + | None, Some _ -> + (* Mismatch: case where no page information are given, but the slot is attested. *) - tzfail - @@ dal_proof_error - "The page ID's slot is confirmed, but no page content and \ - proof are provided." - | Some _, None -> - (* Mismatch: case where page information are given, but the slot + tzfail + @@ dal_proof_error + "The page ID's slot is confirmed, but no page content \ + and proof are provided." + | Some _, None -> + (* Mismatch: case where page information are given, but the slot is not attested. *) - tzfail - @@ dal_proof_error - "The page ID's slot is not confirmed, but page content \ - and proof are provided." + tzfail + @@ dal_proof_error + "The page ID's slot is not confirmed, but page content \ + and proof are provided." in - let {attestation_lag; header_id = _} = - Skip_list.content target_cell |> Content.content_id - in - return (proof, page_opt, attestation_lag) + return (proof, page_opt) - let produce_proof dal_params ~attestation_threshold_percent - ~restricted_commitments_publishers page_id ~page_info ~get_history - slots_hist : - (proof * Page.content option * attestation_lag_kind) tzresult Lwt.t = + let produce_proof dal_params ~page_id_is_valid + ~attestation_threshold_percent ~restricted_commitments_publishers + page_id ~page_info ~get_history slots_hist : + (proof * Page.content option) tzresult Lwt.t = let open Lwt_result_syntax in - let* proof_repr, page_data, attestation_lag = + let* proof_repr, page_data = produce_proof_repr dal_params + ~page_id_is_valid ~attestation_threshold_percent ~restricted_commitments_publishers page_id @@ -1487,7 +1626,7 @@ module History = struct slots_hist in let*? serialized_proof = serialize_proof proof_repr in - return (serialized_proof, page_data, attestation_lag) + return (serialized_proof, page_data) (* Given a starting cell [snapshot] and a (final) [target], this function checks that the provided [inc_proof] encodes a minimal path from @@ -1511,103 +1650,134 @@ module History = struct path) (dal_proof_error "verify_proof_repr: invalid inclusion Dal proof.") - let verify_proof_repr dal_params page_id snapshot proof = + let verify_proof_repr dal_params ~page_id_is_valid page_id snapshot proof = let open Result_syntax in let Page.{slot_id = Header.{published_level; index}; page_index = _} = page_id in - (* With the recent refactoring of the skip list shape, we always have a - target cell and an inclusion proof in the provided proof, because the - skip list contains a cell for each slot index of each level. *) - let ( target_cell, - inc_proof, - attestation_threshold_percent, - restricted_commitments_publishers ) = - match proof with - | Page_confirmed - { - target_cell; - inc_proof; - page_data = _; - page_proof = _; - attestation_threshold_percent; - restricted_commitments_publishers; - } -> - ( target_cell, - inc_proof, - attestation_threshold_percent, - restricted_commitments_publishers ) - | Page_unconfirmed - { - target_cell; - inc_proof; - attestation_threshold_percent; - restricted_commitments_publishers; - } -> - ( target_cell, - inc_proof, - attestation_threshold_percent, - restricted_commitments_publishers ) - in - let cell_content = Skip_list.content target_cell in - (* We check that the target cell has the same level and index than the + match proof with + | Invalid_page_id {target_cell_and_inc_proof = None; _} -> + (* We handle this case first, before processing the others. See where + it is returned in [produced_proof] above for more details. *) + let max_attestation_lag = legacy_attestation_lag in + if + page_id_is_valid ~dal_attestation_lag:max_attestation_lag page_id + || page_id_is_valid ~dal_attestation_lag:0 page_id + then + tzfail + @@ dal_proof_error + "page_id_is_valid returned true for an Invalid_page_id but \ + the provided proof doesn't contain the target cell and \ + inclusion proof." + else return None + | _ -> + (* With the recent refactoring of the skip list shape, we always have + a target cell and an inclusion proof in the provided proof, because + the skip list contains a cell for each slot index of each level. *) + let ( target_cell, + inc_proof, + attestation_threshold_percent, + restricted_commitments_publishers ) = + match proof with + | Invalid_page_id {target_cell_and_inc_proof = None; _} -> + assert false (* Not reachable: handled above *) + | Page_confirmed + { + target_cell; + inc_proof; + page_data = _; + page_proof = _; + attestation_threshold_percent; + restricted_commitments_publishers; + } + | Page_unconfirmed + { + target_cell; + inc_proof; + attestation_threshold_percent; + restricted_commitments_publishers; + } + | Invalid_page_id + { + target_cell_and_inc_proof = Some (target_cell, inc_proof); + attestation_threshold_percent; + restricted_commitments_publishers; + } -> + ( target_cell, + inc_proof, + attestation_threshold_percent, + restricted_commitments_publishers ) + in + let cell_content = Skip_list.content target_cell in + (* We check that the target cell has the same level and index than the page we're about to prove. *) - let {header_id = slot_id; attestation_lag} = - Content.content_id cell_content - in - let* () = - error_when - Raw_level_repr.(slot_id.published_level <> published_level) - (dal_proof_error "verify_proof_repr: published_level mismatch.") - in - let* () = - error_when - (not (Dal_slot_index_repr.equal slot_id.index index)) - (dal_proof_error "verify_proof_repr: slot index mismatch.") - in - (* We check that the given inclusion proof indeed links our L1 snapshot to + let {header_id = slot_id; attestation_lag} = + Content.content_id cell_content + in + let* () = + error_when + Raw_level_repr.(slot_id.published_level <> published_level) + (dal_proof_error "verify_proof_repr: published_level mismatch.") + in + let* () = + error_when + (not (Dal_slot_index_repr.equal slot_id.index index)) + (dal_proof_error "verify_proof_repr: slot index mismatch.") + in + (* We check that the given inclusion proof indeed links our L1 snapshot to the target cell. *) - let* () = - verify_inclusion_proof inc_proof ~src:snapshot ~dest:target_cell - in - let is_commitment_attested = - is_commitment_attested - ~attestation_threshold_percent - ~restricted_commitments_publishers - cell_content - in - let* data_opt = - match (proof, is_commitment_attested) with - | Page_unconfirmed _, Some _ -> - error - @@ dal_proof_error - "verify_proof_repr: the confirmation proof doesn't contain \ - the attested slot." - | Page_unconfirmed _, None -> return_none - | Page_confirmed _, None -> - error - @@ dal_proof_error - "verify_proof_repr: the unconfirmation proof contains the \ - target slot." - | Page_confirmed {page_data; page_proof; _}, Some commitment -> - (* We check that the page indeed belongs to the target slot at the + let* () = + verify_inclusion_proof inc_proof ~src:snapshot ~dest:target_cell + in + let is_commitment_attested = + is_commitment_attested + ~attestation_threshold_percent + ~restricted_commitments_publishers + cell_content + in + let* data_opt = + match (proof, is_commitment_attested) with + | Page_unconfirmed _, Some _ -> + error + @@ dal_proof_error + "verify_proof_repr: the confirmation proof doesn't \ + contain the attested slot." + | Page_unconfirmed _, None -> return_none + | Page_confirmed _, None -> + error + @@ dal_proof_error + "verify_proof_repr: the unconfirmation proof contains the \ + target slot." + | Page_confirmed {page_data; page_proof; _}, Some commitment -> + (* We check that the page indeed belongs to the target slot at the given page index. *) - let* () = - check_page_proof - dal_params - page_proof - page_data - page_id - commitment - in - return_some page_data - in - return (data_opt, attestation_lag) + let* () = + check_page_proof + dal_params + page_proof + page_data + page_id + commitment + in + return_some page_data + | Invalid_page_id _, _ -> + let dal_attestation_lag = + attestation_lag_value attestation_lag + in + if page_id_is_valid ~dal_attestation_lag page_id then + tzfail + @@ dal_proof_error + "page_id_is_valid returned true for an Invalid_page_id \ + whose target cell is given." + else return None + in + return data_opt - let verify_proof dal_params page_id snapshot serialized_proof = + let verify_proof dal_params ~page_id_is_valid page_id snapshot + serialized_proof = let open Result_syntax in let* proof_repr = deserialize_proof serialized_proof in - verify_proof_repr dal_params page_id snapshot proof_repr + verify_proof_repr dal_params ~page_id_is_valid page_id snapshot proof_repr let adal_parameters_of_proof serialized_proof = let open Result_syntax in @@ -1617,6 +1787,8 @@ module History = struct {attestation_threshold_percent; restricted_commitments_publishers; _} | Page_unconfirmed {attestation_threshold_percent; restricted_commitments_publishers; _} + | Invalid_page_id + {attestation_threshold_percent; restricted_commitments_publishers; _} -> (attestation_threshold_percent, restricted_commitments_publishers) diff --git a/src/proto_alpha/lib_protocol/dal_slot_repr.mli b/src/proto_alpha/lib_protocol/dal_slot_repr.mli index 47ca00b86b3857cd3feb3a4840f132b4b4416a5a..170eb16dbcbeb55c3dccebdc81e03471217f5560 100644 --- a/src/proto_alpha/lib_protocol/dal_slot_repr.mli +++ b/src/proto_alpha/lib_protocol/dal_slot_repr.mli @@ -506,13 +506,14 @@ module History : sig in particular across protocol migrations that decrease the lag. *) val produce_proof : parameters -> + page_id_is_valid:(dal_attestation_lag:int -> Page.t -> bool) -> attestation_threshold_percent:int option -> restricted_commitments_publishers:Contract_repr.t list option -> Page.t -> page_info:(Page.content * Page.proof) option -> get_history:(hash -> t option Lwt.t) -> t -> - (proof * Page.content option * attestation_lag_kind) tzresult Lwt.t + (proof * Page.content option) tzresult Lwt.t (** [verify_proof dal_params page_id snapshot proof] verifies that the given [proof] is a valid proof to show that either: @@ -530,10 +531,11 @@ module History : sig list is returned, alongside the page's bytes if the slot is attested. *) val verify_proof : parameters -> + page_id_is_valid:(dal_attestation_lag:int -> Page.t -> bool) -> Page.t -> t -> proof -> - (bytes option * attestation_lag_kind) tzresult + bytes option tzresult (** Given a DAL proof, this function returns the values of the fields [attestation_threshold_percent] [restricted_commitments_publishers] stored diff --git a/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.ml index e4d7fd1fcc4fecfb2367d64393f54f51a2a2e442..b35ca668cd83d216cd657161f070e74045ac212c 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.ml @@ -237,9 +237,8 @@ module Dal_helpers = struct (* FIXME/DAL: https://gitlab.com/tezos/tezos/-/issues/3997 The current DAL refutation integration is not resilient to DAL parameters changes when upgrading the protocol. The code needs to be adapted. *) - let import_level_is_valid ~dal_activation_level ~dal_attestation_lag - ~origination_level ~commit_inbox_level ~published_level + ~origination_level ~import_inbox_level ~published_level ~dal_attested_slots_validity_lag = (* [dal_attestation_lag] is supposed to be positive. *) let open Raw_level_repr in @@ -251,24 +250,20 @@ module Dal_helpers = struct let slot_published_after_origination = published_level > origination_level in - let not_too_recent = - add published_level dal_attestation_lag <= commit_inbox_level - in + let attested_level = add published_level dal_attestation_lag in + let not_too_recent = attested_level <= import_inbox_level in (* An attested slot is not expired if its attested level (equal to [published_level + dal_attestation_lag]) is not further than [dal_attested_slots_validity_lag] from the given inbox level. *) let ttl_not_expired = Raw_level_repr.( - add - (add published_level dal_attestation_lag) - dal_attested_slots_validity_lag - >= commit_inbox_level) + add attested_level dal_attested_slots_validity_lag >= import_inbox_level) in dal_was_activated && slot_published_after_origination && not_too_recent && ttl_not_expired let page_id_is_valid ~dal_number_of_slots ~dal_activation_level - ~dal_attestation_lag ~origination_level ~commit_inbox_level + ~dal_attestation_lag ~origination_level ~import_inbox_level cryptobox_parameters Dal_slot_repr.Page.{slot_id = {published_level; index}; page_index} ~dal_attested_slots_validity_lag = @@ -285,43 +280,38 @@ module Dal_helpers = struct ~dal_activation_level ~dal_attestation_lag ~origination_level - ~commit_inbox_level + ~import_inbox_level ~published_level ~dal_attested_slots_validity_lag let verify ~metadata ~dal_activation_level ~dal_number_of_slots - ~commit_inbox_level dal_parameters page_id dal_snapshot proof + ~import_inbox_level dal_parameters page_id dal_snapshot proof ~dal_attested_slots_validity_lag = let open Result_syntax in - let* input_opt, attestation_lag = + let* input_opt = Dal_slot_repr.History.verify_proof dal_parameters page_id dal_snapshot proof + ~page_id_is_valid: + (page_id_is_valid + dal_parameters + ~dal_activation_level + ~origination_level: + metadata.Sc_rollup_metadata_repr.origination_level + ~import_inbox_level + ~dal_number_of_slots + ~dal_attested_slots_validity_lag) in - let dal_attestation_lag = - Dal_slot_repr.History.attestation_lag_value attestation_lag - in - if - page_id_is_valid - dal_parameters - ~dal_activation_level - ~origination_level:metadata.Sc_rollup_metadata_repr.origination_level - ~dal_attestation_lag - ~commit_inbox_level - ~dal_number_of_slots - page_id - ~dal_attested_slots_validity_lag - then return_some (Sc_rollup_PVM_sig.Reveal (Dal_page input_opt)) - else return_none + return_some (Sc_rollup_PVM_sig.Reveal (Dal_page input_opt)) let produce ~metadata ~dal_activation_level ~dal_number_of_slots - ~commit_inbox_level dal_parameters ~attestation_threshold_percent + ~import_inbox_level dal_parameters ~attestation_threshold_percent ~restricted_commitments_publishers page_id ~page_info ~get_history confirmed_slots_history ~dal_attested_slots_validity_lag = let open Lwt_result_syntax in - let* proof, content_opt, attestation_lag = + let* proof, content_opt = Dal_slot_repr.History.produce_proof dal_parameters ~attestation_threshold_percent @@ -330,25 +320,19 @@ module Dal_helpers = struct ~page_info ~get_history confirmed_slots_history + ~page_id_is_valid: + (page_id_is_valid + dal_parameters + ~dal_number_of_slots + ~dal_activation_level + ~origination_level: + metadata.Sc_rollup_metadata_repr.origination_level + ~import_inbox_level + ~dal_attested_slots_validity_lag) in - let dal_attestation_lag = - Dal_slot_repr.History.attestation_lag_value attestation_lag - in - if - page_id_is_valid - dal_parameters - ~dal_number_of_slots - ~dal_activation_level - ~origination_level:metadata.Sc_rollup_metadata_repr.origination_level - ~dal_attestation_lag - ~commit_inbox_level - page_id - ~dal_attested_slots_validity_lag - then - return - ( Some (Reveal_proof (Dal_page_proof {proof; page_id})), - Some (Sc_rollup_PVM_sig.Reveal (Dal_page content_opt)) ) - else return (None, None) + return + ( Some (Reveal_proof (Dal_page_proof {proof; page_id})), + Some (Sc_rollup_PVM_sig.Reveal (Dal_page content_opt)) ) let validate_dal_input_request proof ~proof_page_id ~request_page_id ~request_attestation_threshold_percent @@ -413,17 +397,17 @@ let valid (type state proof output) return_some (Sc_rollup_PVM_sig.Reveal (Metadata metadata)) | Some (Reveal_proof (Dal_page_proof {proof = dal_page_proof; page_id})) -> let* disputed_level = P.get_proof_state_level proof.pvm_step in - let* dal_parameters : Constants_parametric_repr.dal = - find_dal_parameters - ((* The rationale for [Option.value + let import_inbox_level = + (* The rationale for [Option.value ~default:metatadata.origination_level] is the first input a Smart Rollup will consume is the [Start_of_level] of origination_level + 1. As the level of a PVM is given by the inputs, if it's none, that means the PVM has never consumed an input and therefore is on the origination level. *) - Option.value - ~default:metadata.origination_level - disputed_level) + Option.value ~default:metadata.origination_level disputed_level + in + let* dal_parameters : Constants_parametric_repr.dal = + find_dal_parameters import_inbox_level in Dal_helpers.verify ~dal_number_of_slots:dal_parameters.number_of_slots @@ -431,17 +415,17 @@ let valid (type state proof output) ~dal_activation_level ~dal_attested_slots_validity_lag dal_parameters.cryptobox_parameters - ~commit_inbox_level + ~import_inbox_level page_id dal_snapshot dal_page_proof |> Lwt.return | Some (Reveal_proof Dal_parameters_proof) -> let* disputed_level = P.get_proof_state_level proof.pvm_step in - let* dal_parameters = - find_dal_parameters - (Option.value ~default:metadata.origination_level disputed_level) + let import_inbox_level = + Option.value ~default:metadata.origination_level disputed_level in + let* dal_parameters = find_dal_parameters import_inbox_level in return_some (Sc_rollup_PVM_sig.Reveal (Dal_parameters @@ -626,12 +610,16 @@ let produce ~metadata ~find_dal_parameters pvm_and_state commit_inbox_level Some Sc_rollup_PVM_sig.(Reveal (Metadata metadata)) ) | Needs_reveal (Request_dal_page page_id) -> let open Dal_with_history in + let*! disputed_level = P.get_current_level P.state in + let import_inbox_level = + Option.value ~default:metadata.origination_level disputed_level + in Dal_helpers.produce ~dal_number_of_slots ~metadata ~dal_activation_level dal_parameters - ~commit_inbox_level + ~import_inbox_level ~attestation_threshold_percent:None ~restricted_commitments_publishers:None page_id @@ -650,12 +638,16 @@ let produce ~metadata ~find_dal_parameters pvm_and_state commit_inbox_level let attestation_threshold_percent = Some attestation_threshold_percent in + let*! disputed_level = P.get_current_level P.state in + let import_inbox_level = + Option.value ~default:metadata.origination_level disputed_level + in Dal_helpers.produce ~dal_number_of_slots ~metadata ~dal_activation_level dal_parameters - ~commit_inbox_level + ~import_inbox_level ~attestation_threshold_percent ~restricted_commitments_publishers page_id diff --git a/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.mli b/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.mli index 97fbbd0322da827d7a8af1e3b94c5a04ba19f299..c9ebdbbd3fe78330b4517c164e4fad83e2052091 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.mli @@ -282,21 +282,17 @@ module Dal_helpers : sig - [published_level] > [origination_level]: this means that the slot of the page was published after the rollup origination ; - - [published_level] + [dal_attestation_lag] <= [commit_inbox_level]: this + - [published_level] + [dal_attestation_lag] <= [import_inbox_level]: this means that the slot of the page has been attested before or at the - [commit_inbox_level]. + [import_inbox_level]. - According to the definition in {!Sc_rollup_commitment_repr}, - [commit_inbox_level] (aka inbox_level in that module) is the level - (included) up to which the PVM consumed all messages and DAL/DAC inputs - before producing the related commitment. We also check that the given slot ID's index is within the range of allowed slots thanks to [dal_number_of_slots]. *) val import_level_is_valid : dal_activation_level:Raw_level_repr.t option -> dal_attestation_lag:int -> origination_level:Raw_level_repr.t -> - commit_inbox_level:Raw_level_repr.t -> + import_inbox_level:Raw_level_repr.t -> published_level:Raw_level_repr.t -> dal_attested_slots_validity_lag:int -> bool diff --git a/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.ml b/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.ml index ea8af07713a92f53cb09d2d3a998609fd0fb31e9..bc2b26715a378b8ef9bc0a7edeb92f378fe2827d 100644 --- a/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.ml +++ b/src/proto_alpha/lib_protocol/test/helpers/dal_helpers.ml @@ -204,6 +204,7 @@ struct let*!@ res = Hist.produce_proof params + ~page_id_is_valid:(fun ~dal_attestation_lag:_ _page_id -> true) ~page_info ~attestation_threshold_percent:None ~restricted_commitments_publishers:None @@ -211,16 +212,19 @@ struct ~get_history skip_list in - let res = - Result.map (fun (proof, input_opt, _lag) -> (proof, input_opt)) res - in let* () = check_produce res page_info in match check_verify with | None -> return_unit | Some check_verify -> let*? proof, _input_opt = res in - let@ res = Hist.verify_proof params page_id skip_list proof in - let res = Result.map (fun (bytes_opt, _lag) -> bytes_opt) res in + let@ res = + Hist.verify_proof + params + page_id + skip_list + proof + ~page_id_is_valid:(fun ~dal_attestation_lag:_ _page_id -> true) + in check_verify res page_info (* Some check functions. *) 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 58ed19525a6d70eaec7fadcbf3b616b8a4ee1027..84857d84d0fcf0ef8207809c7fe1a61d5da99a9a 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 @@ -270,14 +270,14 @@ let slot_id_is_valid chain_id ~dal_attestation_lag ~number_of_slots (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 - match (origination_level_res, commit_inbox_level_res) with - | Ok origination_level, Ok commit_inbox_level -> + let import_inbox_level_res = Raw_level.of_int32 inbox_level in + match (origination_level_res, import_inbox_level_res) with + | Ok origination_level, Ok import_inbox_level -> Alpha_context.Sc_rollup.Proof.Dal_helpers.import_level_is_valid ~dal_activation_level ~dal_attestation_lag ~origination_level - ~commit_inbox_level + ~import_inbox_level ~dal_attested_slots_validity_lag ~published_level:slot_id.published_level | _ -> false diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.ml b/src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.ml index 38a3bf4f45cb686e7729e8cae12b5ca2c0cf9fd2..95275a7793d4f47aab80f27cb4e06248dffecf6c 100644 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.ml +++ b/src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.ml @@ -160,10 +160,20 @@ let generate_proof (node_ctxt : _ Node_context.t) ) | _ -> return (None, max_int) in + let state = PVM.Ctxt_wrapper.of_node_pvmstate start_state in let* page_info = + (* The page content that could be imported at the current import level of + the PVM. It is expected to be [None] if the page id is not valid or if + the slot is not attested. *) + let*! import_level = + let*! import_level = PVM.get_current_level state in + match import_level with + | Some level -> Raw_level.to_int32 level |> Lwt.return + | None -> Lwt.return node_ctxt.genesis_info.level + in page_info_from_pvm_state constants - ~inbox_level:game.inbox_level + ~inbox_level:import_level node_ctxt start_state in @@ -172,7 +182,7 @@ let generate_proof (node_ctxt : _ Node_context.t) let context : context = (Ctxt_wrapper.of_node_context context).index - let state = Ctxt_wrapper.of_node_pvmstate start_state + let state = state let reveal hash = let open Lwt_syntax in