diff --git a/src/lib_protocol_environment/environment_V8.ml b/src/lib_protocol_environment/environment_V8.ml index ab364121bfa6f8fc2594158db62328716c10e707..5057161c3ff44c484bcb8066843a73f8c1deeb2a 100644 --- a/src/lib_protocol_environment/environment_V8.ml +++ b/src/lib_protocol_environment/environment_V8.ml @@ -1080,7 +1080,7 @@ struct struct type Tezos_lazy_containers.Lazy_map.tree += PVM_tree of Tree.tree - module Wasm = Tezos_scoru_wasm.Wasm_pvm.Make (struct + include Tezos_scoru_wasm.Wasm_pvm.Make (struct include Tree let select = function @@ -1089,17 +1089,6 @@ struct let wrap t = PVM_tree t end) - - let compute_step (tree : Tree.tree) = Wasm.compute_step tree - - let set_input_step input payload (tree : Tree.tree) = - Wasm.set_input_step input payload tree - - let reveal_step = Wasm.reveal_step - - let get_output output (tree : Tree.tree) = Wasm.get_output output tree - - let get_info (tree : Tree.tree) = Wasm.get_info tree end end diff --git a/src/lib_scoru_wasm/gather_floppies.ml b/src/lib_scoru_wasm/gather_floppies.ml index 0b9ee82d69f02d6e5feb5bed976a4a77d3cab340..121f29ca74dfd75e2ee1ad930703bccd3a007777 100644 --- a/src/lib_scoru_wasm/gather_floppies.ml +++ b/src/lib_scoru_wasm/gather_floppies.ml @@ -334,21 +334,31 @@ module Make let* state = read_state tree in match state with | Broken {current_tick} -> - Tree_encoding_runner.encode broken_merklizer (Z.succ current_tick) tree - | Halted origination_message -> ( - match origination_kernel_loading_step origination_message with - | Some state -> Tree_encoding_runner.encode state_merklizer state tree - | None -> - (* We could not interpret [origination_message], - meaning the PVM is stuck. *) - Tree_encoding_runner.encode broken_merklizer Z.one tree) + let+ result = + Tree_encoding_runner.encode + broken_merklizer + (Z.succ current_tick) + tree + in + (result, 1L) + | Halted origination_message -> + let+ result = + match origination_kernel_loading_step origination_message with + | Some state -> Tree_encoding_runner.encode state_merklizer state tree + | None -> + (* We could not interpret [origination_message], + meaning the PVM is stuck. *) + Tree_encoding_runner.encode broken_merklizer Z.one tree + in + (result, 1L) | Running state -> ( let state = increment_ticks state in match state.internal_status with | Gathering_floppies _ -> raise Compute_step_expected_input | Not_gathering_floppies -> wasm_step tree) - let compute_step tree = compute_step_gen Wasm.compute_step tree + let compute_step tree = + Lwt.map fst @@ compute_step_gen (Wasm.compute_step_many ~max_steps:1L) tree (** [set_input_step input message tree] instruments [Wasm.set_input_step] to interpret incoming input messages as diff --git a/src/lib_scoru_wasm/test/helpers/wasm_utils.ml b/src/lib_scoru_wasm/test/helpers/wasm_utils.ml index 76d3cb634dfef9124d11c0bb16aea00b468115a0..24311ab5f13b5690313fbde853856644561d6e95 100644 --- a/src/lib_scoru_wasm/test/helpers/wasm_utils.ml +++ b/src/lib_scoru_wasm/test/helpers/wasm_utils.ml @@ -64,7 +64,7 @@ let initial_tree ?(max_tick = default_max_tick) let eval_until_stuck ?(max_steps = 20000L) tree = let open Lwt.Syntax in let rec go counter tree = - let* tree = Wasm.compute_step_many ~max_steps tree in + let* tree, _ = Wasm.compute_step_many ~max_steps tree in let* stuck = Wasm.Internal_for_tests.is_stuck tree in match stuck with | Some stuck -> Lwt_result.return (stuck, tree) @@ -79,7 +79,7 @@ let rec eval_until_input_requested ?(max_steps = Int64.max_int) tree = let* info = Wasm.get_info tree in match info.input_request with | No_input_required -> - let* tree = Wasm.compute_step_many ~max_steps tree in + let* tree, _ = Wasm.compute_step_many ~max_steps tree in eval_until_input_requested tree | Input_required -> return tree | Reveal_required _ -> return tree diff --git a/src/lib_scoru_wasm/test/test_hash_consistency.ml b/src/lib_scoru_wasm/test/test_hash_consistency.ml index 08caecff5e9e284ae3eb98e8a1d5f07fcd243c85..91a3574d53c65c40d7406329bf0a2b32e3ae75f5 100644 --- a/src/lib_scoru_wasm/test/test_hash_consistency.ml +++ b/src/lib_scoru_wasm/test/test_hash_consistency.ml @@ -44,10 +44,12 @@ let test_execution_correspondance skip count () = in let*! tree = if skip = 0L then Lwt.return tree_with_dummy_input - else Wasm.compute_step_many ~max_steps:skip tree_with_dummy_input + else + Lwt.map fst + @@ Wasm.compute_step_many ~max_steps:skip tree_with_dummy_input in let rec explore tree' n = - let*! tree_ref = Wasm.compute_step_many ~max_steps:n tree in + let*! tree_ref, _ = Wasm.compute_step_many ~max_steps:n tree in let*! tree' = Wasm.compute_step tree' in assert ( Context_hash.(Context.Tree.hash tree_ref = Context.Tree.hash tree')) ; diff --git a/src/lib_scoru_wasm/test/test_wasm_pvm.ml b/src/lib_scoru_wasm/test/test_wasm_pvm.ml index b6b433cdc178218b4b90265b55bdb89944ac4198..b5d556c9342231fffed46d79369f08f95c5d324d 100644 --- a/src/lib_scoru_wasm/test/test_wasm_pvm.ml +++ b/src/lib_scoru_wasm/test/test_wasm_pvm.ml @@ -429,7 +429,7 @@ let test_bulk_noops () = let* base_tree = set_input_step "dummy_input" 0 base_tree in let rec goto_snapshot ticks tree_slow = - let* tree_fast = Wasm.compute_step_many ~max_steps:ticks base_tree in + let* tree_fast, _ = Wasm.compute_step_many ~max_steps:ticks base_tree in let* tree_slow = Wasm.compute_step tree_slow in assert ( @@ -448,7 +448,7 @@ let test_bulk_noops () = assert (snapshot_info.input_request = Input_required) ; (* Try to advance past the snapshot point. *) - let* tree_fast = + let* tree_fast, _ = Wasm.compute_step_many ~max_steps:(Int64.mul ticks 2L) base_tree in diff --git a/src/lib_scoru_wasm/wasm_pvm.ml b/src/lib_scoru_wasm/wasm_pvm.ml index a82cd05cb08049a761f0633d8e572ab86d988607..7fd58d61fc60b88fcab41416fe859a4d43f579da 100644 --- a/src/lib_scoru_wasm/wasm_pvm.ml +++ b/src/lib_scoru_wasm/wasm_pvm.ml @@ -387,6 +387,9 @@ module Make (T : Tezos_tree_encoding.TREE) : | Restarting | Failing -> maximum_reboots_per_input | Starting | Running -> reboot_counter + (** [compute_step_inner pvm_state] does one computation step on [pvm_state]. + Returns the new state. + *) let compute_step_inner pvm_state = let open Lwt_syntax in (* Calculate the next tick state. *) @@ -424,6 +427,16 @@ module Make (T : Tezos_tree_encoding.TREE) : eval_has_finished pvm_state.tick_state && not (is_time_for_snapshot pvm_state) + let measure_executed_ticks (transition : pvm_state -> pvm_state Lwt.t) + (initial_state : pvm_state) : (pvm_state * int64) Lwt.t = + let open Lwt.Syntax in + let open Z in + let+ final_state = transition initial_state in + let ticks_executed = + final_state.current_tick - initial_state.current_tick + in + (final_state, to_int64 ticks_executed) + let decode tree = Tree_encoding_runner.decode pvm_state_encoding tree let encode pvm_state tree = @@ -446,8 +459,7 @@ module Make (T : Tezos_tree_encoding.TREE) : let* tree = T.remove tree ["wasm"] in Tree_encoding_runner.encode pvm_state_encoding pvm_state tree - let compute_step_many_until_pvm_state ?(max_steps = 1L) should_continue - pvm_state = + let compute_step_many_until_pvm_state ?(max_steps = 1L) should_continue = let open Lwt.Syntax in assert (max_steps > 0L) ; let rec go steps_left pvm_state = @@ -472,10 +484,13 @@ module Make (T : Tezos_tree_encoding.TREE) : go (Int64.pred steps_left) pvm_state else Lwt.return pvm_state in - (* Make sure we perform at least 1 step. The assertion above ensures that - we were asked to perform at least 1. *) - let* pvm_state = compute_step_inner pvm_state in - go (Int64.pred max_steps) pvm_state + let one_or_more_steps pvm_state = + (* Make sure we perform at least 1 step. The assertion above ensures that + we were asked to perform at least 1. *) + let* pvm_state = compute_step_inner pvm_state in + go (Int64.pred max_steps) pvm_state + in + measure_executed_ticks one_or_more_steps let compute_step_many_until ?(max_steps = 1L) should_continue tree = let open Lwt.Syntax in @@ -485,11 +500,12 @@ module Make (T : Tezos_tree_encoding.TREE) : (* Make sure we perform at least 1 step. The assertion above ensures that we were asked to perform at least 1. *) - let* pvm_state = + let* pvm_state, executed_ticks = compute_step_many_until_pvm_state ~max_steps should_continue pvm_state in - encode pvm_state tree + let* tree = encode pvm_state tree in + Lwt.return (tree, executed_ticks) let compute_step_many ~max_steps tree = let open Lwt_syntax in @@ -501,7 +517,11 @@ module Make (T : Tezos_tree_encoding.TREE) : in compute_step_many_until ~max_steps should_continue tree - let compute_step tree = compute_step_many ~max_steps:1L tree + let compute_step tree = + let open Lwt.Syntax in + let* initial_state = decode tree in + let* final_state = compute_step_inner initial_state in + encode final_state tree let get_output output_info tree = let open Lwt_syntax in diff --git a/src/lib_scoru_wasm/wasm_pvm_sig.ml b/src/lib_scoru_wasm/wasm_pvm_sig.ml index a29cc3bfafade1c2ceb33fa22528c59ecffd91a2..d1ca47fcd75ca221b7e9ab580353df7b78c6eb47 100644 --- a/src/lib_scoru_wasm/wasm_pvm_sig.ml +++ b/src/lib_scoru_wasm/wasm_pvm_sig.ml @@ -46,6 +46,8 @@ module type Internal_for_benchmark = sig advance forwards the VM in the same manners as [compute_step_many] as long as [should_continue] returns true. + Returns the new state and number of the executed ticks. + IS applied on [pvm_state] rather than a tree. /!\ as it allows to redefine the stop condition, this function should @@ -56,18 +58,23 @@ module type Internal_for_benchmark = sig ?max_steps:int64 -> (pvm_state -> bool Lwt.t) -> pvm_state -> - pvm_state Lwt.t + (pvm_state * int64) Lwt.t (** [compute_step_many_until max_step should_continue tree] advance forwards the VM in the same manners as [compute_step_many] as long as [should_continue] returns true. + + Returns the new tree and number of the executed ticks. /!\ as it allows to redefine the stop condition, this function should not be used in unit test: the test could hide regression if the condition change in the code, but not in the test. *) val compute_step_many_until : - ?max_steps:int64 -> (pvm_state -> bool Lwt.t) -> tree -> tree Lwt.t + ?max_steps:int64 -> + (pvm_state -> bool Lwt.t) -> + tree -> + (tree * int64) Lwt.t val eval_has_finished : tick_state -> bool end @@ -106,8 +113,9 @@ module type S = sig toplevel kernel call. If the VM is expecting input, it gets stuck. If the VM is already stuck, this function may raise an exception. It is more efficient than [compute_step] if it has to be called for more than one - tick, but its resulting tree will be stricly equivalent. *) - val compute_step_many : max_steps:int64 -> tree -> tree Lwt.t + tick, but its resulting tree will be stricly equivalent. + Returns a tuple containing the number of executed ticks and the new tree*) + val compute_step_many : max_steps:int64 -> tree -> (tree * int64) Lwt.t (** [compute_step tree] forwards the VM by one compute tick. If the VM is expecting input, it gets stuck. If the VM is already stuck, this function may raise diff --git a/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml b/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml index 190b4f3ba021c421203ffb870b8eac7623ebae9b..fb24246a759094d57307977f47584235f70bdad1 100644 --- a/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml +++ b/src/proto_alpha/bin_sc_rollup_node/arith_pvm.ml @@ -56,6 +56,23 @@ module Impl : Pvm.S = struct | Waiting_for_metadata -> "Waiting for metadata" | Parsing -> "Parsing" | Evaluating -> "Evaluating" + + let eval_many ~max_steps initial_state = + let rec go state step = + let open Lwt.Syntax in + let* is_input_required = is_input_state state in + + if is_input_required = No_input_required && step <= max_steps then + let open Lwt.Syntax in + (* Note: This is not an efficient implementation because the state is + decoded/encoded to/from the tree at each step but for Arith PVM + it doesn't matter + *) + let* next_state = eval state in + go next_state (Int64.succ step) + else Lwt.return (state, step) + in + go initial_state 0L end include Impl diff --git a/src/proto_alpha/bin_sc_rollup_node/interpreter.ml b/src/proto_alpha/bin_sc_rollup_node/interpreter.ml index ee247a94bea7503abe82bf971685192d09efc37b..49dc45354a8bd20f6f607ba384170477059a94a3 100644 --- a/src/proto_alpha/bin_sc_rollup_node/interpreter.ml +++ b/src/proto_alpha/bin_sc_rollup_node/interpreter.ml @@ -59,13 +59,14 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct let origination_level = node_ctxt.genesis_info.Sc_rollup.Commitment.level in Sc_rollup.Metadata.{address; origination_level} - let consume_fuel = Option.map pred + let consume_fuel consumption = + Option.map (fun fuel -> Int64.sub fuel consumption) - let continue_with_fuel fuel state f = + let continue_with_fuel consumption fuel state f = let open Lwt_result_syntax in match fuel with - | Some 0 -> return (state, fuel) - | _ -> f (consume_fuel fuel) state + | Some 0L -> return (state, fuel) + | _ -> f (consume_fuel consumption fuel) state (** [eval_until_input ~metadata level message_index ~fuel start_tick failing_ticks state] advances a PVM [state] until it wants more @@ -77,10 +78,13 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct let eval_until_input ~metadata data_dir level message_index ~fuel start_tick failing_ticks state = let open Lwt_result_syntax in - let eval_tick tick failing_ticks state = + let eval_tick fuel_left tick failing_ticks state = + let max_steps = + match fuel_left with None -> Int64.max_int | Some v -> Int64.max 0L v + in let normal_eval state = - let*! state = PVM.eval state in - return (state, failing_ticks) + let*! state, executed_ticks = PVM.eval_many ~max_steps state in + return (state, executed_ticks, failing_ticks) in let failure_insertion_eval state failing_ticks' = let*! () = @@ -91,24 +95,28 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct ~internal:true in let*! state = PVM.Internal_for_tests.insert_failure state in - return (state, failing_ticks') + return (state, 1L, failing_ticks') in match failing_ticks with | xtick :: failing_ticks' when xtick = tick -> failure_insertion_eval state failing_ticks' | _ -> normal_eval state in - let rec go fuel tick failing_ticks state = + let rec go fuel_left current_tick failing_ticks state = let*! input_request = PVM.is_input_state state in - match fuel with - | Some 0 -> return (state, fuel, tick, failing_ticks) + match fuel_left with + | Some 0L -> return (state, fuel_left, current_tick, failing_ticks) | None | Some _ -> ( match input_request with | No_input_required -> - let* next_state, failing_ticks = - eval_tick tick failing_ticks state + let* next_state, executed_ticks, failing_ticks = + eval_tick fuel_left current_tick failing_ticks state in - go (consume_fuel fuel) (tick + 1) failing_ticks next_state + go + (consume_fuel executed_ticks fuel_left) + (Int64.add current_tick executed_ticks) + failing_ticks + next_state | Needs_reveal (Reveal_raw_data hash) -> ( match Reveals.get ~data_dir ~pvm_name:PVM.name ~hash with | None -> @@ -117,13 +125,21 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct let*! next_state = PVM.set_input (Reveal (Raw_data data)) state in - go (consume_fuel fuel) (tick + 1) failing_ticks next_state) + go + (consume_fuel 1L fuel_left) + (Int64.succ current_tick) + failing_ticks + next_state) | Needs_reveal Reveal_metadata -> let*! next_state = PVM.set_input (Reveal (Metadata metadata)) state in - go (consume_fuel fuel) (tick + 1) failing_ticks next_state - | _ -> return (state, fuel, tick, failing_ticks)) + go + (consume_fuel 1L fuel_left) + (Int64.succ current_tick) + failing_ticks + next_state + | _ -> return (state, fuel_left, current_tick, failing_ticks)) in go fuel start_tick failing_ticks state @@ -148,11 +164,11 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct level message_index ~fuel - 0 + 0L failing_ticks state in - continue_with_fuel fuel state @@ fun fuel state -> + continue_with_fuel tick fuel state @@ fun fuel state -> let* input, failing_ticks = match failing_ticks with | xtick :: failing_ticks' -> @@ -216,6 +232,7 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct } in let level = Raw_level.to_int32 inbox_level |> Int32.to_int in + let failing_ticks = Loser_mode.is_failure loser_mode @@ -366,7 +383,7 @@ module Make (PVM : Pvm.S) : S with module PVM = PVM = struct if Raw_level.(event.level > level) then return None else let tick_distance = - Sc_rollup.Tick.distance tick event.tick |> Z.to_int + Sc_rollup.Tick.distance tick event.tick |> Z.to_int64 in (* TODO: #3384 We assume that [StateHistory] correctly stores enough diff --git a/src/proto_alpha/bin_sc_rollup_node/interpreter_event.ml b/src/proto_alpha/bin_sc_rollup_node/interpreter_event.ml index a6dfa4bfbb0cb7c10b5dc2fc76f0af53684366a8..a6e1d99fa6e29299d029788202f38a29beeca137 100644 --- a/src/proto_alpha/bin_sc_rollup_node/interpreter_event.ml +++ b/src/proto_alpha/bin_sc_rollup_node/interpreter_event.ml @@ -55,7 +55,7 @@ module Make (PVM : Pvm.S) = struct ~level:Notice ("level", Data_encoding.int31) ("message_index", Data_encoding.int31) - ("message_tick", Data_encoding.int31) + ("message_tick", Data_encoding.int64) ("internal", Data_encoding.bool) end diff --git a/src/proto_alpha/bin_sc_rollup_node/interpreter_event.mli b/src/proto_alpha/bin_sc_rollup_node/interpreter_event.mli index fc6634f76b05f9a441c0d750da7e35775657320b..bfff5931bf2d49b37820990d0eaeed55aaf7fa76 100644 --- a/src/proto_alpha/bin_sc_rollup_node/interpreter_event.mli +++ b/src/proto_alpha/bin_sc_rollup_node/interpreter_event.mli @@ -43,7 +43,7 @@ module Make (PVM : Pvm.S) : sig val intended_failure : level:int -> message_index:int -> - message_tick:int -> + message_tick:int64 -> internal:bool -> unit Lwt.t end diff --git a/src/proto_alpha/bin_sc_rollup_node/loser_mode.ml b/src/proto_alpha/bin_sc_rollup_node/loser_mode.ml index fd2dcc70ce0588bcd29229753aa0d53b2f35da79..2cfbecea7baf39019b5b75b894d47f1ac99a6de9 100644 --- a/src/proto_alpha/bin_sc_rollup_node/loser_mode.ml +++ b/src/proto_alpha/bin_sc_rollup_node/loser_mode.ml @@ -23,7 +23,7 @@ (* *) (*****************************************************************************) -type failure = {level : int; message_index : int; message_tick : int} +type failure = {level : int; message_index : int; message_tick : int64} let failure_encoding = let open Data_encoding in @@ -35,14 +35,14 @@ let failure_encoding = (obj3 (req "level" int31) (req "message_index" int31) - (req "message_tick" int31)) + (req "message_tick" int64)) let compare_failure {level; message_index; message_tick} f2 = let open Compare.Int in match compare level f2.level with | 0 -> ( match compare message_index f2.message_index with - | 0 -> compare message_tick f2.message_tick + | 0 -> Int64.compare message_tick f2.message_tick | n -> n) | n -> n @@ -60,7 +60,7 @@ let make s = { level = int_of_string level; message_index = int_of_string message_index; - message_tick = int_of_string message_tick; + message_tick = Int64.of_string message_tick; } :: chop rest | _ -> raise Not_found diff --git a/src/proto_alpha/bin_sc_rollup_node/loser_mode.mli b/src/proto_alpha/bin_sc_rollup_node/loser_mode.mli index d86a269ee844a2529a13b30e531a068fed52659d..24171007e6b099163328396399fd535818316f97 100644 --- a/src/proto_alpha/bin_sc_rollup_node/loser_mode.mli +++ b/src/proto_alpha/bin_sc_rollup_node/loser_mode.mli @@ -43,4 +43,4 @@ val make : string -> t option of the rollup node processing of a given inbox [level], a given [message_index] and for all [message_ticks]. Ticks are sorted by increasing order. *) -val is_failure : t -> level:int -> message_index:int -> int list +val is_failure : t -> level:int -> message_index:int -> int64 list diff --git a/src/proto_alpha/bin_sc_rollup_node/pvm.ml b/src/proto_alpha/bin_sc_rollup_node/pvm.ml index 0fa214ff08f5e743440804d56f81aeda1a8f675d..a73f7cd3488f440fba59c4005889162afda8973c 100644 --- a/src/proto_alpha/bin_sc_rollup_node/pvm.ml +++ b/src/proto_alpha/bin_sc_rollup_node/pvm.ml @@ -50,6 +50,10 @@ module type S = sig outbox of [state]. *) val get_outbox : state -> Sc_rollup.output list Lwt.t + (** [eval_many ~max_steps s0] returns a state [s1] resulting from the + execution of up to [~max_steps] steps of the rollup at state [s0]. *) + val eval_many : max_steps:int64 -> state -> (state * int64) Lwt.t + (** State storage for this PVM. *) module State : sig (** [find context] returns the PVM state stored in the [context], if any. *) diff --git a/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml index 16d6f0594a8af5b969a67183f3f78e7a995460c9..db78f4667fdfef9fa7676b9a5f483123b6ae7f3a 100644 --- a/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_alpha/bin_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -76,6 +76,10 @@ module Impl : Pvm.S = struct hash | Waiting_for_reveal Sc_rollup.Reveal_metadata -> "Waiting for metadata" | Computing -> "Computing" + + module Backend = Make_backend (Wasm_2_0_0_proof_format.Tree) + + let eval_many = Backend.compute_step_many end include Impl