diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index ce4bffdb6ba528664661ad581e673ad8fb8653d3..63068a8cc2f60875600cab287a6bd695ff79b9e9 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -3538,6 +3538,13 @@ module Sc_rollup : sig val produce_output_proof : context -> state -> output -> (output_proof, error) result Lwt.t + val check_dissection : + default_number_of_sections:int -> + start_chunk:Dissection_chunk.t -> + stop_chunk:Dissection_chunk.t -> + Dissection_chunk.t list -> + unit tzresult + module Internal_for_tests : sig val insert_failure : state -> state Lwt.t end diff --git a/src/proto_alpha/lib_protocol/sc_rollup_PVM_sig.ml b/src/proto_alpha/lib_protocol/sc_rollup_PVM_sig.ml index 8b8b3a623219222565f0ba3f22f79f9aa53c0fc5..b7ed6fdb7f7e2768ea8f24fc87d5f9ab79bab205 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_PVM_sig.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_PVM_sig.ml @@ -571,6 +571,17 @@ module type S = sig val produce_output_proof : context -> state -> output -> (output_proof, error) result Lwt.t + (** [check_dissection ~default_number_of_sections ~start_chunk + ~stop_chunk chunks] fails if the dissection encoded by the list + [[start_chunk] @ chunks @ [stop_chunk]] does not satisfy the + properties expected by the PVM. *) + val check_dissection : + default_number_of_sections:int -> + start_chunk:Sc_rollup_dissection_chunk_repr.t -> + stop_chunk:Sc_rollup_dissection_chunk_repr.t -> + Sc_rollup_dissection_chunk_repr.t list -> + unit tzresult + module Internal_for_tests : sig (** [insert_failure state] corrupts the PVM state. This is used in the loser mode of the rollup node. *) diff --git a/src/proto_alpha/lib_protocol/sc_rollup_arith.ml b/src/proto_alpha/lib_protocol/sc_rollup_arith.ml index 42ca2e4543646ffb59e58cf533874e237a9a8882..96133f425f374cde366f45809bd9ca85b8779188 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_arith.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_arith.ml @@ -213,6 +213,8 @@ module Make (Context : P) : | IAdd -> Format.fprintf fmt "add" | IStore x -> Format.fprintf fmt "store(%s)" x + let check_dissection = Sc_rollup_dissection_chunk_repr.default_check + (* The machine state is represented using a Merkle tree. diff --git a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml index 54e5356ec5cf4555501e8b839f0ac30e52b93eea..a717714b825a2907b8c0b28f67bf22c30bc90c6d 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml @@ -322,6 +322,12 @@ module V1 = struct Final_move {agreed_start_chunk; refuted_stop_chunk}); ] + let restrict_pvm_name_encoding = + let restrict_string l = + Data_encoding.string_enum @@ List.map (fun x -> (x, x)) l + in + restrict_string Sc_rollups.Kind.all_names + let encoding = let open Data_encoding in conv @@ -363,7 +369,7 @@ module V1 = struct (req "dal_snapshot" Dal_slot_repr.History.encoding) (req "start_level" Raw_level_repr.encoding) (req "inbox_level" Raw_level_repr.encoding) - (req "pvm_name" string) + (req "pvm_name" restrict_pvm_name_encoding) (req "game_state" game_state_encoding)) let pp_dissection ppf d = @@ -824,31 +830,42 @@ let play dal_parameters ~dal_attestation_lag ~stakers metadata game refutation = Either.Left (Loser {loser; reason = Conflict_resolved}) in match (refutation.step, game.game_state) with - | Dissection states, Dissecting {dissection; default_number_of_sections} -> + | Dissection states, Dissecting {dissection; default_number_of_sections} -> ( let*? start_chunk, stop_chunk = find_choice dissection refutation.choice in - let*? () = - Sc_rollup_dissection_chunk_repr.default_check - ~default_number_of_sections - ~start_chunk - ~stop_chunk - states - in - let new_game_state = - Dissecting {dissection = states; default_number_of_sections} - in - return - (Either.Right - { - turn = opponent game.turn; - inbox_snapshot = game.inbox_snapshot; - dal_snapshot = game.dal_snapshot; - start_level = game.start_level; - inbox_level = game.inbox_level; - pvm_name = game.pvm_name; - game_state = new_game_state; - }) + match Sc_rollups.Kind.pvm_of_name ~name:game.pvm_name with + | Some (module PVM) -> + let*? () = + PVM.check_dissection + ~default_number_of_sections + ~start_chunk + ~stop_chunk + states + in + let new_game_state = + Dissecting {dissection = states; default_number_of_sections} + in + return + (Either.Right + { + turn = opponent game.turn; + inbox_snapshot = game.inbox_snapshot; + dal_snapshot = game.dal_snapshot; + start_level = game.start_level; + inbox_level = game.inbox_level; + pvm_name = game.pvm_name; + game_state = new_game_state; + }) + | None -> + (* + Assuming the [pvm_name] registered in the [game] + structure is correct, this case cannot happen. This + property is enforced by the correctness of the + implementation of the rejection game, and is strengthen + by the encoding of [game]. + *) + assert false) | Dissection _, Final_move _ -> tzfail Dissecting_during_final_move | Proof proof, Dissecting {dissection; default_number_of_sections = _} -> let*? start_chunk, stop_chunk = diff --git a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml index ab131be41395ea30e9117862ca380bedc00a633e..812bd9a685254132b7e22bd0937c8347dfcc6049 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml @@ -517,6 +517,8 @@ module V2_0_0 = struct | Some (_, false) -> fail WASM_invalid_claim_about_outbox | None -> fail WASM_output_proof_production_failed + let check_dissection = Sc_rollup_dissection_chunk_repr.default_check + module Internal_for_tests = struct let insert_failure state = let add n = Tree.add state ["failures"; string_of_int n] Bytes.empty in diff --git a/src/proto_alpha/lib_protocol/test/pbt/test_sc_rollup_encoding.ml b/src/proto_alpha/lib_protocol/test/pbt/test_sc_rollup_encoding.ml index 6218e001eda9420d3c491385672c41be8e156bdf..034a1ec026e42af8e8c64f95a1e1caae34dbf38a 100644 --- a/src/proto_alpha/lib_protocol/test/pbt/test_sc_rollup_encoding.ml +++ b/src/proto_alpha/lib_protocol/test/pbt/test_sc_rollup_encoding.ml @@ -151,7 +151,7 @@ let gen_inbox_history_proof inbox_level = let* inbox = gen_inbox inbox_level in return (Sc_rollup_inbox_repr.take_snapshot inbox) -let gen_pvm_name = Gen.string_printable +let gen_pvm_name = Gen.oneofl Sc_rollups.Kind.all_names let gen_tick = let open Gen in diff --git a/tezt/tests/expected/sc_rollup.ml/Alpha- arith - participant of a refutation game are slashed-rewarded.out b/tezt/tests/expected/sc_rollup.ml/Alpha- arith - participant of a refutation game are slashed-rewarded.out index b24f7477cb1427cb48478068d932c507a6ba8672..86a9d19a753a700289b914e8721ca09e01cfd457 100644 --- a/tezt/tests/expected/sc_rollup.ml/Alpha- arith - participant of a refutation game are slashed-rewarded.out +++ b/tezt/tests/expected/sc_rollup.ml/Alpha- arith - participant of a refutation game are slashed-rewarded.out @@ -107,7 +107,7 @@ This sequence of operations was run: ./octez-client --wait none timeout dispute on sc rollup '[SC_ROLLUP_HASH]' with '[PUBLIC_KEY_HASH]' from bootstrap1 Node is bootstrapped. -Estimated gas: 6460.944 units (will add 100 for safety) +Estimated gas: 6460.928 units (will add 100 for safety) Estimated storage: no bytes added Operation successfully injected in the node. Operation hash is '[OPERATION_HASH]' @@ -130,7 +130,7 @@ This sequence of operations was run: First staker (Alice): [PUBLIC_KEY_HASH] Second staker (Bob): [PUBLIC_KEY_HASH] This smart contract rollup refutation timeout was successfully applied - Consumed gas: 6460.944 + Consumed gas: 6460.928 Refutation game status: Game ended: [PUBLIC_KEY_HASH] lost because: timeout Balance updates: Frozen_bonds([PUBLIC_KEY_HASH],[SC_ROLLUP_HASH]) ... -ꜩ10000