diff --git a/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml b/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml index 881417dcc1d31c778a3fe4e945eb363d04bd1baa..1dcc6681f7accc7454da7452d7608e999689b9dc 100644 --- a/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml +++ b/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml @@ -52,6 +52,8 @@ module Impl : Pvm.S = struct module State = Context.PVMState + let new_dissection = Game_helpers.default_new_dissection + let string_of_status status = match status with | Halted -> "Halted" diff --git a/src/proto_alpha/bin_sc_rollup_node/pvm.ml b/src/proto_alpha/bin_sc_rollup_node/pvm.ml index 566c49e1d52e682121787fdfd85cd50142983f74..48f308b3c3fe16c79aa4f139a5c2ac8566088c6f 100644 --- a/src/proto_alpha/bin_sc_rollup_node/pvm.ml +++ b/src/proto_alpha/bin_sc_rollup_node/pvm.ml @@ -62,6 +62,12 @@ module type S = sig state -> (state * int64) Lwt.t + val new_dissection : + default_number_of_sections:int -> + start_chunk:Sc_rollup.Dissection_chunk.t -> + our_stop_chunk:Sc_rollup.Dissection_chunk.t -> + Sc_rollup.Tick.t list + (** State storage for this PVM. *) module State : sig (** [empty ()] is the empty state. *) 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 99482033b09d5c40248fd991d6775d9fff5e1e5b..5f03c3c3befb7d9f5059ee94cccd4f2806fd7c2b 100644 --- a/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml +++ b/src/proto_alpha/bin_sc_rollup_node/refutation_game.ml @@ -265,8 +265,8 @@ module Make (Interpreter : Interpreter.S) : let new_dissection ~default_number_of_sections node_ctxt last_level ok our_view = + let open Lwt_result_syntax in let state_hash_from_tick tick = - let open Lwt_result_syntax in let* r = Interpreter.state_of_tick node_ctxt tick last_level in return (Option.map snd r) in @@ -279,11 +279,14 @@ module Make (Interpreter : Interpreter.S) : let our_stop_chunk = Sc_rollup.Dissection_chunk.{state_hash = start_hash; tick = start_tick} in - Game_helpers.new_dissection + Game_helpers.make_dissection + ~state_hash_from_tick ~start_chunk ~our_stop_chunk - ~default_number_of_sections - ~state_hash_from_tick + @@ PVM.new_dissection + ~start_chunk + ~our_stop_chunk + ~default_number_of_sections (** [generate_from_dissection ~default_number_of_sections node_ctxt game dissection] traverses the current [dissection] and returns a move which diff --git a/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml index 45fc6c234f82f3cf48e4ce0c2021a5a98d0963e3..f0a5b0515adf83d97ae85c80189ee81c303f28ec 100644 --- a/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -70,6 +70,8 @@ module Impl : Pvm.S = struct let kind = Sc_rollup.Kind.of_pvm (module PVM) + let new_dissection = Game_helpers.default_new_dissection + module State = Context.PVMState let string_of_status : status -> string = function diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 5a7cb2bc2603872c141842854a55c07f296b193d..23953c79d48f760d41cc63d2772b11ad86e3932b 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -3452,13 +3452,6 @@ module Sc_rollup : sig 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 diff --git a/src/proto_alpha/lib_protocol/sc_rollup_arith.ml b/src/proto_alpha/lib_protocol/sc_rollup_arith.ml index 7df9e544e8e9b126a9e4e90b52fd2aa322707701..48dd7216682b01f8ee731ff075957fe66c0254df 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_arith.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_arith.ml @@ -213,7 +213,9 @@ 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 + let check_dissection = + Sc_rollup_dissection_chunk_repr.( + default_check ~check_sections_number:default_check_sections_number) (* 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 index e40e7edc0b2d37237ea45c7441679529b6fde78a..c363d6e75eba58ef38ba99ef95008bd947477a69 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.ml @@ -85,8 +85,8 @@ let pp ppf {state_hash; tick} = Sc_rollup_tick_repr.pp tick -let default_check ~default_number_of_sections ~start_chunk ~stop_chunk - dissection = +let default_check_sections_number ~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 @@ -94,12 +94,23 @@ let default_check ~default_number_of_sections ~start_chunk ~stop_chunk Dissection_number_of_sections_mismatch {expected; given = len} in let num_sections = Z.of_int @@ default_number_of_sections in + 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) + +let default_check ~check_sections_number ~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* () = - 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) + check_sections_number + ~default_number_of_sections + ~start_chunk + ~stop_chunk + dissection in let* () = match (List.hd dissection, List.last_opt dissection) with 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 index c3d80e6ebd4c9aa25969e4ad8aeb7c616c78195f..8f3d14279ed11c4b80e3d6504801e229371ff786 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_dissection_chunk_repr.mli @@ -35,6 +35,13 @@ val pp : Format.formatter -> t -> unit val encoding : t Data_encoding.t +val default_check_sections_number : + default_number_of_sections:int -> + start_chunk:t -> + stop_chunk:t -> + t list -> + unit 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 @@ -55,6 +62,12 @@ val encoding : t Data_encoding.t game' attack) will mean that sometimes the honest play is a dissection with multiple [None] states. *) val default_check : + check_sections_number: + (default_number_of_sections:int -> + start_chunk:t -> + stop_chunk:t -> + t list -> + unit tzresult) -> default_number_of_sections:int -> start_chunk:t -> stop_chunk:t -> 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 a717714b825a2907b8c0b28f67bf22c30bc90c6d..dc5c1f512a3d00ab912100677e544b091efb8542 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_game_repr.ml @@ -920,7 +920,9 @@ let play dal_parameters ~dal_attestation_lag ~stakers metadata game refutation = module Internal_for_tests = struct let find_choice = find_choice - let check_dissection = Sc_rollup_dissection_chunk_repr.default_check + let check_dissection = + Sc_rollup_dissection_chunk_repr.( + default_check ~check_sections_number:default_check_sections_number) end type timeout = {alice : int; bob : int; last_turn_level : Raw_level_repr.t} diff --git a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml index fb5b07f5507934fdaf69937f3556e614cbe261e0..330e67005462ed1ee257a7d099e6a277b2d9a594 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml @@ -519,7 +519,9 @@ 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 + let check_dissection = + Sc_rollup_dissection_chunk_repr.( + default_check ~check_sections_number:default_check_sections_number) module Internal_for_tests = struct let insert_failure state = 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 cd6d2893418561a0d15536fc460e424b70001b64..570b0f95cc8baf89db88901488bbc4782d1c882f 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 @@ -202,11 +202,12 @@ let build_dissection ~number_of_sections ~start_chunk ~stop_chunk ~our_states = incorrect cases. *) Lwt_main.run @@ let*! r = - Game_helpers.new_dissection - ~start_chunk - ~our_stop_chunk - ~default_number_of_sections:number_of_sections - ~state_hash_from_tick + Game_helpers.( + make_dissection ~state_hash_from_tick ~start_chunk ~our_stop_chunk + @@ default_new_dissection + ~start_chunk + ~our_stop_chunk + ~default_number_of_sections:number_of_sections) in Lwt.return @@ WithExceptions.Result.get_ok ~loc:__LOC__ r diff --git a/src/proto_alpha/lib_sc_rollup/game_helpers.ml b/src/proto_alpha/lib_sc_rollup/game_helpers.ml index 62038eb312ccadeb43036cd7712d4c23e477e206..1e23b59a5072e54f6d6bc8cf357e6419f5dd8eef 100644 --- a/src/proto_alpha/lib_sc_rollup/game_helpers.ml +++ b/src/proto_alpha/lib_sc_rollup/game_helpers.ml @@ -25,10 +25,9 @@ open Protocol.Alpha_context.Sc_rollup -let new_dissection ~state_hash_from_tick ~default_number_of_sections +let default_new_dissection ~default_number_of_sections ~(start_chunk : Game.dissection_chunk) ~(our_stop_chunk : Game.dissection_chunk) = - let open Lwt_result_syntax in let max_number_of_sections = Z.of_int default_number_of_sections in let trace_length = Z.succ (Tick.distance our_stop_chunk.tick start_chunk.tick) @@ -48,23 +47,22 @@ let new_dissection ~state_hash_from_tick ~default_number_of_sections else (section_length, section_length) in (* [k] is the number of sections in [rev_dissection]. *) - let rec make rev_dissection k tick : Game.dissection_chunk list tzresult Lwt.t - = - if Z.(equal k (pred number_of_sections)) then - return - @@ List.rev - (({ - state_hash = our_stop_chunk.state_hash; - tick = our_stop_chunk.tick; - } - : Game.dissection_chunk) - :: rev_dissection) + let rec make rev_dissection k tick = + if Z.(equal k (pred number_of_sections)) then List.rev rev_dissection else - let* state_hash = state_hash_from_tick tick in let next_tick = Tick.jump tick section_length in - make ({state_hash; tick} :: rev_dissection) (Z.succ k) next_tick + make (tick :: rev_dissection) (Z.succ k) next_tick in - make - [{state_hash = start_chunk.state_hash; tick = start_chunk.tick}] - Z.one - (Tick.jump start_chunk.tick first_section_length) + make [] Z.one (Tick.jump start_chunk.tick first_section_length) + +let make_dissection ~state_hash_from_tick ~start_chunk ~our_stop_chunk ticks = + let rec make_dissection_aux ticks acc = + let open Lwt_result_syntax in + match ticks with + | tick :: rst -> + let* state_hash = state_hash_from_tick tick in + let chunk = Dissection_chunk.{tick; state_hash} in + make_dissection_aux rst (chunk :: acc) + | [] -> return @@ List.rev (our_stop_chunk :: acc) + in + make_dissection_aux ticks [start_chunk] diff --git a/src/proto_alpha/lib_sc_rollup/game_helpers.mli b/src/proto_alpha/lib_sc_rollup/game_helpers.mli index ef07fc238306c99a59b4d8c5fe922feeb7e7d4fe..b9a8ddca1d57f9ed80a893b3623cba96fb97ecd7 100644 --- a/src/proto_alpha/lib_sc_rollup/game_helpers.mli +++ b/src/proto_alpha/lib_sc_rollup/game_helpers.mli @@ -25,12 +25,28 @@ open Protocol.Alpha_context.Sc_rollup -(** Create a valid dissection based on the agreed [start_chunk] and our vision - of the stop chunk [our_stop_chunk]. We use [state_hash_from_tick] to - give our vision of the state hashes for each tick. *) -val new_dissection : - state_hash_from_tick:(Tick.t -> State_hash.t option tzresult Lwt.t) -> +(** [default_new_dissection ~default_number_of_sections ~start_chunk + ~our_stop_chunk] computes a list of intermediary ticks that can + later be turned into new dissection from between [start_chunk] and + [our_stop_chunk] with [make_dissection]. The algorithm satisfies + the default predicate on dissection exported by the protocol. *) +val default_new_dissection : default_number_of_sections:int -> start_chunk:Game.dissection_chunk -> our_stop_chunk:Game.dissection_chunk -> - Game.dissection_chunk list tzresult Lwt.t + Tick.t list + +(** [make_dissection ~state_hash_from_tick ~start_chunk + ~our_stop_chunk intermediary_ticks] computes a new dissection from + a list of intermediary ticks between [start_chunk] and + [our_stop_chunk]. + + This function assumes [intermediary_ticks] encodes a valid + dissection from [start_chunk] to [our_stop_chunk], and recomputes + the state hash associated to each ticks. *) +val make_dissection : + state_hash_from_tick:(Tick.t -> State_hash.t option tzresult Lwt.t) -> + start_chunk:Dissection_chunk.t -> + our_stop_chunk:Dissection_chunk.t -> + Tick.t trace -> + Dissection_chunk.t list tzresult Lwt.t