diff --git a/src/lib_smart_rollup/game.ml b/src/lib_smart_rollup/game.ml index ab17ca00e1dbb6f975ece9d2f79d5070988bd5bd..ad90253534a828909c6dc30ed5c144a111551030 100644 --- a/src/lib_smart_rollup/game.ml +++ b/src/lib_smart_rollup/game.ml @@ -23,90 +23,280 @@ (* *) (*****************************************************************************) -type dissection_chunk = {state_hash : State_hash.t option; tick : Z.t} +module V1 = struct + type dissection_chunk = {state_hash : State_hash.t option; tick : Z.t} -type step = Dissection of dissection_chunk list | Proof of string + type step = Dissection of dissection_chunk list | Proof of string -type refutation = - | Start of { - player_commitment_hash : Commitment.Hash.t; - opponent_commitment_hash : Commitment.Hash.t; - } - | Move of {choice : Z.t; step : step} + type refutation = + | Start of { + player_commitment_hash : Commitment.Hash.t; + opponent_commitment_hash : Commitment.Hash.t; + } + | Move of {choice : Z.t; step : step} -type index = { - alice : Signature.Public_key_hash.t; - bob : Signature.Public_key_hash.t; -} + type index = { + alice : Signature.Public_key_hash.t; + bob : Signature.Public_key_hash.t; + } -let make_index a b = - let alice, bob = - if Signature.Public_key_hash.(a > b) then (b, a) else (a, b) - in - {alice; bob} + let make_index a b = + let alice, bob = + if Signature.Public_key_hash.(a > b) then (b, a) else (a, b) + in + {alice; bob} -let index_encoding = - let open Data_encoding in - conv - (fun {alice; bob} -> (alice, bob)) - (fun (alice, bob) -> make_index alice bob) - (obj2 - (req "alice" Signature.Public_key_hash.encoding) - (req "bob" Signature.Public_key_hash.encoding)) - -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" n)) + let equal_dissection_chunk c1 c2 = + Z.equal c1.tick c2.tick + && Option.equal State_hash.equal c1.state_hash c2.state_hash -let dissection_encoding = Data_encoding.list dissection_chunk_encoding + let index_encoding = + let open Data_encoding in + conv + (fun {alice; bob} -> (alice, bob)) + (fun (alice, bob) -> make_index alice bob) + (obj2 + (req "alice" Signature.Public_key_hash.encoding) + (req "bob" Signature.Public_key_hash.encoding)) -let step_encoding = - let open Data_encoding in - union - ~tag_size:`Uint8 - [ - case - ~title:"Dissection" - (Tag 0) - dissection_encoding - (function Dissection d -> Some d | _ -> None) - (fun d -> Dissection d); - case - ~title:"Proof" - (Tag 1) - (string' Hex) - (function Proof p -> Some p | _ -> None) - (fun p -> Proof p); - ] + 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" n)) + + let dissection_encoding = Data_encoding.list dissection_chunk_encoding + + let step_encoding = + let open Data_encoding in + union + ~tag_size:`Uint8 + [ + case + ~title:"Dissection" + (Tag 0) + dissection_encoding + (function Dissection d -> Some d | _ -> None) + (fun d -> Dissection d); + case + ~title:"Proof" + (Tag 1) + (string' Hex) + (function Proof p -> Some p | _ -> None) + (fun p -> Proof p); + ] + + let refutation_encoding = + let open Data_encoding in + union + ~tag_size:`Uint8 + [ + case + ~title:"Start" + (Tag 0) + (obj3 + (req "refutation_kind" (constant "start")) + (req "player_commitment_hash" Commitment.Hash.encoding) + (req "opponent_commitment_hash" Commitment.Hash.encoding)) + (function + | Start {player_commitment_hash; opponent_commitment_hash} -> + Some ((), player_commitment_hash, opponent_commitment_hash) + | _ -> None) + (fun ((), player_commitment_hash, opponent_commitment_hash) -> + Start {player_commitment_hash; opponent_commitment_hash}); + case + ~title:"Move" + (Tag 1) + (obj3 + (req "refutation_kind" (constant "move")) + (req "choice" n) + (req "step" step_encoding)) + (function + | Move {choice; step} -> Some ((), choice, step) | _ -> None) + (fun ((), choice, step) -> Move {choice; step}); + ] + + type conflict = { + other : Signature.Public_key_hash.t; + their_commitment : Commitment.t; + our_commitment : Commitment.t; + parent_commitment : Commitment.Hash.t; + } -let refutation_encoding = + let conflict_encoding = + Data_encoding.( + conv + (fun {other; their_commitment; our_commitment; parent_commitment} -> + (other, their_commitment, our_commitment, parent_commitment)) + (fun (other, their_commitment, our_commitment, parent_commitment) -> + {other; their_commitment; our_commitment; parent_commitment}) + (obj4 + (req "other" Signature.Public_key_hash.encoding) + (req "their_commitment" Commitment.encoding) + (req "our_commitment" Commitment.encoding) + (req "parent_commitment" Commitment.Hash.encoding))) + + type player = Alice | Bob + + type game_state = + | Dissecting of { + dissection : dissection_chunk list; + default_number_of_sections : int; + } + | Final_move of { + agreed_start_chunk : dissection_chunk; + refuted_stop_chunk : dissection_chunk; + } + + type t = { + turn : player; + inbox_snapshot : Inbox.V1.history_proof; + dal_snapshot : Dal.Slot_history.t; + start_level : int32; + inbox_level : int32; + game_state : game_state; + } + + let game_state_equal gs1 gs2 = + match (gs1, gs2) with + | ( Dissecting + { + dissection = dissection1; + default_number_of_sections = default_number_of_sections1; + }, + Dissecting + { + dissection = dissection2; + default_number_of_sections = default_number_of_sections2; + } ) -> + Compare.Int.equal + default_number_of_sections1 + default_number_of_sections2 + && List.equal equal_dissection_chunk dissection1 dissection2 + | Dissecting _, _ -> false + | ( Final_move + { + agreed_start_chunk = agreed_start_chunk1; + refuted_stop_chunk = refuted_stop_chunk1; + }, + Final_move + { + agreed_start_chunk = agreed_start_chunk2; + refuted_stop_chunk = refuted_stop_chunk2; + } ) -> + equal_dissection_chunk agreed_start_chunk1 agreed_start_chunk2 + && equal_dissection_chunk refuted_stop_chunk1 refuted_stop_chunk2 + | Final_move _, _ -> false + + let player_encoding = + let open Data_encoding in + union + ~tag_size:`Uint8 + [ + case + ~title:"Alice" + (Tag 0) + (constant "alice") + (function Alice -> Some () | _ -> None) + (fun () -> Alice); + case + ~title:"Bob" + (Tag 1) + (constant "bob") + (function Bob -> Some () | _ -> None) + (fun () -> Bob); + ] + + let game_state_encoding = + let open Data_encoding in + union + ~tag_size:`Uint8 + [ + case + ~title:"Dissecting" + (Tag 0) + (obj3 + (req "kind" (constant "Dissecting")) + (req "dissection" dissection_encoding) + (req "default_number_of_sections" uint8)) + (function + | Dissecting {dissection; default_number_of_sections} -> + Some ((), dissection, default_number_of_sections) + | _ -> None) + (fun ((), dissection, default_number_of_sections) -> + Dissecting {dissection; default_number_of_sections}); + case + ~title:"Final_move" + (Tag 1) + (obj3 + (req "kind" (constant "Final_move")) + (req "agreed_start_chunk" dissection_chunk_encoding) + (req "refuted_stop_chunk" dissection_chunk_encoding)) + (function + | Final_move {agreed_start_chunk; refuted_stop_chunk} -> + Some ((), agreed_start_chunk, refuted_stop_chunk) + | _ -> None) + (fun ((), agreed_start_chunk, refuted_stop_chunk) -> + Final_move {agreed_start_chunk; refuted_stop_chunk}); + ] + + let encoding = + let open Data_encoding in + conv + (fun { + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + } -> + ( turn, + inbox_snapshot, + dal_snapshot, + start_level, + inbox_level, + game_state )) + (fun ( turn, + inbox_snapshot, + dal_snapshot, + start_level, + inbox_level, + game_state ) -> + { + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + }) + (obj6 + (req "turn" player_encoding) + (req "inbox_snapshot" Inbox.V1.history_proof_encoding) + (req "dal_snapshot" (dynamic_size Dal.Slot_history.encoding)) + (req "start_level" int32) + (req "inbox_level" int32) + (req "game_state" game_state_encoding)) +end + +type versioned = V1 of V1.t + +let versioned_encoding = let open Data_encoding in union - ~tag_size:`Uint8 [ case - ~title:"Start" + ~title:"smart_rollup_game.V1" (Tag 0) - (obj3 - (req "refutation_kind" (constant "start")) - (req "player_commitment_hash" Commitment.Hash.encoding) - (req "opponent_commitment_hash" Commitment.Hash.encoding)) - (function - | Start {player_commitment_hash; opponent_commitment_hash} -> - Some ((), player_commitment_hash, opponent_commitment_hash) - | _ -> None) - (fun ((), player_commitment_hash, opponent_commitment_hash) -> - Start {player_commitment_hash; opponent_commitment_hash}); - case - ~title:"Move" - (Tag 1) - (obj3 - (req "refutation_kind" (constant "move")) - (req "choice" n) - (req "step" step_encoding)) - (function Move {choice; step} -> Some ((), choice, step) | _ -> None) - (fun ((), choice, step) -> Move {choice; step}); + V1.encoding + (function V1 game -> Some game) + (fun game -> V1 game); ] + +include V1 + +let of_versioned = function V1 g -> g [@@inline] + +let to_versioned g = V1 g [@@inline] diff --git a/src/lib_smart_rollup/game.mli b/src/lib_smart_rollup/game.mli index 9c2676b00bfd79a6dbec5426d188d9a88e541491..455fcf96b152626956ea0b05333360a1dd35d05f 100644 --- a/src/lib_smart_rollup/game.mli +++ b/src/lib_smart_rollup/game.mli @@ -23,31 +23,84 @@ (* *) (*****************************************************************************) -type dissection_chunk = {state_hash : State_hash.t option; tick : Z.t} +module V1 : sig + type dissection_chunk = {state_hash : State_hash.t option; tick : Z.t} -type step = Dissection of dissection_chunk list | Proof of string + type step = Dissection of dissection_chunk list | Proof of string -type refutation = - | Start of { - player_commitment_hash : Commitment.Hash.t; - opponent_commitment_hash : Commitment.Hash.t; - } - | Move of {choice : Z.t; step : step} + type refutation = + | Start of { + player_commitment_hash : Commitment.Hash.t; + opponent_commitment_hash : Commitment.Hash.t; + } + | Move of {choice : Z.t; step : step} -type index = { - alice : Signature.Public_key_hash.t; - bob : Signature.Public_key_hash.t; -} + type index = { + alice : Signature.Public_key_hash.t; + bob : Signature.Public_key_hash.t; + } -val dissection_chunk_encoding : dissection_chunk Data_encoding.t + val dissection_chunk_encoding : dissection_chunk Data_encoding.t -val dissection_encoding : dissection_chunk list Data_encoding.t + val dissection_encoding : dissection_chunk list Data_encoding.t -val step_encoding : step Data_encoding.t + val step_encoding : step Data_encoding.t -val refutation_encoding : refutation Data_encoding.t + val refutation_encoding : refutation Data_encoding.t -val index_encoding : index Data_encoding.t + val index_encoding : index Data_encoding.t -val make_index : - Signature.Public_key_hash.t -> Signature.Public_key_hash.t -> index + val make_index : + Signature.Public_key_hash.t -> Signature.Public_key_hash.t -> index + + type player = Alice | Bob + + type game_state = + | Dissecting of { + dissection : dissection_chunk list; + default_number_of_sections : int; + } + | Final_move of { + agreed_start_chunk : dissection_chunk; + refuted_stop_chunk : dissection_chunk; + } + + type t = { + turn : player; + inbox_snapshot : Inbox.V1.history_proof; + dal_snapshot : Dal.Slot_history.t; + start_level : int32; + inbox_level : int32; + game_state : game_state; + } + + type conflict = { + other : Signature.Public_key_hash.t; + their_commitment : Commitment.t; + our_commitment : Commitment.t; + parent_commitment : Commitment.Hash.t; + } + + val game_state_equal : game_state -> game_state -> bool + + val player_encoding : player Data_encoding.t + + val game_state_encoding : game_state Data_encoding.t + + val encoding : t Data_encoding.t + + val conflict_encoding : conflict Data_encoding.t +end + +include Versioned_data.S with type t = V1.t + +include + module type of V1 + with type dissection_chunk = V1.dissection_chunk + and type step = V1.step + and type refutation = V1.refutation + and type index = V1.index + and type player = V1.player + and type game_state = V1.game_state + and type conflict = V1.conflict + and type t = V1.t diff --git a/src/lib_smart_rollup_node/protocol_plugin_sig.ml b/src/lib_smart_rollup_node/protocol_plugin_sig.ml index 46c78dd7fdf27d7f97dfa87d70e8252cca68f068..48044883eac597263b5b22be41788bbb03cfe224 100644 --- a/src/lib_smart_rollup_node/protocol_plugin_sig.ml +++ b/src/lib_smart_rollup_node/protocol_plugin_sig.ml @@ -131,26 +131,63 @@ module type INTERPRETER = sig ('a Context.t * Context.tree) tzresult Lwt.t end -(** Protocol specific refutation coordinator. NOTE: The refutation coordinator - has to be stopped and the new one restarted on protocol change. *) -module type REFUTATION_COORDINATOR = sig - (** [init node_ctxt] initializes the refutation coordinator worker. *) - val init : Node_context.rw -> unit tzresult Lwt.t - - (** [process head] processes a new l1 head. This means that the coordinator - will: - {ol - {li Gather all existing conflicts} - {li Launch new refutation players for each conflict concerning - the operator that doesn't have a player in this node} - {li Kill all players whose conflict has disappeared from L1} - {li Make all players play a step in the refutation} - } - *) - val process : Layer1.head -> unit tzresult Lwt.t - - (** [shutdown ()] stops the refutation coordinator. *) - val shutdown : unit -> unit Lwt.t +(** Protocol specific refutation helper functions. *) +module type REFUTATION_GAME_HELPERS = sig + (** [generate_proof node_ctxt (game) start_state] generates a serialized proof + for the current [game] for the execution step starting with + [start_state]. *) + val generate_proof : + Node_context.rw -> Game.t -> Context.tree -> string tzresult Lwt.t + + (** [state_of_tick node_ctxt ?start_state ~tick level] returns [Some + (state, hash)] for a given [tick] if this [tick] happened before + [level]. Otherwise, returns [None]. If provided, the evaluation is resumed + from [start_state]. *) + val state_of_tick : + _ Node_context.t -> + ?start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state -> + tick:Z.t -> + int32 -> + Fuel.Accounted.t Pvm_plugin_sig.eval_state option tzresult Lwt.t + + (** [make_dissection node_ctxt ~start_state ~start_chunk ~our_stop_chunk + ~default_number_of_sections ~last_level] computes a dissection from between + [start_chunk] and [our_stop_chunk] at level [last_level]. This dissection + has [default_number_of_sections] if there are enough ticks. *) + val make_dissection : + _ Node_context.t -> + start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state option -> + start_chunk:Game.dissection_chunk -> + our_stop_chunk:Game.dissection_chunk -> + default_number_of_sections:int -> + last_level:int32 -> + Game.dissection_chunk trace tzresult Lwt.t + + (** [timeout_reached node_ctxt ~self ~opponent] returns [true] if the + timeout is reached against opponent in head of the L1 chain. *) + val timeout_reached : + _ Node_context.t -> + self:Signature.public_key_hash -> + opponent:Signature.public_key_hash -> + bool tzresult Lwt.t + + (** [get_conflicts cctxt rollup signer] returns the conflicts for commitments + staked on by [signer]. *) + val get_conflicts : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + Game.conflict list tzresult Lwt.t + + (** [get_ongoing_games cctxt rollup signer] returns the games that [signer] is + currently playing. *) + val get_ongoing_games : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + (Game.t * Signature.public_key_hash * Signature.public_key_hash) list + tzresult + Lwt.t end (** Protocol specific constants for the batcher. *) @@ -269,7 +306,7 @@ module type S = sig module Interpreter : INTERPRETER - module Refutation_coordinator : REFUTATION_COORDINATOR + module Refutation_game_helpers : REFUTATION_GAME_HELPERS module Batcher_constants : BATCHER_CONSTANTS diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator.ml b/src/lib_smart_rollup_node/refutation_coordinator.ml similarity index 84% rename from src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator.ml rename to src/lib_smart_rollup_node/refutation_coordinator.ml index 21403e6efef25151bbd555dd43b0bbc7afbe13e3..d87e0ab1e3e8c6cf937d0340344f04b78fa49145 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator.ml +++ b/src/lib_smart_rollup_node/refutation_coordinator.ml @@ -23,33 +23,16 @@ (* *) (*****************************************************************************) -open Protocol -open Alpha_context open Refutation_coordinator_types -include Refutation_game module Player = Refutation_player module Pkh_map = Signature.Public_key_hash.Map module Pkh_table = Signature.Public_key_hash.Table -type state = { - node_ctxt : Node_context.rw; - cctxt : Protocol_client_context.full; - pending_opponents : unit Pkh_table.t; -} - -let get_conflicts cctxt head_block = - Plugin.RPC.Sc_rollup.conflicts cctxt (cctxt#chain, head_block) - -let get_ongoing_games cctxt head_block = - Plugin.RPC.Sc_rollup.ongoing_refutation_games cctxt (cctxt#chain, head_block) +type state = {node_ctxt : Node_context.rw; pending_opponents : unit Pkh_table.t} let untracked_conflicts opponent_players conflicts = List.filter - (fun conflict -> - not - @@ Pkh_map.mem - conflict.Sc_rollup.Refutation_storage.other - opponent_players) + (fun conflict -> not @@ Pkh_map.mem conflict.Game.other opponent_players) conflicts (* Transform the list of ongoing games [(Game.t * pkh * pkh) list] @@ -66,9 +49,8 @@ let make_game_map self ongoing_games = Pkh_map.empty ongoing_games -let on_process Layer1.{hash; level} state = +let on_process Layer1.{level; _} state = let node_ctxt = state.node_ctxt in - let head_block = `Hash (hash, 0) in let open Lwt_result_syntax in let refute_signer = Node_context.get_operator node_ctxt Refute in match refute_signer with @@ -77,9 +59,14 @@ let on_process Layer1.{hash; level} state = return_unit | Some self -> let Node_context.{rollup_address; _} = node_ctxt in + let* plugin = Protocol_plugins.last_proto_plugin node_ctxt in + let module Plugin = (val plugin) in (* Current conflicts in L1 *) let* conflicts = - get_conflicts state.cctxt head_block rollup_address self + Plugin.Refutation_game_helpers.get_conflicts + state.node_ctxt.cctxt + rollup_address + self in (* Map of opponents the node is playing against to the corresponding player worker *) @@ -91,7 +78,10 @@ let on_process Layer1.{hash; level} state = let new_conflicts = untracked_conflicts opponent_players conflicts in (* L1 ongoing games *) let* ongoing_games = - get_ongoing_games state.cctxt head_block rollup_address self + Plugin.Refutation_game_helpers.get_ongoing_games + state.node_ctxt.cctxt + rollup_address + self in (* Map between opponents and their corresponding games *) let ongoing_game_map = make_game_map self ongoing_games in @@ -99,7 +89,7 @@ let on_process Layer1.{hash; level} state = let* () = List.iter_ep (fun conflict -> - let other = conflict.Sc_rollup.Refutation_storage.other in + let other = conflict.Octez_smart_rollup.Game.other in Pkh_table.replace state.pending_opponents other () ; let game = Pkh_map.find_opt other ongoing_game_map in Player.init_and_play node_ctxt ~self ~conflict ~game ~level) @@ -127,10 +117,7 @@ let on_process Layer1.{hash; level} state = module Types = struct type nonrec state = state - type parameters = { - node_ctxt : Node_context.rw; - cctxt : Protocol_client_context.full; - } + type parameters = Node_context.rw end module Name = struct @@ -166,8 +153,8 @@ module Handlers = struct type launch_error = error trace - let on_launch _w () Types.{node_ctxt; cctxt} = - return {node_ctxt; cctxt; pending_opponents = Pkh_table.create 5} + let on_launch _w () node_ctxt = + Lwt_result.return {node_ctxt; pending_opponents = Pkh_table.create 5} let on_error (type a b) _w st (r : (a, b) Request.t) (errs : b) : unit tzresult Lwt.t = @@ -196,10 +183,7 @@ let worker_promise, worker_waker = Lwt.task () let start node_ctxt = let open Lwt_result_syntax in let*! () = Refutation_game_event.Coordinator.starting () in - let cctxt = - new Protocol_client_context.wrap_full node_ctxt.Node_context.cctxt - in - let+ worker = Worker.launch table () {node_ctxt; cctxt} (module Handlers) in + let+ worker = Worker.launch table () node_ctxt (module Handlers) in Lwt.wakeup worker_waker worker let init node_ctxt = @@ -210,18 +194,19 @@ let init node_ctxt = return_unit | Lwt.Fail exn -> (* Worker crashed, not recoverable. *) - fail [Sc_rollup_node_errors.No_refutation_coordinator; Exn exn] + fail [Rollup_node_errors.No_refutation_coordinator; Exn exn] | Lwt.Sleep -> (* Never started, start it. *) start node_ctxt (* This is a refutation coordinator for a single scoru *) let worker = + let open Result_syntax in lazy (match Lwt.state worker_promise with - | Lwt.Return worker -> ok worker + | Lwt.Return worker -> return worker | Lwt.Fail _ | Lwt.Sleep -> - error Sc_rollup_node_errors.No_refutation_coordinator) + tzfail Rollup_node_errors.No_refutation_coordinator) let process b = let open Lwt_result_syntax in diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator.mli b/src/lib_smart_rollup_node/refutation_coordinator.mli similarity index 92% rename from src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator.mli rename to src/lib_smart_rollup_node/refutation_coordinator.mli index 12a35582b9b294687783aa6964b0290f6d3d35ea..d2303ca95f38b86afc4b8fd140c7060829e511bb 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator.mli +++ b/src/lib_smart_rollup_node/refutation_coordinator.mli @@ -32,15 +32,16 @@ (** Initiatilize the refuation coordinator. *) val init : Node_context.rw -> unit tzresult Lwt.t -(** Process a new l1 head. This means that the coordinator will: +(** [process head] processes a new l1 head. This means that the coordinator + will: {ol {li Gather all existing conflicts} - {li Launch new refutation players for each conflict that doesn't - have a player in this node} + {li Launch new refutation players for each conflict concerning + the operator that doesn't have a player in this node} {li Kill all players whose conflict has disappeared from L1} {li Make all players play a step in the refutation} } - *) +*) val process : Layer1.head -> unit tzresult Lwt.t (** Shutdown the refutation coordinator. *) diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator_types.ml b/src/lib_smart_rollup_node/refutation_coordinator_types.ml similarity index 100% rename from src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator_types.ml rename to src/lib_smart_rollup_node/refutation_coordinator_types.ml diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator_types.mli b/src/lib_smart_rollup_node/refutation_coordinator_types.mli similarity index 100% rename from src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator_types.mli rename to src/lib_smart_rollup_node/refutation_coordinator_types.mli diff --git a/src/lib_smart_rollup_node/refutation_game.ml b/src/lib_smart_rollup_node/refutation_game.ml new file mode 100644 index 0000000000000000000000000000000000000000..1725425e3840b51d88882bc18527b81a880f1d5a --- /dev/null +++ b/src/lib_smart_rollup_node/refutation_game.ml @@ -0,0 +1,269 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2022 Nomadic Labs, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** This module implements the refutation game logic of the rollup + node. + + When a new L1 block arises, the rollup node asks the L1 node for + the current game it is part of, if any. + + If a game is running and it is the rollup operator turn, the rollup + node injects the next move of the winning strategy. + + If a game is running and it is not the rollup operator turn, the + rollup node asks the L1 node whether the timeout is reached to play + the timeout argument if possible. + + Otherwise, if no game is running, the rollup node asks the L1 node + whether there is a conflict with one of its disputable commitments. If + there is such a conflict with a commitment C', then the rollup node + starts a game to refute C' by starting a game with one of its staker. + +*) + +open Game + +let node_role ~self {alice; bob} = + if Signature.Public_key_hash.equal alice self then Alice + else if Signature.Public_key_hash.equal bob self then Bob + else (* By validity of [ongoing_game] RPC. *) + assert false + +type role = Our_turn of {opponent : Signature.public_key_hash} | Their_turn + +let turn ~self game ({alice; bob} as players) = + match (node_role ~self players, game.turn) with + | Alice, Alice -> Our_turn {opponent = bob} + | Bob, Bob -> Our_turn {opponent = alice} + | Alice, Bob -> Their_turn + | Bob, Alice -> Their_turn + +(** [inject_next_move node_ctxt source ~refutation ~opponent ~commitment + ~opponent_commitment] submits an L1 operation (signed by [source]) to + issue the next move in the refutation game. *) +let inject_next_move node_ctxt source ~refutation ~opponent = + let open Lwt_result_syntax in + let refute_operation = + L1_operation.Refute + {rollup = node_ctxt.Node_context.rollup_address; refutation; opponent} + in + let* _hash = Injector.add_pending_operation ~source refute_operation in + return_unit + +type pvm_intermediate_state = + | Hash of State_hash.t + | Evaluated of Fuel.Accounted.t Pvm_plugin_sig.eval_state + +let new_dissection (module Plugin : Protocol_plugin_sig.S) ~opponent + ~default_number_of_sections node_ctxt last_level ok our_view = + let open Lwt_result_syntax in + let start_hash, start_tick, start_state = + match ok with + | Hash hash, tick -> (hash, tick, None) + | Evaluated ({state_hash; _} as state), tick -> + (state_hash, tick, Some state) + in + let start_chunk = Game.{state_hash = Some start_hash; tick = start_tick} in + let our_state, our_tick = our_view in + let our_state_hash = + Option.map (fun Pvm_plugin_sig.{state_hash; _} -> state_hash) our_state + in + let our_stop_chunk = Game.{state_hash = our_state_hash; tick = our_tick} in + let* dissection = + Plugin.Refutation_game_helpers.make_dissection + node_ctxt + ~start_state + ~start_chunk + ~our_stop_chunk + ~default_number_of_sections + ~last_level + in + let*! () = + Refutation_game_event.computed_dissection + ~opponent + ~start_tick + ~end_tick:our_tick + dissection + in + return dissection + +(** [generate_from_dissection ~default_number_of_sections node_ctxt game + dissection] traverses the current [dissection] and returns a move which + performs a new dissection of the execution trace or provides a refutation + proof to serve as the next move of the [game]. *) +let generate_next_dissection (module Plugin : Protocol_plugin_sig.S) + ~default_number_of_sections node_ctxt ~opponent + (game : Octez_smart_rollup.Game.t) + (dissection : Octez_smart_rollup.Game.dissection_chunk list) = + let open Lwt_result_syntax in + let rec traverse ok = function + | [] -> + (* The game invariant states that the dissection from the + opponent must contain a tick we disagree with. If the + retrieved game does not respect this, we cannot trust the + Tezos node we are connected to and prefer to stop here. *) + tzfail + Rollup_node_errors.Unreliable_tezos_node_returning_inconsistent_game + | Octez_smart_rollup.Game.{state_hash = their_hash; tick} :: dissection -> ( + let start_state = + match ok with + | Hash _, _ -> None + | Evaluated ok_state, _ -> Some ok_state + in + let* our = + Plugin.Refutation_game_helpers.state_of_tick + node_ctxt + ?start_state + ~tick + game.inbox_level + in + match (their_hash, our) with + | None, None -> + (* This case is absurd since: [None] can only occur at the + end and the two players disagree about the end. *) + assert false + | Some _, None | None, Some _ -> return (ok, (our, tick)) + | Some their_hash, Some ({state_hash = our_hash; _} as our_state) -> + if Octez_smart_rollup.State_hash.equal our_hash their_hash then + traverse (Evaluated our_state, tick) dissection + else return (ok, (our, tick))) + in + match dissection with + | {state_hash = Some hash; tick} :: dissection -> + let* ok, ko = traverse (Hash hash, tick) dissection in + let* dissection = + new_dissection + (module Plugin) + ~opponent + ~default_number_of_sections + node_ctxt + game.inbox_level + ok + ko + in + let _, choice = ok in + let _, ko_tick = ko in + let chosen_section_len = Z.abs (Z.sub choice ko_tick) in + return (choice, chosen_section_len, dissection) + | [] | {state_hash = None; _} :: _ -> + (* + By wellformedness of dissection. + A dissection always starts with a tick of the form [(Some hash, tick)]. + A dissection always contains strictly more than one element. + *) + tzfail + Rollup_node_errors.Unreliable_tezos_node_returning_inconsistent_game + +let next_move (module Plugin : Protocol_plugin_sig.S) node_ctxt ~opponent + (game : Octez_smart_rollup.Game.t) = + let open Lwt_result_syntax in + let final_move start_tick = + let* start_state = + Plugin.Refutation_game_helpers.state_of_tick + node_ctxt + ~tick:start_tick + game.inbox_level + in + match start_state with + | None -> + tzfail + Rollup_node_errors.Unreliable_tezos_node_returning_inconsistent_game + | Some {state = start_state; _} -> + let* proof = + Plugin.Refutation_game_helpers.generate_proof + node_ctxt + game + start_state + in + let choice = start_tick in + return (Octez_smart_rollup.Game.Move {choice; step = Proof proof}) + in + + match game.game_state with + | Dissecting {dissection; default_number_of_sections} -> + let* choice, chosen_section_len, dissection = + generate_next_dissection + (module Plugin) + ~default_number_of_sections + node_ctxt + ~opponent + game + dissection + in + if Z.(equal chosen_section_len one) then final_move choice + else + return + (Octez_smart_rollup.Game.Move {choice; step = Dissection dissection}) + | Final_move {agreed_start_chunk; refuted_stop_chunk = _} -> + let choice = agreed_start_chunk.tick in + final_move choice + +let play_next_move plugin node_ctxt game self opponent = + let open Lwt_result_syntax in + let* refutation = next_move plugin node_ctxt ~opponent game in + inject_next_move node_ctxt self ~refutation ~opponent + +let play_timeout (node_ctxt : _ Node_context.t) self stakers = + let open Lwt_result_syntax in + let timeout_operation = + L1_operation.Timeout {rollup = node_ctxt.rollup_address; stakers} + in + let source = + Node_context.get_operator node_ctxt Timeout |> Option.value ~default:self + (* We fallback on the [Refute] operator if none is provided for [Timeout] *) + in + let* _hash = Injector.add_pending_operation ~source timeout_operation in + return_unit + +let play node_ctxt ~self game opponent = + let open Lwt_result_syntax in + let index = make_index self opponent in + let* plugin = Protocol_plugins.last_proto_plugin node_ctxt in + match turn ~self game index with + | Our_turn {opponent} -> play_next_move plugin node_ctxt game self opponent + | Their_turn -> + let module Plugin = (val plugin) in + let* timeout_reached = + Plugin.Refutation_game_helpers.timeout_reached node_ctxt ~self ~opponent + in + when_ timeout_reached @@ fun () -> + let*! () = Refutation_game_event.timeout_detected opponent in + play_timeout node_ctxt self index + +let play_opening_move node_ctxt self + (conflict : Octez_smart_rollup.Game.conflict) = + let open Lwt_syntax in + let* () = Refutation_game_event.conflict_detected conflict in + let player_commitment_hash = + Octez_smart_rollup.Commitment.hash conflict.our_commitment + in + let opponent_commitment_hash = + Octez_smart_rollup.Commitment.hash conflict.their_commitment + in + let refutation = + Octez_smart_rollup.Game.Start + {player_commitment_hash; opponent_commitment_hash} + in + inject_next_move node_ctxt self ~refutation ~opponent:conflict.other diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game.mli b/src/lib_smart_rollup_node/refutation_game.mli similarity index 87% rename from src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game.mli rename to src/lib_smart_rollup_node/refutation_game.mli index 3229857d1aa7ad1cb2778b885650aff71cac5ff7..f718e20af1bd3cecd783f38dfd975aa9d923e604 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game.mli +++ b/src/lib_smart_rollup_node/refutation_game.mli @@ -23,24 +23,21 @@ (* *) (*****************************************************************************) -open Protocol -open Alpha_context - (** This module implements the refutation game logic of the rollup node. *) (** [play_opening_move node_ctxt self conflict] injects the opening refutation game move for [conflict]. *) val play_opening_move : [< `Read | `Write > `Read] Node_context.t -> - public_key_hash -> - Sc_rollup.Refutation_storage.conflict -> + Signature.public_key_hash -> + Octez_smart_rollup.Game.conflict -> (unit, tztrace) result Lwt.t -(** [play head_block node_ctxt ~self game opponent] injects the next move in the - refutation [game] played by [self] and [opponent]. *) +(** [play head_block plugin node_ctxt ~self game opponent] injects the next move + in the refutation [game] played by [self] and [opponent]. *) val play : Node_context.rw -> - self:public_key_hash -> - Sc_rollup.Game.t -> - public_key_hash -> + self:Signature.public_key_hash -> + Octez_smart_rollup.Game.t -> + Signature.public_key_hash -> (unit, tztrace) result Lwt.t diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game_event.ml b/src/lib_smart_rollup_node/refutation_game_event.ml similarity index 86% rename from src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game_event.ml rename to src/lib_smart_rollup_node/refutation_game_event.ml index b9231bfc5f90de13c320f966e116353f1f054c0e..73964d94f9c01a776df41945096160036bba514f 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game_event.ml +++ b/src/lib_smart_rollup_node/refutation_game_event.ml @@ -23,12 +23,10 @@ (* *) (*****************************************************************************) -open Protocol.Alpha_context - (* TODO: https://gitlab.com/tezos/tezos/-/issues/2880 Add corresponding .mli file. *) -let section = [Protocol.name; "sc_rollup_node"; "refutation_game"] +let section = ["sc_rollup_node"; "refutation_game"] module Simple = struct include Internal_event.Simple @@ -64,11 +62,11 @@ module Simple = struct at level {level} with staker {other} that hash issued commitment \ {their_commitment_hash} both based on {parent_commitment_hash}." ~level:Notice - ("our_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("level", Raw_level.encoding) - ("other", Sc_rollup.Staker.encoding) - ("their_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("parent_commitment_hash", Sc_rollup.Commitment.Hash.encoding) + ("our_commitment_hash", Octez_smart_rollup.Commitment.Hash.encoding) + ("level", Data_encoding.int32) + ("other", Signature.Public_key_hash.encoding) + ("their_commitment_hash", Octez_smart_rollup.Commitment.Hash.encoding) + ("parent_commitment_hash", Octez_smart_rollup.Commitment.Hash.encoding) let potential_conflict_detected = declare_4 @@ -79,10 +77,10 @@ module Simple = struct {our_commitment_hash} at level {level} with staker {other} that hash \ issued commitment {their_commitment_hash}." ~level:Notice - ("our_commitment_hash", Octez_smart_rollup.Commitment.Hash.encoding) + ("our_commitment_hash", Commitment.Hash.encoding) ("level", Data_encoding.int32) ("other", Signature.Public_key_hash.encoding) - ("their_commitment_hash", Octez_smart_rollup.Commitment.Hash.encoding) + ("their_commitment_hash", Commitment.Hash.encoding) let timeout_detected = declare_1 @@ -91,17 +89,7 @@ module Simple = struct ~msg: "The rollup node has detected that opponent {other} can be timed out." ~level:Notice - ("other", Sc_rollup.Staker.encoding) - - let dissection_chunk_encoding = - let open Data_encoding in - let open Sc_rollup.Dissection_chunk in - conv - (fun {state_hash; tick} -> (state_hash, tick)) - (fun (state_hash, tick) -> {state_hash; tick}) - (obj2 - (opt "state" Sc_rollup.State_hash.encoding) - (req "tick" Sc_rollup.Tick.encoding)) + ("other", Signature.Public_key_hash.encoding) let computed_dissection = declare_4 @@ -112,9 +100,10 @@ module Simple = struct {end_tick}: {dissection}." ~level:Debug ("opponent", Signature.Public_key_hash.encoding) - ("start_tick", Sc_rollup.Tick.encoding) - ("end_tick", Sc_rollup.Tick.encoding) - ("dissection", Data_encoding.list dissection_chunk_encoding) + ("start_tick", Data_encoding.z) + ("end_tick", Data_encoding.z) + ( "dissection", + Data_encoding.list Octez_smart_rollup.Game.dissection_chunk_encoding ) module Worker (ARG : sig val section : string list @@ -166,8 +155,8 @@ module Simple = struct ~level:Notice ("opponent", Signature.Public_key_hash.encoding) ~pp1:Signature.Public_key_hash.pp - ("commitment", Sc_rollup.Commitment.encoding) - ~pp2:Sc_rollup.Commitment.pp + ("commitment", Octez_smart_rollup.Commitment.encoding) + ~pp2:Octez_smart_rollup.Commitment.pp let stopped = declare_1 @@ -201,12 +190,12 @@ let timeout address = Simple.(emit timeout address) let invalid_move () = Simple.(emit invalid_move ()) -let conflict_detected (conflict : Sc_rollup.Refutation_storage.conflict) = +let conflict_detected (conflict : Octez_smart_rollup.Game.conflict) = let our_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.our_commitment + Octez_smart_rollup.Commitment.hash conflict.our_commitment in let their_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.their_commitment + Octez_smart_rollup.Commitment.hash conflict.their_commitment in let parent_commitment_hash = conflict.parent_commitment in let other = conflict.other in diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_player.ml b/src/lib_smart_rollup_node/refutation_player.ml similarity index 88% rename from src/proto_alpha/lib_sc_rollup_node/refutation_player.ml rename to src/lib_smart_rollup_node/refutation_player.ml index 72901a452bf2e325b3b1fb5c791a1d61767884a3..c615511eb3b727db26bdcd6681111c571b33e26e 100644 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_player.ml +++ b/src/lib_smart_rollup_node/refutation_player.ml @@ -23,23 +23,22 @@ (* *) (*****************************************************************************) -open Protocol -open Alpha_context open Refutation_player_types open Refutation_game module Types = struct type state = { node_ctxt : Node_context.rw; - self : public_key_hash; - opponent : public_key_hash; - mutable last_move_cache : (Sc_rollup.Game.game_state * int32) option; + self : Signature.public_key_hash; + opponent : Signature.public_key_hash; + mutable last_move_cache : + (Octez_smart_rollup.Game.game_state * int32) option; } type parameters = { node_ctxt : Node_context.rw; - self : public_key_hash; - conflict : Sc_rollup.Refutation_storage.conflict; + self : Signature.public_key_hash; + conflict : Octez_smart_rollup.Game.conflict; } end @@ -77,7 +76,7 @@ module Handlers = struct type launch_error = error trace let on_launch _w _name Types.{node_ctxt; self; conflict} = - return + Lwt_result.return Types.{node_ctxt; self; opponent = conflict.other; last_move_cache = None} let on_error (type a b) _w st (r : (a, b) Request.t) (errs : b) : @@ -110,12 +109,12 @@ let init node_ctxt ~self ~conflict = let open Lwt_result_syntax in let*! () = Refutation_game_event.Player.started - conflict.Sc_rollup.Refutation_storage.other - conflict.Sc_rollup.Refutation_storage.our_commitment + conflict.Game.other + conflict.Game.our_commitment in let worker_promise, worker_waker = Lwt.task () in let* worker = - trace Sc_rollup_node_errors.Refutation_player_failed_to_start + trace Rollup_node_errors.Refutation_player_failed_to_start @@ Worker.launch table conflict.other @@ -124,10 +123,11 @@ let init node_ctxt ~self ~conflict = in let () = Lwt.wakeup worker_waker worker in let worker = + let open Result_syntax in match Lwt.state worker_promise with - | Lwt.Return worker -> ok worker + | Lwt.Return worker -> return worker | Lwt.Fail _ | Lwt.Sleep -> - error Sc_rollup_node_errors.Refutation_player_failed_to_start + tzfail Rollup_node_errors.Refutation_player_failed_to_start in Lwt.return worker @@ -140,10 +140,7 @@ let should_move ~level game last_move_cache = match last_move_cache with | None -> true | Some (last_move_game_state, last_move_level) -> - (not - (Sc_rollup.Game.game_state_equal - game.Sc_rollup.Game.game_state - last_move_game_state)) + (not (Game.game_state_equal game.Game.game_state last_move_game_state)) || Int32.( sub level last_move_level > of_int Configuration.refutation_player_buffer_levels) @@ -153,8 +150,7 @@ let play w game ~(level : int32) = let state = Worker.state w in if should_move ~level game state.last_move_cache then ( let* pushed = Worker.Queue.push_request w (Request.Play game) in - if pushed then - state.last_move_cache <- Some (game.Sc_rollup.Game.game_state, level) ; + if pushed then state.last_move_cache <- Some (game.Game.game_state, level) ; return_unit) else return_unit diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player.mli b/src/lib_smart_rollup_node/refutation_player.mli similarity index 91% rename from src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player.mli rename to src/lib_smart_rollup_node/refutation_player.mli index 92592e7c7cc5f17f7aa70b9be69eb6319bd31c1b..64cca0e7e56a96bce9f14a6aa286b0fae03525e6 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player.mli +++ b/src/lib_smart_rollup_node/refutation_player.mli @@ -23,9 +23,6 @@ (* *) (*****************************************************************************) -open Protocol -open Alpha_context - (** Worker module for a single refutation game player. The node's refutation coordinator will spawn a new refutation player for each refutation game. *) @@ -40,20 +37,20 @@ type worker = Worker.infinite Worker.queue Worker.t is passed, the worker will play the opening move for [conflict]. *) val init_and_play : Node_context.rw -> - self:public_key_hash -> - conflict:Sc_rollup.Refutation_storage.conflict -> - game:Sc_rollup.Game.t option -> + self:Signature.public_key_hash -> + conflict:Game.conflict -> + game:Game.t option -> level:int32 -> unit tzresult Lwt.t (** [play worker game ~level] makes the [worker] play the next move depending on the [game] state for their conflict. *) -val play : worker -> Sc_rollup.Game.t -> level:int32 -> unit Lwt.t +val play : worker -> Game.t -> level:int32 -> unit Lwt.t (** Shutdown a refutaiton game player. *) val shutdown : worker -> unit Lwt.t (** [current_games ()] lists the opponents' this node is playing refutation games against, alongside the worker that takes care of each game. *) -val current_games : unit -> (public_key_hash * worker) list +val current_games : unit -> (Signature.public_key_hash * worker) list diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player_types.ml b/src/lib_smart_rollup_node/refutation_player_types.ml similarity index 82% rename from src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player_types.ml rename to src/lib_smart_rollup_node/refutation_player_types.ml index 5cb43af305096ca46dc4584d791b021229c4d0d2..8ff59d0b864566580c43f08d8a79f33ab5144bf6 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player_types.ml +++ b/src/lib_smart_rollup_node/refutation_player_types.ml @@ -22,15 +22,11 @@ (* DEALINGS IN THE SOFTWARE. *) (* *) (*****************************************************************************) -open Protocol -open Alpha_context module Request = struct type ('a, 'b) t = - | Play : Sc_rollup.Game.t -> (unit, error trace) t - | Play_opening : - Sc_rollup.Refutation_storage.conflict - -> (unit, error trace) t + | Play : Game.t -> (unit, error trace) t + | Play_opening : Game.conflict -> (unit, error trace) t type view = View : _ t -> view @@ -43,9 +39,7 @@ module Request = struct case (Tag 0) ~title:"Play" - (obj2 - (req "request" (constant "play")) - (req "game" Sc_rollup.Game.encoding)) + (obj2 (req "request" (constant "play")) (req "game" Game.encoding)) (function View (Play g) -> Some ((), g) | _ -> None) (fun ((), g) -> View (Play g)); case @@ -53,21 +47,28 @@ module Request = struct ~title:"Play opening" (obj2 (req "request" (constant "play_opening")) - (req "conflict" Sc_rollup.Refutation_storage.conflict_encoding)) + (req "conflict" Game.conflict_encoding)) (function View (Play_opening c) -> Some ((), c) | _ -> None) (fun ((), c) -> View (Play_opening c)); ] let pp ppf (View r) = match r with - | Play game -> Format.fprintf ppf "Playing game %a" Sc_rollup.Game.pp game + | Play game -> + Format.fprintf + ppf + "Playing game %a" + Data_encoding.Json.pp + (Data_encoding.Json.construct Game.encoding game) | Play_opening conflict -> Format.fprintf ppf "Playing opening move for conflict against staker %a at our \ commitment %a" - Sc_rollup.Staker.pp + Signature.Public_key_hash.pp conflict.other - Sc_rollup.Commitment.pp - conflict.our_commitment + Data_encoding.Json.pp + (Data_encoding.Json.construct + Commitment.encoding + conflict.our_commitment) end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player_types.mli b/src/lib_smart_rollup_node/refutation_player_types.mli similarity index 92% rename from src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player_types.mli rename to src/lib_smart_rollup_node/refutation_player_types.mli index d29fd8289f450cde25d7a3e5b4fa6bc7ca278e8b..9479a391e48ca5a170cf63dcbdc556a1a69624de 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player_types.mli +++ b/src/lib_smart_rollup_node/refutation_player_types.mli @@ -23,17 +23,12 @@ (* *) (*****************************************************************************) -open Protocol -open Alpha_context - module Request : sig (** Type of requests accepted by the refutation player. *) type ('a, 'b) t = - | Play : Sc_rollup.Game.t -> (unit, error trace) t + | Play : Game.t -> (unit, error trace) t (** Play a step of an ongoing refutation game. *) - | Play_opening : - Sc_rollup.Refutation_storage.conflict - -> (unit, error trace) t + | Play_opening : Game.conflict -> (unit, error trace) t (** Play the opening move of a refutation game. *) type view = View : _ t -> view diff --git a/src/lib_smart_rollup_node/rollup_node_daemon.ml b/src/lib_smart_rollup_node/rollup_node_daemon.ml index 7528eef257ee9115be88efb3112697ec33bcea03..9d9171661ad94d1015ef4ba376956146a53fe1ad 100644 --- a/src/lib_smart_rollup_node/rollup_node_daemon.ml +++ b/src/lib_smart_rollup_node/rollup_node_daemon.ml @@ -57,24 +57,22 @@ let previous_context (node_ctxt : _ Node_context.t) return (Context.empty node_ctxt.context) else Node_context.checkout_context node_ctxt predecessor.Layer1.hash -let start_workers ?(degraded = false) (configuration : Configuration.t) +let start_workers (configuration : Configuration.t) (plugin : (module Protocol_plugin_sig.S)) (node_ctxt : _ Node_context.t) = let open Lwt_result_syntax in let module Plugin = (val plugin) in + let* () = Publisher.init node_ctxt in let* () = - unless degraded @@ fun () -> - let* () = Publisher.init node_ctxt in match Configuration.Operator_purpose_map.find Add_messages node_ctxt.operators with | None -> return_unit | Some signer -> Batcher.init plugin configuration.batcher ~signer node_ctxt in - let* () = Plugin.Refutation_coordinator.init node_ctxt in + let* () = Refutation_coordinator.init node_ctxt in return_unit -let handle_protocol_migration ?degraded ~catching_up state - (head : Layer1.header) = +let handle_protocol_migration ~catching_up state (head : Layer1.header) = let open Lwt_result_syntax in let* head_proto = Node_context.protocol_of_level state.node_ctxt head.level in let new_protocol = head_proto.protocol in @@ -90,10 +88,7 @@ let handle_protocol_migration ?degraded ~catching_up state let*? constants, new_plugin = protocol_info state.node_ctxt.cctxt new_protocol head.hash in - let* constants - and* () = - start_workers ?degraded state.configuration new_plugin state.node_ctxt - in + let* constants in let new_protocol = { Node_context.hash = new_protocol; @@ -273,7 +268,7 @@ let on_layer_1_head ({node_ctxt; _} as state) (head : Layer1.header) = let* () = Publisher.publish_commitments () in let* () = Publisher.cement_commitments () in let*! () = Daemon_event.new_heads_processed reorg.new_chain in - let* () = Plugin.Refutation_coordinator.process stripped_head in + let* () = Refutation_coordinator.process stripped_head in let* () = Batcher.new_head stripped_head in let*! () = Injector.inject ~header:head.header () in return_unit @@ -291,13 +286,9 @@ let degraded_refutation_mode state = let*! () = message "Shutting down Commitment Publisher@." in let*! () = Publisher.shutdown () in Layer1.iter_heads state.node_ctxt.l1_ctxt @@ fun head -> - let* () = - handle_protocol_migration ~degraded:true ~catching_up:false state head - in + let* () = handle_protocol_migration ~catching_up:false state head in let module Plugin = (val state.plugin) in - let* () = - Plugin.Refutation_coordinator.process (Layer1.head_of_header head) - in + let* () = Refutation_coordinator.process (Layer1.head_of_header head) in let*! () = Injector.inject () in return_unit @@ -315,7 +306,7 @@ let install_finalizer state = let* () = message "Shutting down Commitment Publisher@." in let* () = Publisher.shutdown () in let* () = message "Shutting down Refutation Coordinator@." in - let* () = Plugin.Refutation_coordinator.shutdown () in + let* () = Refutation_coordinator.shutdown () in let* (_ : unit tzresult) = Node_context.close state.node_ctxt in let* () = Event.shutdown_node exit_status in Tezos_base_unix.Internal_event_unix.close () diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_layer2/sc_rollup_proto_types.ml b/src/proto_016_PtMumbai/lib_sc_rollup_layer2/sc_rollup_proto_types.ml index 5bb9d6dbb492327d34b256e2d8c66b1693287040..4df8dba798d2de3e036aba53f3e9ec980e54be13 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_layer2/sc_rollup_proto_types.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_layer2/sc_rollup_proto_types.ml @@ -94,6 +94,8 @@ end module Inbox = struct type t = Sc_rollup.Inbox.t + type history_proof = Sc_rollup.Inbox.history_proof + let to_repr inbox = inbox |> Data_encoding.Binary.to_string_exn Sc_rollup.Inbox.encoding @@ -119,6 +121,121 @@ module Inbox = struct |> Data_encoding.Binary.of_string_exn Octez_smart_rollup.Inbox.versioned_encoding |> Octez_smart_rollup.Inbox.of_versioned + + (* Workaround because history_proof encoding not in Alpha_context *) + let proto_history_proof_encoding : + Sc_rollup.Inbox.history_proof Data_encoding.t = + let level_proof_encoding = + let open Data_encoding in + conv + (fun {Sc_rollup.Inbox.hash; level} -> (hash, level)) + (fun (hash, level) -> {hash; level}) + (obj2 + (req "hash" Sc_rollup.Inbox_merkelized_payload_hashes.Hash.encoding) + (req "level" Raw_level.encoding)) + in + Sc_rollup.Inbox.Skip_list.encoding + Sc_rollup.Inbox.Hash.encoding + level_proof_encoding + + let history_proof_of_octez (hist : Octez_smart_rollup.Inbox.history_proof) : + history_proof = + hist + |> Data_encoding.Binary.to_string_exn + Octez_smart_rollup.Inbox.history_proof_encoding + |> Data_encoding.Binary.of_string_exn proto_history_proof_encoding + + let history_proof_to_octez (hist : history_proof) : + Octez_smart_rollup.Inbox.history_proof = + hist + |> Data_encoding.Binary.to_string_exn proto_history_proof_encoding + |> Data_encoding.Binary.of_string_exn + Octez_smart_rollup.Inbox.history_proof_encoding +end + +module Dal = struct + module Slot_index = struct + type t = Dal.Slot_index.t + + let of_octez (i : Octez_smart_rollup.Dal.Slot_index.t) : t = + match Dal.Slot_index.of_int i with + | None -> Format.ksprintf invalid_arg "Dal.Slot_index.of_octez: %d" i + | Some i -> i + + let to_octez : t -> Octez_smart_rollup.Dal.Slot_index.t = + Dal.Slot_index.to_int + end + + module Page_index = struct + type t = Dal.Page.Index.t + + let of_octez : Octez_smart_rollup.Dal.Page_index.t -> t = Fun.id + + let to_octez : t -> Octez_smart_rollup.Dal.Page_index.t = Fun.id + end + + module Slot_header = struct + type t = Dal.Slot.Header.t + + let of_octez + Octez_smart_rollup.Dal.Slot_header. + {id = {published_level; index}; commitment} : t = + Dal.Slot.Header. + { + id = + { + published_level = Raw_level.of_int32_exn published_level; + index = Slot_index.of_octez index; + }; + commitment; + } + + let to_octez Dal.Slot.Header.{id = {published_level; index}; commitment} : + Octez_smart_rollup.Dal.Slot_header.t = + Octez_smart_rollup.Dal.Slot_header. + { + id = + { + published_level = Raw_level.to_int32 published_level; + index = Slot_index.to_octez index; + }; + commitment; + } + end + + module Slot_history = struct + type t = Dal.Slots_history.t + + let of_octez (h : Octez_smart_rollup.Dal.Slot_history.t) : t = + h + |> Data_encoding.Binary.to_bytes_exn + Octez_smart_rollup.Dal.Slot_history.encoding + |> Data_encoding.Binary.of_bytes_exn Dal.Slots_history.encoding + + let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history.t = + h + |> Data_encoding.Binary.to_bytes_exn Dal.Slots_history.encoding + |> Data_encoding.Binary.of_bytes_exn + Octez_smart_rollup.Dal.Slot_history.encoding + end + + module Slot_history_cache = struct + type t = Dal.Slots_history.History_cache.t + + let of_octez (h : Octez_smart_rollup.Dal.Slot_history_cache.t) : t = + h + |> Data_encoding.Binary.to_bytes_exn + Octez_smart_rollup.Dal.Slot_history_cache.encoding + |> Data_encoding.Binary.of_bytes_exn + Dal.Slots_history.History_cache.encoding + + let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history_cache.t = + h + |> Data_encoding.Binary.to_bytes_exn + Dal.Slots_history.History_cache.encoding + |> Data_encoding.Binary.of_bytes_exn + Octez_smart_rollup.Dal.Slot_history_cache.encoding + end end module Commitment = struct @@ -161,6 +278,14 @@ module Game = struct type index = Sc_rollup.Game.Index.t + type player = Sc_rollup.Game.player + + type game_state = Sc_rollup.Game.game_state + + type t = Sc_rollup.Game.t + + type conflict = Sc_rollup.Refutation_storage.conflict + let dissection_chunk_of_octez Octez_smart_rollup.Game.{state_hash; tick} : dissection_chunk = { @@ -238,101 +363,114 @@ module Game = struct let index_to_octez Sc_rollup.Game.Index.{alice; bob} = Octez_smart_rollup.Game.make_index alice bob -end - -module Kind = struct - type t = Sc_rollup.Kind.t - - let of_octez : Octez_smart_rollup.Kind.t -> t = function - | Example_arith -> Example_arith - | Wasm_2_0_0 -> Wasm_2_0_0 - - let to_octez : t -> Octez_smart_rollup.Kind.t = function - | Example_arith -> Example_arith - | Wasm_2_0_0 -> Wasm_2_0_0 -end - -module Dal = struct - module Slot_index = struct - type t = Dal.Slot_index.t - - let of_octez (i : Octez_smart_rollup.Dal.Slot_index.t) : t = - match Dal.Slot_index.of_int i with - | None -> Format.ksprintf invalid_arg "Dal.Slot_index.of_octez: %d" i - | Some i -> i - let to_octez : t -> Octez_smart_rollup.Dal.Slot_index.t = - Dal.Slot_index.to_int - end + let player_of_octez : Octez_smart_rollup.Game.player -> player = function + | Alice -> Alice + | Bob -> Bob - module Page_index = struct - type t = Dal.Page.Index.t - - let of_octez : Octez_smart_rollup.Dal.Page_index.t -> t = Fun.id + let player_to_octez : player -> Octez_smart_rollup.Game.player = function + | Alice -> Alice + | Bob -> Bob - let to_octez : t -> Octez_smart_rollup.Dal.Page_index.t = Fun.id - end + let game_state_of_octez : Octez_smart_rollup.Game.game_state -> game_state = + function + | Dissecting {dissection; default_number_of_sections} -> + Dissecting + { + dissection = List.map dissection_chunk_of_octez dissection; + default_number_of_sections; + } + | Final_move {agreed_start_chunk; refuted_stop_chunk} -> + Final_move + { + agreed_start_chunk = dissection_chunk_of_octez agreed_start_chunk; + refuted_stop_chunk = dissection_chunk_of_octez refuted_stop_chunk; + } - module Slot_header = struct - type t = Dal.Slot.Header.t + let game_state_to_octez : game_state -> Octez_smart_rollup.Game.game_state = + function + | Dissecting {dissection; default_number_of_sections} -> + Dissecting + { + dissection = List.map dissection_chunk_to_octez dissection; + default_number_of_sections; + } + | Final_move {agreed_start_chunk; refuted_stop_chunk} -> + Final_move + { + agreed_start_chunk = dissection_chunk_to_octez agreed_start_chunk; + refuted_stop_chunk = dissection_chunk_to_octez refuted_stop_chunk; + } - let of_octez - Octez_smart_rollup.Dal.Slot_header. - {id = {published_level; index}; commitment} : t = - Dal.Slot.Header. + let of_octez + Octez_smart_rollup.Game. { - id = - { - published_level = Raw_level.of_int32_exn published_level; - index = Slot_index.of_octez index; - }; - commitment; - } + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + } : t = + { + turn = player_of_octez turn; + inbox_snapshot = Inbox.history_proof_of_octez inbox_snapshot; + dal_snapshot = Dal.Slot_history.of_octez dal_snapshot; + start_level = Raw_level.of_int32_exn start_level; + inbox_level = Raw_level.of_int32_exn inbox_level; + game_state = game_state_of_octez game_state; + } - let to_octez Dal.Slot.Header.{id = {published_level; index}; commitment} : - Octez_smart_rollup.Dal.Slot_header.t = - Octez_smart_rollup.Dal.Slot_header. + let to_octez + Sc_rollup.Game. { - id = - { - published_level = Raw_level.to_int32 published_level; - index = Slot_index.to_octez index; - }; - commitment; - } - end - - module Slot_history = struct - type t = Dal.Slots_history.t + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + } : Octez_smart_rollup.Game.t = + { + turn = player_to_octez turn; + inbox_snapshot = Inbox.history_proof_to_octez inbox_snapshot; + dal_snapshot = Dal.Slot_history.to_octez dal_snapshot; + start_level = Raw_level.to_int32 start_level; + inbox_level = Raw_level.to_int32 inbox_level; + game_state = game_state_to_octez game_state; + } - let of_octez (h : Octez_smart_rollup.Dal.Slot_history.t) : t = - h - |> Data_encoding.Binary.to_bytes_exn - Octez_smart_rollup.Dal.Slot_history.encoding - |> Data_encoding.Binary.of_bytes_exn Dal.Slots_history.encoding + let conflict_of_octez + Octez_smart_rollup.Game. + {other; their_commitment; our_commitment; parent_commitment} : conflict + = + { + other; + their_commitment = Commitment.of_octez their_commitment; + our_commitment = Commitment.of_octez our_commitment; + parent_commitment = Commitment_hash.of_octez parent_commitment; + } - let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history.t = - h - |> Data_encoding.Binary.to_bytes_exn Dal.Slots_history.encoding - |> Data_encoding.Binary.of_bytes_exn - Octez_smart_rollup.Dal.Slot_history.encoding - end + let conflict_to_octez + Sc_rollup.Refutation_storage. + {other; their_commitment; our_commitment; parent_commitment} : + Octez_smart_rollup.Game.conflict = + { + other; + their_commitment = Commitment.to_octez their_commitment; + our_commitment = Commitment.to_octez our_commitment; + parent_commitment = Commitment_hash.to_octez parent_commitment; + } +end - module Slot_history_cache = struct - type t = Dal.Slots_history.History_cache.t +module Kind = struct + type t = Sc_rollup.Kind.t - let of_octez (h : Octez_smart_rollup.Dal.Slot_history_cache.t) : t = - h - |> Data_encoding.Binary.to_bytes_exn - Octez_smart_rollup.Dal.Slot_history_cache.encoding - |> Data_encoding.Binary.of_bytes_exn - Dal.Slots_history.History_cache.encoding + let of_octez : Octez_smart_rollup.Kind.t -> t = function + | Example_arith -> Example_arith + | Wasm_2_0_0 -> Wasm_2_0_0 - let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history_cache.t = - h - |> Data_encoding.Binary.to_bytes_exn - Dal.Slots_history.History_cache.encoding - |> Data_encoding.Binary.of_bytes_exn - Octez_smart_rollup.Dal.Slot_history_cache.encoding - end + let to_octez : t -> Octez_smart_rollup.Kind.t = function + | Example_arith -> Example_arith + | Wasm_2_0_0 -> Wasm_2_0_0 end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_layer2/sc_rollup_proto_types.mli b/src/proto_016_PtMumbai/lib_sc_rollup_layer2/sc_rollup_proto_types.mli index 905a7b7bde6dc484c26a08fdd5f47eaf8d4c951b..131d236b838f92f6bb499b441d54140fb26714b4 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_layer2/sc_rollup_proto_types.mli +++ b/src/proto_016_PtMumbai/lib_sc_rollup_layer2/sc_rollup_proto_types.mli @@ -76,9 +76,17 @@ end module Inbox : sig type t = Sc_rollup.Inbox.t + type history_proof = Sc_rollup.Inbox.history_proof + val of_octez : Octez_smart_rollup.Inbox.t -> t val to_octez : t -> Octez_smart_rollup.Inbox.t + + val history_proof_of_octez : + Octez_smart_rollup.Inbox.history_proof -> history_proof + + val history_proof_to_octez : + history_proof -> Octez_smart_rollup.Inbox.history_proof end module Game : sig @@ -107,6 +115,30 @@ module Game : sig val index_of_octez : Octez_smart_rollup.Game.index -> index val index_to_octez : index -> Octez_smart_rollup.Game.index + + type player = Sc_rollup.Game.player + + val player_of_octez : Octez_smart_rollup.Game.player -> player + + val player_to_octez : player -> Octez_smart_rollup.Game.player + + type game_state = Sc_rollup.Game.game_state + + val game_state_of_octez : Octez_smart_rollup.Game.game_state -> game_state + + val game_state_to_octez : game_state -> Octez_smart_rollup.Game.game_state + + type t = Sc_rollup.Game.t + + val of_octez : Octez_smart_rollup.Game.t -> t + + val to_octez : t -> Octez_smart_rollup.Game.t + + type conflict = Sc_rollup.Refutation_storage.conflict + + val conflict_of_octez : Octez_smart_rollup.Game.conflict -> conflict + + val conflict_to_octez : conflict -> Octez_smart_rollup.Game.conflict end module Kind : sig diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator.ml deleted file mode 100644 index 627b7399a5e91e1ed02a84efdca2cc0ab74abdf1..0000000000000000000000000000000000000000 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator.ml +++ /dev/null @@ -1,253 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context -open Refutation_coordinator_types -include Refutation_game -module Player = Refutation_player -module Pkh_map = Signature.Public_key_hash.Map -module Pkh_table = Signature.Public_key_hash.Table - -type state = { - node_ctxt : Node_context.rw; - cctxt : Protocol_client_context.full; - pending_opponents : unit Pkh_table.t; -} - -let get_conflicts cctxt head_block address key = - Plugin.RPC.Sc_rollup.conflicts - cctxt - (cctxt#chain, head_block) - (Sc_rollup_proto_types.Address.of_octez address) - key - -let get_ongoing_games cctxt head_block address key = - Plugin.RPC.Sc_rollup.ongoing_refutation_games - cctxt - (cctxt#chain, head_block) - (Sc_rollup_proto_types.Address.of_octez address) - key - -let untracked_conflicts opponent_players conflicts = - List.filter - (fun conflict -> - not - @@ Pkh_map.mem - conflict.Sc_rollup.Refutation_storage.other - opponent_players) - conflicts - -(* Transform the list of ongoing games [(Game.t * pkh * pkh) list] - into a mapping from opponents' pkhs to their corresponding game - state. -*) -let make_game_map self ongoing_games = - List.fold_left - (fun acc (game, alice, bob) -> - let opponent_pkh = - if Signature.Public_key_hash.equal self alice then bob else alice - in - Pkh_map.add opponent_pkh game acc) - Pkh_map.empty - ongoing_games - -let on_process Layer1.{hash; level} state = - let node_ctxt = state.node_ctxt in - let head_block = `Hash (hash, 0) in - let open Lwt_result_syntax in - let refute_signer = Node_context.get_operator node_ctxt Refute in - match refute_signer with - | None -> - (* Not injecting refutations, don't play refutation games *) - return_unit - | Some self -> - let Node_context.{rollup_address; _} = node_ctxt in - (* Current conflicts in L1 *) - let* conflicts = - get_conflicts state.cctxt head_block rollup_address self - in - (* Map of opponents the node is playing against to the corresponding - player worker *) - let opponent_players = - Pkh_map.of_seq @@ List.to_seq @@ Player.current_games () - in - (* Conflicts for which we need to start new refutation players. - Some of these might be ongoing. *) - let new_conflicts = untracked_conflicts opponent_players conflicts in - (* L1 ongoing games *) - let* ongoing_games = - get_ongoing_games state.cctxt head_block rollup_address self - in - (* Map between opponents and their corresponding games *) - let ongoing_game_map = make_game_map self ongoing_games in - (* Launch new players for new conflicts, and play one step *) - let* () = - List.iter_ep - (fun conflict -> - let other = conflict.Sc_rollup.Refutation_storage.other in - Pkh_table.replace state.pending_opponents other () ; - let game = Pkh_map.find_opt other ongoing_game_map in - Player.init_and_play node_ctxt ~self ~conflict ~game ~level) - new_conflicts - in - let*! () = - (* Play one step of the refutation game in every remaining player *) - Pkh_map.iter_p - (fun opponent worker -> - match Pkh_map.find opponent ongoing_game_map with - | Some game -> - Pkh_table.remove state.pending_opponents opponent ; - Player.play worker game ~level - | None -> - (* Kill finished players: those who don't aren't - playing against pending opponents that don't have - ongoing games in the L1 *) - if not @@ Pkh_table.mem state.pending_opponents opponent then - Player.shutdown worker - else Lwt.return_unit) - opponent_players - in - return_unit - -module Types = struct - type nonrec state = state - - type parameters = { - node_ctxt : Node_context.rw; - cctxt : Protocol_client_context.full; - } -end - -module Name = struct - (* We only have a single coordinator in the node *) - type t = unit - - let encoding = Data_encoding.unit - - let base = - (* But we can have multiple instances in the unit tests. This is just to - avoid conflicts in the events declarations. *) - Refutation_game_event.Coordinator.section @ ["worker"] - - let pp _ _ = () - - let equal () () = true -end - -module Worker = Worker.MakeSingle (Name) (Request) (Types) - -type worker = Worker.infinite Worker.queue Worker.t - -module Handlers = struct - type self = worker - - let on_request : - type r request_error. - worker -> (r, request_error) Request.t -> (r, request_error) result Lwt.t - = - fun w request -> - let state = Worker.state w in - match request with Request.Process b -> on_process b state - - type launch_error = error trace - - let on_launch _w () Types.{node_ctxt; cctxt} = - return {node_ctxt; cctxt; pending_opponents = Pkh_table.create 5} - - let on_error (type a b) _w st (r : (a, b) Request.t) (errs : b) : - unit tzresult Lwt.t = - let open Lwt_result_syntax in - let request_view = Request.view r in - let emit_and_return_errors errs = - let*! () = - Refutation_game_event.Coordinator.request_failed request_view st errs - in - return_unit - in - match r with Request.Process _ -> emit_and_return_errors errs - - let on_completion _w r _ st = - Refutation_game_event.Coordinator.request_completed (Request.view r) st - - let on_no_request _ = Lwt.return_unit - - let on_close _w = Lwt.return_unit -end - -let table = Worker.create_table Queue - -let worker_promise, worker_waker = Lwt.task () - -let start node_ctxt = - let open Lwt_result_syntax in - let*! () = Refutation_game_event.Coordinator.starting () in - let cctxt = - new Protocol_client_context.wrap_full node_ctxt.Node_context.cctxt - in - let+ worker = Worker.launch table () {node_ctxt; cctxt} (module Handlers) in - Lwt.wakeup worker_waker worker - -let init node_ctxt = - let open Lwt_result_syntax in - match Lwt.state worker_promise with - | Lwt.Return _ -> - (* Worker already started, nothing to do. *) - return_unit - | Lwt.Fail exn -> - (* Worker crashed, not recoverable. *) - fail [Sc_rollup_node_errors.No_refutation_coordinator; Exn exn] - | Lwt.Sleep -> - (* Never started, start it. *) - start node_ctxt - -(* This is a refutation coordinator for a single scoru *) -let worker = - lazy - (match Lwt.state worker_promise with - | Lwt.Return worker -> ok worker - | Lwt.Fail _ | Lwt.Sleep -> - error Sc_rollup_node_errors.No_refutation_coordinator) - -let process b = - let open Lwt_result_syntax in - let*? w = Lazy.force worker in - let*! (_pushed : bool) = Worker.Queue.push_request w (Request.Process b) in - return_unit - -let shutdown () = - let open Lwt_syntax in - let w = Lazy.force worker in - match w with - | Error _ -> - (* There is no refutation coordinator, nothing to do *) - Lwt.return_unit - | Ok w -> - (* Shut down all current refutation players *) - let games = Player.current_games () in - let* () = - List.iter_s (fun (_opponent, player) -> Player.shutdown player) games - in - Worker.shutdown w diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator.mli deleted file mode 100644 index 12a35582b9b294687783aa6964b0290f6d3d35ea..0000000000000000000000000000000000000000 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_coordinator.mli +++ /dev/null @@ -1,47 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -(** Component for managing refutation games. - This module is implemented as a single worker in the rollup node, - which takes care of processing new L1 heads, and coordinating - the refutation game players. (See {!Refutation_player}). -*) - -(** Initiatilize the refuation coordinator. *) -val init : Node_context.rw -> unit tzresult Lwt.t - -(** Process a new l1 head. This means that the coordinator will: - {ol - {li Gather all existing conflicts} - {li Launch new refutation players for each conflict that doesn't - have a player in this node} - {li Kill all players whose conflict has disappeared from L1} - {li Make all players play a step in the refutation} - } - *) -val process : Layer1.head -> unit tzresult Lwt.t - -(** Shutdown the refutation coordinator. *) -val shutdown : unit -> unit Lwt.t diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.mli deleted file mode 100644 index 3229857d1aa7ad1cb2778b885650aff71cac5ff7..0000000000000000000000000000000000000000 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.mli +++ /dev/null @@ -1,46 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -(** This module implements the refutation game logic of the rollup node. *) - -(** [play_opening_move node_ctxt self conflict] injects the opening refutation - game move for [conflict]. *) -val play_opening_move : - [< `Read | `Write > `Read] Node_context.t -> - public_key_hash -> - Sc_rollup.Refutation_storage.conflict -> - (unit, tztrace) result Lwt.t - -(** [play head_block node_ctxt ~self game opponent] injects the next move in the - refutation [game] played by [self] and [opponent]. *) -val play : - Node_context.rw -> - self:public_key_hash -> - Sc_rollup.Game.t -> - public_key_hash -> - (unit, tztrace) result Lwt.t diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_event.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_event.ml deleted file mode 100644 index e12ea5dbc4c3a6248e222f41ff3a72bc8fdf3f5f..0000000000000000000000000000000000000000 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_event.ml +++ /dev/null @@ -1,260 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) -(* *) -(* 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 Protocol.Alpha_context - -(* TODO: https://gitlab.com/tezos/tezos/-/issues/2880 - Add corresponding .mli file. *) - -let section = [Protocol.name; "sc_rollup_node"; "refutation_game"] - -module Simple = struct - include Internal_event.Simple - - let timeout = - declare_1 - ~section - ~name:"sc_rollup_node_timeout" - ~msg: - "The rollup node has been slashed because of a timeout issued by \ - {address}" - ~level:Notice - ("address", Tezos_crypto.Signature.Public_key_hash.encoding) - - let invalid_move = - declare_0 - ~section - ~name:"sc_rollup_node_invalid_move" - ~msg: - "The rollup node is about to make an invalid move in the refutation \ - game! It is stopped to avoid being slashed. The problem should be \ - reported immediately or the rollup node should be upgraded to have a \ - chance to be back before the timeout is reached." - ~level:Notice - () - - let conflict_detected = - declare_5 - ~section - ~name:"sc_rollup_node_conflict_detected" - ~msg: - "A conflict has been found with our commitment {our_commitment_hash} \ - at level {level} with staker {other} that hash issued commitment \ - {their_commitment_hash} both based on {parent_commitment_hash}." - ~level:Notice - ("our_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("level", Raw_level.encoding) - ("other", Sc_rollup.Staker.encoding) - ("their_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("parent_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - - let potential_conflict_detected = - declare_4 - ~section - ~name:"sc_rollup_node_potential_conflict_detected" - ~msg: - "A potential conflict has been found with our commitment \ - {our_commitment_hash} at level {level} with staker {other} that hash \ - issued commitment {their_commitment_hash}." - ~level:Notice - ("our_commitment_hash", Octez_smart_rollup.Commitment.Hash.encoding) - ("level", Data_encoding.int32) - ("other", Signature.Public_key_hash.encoding) - ("their_commitment_hash", Octez_smart_rollup.Commitment.Hash.encoding) - - let timeout_detected = - declare_1 - ~section - ~name:"sc_rollup_node_timeout_detected" - ~msg: - "The rollup node has detected that opponent {other} can be timed out." - ~level:Notice - ("other", Sc_rollup.Staker.encoding) - - let dissection_chunk_encoding = - let open Data_encoding in - let open Sc_rollup.Dissection_chunk in - conv - (fun {state_hash; tick} -> (state_hash, tick)) - (fun (state_hash, tick) -> {state_hash; tick}) - (obj2 - (opt "state" Sc_rollup.State_hash.encoding) - (req "tick" Sc_rollup.Tick.encoding)) - - let computed_dissection = - declare_4 - ~section - ~name:"sc_rollup_node_computed_dissection" - ~msg: - "Computed dissection against {opponent} between ticks {start_tick} and \ - {end_tick}: {dissection}." - ~level:Debug - ("opponent", Signature.Public_key_hash.encoding) - ("start_tick", Sc_rollup.Tick.encoding) - ("end_tick", Sc_rollup.Tick.encoding) - ("dissection", Data_encoding.list dissection_chunk_encoding) - - module Worker (ARG : sig - val section : string list - end) - (Request : Worker_intf.REQUEST) = - struct - include ARG - - let request_failed = - declare_3 - ~section - ~name:"request_failed" - ~msg:"request {view} failed ({worker_status}): {errors}" - ~level:Notice - ("view", Request.encoding) - ~pp1:Request.pp - ("worker_status", Worker_types.request_status_encoding) - ~pp2:Worker_types.pp_status - ("errors", Error_monad.trace_encoding) - ~pp3:Error_monad.pp_print_trace - - let request_completed = - declare_2 - ~section - ~name:"request_completed" - ~msg:"{view} {worker_status}" - ~level:Debug - ("view", Request.encoding) - ("worker_status", Worker_types.request_status_encoding) - ~pp1:Request.pp - ~pp2:Worker_types.pp_status - end - - module Player = struct - include - Worker - (struct - let section = section @ ["player"] - end) - (Refutation_player_types.Request) - - let started = - declare_2 - ~section - ~name:"player_started" - ~msg: - "refutation player started to play against {opponent}, defenfing \ - commitment {commitment}" - ~level:Notice - ("opponent", Signature.Public_key_hash.encoding) - ~pp1:Signature.Public_key_hash.pp - ("commitment", Sc_rollup.Commitment.encoding) - ~pp2:Sc_rollup.Commitment.pp - - let stopped = - declare_1 - ~section - ~name:"player_stopped" - ~msg:"refutation player for opponent {opponent} has been stopped" - ~level:Notice - ("opponent", Signature.Public_key_hash.encoding) - ~pp1:Signature.Public_key_hash.pp - end - - module Coordinator = struct - include - Worker - (struct - let section = section @ ["coordinator"] - end) - (Refutation_coordinator_types.Request) - - let starting = - declare_0 - ~section - ~name:"coordinator_starting" - ~msg:"Starting refutation coordinator for the smart rollup node" - ~level:Notice - () - end -end - -let timeout address = Simple.(emit timeout address) - -let invalid_move () = Simple.(emit invalid_move ()) - -let conflict_detected (conflict : Sc_rollup.Refutation_storage.conflict) = - let our_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.our_commitment - in - let their_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.their_commitment - in - let parent_commitment_hash = conflict.parent_commitment in - let other = conflict.other in - let level = conflict.our_commitment.inbox_level in - Simple.( - emit - conflict_detected - ( our_commitment_hash, - level, - other, - their_commitment_hash, - parent_commitment_hash )) - -let potential_conflict_detected ~our_commitment_hash ~their_commitment_hash - ~other ~level = - Simple.( - emit - potential_conflict_detected - (our_commitment_hash, level, other, their_commitment_hash)) - -let timeout_detected other = Simple.(emit timeout_detected other) - -let computed_dissection ~opponent ~start_tick ~end_tick dissection = - Simple.(emit computed_dissection (opponent, start_tick, end_tick, dissection)) - -module Player = struct - let section = Simple.Player.section - - let request_failed view worker_status errors = - Simple.(emit Player.request_failed (view, worker_status, errors)) - - let request_completed view worker_status = - Simple.(emit Player.request_completed (view, worker_status)) - - let started opponent commitment = - Simple.(emit Player.started (opponent, commitment)) - - let stopped opponent = Simple.(emit Player.stopped opponent) -end - -module Coordinator = struct - let section = Simple.Coordinator.section - - let request_failed view worker_status errors = - Simple.(emit Coordinator.request_failed (view, worker_status, errors)) - - let request_completed view worker_status = - Simple.(emit Coordinator.request_completed (view, worker_status)) - - let starting = Simple.(emit Coordinator.starting) -end diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_helpers.ml similarity index 51% rename from src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.ml rename to src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_helpers.ml index 38b0f8895d1c0650b80936d8c3ed76bb919db9eb..0b9cc943bd163f61d88b75b77a2f9901e54a109d 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_helpers.ml @@ -1,7 +1,9 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) +(* Copyright (c) 2023 Functori, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -23,61 +25,8 @@ (* *) (*****************************************************************************) -(** This module implements the refutation game logic of the rollup - node. - - When a new L1 block arises, the rollup node asks the L1 node for - the current game it is part of, if any. - - If a game is running and it is the rollup operator turn, the rollup - node injects the next move of the winning strategy. - - If a game is running and it is not the rollup operator turn, the - rollup node asks the L1 node whether the timeout is reached to play - the timeout argument if possible. - - Otherwise, if no game is running, the rollup node asks the L1 node - whether there is a conflict with one of its disputable commitments. If - there is such a conflict with a commitment C', then the rollup node - starts a game to refute C' by starting a game with one of its staker. - -*) open Protocol - open Alpha_context -open Sc_rollup.Game - -let node_role ~self Sc_rollup.Game.Index.{alice; bob} = - if Sc_rollup.Staker.equal alice self then Alice - else if Sc_rollup.Staker.equal bob self then Bob - else (* By validity of [ongoing_game] RPC. *) - assert false - -type role = Our_turn of {opponent : public_key_hash} | Their_turn - -let turn ~self game players = - let Sc_rollup.Game.Index.{alice; bob} = players in - match (node_role ~self players, game.turn) with - | Alice, Alice -> Our_turn {opponent = bob} - | Bob, Bob -> Our_turn {opponent = alice} - | Alice, Bob -> Their_turn - | Bob, Alice -> Their_turn - -(** [inject_next_move node_ctxt source ~refutation ~opponent ~commitment - ~opponent_commitment] submits an L1 operation (signed by [source]) to issue - the next move in the refutation game. *) -let inject_next_move node_ctxt source ~refutation ~opponent = - let open Lwt_result_syntax in - let refute_operation = - L1_operation.Refute - { - rollup = node_ctxt.Node_context.rollup_address; - refutation = Sc_rollup_proto_types.Game.refutation_to_octez refutation; - opponent; - } - in - let* _hash = Injector.add_pending_operation ~source refute_operation in - return_unit (** This function computes the inclusion/membership proof of the page identified by [page_id] in the slot whose data are provided in @@ -109,14 +58,14 @@ let page_membership_proof params page_index slot_data = Cryptobox.string_of_commit_error commit_error) (** When the PVM is waiting for a Dal page input, this function attempts to - retrieve the page's content from the store, the data of its slot. Then it - computes the proof that the page is part of the slot and returns the content - along with the proof. - - If the PVM is not waiting for a Dal page input, or if the slot is known to - be unconfirmed on L1, this function returns [None]. If the data of the slot - are not saved to the store, the function returns a failure in the error - monad. *) + retrieve the page's content from the store, the data of its slot. Then it + computes the proof that the page is part of the slot and returns the + content along with the proof. + + If the PVM is not waiting for a Dal page input, or if the slot is known to + be unconfirmed on L1, this function returns [None]. If the data of the + slot are not saved to the store, the function returns a failure + in the error monad. *) let page_info_from_pvm_state (node_ctxt : _ Node_context.t) ~dal_attestation_lag (dal_params : Dal.parameters) start_state = let open Lwt_result_syntax in @@ -159,23 +108,24 @@ let metadata (node_ctxt : _ Node_context.t) = let origination_level = Raw_level.of_int32_exn node_ctxt.genesis_info.level in Sc_rollup.Metadata.{address; origination_level} -let generate_proof (node_ctxt : _ Node_context.t) game start_state = +let generate_proof (node_ctxt : _ Node_context.t) + (game : Octez_smart_rollup.Game.t) start_state = let open Lwt_result_syntax in let module PVM = (val Pvm.of_kind node_ctxt.kind) in - let snapshot = game.inbox_snapshot in + let snapshot = + Sc_rollup_proto_types.Inbox.history_proof_of_octez game.inbox_snapshot + in (* NOTE: [snapshot_level_int32] below refers to the level of the snapshotted inbox (from the skip list) which also matches [game.start_level - 1]. *) let snapshot_level_int32 = - Raw_level.to_int32 (Sc_rollup.Inbox.Skip_list.content snapshot).level + (Octez_smart_rollup.Inbox.Skip_list.content game.inbox_snapshot).level in let get_snapshot_head () = let+ hash = Node_context.hash_of_level node_ctxt snapshot_level_int32 in Layer1.{hash; level = snapshot_level_int32} in let* context = - let* start_hash = - Node_context.hash_of_level node_ctxt (Raw_level.to_int32 game.inbox_level) - in + let* start_hash = Node_context.hash_of_level node_ctxt game.inbox_level in let+ context = Node_context.checkout_context node_ctxt start_hash in Context.index context in @@ -259,7 +209,8 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = ~error:(Format.kasprintf Stdlib.failwith "%a" pp_print_trace)) @@ let open Lwt_result_syntax in - let* {predecessor; predecessor_timestamp; messages; _} = + let* {is_first_block = _; predecessor; predecessor_timestamp; messages} + = Node_context.get_messages node_ctxt (Sc_rollup_proto_types.Merkelized_payload_hashes_hash.to_octez @@ -294,10 +245,13 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = trace (Sc_rollup_node_errors.Cannot_produce_proof { - inbox_level = Raw_level.to_int32 game.inbox_level; + inbox_level = game.inbox_level; start_tick = Sc_rollup.Tick.to_z start_tick; }) - @@ (Sc_rollup.Proof.produce ~metadata (module P) game.inbox_level + @@ (Sc_rollup.Proof.produce + ~metadata + (module P) + (Raw_level.of_int32_exn game.inbox_level) >|= Environment.wrap_tzresult) in let*? pvm_step = @@ -309,7 +263,7 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = Sc_rollup.Proof.valid ~metadata snapshot - game.inbox_level + (Raw_level.of_int32_exn game.inbox_level) dal_slots_history dal_parameters ~dal_attestation_lag @@ -317,17 +271,25 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = unserialized_proof >|= Environment.wrap_tzresult in - if Result.is_ok res then return proof else assert false + assert (Result.is_ok res) ; + let proof = + Data_encoding.Binary.to_string_exn Sc_rollup.Proof.encoding proof + in + return proof -type pvm_intermediate_state = - | Hash of Sc_rollup.State_hash.t - | Evaluated of Fuel.Accounted.t Pvm_plugin_sig.eval_state +let state_of_tick node_ctxt ?start_state ~tick level = + Interpreter.state_of_tick + node_ctxt + ?start_state + ~tick + (Raw_level.of_int32_exn level) -let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok - our_view = +let make_dissection (node_ctxt : _ Node_context.t) ~start_state ~start_chunk + ~our_stop_chunk ~default_number_of_sections ~last_level = let open Lwt_result_syntax in + let module PVM = (val Pvm.of_kind node_ctxt.kind) in let state_of_tick ?start_state tick = - Interpreter.state_of_tick + state_of_tick node_ctxt ?start_state ~tick:(Sc_rollup.Tick.to_z tick) @@ -336,27 +298,13 @@ let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok let state_hash_of_eval_state Pvm_plugin_sig.{state_hash; _} = Sc_rollup_proto_types.State_hash.of_octez state_hash in - let start_hash, start_tick, start_state = - match ok with - | Hash hash, tick -> (hash, tick, None) - | Evaluated ({state_hash; _} as state), tick -> - (Sc_rollup_proto_types.State_hash.of_octez state_hash, tick, Some state) - in let start_chunk = - Sc_rollup.Dissection_chunk.{state_hash = Some start_hash; tick = start_tick} - in - let our_state, our_tick = our_view in - let our_state_hash = - Option.map - (fun Pvm_plugin_sig.{state_hash; _} -> - Sc_rollup_proto_types.State_hash.of_octez state_hash) - our_state + Sc_rollup_proto_types.Game.dissection_chunk_of_octez start_chunk in let our_stop_chunk = - Sc_rollup.Dissection_chunk.{state_hash = our_state_hash; tick = our_tick} + Sc_rollup_proto_types.Game.dissection_chunk_of_octez our_stop_chunk in - let module PVM = (val Pvm.of_kind node_ctxt.kind) in - let* dissection = + let+ dissection = Game_helpers.make_dissection ~state_of_tick ~state_hash_of_eval_state @@ -368,184 +316,49 @@ let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok ~our_stop_chunk ~default_number_of_sections in - let*! () = - Refutation_game_event.computed_dissection - ~opponent - ~start_tick - ~end_tick:our_tick - dissection - in - return dissection - -(** [generate_from_dissection ~default_number_of_sections node_ctxt game - dissection] traverses the current [dissection] and returns a move which - performs a new dissection of the execution trace or provides a refutation - proof to serve as the next move of the [game]. *) -let generate_next_dissection ~default_number_of_sections node_ctxt ~opponent - game dissection = - let open Lwt_result_syntax in - let rec traverse ok = function - | [] -> - (* The game invariant states that the dissection from the - opponent must contain a tick we disagree with. If the - retrieved game does not respect this, we cannot trust the - Tezos node we are connected to and prefer to stop here. *) - tzfail - Sc_rollup_node_errors - .Unreliable_tezos_node_returning_inconsistent_game - | Sc_rollup.Dissection_chunk.{state_hash = their_hash; tick} :: dissection - -> ( - let start_state = - match ok with - | Hash _, _ -> None - | Evaluated ok_state, _ -> Some ok_state - in - let* our = - Interpreter.state_of_tick - node_ctxt - ?start_state - ~tick:(Sc_rollup.Tick.to_z tick) - game.inbox_level - in - match (their_hash, our) with - | None, None -> - (* This case is absurd since: [None] can only occur at the - end and the two players disagree about the end. *) - assert false - | Some _, None | None, Some _ -> return (ok, (our, tick)) - | Some their_hash, Some ({state_hash = our_hash; _} as our_state) -> - if - Sc_rollup.State_hash.equal - (Sc_rollup_proto_types.State_hash.of_octez our_hash) - their_hash - then traverse (Evaluated our_state, tick) dissection - else return (ok, (our, tick))) - in - match dissection with - | Sc_rollup.Dissection_chunk.{state_hash = Some hash; tick} :: dissection -> - let* ok, ko = traverse (Hash hash, tick) dissection in - let* dissection = - new_dissection - ~opponent - ~default_number_of_sections - node_ctxt - game.inbox_level - ok - ko - in - let _, choice = ok in - let _, ko_tick = ko in - let chosen_section_len = Sc_rollup.Tick.distance ko_tick choice in - return (choice, chosen_section_len, dissection) - | [] | {state_hash = None; _} :: _ -> - (* - By wellformedness of dissection. - A dissection always starts with a tick of the form [(Some hash, tick)]. - A dissection always contains strictly more than one element. - *) - tzfail - Sc_rollup_node_errors.Unreliable_tezos_node_returning_inconsistent_game - -let next_move node_ctxt ~opponent game = - let open Lwt_result_syntax in - let final_move start_tick = - let* start_state = - Interpreter.state_of_tick - node_ctxt - ~tick:(Sc_rollup.Tick.to_z start_tick) - game.inbox_level - in - match start_state with - | None -> - tzfail - Sc_rollup_node_errors - .Unreliable_tezos_node_returning_inconsistent_game - | Some {state = start_state; _} -> - let* proof = generate_proof node_ctxt game start_state in - let choice = start_tick in - return (Move {choice; step = Proof proof}) - in - - match game.game_state with - | Dissecting {dissection; default_number_of_sections} -> - let* choice, chosen_section_len, dissection = - generate_next_dissection - ~default_number_of_sections - node_ctxt - ~opponent - game - dissection - in - if Z.(equal chosen_section_len one) then final_move choice - else return (Move {choice; step = Dissection dissection}) - | Final_move {agreed_start_chunk; refuted_stop_chunk = _} -> - let choice = agreed_start_chunk.tick in - final_move choice - -let play_next_move node_ctxt game self opponent = - let open Lwt_result_syntax in - let* refutation = next_move node_ctxt ~opponent game in - inject_next_move node_ctxt self ~refutation ~opponent - -let play_timeout (node_ctxt : _ Node_context.t) self stakers = - let open Lwt_result_syntax in - let timeout_operation = - L1_operation.Timeout - { - rollup = node_ctxt.rollup_address; - stakers = Sc_rollup_proto_types.Game.index_to_octez stakers; - } - in - let source = - Node_context.get_operator node_ctxt Timeout |> Option.value ~default:self - (* We fallback on the [Refute] operator if none is provided for [Timeout] *) - in - let* _hash = Injector.add_pending_operation ~source timeout_operation in - return_unit + List.map Sc_rollup_proto_types.Game.dissection_chunk_to_octez dissection -let timeout_reached ~self head_block node_ctxt staker1 staker2 = +let timeout_reached node_ctxt ~self ~opponent = let open Lwt_result_syntax in let Node_context.{rollup_address; cctxt; _} = node_ctxt in - let* game_result = + let+ game_result = Plugin.RPC.Sc_rollup.timeout_reached (new Protocol_client_context.wrap_full cctxt) - (cctxt#chain, head_block) + (cctxt#chain, `Head 0) (Sc_rollup_proto_types.Address.of_octez rollup_address) - staker1 - staker2 + self + opponent in let open Sc_rollup.Game in match game_result with | Some (Loser {loser; _}) -> let is_it_me = Signature.Public_key_hash.(self = loser) in - if is_it_me then return_none else return (Some loser) - | _ -> return_none + not is_it_me + | _ -> false -let play node_ctxt ~self game opponent = +let get_conflicts cctxt rollup staker = let open Lwt_result_syntax in - let index = Sc_rollup.Game.Index.make self opponent in - let head_block = `Head 0 in - match turn ~self game index with - | Our_turn {opponent} -> play_next_move node_ctxt game self opponent - | Their_turn -> ( - let* timeout_reached = - timeout_reached ~self head_block node_ctxt self opponent - in - match timeout_reached with - | Some opponent -> - let*! () = Refutation_game_event.timeout_detected opponent in - play_timeout node_ctxt self index - | None -> return_unit) - -let play_opening_move node_ctxt self conflict = - let open Lwt_syntax in - let open Sc_rollup.Refutation_storage in - let* () = Refutation_game_event.conflict_detected conflict in - let player_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.our_commitment + let cctxt = new Protocol_client_context.wrap_full cctxt in + let+ conflicts = + Plugin.RPC.Sc_rollup.conflicts + cctxt + (cctxt#chain, `Head 0) + (Sc_rollup_proto_types.Address.of_octez rollup) + staker in - let opponent_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.their_commitment + List.map Sc_rollup_proto_types.Game.conflict_to_octez conflicts + +let get_ongoing_games cctxt rollup staker = + let open Lwt_result_syntax in + let cctxt = new Protocol_client_context.wrap_full cctxt in + let+ games = + Plugin.RPC.Sc_rollup.ongoing_refutation_games + cctxt + (cctxt#chain, `Head 0) + (Sc_rollup_proto_types.Address.of_octez rollup) + staker in - let refutation = Start {player_commitment_hash; opponent_commitment_hash} in - inject_next_move node_ctxt self ~refutation ~opponent:conflict.other + List.map + (fun (game, staker1, staker2) -> + (Sc_rollup_proto_types.Game.to_octez game, staker1, staker2)) + games diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_helpers.mli b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_helpers.mli new file mode 100644 index 0000000000000000000000000000000000000000..8799f5deb3aa72166227ae37c12c9d2cc5226b42 --- /dev/null +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_game_helpers.mli @@ -0,0 +1,81 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) +(* Copyright (c) 2023 Functori, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** [generate_proof node_ctxt (game) start_state] generates a serialized proof + for the current [game] for the execution step starting with + [start_state]. *) +val generate_proof : + Node_context.rw -> Game.t -> Context.tree -> string tzresult Lwt.t + +(** [state_of_tick node_ctxt ?start_state ~tick level] returns [Some + (state, hash)] for a given [tick] if this [tick] happened before + [level]. Otherwise, returns [None]. If provided, the evaluation is resumed + from [start_state]. *) +val state_of_tick : + _ Node_context.t -> + ?start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state -> + tick:Z.t -> + int32 -> + Fuel.Accounted.t Pvm_plugin_sig.eval_state option tzresult Lwt.t + +(** [make_dissection node_ctxt ~start_state ~start_chunk ~our_stop_chunk + ~default_number_of_sections ~last_level] computes a dissection from between + [start_chunk] and [our_stop_chunk] at level [last_level]. This dissection + has [default_number_of_sections] if there are enough ticks. *) +val make_dissection : + _ Node_context.t -> + start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state option -> + start_chunk:Game.dissection_chunk -> + our_stop_chunk:Game.dissection_chunk -> + default_number_of_sections:int -> + last_level:int32 -> + Game.dissection_chunk trace tzresult Lwt.t + +(** [timeout_reached node_ctxt ~self ~opponent] returns [true] if the + timeout is reached against opponent in head of the L1 chain. *) +val timeout_reached : + _ Node_context.t -> + self:Signature.public_key_hash -> + opponent:Signature.public_key_hash -> + bool tzresult Lwt.t + +(** [get_conflicts cctxt rollup signer] returns the conflicts for commitments + staked on by [signer]. *) +val get_conflicts : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + Game.conflict list tzresult Lwt.t + +(** [get_ongoing_games cctxt rollup signer] returns the games that [signer] is + currently playing. *) +val get_ongoing_games : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + (Game.t * Signature.public_key_hash * Signature.public_key_hash) list tzresult + Lwt.t diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player.ml deleted file mode 100644 index 1258a6fa25d6c1f64b87bce7cb963052d5b40c54..0000000000000000000000000000000000000000 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/refutation_player.ml +++ /dev/null @@ -1,185 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context -open Refutation_player_types -open Refutation_game - -module Types = struct - type state = { - node_ctxt : Node_context.rw; - self : public_key_hash; - opponent : public_key_hash; - mutable last_move_cache : (Sc_rollup.Game.game_state * int32) option; - } - - type parameters = { - node_ctxt : Node_context.rw; - self : public_key_hash; - conflict : Sc_rollup.Refutation_storage.conflict; - } -end - -module Name = struct - let base = Refutation_game_event.Player.section @ ["worker"] - - include Signature.Public_key_hash -end - -module Worker = Worker.MakeSingle (Name) (Request) (Types) - -type worker = Worker.infinite Worker.queue Worker.t - -let table = Worker.create_table Queue - -let on_play game Types.{node_ctxt; self; opponent; _} = - play node_ctxt ~self game opponent - -let on_play_opening conflict (Types.{node_ctxt; self; _} : Types.state) = - play_opening_move node_ctxt self conflict - -module Handlers = struct - type self = worker - - let on_request : - type r request_error. - worker -> (r, request_error) Request.t -> (r, request_error) result Lwt.t - = - fun w request -> - let state = Worker.state w in - match request with - | Request.Play game -> on_play game state - | Request.Play_opening conflict -> on_play_opening conflict state - - type launch_error = error trace - - let on_launch _w _name Types.{node_ctxt; self; conflict} = - return - Types.{node_ctxt; self; opponent = conflict.other; last_move_cache = None} - - let on_error (type a b) _w st (r : (a, b) Request.t) (errs : b) : - unit tzresult Lwt.t = - let open Lwt_result_syntax in - let request_view = Request.view r in - let emit_and_return_errors errs = - let*! () = - Refutation_game_event.Player.request_failed request_view st errs - in - return_unit - in - match r with - | Request.Play _ -> emit_and_return_errors errs - | Request.Play_opening _ -> emit_and_return_errors errs - - let on_completion _w r _ st = - Refutation_game_event.Player.request_completed (Request.view r) st - - let on_no_request _ = Lwt.return_unit - - let on_close w = - let open Lwt_syntax in - let state = Worker.state w in - let* () = Refutation_game_event.Player.stopped state.opponent in - return_unit -end - -let init node_ctxt ~self ~conflict = - let open Lwt_result_syntax in - let*! () = - Refutation_game_event.Player.started - conflict.Sc_rollup.Refutation_storage.other - conflict.Sc_rollup.Refutation_storage.our_commitment - in - let worker_promise, worker_waker = Lwt.task () in - let* worker = - trace Sc_rollup_node_errors.Refutation_player_failed_to_start - @@ Worker.launch - table - conflict.other - {node_ctxt; self; conflict} - (module Handlers) - in - let () = Lwt.wakeup worker_waker worker in - let worker = - match Lwt.state worker_promise with - | Lwt.Return worker -> ok worker - | Lwt.Fail _ | Lwt.Sleep -> - error Sc_rollup_node_errors.Refutation_player_failed_to_start - in - Lwt.return worker - -(* Number of levels the player waits until trying to play - for a game state it already played for. *) -let buffer_levels = 5l - -(* Play if: - - There's a new game state to play against or - - The current level is past the buffer for re-playing in the - same game state. -*) -let should_move ~level game last_move_cache = - match last_move_cache with - | None -> true - | Some (last_move_game_state, last_move_level) -> - (not - (Sc_rollup.Game.game_state_equal - game.Sc_rollup.Game.game_state - last_move_game_state)) - || Int32.(sub level last_move_level > buffer_levels) - -let play w game ~(level : int32) = - let open Lwt_syntax in - let state = Worker.state w in - if should_move ~level game state.last_move_cache then ( - let* pushed = Worker.Queue.push_request w (Request.Play game) in - if pushed then - state.last_move_cache <- Some (game.Sc_rollup.Game.game_state, level) ; - return_unit) - else return_unit - -let play_opening w conflict = - let open Lwt_syntax in - let* (_pushed : bool) = - Worker.Queue.push_request w (Request.Play_opening conflict) - in - return_unit - -let init_and_play node_ctxt ~self ~conflict ~game ~level = - let open Lwt_result_syntax in - let* worker = init node_ctxt ~self ~conflict in - let*! () = - match game with - | None -> play_opening worker conflict - | Some game -> play worker game ~level - in - return_unit - -let current_games () = - List.map - (fun (_name, worker) -> ((Worker.state worker).opponent, worker)) - (Worker.list table) - -let shutdown = Worker.shutdown diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/rollup_node_plugin.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/rollup_node_plugin.ml index d54d5b6674235872968376834fd8ab660cf6fbbf..4c5dd5e5cfe44af177cd455e62b8dd74819996ad 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/rollup_node_plugin.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/rollup_node_plugin.ml @@ -30,7 +30,7 @@ module Plugin : Protocol_plugin_sig.S = struct module Dal_slots_tracker = Dal_slots_tracker module Inbox = Inbox module Interpreter = Interpreter - module Refutation_coordinator = Refutation_coordinator + module Refutation_game_helpers = Refutation_game_helpers module Batcher_constants = Batcher_constants module Layer1_helpers = Layer1_helpers module L1_processing = Daemon_helpers diff --git a/src/proto_017_PtNairob/lib_sc_rollup_layer2/sc_rollup_proto_types.ml b/src/proto_017_PtNairob/lib_sc_rollup_layer2/sc_rollup_proto_types.ml index e8c04d28ba95600bf8e40c65d7ebcbe8bdddcd72..28c86619eca1b011fcb87c8b80457ef2196a43a2 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_layer2/sc_rollup_proto_types.ml +++ b/src/proto_017_PtNairob/lib_sc_rollup_layer2/sc_rollup_proto_types.ml @@ -125,6 +125,8 @@ end module Inbox = struct type t = Sc_rollup.Inbox.t + type history_proof = Sc_rollup.Inbox.history_proof + let to_repr inbox = inbox |> Data_encoding.Binary.to_string_exn Sc_rollup.Inbox.encoding @@ -150,6 +152,121 @@ module Inbox = struct |> Data_encoding.Binary.of_string_exn Octez_smart_rollup.Inbox.versioned_encoding |> Octez_smart_rollup.Inbox.of_versioned + + (* Workaround because history_proof encoding not in Alpha_context *) + let proto_history_proof_encoding : + Sc_rollup.Inbox.history_proof Data_encoding.t = + let level_proof_encoding = + let open Data_encoding in + conv + (fun {Sc_rollup.Inbox.hash; level} -> (hash, level)) + (fun (hash, level) -> {hash; level}) + (obj2 + (req "hash" Sc_rollup.Inbox_merkelized_payload_hashes.Hash.encoding) + (req "level" Raw_level.encoding)) + in + Sc_rollup.Inbox.Skip_list.encoding + Sc_rollup.Inbox.Hash.encoding + level_proof_encoding + + let history_proof_of_octez (hist : Octez_smart_rollup.Inbox.history_proof) : + history_proof = + hist + |> Data_encoding.Binary.to_string_exn + Octez_smart_rollup.Inbox.history_proof_encoding + |> Data_encoding.Binary.of_string_exn proto_history_proof_encoding + + let history_proof_to_octez (hist : history_proof) : + Octez_smart_rollup.Inbox.history_proof = + hist + |> Data_encoding.Binary.to_string_exn proto_history_proof_encoding + |> Data_encoding.Binary.of_string_exn + Octez_smart_rollup.Inbox.history_proof_encoding +end + +module Dal = struct + module Slot_index = struct + type t = Dal.Slot_index.t + + let of_octez (i : Octez_smart_rollup.Dal.Slot_index.t) : t = + match Dal.Slot_index.of_int_opt i with + | None -> Format.ksprintf invalid_arg "Dal.Slot_index.of_octez: %d" i + | Some i -> i + + let to_octez : t -> Octez_smart_rollup.Dal.Slot_index.t = + Dal.Slot_index.to_int + end + + module Page_index = struct + type t = Dal.Page.Index.t + + let of_octez : Octez_smart_rollup.Dal.Page_index.t -> t = Fun.id + + let to_octez : t -> Octez_smart_rollup.Dal.Page_index.t = Fun.id + end + + module Slot_header = struct + type t = Dal.Slot.Header.t + + let of_octez + Octez_smart_rollup.Dal.Slot_header. + {id = {published_level; index}; commitment} : t = + Dal.Slot.Header. + { + id = + { + published_level = Raw_level.of_int32_exn published_level; + index = Slot_index.of_octez index; + }; + commitment; + } + + let to_octez Dal.Slot.Header.{id = {published_level; index}; commitment} : + Octez_smart_rollup.Dal.Slot_header.t = + Octez_smart_rollup.Dal.Slot_header. + { + id = + { + published_level = Raw_level.to_int32 published_level; + index = Slot_index.to_octez index; + }; + commitment; + } + end + + module Slot_history = struct + type t = Dal.Slots_history.t + + let of_octez (h : Octez_smart_rollup.Dal.Slot_history.t) : t = + h + |> Data_encoding.Binary.to_bytes_exn + Octez_smart_rollup.Dal.Slot_history.encoding + |> Data_encoding.Binary.of_bytes_exn Dal.Slots_history.encoding + + let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history.t = + h + |> Data_encoding.Binary.to_bytes_exn Dal.Slots_history.encoding + |> Data_encoding.Binary.of_bytes_exn + Octez_smart_rollup.Dal.Slot_history.encoding + end + + module Slot_history_cache = struct + type t = Dal.Slots_history.History_cache.t + + let of_octez (h : Octez_smart_rollup.Dal.Slot_history_cache.t) : t = + h + |> Data_encoding.Binary.to_bytes_exn + Octez_smart_rollup.Dal.Slot_history_cache.encoding + |> Data_encoding.Binary.of_bytes_exn + Dal.Slots_history.History_cache.encoding + + let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history_cache.t = + h + |> Data_encoding.Binary.to_bytes_exn + Dal.Slots_history.History_cache.encoding + |> Data_encoding.Binary.of_bytes_exn + Octez_smart_rollup.Dal.Slot_history_cache.encoding + end end module Game = struct @@ -161,6 +278,14 @@ module Game = struct type index = Sc_rollup.Game.Index.t + type player = Sc_rollup.Game.player + + type game_state = Sc_rollup.Game.game_state + + type t = Sc_rollup.Game.t + + type conflict = Sc_rollup.Refutation_storage.conflict + let dissection_chunk_of_octez Octez_smart_rollup.Game.{state_hash; tick} : dissection_chunk = { @@ -238,101 +363,114 @@ module Game = struct let index_to_octez Sc_rollup.Game.Index.{alice; bob} = Octez_smart_rollup.Game.make_index alice bob -end - -module Kind = struct - type t = Sc_rollup.Kind.t - - let of_octez : Octez_smart_rollup.Kind.t -> t = function - | Example_arith -> Example_arith - | Wasm_2_0_0 -> Wasm_2_0_0 - - let to_octez : t -> Octez_smart_rollup.Kind.t = function - | Example_arith -> Example_arith - | Wasm_2_0_0 -> Wasm_2_0_0 -end - -module Dal = struct - module Slot_index = struct - type t = Dal.Slot_index.t - - let of_octez (i : Octez_smart_rollup.Dal.Slot_index.t) : t = - match Dal.Slot_index.of_int_opt i with - | None -> Format.ksprintf invalid_arg "Dal.Slot_index.of_octez: %d" i - | Some i -> i - let to_octez : t -> Octez_smart_rollup.Dal.Slot_index.t = - Dal.Slot_index.to_int - end + let player_of_octez : Octez_smart_rollup.Game.player -> player = function + | Alice -> Alice + | Bob -> Bob - module Page_index = struct - type t = Dal.Page.Index.t - - let of_octez : Octez_smart_rollup.Dal.Page_index.t -> t = Fun.id + let player_to_octez : player -> Octez_smart_rollup.Game.player = function + | Alice -> Alice + | Bob -> Bob - let to_octez : t -> Octez_smart_rollup.Dal.Page_index.t = Fun.id - end + let game_state_of_octez : Octez_smart_rollup.Game.game_state -> game_state = + function + | Dissecting {dissection; default_number_of_sections} -> + Dissecting + { + dissection = List.map dissection_chunk_of_octez dissection; + default_number_of_sections; + } + | Final_move {agreed_start_chunk; refuted_stop_chunk} -> + Final_move + { + agreed_start_chunk = dissection_chunk_of_octez agreed_start_chunk; + refuted_stop_chunk = dissection_chunk_of_octez refuted_stop_chunk; + } - module Slot_header = struct - type t = Dal.Slot.Header.t + let game_state_to_octez : game_state -> Octez_smart_rollup.Game.game_state = + function + | Dissecting {dissection; default_number_of_sections} -> + Dissecting + { + dissection = List.map dissection_chunk_to_octez dissection; + default_number_of_sections; + } + | Final_move {agreed_start_chunk; refuted_stop_chunk} -> + Final_move + { + agreed_start_chunk = dissection_chunk_to_octez agreed_start_chunk; + refuted_stop_chunk = dissection_chunk_to_octez refuted_stop_chunk; + } - let of_octez - Octez_smart_rollup.Dal.Slot_header. - {id = {published_level; index}; commitment} : t = - Dal.Slot.Header. + let of_octez + Octez_smart_rollup.Game. { - id = - { - published_level = Raw_level.of_int32_exn published_level; - index = Slot_index.of_octez index; - }; - commitment; - } + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + } : t = + { + turn = player_of_octez turn; + inbox_snapshot = Inbox.history_proof_of_octez inbox_snapshot; + dal_snapshot = Dal.Slot_history.of_octez dal_snapshot; + start_level = Raw_level.of_int32_exn start_level; + inbox_level = Raw_level.of_int32_exn inbox_level; + game_state = game_state_of_octez game_state; + } - let to_octez Dal.Slot.Header.{id = {published_level; index}; commitment} : - Octez_smart_rollup.Dal.Slot_header.t = - Octez_smart_rollup.Dal.Slot_header. + let to_octez + Sc_rollup.Game. { - id = - { - published_level = Raw_level.to_int32 published_level; - index = Slot_index.to_octez index; - }; - commitment; - } - end - - module Slot_history = struct - type t = Dal.Slots_history.t + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + } : Octez_smart_rollup.Game.t = + { + turn = player_to_octez turn; + inbox_snapshot = Inbox.history_proof_to_octez inbox_snapshot; + dal_snapshot = Dal.Slot_history.to_octez dal_snapshot; + start_level = Raw_level.to_int32 start_level; + inbox_level = Raw_level.to_int32 inbox_level; + game_state = game_state_to_octez game_state; + } - let of_octez (h : Octez_smart_rollup.Dal.Slot_history.t) : t = - h - |> Data_encoding.Binary.to_bytes_exn - Octez_smart_rollup.Dal.Slot_history.encoding - |> Data_encoding.Binary.of_bytes_exn Dal.Slots_history.encoding + let conflict_of_octez + Octez_smart_rollup.Game. + {other; their_commitment; our_commitment; parent_commitment} : conflict + = + { + other; + their_commitment = Commitment.of_octez their_commitment; + our_commitment = Commitment.of_octez our_commitment; + parent_commitment = Commitment_hash.of_octez parent_commitment; + } - let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history.t = - h - |> Data_encoding.Binary.to_bytes_exn Dal.Slots_history.encoding - |> Data_encoding.Binary.of_bytes_exn - Octez_smart_rollup.Dal.Slot_history.encoding - end + let conflict_to_octez + Sc_rollup.Refutation_storage. + {other; their_commitment; our_commitment; parent_commitment} : + Octez_smart_rollup.Game.conflict = + { + other; + their_commitment = Commitment.to_octez their_commitment; + our_commitment = Commitment.to_octez our_commitment; + parent_commitment = Commitment_hash.to_octez parent_commitment; + } +end - module Slot_history_cache = struct - type t = Dal.Slots_history.History_cache.t +module Kind = struct + type t = Sc_rollup.Kind.t - let of_octez (h : Octez_smart_rollup.Dal.Slot_history_cache.t) : t = - h - |> Data_encoding.Binary.to_bytes_exn - Octez_smart_rollup.Dal.Slot_history_cache.encoding - |> Data_encoding.Binary.of_bytes_exn - Dal.Slots_history.History_cache.encoding + let of_octez : Octez_smart_rollup.Kind.t -> t = function + | Example_arith -> Example_arith + | Wasm_2_0_0 -> Wasm_2_0_0 - let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history_cache.t = - h - |> Data_encoding.Binary.to_bytes_exn - Dal.Slots_history.History_cache.encoding - |> Data_encoding.Binary.of_bytes_exn - Octez_smart_rollup.Dal.Slot_history_cache.encoding - end + let to_octez : t -> Octez_smart_rollup.Kind.t = function + | Example_arith -> Example_arith + | Wasm_2_0_0 -> Wasm_2_0_0 end diff --git a/src/proto_017_PtNairob/lib_sc_rollup_layer2/sc_rollup_proto_types.mli b/src/proto_017_PtNairob/lib_sc_rollup_layer2/sc_rollup_proto_types.mli index 905a7b7bde6dc484c26a08fdd5f47eaf8d4c951b..131d236b838f92f6bb499b441d54140fb26714b4 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_layer2/sc_rollup_proto_types.mli +++ b/src/proto_017_PtNairob/lib_sc_rollup_layer2/sc_rollup_proto_types.mli @@ -76,9 +76,17 @@ end module Inbox : sig type t = Sc_rollup.Inbox.t + type history_proof = Sc_rollup.Inbox.history_proof + val of_octez : Octez_smart_rollup.Inbox.t -> t val to_octez : t -> Octez_smart_rollup.Inbox.t + + val history_proof_of_octez : + Octez_smart_rollup.Inbox.history_proof -> history_proof + + val history_proof_to_octez : + history_proof -> Octez_smart_rollup.Inbox.history_proof end module Game : sig @@ -107,6 +115,30 @@ module Game : sig val index_of_octez : Octez_smart_rollup.Game.index -> index val index_to_octez : index -> Octez_smart_rollup.Game.index + + type player = Sc_rollup.Game.player + + val player_of_octez : Octez_smart_rollup.Game.player -> player + + val player_to_octez : player -> Octez_smart_rollup.Game.player + + type game_state = Sc_rollup.Game.game_state + + val game_state_of_octez : Octez_smart_rollup.Game.game_state -> game_state + + val game_state_to_octez : game_state -> Octez_smart_rollup.Game.game_state + + type t = Sc_rollup.Game.t + + val of_octez : Octez_smart_rollup.Game.t -> t + + val to_octez : t -> Octez_smart_rollup.Game.t + + type conflict = Sc_rollup.Refutation_storage.conflict + + val conflict_of_octez : Octez_smart_rollup.Game.conflict -> conflict + + val conflict_to_octez : conflict -> Octez_smart_rollup.Game.conflict end module Kind : sig diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator.ml deleted file mode 100644 index 627b7399a5e91e1ed02a84efdca2cc0ab74abdf1..0000000000000000000000000000000000000000 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator.ml +++ /dev/null @@ -1,253 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context -open Refutation_coordinator_types -include Refutation_game -module Player = Refutation_player -module Pkh_map = Signature.Public_key_hash.Map -module Pkh_table = Signature.Public_key_hash.Table - -type state = { - node_ctxt : Node_context.rw; - cctxt : Protocol_client_context.full; - pending_opponents : unit Pkh_table.t; -} - -let get_conflicts cctxt head_block address key = - Plugin.RPC.Sc_rollup.conflicts - cctxt - (cctxt#chain, head_block) - (Sc_rollup_proto_types.Address.of_octez address) - key - -let get_ongoing_games cctxt head_block address key = - Plugin.RPC.Sc_rollup.ongoing_refutation_games - cctxt - (cctxt#chain, head_block) - (Sc_rollup_proto_types.Address.of_octez address) - key - -let untracked_conflicts opponent_players conflicts = - List.filter - (fun conflict -> - not - @@ Pkh_map.mem - conflict.Sc_rollup.Refutation_storage.other - opponent_players) - conflicts - -(* Transform the list of ongoing games [(Game.t * pkh * pkh) list] - into a mapping from opponents' pkhs to their corresponding game - state. -*) -let make_game_map self ongoing_games = - List.fold_left - (fun acc (game, alice, bob) -> - let opponent_pkh = - if Signature.Public_key_hash.equal self alice then bob else alice - in - Pkh_map.add opponent_pkh game acc) - Pkh_map.empty - ongoing_games - -let on_process Layer1.{hash; level} state = - let node_ctxt = state.node_ctxt in - let head_block = `Hash (hash, 0) in - let open Lwt_result_syntax in - let refute_signer = Node_context.get_operator node_ctxt Refute in - match refute_signer with - | None -> - (* Not injecting refutations, don't play refutation games *) - return_unit - | Some self -> - let Node_context.{rollup_address; _} = node_ctxt in - (* Current conflicts in L1 *) - let* conflicts = - get_conflicts state.cctxt head_block rollup_address self - in - (* Map of opponents the node is playing against to the corresponding - player worker *) - let opponent_players = - Pkh_map.of_seq @@ List.to_seq @@ Player.current_games () - in - (* Conflicts for which we need to start new refutation players. - Some of these might be ongoing. *) - let new_conflicts = untracked_conflicts opponent_players conflicts in - (* L1 ongoing games *) - let* ongoing_games = - get_ongoing_games state.cctxt head_block rollup_address self - in - (* Map between opponents and their corresponding games *) - let ongoing_game_map = make_game_map self ongoing_games in - (* Launch new players for new conflicts, and play one step *) - let* () = - List.iter_ep - (fun conflict -> - let other = conflict.Sc_rollup.Refutation_storage.other in - Pkh_table.replace state.pending_opponents other () ; - let game = Pkh_map.find_opt other ongoing_game_map in - Player.init_and_play node_ctxt ~self ~conflict ~game ~level) - new_conflicts - in - let*! () = - (* Play one step of the refutation game in every remaining player *) - Pkh_map.iter_p - (fun opponent worker -> - match Pkh_map.find opponent ongoing_game_map with - | Some game -> - Pkh_table.remove state.pending_opponents opponent ; - Player.play worker game ~level - | None -> - (* Kill finished players: those who don't aren't - playing against pending opponents that don't have - ongoing games in the L1 *) - if not @@ Pkh_table.mem state.pending_opponents opponent then - Player.shutdown worker - else Lwt.return_unit) - opponent_players - in - return_unit - -module Types = struct - type nonrec state = state - - type parameters = { - node_ctxt : Node_context.rw; - cctxt : Protocol_client_context.full; - } -end - -module Name = struct - (* We only have a single coordinator in the node *) - type t = unit - - let encoding = Data_encoding.unit - - let base = - (* But we can have multiple instances in the unit tests. This is just to - avoid conflicts in the events declarations. *) - Refutation_game_event.Coordinator.section @ ["worker"] - - let pp _ _ = () - - let equal () () = true -end - -module Worker = Worker.MakeSingle (Name) (Request) (Types) - -type worker = Worker.infinite Worker.queue Worker.t - -module Handlers = struct - type self = worker - - let on_request : - type r request_error. - worker -> (r, request_error) Request.t -> (r, request_error) result Lwt.t - = - fun w request -> - let state = Worker.state w in - match request with Request.Process b -> on_process b state - - type launch_error = error trace - - let on_launch _w () Types.{node_ctxt; cctxt} = - return {node_ctxt; cctxt; pending_opponents = Pkh_table.create 5} - - let on_error (type a b) _w st (r : (a, b) Request.t) (errs : b) : - unit tzresult Lwt.t = - let open Lwt_result_syntax in - let request_view = Request.view r in - let emit_and_return_errors errs = - let*! () = - Refutation_game_event.Coordinator.request_failed request_view st errs - in - return_unit - in - match r with Request.Process _ -> emit_and_return_errors errs - - let on_completion _w r _ st = - Refutation_game_event.Coordinator.request_completed (Request.view r) st - - let on_no_request _ = Lwt.return_unit - - let on_close _w = Lwt.return_unit -end - -let table = Worker.create_table Queue - -let worker_promise, worker_waker = Lwt.task () - -let start node_ctxt = - let open Lwt_result_syntax in - let*! () = Refutation_game_event.Coordinator.starting () in - let cctxt = - new Protocol_client_context.wrap_full node_ctxt.Node_context.cctxt - in - let+ worker = Worker.launch table () {node_ctxt; cctxt} (module Handlers) in - Lwt.wakeup worker_waker worker - -let init node_ctxt = - let open Lwt_result_syntax in - match Lwt.state worker_promise with - | Lwt.Return _ -> - (* Worker already started, nothing to do. *) - return_unit - | Lwt.Fail exn -> - (* Worker crashed, not recoverable. *) - fail [Sc_rollup_node_errors.No_refutation_coordinator; Exn exn] - | Lwt.Sleep -> - (* Never started, start it. *) - start node_ctxt - -(* This is a refutation coordinator for a single scoru *) -let worker = - lazy - (match Lwt.state worker_promise with - | Lwt.Return worker -> ok worker - | Lwt.Fail _ | Lwt.Sleep -> - error Sc_rollup_node_errors.No_refutation_coordinator) - -let process b = - let open Lwt_result_syntax in - let*? w = Lazy.force worker in - let*! (_pushed : bool) = Worker.Queue.push_request w (Request.Process b) in - return_unit - -let shutdown () = - let open Lwt_syntax in - let w = Lazy.force worker in - match w with - | Error _ -> - (* There is no refutation coordinator, nothing to do *) - Lwt.return_unit - | Ok w -> - (* Shut down all current refutation players *) - let games = Player.current_games () in - let* () = - List.iter_s (fun (_opponent, player) -> Player.shutdown player) games - in - Worker.shutdown w diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator_types.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator_types.ml deleted file mode 100644 index 314698ed82ff7cce4951b0d7eadebaf9bf3b7247..0000000000000000000000000000000000000000 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator_types.ml +++ /dev/null @@ -1,56 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -module Request = struct - type ('a, 'b) t = Process : Layer1.head -> (unit, error trace) t - - type view = View : _ t -> view - - let view req = View req - - let encoding = - let open Data_encoding in - union - [ - case - (Tag 0) - ~title:"Process" - (obj2 - (req "request" (constant "process")) - (req "block" Layer1.head_encoding)) - (function View (Process b) -> Some ((), b)) - (fun ((), b) -> View (Process b)); - ] - - let pp ppf (View r) = - match r with - | Process {Layer1.hash; level} -> - Format.fprintf - ppf - "Processing new L1 head %a at level %ld" - Block_hash.pp - hash - level -end diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator_types.mli b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator_types.mli deleted file mode 100644 index f26d46885c774a05b48c75bcee47dd40a099fd64..0000000000000000000000000000000000000000 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_coordinator_types.mli +++ /dev/null @@ -1,38 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -module Request : sig - (** Type of requests accepted by the refutation coordinator. *) - type ('a, 'b) t = - | Process : Layer1.head -> (unit, error trace) t - (** Request to process new refutation games. *) - - type view = View : _ t -> view - - include - Worker_intf.REQUEST - with type ('a, 'request_error) t := ('a, 'request_error) t - and type view := view -end diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game_helpers.ml similarity index 54% rename from src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game.ml rename to src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game_helpers.ml index 5a6b60aaa7edba6686e942031786d8c95f26597d..2299dfa88d467f48ac3380ea44025d95dd75d0dd 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game.ml +++ b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game_helpers.ml @@ -1,7 +1,9 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) +(* Copyright (c) 2023 Functori, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -23,61 +25,8 @@ (* *) (*****************************************************************************) -(** This module implements the refutation game logic of the rollup - node. - - When a new L1 block arises, the rollup node asks the L1 node for - the current game it is part of, if any. - - If a game is running and it is the rollup operator turn, the rollup - node injects the next move of the winning strategy. - - If a game is running and it is not the rollup operator turn, the - rollup node asks the L1 node whether the timeout is reached to play - the timeout argument if possible. - - Otherwise, if no game is running, the rollup node asks the L1 node - whether there is a conflict with one of its disputable commitments. If - there is such a conflict with a commitment C', then the rollup node - starts a game to refute C' by starting a game with one of its staker. - -*) - open Protocol open Alpha_context -open Sc_rollup.Game - -let node_role ~self Sc_rollup.Game.Index.{alice; bob} = - if Sc_rollup.Staker.equal alice self then Alice - else if Sc_rollup.Staker.equal bob self then Bob - else (* By validity of [ongoing_game] RPC. *) - assert false - -type role = Our_turn of {opponent : public_key_hash} | Their_turn - -let turn ~self game players = - let Sc_rollup.Game.Index.{alice; bob} = players in - match (node_role ~self players, game.turn) with - | Alice, Alice -> Our_turn {opponent = bob} - | Bob, Bob -> Our_turn {opponent = alice} - | Alice, Bob -> Their_turn - | Bob, Alice -> Their_turn - -(** [inject_next_move node_ctxt source ~refutation ~opponent ~commitment - ~opponent_commitment] submits an L1 operation (signed by [source]) to - issue the next move in the refutation game. *) -let inject_next_move node_ctxt source ~refutation ~opponent = - let open Lwt_result_syntax in - let refute_operation = - L1_operation.Refute - { - rollup = node_ctxt.Node_context.rollup_address; - refutation = Sc_rollup_proto_types.Game.refutation_to_octez refutation; - opponent; - } - in - let* _hash = Injector.add_pending_operation ~source refute_operation in - return_unit (** This function computes the inclusion/membership proof of the page identified by [page_id] in the slot whose data are provided in @@ -159,23 +108,24 @@ let metadata (node_ctxt : _ Node_context.t) = let origination_level = Raw_level.of_int32_exn node_ctxt.genesis_info.level in Sc_rollup.Metadata.{address; origination_level} -let generate_proof (node_ctxt : _ Node_context.t) game start_state = +let generate_proof (node_ctxt : _ Node_context.t) + (game : Octez_smart_rollup.Game.t) start_state = let open Lwt_result_syntax in let module PVM = (val Pvm.of_kind node_ctxt.kind) in - let snapshot = game.inbox_snapshot in + let snapshot = + Sc_rollup_proto_types.Inbox.history_proof_of_octez game.inbox_snapshot + in (* NOTE: [snapshot_level_int32] below refers to the level of the snapshotted inbox (from the skip list) which also matches [game.start_level - 1]. *) let snapshot_level_int32 = - Raw_level.to_int32 (Sc_rollup.Inbox.Skip_list.content snapshot).level + (Octez_smart_rollup.Inbox.Skip_list.content game.inbox_snapshot).level in let get_snapshot_head () = let+ hash = Node_context.hash_of_level node_ctxt snapshot_level_int32 in Layer1.{hash; level = snapshot_level_int32} in let* context = - let* start_hash = - Node_context.hash_of_level node_ctxt (Raw_level.to_int32 game.inbox_level) - in + let* start_hash = Node_context.hash_of_level node_ctxt game.inbox_level in let+ context = Node_context.checkout_context node_ctxt start_hash in Context.index context in @@ -295,10 +245,13 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = trace (Sc_rollup_node_errors.Cannot_produce_proof { - inbox_level = Raw_level.to_int32 game.inbox_level; + inbox_level = game.inbox_level; start_tick = Sc_rollup.Tick.to_z start_tick; }) - @@ (Sc_rollup.Proof.produce ~metadata (module P) game.inbox_level + @@ (Sc_rollup.Proof.produce + ~metadata + (module P) + (Raw_level.of_int32_exn game.inbox_level) >|= Environment.wrap_tzresult) in let*? pvm_step = @@ -310,7 +263,7 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = Sc_rollup.Proof.valid ~metadata snapshot - game.inbox_level + (Raw_level.of_int32_exn game.inbox_level) dal_slots_history dal_parameters ~dal_attestation_lag @@ -318,17 +271,25 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = unserialized_proof >|= Environment.wrap_tzresult in - if Result.is_ok res then return proof else assert false + assert (Result.is_ok res) ; + let proof = + Data_encoding.Binary.to_string_exn Sc_rollup.Proof.encoding proof + in + return proof -type pvm_intermediate_state = - | Hash of Sc_rollup.State_hash.t - | Evaluated of Fuel.Accounted.t Pvm_plugin_sig.eval_state +let state_of_tick node_ctxt ?start_state ~tick level = + Interpreter.state_of_tick + node_ctxt + ?start_state + ~tick + (Raw_level.of_int32_exn level) -let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok - our_view = +let make_dissection (node_ctxt : _ Node_context.t) ~start_state ~start_chunk + ~our_stop_chunk ~default_number_of_sections ~last_level = let open Lwt_result_syntax in + let module PVM = (val Pvm.of_kind node_ctxt.kind) in let state_of_tick ?start_state tick = - Interpreter.state_of_tick + state_of_tick node_ctxt ?start_state ~tick:(Sc_rollup.Tick.to_z tick) @@ -337,27 +298,13 @@ let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok let state_hash_of_eval_state Pvm_plugin_sig.{state_hash; _} = Sc_rollup_proto_types.State_hash.of_octez state_hash in - let start_hash, start_tick, start_state = - match ok with - | Hash hash, tick -> (hash, tick, None) - | Evaluated ({state_hash; _} as state), tick -> - (Sc_rollup_proto_types.State_hash.of_octez state_hash, tick, Some state) - in let start_chunk = - Sc_rollup.Dissection_chunk.{state_hash = Some start_hash; tick = start_tick} - in - let our_state, our_tick = our_view in - let our_state_hash = - Option.map - (fun Pvm_plugin_sig.{state_hash; _} -> - Sc_rollup_proto_types.State_hash.of_octez state_hash) - our_state + Sc_rollup_proto_types.Game.dissection_chunk_of_octez start_chunk in let our_stop_chunk = - Sc_rollup.Dissection_chunk.{state_hash = our_state_hash; tick = our_tick} + Sc_rollup_proto_types.Game.dissection_chunk_of_octez our_stop_chunk in - let module PVM = (val Pvm.of_kind node_ctxt.kind) in - let* dissection = + let+ dissection = Game_helpers.make_dissection ~state_of_tick ~state_hash_of_eval_state @@ -369,184 +316,49 @@ let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok ~our_stop_chunk ~default_number_of_sections in - let*! () = - Refutation_game_event.computed_dissection - ~opponent - ~start_tick - ~end_tick:our_tick - dissection - in - return dissection + List.map Sc_rollup_proto_types.Game.dissection_chunk_to_octez dissection -(** [generate_from_dissection ~default_number_of_sections node_ctxt game - dissection] traverses the current [dissection] and returns a move which - performs a new dissection of the execution trace or provides a refutation - proof to serve as the next move of the [game]. *) -let generate_next_dissection ~default_number_of_sections node_ctxt ~opponent - game dissection = - let open Lwt_result_syntax in - let rec traverse ok = function - | [] -> - (* The game invariant states that the dissection from the - opponent must contain a tick we disagree with. If the - retrieved game does not respect this, we cannot trust the - Tezos node we are connected to and prefer to stop here. *) - tzfail - Sc_rollup_node_errors - .Unreliable_tezos_node_returning_inconsistent_game - | Sc_rollup.Dissection_chunk.{state_hash = their_hash; tick} :: dissection - -> ( - let start_state = - match ok with - | Hash _, _ -> None - | Evaluated ok_state, _ -> Some ok_state - in - let* our = - Interpreter.state_of_tick - node_ctxt - ?start_state - ~tick:(Sc_rollup.Tick.to_z tick) - game.inbox_level - in - match (their_hash, our) with - | None, None -> - (* This case is absurd since: [None] can only occur at the - end and the two players disagree about the end. *) - assert false - | Some _, None | None, Some _ -> return (ok, (our, tick)) - | Some their_hash, Some ({state_hash = our_hash; _} as our_state) -> - if - Sc_rollup.State_hash.equal - (Sc_rollup_proto_types.State_hash.of_octez our_hash) - their_hash - then traverse (Evaluated our_state, tick) dissection - else return (ok, (our, tick))) - in - match dissection with - | Sc_rollup.Dissection_chunk.{state_hash = Some hash; tick} :: dissection -> - let* ok, ko = traverse (Hash hash, tick) dissection in - let* dissection = - new_dissection - ~opponent - ~default_number_of_sections - node_ctxt - game.inbox_level - ok - ko - in - let _, choice = ok in - let _, ko_tick = ko in - let chosen_section_len = Sc_rollup.Tick.distance ko_tick choice in - return (choice, chosen_section_len, dissection) - | [] | {state_hash = None; _} :: _ -> - (* - By wellformedness of dissection. - A dissection always starts with a tick of the form [(Some hash, tick)]. - A dissection always contains strictly more than one element. - *) - tzfail - Sc_rollup_node_errors.Unreliable_tezos_node_returning_inconsistent_game - -let next_move node_ctxt ~opponent game = - let open Lwt_result_syntax in - let final_move start_tick = - let* start_state = - Interpreter.state_of_tick - node_ctxt - ~tick:(Sc_rollup.Tick.to_z start_tick) - game.inbox_level - in - match start_state with - | None -> - tzfail - Sc_rollup_node_errors - .Unreliable_tezos_node_returning_inconsistent_game - | Some {state = start_state; _} -> - let* proof = generate_proof node_ctxt game start_state in - let choice = start_tick in - return (Move {choice; step = Proof proof}) - in - - match game.game_state with - | Dissecting {dissection; default_number_of_sections} -> - let* choice, chosen_section_len, dissection = - generate_next_dissection - ~default_number_of_sections - node_ctxt - ~opponent - game - dissection - in - if Z.(equal chosen_section_len one) then final_move choice - else return (Move {choice; step = Dissection dissection}) - | Final_move {agreed_start_chunk; refuted_stop_chunk = _} -> - let choice = agreed_start_chunk.tick in - final_move choice - -let play_next_move node_ctxt game self opponent = - let open Lwt_result_syntax in - let* refutation = next_move node_ctxt ~opponent game in - inject_next_move node_ctxt self ~refutation ~opponent - -let play_timeout (node_ctxt : _ Node_context.t) self stakers = - let open Lwt_result_syntax in - let timeout_operation = - L1_operation.Timeout - { - rollup = node_ctxt.rollup_address; - stakers = Sc_rollup_proto_types.Game.index_to_octez stakers; - } - in - let source = - Node_context.get_operator node_ctxt Timeout |> Option.value ~default:self - (* We fallback on the [Refute] operator if none is provided for [Timeout] *) - in - let* _hash = Injector.add_pending_operation ~source timeout_operation in - return_unit - -let timeout_reached ~self head_block node_ctxt staker1 staker2 = +let timeout_reached node_ctxt ~self ~opponent = let open Lwt_result_syntax in let Node_context.{rollup_address; cctxt; _} = node_ctxt in - let* game_result = + let+ game_result = Plugin.RPC.Sc_rollup.timeout_reached (new Protocol_client_context.wrap_full cctxt) - (cctxt#chain, head_block) + (cctxt#chain, `Head 0) (Sc_rollup_proto_types.Address.of_octez rollup_address) - staker1 - staker2 + self + opponent in let open Sc_rollup.Game in match game_result with | Some (Loser {loser; _}) -> let is_it_me = Signature.Public_key_hash.(self = loser) in - if is_it_me then return_none else return (Some loser) - | _ -> return_none + not is_it_me + | _ -> false -let play node_ctxt ~self game opponent = +let get_conflicts cctxt rollup staker = let open Lwt_result_syntax in - let index = Sc_rollup.Game.Index.make self opponent in - let head_block = `Head 0 in - match turn ~self game index with - | Our_turn {opponent} -> play_next_move node_ctxt game self opponent - | Their_turn -> ( - let* timeout_reached = - timeout_reached ~self head_block node_ctxt self opponent - in - match timeout_reached with - | Some opponent -> - let*! () = Refutation_game_event.timeout_detected opponent in - play_timeout node_ctxt self index - | None -> return_unit) - -let play_opening_move node_ctxt self conflict = - let open Lwt_syntax in - let open Sc_rollup.Refutation_storage in - let* () = Refutation_game_event.conflict_detected conflict in - let player_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.our_commitment + let cctxt = new Protocol_client_context.wrap_full cctxt in + let+ conflicts = + Plugin.RPC.Sc_rollup.conflicts + cctxt + (cctxt#chain, `Head 0) + (Sc_rollup_proto_types.Address.of_octez rollup) + staker in - let opponent_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.their_commitment + List.map Sc_rollup_proto_types.Game.conflict_to_octez conflicts + +let get_ongoing_games cctxt rollup staker = + let open Lwt_result_syntax in + let cctxt = new Protocol_client_context.wrap_full cctxt in + let+ games = + Plugin.RPC.Sc_rollup.ongoing_refutation_games + cctxt + (cctxt#chain, `Head 0) + (Sc_rollup_proto_types.Address.of_octez rollup) + staker in - let refutation = Start {player_commitment_hash; opponent_commitment_hash} in - inject_next_move node_ctxt self ~refutation ~opponent:conflict.other + List.map + (fun (game, staker1, staker2) -> + (Sc_rollup_proto_types.Game.to_octez game, staker1, staker2)) + games diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game_helpers.mli b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game_helpers.mli new file mode 100644 index 0000000000000000000000000000000000000000..8799f5deb3aa72166227ae37c12c9d2cc5226b42 --- /dev/null +++ b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_game_helpers.mli @@ -0,0 +1,81 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) +(* Copyright (c) 2023 Functori, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** [generate_proof node_ctxt (game) start_state] generates a serialized proof + for the current [game] for the execution step starting with + [start_state]. *) +val generate_proof : + Node_context.rw -> Game.t -> Context.tree -> string tzresult Lwt.t + +(** [state_of_tick node_ctxt ?start_state ~tick level] returns [Some + (state, hash)] for a given [tick] if this [tick] happened before + [level]. Otherwise, returns [None]. If provided, the evaluation is resumed + from [start_state]. *) +val state_of_tick : + _ Node_context.t -> + ?start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state -> + tick:Z.t -> + int32 -> + Fuel.Accounted.t Pvm_plugin_sig.eval_state option tzresult Lwt.t + +(** [make_dissection node_ctxt ~start_state ~start_chunk ~our_stop_chunk + ~default_number_of_sections ~last_level] computes a dissection from between + [start_chunk] and [our_stop_chunk] at level [last_level]. This dissection + has [default_number_of_sections] if there are enough ticks. *) +val make_dissection : + _ Node_context.t -> + start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state option -> + start_chunk:Game.dissection_chunk -> + our_stop_chunk:Game.dissection_chunk -> + default_number_of_sections:int -> + last_level:int32 -> + Game.dissection_chunk trace tzresult Lwt.t + +(** [timeout_reached node_ctxt ~self ~opponent] returns [true] if the + timeout is reached against opponent in head of the L1 chain. *) +val timeout_reached : + _ Node_context.t -> + self:Signature.public_key_hash -> + opponent:Signature.public_key_hash -> + bool tzresult Lwt.t + +(** [get_conflicts cctxt rollup signer] returns the conflicts for commitments + staked on by [signer]. *) +val get_conflicts : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + Game.conflict list tzresult Lwt.t + +(** [get_ongoing_games cctxt rollup signer] returns the games that [signer] is + currently playing. *) +val get_ongoing_games : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + (Game.t * Signature.public_key_hash * Signature.public_key_hash) list tzresult + Lwt.t diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player.ml deleted file mode 100644 index 72901a452bf2e325b3b1fb5c791a1d61767884a3..0000000000000000000000000000000000000000 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player.ml +++ /dev/null @@ -1,183 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context -open Refutation_player_types -open Refutation_game - -module Types = struct - type state = { - node_ctxt : Node_context.rw; - self : public_key_hash; - opponent : public_key_hash; - mutable last_move_cache : (Sc_rollup.Game.game_state * int32) option; - } - - type parameters = { - node_ctxt : Node_context.rw; - self : public_key_hash; - conflict : Sc_rollup.Refutation_storage.conflict; - } -end - -module Name = struct - let base = Refutation_game_event.Player.section @ ["worker"] - - include Signature.Public_key_hash -end - -module Worker = Worker.MakeSingle (Name) (Request) (Types) - -type worker = Worker.infinite Worker.queue Worker.t - -let table = Worker.create_table Queue - -let on_play game Types.{node_ctxt; self; opponent; _} = - play node_ctxt ~self game opponent - -let on_play_opening conflict (Types.{node_ctxt; self; _} : Types.state) = - play_opening_move node_ctxt self conflict - -module Handlers = struct - type self = worker - - let on_request : - type r request_error. - worker -> (r, request_error) Request.t -> (r, request_error) result Lwt.t - = - fun w request -> - let state = Worker.state w in - match request with - | Request.Play game -> on_play game state - | Request.Play_opening conflict -> on_play_opening conflict state - - type launch_error = error trace - - let on_launch _w _name Types.{node_ctxt; self; conflict} = - return - Types.{node_ctxt; self; opponent = conflict.other; last_move_cache = None} - - let on_error (type a b) _w st (r : (a, b) Request.t) (errs : b) : - unit tzresult Lwt.t = - let open Lwt_result_syntax in - let request_view = Request.view r in - let emit_and_return_errors errs = - let*! () = - Refutation_game_event.Player.request_failed request_view st errs - in - return_unit - in - match r with - | Request.Play _ -> emit_and_return_errors errs - | Request.Play_opening _ -> emit_and_return_errors errs - - let on_completion _w r _ st = - Refutation_game_event.Player.request_completed (Request.view r) st - - let on_no_request _ = Lwt.return_unit - - let on_close w = - let open Lwt_syntax in - let state = Worker.state w in - let* () = Refutation_game_event.Player.stopped state.opponent in - return_unit -end - -let init node_ctxt ~self ~conflict = - let open Lwt_result_syntax in - let*! () = - Refutation_game_event.Player.started - conflict.Sc_rollup.Refutation_storage.other - conflict.Sc_rollup.Refutation_storage.our_commitment - in - let worker_promise, worker_waker = Lwt.task () in - let* worker = - trace Sc_rollup_node_errors.Refutation_player_failed_to_start - @@ Worker.launch - table - conflict.other - {node_ctxt; self; conflict} - (module Handlers) - in - let () = Lwt.wakeup worker_waker worker in - let worker = - match Lwt.state worker_promise with - | Lwt.Return worker -> ok worker - | Lwt.Fail _ | Lwt.Sleep -> - error Sc_rollup_node_errors.Refutation_player_failed_to_start - in - Lwt.return worker - -(* Play if: - - There's a new game state to play against or - - The current level is past the buffer for re-playing in the - same game state. -*) -let should_move ~level game last_move_cache = - match last_move_cache with - | None -> true - | Some (last_move_game_state, last_move_level) -> - (not - (Sc_rollup.Game.game_state_equal - game.Sc_rollup.Game.game_state - last_move_game_state)) - || Int32.( - sub level last_move_level - > of_int Configuration.refutation_player_buffer_levels) - -let play w game ~(level : int32) = - let open Lwt_syntax in - let state = Worker.state w in - if should_move ~level game state.last_move_cache then ( - let* pushed = Worker.Queue.push_request w (Request.Play game) in - if pushed then - state.last_move_cache <- Some (game.Sc_rollup.Game.game_state, level) ; - return_unit) - else return_unit - -let play_opening w conflict = - let open Lwt_syntax in - let* (_pushed : bool) = - Worker.Queue.push_request w (Request.Play_opening conflict) - in - return_unit - -let init_and_play node_ctxt ~self ~conflict ~game ~level = - let open Lwt_result_syntax in - let* worker = init node_ctxt ~self ~conflict in - let*! () = - match game with - | None -> play_opening worker conflict - | Some game -> play worker game ~level - in - return_unit - -let current_games () = - List.map - (fun (_name, worker) -> ((Worker.state worker).opponent, worker)) - (Worker.list table) - -let shutdown = Worker.shutdown diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player.mli b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player.mli deleted file mode 100644 index 92592e7c7cc5f17f7aa70b9be69eb6319bd31c1b..0000000000000000000000000000000000000000 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player.mli +++ /dev/null @@ -1,59 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -(** Worker module for a single refutation game player. The node's refutation - coordinator will spawn a new refutation player for each refutation game. -*) -module Worker : Worker.T - -(** Type for a refutation game player. *) -type worker = Worker.infinite Worker.queue Worker.t - -(** [init_and_play node_ctxt ~self ~conflict ~game ~level] initializes a new - refutation game player for signer [self]. After initizialization, the - worker will play the next move depending on the [game] state. If no [game] - is passed, the worker will play the opening move for [conflict]. *) -val init_and_play : - Node_context.rw -> - self:public_key_hash -> - conflict:Sc_rollup.Refutation_storage.conflict -> - game:Sc_rollup.Game.t option -> - level:int32 -> - unit tzresult Lwt.t - -(** [play worker game ~level] makes the [worker] play the next move depending - on the [game] state for their conflict. - *) -val play : worker -> Sc_rollup.Game.t -> level:int32 -> unit Lwt.t - -(** Shutdown a refutaiton game player. *) -val shutdown : worker -> unit Lwt.t - -(** [current_games ()] lists the opponents' this node is playing refutation - games against, alongside the worker that takes care of each game. *) -val current_games : unit -> (public_key_hash * worker) list diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player_types.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player_types.ml deleted file mode 100644 index 5cb43af305096ca46dc4584d791b021229c4d0d2..0000000000000000000000000000000000000000 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player_types.ml +++ /dev/null @@ -1,73 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -module Request = struct - type ('a, 'b) t = - | Play : Sc_rollup.Game.t -> (unit, error trace) t - | Play_opening : - Sc_rollup.Refutation_storage.conflict - -> (unit, error trace) t - - type view = View : _ t -> view - - let view req = View req - - let encoding = - let open Data_encoding in - union - [ - case - (Tag 0) - ~title:"Play" - (obj2 - (req "request" (constant "play")) - (req "game" Sc_rollup.Game.encoding)) - (function View (Play g) -> Some ((), g) | _ -> None) - (fun ((), g) -> View (Play g)); - case - (Tag 1) - ~title:"Play opening" - (obj2 - (req "request" (constant "play_opening")) - (req "conflict" Sc_rollup.Refutation_storage.conflict_encoding)) - (function View (Play_opening c) -> Some ((), c) | _ -> None) - (fun ((), c) -> View (Play_opening c)); - ] - - let pp ppf (View r) = - match r with - | Play game -> Format.fprintf ppf "Playing game %a" Sc_rollup.Game.pp game - | Play_opening conflict -> - Format.fprintf - ppf - "Playing opening move for conflict against staker %a at our \ - commitment %a" - Sc_rollup.Staker.pp - conflict.other - Sc_rollup.Commitment.pp - conflict.our_commitment -end diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player_types.mli b/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player_types.mli deleted file mode 100644 index d29fd8289f450cde25d7a3e5b4fa6bc7ca278e8b..0000000000000000000000000000000000000000 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/refutation_player_types.mli +++ /dev/null @@ -1,45 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -module Request : sig - (** Type of requests accepted by the refutation player. *) - type ('a, 'b) t = - | Play : Sc_rollup.Game.t -> (unit, error trace) t - (** Play a step of an ongoing refutation game. *) - | Play_opening : - Sc_rollup.Refutation_storage.conflict - -> (unit, error trace) t - (** Play the opening move of a refutation game. *) - - type view = View : _ t -> view - - include - Worker_intf.REQUEST - with type ('a, 'request_error) t := ('a, 'request_error) t - and type view := view -end diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/rollup_node_plugin.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/rollup_node_plugin.ml index d54d5b6674235872968376834fd8ab660cf6fbbf..4c5dd5e5cfe44af177cd455e62b8dd74819996ad 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/rollup_node_plugin.ml +++ b/src/proto_017_PtNairob/lib_sc_rollup_node/rollup_node_plugin.ml @@ -30,7 +30,7 @@ module Plugin : Protocol_plugin_sig.S = struct module Dal_slots_tracker = Dal_slots_tracker module Inbox = Inbox module Interpreter = Interpreter - module Refutation_coordinator = Refutation_coordinator + module Refutation_game_helpers = Refutation_game_helpers module Batcher_constants = Batcher_constants module Layer1_helpers = Layer1_helpers module L1_processing = Daemon_helpers diff --git a/src/proto_018_Proxford/lib_sc_rollup_layer2/sc_rollup_proto_types.ml b/src/proto_018_Proxford/lib_sc_rollup_layer2/sc_rollup_proto_types.ml index b85e403c010d93097efde9b1ca0b5b6e28161177..4b70ebeefd2474dedad4684f6d9199d3afbf179e 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_layer2/sc_rollup_proto_types.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_layer2/sc_rollup_proto_types.ml @@ -110,6 +110,8 @@ end module Inbox = struct type t = Sc_rollup.Inbox.t + type history_proof = Sc_rollup.Inbox.history_proof + let to_repr inbox = inbox |> Data_encoding.Binary.to_string_exn Sc_rollup.Inbox.encoding @@ -135,6 +137,122 @@ module Inbox = struct |> Data_encoding.Binary.of_string_exn Octez_smart_rollup.Inbox.versioned_encoding |> Octez_smart_rollup.Inbox.of_versioned + + (* Workaround because history_proof encoding not in Alpha_context *) + let proto_history_proof_encoding : + Sc_rollup.Inbox.history_proof Data_encoding.t = + let level_proof_encoding = + let open Data_encoding in + conv + (fun {Sc_rollup.Inbox.hash; level} -> (hash, level)) + (fun (hash, level) -> {hash; level}) + (obj2 + (req "hash" Sc_rollup.Inbox_merkelized_payload_hashes.Hash.encoding) + (req "level" Raw_level.encoding)) + in + Sc_rollup.Inbox.Skip_list.encoding + Sc_rollup.Inbox.Hash.encoding + level_proof_encoding + + let history_proof_of_octez (hist : Octez_smart_rollup.Inbox.history_proof) : + history_proof = + hist + |> Data_encoding.Binary.to_string_exn + Octez_smart_rollup.Inbox.history_proof_encoding + |> Data_encoding.Binary.of_string_exn proto_history_proof_encoding + + let history_proof_to_octez (hist : history_proof) : + Octez_smart_rollup.Inbox.history_proof = + hist + |> Data_encoding.Binary.to_string_exn proto_history_proof_encoding + |> Data_encoding.Binary.of_string_exn + Octez_smart_rollup.Inbox.history_proof_encoding +end + +module Dal = struct + module Slot_index = struct + type t = Dal.Slot_index.t + + let of_octez ~number_of_slots (i : Octez_smart_rollup.Dal.Slot_index.t) : t + = + match Dal.Slot_index.of_int_opt ~number_of_slots i with + | None -> Format.ksprintf invalid_arg "Dal.Slot_index.of_octez: %d" i + | Some i -> i + + let to_octez : t -> Octez_smart_rollup.Dal.Slot_index.t = + Dal.Slot_index.to_int + end + + module Page_index = struct + type t = Dal.Page.Index.t + + let of_octez : Octez_smart_rollup.Dal.Page_index.t -> t = Fun.id + + let to_octez : t -> Octez_smart_rollup.Dal.Page_index.t = Fun.id + end + + module Slot_header = struct + type t = Dal.Slot.Header.t + + let of_octez ~number_of_slots + Octez_smart_rollup.Dal.Slot_header. + {id = {published_level; index}; commitment} : t = + Dal.Slot.Header. + { + id = + { + published_level = Raw_level.of_int32_exn published_level; + index = Slot_index.of_octez ~number_of_slots index; + }; + commitment; + } + + let to_octez Dal.Slot.Header.{id = {published_level; index}; commitment} : + Octez_smart_rollup.Dal.Slot_header.t = + Octez_smart_rollup.Dal.Slot_header. + { + id = + { + published_level = Raw_level.to_int32 published_level; + index = Slot_index.to_octez index; + }; + commitment; + } + end + + module Slot_history = struct + type t = Dal.Slots_history.t + + let of_octez (h : Octez_smart_rollup.Dal.Slot_history.t) : t = + h + |> Data_encoding.Binary.to_bytes_exn + Octez_smart_rollup.Dal.Slot_history.encoding + |> Data_encoding.Binary.of_bytes_exn Dal.Slots_history.encoding + + let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history.t = + h + |> Data_encoding.Binary.to_bytes_exn Dal.Slots_history.encoding + |> Data_encoding.Binary.of_bytes_exn + Octez_smart_rollup.Dal.Slot_history.encoding + end + + module Slot_history_cache = struct + type t = Dal.Slots_history.History_cache.t + + let of_octez (h : Octez_smart_rollup.Dal.Slot_history_cache.t) : t = + h + |> Data_encoding.Binary.to_bytes_exn + Octez_smart_rollup.Dal.Slot_history_cache.encoding + |> Data_encoding.Binary.of_bytes_exn + Dal.Slots_history.History_cache.encoding + + let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history_cache.t = + h + |> Data_encoding.Binary.to_bytes_exn + Dal.Slots_history.History_cache.encoding + |> Data_encoding.Binary.of_bytes_exn + Octez_smart_rollup.Dal.Slot_history_cache.encoding + end end module Game = struct @@ -146,6 +264,14 @@ module Game = struct type index = Sc_rollup.Game.Index.t + type player = Sc_rollup.Game.player + + type game_state = Sc_rollup.Game.game_state + + type t = Sc_rollup.Game.t + + type conflict = Sc_rollup.Refutation_storage.conflict + let dissection_chunk_of_octez Octez_smart_rollup.Game.{state_hash; tick} : dissection_chunk = { @@ -223,104 +349,116 @@ module Game = struct let index_to_octez Sc_rollup.Game.Index.{alice; bob} = Octez_smart_rollup.Game.make_index alice bob -end - -module Kind = struct - type t = Sc_rollup.Kind.t - - let of_octez : Octez_smart_rollup.Kind.t -> t = function - | Example_arith -> Example_arith - | Wasm_2_0_0 -> Wasm_2_0_0 - - let to_octez : t -> Octez_smart_rollup.Kind.t = function - | Example_arith -> Example_arith - | Wasm_2_0_0 -> Wasm_2_0_0 -end - -module Dal = struct - module Slot_index = struct - type t = Dal.Slot_index.t - - let of_octez ~number_of_slots (i : Octez_smart_rollup.Dal.Slot_index.t) : t - = - match Dal.Slot_index.of_int_opt ~number_of_slots i with - | None -> Format.ksprintf invalid_arg "Dal.Slot_index.of_octez: %d" i - | Some i -> i - let to_octez : t -> Octez_smart_rollup.Dal.Slot_index.t = - Dal.Slot_index.to_int - end + let player_of_octez : Octez_smart_rollup.Game.player -> player = function + | Alice -> Alice + | Bob -> Bob - module Page_index = struct - type t = Dal.Page.Index.t + let player_to_octez : player -> Octez_smart_rollup.Game.player = function + | Alice -> Alice + | Bob -> Bob - let of_octez : Octez_smart_rollup.Dal.Page_index.t -> t = Fun.id - - let to_octez : t -> Octez_smart_rollup.Dal.Page_index.t = Fun.id - end + let game_state_of_octez : Octez_smart_rollup.Game.game_state -> game_state = + function + | Dissecting {dissection; default_number_of_sections} -> + Dissecting + { + dissection = List.map dissection_chunk_of_octez dissection; + default_number_of_sections; + } + | Final_move {agreed_start_chunk; refuted_stop_chunk} -> + Final_move + { + agreed_start_chunk = dissection_chunk_of_octez agreed_start_chunk; + refuted_stop_chunk = dissection_chunk_of_octez refuted_stop_chunk; + } - module Slot_header = struct - type t = Dal.Slot.Header.t + let game_state_to_octez : game_state -> Octez_smart_rollup.Game.game_state = + function + | Dissecting {dissection; default_number_of_sections} -> + Dissecting + { + dissection = List.map dissection_chunk_to_octez dissection; + default_number_of_sections; + } + | Final_move {agreed_start_chunk; refuted_stop_chunk} -> + Final_move + { + agreed_start_chunk = dissection_chunk_to_octez agreed_start_chunk; + refuted_stop_chunk = dissection_chunk_to_octez refuted_stop_chunk; + } - let of_octez ~number_of_slots - Octez_smart_rollup.Dal.Slot_header. - {id = {published_level; index}; commitment} : t = - Dal.Slot.Header. + let of_octez + Octez_smart_rollup.Game. { - id = - { - published_level = Raw_level.of_int32_exn published_level; - index = Slot_index.of_octez ~number_of_slots index; - }; - commitment; - } + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + } : t = + { + turn = player_of_octez turn; + inbox_snapshot = Inbox.history_proof_of_octez inbox_snapshot; + dal_snapshot = Dal.Slot_history.of_octez dal_snapshot; + start_level = Raw_level.of_int32_exn start_level; + inbox_level = Raw_level.of_int32_exn inbox_level; + game_state = game_state_of_octez game_state; + } - let to_octez Dal.Slot.Header.{id = {published_level; index}; commitment} : - Octez_smart_rollup.Dal.Slot_header.t = - Octez_smart_rollup.Dal.Slot_header. + let to_octez + Sc_rollup.Game. { - id = - { - published_level = Raw_level.to_int32 published_level; - index = Slot_index.to_octez index; - }; - commitment; - } - end - - module Slot_history = struct - type t = Dal.Slots_history.t + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + } : Octez_smart_rollup.Game.t = + { + turn = player_to_octez turn; + inbox_snapshot = Inbox.history_proof_to_octez inbox_snapshot; + dal_snapshot = Dal.Slot_history.to_octez dal_snapshot; + start_level = Raw_level.to_int32 start_level; + inbox_level = Raw_level.to_int32 inbox_level; + game_state = game_state_to_octez game_state; + } - let of_octez (h : Octez_smart_rollup.Dal.Slot_history.t) : t = - h - |> Data_encoding.Binary.to_bytes_exn - Octez_smart_rollup.Dal.Slot_history.encoding - |> Data_encoding.Binary.of_bytes_exn Dal.Slots_history.encoding + let conflict_of_octez + Octez_smart_rollup.Game. + {other; their_commitment; our_commitment; parent_commitment} : conflict + = + { + other; + their_commitment = Commitment.of_octez their_commitment; + our_commitment = Commitment.of_octez our_commitment; + parent_commitment; + } - let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history.t = - h - |> Data_encoding.Binary.to_bytes_exn Dal.Slots_history.encoding - |> Data_encoding.Binary.of_bytes_exn - Octez_smart_rollup.Dal.Slot_history.encoding - end + let conflict_to_octez + Sc_rollup.Refutation_storage. + {other; their_commitment; our_commitment; parent_commitment} : + Octez_smart_rollup.Game.conflict = + { + other; + their_commitment = Commitment.to_octez their_commitment; + our_commitment = Commitment.to_octez our_commitment; + parent_commitment; + } +end - module Slot_history_cache = struct - type t = Dal.Slots_history.History_cache.t +module Kind = struct + type t = Sc_rollup.Kind.t - let of_octez (h : Octez_smart_rollup.Dal.Slot_history_cache.t) : t = - h - |> Data_encoding.Binary.to_bytes_exn - Octez_smart_rollup.Dal.Slot_history_cache.encoding - |> Data_encoding.Binary.of_bytes_exn - Dal.Slots_history.History_cache.encoding + let of_octez : Octez_smart_rollup.Kind.t -> t = function + | Example_arith -> Example_arith + | Wasm_2_0_0 -> Wasm_2_0_0 - let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history_cache.t = - h - |> Data_encoding.Binary.to_bytes_exn - Dal.Slots_history.History_cache.encoding - |> Data_encoding.Binary.of_bytes_exn - Octez_smart_rollup.Dal.Slot_history_cache.encoding - end + let to_octez : t -> Octez_smart_rollup.Kind.t = function + | Example_arith -> Example_arith + | Wasm_2_0_0 -> Wasm_2_0_0 end module Constants = struct diff --git a/src/proto_018_Proxford/lib_sc_rollup_layer2/sc_rollup_proto_types.mli b/src/proto_018_Proxford/lib_sc_rollup_layer2/sc_rollup_proto_types.mli index e1426d860a988de2c9006e7f0604c107560be539..b00d3991fe0dce4ddc1f817537092d75e1ae30d9 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_layer2/sc_rollup_proto_types.mli +++ b/src/proto_018_Proxford/lib_sc_rollup_layer2/sc_rollup_proto_types.mli @@ -76,9 +76,17 @@ end module Inbox : sig type t = Sc_rollup.Inbox.t + type history_proof = Sc_rollup.Inbox.history_proof + val of_octez : Octez_smart_rollup.Inbox.t -> t val to_octez : t -> Octez_smart_rollup.Inbox.t + + val history_proof_of_octez : + Octez_smart_rollup.Inbox.history_proof -> history_proof + + val history_proof_to_octez : + history_proof -> Octez_smart_rollup.Inbox.history_proof end module Game : sig @@ -107,6 +115,30 @@ module Game : sig val index_of_octez : Octez_smart_rollup.Game.index -> index val index_to_octez : index -> Octez_smart_rollup.Game.index + + type player = Sc_rollup.Game.player + + val player_of_octez : Octez_smart_rollup.Game.player -> player + + val player_to_octez : player -> Octez_smart_rollup.Game.player + + type game_state = Sc_rollup.Game.game_state + + val game_state_of_octez : Octez_smart_rollup.Game.game_state -> game_state + + val game_state_to_octez : game_state -> Octez_smart_rollup.Game.game_state + + type t = Sc_rollup.Game.t + + val of_octez : Octez_smart_rollup.Game.t -> t + + val to_octez : t -> Octez_smart_rollup.Game.t + + type conflict = Sc_rollup.Refutation_storage.conflict + + val conflict_of_octez : Octez_smart_rollup.Game.conflict -> conflict + + val conflict_to_octez : conflict -> Octez_smart_rollup.Game.conflict end module Kind : sig diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/daemon_helpers.ml b/src/proto_018_Proxford/lib_sc_rollup_node/daemon_helpers.ml index 57315ced452c02e0f548959d783bc549d5c003a2..5e4a5a9851028233e7eeb89b2b5dee0d773a9741 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/daemon_helpers.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_node/daemon_helpers.ml @@ -99,7 +99,7 @@ let accuser_publish_commitment_when_refutable node_ctxt ~other rollup Refutation_game_event.potential_conflict_detected ~our_commitment_hash ~their_commitment_hash - ~level:their_commitment.inbox_level + ~level:(Raw_level.to_int32 their_commitment.inbox_level) ~other in assert (Sc_rollup.Address.(node_ctxt.rollup_address = rollup)) ; diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator.mli b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator.mli deleted file mode 100644 index 12a35582b9b294687783aa6964b0290f6d3d35ea..0000000000000000000000000000000000000000 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator.mli +++ /dev/null @@ -1,47 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -(** Component for managing refutation games. - This module is implemented as a single worker in the rollup node, - which takes care of processing new L1 heads, and coordinating - the refutation game players. (See {!Refutation_player}). -*) - -(** Initiatilize the refuation coordinator. *) -val init : Node_context.rw -> unit tzresult Lwt.t - -(** Process a new l1 head. This means that the coordinator will: - {ol - {li Gather all existing conflicts} - {li Launch new refutation players for each conflict that doesn't - have a player in this node} - {li Kill all players whose conflict has disappeared from L1} - {li Make all players play a step in the refutation} - } - *) -val process : Layer1.head -> unit tzresult Lwt.t - -(** Shutdown the refutation coordinator. *) -val shutdown : unit -> unit Lwt.t diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator_types.ml b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator_types.ml deleted file mode 100644 index 314698ed82ff7cce4951b0d7eadebaf9bf3b7247..0000000000000000000000000000000000000000 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator_types.ml +++ /dev/null @@ -1,56 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -module Request = struct - type ('a, 'b) t = Process : Layer1.head -> (unit, error trace) t - - type view = View : _ t -> view - - let view req = View req - - let encoding = - let open Data_encoding in - union - [ - case - (Tag 0) - ~title:"Process" - (obj2 - (req "request" (constant "process")) - (req "block" Layer1.head_encoding)) - (function View (Process b) -> Some ((), b)) - (fun ((), b) -> View (Process b)); - ] - - let pp ppf (View r) = - match r with - | Process {Layer1.hash; level} -> - Format.fprintf - ppf - "Processing new L1 head %a at level %ld" - Block_hash.pp - hash - level -end diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator_types.mli b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator_types.mli deleted file mode 100644 index f26d46885c774a05b48c75bcee47dd40a099fd64..0000000000000000000000000000000000000000 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_coordinator_types.mli +++ /dev/null @@ -1,38 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -module Request : sig - (** Type of requests accepted by the refutation coordinator. *) - type ('a, 'b) t = - | Process : Layer1.head -> (unit, error trace) t - (** Request to process new refutation games. *) - - type view = View : _ t -> view - - include - Worker_intf.REQUEST - with type ('a, 'request_error) t := ('a, 'request_error) t - and type view := view -end diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game.mli b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game.mli deleted file mode 100644 index 3229857d1aa7ad1cb2778b885650aff71cac5ff7..0000000000000000000000000000000000000000 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game.mli +++ /dev/null @@ -1,46 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -(** This module implements the refutation game logic of the rollup node. *) - -(** [play_opening_move node_ctxt self conflict] injects the opening refutation - game move for [conflict]. *) -val play_opening_move : - [< `Read | `Write > `Read] Node_context.t -> - public_key_hash -> - Sc_rollup.Refutation_storage.conflict -> - (unit, tztrace) result Lwt.t - -(** [play head_block node_ctxt ~self game opponent] injects the next move in the - refutation [game] played by [self] and [opponent]. *) -val play : - Node_context.rw -> - self:public_key_hash -> - Sc_rollup.Game.t -> - public_key_hash -> - (unit, tztrace) result Lwt.t diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game_event.ml b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game_event.ml deleted file mode 100644 index ceb5ef25e148d96bfcfd688c0ea316a95452ab5a..0000000000000000000000000000000000000000 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game_event.ml +++ /dev/null @@ -1,260 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) -(* *) -(* 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 Protocol.Alpha_context - -(* TODO: https://gitlab.com/tezos/tezos/-/issues/2880 - Add corresponding .mli file. *) - -let section = [Protocol.name; "sc_rollup_node"; "refutation_game"] - -module Simple = struct - include Internal_event.Simple - - let timeout = - declare_1 - ~section - ~name:"sc_rollup_node_timeout" - ~msg: - "The rollup node has been slashed because of a timeout issued by \ - {address}" - ~level:Notice - ("address", Signature.Public_key_hash.encoding) - - let invalid_move = - declare_0 - ~section - ~name:"sc_rollup_node_invalid_move" - ~msg: - "The rollup node is about to make an invalid move in the refutation \ - game! It is stopped to avoid being slashed. The problem should be \ - reported immediately or the rollup node should be upgraded to have a \ - chance to be back before the timeout is reached." - ~level:Notice - () - - let conflict_detected = - declare_5 - ~section - ~name:"sc_rollup_node_conflict_detected" - ~msg: - "A conflict has been found with our commitment {our_commitment_hash} \ - at level {level} with staker {other} that hash issued commitment \ - {their_commitment_hash} both based on {parent_commitment_hash}." - ~level:Notice - ("our_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("level", Raw_level.encoding) - ("other", Sc_rollup.Staker.encoding) - ("their_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("parent_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - - let potential_conflict_detected = - declare_4 - ~section - ~name:"sc_rollup_node_potential_conflict_detected" - ~msg: - "A potential conflict has been found with our commitment \ - {our_commitment_hash} at level {level} with staker {other} that hash \ - issued commitment {their_commitment_hash}." - ~level:Notice - ("our_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("level", Raw_level.encoding) - ("other", Sc_rollup.Staker.encoding) - ("their_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - - let timeout_detected = - declare_1 - ~section - ~name:"sc_rollup_node_timeout_detected" - ~msg: - "The rollup node has detected that opponent {other} can be timed out." - ~level:Notice - ("other", Sc_rollup.Staker.encoding) - - let dissection_chunk_encoding = - let open Data_encoding in - let open Sc_rollup.Dissection_chunk in - conv - (fun {state_hash; tick} -> (state_hash, tick)) - (fun (state_hash, tick) -> {state_hash; tick}) - (obj2 - (opt "state" Sc_rollup.State_hash.encoding) - (req "tick" Sc_rollup.Tick.encoding)) - - let computed_dissection = - declare_4 - ~section - ~name:"sc_rollup_node_computed_dissection" - ~msg: - "Computed dissection against {opponent} between ticks {start_tick} and \ - {end_tick}: {dissection}." - ~level:Debug - ("opponent", Signature.Public_key_hash.encoding) - ("start_tick", Sc_rollup.Tick.encoding) - ("end_tick", Sc_rollup.Tick.encoding) - ("dissection", Data_encoding.list dissection_chunk_encoding) - - module Worker (ARG : sig - val section : string list - end) - (Request : Worker_intf.REQUEST) = - struct - include ARG - - let request_failed = - declare_3 - ~section - ~name:"request_failed" - ~msg:"request {view} failed ({worker_status}): {errors}" - ~level:Notice - ("view", Request.encoding) - ~pp1:Request.pp - ("worker_status", Worker_types.request_status_encoding) - ~pp2:Worker_types.pp_status - ("errors", Error_monad.trace_encoding) - ~pp3:Error_monad.pp_print_trace - - let request_completed = - declare_2 - ~section - ~name:"request_completed" - ~msg:"{view} {worker_status}" - ~level:Debug - ("view", Request.encoding) - ("worker_status", Worker_types.request_status_encoding) - ~pp1:Request.pp - ~pp2:Worker_types.pp_status - end - - module Player = struct - include - Worker - (struct - let section = section @ ["player"] - end) - (Refutation_player_types.Request) - - let started = - declare_2 - ~section - ~name:"player_started" - ~msg: - "refutation player started to play against {opponent}, defenfing \ - commitment {commitment}" - ~level:Notice - ("opponent", Signature.Public_key_hash.encoding) - ~pp1:Signature.Public_key_hash.pp - ("commitment", Sc_rollup.Commitment.encoding) - ~pp2:Sc_rollup.Commitment.pp - - let stopped = - declare_1 - ~section - ~name:"player_stopped" - ~msg:"refutation player for opponent {opponent} has been stopped" - ~level:Notice - ("opponent", Signature.Public_key_hash.encoding) - ~pp1:Signature.Public_key_hash.pp - end - - module Coordinator = struct - include - Worker - (struct - let section = section @ ["coordinator"] - end) - (Refutation_coordinator_types.Request) - - let starting = - declare_0 - ~section - ~name:"coordinator_starting" - ~msg:"Starting refutation coordinator for the smart rollup node" - ~level:Notice - () - end -end - -let timeout address = Simple.(emit timeout address) - -let invalid_move () = Simple.(emit invalid_move ()) - -let conflict_detected (conflict : Sc_rollup.Refutation_storage.conflict) = - let our_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.our_commitment - in - let their_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.their_commitment - in - let parent_commitment_hash = conflict.parent_commitment in - let other = conflict.other in - let level = conflict.our_commitment.inbox_level in - Simple.( - emit - conflict_detected - ( our_commitment_hash, - level, - other, - their_commitment_hash, - parent_commitment_hash )) - -let potential_conflict_detected ~our_commitment_hash ~their_commitment_hash - ~other ~level = - Simple.( - emit - potential_conflict_detected - (our_commitment_hash, level, other, their_commitment_hash)) - -let timeout_detected other = Simple.(emit timeout_detected other) - -let computed_dissection ~opponent ~start_tick ~end_tick dissection = - Simple.(emit computed_dissection (opponent, start_tick, end_tick, dissection)) - -module Player = struct - let section = Simple.Player.section - - let request_failed view worker_status errors = - Simple.(emit Player.request_failed (view, worker_status, errors)) - - let request_completed view worker_status = - Simple.(emit Player.request_completed (view, worker_status)) - - let started opponent commitment = - Simple.(emit Player.started (opponent, commitment)) - - let stopped opponent = Simple.(emit Player.stopped opponent) -end - -module Coordinator = struct - let section = Simple.Coordinator.section - - let request_failed view worker_status errors = - Simple.(emit Coordinator.request_failed (view, worker_status, errors)) - - let request_completed view worker_status = - Simple.(emit Coordinator.request_completed (view, worker_status)) - - let starting = Simple.(emit Coordinator.starting) -end diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game.ml b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game_helpers.ml similarity index 55% rename from src/proto_018_Proxford/lib_sc_rollup_node/refutation_game.ml rename to src/proto_018_Proxford/lib_sc_rollup_node/refutation_game_helpers.ml index afabcca77936d54bb0b48f2f31a0b16397bbffad..850e54227fb888d5885e99ede49b502304295902 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game_helpers.ml @@ -1,7 +1,9 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) +(* Copyright (c) 2023 Functori, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -23,61 +25,8 @@ (* *) (*****************************************************************************) -(** This module implements the refutation game logic of the rollup - node. - - When a new L1 block arises, the rollup node asks the L1 node for - the current game it is part of, if any. - - If a game is running and it is the rollup operator turn, the rollup - node injects the next move of the winning strategy. - - If a game is running and it is not the rollup operator turn, the - rollup node asks the L1 node whether the timeout is reached to play - the timeout argument if possible. - - Otherwise, if no game is running, the rollup node asks the L1 node - whether there is a conflict with one of its disputable commitments. If - there is such a conflict with a commitment C', then the rollup node - starts a game to refute C' by starting a game with one of its staker. - -*) open Protocol - open Alpha_context -open Sc_rollup.Game - -let node_role ~self Sc_rollup.Game.Index.{alice; bob} = - if Sc_rollup.Staker.equal alice self then Alice - else if Sc_rollup.Staker.equal bob self then Bob - else (* By validity of [ongoing_game] RPC. *) - assert false - -type role = Our_turn of {opponent : public_key_hash} | Their_turn - -let turn ~self game players = - let Sc_rollup.Game.Index.{alice; bob} = players in - match (node_role ~self players, game.turn) with - | Alice, Alice -> Our_turn {opponent = bob} - | Bob, Bob -> Our_turn {opponent = alice} - | Alice, Bob -> Their_turn - | Bob, Alice -> Their_turn - -(** [inject_next_move node_ctxt source ~refutation ~opponent ~commitment - ~opponent_commitment] submits an L1 operation (signed by [source]) to - issue the next move in the refutation game. *) -let inject_next_move node_ctxt source ~refutation ~opponent = - let open Lwt_result_syntax in - let refute_operation = - L1_operation.Refute - { - rollup = node_ctxt.Node_context.rollup_address; - refutation = Sc_rollup_proto_types.Game.refutation_to_octez refutation; - opponent; - } - in - let* _hash = Injector.add_pending_operation ~source refute_operation in - return_unit (** This function computes the inclusion/membership proof of the page identified by [page_id] in the slot whose data are provided in @@ -161,29 +110,28 @@ let page_info_from_pvm_state (node_ctxt : _ Node_context.t) ~dal_attestation_lag | _ -> return_none let metadata (node_ctxt : _ Node_context.t) = - let address = - Sc_rollup_proto_types.Address.of_octez node_ctxt.rollup_address - in + let address = node_ctxt.rollup_address in let origination_level = Raw_level.of_int32_exn node_ctxt.genesis_info.level in Sc_rollup.Metadata.{address; origination_level} -let generate_proof (node_ctxt : _ Node_context.t) game start_state = +let generate_proof (node_ctxt : _ Node_context.t) + (game : Octez_smart_rollup.Game.t) start_state = let open Lwt_result_syntax in let module PVM = (val Pvm.of_kind node_ctxt.kind) in - let snapshot = game.inbox_snapshot in + let snapshot = + Sc_rollup_proto_types.Inbox.history_proof_of_octez game.inbox_snapshot + in (* NOTE: [snapshot_level_int32] below refers to the level of the snapshotted inbox (from the skip list) which also matches [game.start_level - 1]. *) let snapshot_level_int32 = - Raw_level.to_int32 (Sc_rollup.Inbox.Skip_list.content snapshot).level + (Octez_smart_rollup.Inbox.Skip_list.content game.inbox_snapshot).level in let get_snapshot_head () = let+ hash = Node_context.hash_of_level node_ctxt snapshot_level_int32 in Layer1.{hash; level = snapshot_level_int32} in let* context = - let* start_hash = - Node_context.hash_of_level node_ctxt (Raw_level.to_int32 game.inbox_level) - in + let* start_hash = Node_context.hash_of_level node_ctxt game.inbox_level in let+ context = Node_context.checkout_context node_ctxt start_hash in Context.index context in @@ -301,13 +249,13 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = trace (Sc_rollup_node_errors.Cannot_produce_proof { - inbox_level = Raw_level.to_int32 game.inbox_level; + inbox_level = game.inbox_level; start_tick = Sc_rollup.Tick.to_z start_tick; }) @@ (Sc_rollup.Proof.produce ~metadata (module P) - game.inbox_level + (Raw_level.of_int32_exn game.inbox_level) ~is_reveal_enabled >|= Environment.wrap_tzresult) in @@ -320,7 +268,7 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = Sc_rollup.Proof.valid ~metadata snapshot - game.inbox_level + (Raw_level.of_int32_exn game.inbox_level) dal_slots_history dal_parameters ~dal_attestation_lag @@ -329,41 +277,38 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = ~is_reveal_enabled >|= Environment.wrap_tzresult in - if Result.is_ok res then return proof else assert false + assert (Result.is_ok res) ; + let proof = + Data_encoding.Binary.to_string_exn Sc_rollup.Proof.encoding proof + in + return proof -type pvm_intermediate_state = - | Hash of Sc_rollup.State_hash.t - | Evaluated of Fuel.Accounted.t Pvm_plugin_sig.eval_state +let state_of_tick node_ctxt ?start_state ~tick level = + Interpreter.state_of_tick + node_ctxt + ?start_state + ~tick + (Raw_level.of_int32_exn level) -let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok - our_view = +let make_dissection (node_ctxt : _ Node_context.t) ~start_state ~start_chunk + ~our_stop_chunk ~default_number_of_sections ~last_level = let open Lwt_result_syntax in + let module PVM = (val Pvm.of_kind node_ctxt.kind) in let state_of_tick ?start_state tick = - Interpreter.state_of_tick + state_of_tick node_ctxt ?start_state ~tick:(Sc_rollup.Tick.to_z tick) last_level in let state_hash_of_eval_state Pvm_plugin_sig.{state_hash; _} = state_hash in - let start_hash, start_tick, start_state = - match ok with - | Hash hash, tick -> (hash, tick, None) - | Evaluated ({state_hash; _} as state), tick -> - (state_hash, tick, Some state) - in let start_chunk = - Sc_rollup.Dissection_chunk.{state_hash = Some start_hash; tick = start_tick} - in - let our_state, our_tick = our_view in - let our_state_hash = - Option.map (fun Pvm_plugin_sig.{state_hash; _} -> state_hash) our_state + Sc_rollup_proto_types.Game.dissection_chunk_of_octez start_chunk in let our_stop_chunk = - Sc_rollup.Dissection_chunk.{state_hash = our_state_hash; tick = our_tick} + Sc_rollup_proto_types.Game.dissection_chunk_of_octez our_stop_chunk in - let module PVM = (val Pvm.of_kind node_ctxt.kind) in - let* dissection = + let+ dissection = Game_helpers.make_dissection ~state_of_tick ~state_hash_of_eval_state @@ -375,181 +320,45 @@ let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok ~our_stop_chunk ~default_number_of_sections in - let*! () = - Refutation_game_event.computed_dissection - ~opponent - ~start_tick - ~end_tick:our_tick - dissection - in - return dissection + List.map Sc_rollup_proto_types.Game.dissection_chunk_to_octez dissection -(** [generate_from_dissection ~default_number_of_sections node_ctxt game - dissection] traverses the current [dissection] and returns a move which - performs a new dissection of the execution trace or provides a refutation - proof to serve as the next move of the [game]. *) -let generate_next_dissection ~default_number_of_sections node_ctxt ~opponent - game dissection = - let open Lwt_result_syntax in - let rec traverse ok = function - | [] -> - (* The game invariant states that the dissection from the - opponent must contain a tick we disagree with. If the - retrieved game does not respect this, we cannot trust the - Tezos node we are connected to and prefer to stop here. *) - tzfail - Sc_rollup_node_errors - .Unreliable_tezos_node_returning_inconsistent_game - | Sc_rollup.Dissection_chunk.{state_hash = their_hash; tick} :: dissection - -> ( - let start_state = - match ok with - | Hash _, _ -> None - | Evaluated ok_state, _ -> Some ok_state - in - let* our = - Interpreter.state_of_tick - node_ctxt - ?start_state - ~tick:(Sc_rollup.Tick.to_z tick) - game.inbox_level - in - match (their_hash, our) with - | None, None -> - (* This case is absurd since: [None] can only occur at the - end and the two players disagree about the end. *) - assert false - | Some _, None | None, Some _ -> return (ok, (our, tick)) - | Some their_hash, Some ({state_hash = our_hash; _} as our_state) -> - if Sc_rollup.State_hash.equal our_hash their_hash then - traverse (Evaluated our_state, tick) dissection - else return (ok, (our, tick))) - in - match dissection with - | Sc_rollup.Dissection_chunk.{state_hash = Some hash; tick} :: dissection -> - let* ok, ko = traverse (Hash hash, tick) dissection in - let* dissection = - new_dissection - ~opponent - ~default_number_of_sections - node_ctxt - game.inbox_level - ok - ko - in - let _, choice = ok in - let _, ko_tick = ko in - let chosen_section_len = Sc_rollup.Tick.distance ko_tick choice in - return (choice, chosen_section_len, dissection) - | [] | {state_hash = None; _} :: _ -> - (* - By wellformedness of dissection. - A dissection always starts with a tick of the form [(Some hash, tick)]. - A dissection always contains strictly more than one element. - *) - tzfail - Sc_rollup_node_errors.Unreliable_tezos_node_returning_inconsistent_game - -let next_move node_ctxt ~opponent game = - let open Lwt_result_syntax in - let final_move start_tick = - let* start_state = - Interpreter.state_of_tick - node_ctxt - ~tick:(Sc_rollup.Tick.to_z start_tick) - game.inbox_level - in - match start_state with - | None -> - tzfail - Sc_rollup_node_errors - .Unreliable_tezos_node_returning_inconsistent_game - | Some {state = start_state; _} -> - let* proof = generate_proof node_ctxt game start_state in - let choice = start_tick in - return (Move {choice; step = Proof proof}) - in - - match game.game_state with - | Dissecting {dissection; default_number_of_sections} -> - let* choice, chosen_section_len, dissection = - generate_next_dissection - ~default_number_of_sections - node_ctxt - ~opponent - game - dissection - in - if Z.(equal chosen_section_len one) then final_move choice - else return (Move {choice; step = Dissection dissection}) - | Final_move {agreed_start_chunk; refuted_stop_chunk = _} -> - let choice = agreed_start_chunk.tick in - final_move choice - -let play_next_move node_ctxt game self opponent = - let open Lwt_result_syntax in - let* refutation = next_move node_ctxt ~opponent game in - inject_next_move node_ctxt self ~refutation ~opponent - -let play_timeout (node_ctxt : _ Node_context.t) self stakers = - let open Lwt_result_syntax in - let timeout_operation = - L1_operation.Timeout - { - rollup = node_ctxt.rollup_address; - stakers = Sc_rollup_proto_types.Game.index_to_octez stakers; - } - in - let source = - Node_context.get_operator node_ctxt Timeout |> Option.value ~default:self - (* We fallback on the [Refute] operator if none is provided for [Timeout] *) - in - let* _hash = Injector.add_pending_operation ~source timeout_operation in - return_unit - -let timeout_reached ~self head_block node_ctxt staker1 staker2 = +let timeout_reached node_ctxt ~self ~opponent = let open Lwt_result_syntax in let Node_context.{rollup_address; cctxt; _} = node_ctxt in - let* game_result = + let+ game_result = Plugin.RPC.Sc_rollup.timeout_reached (new Protocol_client_context.wrap_full cctxt) - (cctxt#chain, head_block) + (cctxt#chain, `Head 0) rollup_address - staker1 - staker2 + self + opponent in let open Sc_rollup.Game in match game_result with | Some (Loser {loser; _}) -> let is_it_me = Signature.Public_key_hash.(self = loser) in - if is_it_me then return_none else return (Some loser) - | _ -> return_none + not is_it_me + | _ -> false -let play node_ctxt ~self game opponent = +let get_conflicts cctxt rollup staker = let open Lwt_result_syntax in - let index = Sc_rollup.Game.Index.make self opponent in - let head_block = `Head 0 in - match turn ~self game index with - | Our_turn {opponent} -> play_next_move node_ctxt game self opponent - | Their_turn -> ( - let* timeout_reached = - timeout_reached ~self head_block node_ctxt self opponent - in - match timeout_reached with - | Some opponent -> - let*! () = Refutation_game_event.timeout_detected opponent in - play_timeout node_ctxt self index - | None -> return_unit) - -let play_opening_move node_ctxt self conflict = - let open Lwt_syntax in - let open Sc_rollup.Refutation_storage in - let* () = Refutation_game_event.conflict_detected conflict in - let player_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.our_commitment + let cctxt = new Protocol_client_context.wrap_full cctxt in + let+ conflicts = + Plugin.RPC.Sc_rollup.conflicts cctxt (cctxt#chain, `Head 0) rollup staker in - let opponent_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.their_commitment + List.map Sc_rollup_proto_types.Game.conflict_to_octez conflicts + +let get_ongoing_games cctxt rollup staker = + let open Lwt_result_syntax in + let cctxt = new Protocol_client_context.wrap_full cctxt in + let+ games = + Plugin.RPC.Sc_rollup.ongoing_refutation_games + cctxt + (cctxt#chain, `Head 0) + rollup + staker in - let refutation = Start {player_commitment_hash; opponent_commitment_hash} in - inject_next_move node_ctxt self ~refutation ~opponent:conflict.other + List.map + (fun (game, staker1, staker2) -> + (Sc_rollup_proto_types.Game.to_octez game, staker1, staker2)) + games diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game_helpers.mli b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game_helpers.mli new file mode 100644 index 0000000000000000000000000000000000000000..8799f5deb3aa72166227ae37c12c9d2cc5226b42 --- /dev/null +++ b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_game_helpers.mli @@ -0,0 +1,81 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) +(* Copyright (c) 2023 Functori, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** [generate_proof node_ctxt (game) start_state] generates a serialized proof + for the current [game] for the execution step starting with + [start_state]. *) +val generate_proof : + Node_context.rw -> Game.t -> Context.tree -> string tzresult Lwt.t + +(** [state_of_tick node_ctxt ?start_state ~tick level] returns [Some + (state, hash)] for a given [tick] if this [tick] happened before + [level]. Otherwise, returns [None]. If provided, the evaluation is resumed + from [start_state]. *) +val state_of_tick : + _ Node_context.t -> + ?start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state -> + tick:Z.t -> + int32 -> + Fuel.Accounted.t Pvm_plugin_sig.eval_state option tzresult Lwt.t + +(** [make_dissection node_ctxt ~start_state ~start_chunk ~our_stop_chunk + ~default_number_of_sections ~last_level] computes a dissection from between + [start_chunk] and [our_stop_chunk] at level [last_level]. This dissection + has [default_number_of_sections] if there are enough ticks. *) +val make_dissection : + _ Node_context.t -> + start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state option -> + start_chunk:Game.dissection_chunk -> + our_stop_chunk:Game.dissection_chunk -> + default_number_of_sections:int -> + last_level:int32 -> + Game.dissection_chunk trace tzresult Lwt.t + +(** [timeout_reached node_ctxt ~self ~opponent] returns [true] if the + timeout is reached against opponent in head of the L1 chain. *) +val timeout_reached : + _ Node_context.t -> + self:Signature.public_key_hash -> + opponent:Signature.public_key_hash -> + bool tzresult Lwt.t + +(** [get_conflicts cctxt rollup signer] returns the conflicts for commitments + staked on by [signer]. *) +val get_conflicts : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + Game.conflict list tzresult Lwt.t + +(** [get_ongoing_games cctxt rollup signer] returns the games that [signer] is + currently playing. *) +val get_ongoing_games : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + (Game.t * Signature.public_key_hash * Signature.public_key_hash) list tzresult + Lwt.t diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player.ml b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player.ml deleted file mode 100644 index 72901a452bf2e325b3b1fb5c791a1d61767884a3..0000000000000000000000000000000000000000 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player.ml +++ /dev/null @@ -1,183 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context -open Refutation_player_types -open Refutation_game - -module Types = struct - type state = { - node_ctxt : Node_context.rw; - self : public_key_hash; - opponent : public_key_hash; - mutable last_move_cache : (Sc_rollup.Game.game_state * int32) option; - } - - type parameters = { - node_ctxt : Node_context.rw; - self : public_key_hash; - conflict : Sc_rollup.Refutation_storage.conflict; - } -end - -module Name = struct - let base = Refutation_game_event.Player.section @ ["worker"] - - include Signature.Public_key_hash -end - -module Worker = Worker.MakeSingle (Name) (Request) (Types) - -type worker = Worker.infinite Worker.queue Worker.t - -let table = Worker.create_table Queue - -let on_play game Types.{node_ctxt; self; opponent; _} = - play node_ctxt ~self game opponent - -let on_play_opening conflict (Types.{node_ctxt; self; _} : Types.state) = - play_opening_move node_ctxt self conflict - -module Handlers = struct - type self = worker - - let on_request : - type r request_error. - worker -> (r, request_error) Request.t -> (r, request_error) result Lwt.t - = - fun w request -> - let state = Worker.state w in - match request with - | Request.Play game -> on_play game state - | Request.Play_opening conflict -> on_play_opening conflict state - - type launch_error = error trace - - let on_launch _w _name Types.{node_ctxt; self; conflict} = - return - Types.{node_ctxt; self; opponent = conflict.other; last_move_cache = None} - - let on_error (type a b) _w st (r : (a, b) Request.t) (errs : b) : - unit tzresult Lwt.t = - let open Lwt_result_syntax in - let request_view = Request.view r in - let emit_and_return_errors errs = - let*! () = - Refutation_game_event.Player.request_failed request_view st errs - in - return_unit - in - match r with - | Request.Play _ -> emit_and_return_errors errs - | Request.Play_opening _ -> emit_and_return_errors errs - - let on_completion _w r _ st = - Refutation_game_event.Player.request_completed (Request.view r) st - - let on_no_request _ = Lwt.return_unit - - let on_close w = - let open Lwt_syntax in - let state = Worker.state w in - let* () = Refutation_game_event.Player.stopped state.opponent in - return_unit -end - -let init node_ctxt ~self ~conflict = - let open Lwt_result_syntax in - let*! () = - Refutation_game_event.Player.started - conflict.Sc_rollup.Refutation_storage.other - conflict.Sc_rollup.Refutation_storage.our_commitment - in - let worker_promise, worker_waker = Lwt.task () in - let* worker = - trace Sc_rollup_node_errors.Refutation_player_failed_to_start - @@ Worker.launch - table - conflict.other - {node_ctxt; self; conflict} - (module Handlers) - in - let () = Lwt.wakeup worker_waker worker in - let worker = - match Lwt.state worker_promise with - | Lwt.Return worker -> ok worker - | Lwt.Fail _ | Lwt.Sleep -> - error Sc_rollup_node_errors.Refutation_player_failed_to_start - in - Lwt.return worker - -(* Play if: - - There's a new game state to play against or - - The current level is past the buffer for re-playing in the - same game state. -*) -let should_move ~level game last_move_cache = - match last_move_cache with - | None -> true - | Some (last_move_game_state, last_move_level) -> - (not - (Sc_rollup.Game.game_state_equal - game.Sc_rollup.Game.game_state - last_move_game_state)) - || Int32.( - sub level last_move_level - > of_int Configuration.refutation_player_buffer_levels) - -let play w game ~(level : int32) = - let open Lwt_syntax in - let state = Worker.state w in - if should_move ~level game state.last_move_cache then ( - let* pushed = Worker.Queue.push_request w (Request.Play game) in - if pushed then - state.last_move_cache <- Some (game.Sc_rollup.Game.game_state, level) ; - return_unit) - else return_unit - -let play_opening w conflict = - let open Lwt_syntax in - let* (_pushed : bool) = - Worker.Queue.push_request w (Request.Play_opening conflict) - in - return_unit - -let init_and_play node_ctxt ~self ~conflict ~game ~level = - let open Lwt_result_syntax in - let* worker = init node_ctxt ~self ~conflict in - let*! () = - match game with - | None -> play_opening worker conflict - | Some game -> play worker game ~level - in - return_unit - -let current_games () = - List.map - (fun (_name, worker) -> ((Worker.state worker).opponent, worker)) - (Worker.list table) - -let shutdown = Worker.shutdown diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player.mli b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player.mli deleted file mode 100644 index 92592e7c7cc5f17f7aa70b9be69eb6319bd31c1b..0000000000000000000000000000000000000000 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player.mli +++ /dev/null @@ -1,59 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -(** Worker module for a single refutation game player. The node's refutation - coordinator will spawn a new refutation player for each refutation game. -*) -module Worker : Worker.T - -(** Type for a refutation game player. *) -type worker = Worker.infinite Worker.queue Worker.t - -(** [init_and_play node_ctxt ~self ~conflict ~game ~level] initializes a new - refutation game player for signer [self]. After initizialization, the - worker will play the next move depending on the [game] state. If no [game] - is passed, the worker will play the opening move for [conflict]. *) -val init_and_play : - Node_context.rw -> - self:public_key_hash -> - conflict:Sc_rollup.Refutation_storage.conflict -> - game:Sc_rollup.Game.t option -> - level:int32 -> - unit tzresult Lwt.t - -(** [play worker game ~level] makes the [worker] play the next move depending - on the [game] state for their conflict. - *) -val play : worker -> Sc_rollup.Game.t -> level:int32 -> unit Lwt.t - -(** Shutdown a refutaiton game player. *) -val shutdown : worker -> unit Lwt.t - -(** [current_games ()] lists the opponents' this node is playing refutation - games against, alongside the worker that takes care of each game. *) -val current_games : unit -> (public_key_hash * worker) list diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player_types.ml b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player_types.ml deleted file mode 100644 index 5cb43af305096ca46dc4584d791b021229c4d0d2..0000000000000000000000000000000000000000 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player_types.ml +++ /dev/null @@ -1,73 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -module Request = struct - type ('a, 'b) t = - | Play : Sc_rollup.Game.t -> (unit, error trace) t - | Play_opening : - Sc_rollup.Refutation_storage.conflict - -> (unit, error trace) t - - type view = View : _ t -> view - - let view req = View req - - let encoding = - let open Data_encoding in - union - [ - case - (Tag 0) - ~title:"Play" - (obj2 - (req "request" (constant "play")) - (req "game" Sc_rollup.Game.encoding)) - (function View (Play g) -> Some ((), g) | _ -> None) - (fun ((), g) -> View (Play g)); - case - (Tag 1) - ~title:"Play opening" - (obj2 - (req "request" (constant "play_opening")) - (req "conflict" Sc_rollup.Refutation_storage.conflict_encoding)) - (function View (Play_opening c) -> Some ((), c) | _ -> None) - (fun ((), c) -> View (Play_opening c)); - ] - - let pp ppf (View r) = - match r with - | Play game -> Format.fprintf ppf "Playing game %a" Sc_rollup.Game.pp game - | Play_opening conflict -> - Format.fprintf - ppf - "Playing opening move for conflict against staker %a at our \ - commitment %a" - Sc_rollup.Staker.pp - conflict.other - Sc_rollup.Commitment.pp - conflict.our_commitment -end diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player_types.mli b/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player_types.mli deleted file mode 100644 index d29fd8289f450cde25d7a3e5b4fa6bc7ca278e8b..0000000000000000000000000000000000000000 --- a/src/proto_018_Proxford/lib_sc_rollup_node/refutation_player_types.mli +++ /dev/null @@ -1,45 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -module Request : sig - (** Type of requests accepted by the refutation player. *) - type ('a, 'b) t = - | Play : Sc_rollup.Game.t -> (unit, error trace) t - (** Play a step of an ongoing refutation game. *) - | Play_opening : - Sc_rollup.Refutation_storage.conflict - -> (unit, error trace) t - (** Play the opening move of a refutation game. *) - - type view = View : _ t -> view - - include - Worker_intf.REQUEST - with type ('a, 'request_error) t := ('a, 'request_error) t - and type view := view -end diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/rollup_node_plugin.ml b/src/proto_018_Proxford/lib_sc_rollup_node/rollup_node_plugin.ml index d54d5b6674235872968376834fd8ab660cf6fbbf..4c5dd5e5cfe44af177cd455e62b8dd74819996ad 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/rollup_node_plugin.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_node/rollup_node_plugin.ml @@ -30,7 +30,7 @@ module Plugin : Protocol_plugin_sig.S = struct module Dal_slots_tracker = Dal_slots_tracker module Inbox = Inbox module Interpreter = Interpreter - module Refutation_coordinator = Refutation_coordinator + module Refutation_game_helpers = Refutation_game_helpers module Batcher_constants = Batcher_constants module Layer1_helpers = Layer1_helpers module L1_processing = Daemon_helpers diff --git a/src/proto_alpha/lib_protocol/alpha_context.mli b/src/proto_alpha/lib_protocol/alpha_context.mli index 691c1b09392273fa2a70e2dd360ffb327d1f0296..a319cbc5d89b92a931ea3d85f202175e557125a6 100644 --- a/src/proto_alpha/lib_protocol/alpha_context.mli +++ b/src/proto_alpha/lib_protocol/alpha_context.mli @@ -2996,6 +2996,8 @@ module Sc_rollup : sig val old_levels_messages : t -> history_proof + val history_proof_encoding : history_proof Data_encoding.t + val equal_history_proof : history_proof -> history_proof -> bool val pp_history_proof : Format.formatter -> history_proof -> unit diff --git a/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_proto_types.ml b/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_proto_types.ml index b85e403c010d93097efde9b1ca0b5b6e28161177..85b565a104fa87fac05a1916589134c86ba3c90d 100644 --- a/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_proto_types.ml +++ b/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_proto_types.ml @@ -110,6 +110,8 @@ end module Inbox = struct type t = Sc_rollup.Inbox.t + type history_proof = Sc_rollup.Inbox.history_proof + let to_repr inbox = inbox |> Data_encoding.Binary.to_string_exn Sc_rollup.Inbox.encoding @@ -135,6 +137,106 @@ module Inbox = struct |> Data_encoding.Binary.of_string_exn Octez_smart_rollup.Inbox.versioned_encoding |> Octez_smart_rollup.Inbox.of_versioned + + let history_proof_of_octez (hist : Octez_smart_rollup.Inbox.history_proof) : + history_proof = + hist + |> Data_encoding.Binary.to_string_exn + Octez_smart_rollup.Inbox.history_proof_encoding + |> Data_encoding.Binary.of_string_exn Sc_rollup.Inbox.history_proof_encoding + + let history_proof_to_octez (hist : history_proof) : + Octez_smart_rollup.Inbox.history_proof = + hist + |> Data_encoding.Binary.to_string_exn Sc_rollup.Inbox.history_proof_encoding + |> Data_encoding.Binary.of_string_exn + Octez_smart_rollup.Inbox.history_proof_encoding +end + +module Dal = struct + module Slot_index = struct + type t = Dal.Slot_index.t + + let of_octez ~number_of_slots (i : Octez_smart_rollup.Dal.Slot_index.t) : t + = + match Dal.Slot_index.of_int_opt ~number_of_slots i with + | None -> Format.ksprintf invalid_arg "Dal.Slot_index.of_octez: %d" i + | Some i -> i + + let to_octez : t -> Octez_smart_rollup.Dal.Slot_index.t = + Dal.Slot_index.to_int + end + + module Page_index = struct + type t = Dal.Page.Index.t + + let of_octez : Octez_smart_rollup.Dal.Page_index.t -> t = Fun.id + + let to_octez : t -> Octez_smart_rollup.Dal.Page_index.t = Fun.id + end + + module Slot_header = struct + type t = Dal.Slot.Header.t + + let of_octez ~number_of_slots + Octez_smart_rollup.Dal.Slot_header. + {id = {published_level; index}; commitment} : t = + Dal.Slot.Header. + { + id = + { + published_level = Raw_level.of_int32_exn published_level; + index = Slot_index.of_octez ~number_of_slots index; + }; + commitment; + } + + let to_octez Dal.Slot.Header.{id = {published_level; index}; commitment} : + Octez_smart_rollup.Dal.Slot_header.t = + Octez_smart_rollup.Dal.Slot_header. + { + id = + { + published_level = Raw_level.to_int32 published_level; + index = Slot_index.to_octez index; + }; + commitment; + } + end + + module Slot_history = struct + type t = Dal.Slots_history.t + + let of_octez (h : Octez_smart_rollup.Dal.Slot_history.t) : t = + h + |> Data_encoding.Binary.to_bytes_exn + Octez_smart_rollup.Dal.Slot_history.encoding + |> Data_encoding.Binary.of_bytes_exn Dal.Slots_history.encoding + + let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history.t = + h + |> Data_encoding.Binary.to_bytes_exn Dal.Slots_history.encoding + |> Data_encoding.Binary.of_bytes_exn + Octez_smart_rollup.Dal.Slot_history.encoding + end + + module Slot_history_cache = struct + type t = Dal.Slots_history.History_cache.t + + let of_octez (h : Octez_smart_rollup.Dal.Slot_history_cache.t) : t = + h + |> Data_encoding.Binary.to_bytes_exn + Octez_smart_rollup.Dal.Slot_history_cache.encoding + |> Data_encoding.Binary.of_bytes_exn + Dal.Slots_history.History_cache.encoding + + let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history_cache.t = + h + |> Data_encoding.Binary.to_bytes_exn + Dal.Slots_history.History_cache.encoding + |> Data_encoding.Binary.of_bytes_exn + Octez_smart_rollup.Dal.Slot_history_cache.encoding + end end module Game = struct @@ -146,6 +248,14 @@ module Game = struct type index = Sc_rollup.Game.Index.t + type player = Sc_rollup.Game.player + + type game_state = Sc_rollup.Game.game_state + + type t = Sc_rollup.Game.t + + type conflict = Sc_rollup.Refutation_storage.conflict + let dissection_chunk_of_octez Octez_smart_rollup.Game.{state_hash; tick} : dissection_chunk = { @@ -223,104 +333,116 @@ module Game = struct let index_to_octez Sc_rollup.Game.Index.{alice; bob} = Octez_smart_rollup.Game.make_index alice bob -end - -module Kind = struct - type t = Sc_rollup.Kind.t - - let of_octez : Octez_smart_rollup.Kind.t -> t = function - | Example_arith -> Example_arith - | Wasm_2_0_0 -> Wasm_2_0_0 - - let to_octez : t -> Octez_smart_rollup.Kind.t = function - | Example_arith -> Example_arith - | Wasm_2_0_0 -> Wasm_2_0_0 -end - -module Dal = struct - module Slot_index = struct - type t = Dal.Slot_index.t - - let of_octez ~number_of_slots (i : Octez_smart_rollup.Dal.Slot_index.t) : t - = - match Dal.Slot_index.of_int_opt ~number_of_slots i with - | None -> Format.ksprintf invalid_arg "Dal.Slot_index.of_octez: %d" i - | Some i -> i - let to_octez : t -> Octez_smart_rollup.Dal.Slot_index.t = - Dal.Slot_index.to_int - end + let player_of_octez : Octez_smart_rollup.Game.player -> player = function + | Alice -> Alice + | Bob -> Bob - module Page_index = struct - type t = Dal.Page.Index.t + let player_to_octez : player -> Octez_smart_rollup.Game.player = function + | Alice -> Alice + | Bob -> Bob - let of_octez : Octez_smart_rollup.Dal.Page_index.t -> t = Fun.id - - let to_octez : t -> Octez_smart_rollup.Dal.Page_index.t = Fun.id - end + let game_state_of_octez : Octez_smart_rollup.Game.game_state -> game_state = + function + | Dissecting {dissection; default_number_of_sections} -> + Dissecting + { + dissection = List.map dissection_chunk_of_octez dissection; + default_number_of_sections; + } + | Final_move {agreed_start_chunk; refuted_stop_chunk} -> + Final_move + { + agreed_start_chunk = dissection_chunk_of_octez agreed_start_chunk; + refuted_stop_chunk = dissection_chunk_of_octez refuted_stop_chunk; + } - module Slot_header = struct - type t = Dal.Slot.Header.t + let game_state_to_octez : game_state -> Octez_smart_rollup.Game.game_state = + function + | Dissecting {dissection; default_number_of_sections} -> + Dissecting + { + dissection = List.map dissection_chunk_to_octez dissection; + default_number_of_sections; + } + | Final_move {agreed_start_chunk; refuted_stop_chunk} -> + Final_move + { + agreed_start_chunk = dissection_chunk_to_octez agreed_start_chunk; + refuted_stop_chunk = dissection_chunk_to_octez refuted_stop_chunk; + } - let of_octez ~number_of_slots - Octez_smart_rollup.Dal.Slot_header. - {id = {published_level; index}; commitment} : t = - Dal.Slot.Header. + let of_octez + Octez_smart_rollup.Game. { - id = - { - published_level = Raw_level.of_int32_exn published_level; - index = Slot_index.of_octez ~number_of_slots index; - }; - commitment; - } + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + } : t = + { + turn = player_of_octez turn; + inbox_snapshot = Inbox.history_proof_of_octez inbox_snapshot; + dal_snapshot = Dal.Slot_history.of_octez dal_snapshot; + start_level = Raw_level.of_int32_exn start_level; + inbox_level = Raw_level.of_int32_exn inbox_level; + game_state = game_state_of_octez game_state; + } - let to_octez Dal.Slot.Header.{id = {published_level; index}; commitment} : - Octez_smart_rollup.Dal.Slot_header.t = - Octez_smart_rollup.Dal.Slot_header. + let to_octez + Sc_rollup.Game. { - id = - { - published_level = Raw_level.to_int32 published_level; - index = Slot_index.to_octez index; - }; - commitment; - } - end - - module Slot_history = struct - type t = Dal.Slots_history.t + turn; + inbox_snapshot; + dal_snapshot; + start_level; + inbox_level; + game_state; + } : Octez_smart_rollup.Game.t = + { + turn = player_to_octez turn; + inbox_snapshot = Inbox.history_proof_to_octez inbox_snapshot; + dal_snapshot = Dal.Slot_history.to_octez dal_snapshot; + start_level = Raw_level.to_int32 start_level; + inbox_level = Raw_level.to_int32 inbox_level; + game_state = game_state_to_octez game_state; + } - let of_octez (h : Octez_smart_rollup.Dal.Slot_history.t) : t = - h - |> Data_encoding.Binary.to_bytes_exn - Octez_smart_rollup.Dal.Slot_history.encoding - |> Data_encoding.Binary.of_bytes_exn Dal.Slots_history.encoding + let conflict_of_octez + Octez_smart_rollup.Game. + {other; their_commitment; our_commitment; parent_commitment} : conflict + = + { + other; + their_commitment = Commitment.of_octez their_commitment; + our_commitment = Commitment.of_octez our_commitment; + parent_commitment; + } - let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history.t = - h - |> Data_encoding.Binary.to_bytes_exn Dal.Slots_history.encoding - |> Data_encoding.Binary.of_bytes_exn - Octez_smart_rollup.Dal.Slot_history.encoding - end + let conflict_to_octez + Sc_rollup.Refutation_storage. + {other; their_commitment; our_commitment; parent_commitment} : + Octez_smart_rollup.Game.conflict = + { + other; + their_commitment = Commitment.to_octez their_commitment; + our_commitment = Commitment.to_octez our_commitment; + parent_commitment; + } +end - module Slot_history_cache = struct - type t = Dal.Slots_history.History_cache.t +module Kind = struct + type t = Sc_rollup.Kind.t - let of_octez (h : Octez_smart_rollup.Dal.Slot_history_cache.t) : t = - h - |> Data_encoding.Binary.to_bytes_exn - Octez_smart_rollup.Dal.Slot_history_cache.encoding - |> Data_encoding.Binary.of_bytes_exn - Dal.Slots_history.History_cache.encoding + let of_octez : Octez_smart_rollup.Kind.t -> t = function + | Example_arith -> Example_arith + | Wasm_2_0_0 -> Wasm_2_0_0 - let to_octez (h : t) : Octez_smart_rollup.Dal.Slot_history_cache.t = - h - |> Data_encoding.Binary.to_bytes_exn - Dal.Slots_history.History_cache.encoding - |> Data_encoding.Binary.of_bytes_exn - Octez_smart_rollup.Dal.Slot_history_cache.encoding - end + let to_octez : t -> Octez_smart_rollup.Kind.t = function + | Example_arith -> Example_arith + | Wasm_2_0_0 -> Wasm_2_0_0 end module Constants = struct diff --git a/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_proto_types.mli b/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_proto_types.mli index e1426d860a988de2c9006e7f0604c107560be539..b00d3991fe0dce4ddc1f817537092d75e1ae30d9 100644 --- a/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_proto_types.mli +++ b/src/proto_alpha/lib_sc_rollup_layer2/sc_rollup_proto_types.mli @@ -76,9 +76,17 @@ end module Inbox : sig type t = Sc_rollup.Inbox.t + type history_proof = Sc_rollup.Inbox.history_proof + val of_octez : Octez_smart_rollup.Inbox.t -> t val to_octez : t -> Octez_smart_rollup.Inbox.t + + val history_proof_of_octez : + Octez_smart_rollup.Inbox.history_proof -> history_proof + + val history_proof_to_octez : + history_proof -> Octez_smart_rollup.Inbox.history_proof end module Game : sig @@ -107,6 +115,30 @@ module Game : sig val index_of_octez : Octez_smart_rollup.Game.index -> index val index_to_octez : index -> Octez_smart_rollup.Game.index + + type player = Sc_rollup.Game.player + + val player_of_octez : Octez_smart_rollup.Game.player -> player + + val player_to_octez : player -> Octez_smart_rollup.Game.player + + type game_state = Sc_rollup.Game.game_state + + val game_state_of_octez : Octez_smart_rollup.Game.game_state -> game_state + + val game_state_to_octez : game_state -> Octez_smart_rollup.Game.game_state + + type t = Sc_rollup.Game.t + + val of_octez : Octez_smart_rollup.Game.t -> t + + val to_octez : t -> Octez_smart_rollup.Game.t + + type conflict = Sc_rollup.Refutation_storage.conflict + + val conflict_of_octez : Octez_smart_rollup.Game.conflict -> conflict + + val conflict_to_octez : conflict -> Octez_smart_rollup.Game.conflict end module Kind : sig diff --git a/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml b/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml index 57315ced452c02e0f548959d783bc549d5c003a2..5e4a5a9851028233e7eeb89b2b5dee0d773a9741 100644 --- a/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml +++ b/src/proto_alpha/lib_sc_rollup_node/daemon_helpers.ml @@ -99,7 +99,7 @@ let accuser_publish_commitment_when_refutable node_ctxt ~other rollup Refutation_game_event.potential_conflict_detected ~our_commitment_hash ~their_commitment_hash - ~level:their_commitment.inbox_level + ~level:(Raw_level.to_int32 their_commitment.inbox_level) ~other in assert (Sc_rollup.Address.(node_ctxt.rollup_address = rollup)) ; diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator.ml b/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator.ml deleted file mode 100644 index 21403e6efef25151bbd555dd43b0bbc7afbe13e3..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator.ml +++ /dev/null @@ -1,245 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context -open Refutation_coordinator_types -include Refutation_game -module Player = Refutation_player -module Pkh_map = Signature.Public_key_hash.Map -module Pkh_table = Signature.Public_key_hash.Table - -type state = { - node_ctxt : Node_context.rw; - cctxt : Protocol_client_context.full; - pending_opponents : unit Pkh_table.t; -} - -let get_conflicts cctxt head_block = - Plugin.RPC.Sc_rollup.conflicts cctxt (cctxt#chain, head_block) - -let get_ongoing_games cctxt head_block = - Plugin.RPC.Sc_rollup.ongoing_refutation_games cctxt (cctxt#chain, head_block) - -let untracked_conflicts opponent_players conflicts = - List.filter - (fun conflict -> - not - @@ Pkh_map.mem - conflict.Sc_rollup.Refutation_storage.other - opponent_players) - conflicts - -(* Transform the list of ongoing games [(Game.t * pkh * pkh) list] - into a mapping from opponents' pkhs to their corresponding game - state. -*) -let make_game_map self ongoing_games = - List.fold_left - (fun acc (game, alice, bob) -> - let opponent_pkh = - if Signature.Public_key_hash.equal self alice then bob else alice - in - Pkh_map.add opponent_pkh game acc) - Pkh_map.empty - ongoing_games - -let on_process Layer1.{hash; level} state = - let node_ctxt = state.node_ctxt in - let head_block = `Hash (hash, 0) in - let open Lwt_result_syntax in - let refute_signer = Node_context.get_operator node_ctxt Refute in - match refute_signer with - | None -> - (* Not injecting refutations, don't play refutation games *) - return_unit - | Some self -> - let Node_context.{rollup_address; _} = node_ctxt in - (* Current conflicts in L1 *) - let* conflicts = - get_conflicts state.cctxt head_block rollup_address self - in - (* Map of opponents the node is playing against to the corresponding - player worker *) - let opponent_players = - Pkh_map.of_seq @@ List.to_seq @@ Player.current_games () - in - (* Conflicts for which we need to start new refutation players. - Some of these might be ongoing. *) - let new_conflicts = untracked_conflicts opponent_players conflicts in - (* L1 ongoing games *) - let* ongoing_games = - get_ongoing_games state.cctxt head_block rollup_address self - in - (* Map between opponents and their corresponding games *) - let ongoing_game_map = make_game_map self ongoing_games in - (* Launch new players for new conflicts, and play one step *) - let* () = - List.iter_ep - (fun conflict -> - let other = conflict.Sc_rollup.Refutation_storage.other in - Pkh_table.replace state.pending_opponents other () ; - let game = Pkh_map.find_opt other ongoing_game_map in - Player.init_and_play node_ctxt ~self ~conflict ~game ~level) - new_conflicts - in - let*! () = - (* Play one step of the refutation game in every remaining player *) - Pkh_map.iter_p - (fun opponent worker -> - match Pkh_map.find opponent ongoing_game_map with - | Some game -> - Pkh_table.remove state.pending_opponents opponent ; - Player.play worker game ~level - | None -> - (* Kill finished players: those who don't aren't - playing against pending opponents that don't have - ongoing games in the L1 *) - if not @@ Pkh_table.mem state.pending_opponents opponent then - Player.shutdown worker - else Lwt.return_unit) - opponent_players - in - return_unit - -module Types = struct - type nonrec state = state - - type parameters = { - node_ctxt : Node_context.rw; - cctxt : Protocol_client_context.full; - } -end - -module Name = struct - (* We only have a single coordinator in the node *) - type t = unit - - let encoding = Data_encoding.unit - - let base = - (* But we can have multiple instances in the unit tests. This is just to - avoid conflicts in the events declarations. *) - Refutation_game_event.Coordinator.section @ ["worker"] - - let pp _ _ = () - - let equal () () = true -end - -module Worker = Worker.MakeSingle (Name) (Request) (Types) - -type worker = Worker.infinite Worker.queue Worker.t - -module Handlers = struct - type self = worker - - let on_request : - type r request_error. - worker -> (r, request_error) Request.t -> (r, request_error) result Lwt.t - = - fun w request -> - let state = Worker.state w in - match request with Request.Process b -> on_process b state - - type launch_error = error trace - - let on_launch _w () Types.{node_ctxt; cctxt} = - return {node_ctxt; cctxt; pending_opponents = Pkh_table.create 5} - - let on_error (type a b) _w st (r : (a, b) Request.t) (errs : b) : - unit tzresult Lwt.t = - let open Lwt_result_syntax in - let request_view = Request.view r in - let emit_and_return_errors errs = - let*! () = - Refutation_game_event.Coordinator.request_failed request_view st errs - in - return_unit - in - match r with Request.Process _ -> emit_and_return_errors errs - - let on_completion _w r _ st = - Refutation_game_event.Coordinator.request_completed (Request.view r) st - - let on_no_request _ = Lwt.return_unit - - let on_close _w = Lwt.return_unit -end - -let table = Worker.create_table Queue - -let worker_promise, worker_waker = Lwt.task () - -let start node_ctxt = - let open Lwt_result_syntax in - let*! () = Refutation_game_event.Coordinator.starting () in - let cctxt = - new Protocol_client_context.wrap_full node_ctxt.Node_context.cctxt - in - let+ worker = Worker.launch table () {node_ctxt; cctxt} (module Handlers) in - Lwt.wakeup worker_waker worker - -let init node_ctxt = - let open Lwt_result_syntax in - match Lwt.state worker_promise with - | Lwt.Return _ -> - (* Worker already started, nothing to do. *) - return_unit - | Lwt.Fail exn -> - (* Worker crashed, not recoverable. *) - fail [Sc_rollup_node_errors.No_refutation_coordinator; Exn exn] - | Lwt.Sleep -> - (* Never started, start it. *) - start node_ctxt - -(* This is a refutation coordinator for a single scoru *) -let worker = - lazy - (match Lwt.state worker_promise with - | Lwt.Return worker -> ok worker - | Lwt.Fail _ | Lwt.Sleep -> - error Sc_rollup_node_errors.No_refutation_coordinator) - -let process b = - let open Lwt_result_syntax in - let*? w = Lazy.force worker in - let*! (_pushed : bool) = Worker.Queue.push_request w (Request.Process b) in - return_unit - -let shutdown () = - let open Lwt_syntax in - let w = Lazy.force worker in - match w with - | Error _ -> - (* There is no refutation coordinator, nothing to do *) - Lwt.return_unit - | Ok w -> - (* Shut down all current refutation players *) - let games = Player.current_games () in - let* () = - List.iter_s (fun (_opponent, player) -> Player.shutdown player) games - in - Worker.shutdown w diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator.mli b/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator.mli deleted file mode 100644 index 12a35582b9b294687783aa6964b0290f6d3d35ea..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator.mli +++ /dev/null @@ -1,47 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -(** Component for managing refutation games. - This module is implemented as a single worker in the rollup node, - which takes care of processing new L1 heads, and coordinating - the refutation game players. (See {!Refutation_player}). -*) - -(** Initiatilize the refuation coordinator. *) -val init : Node_context.rw -> unit tzresult Lwt.t - -(** Process a new l1 head. This means that the coordinator will: - {ol - {li Gather all existing conflicts} - {li Launch new refutation players for each conflict that doesn't - have a player in this node} - {li Kill all players whose conflict has disappeared from L1} - {li Make all players play a step in the refutation} - } - *) -val process : Layer1.head -> unit tzresult Lwt.t - -(** Shutdown the refutation coordinator. *) -val shutdown : unit -> unit Lwt.t diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator_types.ml b/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator_types.ml deleted file mode 100644 index 314698ed82ff7cce4951b0d7eadebaf9bf3b7247..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator_types.ml +++ /dev/null @@ -1,56 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -module Request = struct - type ('a, 'b) t = Process : Layer1.head -> (unit, error trace) t - - type view = View : _ t -> view - - let view req = View req - - let encoding = - let open Data_encoding in - union - [ - case - (Tag 0) - ~title:"Process" - (obj2 - (req "request" (constant "process")) - (req "block" Layer1.head_encoding)) - (function View (Process b) -> Some ((), b)) - (fun ((), b) -> View (Process b)); - ] - - let pp ppf (View r) = - match r with - | Process {Layer1.hash; level} -> - Format.fprintf - ppf - "Processing new L1 head %a at level %ld" - Block_hash.pp - hash - level -end diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator_types.mli b/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator_types.mli deleted file mode 100644 index f26d46885c774a05b48c75bcee47dd40a099fd64..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_coordinator_types.mli +++ /dev/null @@ -1,38 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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. *) -(* *) -(*****************************************************************************) - -module Request : sig - (** Type of requests accepted by the refutation coordinator. *) - type ('a, 'b) t = - | Process : Layer1.head -> (unit, error trace) t - (** Request to process new refutation games. *) - - type view = View : _ t -> view - - include - Worker_intf.REQUEST - with type ('a, 'request_error) t := ('a, 'request_error) t - and type view := view -end diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_game.mli b/src/proto_alpha/lib_sc_rollup_node/refutation_game.mli deleted file mode 100644 index 3229857d1aa7ad1cb2778b885650aff71cac5ff7..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_game.mli +++ /dev/null @@ -1,46 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -(** This module implements the refutation game logic of the rollup node. *) - -(** [play_opening_move node_ctxt self conflict] injects the opening refutation - game move for [conflict]. *) -val play_opening_move : - [< `Read | `Write > `Read] Node_context.t -> - public_key_hash -> - Sc_rollup.Refutation_storage.conflict -> - (unit, tztrace) result Lwt.t - -(** [play head_block node_ctxt ~self game opponent] injects the next move in the - refutation [game] played by [self] and [opponent]. *) -val play : - Node_context.rw -> - self:public_key_hash -> - Sc_rollup.Game.t -> - public_key_hash -> - (unit, tztrace) result Lwt.t diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_game_event.ml b/src/proto_alpha/lib_sc_rollup_node/refutation_game_event.ml deleted file mode 100644 index ceb5ef25e148d96bfcfd688c0ea316a95452ab5a..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_game_event.ml +++ /dev/null @@ -1,260 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) -(* *) -(* 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 Protocol.Alpha_context - -(* TODO: https://gitlab.com/tezos/tezos/-/issues/2880 - Add corresponding .mli file. *) - -let section = [Protocol.name; "sc_rollup_node"; "refutation_game"] - -module Simple = struct - include Internal_event.Simple - - let timeout = - declare_1 - ~section - ~name:"sc_rollup_node_timeout" - ~msg: - "The rollup node has been slashed because of a timeout issued by \ - {address}" - ~level:Notice - ("address", Signature.Public_key_hash.encoding) - - let invalid_move = - declare_0 - ~section - ~name:"sc_rollup_node_invalid_move" - ~msg: - "The rollup node is about to make an invalid move in the refutation \ - game! It is stopped to avoid being slashed. The problem should be \ - reported immediately or the rollup node should be upgraded to have a \ - chance to be back before the timeout is reached." - ~level:Notice - () - - let conflict_detected = - declare_5 - ~section - ~name:"sc_rollup_node_conflict_detected" - ~msg: - "A conflict has been found with our commitment {our_commitment_hash} \ - at level {level} with staker {other} that hash issued commitment \ - {their_commitment_hash} both based on {parent_commitment_hash}." - ~level:Notice - ("our_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("level", Raw_level.encoding) - ("other", Sc_rollup.Staker.encoding) - ("their_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("parent_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - - let potential_conflict_detected = - declare_4 - ~section - ~name:"sc_rollup_node_potential_conflict_detected" - ~msg: - "A potential conflict has been found with our commitment \ - {our_commitment_hash} at level {level} with staker {other} that hash \ - issued commitment {their_commitment_hash}." - ~level:Notice - ("our_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - ("level", Raw_level.encoding) - ("other", Sc_rollup.Staker.encoding) - ("their_commitment_hash", Sc_rollup.Commitment.Hash.encoding) - - let timeout_detected = - declare_1 - ~section - ~name:"sc_rollup_node_timeout_detected" - ~msg: - "The rollup node has detected that opponent {other} can be timed out." - ~level:Notice - ("other", Sc_rollup.Staker.encoding) - - let dissection_chunk_encoding = - let open Data_encoding in - let open Sc_rollup.Dissection_chunk in - conv - (fun {state_hash; tick} -> (state_hash, tick)) - (fun (state_hash, tick) -> {state_hash; tick}) - (obj2 - (opt "state" Sc_rollup.State_hash.encoding) - (req "tick" Sc_rollup.Tick.encoding)) - - let computed_dissection = - declare_4 - ~section - ~name:"sc_rollup_node_computed_dissection" - ~msg: - "Computed dissection against {opponent} between ticks {start_tick} and \ - {end_tick}: {dissection}." - ~level:Debug - ("opponent", Signature.Public_key_hash.encoding) - ("start_tick", Sc_rollup.Tick.encoding) - ("end_tick", Sc_rollup.Tick.encoding) - ("dissection", Data_encoding.list dissection_chunk_encoding) - - module Worker (ARG : sig - val section : string list - end) - (Request : Worker_intf.REQUEST) = - struct - include ARG - - let request_failed = - declare_3 - ~section - ~name:"request_failed" - ~msg:"request {view} failed ({worker_status}): {errors}" - ~level:Notice - ("view", Request.encoding) - ~pp1:Request.pp - ("worker_status", Worker_types.request_status_encoding) - ~pp2:Worker_types.pp_status - ("errors", Error_monad.trace_encoding) - ~pp3:Error_monad.pp_print_trace - - let request_completed = - declare_2 - ~section - ~name:"request_completed" - ~msg:"{view} {worker_status}" - ~level:Debug - ("view", Request.encoding) - ("worker_status", Worker_types.request_status_encoding) - ~pp1:Request.pp - ~pp2:Worker_types.pp_status - end - - module Player = struct - include - Worker - (struct - let section = section @ ["player"] - end) - (Refutation_player_types.Request) - - let started = - declare_2 - ~section - ~name:"player_started" - ~msg: - "refutation player started to play against {opponent}, defenfing \ - commitment {commitment}" - ~level:Notice - ("opponent", Signature.Public_key_hash.encoding) - ~pp1:Signature.Public_key_hash.pp - ("commitment", Sc_rollup.Commitment.encoding) - ~pp2:Sc_rollup.Commitment.pp - - let stopped = - declare_1 - ~section - ~name:"player_stopped" - ~msg:"refutation player for opponent {opponent} has been stopped" - ~level:Notice - ("opponent", Signature.Public_key_hash.encoding) - ~pp1:Signature.Public_key_hash.pp - end - - module Coordinator = struct - include - Worker - (struct - let section = section @ ["coordinator"] - end) - (Refutation_coordinator_types.Request) - - let starting = - declare_0 - ~section - ~name:"coordinator_starting" - ~msg:"Starting refutation coordinator for the smart rollup node" - ~level:Notice - () - end -end - -let timeout address = Simple.(emit timeout address) - -let invalid_move () = Simple.(emit invalid_move ()) - -let conflict_detected (conflict : Sc_rollup.Refutation_storage.conflict) = - let our_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.our_commitment - in - let their_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.their_commitment - in - let parent_commitment_hash = conflict.parent_commitment in - let other = conflict.other in - let level = conflict.our_commitment.inbox_level in - Simple.( - emit - conflict_detected - ( our_commitment_hash, - level, - other, - their_commitment_hash, - parent_commitment_hash )) - -let potential_conflict_detected ~our_commitment_hash ~their_commitment_hash - ~other ~level = - Simple.( - emit - potential_conflict_detected - (our_commitment_hash, level, other, their_commitment_hash)) - -let timeout_detected other = Simple.(emit timeout_detected other) - -let computed_dissection ~opponent ~start_tick ~end_tick dissection = - Simple.(emit computed_dissection (opponent, start_tick, end_tick, dissection)) - -module Player = struct - let section = Simple.Player.section - - let request_failed view worker_status errors = - Simple.(emit Player.request_failed (view, worker_status, errors)) - - let request_completed view worker_status = - Simple.(emit Player.request_completed (view, worker_status)) - - let started opponent commitment = - Simple.(emit Player.started (opponent, commitment)) - - let stopped opponent = Simple.(emit Player.stopped opponent) -end - -module Coordinator = struct - let section = Simple.Coordinator.section - - let request_failed view worker_status errors = - Simple.(emit Coordinator.request_failed (view, worker_status, errors)) - - let request_completed view worker_status = - Simple.(emit Coordinator.request_completed (view, worker_status)) - - let starting = Simple.(emit Coordinator.starting) -end diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_game.ml b/src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.ml similarity index 55% rename from src/proto_alpha/lib_sc_rollup_node/refutation_game.ml rename to src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.ml index afabcca77936d54bb0b48f2f31a0b16397bbffad..850e54227fb888d5885e99ede49b502304295902 100644 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_game.ml +++ b/src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.ml @@ -1,7 +1,9 @@ (*****************************************************************************) (* *) (* Open Source License *) -(* Copyright (c) 2022 Nomadic Labs, *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) +(* Copyright (c) 2023 Functori, *) (* *) (* Permission is hereby granted, free of charge, to any person obtaining a *) (* copy of this software and associated documentation files (the "Software"),*) @@ -23,61 +25,8 @@ (* *) (*****************************************************************************) -(** This module implements the refutation game logic of the rollup - node. - - When a new L1 block arises, the rollup node asks the L1 node for - the current game it is part of, if any. - - If a game is running and it is the rollup operator turn, the rollup - node injects the next move of the winning strategy. - - If a game is running and it is not the rollup operator turn, the - rollup node asks the L1 node whether the timeout is reached to play - the timeout argument if possible. - - Otherwise, if no game is running, the rollup node asks the L1 node - whether there is a conflict with one of its disputable commitments. If - there is such a conflict with a commitment C', then the rollup node - starts a game to refute C' by starting a game with one of its staker. - -*) open Protocol - open Alpha_context -open Sc_rollup.Game - -let node_role ~self Sc_rollup.Game.Index.{alice; bob} = - if Sc_rollup.Staker.equal alice self then Alice - else if Sc_rollup.Staker.equal bob self then Bob - else (* By validity of [ongoing_game] RPC. *) - assert false - -type role = Our_turn of {opponent : public_key_hash} | Their_turn - -let turn ~self game players = - let Sc_rollup.Game.Index.{alice; bob} = players in - match (node_role ~self players, game.turn) with - | Alice, Alice -> Our_turn {opponent = bob} - | Bob, Bob -> Our_turn {opponent = alice} - | Alice, Bob -> Their_turn - | Bob, Alice -> Their_turn - -(** [inject_next_move node_ctxt source ~refutation ~opponent ~commitment - ~opponent_commitment] submits an L1 operation (signed by [source]) to - issue the next move in the refutation game. *) -let inject_next_move node_ctxt source ~refutation ~opponent = - let open Lwt_result_syntax in - let refute_operation = - L1_operation.Refute - { - rollup = node_ctxt.Node_context.rollup_address; - refutation = Sc_rollup_proto_types.Game.refutation_to_octez refutation; - opponent; - } - in - let* _hash = Injector.add_pending_operation ~source refute_operation in - return_unit (** This function computes the inclusion/membership proof of the page identified by [page_id] in the slot whose data are provided in @@ -161,29 +110,28 @@ let page_info_from_pvm_state (node_ctxt : _ Node_context.t) ~dal_attestation_lag | _ -> return_none let metadata (node_ctxt : _ Node_context.t) = - let address = - Sc_rollup_proto_types.Address.of_octez node_ctxt.rollup_address - in + let address = node_ctxt.rollup_address in let origination_level = Raw_level.of_int32_exn node_ctxt.genesis_info.level in Sc_rollup.Metadata.{address; origination_level} -let generate_proof (node_ctxt : _ Node_context.t) game start_state = +let generate_proof (node_ctxt : _ Node_context.t) + (game : Octez_smart_rollup.Game.t) start_state = let open Lwt_result_syntax in let module PVM = (val Pvm.of_kind node_ctxt.kind) in - let snapshot = game.inbox_snapshot in + let snapshot = + Sc_rollup_proto_types.Inbox.history_proof_of_octez game.inbox_snapshot + in (* NOTE: [snapshot_level_int32] below refers to the level of the snapshotted inbox (from the skip list) which also matches [game.start_level - 1]. *) let snapshot_level_int32 = - Raw_level.to_int32 (Sc_rollup.Inbox.Skip_list.content snapshot).level + (Octez_smart_rollup.Inbox.Skip_list.content game.inbox_snapshot).level in let get_snapshot_head () = let+ hash = Node_context.hash_of_level node_ctxt snapshot_level_int32 in Layer1.{hash; level = snapshot_level_int32} in let* context = - let* start_hash = - Node_context.hash_of_level node_ctxt (Raw_level.to_int32 game.inbox_level) - in + let* start_hash = Node_context.hash_of_level node_ctxt game.inbox_level in let+ context = Node_context.checkout_context node_ctxt start_hash in Context.index context in @@ -301,13 +249,13 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = trace (Sc_rollup_node_errors.Cannot_produce_proof { - inbox_level = Raw_level.to_int32 game.inbox_level; + inbox_level = game.inbox_level; start_tick = Sc_rollup.Tick.to_z start_tick; }) @@ (Sc_rollup.Proof.produce ~metadata (module P) - game.inbox_level + (Raw_level.of_int32_exn game.inbox_level) ~is_reveal_enabled >|= Environment.wrap_tzresult) in @@ -320,7 +268,7 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = Sc_rollup.Proof.valid ~metadata snapshot - game.inbox_level + (Raw_level.of_int32_exn game.inbox_level) dal_slots_history dal_parameters ~dal_attestation_lag @@ -329,41 +277,38 @@ let generate_proof (node_ctxt : _ Node_context.t) game start_state = ~is_reveal_enabled >|= Environment.wrap_tzresult in - if Result.is_ok res then return proof else assert false + assert (Result.is_ok res) ; + let proof = + Data_encoding.Binary.to_string_exn Sc_rollup.Proof.encoding proof + in + return proof -type pvm_intermediate_state = - | Hash of Sc_rollup.State_hash.t - | Evaluated of Fuel.Accounted.t Pvm_plugin_sig.eval_state +let state_of_tick node_ctxt ?start_state ~tick level = + Interpreter.state_of_tick + node_ctxt + ?start_state + ~tick + (Raw_level.of_int32_exn level) -let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok - our_view = +let make_dissection (node_ctxt : _ Node_context.t) ~start_state ~start_chunk + ~our_stop_chunk ~default_number_of_sections ~last_level = let open Lwt_result_syntax in + let module PVM = (val Pvm.of_kind node_ctxt.kind) in let state_of_tick ?start_state tick = - Interpreter.state_of_tick + state_of_tick node_ctxt ?start_state ~tick:(Sc_rollup.Tick.to_z tick) last_level in let state_hash_of_eval_state Pvm_plugin_sig.{state_hash; _} = state_hash in - let start_hash, start_tick, start_state = - match ok with - | Hash hash, tick -> (hash, tick, None) - | Evaluated ({state_hash; _} as state), tick -> - (state_hash, tick, Some state) - in let start_chunk = - Sc_rollup.Dissection_chunk.{state_hash = Some start_hash; tick = start_tick} - in - let our_state, our_tick = our_view in - let our_state_hash = - Option.map (fun Pvm_plugin_sig.{state_hash; _} -> state_hash) our_state + Sc_rollup_proto_types.Game.dissection_chunk_of_octez start_chunk in let our_stop_chunk = - Sc_rollup.Dissection_chunk.{state_hash = our_state_hash; tick = our_tick} + Sc_rollup_proto_types.Game.dissection_chunk_of_octez our_stop_chunk in - let module PVM = (val Pvm.of_kind node_ctxt.kind) in - let* dissection = + let+ dissection = Game_helpers.make_dissection ~state_of_tick ~state_hash_of_eval_state @@ -375,181 +320,45 @@ let new_dissection ~opponent ~default_number_of_sections node_ctxt last_level ok ~our_stop_chunk ~default_number_of_sections in - let*! () = - Refutation_game_event.computed_dissection - ~opponent - ~start_tick - ~end_tick:our_tick - dissection - in - return dissection + List.map Sc_rollup_proto_types.Game.dissection_chunk_to_octez dissection -(** [generate_from_dissection ~default_number_of_sections node_ctxt game - dissection] traverses the current [dissection] and returns a move which - performs a new dissection of the execution trace or provides a refutation - proof to serve as the next move of the [game]. *) -let generate_next_dissection ~default_number_of_sections node_ctxt ~opponent - game dissection = - let open Lwt_result_syntax in - let rec traverse ok = function - | [] -> - (* The game invariant states that the dissection from the - opponent must contain a tick we disagree with. If the - retrieved game does not respect this, we cannot trust the - Tezos node we are connected to and prefer to stop here. *) - tzfail - Sc_rollup_node_errors - .Unreliable_tezos_node_returning_inconsistent_game - | Sc_rollup.Dissection_chunk.{state_hash = their_hash; tick} :: dissection - -> ( - let start_state = - match ok with - | Hash _, _ -> None - | Evaluated ok_state, _ -> Some ok_state - in - let* our = - Interpreter.state_of_tick - node_ctxt - ?start_state - ~tick:(Sc_rollup.Tick.to_z tick) - game.inbox_level - in - match (their_hash, our) with - | None, None -> - (* This case is absurd since: [None] can only occur at the - end and the two players disagree about the end. *) - assert false - | Some _, None | None, Some _ -> return (ok, (our, tick)) - | Some their_hash, Some ({state_hash = our_hash; _} as our_state) -> - if Sc_rollup.State_hash.equal our_hash their_hash then - traverse (Evaluated our_state, tick) dissection - else return (ok, (our, tick))) - in - match dissection with - | Sc_rollup.Dissection_chunk.{state_hash = Some hash; tick} :: dissection -> - let* ok, ko = traverse (Hash hash, tick) dissection in - let* dissection = - new_dissection - ~opponent - ~default_number_of_sections - node_ctxt - game.inbox_level - ok - ko - in - let _, choice = ok in - let _, ko_tick = ko in - let chosen_section_len = Sc_rollup.Tick.distance ko_tick choice in - return (choice, chosen_section_len, dissection) - | [] | {state_hash = None; _} :: _ -> - (* - By wellformedness of dissection. - A dissection always starts with a tick of the form [(Some hash, tick)]. - A dissection always contains strictly more than one element. - *) - tzfail - Sc_rollup_node_errors.Unreliable_tezos_node_returning_inconsistent_game - -let next_move node_ctxt ~opponent game = - let open Lwt_result_syntax in - let final_move start_tick = - let* start_state = - Interpreter.state_of_tick - node_ctxt - ~tick:(Sc_rollup.Tick.to_z start_tick) - game.inbox_level - in - match start_state with - | None -> - tzfail - Sc_rollup_node_errors - .Unreliable_tezos_node_returning_inconsistent_game - | Some {state = start_state; _} -> - let* proof = generate_proof node_ctxt game start_state in - let choice = start_tick in - return (Move {choice; step = Proof proof}) - in - - match game.game_state with - | Dissecting {dissection; default_number_of_sections} -> - let* choice, chosen_section_len, dissection = - generate_next_dissection - ~default_number_of_sections - node_ctxt - ~opponent - game - dissection - in - if Z.(equal chosen_section_len one) then final_move choice - else return (Move {choice; step = Dissection dissection}) - | Final_move {agreed_start_chunk; refuted_stop_chunk = _} -> - let choice = agreed_start_chunk.tick in - final_move choice - -let play_next_move node_ctxt game self opponent = - let open Lwt_result_syntax in - let* refutation = next_move node_ctxt ~opponent game in - inject_next_move node_ctxt self ~refutation ~opponent - -let play_timeout (node_ctxt : _ Node_context.t) self stakers = - let open Lwt_result_syntax in - let timeout_operation = - L1_operation.Timeout - { - rollup = node_ctxt.rollup_address; - stakers = Sc_rollup_proto_types.Game.index_to_octez stakers; - } - in - let source = - Node_context.get_operator node_ctxt Timeout |> Option.value ~default:self - (* We fallback on the [Refute] operator if none is provided for [Timeout] *) - in - let* _hash = Injector.add_pending_operation ~source timeout_operation in - return_unit - -let timeout_reached ~self head_block node_ctxt staker1 staker2 = +let timeout_reached node_ctxt ~self ~opponent = let open Lwt_result_syntax in let Node_context.{rollup_address; cctxt; _} = node_ctxt in - let* game_result = + let+ game_result = Plugin.RPC.Sc_rollup.timeout_reached (new Protocol_client_context.wrap_full cctxt) - (cctxt#chain, head_block) + (cctxt#chain, `Head 0) rollup_address - staker1 - staker2 + self + opponent in let open Sc_rollup.Game in match game_result with | Some (Loser {loser; _}) -> let is_it_me = Signature.Public_key_hash.(self = loser) in - if is_it_me then return_none else return (Some loser) - | _ -> return_none + not is_it_me + | _ -> false -let play node_ctxt ~self game opponent = +let get_conflicts cctxt rollup staker = let open Lwt_result_syntax in - let index = Sc_rollup.Game.Index.make self opponent in - let head_block = `Head 0 in - match turn ~self game index with - | Our_turn {opponent} -> play_next_move node_ctxt game self opponent - | Their_turn -> ( - let* timeout_reached = - timeout_reached ~self head_block node_ctxt self opponent - in - match timeout_reached with - | Some opponent -> - let*! () = Refutation_game_event.timeout_detected opponent in - play_timeout node_ctxt self index - | None -> return_unit) - -let play_opening_move node_ctxt self conflict = - let open Lwt_syntax in - let open Sc_rollup.Refutation_storage in - let* () = Refutation_game_event.conflict_detected conflict in - let player_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.our_commitment + let cctxt = new Protocol_client_context.wrap_full cctxt in + let+ conflicts = + Plugin.RPC.Sc_rollup.conflicts cctxt (cctxt#chain, `Head 0) rollup staker in - let opponent_commitment_hash = - Sc_rollup.Commitment.hash_uncarbonated conflict.their_commitment + List.map Sc_rollup_proto_types.Game.conflict_to_octez conflicts + +let get_ongoing_games cctxt rollup staker = + let open Lwt_result_syntax in + let cctxt = new Protocol_client_context.wrap_full cctxt in + let+ games = + Plugin.RPC.Sc_rollup.ongoing_refutation_games + cctxt + (cctxt#chain, `Head 0) + rollup + staker in - let refutation = Start {player_commitment_hash; opponent_commitment_hash} in - inject_next_move node_ctxt self ~refutation ~opponent:conflict.other + List.map + (fun (game, staker1, staker2) -> + (Sc_rollup_proto_types.Game.to_octez game, staker1, staker2)) + games diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.mli b/src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.mli new file mode 100644 index 0000000000000000000000000000000000000000..8799f5deb3aa72166227ae37c12c9d2cc5226b42 --- /dev/null +++ b/src/proto_alpha/lib_sc_rollup_node/refutation_game_helpers.mli @@ -0,0 +1,81 @@ +(*****************************************************************************) +(* *) +(* Open Source License *) +(* Copyright (c) 2023 Nomadic Labs, *) +(* Copyright (c) 2023 TriliTech *) +(* Copyright (c) 2023 Functori, *) +(* *) +(* 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. *) +(* *) +(*****************************************************************************) + +(** [generate_proof node_ctxt (game) start_state] generates a serialized proof + for the current [game] for the execution step starting with + [start_state]. *) +val generate_proof : + Node_context.rw -> Game.t -> Context.tree -> string tzresult Lwt.t + +(** [state_of_tick node_ctxt ?start_state ~tick level] returns [Some + (state, hash)] for a given [tick] if this [tick] happened before + [level]. Otherwise, returns [None]. If provided, the evaluation is resumed + from [start_state]. *) +val state_of_tick : + _ Node_context.t -> + ?start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state -> + tick:Z.t -> + int32 -> + Fuel.Accounted.t Pvm_plugin_sig.eval_state option tzresult Lwt.t + +(** [make_dissection node_ctxt ~start_state ~start_chunk ~our_stop_chunk + ~default_number_of_sections ~last_level] computes a dissection from between + [start_chunk] and [our_stop_chunk] at level [last_level]. This dissection + has [default_number_of_sections] if there are enough ticks. *) +val make_dissection : + _ Node_context.t -> + start_state:Fuel.Accounted.t Pvm_plugin_sig.eval_state option -> + start_chunk:Game.dissection_chunk -> + our_stop_chunk:Game.dissection_chunk -> + default_number_of_sections:int -> + last_level:int32 -> + Game.dissection_chunk trace tzresult Lwt.t + +(** [timeout_reached node_ctxt ~self ~opponent] returns [true] if the + timeout is reached against opponent in head of the L1 chain. *) +val timeout_reached : + _ Node_context.t -> + self:Signature.public_key_hash -> + opponent:Signature.public_key_hash -> + bool tzresult Lwt.t + +(** [get_conflicts cctxt rollup signer] returns the conflicts for commitments + staked on by [signer]. *) +val get_conflicts : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + Game.conflict list tzresult Lwt.t + +(** [get_ongoing_games cctxt rollup signer] returns the games that [signer] is + currently playing. *) +val get_ongoing_games : + Client_context.full -> + Address.t -> + Signature.public_key_hash -> + (Game.t * Signature.public_key_hash * Signature.public_key_hash) list tzresult + Lwt.t diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_player.mli b/src/proto_alpha/lib_sc_rollup_node/refutation_player.mli deleted file mode 100644 index 92592e7c7cc5f17f7aa70b9be69eb6319bd31c1b..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_player.mli +++ /dev/null @@ -1,59 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -(** Worker module for a single refutation game player. The node's refutation - coordinator will spawn a new refutation player for each refutation game. -*) -module Worker : Worker.T - -(** Type for a refutation game player. *) -type worker = Worker.infinite Worker.queue Worker.t - -(** [init_and_play node_ctxt ~self ~conflict ~game ~level] initializes a new - refutation game player for signer [self]. After initizialization, the - worker will play the next move depending on the [game] state. If no [game] - is passed, the worker will play the opening move for [conflict]. *) -val init_and_play : - Node_context.rw -> - self:public_key_hash -> - conflict:Sc_rollup.Refutation_storage.conflict -> - game:Sc_rollup.Game.t option -> - level:int32 -> - unit tzresult Lwt.t - -(** [play worker game ~level] makes the [worker] play the next move depending - on the [game] state for their conflict. - *) -val play : worker -> Sc_rollup.Game.t -> level:int32 -> unit Lwt.t - -(** Shutdown a refutaiton game player. *) -val shutdown : worker -> unit Lwt.t - -(** [current_games ()] lists the opponents' this node is playing refutation - games against, alongside the worker that takes care of each game. *) -val current_games : unit -> (public_key_hash * worker) list diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_player_types.ml b/src/proto_alpha/lib_sc_rollup_node/refutation_player_types.ml deleted file mode 100644 index 5cb43af305096ca46dc4584d791b021229c4d0d2..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_player_types.ml +++ /dev/null @@ -1,73 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -module Request = struct - type ('a, 'b) t = - | Play : Sc_rollup.Game.t -> (unit, error trace) t - | Play_opening : - Sc_rollup.Refutation_storage.conflict - -> (unit, error trace) t - - type view = View : _ t -> view - - let view req = View req - - let encoding = - let open Data_encoding in - union - [ - case - (Tag 0) - ~title:"Play" - (obj2 - (req "request" (constant "play")) - (req "game" Sc_rollup.Game.encoding)) - (function View (Play g) -> Some ((), g) | _ -> None) - (fun ((), g) -> View (Play g)); - case - (Tag 1) - ~title:"Play opening" - (obj2 - (req "request" (constant "play_opening")) - (req "conflict" Sc_rollup.Refutation_storage.conflict_encoding)) - (function View (Play_opening c) -> Some ((), c) | _ -> None) - (fun ((), c) -> View (Play_opening c)); - ] - - let pp ppf (View r) = - match r with - | Play game -> Format.fprintf ppf "Playing game %a" Sc_rollup.Game.pp game - | Play_opening conflict -> - Format.fprintf - ppf - "Playing opening move for conflict against staker %a at our \ - commitment %a" - Sc_rollup.Staker.pp - conflict.other - Sc_rollup.Commitment.pp - conflict.our_commitment -end diff --git a/src/proto_alpha/lib_sc_rollup_node/refutation_player_types.mli b/src/proto_alpha/lib_sc_rollup_node/refutation_player_types.mli deleted file mode 100644 index d29fd8289f450cde25d7a3e5b4fa6bc7ca278e8b..0000000000000000000000000000000000000000 --- a/src/proto_alpha/lib_sc_rollup_node/refutation_player_types.mli +++ /dev/null @@ -1,45 +0,0 @@ -(*****************************************************************************) -(* *) -(* Open Source License *) -(* Copyright (c) 2023 Nomadic Labs, *) -(* *) -(* 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 Protocol -open Alpha_context - -module Request : sig - (** Type of requests accepted by the refutation player. *) - type ('a, 'b) t = - | Play : Sc_rollup.Game.t -> (unit, error trace) t - (** Play a step of an ongoing refutation game. *) - | Play_opening : - Sc_rollup.Refutation_storage.conflict - -> (unit, error trace) t - (** Play the opening move of a refutation game. *) - - type view = View : _ t -> view - - include - Worker_intf.REQUEST - with type ('a, 'request_error) t := ('a, 'request_error) t - and type view := view -end diff --git a/src/proto_alpha/lib_sc_rollup_node/rollup_node_plugin.ml b/src/proto_alpha/lib_sc_rollup_node/rollup_node_plugin.ml index d54d5b6674235872968376834fd8ab660cf6fbbf..4c5dd5e5cfe44af177cd455e62b8dd74819996ad 100644 --- a/src/proto_alpha/lib_sc_rollup_node/rollup_node_plugin.ml +++ b/src/proto_alpha/lib_sc_rollup_node/rollup_node_plugin.ml @@ -30,7 +30,7 @@ module Plugin : Protocol_plugin_sig.S = struct module Dal_slots_tracker = Dal_slots_tracker module Inbox = Inbox module Interpreter = Interpreter - module Refutation_coordinator = Refutation_coordinator + module Refutation_game_helpers = Refutation_game_helpers module Batcher_constants = Batcher_constants module Layer1_helpers = Layer1_helpers module L1_processing = Daemon_helpers