From ec271f087e0f295fd261aaac96570bb46e96277c Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Fri, 24 Feb 2023 13:37:18 +0100 Subject: [PATCH] WASM: Refactor WASM PVM versioning Prior to this patch, the versioning of the WASM PVM was hard-coded in the `initial_tree` version. There is now several compliant use-case to introduce a newer version of the WASM PVM, with refactoring of the existing host functions, introduction of new host functions, and parameterization of the maximum call depth of the WASM interpreter. This patch is a first step towards introducing a new version to welcome these breaking changes. --- .../environment_V8.ml | 2 ++ .../environment_V9.ml | 5 ++++ .../environment_V9.mli | 1 + src/lib_protocol_environment/sigs/v9.ml | 6 +++- .../sigs/v9/wasm_2_0_0.mli | 6 +++- src/lib_scoru_wasm/constants.ml | 2 ++ src/lib_scoru_wasm/helpers/wasm_utils.ml | 2 +- src/lib_scoru_wasm/wasm_pvm.ml | 29 +++++++++++++------ src/lib_scoru_wasm/wasm_pvm_sig.ml | 2 +- src/lib_scoru_wasm/wasm_pvm_state.ml | 15 ++++++++++ src/lib_store/unix/test/test_consistency.ml | 2 +- src/lib_tree_encoding/decoding.ml | 27 ++++++++++++----- .../test/unit/test_sc_rollup_wasm.ml | 2 +- .../lib_sc_rollup_node/wasm_2_0_0_pvm.ml | 7 +++-- .../lib_protocol/sc_rollup_wasm.ml | 4 ++- .../lib_protocol/sc_rollup_wasm.mli | 2 ++ .../test/unit/test_sc_rollup_wasm.ml | 4 ++- 17 files changed, 92 insertions(+), 26 deletions(-) diff --git a/src/lib_protocol_environment/environment_V8.ml b/src/lib_protocol_environment/environment_V8.ml index 87cf7962e1dc..d99e65dc5a57 100644 --- a/src/lib_protocol_environment/environment_V8.ml +++ b/src/lib_protocol_environment/environment_V8.ml @@ -1137,6 +1137,8 @@ struct let wrap t = PVM_tree t end) + + let initial_state = initial_state V0 end end diff --git a/src/lib_protocol_environment/environment_V9.ml b/src/lib_protocol_environment/environment_V9.ml index 78bc7a788f00..a4af1d588798 100644 --- a/src/lib_protocol_environment/environment_V9.ml +++ b/src/lib_protocol_environment/environment_V9.ml @@ -114,6 +114,7 @@ module type T = sig and type Dal.page_proof = Tezos_crypto_dal.Cryptobox.Verifier.page_proof and type Bounded.Non_negative_int32.t = Tezos_base.Bounded.Non_negative_int32.t + and type Wasm_2_0_0.version = Tezos_scoru_wasm.Wasm_pvm_state.version and type Wasm_2_0_0.input = Tezos_scoru_wasm.Wasm_pvm_state.input_info and type Wasm_2_0_0.output = Tezos_scoru_wasm.Wasm_pvm_state.output_info and type Wasm_2_0_0.reveal_hash = @@ -1126,6 +1127,10 @@ struct input_request : input_request; } + type version = Tezos_scoru_wasm.Wasm_pvm_state.version + + let v0 = Tezos_scoru_wasm.Wasm_pvm_state.V0 + module Make (Tree : Context.TREE with type key = string list and type value = bytes) = struct diff --git a/src/lib_protocol_environment/environment_V9.mli b/src/lib_protocol_environment/environment_V9.mli index 6426410d4b4d..4213335f5bc1 100644 --- a/src/lib_protocol_environment/environment_V9.mli +++ b/src/lib_protocol_environment/environment_V9.mli @@ -114,6 +114,7 @@ module type T = sig and type Dal.page_proof = Tezos_crypto_dal.Cryptobox.Verifier.page_proof and type Bounded.Non_negative_int32.t = Tezos_base.Bounded.Non_negative_int32.t + and type Wasm_2_0_0.version = Tezos_scoru_wasm.Wasm_pvm_state.version and type Wasm_2_0_0.input = Tezos_scoru_wasm.Wasm_pvm_state.input_info and type Wasm_2_0_0.output = Tezos_scoru_wasm.Wasm_pvm_state.output_info and type Wasm_2_0_0.reveal_hash = diff --git a/src/lib_protocol_environment/sigs/v9.ml b/src/lib_protocol_environment/sigs/v9.ml index 1339a6194915..4694f64a1daa 100644 --- a/src/lib_protocol_environment/sigs/v9.ml +++ b/src/lib_protocol_environment/sigs/v9.ml @@ -12078,6 +12078,10 @@ end (* *) (*****************************************************************************) +type version + +val v0 : version + type input = {inbox_level : Bounded.Non_negative_int32.t; message_counter : Z.t} type output = {outbox_level : Bounded.Non_negative_int32.t; message_index : Z.t} @@ -12099,7 +12103,7 @@ type info = { module Make (Tree : Context.TREE with type key = string list and type value = bytes) : sig - val initial_state : Tree.tree -> Tree.tree Lwt.t + val initial_state : version -> Tree.tree -> Tree.tree Lwt.t val install_boot_sector : ticks_per_snapshot:Z.t -> diff --git a/src/lib_protocol_environment/sigs/v9/wasm_2_0_0.mli b/src/lib_protocol_environment/sigs/v9/wasm_2_0_0.mli index e97eecc3dddd..a7107b945eb8 100644 --- a/src/lib_protocol_environment/sigs/v9/wasm_2_0_0.mli +++ b/src/lib_protocol_environment/sigs/v9/wasm_2_0_0.mli @@ -23,6 +23,10 @@ (* *) (*****************************************************************************) +type version + +val v0 : version + type input = {inbox_level : Bounded.Non_negative_int32.t; message_counter : Z.t} type output = {outbox_level : Bounded.Non_negative_int32.t; message_index : Z.t} @@ -44,7 +48,7 @@ type info = { module Make (Tree : Context.TREE with type key = string list and type value = bytes) : sig - val initial_state : Tree.tree -> Tree.tree Lwt.t + val initial_state : version -> Tree.tree -> Tree.tree Lwt.t val install_boot_sector : ticks_per_snapshot:Z.t -> diff --git a/src/lib_scoru_wasm/constants.ml b/src/lib_scoru_wasm/constants.ml index 3f51cf9c497e..18e1b599d44d 100644 --- a/src/lib_scoru_wasm/constants.ml +++ b/src/lib_scoru_wasm/constants.ml @@ -65,4 +65,6 @@ let too_many_reboot_flag_key = let reboot_counter_key = Durable.key_of_string_exn "/readonly/kernel/env/reboot_counter" +let version_key = Durable.key_of_string_exn "/readonly/wasm_version" + let stack_size_limit = 300 diff --git a/src/lib_scoru_wasm/helpers/wasm_utils.ml b/src/lib_scoru_wasm/helpers/wasm_utils.ml index 25e39d418f86..640968a802ed 100644 --- a/src/lib_scoru_wasm/helpers/wasm_utils.ml +++ b/src/lib_scoru_wasm/helpers/wasm_utils.ml @@ -61,7 +61,7 @@ let initial_tree ?(ticks_per_snapshot = default_max_tick) let open Lwt.Syntax in let max_tick_Z = Z.of_int64 ticks_per_snapshot in let* tree = empty_tree () in - let* tree = Wasm.initial_state tree in + let* tree = Wasm.initial_state V0 tree in let* boot_sector = if from_binary then Lwt.return code else wat2wasm code in let* tree = Wasm.install_boot_sector diff --git a/src/lib_scoru_wasm/wasm_pvm.ml b/src/lib_scoru_wasm/wasm_pvm.ml index e7069351e42d..7c5b0e410ee4 100644 --- a/src/lib_scoru_wasm/wasm_pvm.ml +++ b/src/lib_scoru_wasm/wasm_pvm.ml @@ -28,6 +28,8 @@ open Wasm_pvm_state.Internal_state module Wasm = Tezos_webassembly_interpreter module Parsing = Binary_parser_encodings +let durable_scope = ["durable"] + let tick_state_encoding = let open Tezos_tree_encoding in tagged_union @@ -110,7 +112,7 @@ let durable_buffers_encoding = Tezos_tree_encoding.(scope ["pvm"; "buffers"] Wasm_encoding.buffers_encoding) let durable_storage_encoding = - Tezos_tree_encoding.(scope ["durable"] Durable.encoding) + Tezos_tree_encoding.(scope durable_scope Durable.encoding) let default_buffers validity_period message_limit () = Tezos_webassembly_interpreter.Eval. @@ -236,20 +238,29 @@ module Make_pvm (Wasm_vm : Wasm_vm_sig.S) (T : Tezos_tree_encoding.TREE) : let* tree = T.remove tree ["wasm"] in Tree_encoding_runner.encode pvm_state_encoding pvm_state tree - let initial_state empty_tree = - let version = Tezos_lazy_containers.Chunked_byte_vector.of_string "2.0.0" in - Tree_encoding_runner.encode - Tezos_tree_encoding.( - scope ["durable"; "readonly"; "wasm_version"; "@"] chunked_byte_vector) - version - empty_tree + let initial_state version empty_tree = + let open Lwt.Syntax in + let* durable = + Tree_encoding_runner.decode durable_storage_encoding empty_tree + in + let version_str = + Data_encoding.Binary.to_string_exn Wasm_pvm_state.version_encoding version + in + let* durable = + Durable.set_value_exn + ~edit_readonly:true + durable + Constants.version_key + version_str + in + Tree_encoding_runner.encode durable_storage_encoding durable empty_tree let install_boot_sector ~ticks_per_snapshot ~outbox_validity_period ~outbox_message_limit bs tree = let open Lwt_syntax in let open Tezos_tree_encoding in let* durable = - Tree_encoding_runner.decode (scope ["durable"] Durable.encoding) tree + Tree_encoding_runner.decode (scope durable_scope Durable.encoding) tree in let reboot_flag_key = Durable.key_of_string_exn "/kernel/env/reboot" in let kernel_key = Durable.key_of_string_exn "/kernel/boot.wasm" in diff --git a/src/lib_scoru_wasm/wasm_pvm_sig.ml b/src/lib_scoru_wasm/wasm_pvm_sig.ml index 4d41aa61c570..5144289678f9 100644 --- a/src/lib_scoru_wasm/wasm_pvm_sig.ml +++ b/src/lib_scoru_wasm/wasm_pvm_sig.ml @@ -70,7 +70,7 @@ module type S = sig (** [initial_state empty_tree] computes the initial tree whose hash is hard-coded in the protocol. *) - val initial_state : tree -> tree Lwt.t + val initial_state : version -> tree -> tree Lwt.t (** [install_boot_sector ~ticks_per_snapshot ~output_validity_period payload tree] installs the [payload] passed as an argument in [tree] so that it is diff --git a/src/lib_scoru_wasm/wasm_pvm_state.ml b/src/lib_scoru_wasm/wasm_pvm_state.ml index d22e5564ebbe..cf4fe8c81aeb 100644 --- a/src/lib_scoru_wasm/wasm_pvm_state.ml +++ b/src/lib_scoru_wasm/wasm_pvm_state.ml @@ -24,6 +24,21 @@ (* *) (*****************************************************************************) +type version = V0 + +let version_encoding = + (* This encoding is directly used by the protocol. As a consequence, + any change done to it needs to be backward compatible! + + We cannot use [string_enum] here because [string_enum] will + append the size of the string at the beginning of the encoded + bytes. *) + Data_encoding.( + conv_with_guard + (function V0 -> "2.0.0") + (function "2.0.0" -> Ok V0 | _ -> Error "not a valid version") + Variable.string) + (** Represents the location of an input message. *) type input_info = { inbox_level : Tezos_base.Bounded.Non_negative_int32.t; diff --git a/src/lib_store/unix/test/test_consistency.ml b/src/lib_store/unix/test/test_consistency.ml index 7e0a2e993256..9ec4db0498ad 100644 --- a/src/lib_store/unix/test/test_consistency.ml +++ b/src/lib_store/unix/test/test_consistency.ml @@ -30,7 +30,7 @@ let nb_protocols = 5 let register_protocol ~hash ~sources = let module M = struct include - Registered_protocol.Register_embedded_V8 + Registered_protocol.Register_embedded_V9 (Tezos_protocol_environment_demo_noops) (Tezos_protocol_demo_noops.Protocol) (struct diff --git a/src/lib_tree_encoding/decoding.ml b/src/lib_tree_encoding/decoding.ml index 9f139676e4b0..d5f956c69206 100644 --- a/src/lib_tree_encoding/decoding.ml +++ b/src/lib_tree_encoding/decoding.ml @@ -141,8 +141,24 @@ let value ?default key decoder = let subtree backend tree prefix = let open Lwt_syntax in - let+ tree = Tree.find_tree backend tree (prefix []) in - Option.map (Tree.wrap backend) tree + let tmp_directory = "tmp" in + let* subtree = Tree.find_tree backend tree (prefix []) in + let+ subtree = + match subtree with + | Some subtree -> return subtree + | None -> ( + let* tree = + Tree.add backend tree (prefix [tmp_directory]) (Bytes.of_string "") + in + let* subtree = Tree.find_tree backend tree (prefix []) in + match subtree with + | Some subtree -> Tree.remove backend subtree [tmp_directory] + | None -> + (* This case is impossible, because we have added something + in the tree to avoid it. *) + assert false) + in + Tree.wrap backend subtree let scope key {decode} = { @@ -162,7 +178,7 @@ let lazy_mapping to_key field_enc = input_prefix in let+ tree = subtree backend input_tree input_prefix in - (tree, produce_value)); + (Some tree, produce_value)); } let case_lwt tag decode extract = Case {tag; decode; extract} @@ -209,8 +225,5 @@ let wrapped_tree = (fun backend tree prefix -> let open Lwt.Syntax in let+ tree = subtree backend tree prefix in - match tree with - | Some subtree -> - Tree.Wrapped_tree (Tree.select backend subtree, backend) - | _ -> raise Not_found); + Tree.Wrapped_tree (Tree.select backend tree, backend)); } diff --git a/src/proto_016_PtMumbai/lib_protocol/test/unit/test_sc_rollup_wasm.ml b/src/proto_016_PtMumbai/lib_protocol/test/unit/test_sc_rollup_wasm.ml index 544e03dd212c..9a7f3dbca8d5 100644 --- a/src/proto_016_PtMumbai/lib_protocol/test/unit/test_sc_rollup_wasm.ml +++ b/src/proto_016_PtMumbai/lib_protocol/test/unit/test_sc_rollup_wasm.ml @@ -235,7 +235,7 @@ let test_output () = match parsed.it with Script.Textual m -> m | _ -> assert false in let*! boot_sector = Encode.encode parsed in - let*! tree = Wasm.initial_state empty_tree in + let*! tree = Wasm.initial_state V0 empty_tree in let*! tree = Wasm.install_boot_sector ~ticks_per_snapshot:Sc_rollup_wasm.V2_0_0.ticks_per_snapshot diff --git a/src/proto_016_PtMumbai/lib_sc_rollup_node/wasm_2_0_0_pvm.ml b/src/proto_016_PtMumbai/lib_sc_rollup_node/wasm_2_0_0_pvm.ml index 9a7170774a95..bc9abdd67d5a 100644 --- a/src/proto_016_PtMumbai/lib_sc_rollup_node/wasm_2_0_0_pvm.ml +++ b/src/proto_016_PtMumbai/lib_sc_rollup_node/wasm_2_0_0_pvm.ml @@ -62,8 +62,11 @@ module Make_wrapped_tree (Tree : TreeS) : let wrap t = PVM_tree t end -module Make_backend (Tree : TreeS) = - Tezos_scoru_wasm_fast.Pvm.Make (Make_wrapped_tree (Tree)) +module Make_backend (Tree : TreeS) = struct + include Tezos_scoru_wasm_fast.Pvm.Make (Make_wrapped_tree (Tree)) + + let initial_state = initial_state V0 +end module Make_durable_state (T : Tezos_tree_encoding.TREE with type tree = Context.tree) : diff --git a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml index bdc218943479..1156d96954ce 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml +++ b/src/proto_alpha/lib_protocol/sc_rollup_wasm.ml @@ -81,6 +81,8 @@ let () = (fun () -> WASM_invalid_dissection_distribution) module V2_0_0 = struct + let current_version = Wasm_2_0_0.v0 + let ticks_per_snapshot = Z.of_int64 11_000_000_000L let outbox_validity_period = Int32.of_int 80_640 @@ -260,7 +262,7 @@ module V2_0_0 = struct open Monad - let initial_state ~empty = WASM_machine.initial_state empty + let initial_state ~empty = WASM_machine.initial_state current_version empty let install_boot_sector state boot_sector = WASM_machine.install_boot_sector diff --git a/src/proto_alpha/lib_protocol/sc_rollup_wasm.mli b/src/proto_alpha/lib_protocol/sc_rollup_wasm.mli index cb2291150b2e..72bfc145c2e3 100644 --- a/src/proto_alpha/lib_protocol/sc_rollup_wasm.mli +++ b/src/proto_alpha/lib_protocol/sc_rollup_wasm.mli @@ -28,6 +28,8 @@ module V2_0_0 : sig (** This module provides Proof-Generating Virtual Machine (PVM) running WebAssembly (version 2.0.0). *) + val current_version : Wasm_2_0_0.version + module type S = sig include Sc_rollup_PVM_sig.S diff --git a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_wasm.ml b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_wasm.ml index 544e03dd212c..115f6fc00cb7 100644 --- a/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_wasm.ml +++ b/src/proto_alpha/lib_protocol/test/unit/test_sc_rollup_wasm.ml @@ -235,7 +235,9 @@ let test_output () = match parsed.it with Script.Textual m -> m | _ -> assert false in let*! boot_sector = Encode.encode parsed in - let*! tree = Wasm.initial_state empty_tree in + let*! tree = + Wasm.initial_state Sc_rollup_wasm.V2_0_0.current_version empty_tree + in let*! tree = Wasm.install_boot_sector ~ticks_per_snapshot:Sc_rollup_wasm.V2_0_0.ticks_per_snapshot -- GitLab