diff --git a/CHANGES.rst b/CHANGES.rst index ffa1124637994e6d116cc39b05f959d66430632a..a514658860b77927fec4679be110e14eed4056df 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -208,6 +208,9 @@ Smart Rollup node - Administrative RPCs to inspect injector queues and clear them. (MR :gl:`!12497`) +- Support for unsafely increasing the WASM PVM's tick limit of a rollup. + (MR :gl:`!12907`) + Smart Rollup WASM Debugger -------------------------- diff --git a/src/lib_scoru_wasm/wasm_pvm.ml b/src/lib_scoru_wasm/wasm_pvm.ml index 5323e7fc5b10a1699938a1b99dcf8533dd1aeeab..91eabb8f5fb6f1e283cc3f1e25d552607a3f734c 100644 --- a/src/lib_scoru_wasm/wasm_pvm.ml +++ b/src/lib_scoru_wasm/wasm_pvm.ml @@ -352,7 +352,22 @@ module Make_pvm (Wasm_vm : Wasm_vm_sig.S) (T : Tezos_tree_encoding.TREE) : let* pvm = Tree_encoding_runner.decode pvm_state_encoding tree in Wasm_vm.get_wasm_version pvm + module Unsafe = struct + let get_max_nb_ticks tree = + let open Lwt_syntax in + let+ pvm_state = Tree_encoding_runner.decode pvm_state_encoding tree in + pvm_state.max_nb_ticks + + let set_max_nb_ticks n tree = + let open Lwt_syntax in + let* pvm_state = Tree_encoding_runner.decode pvm_state_encoding tree in + let pvm_state = {pvm_state with max_nb_ticks = n} in + Tree_encoding_runner.encode pvm_state_encoding pvm_state tree + end + module Internal_for_tests = struct + include Unsafe + let get_tick_state tree = let open Lwt_syntax in let+ pvm_state = Tree_encoding_runner.decode pvm_state_encoding tree in @@ -373,12 +388,6 @@ module Make_pvm (Wasm_vm : Wasm_vm_sig.S) (T : Tezos_tree_encoding.TREE) : | Stuck error -> Lwt.return_some error | _ -> Lwt.return_none - let set_max_nb_ticks n tree = - let open Lwt_syntax in - let* pvm_state = Tree_encoding_runner.decode pvm_state_encoding tree in - let pvm_state = {pvm_state with max_nb_ticks = n} in - Tree_encoding_runner.encode pvm_state_encoding pvm_state tree - let set_maximum_reboots_per_input n tree = let open Lwt_syntax in let* pvm_state = Tree_encoding_runner.decode pvm_state_encoding tree in diff --git a/src/lib_scoru_wasm/wasm_pvm_sig.ml b/src/lib_scoru_wasm/wasm_pvm_sig.ml index 904d468a7758bcdc7cdc06c0ec0a3c7dd1c28888..225a49c7d721609de4413f3e418ca985a331e64c 100644 --- a/src/lib_scoru_wasm/wasm_pvm_sig.ml +++ b/src/lib_scoru_wasm/wasm_pvm_sig.ml @@ -25,6 +25,18 @@ (*****************************************************************************) open Wasm_pvm_state +module type Unsafe = sig + type tree + + (** Retrieve the maximum number of ticks for the PVM from the state. *) + val get_max_nb_ticks : tree -> Z.t Lwt.t + + (** Change the maximum number of ticks (per snapshot) of the WASM PVM. This is + to be used only for tests or to increase the tick limit in a non-refutable + setting. *) + val set_max_nb_ticks : Z.t -> tree -> tree Lwt.t +end + module type Internal_for_tests = sig open Internal_state @@ -37,8 +49,6 @@ module type Internal_for_tests = sig val is_stuck : tree -> Wasm_pvm_errors.t option Lwt.t - val set_max_nb_ticks : Z.t -> tree -> tree Lwt.t - val set_maximum_reboots_per_input : Z.t -> tree -> tree Lwt.t val decr_reboot_counter : tree -> tree Lwt.t @@ -60,6 +70,8 @@ module type Internal_for_tests = sig tree -> (tree * int64) Lwt.t + include Unsafe with type tree := tree + include Wasm_vm_sig.Internal_for_tests with type state := tree end @@ -90,6 +102,8 @@ module type S = sig function may raise an exception. *) val get_output : output_info -> tree -> string option Lwt.t + module Unsafe : Unsafe with type tree := tree + module Internal_for_tests : Internal_for_tests with type tree := tree end diff --git a/src/lib_smart_rollup_node/configuration.ml b/src/lib_smart_rollup_node/configuration.ml index 7afa3667f2d9a252e52b66eaab762c5c2d4b0aa2..552bb1a8caeb9cd10a42a957cbc0cd217fbaaa56 100644 --- a/src/lib_smart_rollup_node/configuration.ml +++ b/src/lib_smart_rollup_node/configuration.ml @@ -64,6 +64,7 @@ type t = { fee_parameters : fee_parameters; mode : mode; loser_mode : Loser_mode.t; + unsafe_pvm_patches : Pvm_patches.unsafe_patch list; dal_node_endpoint : Uri.t option; dac_observer_endpoint : Uri.t option; dac_timeout : Z.t option; @@ -436,6 +437,7 @@ let encoding default_display : t Data_encoding.t = fee_parameters; mode; loser_mode; + unsafe_pvm_patches; dal_node_endpoint; dac_observer_endpoint; dac_timeout; @@ -461,8 +463,12 @@ let encoding default_display : t Data_encoding.t = rpc_addr, rpc_port, acl ), - (metrics_addr, reconnection_delay, fee_parameters, mode, loser_mode) - ), + ( metrics_addr, + reconnection_delay, + fee_parameters, + mode, + loser_mode, + unsafe_pvm_patches ) ), ( ( dal_node_endpoint, dac_observer_endpoint, dac_timeout, @@ -487,8 +493,12 @@ let encoding default_display : t Data_encoding.t = rpc_addr, rpc_port, acl ), - (metrics_addr, reconnection_delay, fee_parameters, mode, loser_mode) - ), + ( metrics_addr, + reconnection_delay, + fee_parameters, + mode, + loser_mode, + unsafe_pvm_patches ) ), ( ( dal_node_endpoint, dac_observer_endpoint, dac_timeout, @@ -519,6 +529,7 @@ let encoding default_display : t Data_encoding.t = fee_parameters; mode; loser_mode; + unsafe_pvm_patches; dal_node_endpoint; dac_observer_endpoint; dac_timeout; @@ -559,7 +570,7 @@ let encoding default_display : t Data_encoding.t = ~description:"Access control list" Tezos_rpc_http_server.RPC_server.Acl.policy_encoding default_acl)) - (obj5 + (obj6 (opt "metrics-addr" ~description:"Metrics address" string) (dft "reconnection_delay" @@ -584,7 +595,14 @@ let encoding default_display : t Data_encoding.t = "If enabled, the rollup node will issue wrong commitments \ (for test only!)" Loser_mode.encoding - Loser_mode.no_failures))) + Loser_mode.no_failures) + (dft + "unsafe-pvm-patches" + ~description: + "Unsafe patches to apply to the PVM. For tests only, don't \ + set this value in production." + (list Pvm_patches.unsafe_patch_encoding) + []))) (merge_objs (obj9 (opt "DAL node endpoint" Tezos_rpc.Encoding.uri_encoding) @@ -753,6 +771,7 @@ module Cli = struct fee_parameters = Operation_kind.Map.empty; mode; loser_mode = Option.value ~default:Loser_mode.no_failures loser_mode; + unsafe_pvm_patches = []; batcher = default_batcher; injector = { diff --git a/src/lib_smart_rollup_node/configuration.mli b/src/lib_smart_rollup_node/configuration.mli index f9f146d5db46da732363bc384b0373faea07a882..fefcc0373276dad10a15c2395781c042cbcf92a0 100644 --- a/src/lib_smart_rollup_node/configuration.mli +++ b/src/lib_smart_rollup_node/configuration.mli @@ -93,6 +93,7 @@ type t = { fee_parameters : fee_parameters; mode : mode; loser_mode : Loser_mode.t; + unsafe_pvm_patches : Pvm_patches.unsafe_patch list; (*DAL/FIXME: https://gitlab.com/tezos/tezos/-/issues/3718 Decide whether we want to handle connections to multiple Dal nodes for different slot indexes. diff --git a/src/lib_smart_rollup_node/interpreter.ml b/src/lib_smart_rollup_node/interpreter.ml index 33765d2e2de63acf7baf7510d1d26d5c8978c1dd..4b199972aec3e68900e81154331c9cd97252f340 100644 --- a/src/lib_smart_rollup_node/interpreter.ml +++ b/src/lib_smart_rollup_node/interpreter.ml @@ -23,11 +23,11 @@ (* *) (*****************************************************************************) -let get_boot_sector (module Plugin : Protocol_plugin_sig.PARTIAL) block_hash - (node_ctxt : _ Node_context.t) = +let get_boot_sector (module Plugin : Protocol_plugin_sig.PARTIAL) + genesis_block_hash (node_ctxt : _ Node_context.t) = let open Lwt_result_syntax in match node_ctxt.config.boot_sector_file with - | None -> Plugin.Layer1_helpers.get_boot_sector block_hash node_ctxt + | None -> Plugin.Layer1_helpers.get_boot_sector genesis_block_hash node_ctxt | Some boot_sector_file -> let*! boot_sector = Lwt_utils_unix.read_file boot_sector_file in let*? boot_sector = @@ -40,16 +40,38 @@ let get_boot_sector (module Plugin : Protocol_plugin_sig.PARTIAL) block_hash in return boot_sector -let genesis_state (module Plugin : Protocol_plugin_sig.PARTIAL) block_hash - node_ctxt ctxt = +(** Apply potential unsafe patches to the PVM state. *) +let apply_unsafe_patches (module Plugin : Protocol_plugin_sig.PARTIAL) + (node_ctxt : _ Node_context.t) state = let open Lwt_result_syntax in - let* boot_sector = get_boot_sector (module Plugin) block_hash node_ctxt in + List.fold_left_es + (fun state patch -> + let*! () = Interpreter_event.patching_genesis_state patch in + Plugin.Pvm.Unsafe.apply_patch node_ctxt.kind state patch) + state + (node_ctxt.unsafe_patches :> Pvm_patches.unsafe_patch list) + +type original_genesis_state = Original of Context.pvmstate + +let genesis_state (module Plugin : Protocol_plugin_sig.PARTIAL) ?genesis_block + node_ctxt = + let open Lwt_result_syntax in + let* genesis_block_hash = + match genesis_block with + | Some b -> return b + | None -> Node_context.hash_of_level node_ctxt node_ctxt.genesis_info.level + in + let* boot_sector = + get_boot_sector (module Plugin) genesis_block_hash node_ctxt + in let*! initial_state = Plugin.Pvm.initial_state node_ctxt.kind in - let*! genesis_state = + let*! unpatched_genesis_state = Plugin.Pvm.install_boot_sector node_ctxt.kind initial_state boot_sector in - let*! ctxt = Context.PVMState.set ctxt genesis_state in - return (ctxt, genesis_state) + let* genesis_state = + apply_unsafe_patches (module Plugin) node_ctxt unpatched_genesis_state + in + return (genesis_state, Original unpatched_genesis_state) let state_of_head plugin node_ctxt ctxt Layer1.{hash; level} = let open Lwt_result_syntax in @@ -57,9 +79,11 @@ let state_of_head plugin node_ctxt ctxt Layer1.{hash; level} = match state with | None -> let genesis_level = node_ctxt.Node_context.genesis_info.level in - if level = genesis_level then genesis_state plugin hash node_ctxt ctxt + if level = genesis_level then + let+ state, _ = genesis_state plugin ~genesis_block:hash node_ctxt in + state else tzfail (Rollup_node_errors.Missing_PVM_state (hash, level)) - | Some state -> return (ctxt, state) + | Some state -> return state (** [transition_pvm plugin node_ctxt ctxt predecessor head] runs a PVM at the previous state from block [predecessor] by consuming as many messages as @@ -68,7 +92,7 @@ let transition_pvm (module Plugin : Protocol_plugin_sig.PARTIAL) node_ctxt ctxt predecessor Layer1.{hash = _; _} inbox_messages = let open Lwt_result_syntax in (* Retrieve the previous PVM state from store. *) - let* ctxt, predecessor_state = + let* predecessor_state = state_of_head (module Plugin) node_ctxt ctxt predecessor in let* eval_result = @@ -101,8 +125,8 @@ let process_head plugin (node_ctxt : _ Node_context.t) ctxt let first_inbox_level = node_ctxt.genesis_info.level |> Int32.succ in if head.level >= first_inbox_level then transition_pvm plugin node_ctxt ctxt predecessor head inbox_and_messages - else if head.Layer1.level = node_ctxt.genesis_info.level then - let* ctxt, state = genesis_state plugin head.hash node_ctxt ctxt in + else if head.level = node_ctxt.genesis_info.level then + let* state, _ = genesis_state plugin ~genesis_block:head.hash node_ctxt in let*! ctxt = Context.PVMState.set ctxt state in return (ctxt, 0, 0L, Z.zero) else return (ctxt, 0, 0L, Z.zero) @@ -116,7 +140,7 @@ let start_state_of_block plugin node_ctxt (block : Sc_rollup_block.t) = let* ctxt = Node_context.checkout_context node_ctxt block.header.predecessor in - let* _ctxt, state = + let* state = state_of_head plugin node_ctxt diff --git a/src/lib_smart_rollup_node/interpreter.mli b/src/lib_smart_rollup_node/interpreter.mli index 0d9cbbd9889eb265f42e0a9dac770095302f326c..e18c5576393e8db201febce9c85b9f478f540430 100644 --- a/src/lib_smart_rollup_node/interpreter.mli +++ b/src/lib_smart_rollup_node/interpreter.mli @@ -40,10 +40,24 @@ val process_head : Octez_smart_rollup.Inbox.t * string list -> ('a Context.t * int * int64 * Z.t) tzresult Lwt.t +type original_genesis_state = Original of Context.pvmstate + +(** [genesis_state plugin ?genesis_block node_ctxt] returns a pair [s1, s2] + where [s1] is the PVM state at the genesis block and [s2] is the genesis + state without any patches applied. [s2] is meant to be used to compute the + genesis commitment. If there are no unsafe patches for the rollup [s2] is + the same as [s1]. *) +val genesis_state : + (module Protocol_plugin_sig.PARTIAL) -> + ?genesis_block:Block_hash.t -> + _ Node_context.t -> + (Context.pvmstate * original_genesis_state) tzresult Lwt.t + (** [state_of_tick plugin 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]. *) + state] for a given [tick] if this [tick] happened before [level] and where + [state] is the PVM evaluation state before [tick] happened. Otherwise, + returns [None]. If provided, the evaluation is resumed from + [start_state]. *) val state_of_tick : (module Protocol_plugin_sig.PARTIAL) -> Node_context.rw -> @@ -60,4 +74,4 @@ val state_of_head : 'a Node_context.t -> 'a Context.t -> Layer1.head -> - ('a Context.t * Context.pvmstate) tzresult Lwt.t + Context.pvmstate tzresult Lwt.t diff --git a/src/lib_smart_rollup_node/interpreter_event.ml b/src/lib_smart_rollup_node/interpreter_event.ml index 96ed2611c2eef6ea58a8a686e4e8347079c481cd..4a3122a33dd02414feba939bec315deeacdfb416 100644 --- a/src/lib_smart_rollup_node/interpreter_event.ml +++ b/src/lib_smart_rollup_node/interpreter_event.ml @@ -76,6 +76,15 @@ module Simple = struct ("content_hash", Data_encoding.string) ~pp1:Format.pp_print_string ~pp2:Format.pp_print_string + + let patching_genesis_state = + declare_1 + ~section + ~name:"smart_rollup_node_interpreter_patching_genesis_pvm_state" + ~msg:"Patching genesis PVM state: {patch}" + ~level:Warning + ("patch", Pvm_patches.unsafe_patch_encoding) + ~pp1:Pvm_patches.pp_unsafe_patch end (** [transition_pvm inbox_level hash tick n] emits the event that a PVM @@ -98,3 +107,5 @@ let missing_pre_image ~hash = Simple.(emit missing_pre_image) hash let fetched_incorrect_pre_image ~expected_hash ~content_hash = Simple.(emit fetched_incorrect_pre_image) (expected_hash, content_hash) + +let patching_genesis_state patch = Simple.(emit patching_genesis_state) patch diff --git a/src/lib_smart_rollup_node/node_context.ml b/src/lib_smart_rollup_node/node_context.ml index 35a3a74bc2093f832b74a6421a9cbd07d210e3df..c6f36a2ac2e3ff007ea71cc417bfee37b30005fd 100644 --- a/src/lib_smart_rollup_node/node_context.ml +++ b/src/lib_smart_rollup_node/node_context.ml @@ -106,6 +106,7 @@ type 'a t = { injector_retention_period : int; block_finality_time : int; kind : Kind.t; + unsafe_patches : Pvm_patches.t; lockfile : Lwt_unix.file_descr; store : 'a store; context : 'a Context.t; diff --git a/src/lib_smart_rollup_node/node_context.mli b/src/lib_smart_rollup_node/node_context.mli index 7d246ee8577e6b2a890aed80fce15a944185aa2b..f28826f182d84e20f2b81ceabc1c2900fcfa3b56 100644 --- a/src/lib_smart_rollup_node/node_context.mli +++ b/src/lib_smart_rollup_node/node_context.mli @@ -112,6 +112,7 @@ type 'a t = { block_finality_time : int; (** Deterministic block finality time for the layer 1 protocol. *) kind : Kind.t; (** Kind of the smart rollup. *) + unsafe_patches : Pvm_patches.t; (** Patches to apply to the PVM. *) lockfile : Lwt_unix.file_descr; (** A lock file acquired when the node starts. *) store : 'a store; (** The store for the persistent storage. *) diff --git a/src/lib_smart_rollup_node/node_context_loader.ml b/src/lib_smart_rollup_node/node_context_loader.ml index 856ebd23616ade2801c00c0a79e83f470ed3d18b..0a8d579d56036051747f1641595cf15e3b92acce 100644 --- a/src/lib_smart_rollup_node/node_context_loader.ml +++ b/src/lib_smart_rollup_node/node_context_loader.ml @@ -171,6 +171,9 @@ let init (cctxt : #Client_context.full) ~data_dir ~irmin_cache_size }) last_whitelist_update in + let*? unsafe_patches = + Pvm_patches.make kind rollup_address configuration.unsafe_pvm_patches + in let sync = create_sync_info () in let node_ctxt = { @@ -185,6 +188,7 @@ let init (cctxt : #Client_context.full) ~data_dir ~irmin_cache_size lpc = Reference.new_ lpc; private_info = Reference.new_ private_info; kind; + unsafe_patches; injector_retention_period = 0; block_finality_time = 2; lockfile; @@ -254,6 +258,7 @@ module For_snapshots = struct fee_parameters = Configuration.default_fee_parameters; mode; loser_mode; + unsafe_pvm_patches = []; dal_node_endpoint = None; dac_observer_endpoint = None; dac_timeout = None; @@ -297,6 +302,10 @@ module For_snapshots = struct in let global_block_watcher = Lwt_watcher.create_input () in let sync = create_sync_info () in + let*? unsafe_patches = + (* Only consider hardcoded patches for snapshot validation. *) + Pvm_patches.make metadata.kind metadata.rollup_address [] + in return { config; @@ -310,6 +319,7 @@ module For_snapshots = struct lpc = Reference.new_ lpc; private_info = Reference.new_ None; kind = metadata.kind; + unsafe_patches; injector_retention_period = 0; block_finality_time = 2; lockfile; @@ -354,6 +364,7 @@ module Internal_for_tests = struct fee_parameters = Configuration.default_fee_parameters; mode; loser_mode; + unsafe_pvm_patches = []; dal_node_endpoint = None; dac_observer_endpoint = None; dac_timeout = None; @@ -411,6 +422,7 @@ module Internal_for_tests = struct in let global_block_watcher = Lwt_watcher.create_input () in let sync = create_sync_info () in + let*? unsafe_patches = Pvm_patches.make kind rollup_address [] in return { config; @@ -424,6 +436,7 @@ module Internal_for_tests = struct lpc; private_info = Reference.new_ None; kind; + unsafe_patches; injector_retention_period = 0; block_finality_time = 2; current_protocol; diff --git a/src/lib_smart_rollup_node/publisher.ml b/src/lib_smart_rollup_node/publisher.ml index 98d96797fb05bcf9d1c0174cd94c1c3815538dd0..95f9874120998b77590c13c5e3e7b28c87a3b5ab 100644 --- a/src/lib_smart_rollup_node/publisher.ml +++ b/src/lib_smart_rollup_node/publisher.ml @@ -128,15 +128,28 @@ let build_commitment (module Plugin : Protocol_plugin_sig.S) compressed_state; } +let genesis_pvm_state (module Plugin : Protocol_plugin_sig.S) + (node_ctxt : _ Node_context.t) ctxt = + let open Lwt_result_syntax in + match (node_ctxt.unsafe_patches :> Pvm_patches.unsafe_patch list) with + | [] -> ( + let*! pvm_state = Context.PVMState.find ctxt in + match pvm_state with + | Some pvm_state -> return pvm_state + | None -> failwith "PVM state for genesis commitment is not available") + | _ -> + (* If there are unsafe patches that were applied to the genesis PVM state, + we instead recompute the unpatched version to derive the commitment as + all the following ones will need to be chained to it. *) + let+ _, Original state = + Interpreter.genesis_state (module Plugin) node_ctxt + in + state + let genesis_commitment (module Plugin : Protocol_plugin_sig.S) (node_ctxt : _ Node_context.t) ctxt = let open Lwt_result_syntax in - let*! pvm_state = Context.PVMState.find ctxt in - let*? pvm_state = - match pvm_state with - | Some pvm_state -> Ok pvm_state - | None -> error_with "PVM state for genesis commitment is not available" - in + let* pvm_state = genesis_pvm_state (module Plugin) node_ctxt ctxt in let*! compressed_state = Plugin.Pvm.state_hash node_ctxt.kind pvm_state in let commitment = Octez_smart_rollup.Commitment. diff --git a/src/lib_smart_rollup_node/pvm_patches.ml b/src/lib_smart_rollup_node/pvm_patches.ml new file mode 100644 index 0000000000000000000000000000000000000000..8b5f337b59c51c7fe00c4106ece864c205f6b8b6 --- /dev/null +++ b/src/lib_smart_rollup_node/pvm_patches.ml @@ -0,0 +1,60 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Functori *) +(* *) +(*****************************************************************************) + +type unsafe_patch = Increase_max_nb_ticks of int64 + +type t = unsafe_patch list + +let patch_kinds = function Increase_max_nb_ticks _ -> [Kind.Wasm_2_0_0] + +(* Patches for Etherlink PVM. *) +let etherlink_patches = [Increase_max_nb_ticks 50_000_000_000_000L] + +(* TODO: https://gitlab.com/tezos/tezos/-/issues/7148 + Add hardcoded etherlink addresses on various networks. *) +let etherlink_addresses = [] + +let hardcoded_patches_list = + List.map (fun addr -> (addr, etherlink_patches)) etherlink_addresses + +let unsafe_patch_encoding = + let open Data_encoding in + union + [ + case + (Tag 0) + ~title:"increase_max_nb_tick" + (obj1 (req "increase_max_nb_tick" int64)) + (function Increase_max_nb_ticks ticks -> Some ticks) + (fun ticks -> Increase_max_nb_ticks ticks); + ] + +let pp_unsafe_patch fmt = function + | Increase_max_nb_ticks nb -> + Format.fprintf fmt "Increase maximum number of ticks to %#Ld" nb + +let make kind rollup_address patches = + let open Result_syntax in + let hardcoded_patches = + List.assoc ~equal:Address.equal rollup_address hardcoded_patches_list + |> Option.value ~default:[] + in + let patches = hardcoded_patches @ patches in + let+ () = + List.iter_e + (fun patch -> + if not @@ List.mem ~equal:Kind.equal kind (patch_kinds patch) then + error_with + "Patch \"%a\" is not supported for rollup kind %a" + pp_unsafe_patch + patch + Kind.pp + kind + else Ok ()) + patches + in + patches diff --git a/src/lib_smart_rollup_node/pvm_patches.mli b/src/lib_smart_rollup_node/pvm_patches.mli new file mode 100644 index 0000000000000000000000000000000000000000..149289620449cb1086abe73ead3e17bfa315c823 --- /dev/null +++ b/src/lib_smart_rollup_node/pvm_patches.mli @@ -0,0 +1,24 @@ +(*****************************************************************************) +(* *) +(* SPDX-License-Identifier: MIT *) +(* Copyright (c) 2024 Functori *) +(* *) +(*****************************************************************************) + +(** The type of individual unsafe patch content. *) +type unsafe_patch = + | Increase_max_nb_ticks of int64 + (** Increase the maximum number of ticks. *) + +(** The type of registered patches for the PVM. *) +type t = private unsafe_patch list + +(** Encoding for unsafe patches. *) +val unsafe_patch_encoding : unsafe_patch Data_encoding.t + +(** Pretty printer for unsafe patches. *) +val pp_unsafe_patch : Format.formatter -> unsafe_patch -> unit + +(** [make kind address patches] builds the patches from the provided list + [patches] and adds the hardcoded PVM patches for the rollup [address]. *) +val make : Kind.t -> Address.t -> unsafe_patch list -> t tzresult diff --git a/src/lib_smart_rollup_node/pvm_plugin_sig.ml b/src/lib_smart_rollup_node/pvm_plugin_sig.ml index 78f4483b9bb2a7ea8d1458d94b94c096667a2ee2..e8cded9531265ce86f1865d4bb90b5785604a666 100644 --- a/src/lib_smart_rollup_node/pvm_plugin_sig.ml +++ b/src/lib_smart_rollup_node/pvm_plugin_sig.ml @@ -117,6 +117,14 @@ module type S = sig val info_per_level_serialized : predecessor:Block_hash.t -> predecessor_timestamp:Time.Protocol.t -> string + module Unsafe : sig + val apply_patch : + Kind.t -> + Context.pvmstate -> + Pvm_patches.unsafe_patch -> + Context.pvmstate tzresult Lwt.t + end + module Wasm_2_0_0 : sig (** [decode_durable_state enc tree] decodes a value using the encoder [enc] from the provided [tree] *) diff --git a/src/lib_smart_rollup_node/simulation.ml b/src/lib_smart_rollup_node/simulation.ml index 11dff5f6899942c53c454877b363b4f5b06acb9d..b8f10187ca17638b0fc1d740fbfefbf526051315 100644 --- a/src/lib_smart_rollup_node/simulation.ml +++ b/src/lib_smart_rollup_node/simulation.ml @@ -89,7 +89,7 @@ let start_simulation node_ctxt ~reveal_map ?log_kernel_debug_file return (Context.empty node_ctxt.context) else Node_context.checkout_context node_ctxt hash in - let* ctxt, state = + let* state = Interpreter.state_of_head (module (val plugin)) node_ctxt ctxt head in let+ info_per_level = simulate_info_per_level node_ctxt hash in diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/arith_pvm.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/arith_pvm.ml index 276d555ce826397c7755db28ee3e4bea2e5a19b7..c52e0b04cdebab14c9c6ee71236f8d7699e0e886 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/arith_pvm.ml +++ b/src/proto_017_PtNairob/lib_sc_rollup_node/arith_pvm.ml @@ -57,6 +57,16 @@ module Impl : Pvm_sig.S = struct raise (Invalid_argument "No durable storage for arith PVM") end + module Unsafe_patches = struct + (** No unsafe patches for the arith PVM. *) + type t = | + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with Increase_max_nb_ticks _ -> assert false + + let apply _state (x : t) = match x with _ -> . + end + let new_dissection = Game_helpers.default_new_dissection let string_of_status status = diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/pvm_plugin.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/pvm_plugin.ml index 9a69a4f65f5e54ccef883ba142626dd0493aad90..a348532f4808c1af7bda08033ef93f2d2897a7a1 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/pvm_plugin.ml +++ b/src/proto_017_PtNairob/lib_sc_rollup_node/pvm_plugin.ml @@ -140,3 +140,16 @@ module Wasm_2_0_0 = struct ~init ~f:(fun a b c -> f a (to_node_pvmstate b) c) end + +module Unsafe = struct + let apply_patch (kind : Octez_smart_rollup.Kind.t) state + (patch : Pvm_patches.unsafe_patch) = + let open Lwt_result_syntax in + let open (val Pvm.of_kind kind) in + let*? patch = Unsafe_patches.of_patch patch in + let* state = + protect @@ fun () -> + Unsafe_patches.apply (of_node_pvmstate state) patch |> Lwt_result.ok + in + return (to_node_pvmstate state) +end diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/pvm_sig.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/pvm_sig.ml index 1d7f5e8c1685ce4b9b6f14b531c81b7493ed816a..3b0cc19d9e57c8fe73c77bafc266e27818067ae8 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/pvm_sig.ml +++ b/src/proto_017_PtNairob/lib_sc_rollup_node/pvm_sig.ml @@ -98,4 +98,17 @@ module type S = sig PVM state [state]. *) val lookup : state -> string list -> bytes option Lwt.t end + + (** Expose unsafe state patching functions for manual intervention. + At the moment this feature is only used to increase the maximum number of + ticks of the WASM PVM in a non refutable setting. *) + module Unsafe_patches : sig + type t + + (** [of_patch p] returns the PVM patch if it has a corresponding one. *) + val of_patch : Pvm_patches.unsafe_patch -> t tzresult + + (** [apply state patch] applies the unsafe patch [patch] on the state. *) + val apply : state -> t -> state Lwt.t + end end diff --git a/src/proto_017_PtNairob/lib_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_017_PtNairob/lib_sc_rollup_node/wasm_2_0_0_pvm.ml index 332381409f24d8318c6d75ee0a2cb77e50b38d13..914584b5bf9a4ef5baef6241d12443c61489448e 100644 --- a/src/proto_017_PtNairob/lib_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_017_PtNairob/lib_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -162,7 +162,9 @@ end module Durable_state = Make_durable_state (Make_wrapped_tree (Wasm_2_0_0_proof_format.Tree)) -module Impl : Pvm_sig.S = struct +type unsafe_patch = Increase_max_nb_ticks of int64 + +module Impl : Pvm_sig.S with type Unsafe_patches.t = unsafe_patch = struct module PVM = Sc_rollup.Wasm_2_0_0PVM.Make (Make_backend) (Wasm_2_0_0_proof_format) include PVM @@ -179,6 +181,29 @@ module Impl : Pvm_sig.S = struct Durable_state.lookup state key end + module Backend = Make_backend (Wasm_2_0_0_proof_format.Tree) + + module Unsafe_patches = struct + type t = unsafe_patch + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with + | Increase_max_nb_ticks max_nb_ticks -> + Ok (Increase_max_nb_ticks max_nb_ticks) + + let apply state (Increase_max_nb_ticks max_nb_ticks) = + let open Lwt_syntax in + let* registered_max_nb_ticks = Backend.Unsafe.get_max_nb_ticks state in + let max_nb_ticks = Z.of_int64 max_nb_ticks in + if Z.Compare.(max_nb_ticks < registered_max_nb_ticks) then + Format.ksprintf + invalid_arg + "Decreasing tick limit of WASM PVM from %s to %s is not allowed" + (Z.to_string registered_max_nb_ticks) + (Z.to_string max_nb_ticks) ; + Backend.Unsafe.set_max_nb_ticks max_nb_ticks state + end + let string_of_status : status -> string = function | Waiting_for_input_message -> "Waiting for input message" | Waiting_for_reveal (Sc_rollup.Reveal_raw_data hash) -> @@ -191,8 +216,6 @@ module Impl : Pvm_sig.S = struct Format.asprintf "Waiting for page data %a" Dal.Page.pp page_id | Computing -> "Computing" - module Backend = Make_backend (Wasm_2_0_0_proof_format.Tree) - let eval_many ~reveal_builtins ~write_debug = Backend.compute_step_many ~wasm_entrypoint:Tezos_scoru_wasm.Constants.wasm_entrypoint diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/arith_pvm.ml b/src/proto_018_Proxford/lib_sc_rollup_node/arith_pvm.ml index b03bcdf4aa448f5cc154e70a00b423bad04c86ed..3f19be4f9ff331f5c99c7dda0642b57269741ddb 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/arith_pvm.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_node/arith_pvm.ml @@ -57,6 +57,16 @@ module Impl : Pvm_sig.S = struct raise (Invalid_argument "No durable storage for arith PVM") end + module Unsafe_patches = struct + (** No unsafe patches for the arith PVM. *) + type t = | + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with Increase_max_nb_ticks _ -> assert false + + let apply _state (x : t) = match x with _ -> . + end + let new_dissection = Game_helpers.default_new_dissection let string_of_status = function diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/pvm_plugin.ml b/src/proto_018_Proxford/lib_sc_rollup_node/pvm_plugin.ml index f3e7d97b3334354ec79979a70e45e40e2cbd3984..af7dcb6d1e340d419c7f74dfb5fc5b419d981922 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/pvm_plugin.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_node/pvm_plugin.ml @@ -164,3 +164,16 @@ module Wasm_2_0_0 = struct ~init ~f:(fun a b c -> f a (to_node_pvmstate b) c) end + +module Unsafe = struct + let apply_patch (kind : Octez_smart_rollup.Kind.t) state + (patch : Pvm_patches.unsafe_patch) = + let open Lwt_result_syntax in + let open (val Pvm.of_kind kind) in + let*? patch = Unsafe_patches.of_patch patch in + let* state = + protect @@ fun () -> + Unsafe_patches.apply (of_node_pvmstate state) patch |> Lwt_result.ok + in + return (to_node_pvmstate state) +end diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/pvm_sig.ml b/src/proto_018_Proxford/lib_sc_rollup_node/pvm_sig.ml index 402093322a9c5a94b39f133f9b9882abfcaf663e..8adef28bf98878b8852615cd8cbd706c28a24853 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/pvm_sig.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_node/pvm_sig.ml @@ -100,4 +100,17 @@ module type S = sig PVM state [state]. *) val lookup : state -> string list -> bytes option Lwt.t end + + (** Expose unsafe state patching functions for manual intervention. + At the moment this feature is only used to increase the maximum number of + ticks of the WASM PVM in a non refutable setting. *) + module Unsafe_patches : sig + type t + + (** [of_patch p] returns the PVM patch if it has a corresponding one. *) + val of_patch : Pvm_patches.unsafe_patch -> t tzresult + + (** [apply state patch] applies the unsafe patch [patch] on the state. *) + val apply : state -> t -> state Lwt.t + end end diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/riscv_pvm.ml b/src/proto_018_Proxford/lib_sc_rollup_node/riscv_pvm.ml index ea93568f547d12bccea577d5727579f0a906dfde..a8d3682cc4c558164bab29c7ae4cde1ce5c8cd34 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/riscv_pvm.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_node/riscv_pvm.ml @@ -201,3 +201,13 @@ module Inspect_durable_state = struct let lookup _state _keys = raise (Invalid_argument "No durable storage for riscv PVM") end + +module Unsafe_patches = struct + (** No unsafe patches for the riscv PVM. *) + type t = | + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with Increase_max_nb_ticks _ -> assert false + + let apply _state (x : t) = match x with _ -> . +end diff --git a/src/proto_018_Proxford/lib_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_018_Proxford/lib_sc_rollup_node/wasm_2_0_0_pvm.ml index 37a19ee5787b4328a3763b805b2c597336948cc2..bd2225b2a7572fe0afe903e788660e723b68fb6c 100644 --- a/src/proto_018_Proxford/lib_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_018_Proxford/lib_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -130,7 +130,9 @@ end module Durable_state = Make_durable_state (Make_wrapped_tree (Wasm_2_0_0_proof_format.Tree)) -module Impl : Pvm_sig.S = struct +type unsafe_patch = Increase_max_nb_ticks of int64 + +module Impl : Pvm_sig.S with type Unsafe_patches.t = unsafe_patch = struct module PVM = Sc_rollup.Wasm_2_0_0PVM.Make (Make_backend) (Wasm_2_0_0_proof_format) include PVM @@ -147,6 +149,29 @@ module Impl : Pvm_sig.S = struct Durable_state.lookup state key end + module Backend = Make_backend (Wasm_2_0_0_proof_format.Tree) + + module Unsafe_patches = struct + type t = unsafe_patch + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with + | Increase_max_nb_ticks max_nb_ticks -> + Ok (Increase_max_nb_ticks max_nb_ticks) + + let apply state (Increase_max_nb_ticks max_nb_ticks) = + let open Lwt_syntax in + let* registered_max_nb_ticks = Backend.Unsafe.get_max_nb_ticks state in + let max_nb_ticks = Z.of_int64 max_nb_ticks in + if Z.Compare.(max_nb_ticks < registered_max_nb_ticks) then + Format.ksprintf + invalid_arg + "Decreasing tick limit of WASM PVM from %s to %s is not allowed" + (Z.to_string registered_max_nb_ticks) + (Z.to_string max_nb_ticks) ; + Backend.Unsafe.set_max_nb_ticks max_nb_ticks state + end + let string_of_status : status -> string = function | Waiting_for_input_message -> "Waiting for input message" | Waiting_for_reveal (Sc_rollup.Reveal_raw_data hash) -> @@ -161,8 +186,6 @@ module Impl : Pvm_sig.S = struct "Waiting for DAL parameters" | Computing -> "Computing" - module Backend = Make_backend (Wasm_2_0_0_proof_format.Tree) - let eval_many ~reveal_builtins ~write_debug ~is_reveal_enabled:_ = Backend.compute_step_many ~wasm_entrypoint:Tezos_scoru_wasm.Constants.wasm_entrypoint diff --git a/src/proto_019_PtParisB/lib_sc_rollup_node/arith_pvm.ml b/src/proto_019_PtParisB/lib_sc_rollup_node/arith_pvm.ml index db0ae2a698baeb58121b3f8ce6a811f64a7a193f..e18910690a4e16089981b2688decc8adacc02b03 100644 --- a/src/proto_019_PtParisB/lib_sc_rollup_node/arith_pvm.ml +++ b/src/proto_019_PtParisB/lib_sc_rollup_node/arith_pvm.ml @@ -63,6 +63,16 @@ module Impl : Pvm_sig.S = struct raise (Invalid_argument "No durable storage for arith PVM") end + module Unsafe_patches = struct + (** No unsafe patches for the arith PVM. *) + type t = | + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with Increase_max_nb_ticks _ -> assert false + + let apply _state (x : t) = match x with _ -> . + end + let new_dissection = Game_helpers.default_new_dissection let string_of_status = function diff --git a/src/proto_019_PtParisB/lib_sc_rollup_node/pvm_plugin.ml b/src/proto_019_PtParisB/lib_sc_rollup_node/pvm_plugin.ml index 9add3e39757ff9495f09ea98fa567495c110b2e5..8c403dae83ac182d840aedd651b3b54565a200ac 100644 --- a/src/proto_019_PtParisB/lib_sc_rollup_node/pvm_plugin.ml +++ b/src/proto_019_PtParisB/lib_sc_rollup_node/pvm_plugin.ml @@ -172,3 +172,17 @@ module Wasm_2_0_0 = struct ~init ~f:(fun a b c -> f a (to_node_pvmstate b) c) end + +module Unsafe = struct + let apply_patch (kind : Octez_smart_rollup.Kind.t) state + (patch : Pvm_patches.unsafe_patch) = + let open Lwt_result_syntax in + let open (val Pvm.of_kind kind) in + let*? patch = Unsafe_patches.of_patch patch in + let* state = + protect @@ fun () -> + Unsafe_patches.apply (Ctxt_wrapper.of_node_pvmstate state) patch + |> Lwt_result.ok + in + return (Ctxt_wrapper.to_node_pvmstate state) +end diff --git a/src/proto_019_PtParisB/lib_sc_rollup_node/pvm_sig.ml b/src/proto_019_PtParisB/lib_sc_rollup_node/pvm_sig.ml index dedeb1637dcbace0543ec7e73564c685b53d7a2a..7afc012df23ebd132f64eebafa54048e36ac3c6c 100644 --- a/src/proto_019_PtParisB/lib_sc_rollup_node/pvm_sig.ml +++ b/src/proto_019_PtParisB/lib_sc_rollup_node/pvm_sig.ml @@ -112,4 +112,17 @@ module type S = sig PVM state [state]. *) val lookup : state -> string list -> bytes option Lwt.t end + + (** Expose unsafe state patching functions for manual intervention. + At the moment this feature is only used to increase the maximum number of + ticks of the WASM PVM in a non refutable setting. *) + module Unsafe_patches : sig + type t + + (** [of_patch p] returns the PVM patch if it has a corresponding one. *) + val of_patch : Pvm_patches.unsafe_patch -> t tzresult + + (** [apply state patch] applies the unsafe patch [patch] on the state. *) + val apply : state -> t -> state Lwt.t + end end diff --git a/src/proto_019_PtParisB/lib_sc_rollup_node/riscv_pvm.ml b/src/proto_019_PtParisB/lib_sc_rollup_node/riscv_pvm.ml index e489ea2c2b38b9c7ba503e890c4011e697911635..5bdcea883a6a4f470293ddab48627b13728f5fea 100644 --- a/src/proto_019_PtParisB/lib_sc_rollup_node/riscv_pvm.ml +++ b/src/proto_019_PtParisB/lib_sc_rollup_node/riscv_pvm.ml @@ -207,3 +207,13 @@ module Inspect_durable_state = struct let lookup _state _keys = raise (Invalid_argument "No durable storage for riscv PVM") end + +module Unsafe_patches = struct + (** No unsafe patches for the riscv PVM. *) + type t = | + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with Increase_max_nb_ticks _ -> assert false + + let apply _state (x : t) = match x with _ -> . +end diff --git a/src/proto_019_PtParisB/lib_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_019_PtParisB/lib_sc_rollup_node/wasm_2_0_0_pvm.ml index 84c91db3619fa51c3a0bfe758e2d53ff892123ec..65c6787225092f7a8fc812fbad417ef6e7bd90b2 100644 --- a/src/proto_019_PtParisB/lib_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_019_PtParisB/lib_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -130,7 +130,9 @@ end module Durable_state = Make_durable_state (Make_wrapped_tree (Wasm_2_0_0_proof_format.Tree)) -module Impl : Pvm_sig.S = struct +type unsafe_patch = Increase_max_nb_ticks of int64 + +module Impl : Pvm_sig.S with type Unsafe_patches.t = unsafe_patch = struct module PVM = Sc_rollup.Wasm_2_0_0PVM.Make (Make_backend) (Wasm_2_0_0_proof_format) include PVM @@ -153,6 +155,29 @@ module Impl : Pvm_sig.S = struct Durable_state.lookup state key end + module Backend = Make_backend (Wasm_2_0_0_proof_format.Tree) + + module Unsafe_patches = struct + type t = unsafe_patch + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with + | Increase_max_nb_ticks max_nb_ticks -> + Ok (Increase_max_nb_ticks max_nb_ticks) + + let apply state (Increase_max_nb_ticks max_nb_ticks) = + let open Lwt_syntax in + let* registered_max_nb_ticks = Backend.Unsafe.get_max_nb_ticks state in + let max_nb_ticks = Z.of_int64 max_nb_ticks in + if Z.Compare.(max_nb_ticks < registered_max_nb_ticks) then + Format.ksprintf + invalid_arg + "Decreasing tick limit of WASM PVM from %s to %s is not allowed" + (Z.to_string registered_max_nb_ticks) + (Z.to_string max_nb_ticks) ; + Backend.Unsafe.set_max_nb_ticks max_nb_ticks state + end + let string_of_status : status -> string = function | Waiting_for_input_message -> "Waiting for input message" | Waiting_for_reveal (Sc_rollup.Reveal_raw_data hash) -> @@ -167,8 +192,6 @@ module Impl : Pvm_sig.S = struct "Waiting for DAL parameters" | Computing -> "Computing" - module Backend = Make_backend (Wasm_2_0_0_proof_format.Tree) - let eval_many ~reveal_builtins ~write_debug ~is_reveal_enabled:_ = Backend.compute_step_many ~wasm_entrypoint:Tezos_scoru_wasm.Constants.wasm_entrypoint diff --git a/src/proto_alpha/lib_sc_rollup_node/arith_pvm.ml b/src/proto_alpha/lib_sc_rollup_node/arith_pvm.ml index db0ae2a698baeb58121b3f8ce6a811f64a7a193f..e18910690a4e16089981b2688decc8adacc02b03 100644 --- a/src/proto_alpha/lib_sc_rollup_node/arith_pvm.ml +++ b/src/proto_alpha/lib_sc_rollup_node/arith_pvm.ml @@ -63,6 +63,16 @@ module Impl : Pvm_sig.S = struct raise (Invalid_argument "No durable storage for arith PVM") end + module Unsafe_patches = struct + (** No unsafe patches for the arith PVM. *) + type t = | + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with Increase_max_nb_ticks _ -> assert false + + let apply _state (x : t) = match x with _ -> . + end + let new_dissection = Game_helpers.default_new_dissection let string_of_status = function diff --git a/src/proto_alpha/lib_sc_rollup_node/pvm_plugin.ml b/src/proto_alpha/lib_sc_rollup_node/pvm_plugin.ml index 9add3e39757ff9495f09ea98fa567495c110b2e5..8c403dae83ac182d840aedd651b3b54565a200ac 100644 --- a/src/proto_alpha/lib_sc_rollup_node/pvm_plugin.ml +++ b/src/proto_alpha/lib_sc_rollup_node/pvm_plugin.ml @@ -172,3 +172,17 @@ module Wasm_2_0_0 = struct ~init ~f:(fun a b c -> f a (to_node_pvmstate b) c) end + +module Unsafe = struct + let apply_patch (kind : Octez_smart_rollup.Kind.t) state + (patch : Pvm_patches.unsafe_patch) = + let open Lwt_result_syntax in + let open (val Pvm.of_kind kind) in + let*? patch = Unsafe_patches.of_patch patch in + let* state = + protect @@ fun () -> + Unsafe_patches.apply (Ctxt_wrapper.of_node_pvmstate state) patch + |> Lwt_result.ok + in + return (Ctxt_wrapper.to_node_pvmstate state) +end diff --git a/src/proto_alpha/lib_sc_rollup_node/pvm_sig.ml b/src/proto_alpha/lib_sc_rollup_node/pvm_sig.ml index dedeb1637dcbace0543ec7e73564c685b53d7a2a..7afc012df23ebd132f64eebafa54048e36ac3c6c 100644 --- a/src/proto_alpha/lib_sc_rollup_node/pvm_sig.ml +++ b/src/proto_alpha/lib_sc_rollup_node/pvm_sig.ml @@ -112,4 +112,17 @@ module type S = sig PVM state [state]. *) val lookup : state -> string list -> bytes option Lwt.t end + + (** Expose unsafe state patching functions for manual intervention. + At the moment this feature is only used to increase the maximum number of + ticks of the WASM PVM in a non refutable setting. *) + module Unsafe_patches : sig + type t + + (** [of_patch p] returns the PVM patch if it has a corresponding one. *) + val of_patch : Pvm_patches.unsafe_patch -> t tzresult + + (** [apply state patch] applies the unsafe patch [patch] on the state. *) + val apply : state -> t -> state Lwt.t + end end diff --git a/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml b/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml index e489ea2c2b38b9c7ba503e890c4011e697911635..5bdcea883a6a4f470293ddab48627b13728f5fea 100644 --- a/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml +++ b/src/proto_alpha/lib_sc_rollup_node/riscv_pvm.ml @@ -207,3 +207,13 @@ module Inspect_durable_state = struct let lookup _state _keys = raise (Invalid_argument "No durable storage for riscv PVM") end + +module Unsafe_patches = struct + (** No unsafe patches for the riscv PVM. *) + type t = | + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with Increase_max_nb_ticks _ -> assert false + + let apply _state (x : t) = match x with _ -> . +end diff --git a/src/proto_alpha/lib_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_alpha/lib_sc_rollup_node/wasm_2_0_0_pvm.ml index 84c91db3619fa51c3a0bfe758e2d53ff892123ec..65c6787225092f7a8fc812fbad417ef6e7bd90b2 100644 --- a/src/proto_alpha/lib_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_alpha/lib_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -130,7 +130,9 @@ end module Durable_state = Make_durable_state (Make_wrapped_tree (Wasm_2_0_0_proof_format.Tree)) -module Impl : Pvm_sig.S = struct +type unsafe_patch = Increase_max_nb_ticks of int64 + +module Impl : Pvm_sig.S with type Unsafe_patches.t = unsafe_patch = struct module PVM = Sc_rollup.Wasm_2_0_0PVM.Make (Make_backend) (Wasm_2_0_0_proof_format) include PVM @@ -153,6 +155,29 @@ module Impl : Pvm_sig.S = struct Durable_state.lookup state key end + module Backend = Make_backend (Wasm_2_0_0_proof_format.Tree) + + module Unsafe_patches = struct + type t = unsafe_patch + + let of_patch (p : Pvm_patches.unsafe_patch) = + match p with + | Increase_max_nb_ticks max_nb_ticks -> + Ok (Increase_max_nb_ticks max_nb_ticks) + + let apply state (Increase_max_nb_ticks max_nb_ticks) = + let open Lwt_syntax in + let* registered_max_nb_ticks = Backend.Unsafe.get_max_nb_ticks state in + let max_nb_ticks = Z.of_int64 max_nb_ticks in + if Z.Compare.(max_nb_ticks < registered_max_nb_ticks) then + Format.ksprintf + invalid_arg + "Decreasing tick limit of WASM PVM from %s to %s is not allowed" + (Z.to_string registered_max_nb_ticks) + (Z.to_string max_nb_ticks) ; + Backend.Unsafe.set_max_nb_ticks max_nb_ticks state + end + let string_of_status : status -> string = function | Waiting_for_input_message -> "Waiting for input message" | Waiting_for_reveal (Sc_rollup.Reveal_raw_data hash) -> @@ -167,8 +192,6 @@ module Impl : Pvm_sig.S = struct "Waiting for DAL parameters" | Computing -> "Computing" - module Backend = Make_backend (Wasm_2_0_0_proof_format.Tree) - let eval_many ~reveal_builtins ~write_debug ~is_reveal_enabled:_ = Backend.compute_step_many ~wasm_entrypoint:Tezos_scoru_wasm.Constants.wasm_entrypoint diff --git a/tezt/tests/sc_rollup.ml b/tezt/tests/sc_rollup.ml index b973bdaa82f11265a4a22d0710359fa4173d7af1..7630b5bb610ab0e46fbff6c3f1c34d5f9c346b26 100644 --- a/tezt/tests/sc_rollup.ml +++ b/tezt/tests/sc_rollup.ml @@ -4681,6 +4681,62 @@ let test_arg_boot_sector_file ~kind = let* _ = Sc_rollup_node.wait_sync ~timeout:10. rollup_node in unit +let test_unsafe_genesis_patch ~kind = + let commitment_period = 3 in + let max_nb_tick = 50_000_000_000_000L in + let should_fail = match kind with "wasm_2_0_0" -> false | _ -> true in + test_full_scenario + ~kind + ~commitment_period + { + variant = None; + tags = ["node"; "unsafe_patch"]; + description = + sf + "Rollup can%s apply unsafe genesis PVM patches" + (if should_fail then "not" else ""); + } + @@ fun _protocol rollup_node rollup _node client -> + Log.info "Set patch in configuration" ; + let* _ = Sc_rollup_node.config_init rollup_node rollup in + Sc_rollup_node.Config_file.update rollup_node (fun config -> + let open JSON in + put + ( "unsafe-pvm-patches", + parse + ~origin:"increase-tick" + (sf {| [ { "increase_max_nb_tick" : "%Ld"} ] |} max_nb_tick) ) + config) ; + () ; + let* () = Sc_rollup_node.run ~wait_ready:false rollup_node rollup [] in + if should_fail then + Sc_rollup_node.check_error + ~exit_code:1 + ~msg:(rex "Patch .* is not supported") + rollup_node + else + let* () = bake_levels (commitment_period + 4) client in + let* _ = Sc_rollup_node.wait_sync ~timeout:10. rollup_node in + let* published_commitment = + Sc_rollup_node.RPC.call rollup_node + @@ Sc_rollup_rpc.get_local_last_published_commitment () + in + let* () = + check_published_commitment_in_l1 rollup client published_commitment + in + let* pvm_max_bytes = + Sc_rollup_node.RPC.call rollup_node ~rpc_hooks + @@ Sc_rollup_rpc.get_global_block_state ~key:"pvm/max_nb_ticks" () + in + let pvm_max = + pvm_max_bytes + |> Data_encoding.Binary.of_bytes_exn Data_encoding.n + |> Z.to_int64 + in + Check.((pvm_max = max_nb_tick) int64) + ~error_msg:"PVM max tick should have been increased to %R but is %L" ; + unit + let test_bootstrap_smart_rollup_originated = register_test ~supports:(From_protocol 018) @@ -5692,7 +5748,8 @@ let register ~kind ~protocols = test_consecutive_commitments protocols ~kind ; - test_outbox_message protocols ~kind + test_outbox_message protocols ~kind ; + test_unsafe_genesis_patch protocols ~kind let register ~protocols = (* PVM-independent tests. We still need to specify a PVM kind