diff --git a/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml b/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml index 26403517ddc24a514ec1a4de44c86bca1fd1a455..e4e01ac8d505156707f1184c4fa32031696f7210 100644 --- a/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml +++ b/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml @@ -275,9 +275,14 @@ module Make (Interpreter : Interpreter.S) : return (Option.map snd r) in let start_hash, start_tick = ok in - let start_chunk = {state_hash = Some start_hash; tick = start_tick} in + let start_chunk = + Sc_rollup.Dissection_chunk. + {state_hash = Some start_hash; tick = start_tick} + in let start_hash, start_tick = our_view in - let our_stop_chunk = {state_hash = start_hash; tick = start_tick} in + let our_stop_chunk = + Sc_rollup.Dissection_chunk.{state_hash = start_hash; tick = start_tick} + in Game_helpers.new_dissection ~start_chunk ~our_stop_chunk @@ -300,7 +305,8 @@ module Make (Interpreter : Interpreter.S) : tzfail Sc_rollup_node_errors .Unreliable_tezos_node_returning_inconsistent_game - | {state_hash = their_hash; tick} :: dissection -> ( + | Sc_rollup.Dissection_chunk.{state_hash = their_hash; tick} :: dissection + -> ( let open Lwt_result_syntax in let* our = Interpreter.state_of_tick node_ctxt tick game.inbox_level @@ -318,7 +324,7 @@ module Make (Interpreter : Interpreter.S) : else return (ok, (Some our_hash, tick))) in match dissection with - | {state_hash = Some hash; tick} :: dissection -> + | Sc_rollup.Dissection_chunk.{state_hash = Some hash; tick} :: dissection -> let* ok, ko = traverse (hash, tick) dissection in let choice = snd ok in let* dissection = diff --git a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL index 18692907477c7144c702f6e63d4d4efa85aa11ef..2c69fc6bc63169872ebd6235cde7cb1d33514bf5 100644 --- a/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL +++ b/src/proto_alpha/lib_protocol/TEZOS_PROTOCOL @@ -58,6 +58,7 @@ "Sc_rollup_inbox_message_repr", "Sc_rollup_inbox_merkelized_payload_hashes_repr", "Sc_rollup_outbox_message_repr", + "Sc_rollup_dissection_chunk_repr", "Sc_rollup_PVM_sig", "Sc_rollup_arith", "Sc_rollup_wasm", diff --git a/src/proto_alpha/lib_protocol/alpha_context.ml b/src/proto_alpha/lib_protocol/alpha_context.ml index af1cc487e5e2bc4907c54ba992fd3c76bb9ec9bc..9bc93ba4fbd60da1fd40325e9a439dec16ff33a3 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.ml +++ b/src/proto_alpha/lib_protocol/alpha_context.ml @@ -57,6 +57,7 @@ module Sc_rollup = struct module Tick = Sc_rollup_tick_repr include Sc_rollup_repr module Metadata = Sc_rollup_metadata_repr + module Dissection_chunk = Sc_rollup_dissection_chunk_repr include Sc_rollup_PVM_sig module ArithPVM = Sc_rollup_arith module Wasm_2_0_0PVM = Sc_rollup_wasm.V2_0_0 diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 79968e2a575d9a11e8f73f3290e42904d3416fd4..6f0c6573d7bd60f939b4c806f7c537c3e93ac01a 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -3494,6 +3494,39 @@ module Sc_rollup : sig val output_encoding : output Data_encoding.t + module Dissection_chunk : sig + type t = {state_hash : State_hash.t option; tick : Tick.t} + + val equal : t -> t -> bool + + val pp : Format.formatter -> t -> unit + + val default_check : + default_number_of_sections:int -> + start_chunk:t -> + stop_chunk:t -> + t list -> + unit tzresult + + type error += + | Dissection_number_of_sections_mismatch of {expected : Z.t; given : Z.t} + | Dissection_invalid_number_of_sections of Z.t + | Dissection_start_hash_mismatch of { + expected : State_hash.t option; + given : State_hash.t option; + } + | Dissection_stop_hash_mismatch of State_hash.t option + | Dissection_edge_ticks_mismatch of { + dissection_start_tick : Tick.t; + dissection_stop_tick : Tick.t; + chunk_start_tick : Tick.t; + chunk_stop_tick : Tick.t; + } + | Dissection_ticks_not_increasing + | Dissection_invalid_distribution + | Dissection_invalid_successive_states_shape + end + module PVM : sig type boot_sector = string @@ -3855,11 +3888,7 @@ module Sc_rollup : sig val player_encoding : player Data_encoding.t - type dissection_chunk = {state_hash : State_hash.t option; tick : Tick.t} - - val pp_dissection_chunk : Format.formatter -> dissection_chunk -> unit - - val dissection_chunk_encoding : dissection_chunk Data_encoding.t + type dissection_chunk = Dissection_chunk.t type game_state = | Dissecting of { @@ -3956,22 +3985,6 @@ module Sc_rollup : sig type error += | Dissection_choice_not_found of Tick.t - | Dissection_number_of_sections_mismatch of {expected : Z.t; given : Z.t} - | Dissection_invalid_number_of_sections of Z.t - | Dissection_start_hash_mismatch of { - expected : State_hash.t option; - given : State_hash.t option; - } - | Dissection_stop_hash_mismatch of State_hash.t option - | Dissection_edge_ticks_mismatch of { - dissection_start_tick : Tick.t; - dissection_stop_tick : Tick.t; - chunk_start_tick : Tick.t; - chunk_stop_tick : Tick.t; - } - | Dissection_ticks_not_increasing - | Dissection_invalid_distribution - | Dissection_invalid_successive_states_shape | Proof_unexpected_section_size of Z.t | Proof_start_state_hash_mismatch of { start_state_hash : State_hash.t option; diff --git a/src/proto_alpha/lib_protocol/dune b/src/proto_alpha/lib_protocol/dune index 20abfb9615601593796a1b3e834ed374275798a6..699f67a68de8dc9af10a7a8559d21c95b28105b0 100644 --- a/src/proto_alpha/lib_protocol/dune +++ b/src/proto_alpha/lib_protocol/dune @@ -84,6 +84,7 @@ Sc_rollup_inbox_message_repr Sc_rollup_inbox_merkelized_payload_hashes_repr Sc_rollup_outbox_message_repr + Sc_rollup_dissection_chunk_repr Sc_rollup_PVM_sig Sc_rollup_arith Sc_rollup_wasm @@ -357,6 +358,7 @@ sc_rollup_inbox_merkelized_payload_hashes_repr.ml sc_rollup_inbox_merkelized_payload_hashes_repr.mli sc_rollup_outbox_message_repr.ml sc_rollup_outbox_message_repr.mli + sc_rollup_dissection_chunk_repr.ml sc_rollup_dissection_chunk_repr.mli sc_rollup_PVM_sig.ml sc_rollup_arith.ml sc_rollup_arith.mli sc_rollup_wasm.ml sc_rollup_wasm.mli @@ -613,6 +615,7 @@ sc_rollup_inbox_merkelized_payload_hashes_repr.ml sc_rollup_inbox_merkelized_payload_hashes_repr.mli sc_rollup_outbox_message_repr.ml sc_rollup_outbox_message_repr.mli + sc_rollup_dissection_chunk_repr.ml sc_rollup_dissection_chunk_repr.mli sc_rollup_PVM_sig.ml sc_rollup_arith.ml sc_rollup_arith.mli sc_rollup_wasm.ml sc_rollup_wasm.mli @@ -874,6 +877,7 @@ sc_rollup_inbox_merkelized_payload_hashes_repr.ml sc_rollup_inbox_merkelized_payload_hashes_repr.mli sc_rollup_outbox_message_repr.ml sc_rollup_outbox_message_repr.mli + sc_rollup_dissection_chunk_repr.ml sc_rollup_dissection_chunk_repr.mli sc_rollup_PVM_sig.ml sc_rollup_arith.ml sc_rollup_arith.mli sc_rollup_wasm.ml sc_rollup_wasm.mli diff --git a/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.ml b/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.ml new file mode 100644 index 0000000000000000000000000000000000000000..e40e7edc0b2d37237ea45c7441679529b6fde78a --- /dev/null +++ b/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.ml @@ -0,0 +1,312 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* Copyright (c) 2022 Trili Tech, *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +open Sc_rollup_repr + +type t = {state_hash : State_hash.t option; tick : Sc_rollup_tick_repr.t} + +let equal {state_hash; tick} chunk2 = + Option.equal State_hash.equal state_hash chunk2.state_hash + && Sc_rollup_tick_repr.equal tick chunk2.tick + +let encoding = + let open Data_encoding in + conv + (fun {state_hash; tick} -> (state_hash, tick)) + (fun (state_hash, tick) -> {state_hash; tick}) + (obj2 + (opt "state" State_hash.encoding) + (req "tick" Sc_rollup_tick_repr.encoding)) + +type error += + | (* `Temporary *) + Dissection_number_of_sections_mismatch of { + expected : Z.t; + given : Z.t; + } + | (* `Permanent *) Dissection_invalid_number_of_sections of Z.t + | (* `Temporary *) + Dissection_start_hash_mismatch of { + expected : Sc_rollup_repr.State_hash.t option; + given : Sc_rollup_repr.State_hash.t option; + } + | (* `Temporary *) + Dissection_stop_hash_mismatch of + Sc_rollup_repr.State_hash.t option + | (* `Temporary *) + Dissection_edge_ticks_mismatch of { + dissection_start_tick : Sc_rollup_tick_repr.t; + dissection_stop_tick : Sc_rollup_tick_repr.t; + chunk_start_tick : Sc_rollup_tick_repr.t; + chunk_stop_tick : Sc_rollup_tick_repr.t; + } + | (* `Permanent *) Dissection_ticks_not_increasing + | (* `Permanent *) Dissection_invalid_distribution + | (* `Permanent *) Dissection_invalid_successive_states_shape + +let pp_state_hash = + let open Format in + pp_print_option ~none:(fun ppf () -> fprintf ppf "None") State_hash.pp + +let pp_hash_opt fmt = function + | None -> Format.fprintf fmt "None" + | Some x -> Sc_rollup_repr.State_hash.pp fmt x + +let pp ppf {state_hash; tick} = + let open Format in + fprintf + ppf + "State hash:%a@ Tick: %a" + pp_state_hash + state_hash + Sc_rollup_tick_repr.pp + tick + +let default_check ~default_number_of_sections ~start_chunk ~stop_chunk + dissection = + let open Result_syntax in + let len = Z.of_int @@ List.length dissection in + let dist = Sc_rollup_tick_repr.distance start_chunk.tick stop_chunk.tick in + let should_be_equal_to expected = + Dissection_number_of_sections_mismatch {expected; given = len} + in + let num_sections = Z.of_int @@ default_number_of_sections in + let* () = + if Z.geq dist num_sections then + error_unless Z.(equal len num_sections) (should_be_equal_to num_sections) + else if Z.(gt dist one) then + error_unless Z.(equal len (succ dist)) (should_be_equal_to Z.(succ dist)) + else tzfail (Dissection_invalid_number_of_sections len) + in + let* () = + match (List.hd dissection, List.last_opt dissection) with + | Some {state_hash = a; tick = a_tick}, Some {state_hash = b; tick = b_tick} + -> + let* () = + error_unless + (Option.equal State_hash.equal a start_chunk.state_hash + && not (Option.is_none a)) + (Dissection_start_hash_mismatch + {expected = start_chunk.state_hash; given = a}) + in + let* () = + error_unless + (not (Option.equal State_hash.equal b stop_chunk.state_hash)) + ((* If the [b] state is equal to [stop_chunk], that means we + agree on the after state of the section. But, we're trying + to dispute it, it doesn't make sense. *) + Dissection_stop_hash_mismatch + stop_chunk.state_hash) + in + Sc_rollup_tick_repr.( + error_unless + (a_tick = start_chunk.tick && b_tick = stop_chunk.tick) + (Dissection_edge_ticks_mismatch + { + dissection_start_tick = a_tick; + dissection_stop_tick = b_tick; + chunk_start_tick = start_chunk.tick; + chunk_stop_tick = stop_chunk.tick; + })) + | _ -> + (* This case is probably already handled by the + [Dissection_invalid_number_of_sections] returned above *) + tzfail (Dissection_invalid_number_of_sections len) + in + let half_dist = Z.(div dist (of_int 2) |> succ) in + let rec traverse states = + match states with + | {state_hash = None; _} :: {state_hash = Some _; _} :: _ -> + tzfail Dissection_invalid_successive_states_shape + | {tick; _} :: ({tick = next_tick; state_hash = _} as next) :: others -> + if Sc_rollup_tick_repr.(tick < next_tick) then + let incr = Sc_rollup_tick_repr.distance tick next_tick in + if Z.(leq incr half_dist) then traverse (next :: others) + else tzfail Dissection_invalid_distribution + else tzfail Dissection_ticks_not_increasing + | _ -> return () + in + traverse dissection + +let () = + let description = "Mismatch in the number of sections in the dissection" in + register_error_kind + `Temporary + ~id:"Dissection_number_of_sections_mismatch" + ~title:description + ~description + ~pp:(fun ppf (expected, given) -> + Format.fprintf + ppf + "The number of sections must be equal to %a instead of %a" + Z.pp_print + expected + Z.pp_print + given) + Data_encoding.(obj2 (req "expected" n) (req "given" n)) + (function + | Dissection_number_of_sections_mismatch {expected; given} -> + Some (expected, given) + | _ -> None) + (fun (expected, given) -> + Dissection_number_of_sections_mismatch {expected; given}) ; + let description = "Invalid number of sections in the dissection" in + register_error_kind + `Permanent + ~id:"Dissection_invalid_number_of_sections" + ~title:description + ~description + ~pp:(fun ppf n -> + Format.fprintf + ppf + "A dissection with %a sections can never be valid" + Z.pp_print + n) + Data_encoding.(obj1 (req "value" n)) + (function Dissection_invalid_number_of_sections n -> Some n | _ -> None) + (fun n -> Dissection_invalid_number_of_sections n) ; + let description = "Mismatch in the start hash of the dissection" in + register_error_kind + `Temporary + ~id:"Dissection_start_hash_mismatch" + ~title:description + ~description + ~pp:(fun ppf (given, expected) -> + match given with + | None -> Format.fprintf ppf "The start hash must not be None" + | Some _ -> + Format.fprintf + ppf + "The start hash should be equal to %a, but the provided hash is %a" + pp_hash_opt + expected + pp_hash_opt + given) + Data_encoding.( + obj2 + (req "expected" (option Sc_rollup_repr.State_hash.encoding)) + (req "given" (option Sc_rollup_repr.State_hash.encoding))) + (function + | Dissection_start_hash_mismatch {expected; given} -> + Some (expected, given) + | _ -> None) + (fun (expected, given) -> Dissection_start_hash_mismatch {expected; given}) ; + let description = "Mismatch in the stop hash of the dissection" in + register_error_kind + `Temporary + ~id:"Dissection_stop_hash_mismatch" + ~title:description + ~description + ~pp:(fun ppf h -> + Format.fprintf ppf "The stop hash should not be equal to %a" pp_hash_opt h) + Data_encoding.( + obj1 (req "hash" (option Sc_rollup_repr.State_hash.encoding))) + (function Dissection_stop_hash_mismatch hopt -> Some hopt | _ -> None) + (fun hopt -> Dissection_stop_hash_mismatch hopt) ; + let description = "Mismatch in the edge ticks of the dissection" in + register_error_kind + `Temporary + ~id:"Dissection_edge_ticks_mismatch" + ~title:description + ~description + ~pp: + (fun ppf + ( dissection_start_tick, + dissection_stop_tick, + chunk_start_tick, + chunk_stop_tick ) -> + Sc_rollup_tick_repr.( + Format.fprintf + ppf + "We should have dissection_start_tick(%a) = %a and \ + dissection_stop_tick(%a) = %a" + pp + dissection_start_tick + pp + chunk_start_tick + pp + dissection_stop_tick + pp + chunk_stop_tick)) + Data_encoding.( + obj4 + (req "dissection_start_tick" Sc_rollup_tick_repr.encoding) + (req "dissection_stop_tick" Sc_rollup_tick_repr.encoding) + (req "chunk_start_tick" Sc_rollup_tick_repr.encoding) + (req "chunk_stop_tick" Sc_rollup_tick_repr.encoding)) + (function + | Dissection_edge_ticks_mismatch e -> + Some + ( e.dissection_start_tick, + e.dissection_stop_tick, + e.chunk_start_tick, + e.chunk_stop_tick ) + | _ -> None) + (fun ( dissection_start_tick, + dissection_stop_tick, + chunk_start_tick, + chunk_stop_tick ) -> + Dissection_edge_ticks_mismatch + { + dissection_start_tick; + dissection_stop_tick; + chunk_start_tick; + chunk_stop_tick; + }) ; + let description = "Ticks should only increase in dissection" in + register_error_kind + `Permanent + ~id:"Dissection_ticks_not_increasing" + ~title:description + ~description + ~pp:(fun ppf () -> Format.pp_print_string ppf description) + Data_encoding.empty + (function Dissection_ticks_not_increasing -> Some () | _ -> None) + (fun () -> Dissection_ticks_not_increasing) ; + let description = + "Maximum tick increment in a section cannot be more than half total \ + dissection length" + in + register_error_kind + `Permanent + ~id:"Dissection_invalid_distribution" + ~title:description + ~description + ~pp:(fun ppf () -> Format.pp_print_string ppf description) + Data_encoding.empty + (function Dissection_invalid_distribution -> Some () | _ -> None) + (fun () -> Dissection_invalid_distribution) ; + let description = "Cannot recover from a blocked state in a dissection" in + register_error_kind + `Permanent + ~id:"Dissection_invalid_successive_states_shape" + ~title:description + ~description + ~pp:(fun ppf () -> Format.pp_print_string ppf description) + Data_encoding.empty + (function + | Dissection_invalid_successive_states_shape -> Some () | _ -> None) + (fun () -> Dissection_invalid_successive_states_shape) diff --git a/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.mli b/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.mli new file mode 100644 index 0000000000000000000000000000000000000000..c3d80e6ebd4c9aa25969e4ad8aeb7c616c78195f --- /dev/null +++ b/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.mli @@ -0,0 +1,96 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2021 Nomadic Labs *) +(* Copyright (c) 2022 Trili Tech, *) +(* *) +(* Permission is hereby granted, free of charge, to any person obtaining a *) +(* copy of this software and associated documentation files (the "Software"),*) +(* to deal in the Software without restriction, including without limitation *) +(* the rights to use, copy, modify, merge, publish, distribute, sublicense, *) +(* and/or sell copies of the Software, and to permit persons to whom the *) +(* Software is furnished to do so, subject to the following conditions: *) +(* *) +(* The above copyright notice and this permission notice shall be included *) +(* in all copies or substantial portions of the Software. *) +(* *) +(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR*) +(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *) +(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *) +(* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER*) +(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *) +(* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *) +(* DEALINGS IN THE SOFTWARE. *) +(* *) +(*****************************************************************************) + +open Sc_rollup_repr + +(** A dissection chunk is made of an optional state hash, and a tick count. *) +type t = {state_hash : State_hash.t option; tick : Sc_rollup_tick_repr.t} + +val equal : t -> t -> bool + +val pp : Format.formatter -> t -> unit + +val encoding : t Data_encoding.t + +(** We check firstly that [dissection] is the correct length. It must + be [default_number_of_sections] values long, unless the distance + between [start_tick] and [stop_tick] is too small to make this + possible, in which case it should be as long as possible. (If the + distance is one we fail immediately as there is no possible legal + dissection). + + Then we check that [dissection] starts at the correct tick and + state (specified by [start_chunk]), and that it ends at + [stop_chunk], at the correct tick and with a different state to + the current dissection. + + Finally, we check that [dissection] is well formed: it has + correctly ordered the ticks, and it begins with a real hash of the + form [Some s] not a [None] state. Note that we have to allow the + possibility of multiple [None] states because the restrictions on + dissection shape (which are necessary to prevent a 'linear-time + game' attack) will mean that sometimes the honest play is a + dissection with multiple [None] states. *) +val default_check : + default_number_of_sections:int -> + start_chunk:t -> + stop_chunk:t -> + t list -> + unit tzresult + +type error += + | Dissection_number_of_sections_mismatch of {expected : Z.t; given : Z.t} + (** There are more or less than the expected number of sections in the + given dissection. *) + | Dissection_invalid_number_of_sections of Z.t + (** There are less than two sections in the given dissection, which is + not valid. *) + | Dissection_start_hash_mismatch of { + expected : Sc_rollup_repr.State_hash.t option; + given : Sc_rollup_repr.State_hash.t option; + } + (** The given start hash in a dissection is [None] or doesn't match the + expected one.*) + | Dissection_stop_hash_mismatch of Sc_rollup_repr.State_hash.t option + (** The given stop state hash in a dissection should not match the last + hash of the section being refuted. *) + | Dissection_edge_ticks_mismatch of { + dissection_start_tick : Sc_rollup_tick_repr.t; + dissection_stop_tick : Sc_rollup_tick_repr.t; + chunk_start_tick : Sc_rollup_tick_repr.t; + chunk_stop_tick : Sc_rollup_tick_repr.t; + } + (** The given dissection's edge ticks don't match the edge ticks of the + section being refuted. *) + | Dissection_ticks_not_increasing + (** Invalid provided dissection because ticks are not increasing between + two successive sections. *) + | Dissection_invalid_distribution + (** Invalid provided dissection because ticks split is not well balanced + across sections *) + | Dissection_invalid_successive_states_shape + (** A dissection cannot have a section with no state hash after another + section with some state hash. *) 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 8c8b4016c31706b1068dd3d6248a52cd62011357..54e5356ec5cf4555501e8b839f0ac30e52b93eea 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml @@ -31,30 +31,6 @@ open Sc_rollup_repr type error += | (* `Temporary *) Dissection_choice_not_found of Sc_rollup_tick_repr.t - | (* `Temporary *) - Dissection_number_of_sections_mismatch of { - expected : Z.t; - given : Z.t; - } - | (* `Permanent *) Dissection_invalid_number_of_sections of Z.t - | (* `Temporary *) - Dissection_start_hash_mismatch of { - expected : Sc_rollup_repr.State_hash.t option; - given : Sc_rollup_repr.State_hash.t option; - } - | (* `Temporary *) - Dissection_stop_hash_mismatch of - Sc_rollup_repr.State_hash.t option - | (* `Temporary *) - Dissection_edge_ticks_mismatch of { - dissection_start_tick : Sc_rollup_tick_repr.t; - dissection_stop_tick : Sc_rollup_tick_repr.t; - chunk_start_tick : Sc_rollup_tick_repr.t; - chunk_stop_tick : Sc_rollup_tick_repr.t; - } - | (* `Permanent *) Dissection_ticks_not_increasing - | (* `Permanent *) Dissection_invalid_distribution - | (* `Permanent *) Dissection_invalid_successive_states_shape | (* `Permanent *) Proof_unexpected_section_size of Z.t | (* `Temporary *) Proof_start_state_hash_mismatch of { @@ -93,164 +69,6 @@ let () = Data_encoding.(obj1 (req "choice" Sc_rollup_tick_repr.encoding)) (function Dissection_choice_not_found tick -> Some tick | _ -> None) (fun tick -> Dissection_choice_not_found tick) ; - let description = "Mismatch in the number of sections in the dissection" in - register_error_kind - `Temporary - ~id:"Dissection_number_of_sections_mismatch" - ~title:description - ~description - ~pp:(fun ppf (expected, given) -> - Format.fprintf - ppf - "The number of sections must be equal to %a instead of %a" - Z.pp_print - expected - Z.pp_print - given) - Data_encoding.(obj2 (req "expected" n) (req "given" n)) - (function - | Dissection_number_of_sections_mismatch {expected; given} -> - Some (expected, given) - | _ -> None) - (fun (expected, given) -> - Dissection_number_of_sections_mismatch {expected; given}) ; - let description = "Invalid number of sections in the dissection" in - register_error_kind - `Permanent - ~id:"Dissection_invalid_number_of_sections" - ~title:description - ~description - ~pp:(fun ppf n -> - Format.fprintf - ppf - "A dissection with %a sections can never be valid" - Z.pp_print - n) - Data_encoding.(obj1 (req "value" n)) - (function Dissection_invalid_number_of_sections n -> Some n | _ -> None) - (fun n -> Dissection_invalid_number_of_sections n) ; - let description = "Mismatch in the start hash of the dissection" in - register_error_kind - `Temporary - ~id:"Dissection_start_hash_mismatch" - ~title:description - ~description - ~pp:(fun ppf (given, expected) -> - match given with - | None -> Format.fprintf ppf "The start hash must not be None" - | Some _ -> - Format.fprintf - ppf - "The start hash should be equal to %a, but the provided hash is %a" - pp_hash_opt - expected - pp_hash_opt - given) - Data_encoding.( - obj2 - (req "expected" (option Sc_rollup_repr.State_hash.encoding)) - (req "given" (option Sc_rollup_repr.State_hash.encoding))) - (function - | Dissection_start_hash_mismatch {expected; given} -> - Some (expected, given) - | _ -> None) - (fun (expected, given) -> Dissection_start_hash_mismatch {expected; given}) ; - let description = "Mismatch in the stop hash of the dissection" in - register_error_kind - `Temporary - ~id:"Dissection_stop_hash_mismatch" - ~title:description - ~description - ~pp:(fun ppf h -> - Format.fprintf ppf "The stop hash should not be equal to %a" pp_hash_opt h) - Data_encoding.( - obj1 (req "hash" (option Sc_rollup_repr.State_hash.encoding))) - (function Dissection_stop_hash_mismatch hopt -> Some hopt | _ -> None) - (fun hopt -> Dissection_stop_hash_mismatch hopt) ; - let description = "Mismatch in the edge ticks of the dissection" in - register_error_kind - `Temporary - ~id:"Dissection_edge_ticks_mismatch" - ~title:description - ~description - ~pp: - (fun ppf - ( dissection_start_tick, - dissection_stop_tick, - chunk_start_tick, - chunk_stop_tick ) -> - Sc_rollup_tick_repr.( - Format.fprintf - ppf - "We should have dissection_start_tick(%a) = %a and \ - dissection_stop_tick(%a) = %a" - pp - dissection_start_tick - pp - chunk_start_tick - pp - dissection_stop_tick - pp - chunk_stop_tick)) - Data_encoding.( - obj4 - (req "dissection_start_tick" Sc_rollup_tick_repr.encoding) - (req "dissection_stop_tick" Sc_rollup_tick_repr.encoding) - (req "chunk_start_tick" Sc_rollup_tick_repr.encoding) - (req "chunk_stop_tick" Sc_rollup_tick_repr.encoding)) - (function - | Dissection_edge_ticks_mismatch e -> - Some - ( e.dissection_start_tick, - e.dissection_stop_tick, - e.chunk_start_tick, - e.chunk_stop_tick ) - | _ -> None) - (fun ( dissection_start_tick, - dissection_stop_tick, - chunk_start_tick, - chunk_stop_tick ) -> - Dissection_edge_ticks_mismatch - { - dissection_start_tick; - dissection_stop_tick; - chunk_start_tick; - chunk_stop_tick; - }) ; - let description = "Ticks should only increase in dissection" in - register_error_kind - `Permanent - ~id:"Dissection_ticks_not_increasing" - ~title:description - ~description - ~pp:(fun ppf () -> Format.pp_print_string ppf description) - Data_encoding.empty - (function Dissection_ticks_not_increasing -> Some () | _ -> None) - (fun () -> Dissection_ticks_not_increasing) ; - let description = - "Maximum tick increment in a section cannot be more than half total \ - dissection length" - in - register_error_kind - `Permanent - ~id:"Dissection_invalid_distribution" - ~title:description - ~description - ~pp:(fun ppf () -> Format.pp_print_string ppf description) - Data_encoding.empty - (function Dissection_invalid_distribution -> Some () | _ -> None) - (fun () -> Dissection_invalid_distribution) ; - let description = "Cannot recover from a blocked state in a dissection" in - register_error_kind - `Permanent - ~id:"Dissection_invalid_successive_states_shape" - ~title:description - ~description - ~pp:(fun ppf () -> Format.pp_print_string ppf description) - Data_encoding.empty - (function - | Dissection_invalid_successive_states_shape -> Some () | _ -> None) - (fun () -> Dissection_invalid_successive_states_shape) ; let description = "The distance for a proof should be equal to 1" in register_error_kind `Permanent @@ -354,25 +172,11 @@ let () = type player = Alice | Bob module V1 = struct - type dissection_chunk = { + type dissection_chunk = Sc_rollup_dissection_chunk_repr.t = { state_hash : State_hash.t option; tick : Sc_rollup_tick_repr.t; } - let pp_state_hash = - let open Format in - pp_print_option ~none:(fun ppf () -> fprintf ppf "None") State_hash.pp - - let pp_dissection_chunk ppf {state_hash; tick} = - let open Format in - fprintf - ppf - "State hash:%a@ Tick: %a" - pp_state_hash - state_hash - Sc_rollup_tick_repr.pp - tick - type game_state = | Dissecting of { dissection : dissection_chunk list; @@ -418,10 +222,6 @@ module V1 = struct | Bob, Bob -> true | _, _ -> false - let dissection_chunk_equal {state_hash; tick} chunk2 = - Option.equal State_hash.equal state_hash chunk2.state_hash - && Sc_rollup_tick_repr.equal tick chunk2.tick - let game_state_equal gs1 gs2 = match (gs1, gs2) with | ( Dissecting @@ -437,7 +237,10 @@ module V1 = struct Compare.Int.equal default_number_of_sections1 default_number_of_sections2 - && List.equal dissection_chunk_equal dissection1 dissection2 + && List.equal + Sc_rollup_dissection_chunk_repr.equal + dissection1 + dissection2 | Dissecting _, _ -> false | ( Final_move { @@ -449,8 +252,12 @@ module V1 = struct agreed_start_chunk = agreed_start_chunk2; refuted_stop_chunk = refuted_stop_chunk2; } ) -> - dissection_chunk_equal agreed_start_chunk1 agreed_start_chunk2 - && dissection_chunk_equal refuted_stop_chunk1 refuted_stop_chunk2 + Sc_rollup_dissection_chunk_repr.equal + agreed_start_chunk1 + agreed_start_chunk2 + && Sc_rollup_dissection_chunk_repr.equal + refuted_stop_chunk1 + refuted_stop_chunk2 | Final_move _, _ -> false let equal @@ -478,18 +285,9 @@ module V1 = struct let opponent = function Alice -> Bob | Bob -> Alice - let dissection_chunk_encoding = - let open Data_encoding in - conv - (fun {state_hash; tick} -> (state_hash, tick)) - (fun (state_hash, tick) -> {state_hash; tick}) - (obj2 - (opt "state" State_hash.encoding) - (req "tick" Sc_rollup_tick_repr.encoding)) - let dissection_encoding = let open Data_encoding in - list dissection_chunk_encoding + list Sc_rollup_dissection_chunk_repr.encoding let game_state_encoding = let open Data_encoding in @@ -514,8 +312,8 @@ module V1 = struct (Tag 1) (obj3 (req "kind" (constant "Final_move")) - (req "agreed_start_chunk" dissection_chunk_encoding) - (req "refuted_stop_chunk" dissection_chunk_encoding)) + (req "agreed_start_chunk" Sc_rollup_dissection_chunk_repr.encoding) + (req "refuted_stop_chunk" Sc_rollup_dissection_chunk_repr.encoding)) (function | Final_move {agreed_start_chunk; refuted_stop_chunk} -> Some ((), agreed_start_chunk, refuted_stop_chunk) @@ -571,7 +369,7 @@ module V1 = struct let pp_dissection ppf d = Format.pp_print_list ~pp_sep:(fun ppf () -> Format.pp_print_string ppf ";\n") - pp_dissection_chunk + Sc_rollup_dissection_chunk_repr.pp ppf d @@ -589,9 +387,9 @@ module V1 = struct fprintf ppf "Final move to refute %a from %a, opponent failed to refute" - pp_dissection_chunk + Sc_rollup_dissection_chunk_repr.pp agreed_start_chunk - pp_dissection_chunk + Sc_rollup_dissection_chunk_repr.pp refuted_stop_chunk let pp ppf game = @@ -875,72 +673,6 @@ let find_choice dissection tick = in traverse dissection -let check_dissection ~default_number_of_sections ~start_chunk ~stop_chunk - dissection = - let open Result_syntax in - let len = Z.of_int @@ List.length dissection in - let dist = Sc_rollup_tick_repr.distance start_chunk.tick stop_chunk.tick in - let should_be_equal_to expected = - Dissection_number_of_sections_mismatch {expected; given = len} - in - let num_sections = Z.of_int @@ default_number_of_sections in - let* () = - if Z.geq dist num_sections then - error_unless Z.(equal len num_sections) (should_be_equal_to num_sections) - else if Z.(gt dist one) then - error_unless Z.(equal len (succ dist)) (should_be_equal_to Z.(succ dist)) - else tzfail (Dissection_invalid_number_of_sections len) - in - let* () = - match (List.hd dissection, List.last_opt dissection) with - | Some {state_hash = a; tick = a_tick}, Some {state_hash = b; tick = b_tick} - -> - let* () = - error_unless - (Option.equal State_hash.equal a start_chunk.state_hash - && not (Option.is_none a)) - (Dissection_start_hash_mismatch - {expected = start_chunk.state_hash; given = a}) - in - let* () = - error_unless - (not (Option.equal State_hash.equal b stop_chunk.state_hash)) - ((* If the [b] state is equal to [stop_chunk], that means we - agree on the after state of the section. But, we're trying - to dispute it, it doesn't make sense. *) - Dissection_stop_hash_mismatch - stop_chunk.state_hash) - in - Sc_rollup_tick_repr.( - error_unless - (a_tick = start_chunk.tick && b_tick = stop_chunk.tick) - (Dissection_edge_ticks_mismatch - { - dissection_start_tick = a_tick; - dissection_stop_tick = b_tick; - chunk_start_tick = start_chunk.tick; - chunk_stop_tick = stop_chunk.tick; - })) - | _ -> - (* This case is probably already handled by the - [Dissection_invalid_number_of_sections] returned above *) - tzfail (Dissection_invalid_number_of_sections len) - in - let half_dist = Z.(div dist (of_int 2) |> succ) in - let rec traverse states = - match states with - | {state_hash = None; _} :: {state_hash = Some _; _} :: _ -> - tzfail Dissection_invalid_successive_states_shape - | {tick; _} :: ({tick = next_tick; state_hash = _} as next) :: others -> - if Sc_rollup_tick_repr.(tick < next_tick) then - let incr = Sc_rollup_tick_repr.distance tick next_tick in - if Z.(leq incr half_dist) then traverse (next :: others) - else tzfail Dissection_invalid_distribution - else tzfail Dissection_ticks_not_increasing - | _ -> return () - in - traverse dissection - (** Check that the chosen interval is a single tick. *) let check_proof_distance_is_one ~start_tick ~stop_tick = let dist = Sc_rollup_tick_repr.distance start_tick stop_tick in @@ -1097,7 +829,7 @@ let play dal_parameters ~dal_attestation_lag ~stakers metadata game refutation = find_choice dissection refutation.choice in let*? () = - check_dissection + Sc_rollup_dissection_chunk_repr.default_check ~default_number_of_sections ~start_chunk ~stop_chunk @@ -1171,7 +903,7 @@ let play dal_parameters ~dal_attestation_lag ~stakers metadata game refutation = module Internal_for_tests = struct let find_choice = find_choice - let check_dissection = check_dissection + let check_dissection = Sc_rollup_dissection_chunk_repr.default_check end type timeout = {alice : int; bob : int; last_turn_level : Raw_level_repr.t} diff --git a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.mli b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.mli index 5e376ea11f0fb11d3c4c3da4a8c8ba243702c878..ac447a1266619a5b77aed4cbb0155ffac23dfb1b 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.mli @@ -126,38 +126,6 @@ type error += | Dissection_choice_not_found of Sc_rollup_tick_repr.t (** The given choice in a refutation is not a starting tick of any of the sections in the current dissection. *) - | Dissection_number_of_sections_mismatch of {expected : Z.t; given : Z.t} - (** There are more or less than the expected number of sections in the - given dissection. *) - | Dissection_invalid_number_of_sections of Z.t - (** There are less than two sections in the given dissection, which is - not valid. *) - | Dissection_start_hash_mismatch of { - expected : Sc_rollup_repr.State_hash.t option; - given : Sc_rollup_repr.State_hash.t option; - } - (** The given start hash in a dissection is [None] or doesn't match the - expected one.*) - | Dissection_stop_hash_mismatch of Sc_rollup_repr.State_hash.t option - (** The given stop state hash in a dissection should not match the last - hash of the section being refuted. *) - | Dissection_edge_ticks_mismatch of { - dissection_start_tick : Sc_rollup_tick_repr.t; - dissection_stop_tick : Sc_rollup_tick_repr.t; - chunk_start_tick : Sc_rollup_tick_repr.t; - chunk_stop_tick : Sc_rollup_tick_repr.t; - } - (** The given dissection's edge ticks don't match the edge ticks of the - section being refuted. *) - | Dissection_ticks_not_increasing - (** Invalid provided dissection because ticks are not increasing between - two successive sections. *) - | Dissection_invalid_distribution - (** Invalid provided dissection because ticks split is not well balanced - across sections *) - | Dissection_invalid_successive_states_shape - (** A dissection cannot have a section with no state hash after another - section with some state hash. *) | Proof_unexpected_section_size of Z.t (** Invalid proof step because there is more than one tick. *) | Proof_start_state_hash_mismatch of { @@ -187,16 +155,7 @@ type error += type player = Alice | Bob module V1 : sig - (** A dissection chunk is made of a state hash (that could be [None], see - invariants below), and a tick count. *) - type dissection_chunk = { - state_hash : State_hash.t option; - tick : Sc_rollup_tick_repr.t; - } - - val pp_dissection_chunk : Format.formatter -> dissection_chunk -> unit - - val dissection_chunk_encoding : dissection_chunk Data_encoding.t + type dissection_chunk = Sc_rollup_dissection_chunk_repr.t (** Describes the current state of a game. *) type game_state = @@ -461,23 +420,7 @@ module Internal_for_tests : sig Sc_rollup_tick_repr.t -> (dissection_chunk * dissection_chunk) tzresult - (** We check firstly that [dissection] is the correct length. It must be - [default_number_of_sections] values long, unless the distance between - [start_tick] and [stop_tick] is too small to make this possible, in which - case it should be as long as possible. (If the distance is one we fail - immediately as there is no possible legal dissection). - - Then we check that [dissection] starts at the correct tick and state, - and that it ends at the correct tick and with a different state to - the current dissection. - - Finally, we check that [dissection] is well formed: it has correctly - ordered the ticks, and it begins with a real hash of the form [Some - s] not a [None] state. Note that we have to allow the possibility of - multiple [None] states because the restrictions on dissection shape - (which are necessary to prevent a 'linear-time game' attack) will - mean that sometimes the honest play is a dissection with multiple - [None] states. *) + (** See {!Sc_rollup_dissection_chunk_repr.default_check} *) val check_dissection : default_number_of_sections:int -> start_chunk:dissection_chunk -> diff --git a/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml b/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml index a5f2586b4b5573e4f372d081ecf88be149a4ff39..df975ae634ab4da92a9a3c3446b7793ae72edb08 100644 --- a/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml +++ b/src/proto_alpha/lib_protocol/test/integration/operations/test_sc_rollup.ml @@ -1641,7 +1641,7 @@ let test_timeout () = Context.Sc_rollup.commitment (B block) rollup genesis_info.commitment_hash in let first_chunk = - Sc_rollup.Game.{state_hash = Some compressed_state; tick} + Sc_rollup.Dissection_chunk.{state_hash = Some compressed_state; tick} in let* rest = List.init_es ~when_negative_length:[] 4 (fun i -> @@ -1651,7 +1651,7 @@ let test_timeout () = ~loc:__LOC__ (Sc_rollup.Tick.of_int (i + 1)) in - return Sc_rollup.Game.{state_hash; tick}) + return Sc_rollup.Dissection_chunk.{state_hash; tick}) in let step = Sc_rollup.Game.Dissection (first_chunk :: rest) in let move = Sc_rollup.Game.{choice = tick; step} in diff --git a/src/proto_alpha/lib_protocol/test/pbt/test_refutation_game.ml b/src/proto_alpha/lib_protocol/test/pbt/test_refutation_game.ml index 908db413b6adb25d5b41adc9f3a83751dbe61a2a..4f9e11cd24fb2b5a446f23ed36c9a0490fc5e660 100644 --- a/src/proto_alpha/lib_protocol/test/pbt/test_refutation_game.ml +++ b/src/proto_alpha/lib_protocol/test/pbt/test_refutation_game.ml @@ -79,7 +79,7 @@ let game_status_of_refute_op_result = function let list_assoc (key : Tick.t) list = List.assoc ~equal:( = ) key list -let print_dissection_chunk = Format.asprintf "%a" Game.pp_dissection_chunk +let print_dissection_chunk = Format.asprintf "%a" Dissection_chunk.pp let print_dissection = Format.asprintf "%a" Game.pp_dissection @@ -138,13 +138,13 @@ let valid_dissection ~default_number_of_sections ~start_chunk ~stop_chunk It uses [our_states], an assoc list between tick and state hashes to compare opponent's claims against our point of view. *) let disputed_sections ~our_states dissection = - let open Game in let agree_on_state tick their_state = let our_state = list_assoc tick our_states in Option.equal State_hash.equal our_state their_state in let rec traverse acc = function - | ({state_hash = their_start_state; tick = start_tick} as a) + | Dissection_chunk.( + {state_hash = their_start_state; tick = start_tick} as a) :: ({state_hash = their_stop_state; tick = stop_tick} as b) :: dissection -> let rst = b :: dissection in @@ -166,7 +166,9 @@ let pick_disputed_sections disputed_sections = let single_tick_disputed_sections disputed_sections = List.filter_map (fun disputed_section -> - let Game.({tick = a_tick; _}, {tick = b_tick; _}) = disputed_section in + let Dissection_chunk.({tick = a_tick; _}, {tick = b_tick; _}) = + disputed_section + in let distance = Tick.distance a_tick b_tick in if Z.Compare.(distance = Z.one) then Some disputed_section else None) disputed_sections @@ -184,7 +186,8 @@ let build_dissection ~number_of_sections ~start_chunk ~stop_chunk ~our_states = let open Lwt_result_syntax in let state_hash_from_tick tick = return @@ list_assoc tick our_states in let our_stop_chunk = - Game.{stop_chunk with state_hash = list_assoc stop_chunk.tick our_states} + Dissection_chunk. + {stop_chunk with state_hash = list_assoc stop_chunk.tick our_states} in (* TODO: https://gitlab.com/tezos/tezos/-/issues/3491 @@ -345,16 +348,16 @@ module Dissection = struct if Z.Compare.(ticks = Z.zero) then pure [ - Game.{state_hash = Some child_state; tick = initial_tick}; - Game.{state_hash = None; tick = Tick.next initial_tick}; + Dissection_chunk.{state_hash = Some child_state; tick = initial_tick}; + Dissection_chunk.{state_hash = None; tick = Tick.next initial_tick}; ] else let tick = Tick.jump initial_tick ticks in pure [ - Game.{state_hash = Some parent_state; tick = initial_tick}; - Game.{state_hash = Some child_state; tick}; - Game.{state_hash = None; tick = Tick.next tick}; + Dissection_chunk.{state_hash = Some parent_state; tick = initial_tick}; + Dissection_chunk.{state_hash = Some child_state; tick}; + Dissection_chunk.{state_hash = None; tick = Tick.next tick}; ] (** Generate a *valid* dissection. @@ -382,7 +385,8 @@ module Dissection = struct you disagree with some sections. *) let gen_our_states start_chunk ticks = let open QCheck2.Gen in - let Game.{tick = initial_tick; state_hash = initial_state_hash} = + let Dissection_chunk.{tick = initial_tick; state_hash = initial_state_hash} + = start_chunk in let initial_state_hash = @@ -474,7 +478,7 @@ module Dissection = struct in let expected_len = Z.of_int expected_number_of_sections in let expected_reason = - Game.Dissection_number_of_sections_mismatch + Dissection_chunk.Dissection_number_of_sections_mismatch {expected = expected_len; given = Z.pred expected_len} in assert_fails_with @@ -581,7 +585,8 @@ module Dissection = struct (* Check that we can not change the start hash. *) let dissection_with_different_start = modify_start - (fun chunk -> Game.{chunk with state_hash = Some new_state_hash}) + (fun chunk -> + Dissection_chunk.{chunk with state_hash = Some new_state_hash}) dissection in assert_fails_with @@ -591,7 +596,7 @@ module Dissection = struct ~start_chunk ~stop_chunk dissection_with_different_start) - (Game.Dissection_start_hash_mismatch + (Dissection_chunk.Dissection_start_hash_mismatch {expected = start_chunk.state_hash; given = Some new_state_hash})) (** Test that we can not produce a dissection that agrees with the stop hash. @@ -618,10 +623,13 @@ module Dissection = struct let check_failure_on_same_stop_hash stop_hash = let invalid_dissection = modify_stop - (fun chunk -> Game.{chunk with state_hash = stop_hash}) + (fun chunk -> + Dissection_chunk.{chunk with state_hash = stop_hash}) dissection in - let stop_chunk = Game.{stop_chunk with state_hash = stop_hash} in + let stop_chunk = + Dissection_chunk.{stop_chunk with state_hash = stop_hash} + in assert_fails_with ~__LOC__ (Game.Internal_for_tests.check_dissection @@ -629,7 +637,7 @@ module Dissection = struct ~start_chunk ~stop_chunk invalid_dissection) - (Game.Dissection_stop_hash_mismatch stop_hash) + (Dissection_chunk.Dissection_stop_hash_mismatch stop_hash) in let* b1 = check_failure_on_same_stop_hash None in let* b2 = check_failure_on_same_stop_hash stop_chunk.state_hash in @@ -659,8 +667,8 @@ module Dissection = struct let open Lwt_syntax in let expected_error dissection = match (List.hd dissection, List.last_opt dissection) with - | Some Game.{tick = a_tick; _}, Some {tick = b_tick; _} -> - Game.Dissection_edge_ticks_mismatch + | Some Dissection_chunk.{tick = a_tick; _}, Some {tick = b_tick; _} -> + Dissection_chunk.Dissection_edge_ticks_mismatch { dissection_start_tick = a_tick; dissection_stop_tick = b_tick; @@ -672,7 +680,8 @@ module Dissection = struct let modify_tick modify_X dissection = let invalid_dissection = modify_X - (fun chunk -> Game.{chunk with tick = Tick.next chunk.tick}) + (fun chunk -> + Dissection_chunk.{chunk with tick = Tick.next chunk.tick}) dissection in let expected_error = expected_error invalid_dissection in @@ -747,10 +756,10 @@ module Dissection = struct let b, tick = if k = 0 then let tick = Tick.jump tick max_section_length in - (Game.{b with tick}, tick) + (Dissection_chunk.{b with tick}, tick) else let tick = Tick.jump tick section_length in - (Game.{b with tick}, tick) + (Dissection_chunk.{b with tick}, tick) in a :: replace_distances tick (k - 1) (b :: xs) | xs -> xs @@ -765,7 +774,7 @@ module Dissection = struct ~start_chunk ~stop_chunk invalid_dissection) - Game.Dissection_invalid_distribution) + Dissection_chunk.Dissection_invalid_distribution) let tests = ( "Dissection", 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 c0d3ad9ded5b85608e2788230880622f2668c008..5100b83a4962646261c9d1e1cb6f6eafc2e666e4 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 @@ -167,7 +167,7 @@ let gen_dissection_chunk = let open Gen in let* state_hash = opt gen_state_hash in let+ tick = gen_tick in - Sc_rollup_game_repr.{state_hash; tick} + Sc_rollup_dissection_chunk_repr.{state_hash; tick} let gen_dissection = let open Gen in diff --git a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_game.ml b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_game.ml index 297265697a2ea8f64adad42d32e1114f8a3c8e90..1cfb6041d6e7939839eade055ce1b44100e16449 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_game.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_game.ml @@ -37,6 +37,7 @@ open Lwt_result_syntax module Commitment_repr = Sc_rollup_commitment_repr module T = Test_sc_rollup_storage module R = Sc_rollup_refutation_storage +module D = Sc_rollup_dissection_chunk_repr module G = Sc_rollup_game_repr module Tick = Sc_rollup_tick_repr @@ -56,7 +57,7 @@ let hash_string s = let hash_int n = hash_string (Format.sprintf "%d" n) -let mk_dissection_chunk (state_hash, tick) = G.{state_hash; tick} +let mk_dissection_chunk (state_hash, tick) = D.{state_hash; tick} let init_dissection ~size ?init_tick start_hash = let default_init_tick i = @@ -156,7 +157,7 @@ let test_poorly_distributed_dissection () = assert_fails_with ~__LOC__ (T.lift @@ R.game_move ctxt rollup ~player:refuter ~opponent:defender move) - Sc_rollup_game_repr.Dissection_invalid_distribution + D.Dissection_invalid_distribution let test_single_valid_game_move () = let* ctxt, rollup, refuter, defender = two_stakers_in_conflict () in