From 1d01d36fee1fc2a4382a37790024bfbcb1005fd4 Mon Sep 17 00:00:00 2001 From: "iguerNL@Functori" Date: Tue, 7 Jan 2025 14:57:20 +0100 Subject: [PATCH] Proto/SORU: refactor refutation proofs' valid function to merge two pattern matchings The reason of this refactoring is that for Adjustable DAL, we need Dal_helpers.verify to return some extra information in addition to input_opt. With the previous implementation, we should modify all the other cases of the first pattern matching to return something (even if it's None), and then process it in the second pattern matching. With this refactoring, where we only have one pattern matching and which performs all the checks, we'll only need to modify the DAL related helper's return type --- .../lib_protocol/sc_rollup_proof_repr.ml | 216 +++++++++++------- 1 file changed, 132 insertions(+), 84 deletions(-) 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 a0b3b38530a9..6892a67f0051 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_proof_repr.ml @@ -367,31 +367,109 @@ let valid (type state proof output) ~dal_attestation_lag ~dal_number_of_slots ~is_reveal_enabled ~dal_attested_slots_validity_lag (proof : proof t) = let open Lwt_result_syntax in + let open Sc_rollup_PVM_sig in let (module P) = pvm in let origination_level = metadata.Sc_rollup_metadata_repr.origination_level in - let* input = - match proof.input_proof with - | None -> return_none - | Some (Inbox_proof {level; message_counter; proof}) -> - let*? inbox_message = - check_inbox_proof snapshot proof (level, Z.succ message_counter) - in - return - @@ Option.map (fun i -> Sc_rollup_PVM_sig.Inbox_message i) inbox_message - | Some First_inbox_message -> - let*? payload = - Sc_rollup_inbox_message_repr.(serialize (Internal Start_of_level)) - in - let inbox_level = Raw_level_repr.succ origination_level in - let message_counter = Z.zero in - return_some - Sc_rollup_PVM_sig.( - Inbox_message {inbox_level; message_counter; payload}) - | Some (Reveal_proof (Raw_data_proof data)) -> - return_some (Sc_rollup_PVM_sig.Reveal (Raw_data data)) - | Some (Reveal_proof Metadata_proof) -> - return_some (Sc_rollup_PVM_sig.Reveal (Metadata metadata)) - | Some (Reveal_proof (Dal_page_proof {proof; page_id})) -> + + (* Helper function to check that the requested input pretended by the given + proof matches the input request deduced from the PVM state. *) + let verify_proof_and_check_input_proof_against_input_request input_opt checker + = + let input_opt = + Option.bind + input_opt + (cut_at_level ~origination_level ~commit_inbox_level) + in + let* input_requested = + P.verify_proof ~is_reveal_enabled input_opt proof.pvm_step + in + let* () = checker input_requested in + return (input_opt, input_requested) + in + + let inbox_proof_and_input_request_are_dissociated () = + proof_error "Inbox proof and input request are dissociated." + in + + match proof.input_proof with + (* Case where the proof says that no input is needed: in this case, we check + that the PVM didn't request any input. *) + | None -> + verify_proof_and_check_input_proof_against_input_request None (function + | No_input_required -> return_unit + | _ -> inbox_proof_and_input_request_are_dissociated ()) + (* Case where the proof pretends that the PVM consumes the first inbox + message: we check in this case that the PVM is indeed requesting the + initial message. *) + | Some First_inbox_message -> + let*? payload = + Sc_rollup_inbox_message_repr.(serialize (Internal Start_of_level)) + in + let inbox_level = Raw_level_repr.succ origination_level in + let message_counter = Z.zero in + let input_opt = + Some (Inbox_message {inbox_level; message_counter; payload}) + in + verify_proof_and_check_input_proof_against_input_request + input_opt + (function + | Initial -> + (* If the state is [Initial], we don't need a proof of the input, + we know it's the [Start_of_level] after the origination. *) + return_unit + | _ -> inbox_proof_and_input_request_are_dissociated ()) + (* Case where the proof pretends that the PVM consumes an inbox message which + is not the first one: below, we check that the PVM is indeed requesting a + non intial inbox message corresponding to the given level and messages + counter. *) + | Some (Inbox_proof {level; message_counter; proof}) -> + let*? inbox_message = + check_inbox_proof snapshot proof (level, Z.succ message_counter) + in + let input_opt = Option.map (fun i -> Inbox_message i) inbox_message in + verify_proof_and_check_input_proof_against_input_request + input_opt + (function + | First_after (l, n) -> + check + (Raw_level_repr.(level = l) && Z.(equal message_counter n)) + "Level and index of inbox proof are not equal to the one \ + expected in input request." + | _ -> inbox_proof_and_input_request_are_dissociated ()) + (* Case where the proof pretends that the PVM consumes external data: + we check that the PVM is indeed requesting data and that the + provided data's hash corresponds to the one expected by the PVM. *) + | Some (Reveal_proof (Raw_data_proof data)) -> + let input_opt = Some (Reveal (Raw_data data)) in + verify_proof_and_check_input_proof_against_input_request + input_opt + (function + | Needs_reveal (Reveal_raw_data expected_hash) -> + let scheme = Sc_rollup_reveal_hash.scheme_of_hash expected_hash in + let data_hash = + Sc_rollup_reveal_hash.hash_string ~scheme [data] + in + check + (Sc_rollup_reveal_hash.equal data_hash expected_hash) + "Invalid reveal" + | _ -> inbox_proof_and_input_request_are_dissociated ()) + (* Case where the provided proof pretends that the PVM is asking for metadata + reveal: we check in this case that the PVM is actually requesting metadata + reveal. *) + | Some (Reveal_proof Metadata_proof) -> + let input_opt = Some (Reveal (Metadata metadata)) in + verify_proof_and_check_input_proof_against_input_request + input_opt + (function + | Needs_reveal Reveal_metadata -> return_unit + | _ -> inbox_proof_and_input_request_are_dissociated ()) + (* Case where the provided proof pretends that the PVM is asking for + (Adjustable) DAL page reveal: we check in this case that the DAL proof is + consistent t what's stored in the (DAL) skip list. We then check that the + PVM is actually requesting a DAL page whose ID coincides with the one of + the given proof. *) + | Some (Reveal_proof (Dal_page_proof {proof; page_id})) -> + let*? input_opt = Dal_helpers.verify ~protocol_activation_level ~dal_number_of_slots @@ -404,15 +482,31 @@ let valid (type state proof output) page_id dal_snapshot proof - |> Lwt.return - | Some (Reveal_proof Dal_parameters_proof) -> - (* FIXME: https://gitlab.com/tezos/tezos/-/issues/6562 - Support revealing historical DAL parameters. - - Currently, we do not support revealing DAL parameters for the past. - We ignore the given [published_level] and use the DAL parameters. *) - return_some - (Sc_rollup_PVM_sig.Reveal + in + verify_proof_and_check_input_proof_against_input_request + input_opt + (function + | Needs_reveal (Request_dal_page pid) -> + check + (Dal_slot_repr.Page.equal page_id pid) + "Dal proof's page ID is not the one expected in input request." + | Needs_reveal (Request_adal_page _pid) -> + (* ADAL/FIXME: https://gitlab.com/tezos/tezos/-/milestones/410 implement + refutation games for adaptive DAL. *) + assert false + | _ -> inbox_proof_and_input_request_are_dissociated ()) + (* Case where the provided proof pretends that the PVM is asking for DAL + parameters. In this case, we just check that the PVM is requesting DAL + parameters revelation. *) + | Some (Reveal_proof Dal_parameters_proof) -> + (* FIXME: https://gitlab.com/tezos/tezos/-/issues/6562 + Support revealing historical DAL parameters. + + Currently, we do not support revealing DAL parameters for the past. + We ignore the given [published_level] and use the DAL parameters. *) + let input_opt = + Some + (Reveal (Dal_parameters Sc_rollup_dal_parameters_repr. { @@ -421,58 +515,12 @@ let valid (type state proof output) slot_size = Int64.of_int dal_parameters.slot_size; page_size = Int64.of_int dal_parameters.page_size; })) - in - let input = - Option.bind input (cut_at_level ~origination_level ~commit_inbox_level) - in - let* input_requested = - P.verify_proof ~is_reveal_enabled input proof.pvm_step - in - let* () = - match (proof.input_proof, input_requested) with - | None, No_input_required -> return_unit - | Some First_inbox_message, Initial -> - (* If the state is [Initial], we don't need a proof of the input, - we know it's the [Start_of_level] after the origination. *) - return_unit - | Some (Inbox_proof {level; message_counter; proof = _}), First_after (l, n) - -> - check - (Raw_level_repr.(level = l) && Z.(equal message_counter n)) - "Level and index of inbox proof are not equal to the one expected in \ - input request." - | ( Some (Reveal_proof (Raw_data_proof data)), - Needs_reveal (Reveal_raw_data expected_hash) ) -> - let scheme = Sc_rollup_reveal_hash.scheme_of_hash expected_hash in - - let data_hash = Sc_rollup_reveal_hash.hash_string ~scheme [data] in - check - (Sc_rollup_reveal_hash.equal data_hash expected_hash) - "Invalid reveal" - | Some (Reveal_proof Metadata_proof), Needs_reveal Reveal_metadata -> - return_unit - | ( Some (Reveal_proof (Dal_page_proof {page_id; proof = _})), - Needs_reveal (Request_dal_page pid) ) -> - check - (Dal_slot_repr.Page.equal page_id pid) - "Dal proof's page ID is not the one expected in input request." - | ( Some (Reveal_proof Dal_parameters_proof), - Needs_reveal Reveal_dal_parameters ) -> - return_unit - | Some (Reveal_proof _), Needs_reveal (Request_dal_page _pid) -> - (* ADAL/FIXME: https://gitlab.com/tezos/tezos/-/milestones/410 implement - refutation games for adaptive DAL. *) - assert false - | None, (Initial | First_after _ | Needs_reveal _) - | Some _, No_input_required - | Some (Inbox_proof _), Needs_reveal _ - | _ -> - (* ADAL/TODO: https://gitlab.com/tezos/tezos/-/milestones/410 - - Remove this fragile pattern matching. *) - proof_error "Inbox proof and input request are dissociated." - in - return (input, input_requested) + in + verify_proof_and_check_input_proof_against_input_request + input_opt + (function + | Needs_reveal Reveal_dal_parameters -> return_unit + | _ -> inbox_proof_and_input_request_are_dissociated ()) module type PVM_with_context_and_state = sig include Sc_rollups.PVM.S -- GitLab