From 0a07b274f39b87f6da5071b69139de4d6628e9c9 Mon Sep 17 00:00:00 2001 From: Thomas Letan Date: Tue, 8 Oct 2024 21:22:38 +0200 Subject: [PATCH] EVM Node: Introduce the experimental WASM Runtime MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The goal of the EVM Node’s WASM Runtime is to introduce an ad-hoc WASM runtime, that is an alternative take of the Fast Execution runtime implemented for the rollup node. It can be enabled by setting experimental feature `next_wasm_runtime` to `true` in the configuration file. Do take into account the implementation introduced in this commit is incomplete. In particular, it does support fetching missing preimages from a known endpoint. In a nutshell, the Fast Execution runtime of the WASM PVM leverages the C API of Wasmer. This API, as its name suggests, delegates memory-management to the caller: every time a new Wasmer “object” (module, function instances, etc.) is created, the caller is expected to free it. We have strong evidences that there are some memory leaks in the Fast Execution of the PVM, but we have not been able to pin down where and why. Wasmer being a Rust program, it is a little frustrating to have to face this memory leak issue. But, by moving the abstraction layers a little, it becomes possible to have Rust functions initializing and executing Wasmer. When doing that, we can enjoy Rust automatic memory management. It means having to reimplement the WASM PVM life cycle. But on this side, we don’t need to stick to everything the WASM PVM is doing. We just need to implement the subset that the kernel of Etherlink actually use. To give an example, the Etherlink kernel never checks the flag created by the PVM if the kernel panicks, so we don’t need to bother with it either. Similarly, the reboot counter is not really used beyond cosmetic logs, that we can reimplement as part of the runtime. --- etherlink/bin_node/config/configuration.ml | 21 +- etherlink/bin_node/config/configuration.mli | 1 + etherlink/bin_node/dune | 3 +- .../bin_node/lib_dev/durable_storage_path.ml | 2 + .../bin_node/lib_dev/durable_storage_path.mli | 2 + etherlink/bin_node/lib_dev/evm_context.ml | 29 +- etherlink/bin_node/lib_dev/evm_context.mli | 48 +- etherlink/bin_node/lib_dev/evm_ro_context.ml | 36 +- etherlink/bin_node/lib_dev/evm_ro_context.mli | 1 + etherlink/bin_node/lib_dev/evm_state.ml | 47 +- etherlink/bin_node/lib_dev/evm_state.mli | 10 +- etherlink/bin_node/lib_dev/observer.ml | 1 + etherlink/bin_node/lib_dev/sequencer.ml | 1 + .../lib_dev/threshold_encryption_sequencer.ml | 1 + etherlink/bin_node/lib_dev/wasm_runtime.ml | 48 +- etherlink/bin_node/lib_dev/wasm_runtime.mli | 12 +- etherlink/bin_node/main.ml | 2 + etherlink/bin_node/test/test_wasm_runtime.ml | 32 +- .../Alpha- Configuration RPC.out | 9 +- .../EVM Node- describe config.out | 6 +- manifest/product_etherlink.ml | 1 - opam/octez-evm-node.opam | 1 - src/lib_wasm_debugger/wasm_debugger.ml | 4 +- src/lib_wasm_runtime/Cargo.lock | 711 +++++++++++++++++- src/lib_wasm_runtime/Cargo.toml | 4 +- .../ocaml-api/evm_node_wasm_runtime.ml | 3 + .../ocaml-api/evm_node_wasm_runtime.mli | 17 +- .../ocaml-api/wasm_runtime_gen.ml | 4 +- .../ocaml-api/wasm_runtime_gen.mli | 4 +- src/lib_wasm_runtime/rust-toolchain | 1 + src/lib_wasm_runtime/src/api.rs | 132 +++- src/lib_wasm_runtime/src/bindings.rs | 226 ++++++ src/lib_wasm_runtime/src/host.rs | 126 ++++ src/lib_wasm_runtime/src/lib.rs | 3 + src/lib_wasm_runtime/src/runtime/env.rs | 50 ++ .../src/runtime/host_funcs.rs | 456 +++++++++++ src/lib_wasm_runtime/src/runtime/mod.rs | 117 +++ src/lib_wasm_runtime/src/types.rs | 89 +++ src/lib_wasm_runtime_callbacks/vector.ml | 10 +- src/rust_deps/Cargo.lock | 186 ++--- 40 files changed, 2254 insertions(+), 203 deletions(-) create mode 100644 src/lib_wasm_runtime/rust-toolchain create mode 100644 src/lib_wasm_runtime/src/bindings.rs create mode 100644 src/lib_wasm_runtime/src/host.rs create mode 100644 src/lib_wasm_runtime/src/runtime/env.rs create mode 100644 src/lib_wasm_runtime/src/runtime/host_funcs.rs create mode 100644 src/lib_wasm_runtime/src/runtime/mod.rs diff --git a/etherlink/bin_node/config/configuration.ml b/etherlink/bin_node/config/configuration.ml index dab339f69ce4..06c551c30851 100644 --- a/etherlink/bin_node/config/configuration.ml +++ b/etherlink/bin_node/config/configuration.ml @@ -38,6 +38,7 @@ type experimental_features = { block_storage_sqlite3 : bool; overwrite_simulation_tick_limit : bool; garbage_collector : garbage_collector option; + next_wasm_runtime : bool; } type sequencer = { @@ -129,6 +130,7 @@ let default_experimental_features = block_storage_sqlite3 = false; overwrite_simulation_tick_limit = false; garbage_collector = None; + next_wasm_runtime = false; } let default_data_dir = Filename.concat (Sys.getenv "HOME") ".octez-evm-node" @@ -670,19 +672,22 @@ let experimental_features_encoding = block_storage_sqlite3; overwrite_simulation_tick_limit; garbage_collector; + next_wasm_runtime; } -> ( drop_duplicate_on_injection, enable_send_raw_transaction, node_transaction_validation, block_storage_sqlite3, overwrite_simulation_tick_limit, - garbage_collector )) + garbage_collector, + next_wasm_runtime )) (fun ( drop_duplicate_on_injection, enable_send_raw_transaction, node_transaction_validation, block_storage_sqlite3, overwrite_simulation_tick_limit, - garbage_collector ) -> + garbage_collector, + next_wasm_runtime ) -> { drop_duplicate_on_injection; enable_send_raw_transaction; @@ -690,8 +695,9 @@ let experimental_features_encoding = block_storage_sqlite3; overwrite_simulation_tick_limit; garbage_collector; + next_wasm_runtime; }) - (obj6 + (obj7 (dft ~description: "Request the rollup node to filter messages it has already \ @@ -729,7 +735,14 @@ let experimental_features_encoding = (opt "garbage_collector" ~description:"Enables garbage collector in the node." - garbage_collector_encoding)) + garbage_collector_encoding) + (dft + "next_wasm_runtime" + ~description: + "Enable or disable the experimental WASM runtime that is expected \ + to replace the Smart Rollup’s Fast Exec runtime" + bool + false)) let proxy_encoding = let open Data_encoding in diff --git a/etherlink/bin_node/config/configuration.mli b/etherlink/bin_node/config/configuration.mli index bef93f6a479a..1d849cf61e2b 100644 --- a/etherlink/bin_node/config/configuration.mli +++ b/etherlink/bin_node/config/configuration.mli @@ -60,6 +60,7 @@ type experimental_features = { block_storage_sqlite3 : bool; overwrite_simulation_tick_limit : bool; garbage_collector : garbage_collector option; + next_wasm_runtime : bool; } type sequencer = { diff --git a/etherlink/bin_node/dune b/etherlink/bin_node/dune index d8a33c193562..beacb55d4c00 100644 --- a/etherlink/bin_node/dune +++ b/etherlink/bin_node/dune @@ -18,8 +18,7 @@ octez-shell-libs.client-base-unix octez-l2-libs.sqlite octez-evm-node-libs.evm_node_lib_dev - octez-evm-node-libs.evm_node_config - octez-rust-deps) + octez-evm-node-libs.evm_node_config) (link_flags (:standard) (:include %{workspace_root}/static-link-flags.sexp) diff --git a/etherlink/bin_node/lib_dev/durable_storage_path.ml b/etherlink/bin_node/lib_dev/durable_storage_path.ml index 287650c91b42..afe94fde54bf 100644 --- a/etherlink/bin_node/lib_dev/durable_storage_path.ml +++ b/etherlink/bin_node/lib_dev/durable_storage_path.ml @@ -12,6 +12,8 @@ open Ethereum_types type path = string +let reboot_counter = "/readonly/kernel/env/reboot_counter" + let evm_node_flag = "/__evm_node" module EVM = struct diff --git a/etherlink/bin_node/lib_dev/durable_storage_path.mli b/etherlink/bin_node/lib_dev/durable_storage_path.mli index 5bd5fce47ac2..919a8f50b644 100644 --- a/etherlink/bin_node/lib_dev/durable_storage_path.mli +++ b/etherlink/bin_node/lib_dev/durable_storage_path.mli @@ -12,6 +12,8 @@ open Ethereum_types type path = string +val reboot_counter : string + val evm_node_flag : path val chain_id : path diff --git a/etherlink/bin_node/lib_dev/evm_context.ml b/etherlink/bin_node/lib_dev/evm_context.ml index f413fa17d5bc..6613757c3b5a 100644 --- a/etherlink/bin_node/lib_dev/evm_context.ml +++ b/etherlink/bin_node/lib_dev/evm_context.ml @@ -26,6 +26,7 @@ type parameters = { store_perm : [`Read_only | `Read_write]; block_storage_sqlite3 : bool; garbage_collector : Configuration.garbage_collector option; + wasm_runtime : bool; } type session_state = { @@ -54,6 +55,7 @@ type t = { fail_on_missing_blueprint : bool; block_storage_sqlite3 : bool; history : history; + wasm_runtime : bool; } type store_info = { @@ -71,12 +73,17 @@ let session_to_head_info session = } let pvm_config ctxt = - Config.config - ~preimage_directory:ctxt.preimages - ?preimage_endpoint:ctxt.preimages_endpoint - ~kernel_debug:true - ~destination:ctxt.smart_rollup_address - () + Evm_state. + { + config = + Config.config + ~preimage_directory:ctxt.preimages + ?preimage_endpoint:ctxt.preimages_endpoint + ~kernel_debug:true + ~destination:ctxt.smart_rollup_address + (); + wasm_runtime = ctxt.wasm_runtime; + } module Types = struct type state = t @@ -919,7 +926,7 @@ module State = struct (preload_kernel_from_level ctxt) (earliest_level @ activation_levels) - let init ?kernel_path ~block_storage_sqlite3 ?garbage_collector + let init ?kernel_path ~wasm_runtime ~block_storage_sqlite3 ?garbage_collector ~fail_on_missing_blueprint ~data_dir ~preimages ~preimages_endpoint ?smart_rollup_address ~store_perm () = let open Lwt_result_syntax in @@ -1034,6 +1041,7 @@ module State = struct fail_on_missing_blueprint; block_storage_sqlite3; history; + wasm_runtime; } in @@ -1340,6 +1348,7 @@ module Handlers = struct store_perm; block_storage_sqlite3; garbage_collector; + wasm_runtime; } = let open Lwt_result_syntax in let* ctxt, status = @@ -1353,6 +1362,7 @@ module Handlers = struct ~store_perm ~block_storage_sqlite3 ?garbage_collector + ~wasm_runtime () in Lwt.wakeup execution_config_waker @@ (ctxt.data_dir, pvm_config ctxt) ; @@ -1555,7 +1565,7 @@ let export_store ~data_dir ~output_db_file = let start ?kernel_path ~data_dir ~preimages ~preimages_endpoint ?smart_rollup_address ~fail_on_missing_blueprint ~store_perm - ~block_storage_sqlite3 ?garbage_collector () = + ~block_storage_sqlite3 ?garbage_collector ~wasm_runtime () = let open Lwt_result_syntax in let* () = lock_data_dir ~data_dir in let* worker = @@ -1572,6 +1582,7 @@ let start ?kernel_path ~data_dir ~preimages ~preimages_endpoint store_perm; block_storage_sqlite3; garbage_collector; + wasm_runtime; } (module Handlers) in @@ -1759,6 +1770,7 @@ let reconstruct ~data_dir ~rollup_node_data_dir ~boot_sector = ~fail_on_missing_blueprint:false ~store_perm:`Read_write ~block_storage_sqlite3:false + ~wasm_runtime:false () in worker_wait_for_request @@ -1787,6 +1799,7 @@ let init_from_rollup_node ~omit_delayed_tx_events ~data_dir ~fail_on_missing_blueprint:false ~store_perm:`Read_write ~block_storage_sqlite3:false + ~wasm_runtime:false () in worker_wait_for_request diff --git a/etherlink/bin_node/lib_dev/evm_context.mli b/etherlink/bin_node/lib_dev/evm_context.mli index 9d9f2f181020..0ff106eb16e5 100644 --- a/etherlink/bin_node/lib_dev/evm_context.mli +++ b/etherlink/bin_node/lib_dev/evm_context.mli @@ -32,15 +32,44 @@ type store_info = { val export_store : data_dir:string -> output_db_file:string -> store_info tzresult Lwt.t -(** [start ~data_dir ~preimages ~preimages_endpoint - ~smart_rollup_address ()] creates a new worker to - manage a local EVM context where it initializes the {!type-index}, - and use a checkpoint mechanism to load the latest {!type-store} if - any. - - Returns a value telling if the context was loaded from disk - ([Loaded]) or was initialized from scratch ([Created]). Returns - also the smart rollup address. *) +(** [start] creates a new worker to manage a local EVM context where it + initializes the {!type-index}, and use a checkpoint mechanism to load the + latest {!type-store} if any. Returns a value telling if the context was + loaded from disk ([Loaded]) or was initialized from scratch ([Created]). + Returns also the smart rollup address. + + [kernel_path] can be provided to cover the case where the context does not + exist yet, and is ignored otherwise. + + [data_dir] is the path to the data-dir of the node, notably containing the + SQLite store and the Irmin context. + + [preimages] is the path to the preimages directory, while a + [preimages_endponit] URI can be optionally provided to download missing + preimages when they are requested by the current kernel (during upgrades). + + [smart_rollup_address] can be provided either when starting from a + non-existing data-dir, or when starting a sandbox. + + [fail_on_missing_blueprint] will decide the behavior of the worker when a + blueprint is confirmed by a rollup node before it is applied by the EVM + node. A sequencer will typically set it to true, while observers set it to + [false] for now. + + [store_perm] decides whether or not the worker can modify the Irmin context + (it is most certainly an artifact of the past, made outdated by the + [Evm_ro_context] module. Clearly, [~store_perm:`Read_only] menas you want + to use [Evm_ro_context] instead. + + [block_storage_sqlite3] decides whether or not the blocks are stored in the + SQLite store or not. + + [garbage_collector] can be optionally provided to enable the garbage + collector of the node with a given configuration. + + [wasm_runtime] can be set to true to enable the use of the (experimental) + WASM Runtime instead of relying on the general-purpose Fast Execution + exposed by the WASM debugger. *) val start : ?kernel_path:string -> data_dir:string -> @@ -51,6 +80,7 @@ val start : store_perm:[`Read_only | `Read_write] -> block_storage_sqlite3:bool -> ?garbage_collector:Configuration.garbage_collector -> + wasm_runtime:bool -> unit -> (init_status * Address.t) tzresult Lwt.t diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.ml b/etherlink/bin_node/lib_dev/evm_ro_context.ml index 9497f07c658f..686b84a333fb 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.ml +++ b/etherlink/bin_node/lib_dev/evm_ro_context.ml @@ -14,6 +14,7 @@ type t = { index : Irmin_context.ro_index; finalized_view : bool; block_storage_sqlite3 : bool; + wasm_runtime : bool; } let load ?smart_rollup_address ~data_dir configuration = @@ -38,6 +39,7 @@ let load ?smart_rollup_address ~data_dir configuration = block_storage_sqlite3 = configuration.experimental_features.block_storage_sqlite3; finalized_view = configuration.finalized_view; + wasm_runtime = configuration.experimental_features.next_wasm_runtime; } let get_evm_state ctxt hash = @@ -232,12 +234,17 @@ struct let simulate_and_read ?state_override simulate_state ~input = let open Lwt_result_syntax in let config = - Config.config - ~preimage_directory:Ctxt.ctxt.preimages - ?preimage_endpoint:Ctxt.ctxt.preimages_endpoint - ~kernel_debug:false - ~destination:Ctxt.ctxt.smart_rollup_address - () + Evm_state. + { + config = + Config.config + ~preimage_directory:Ctxt.ctxt.preimages + ?preimage_endpoint:Ctxt.ctxt.preimages_endpoint + ~kernel_debug:false + ~destination:Ctxt.ctxt.smart_rollup_address + (); + wasm_runtime = Ctxt.ctxt.wasm_runtime; + } in let* simulate_state = State_override.update_accounts state_override simulate_state @@ -316,12 +323,17 @@ end) = Services_backend_sig.Make (MakeBackend (Base)) (Base.Executor) let pvm_config ctxt = - Config.config - ~preimage_directory:ctxt.preimages - ?preimage_endpoint:ctxt.preimages_endpoint - ~kernel_debug:true - ~destination:ctxt.smart_rollup_address - () + Evm_state. + { + config = + Config.config + ~preimage_directory:ctxt.preimages + ?preimage_endpoint:ctxt.preimages_endpoint + ~kernel_debug:true + ~destination:ctxt.smart_rollup_address + (); + wasm_runtime = ctxt.wasm_runtime; + } let replay ctxt ?(log_file = "replay") ?profile ?(alter_evm_state = Lwt_result_syntax.return) (Ethereum_types.Qty number) = diff --git a/etherlink/bin_node/lib_dev/evm_ro_context.mli b/etherlink/bin_node/lib_dev/evm_ro_context.mli index 75505027518c..421e05507db0 100644 --- a/etherlink/bin_node/lib_dev/evm_ro_context.mli +++ b/etherlink/bin_node/lib_dev/evm_ro_context.mli @@ -14,6 +14,7 @@ type t = { index : Irmin_context.ro_index; finalized_view : bool; block_storage_sqlite3 : bool; + wasm_runtime : bool; } (** [load ~data_dir configuration] creates a new read-only handler on the diff --git a/etherlink/bin_node/lib_dev/evm_state.ml b/etherlink/bin_node/lib_dev/evm_state.ml index ac831cc79d6d..759f717f0d2c 100644 --- a/etherlink/bin_node/lib_dev/evm_state.ml +++ b/etherlink/bin_node/lib_dev/evm_state.ml @@ -7,6 +7,8 @@ open Ethereum_types +type config = {config : Config.config; wasm_runtime : bool} + module Bare_context = struct module Tree = Irmin_context.Tree @@ -80,12 +82,12 @@ let execute ?(wasm_pvm_fallback = false) ?(profile = false) ~no_reboot:false 0l inbox - {config with flamecharts_directory = data_dir} + {config.config with flamecharts_directory = data_dir} Custom_section.FuncMap.empty evm_state in return evm_state - else + else if not config.wasm_runtime then let hooks = Tezos_scoru_wasm.Hooks.( no_hooks @@ -100,11 +102,28 @@ let execute ?(wasm_pvm_fallback = false) ?(profile = false) ~wasm_entrypoint 0l inbox - config + config.config Inbox evm_state in - + return evm_state + else + (* The [inbox] parameter is inherited from the WASM debugger, where the + inbox is a list of list of messages (because it supports running the + fast exec for several Tezos level in a raw). + + As far as the EVM node is concerned, we only “emulate” one Tezos level + at a time, so we only keep the first item ([inbox] is in parctise + always a singleton). *) + let inbox = match Seq.uncons inbox with Some (x, _) -> x | _ -> [] in + let*! evm_state = + Wasm_runtime.run + ~preimages_dir:config.config.preimage_directory + ~entrypoint:wasm_entrypoint + evm_state + config.config.destination + inbox + in return evm_state in let* evm_state = eval evm_state in @@ -126,17 +145,35 @@ let execute ?(wasm_pvm_fallback = false) ?(profile = false) in return evm_state -let modify ~key ~value evm_state = Wasm.set_durable_value evm_state key value +let modify ?edit_readonly ~key ~value evm_state = + Wasm.set_durable_value ?edit_readonly evm_state key value let flag_local_exec evm_state = modify evm_state ~key:Durable_storage_path.evm_node_flag ~value:"" +let init_reboot_counter evm_state = + let initial_reboot_counter = + Data_encoding.( + Binary.to_string_exn + Little_endian.int32 + Z.( + to_int32 @@ succ Tezos_scoru_wasm.Constants.maximum_reboots_per_input)) + in + modify + ~edit_readonly:true + ~key:Durable_storage_path.reboot_counter + ~value:initial_reboot_counter + evm_state + let init ~kernel = let open Lwt_result_syntax in let evm_state = Irmin_context.PVMState.empty () in let* evm_state = Wasm.start ~tree:evm_state Tezos_scoru_wasm.Wasm_pvm_state.V3 kernel in + (* The WASM Runtime completely ignores the reboot counter, but some versions + of the Etherlink kernel will need it to exist. *) + let*! evm_state = init_reboot_counter evm_state in let*! evm_state = flag_local_exec evm_state in return evm_state diff --git a/etherlink/bin_node/lib_dev/evm_state.mli b/etherlink/bin_node/lib_dev/evm_state.mli index 531d8c748576..3dcd8974ed94 100644 --- a/etherlink/bin_node/lib_dev/evm_state.mli +++ b/etherlink/bin_node/lib_dev/evm_state.mli @@ -5,6 +5,8 @@ (* *) (*****************************************************************************) +type config = {config : Config.config; wasm_runtime : bool} + type t = Irmin_context.PVMState.value (** Directory where the kernel logs are stored. The function {!execute} below @@ -26,7 +28,7 @@ val execute : data_dir:string -> ?log_file:string -> ?wasm_entrypoint:string -> - config:Config.config -> + config:config -> t -> [< `Input of string] list -> t tzresult Lwt.t @@ -36,7 +38,7 @@ val init : kernel:string -> t tzresult Lwt.t (** [modify ~key ~value evm_state] sets [value] at [key] in the local EVM state. *) -val modify : key:string -> value:string -> t -> t Lwt.t +val modify : ?edit_readonly:bool -> key:string -> value:string -> t -> t Lwt.t (** [delete ~kind evm_state key] delete the value/directory at [key] *) val delete : kind:Tezos_scoru_wasm.Durable.kind -> t -> string -> t Lwt.t @@ -61,7 +63,7 @@ val execute_and_inspect : ?wasm_pvm_fallback:bool -> data_dir:string -> ?wasm_entrypoint:string -> - config:Config.config -> + config:config -> input:Simulation.Encodings.simulate_input -> t -> bytes option list tzresult Lwt.t @@ -90,7 +92,7 @@ val apply_blueprint : ?log_file:string -> ?profile:bool -> data_dir:string -> - config:Config.config -> + config:config -> t -> Blueprint_types.payload -> apply_result tzresult Lwt.t diff --git a/etherlink/bin_node/lib_dev/observer.ml b/etherlink/bin_node/lib_dev/observer.ml index 9b546b70a2a5..77ccef8defaa 100644 --- a/etherlink/bin_node/lib_dev/observer.ml +++ b/etherlink/bin_node/lib_dev/observer.ml @@ -76,6 +76,7 @@ let main ?kernel_path ~data_dir ~(config : Configuration.t) ~no_sync () = ~store_perm:`Read_write ~block_storage_sqlite3:config.experimental_features.block_storage_sqlite3 ?garbage_collector:config.experimental_features.garbage_collector + ~wasm_runtime:config.experimental_features.next_wasm_runtime () in let* ro_ctxt = Evm_ro_context.load ~smart_rollup_address ~data_dir config in diff --git a/etherlink/bin_node/lib_dev/sequencer.ml b/etherlink/bin_node/lib_dev/sequencer.ml index 1b58215e14e2..047222070357 100644 --- a/etherlink/bin_node/lib_dev/sequencer.ml +++ b/etherlink/bin_node/lib_dev/sequencer.ml @@ -74,6 +74,7 @@ let main ~data_dir ?(genesis_timestamp = Misc.now ()) ~cctxt ~block_storage_sqlite3: configuration.experimental_features.block_storage_sqlite3 ?garbage_collector:configuration.experimental_features.garbage_collector + ~wasm_runtime:configuration.experimental_features.next_wasm_runtime () in let smart_rollup_address_b58 = Address.to_string smart_rollup_address_typed in diff --git a/etherlink/bin_node/lib_dev/threshold_encryption_sequencer.ml b/etherlink/bin_node/lib_dev/threshold_encryption_sequencer.ml index 8ee5e62e1cb5..8014e9396a39 100644 --- a/etherlink/bin_node/lib_dev/threshold_encryption_sequencer.ml +++ b/etherlink/bin_node/lib_dev/threshold_encryption_sequencer.ml @@ -44,6 +44,7 @@ let main ~data_dir ?(genesis_timestamp = Misc.now ()) ~cctxt ~store_perm:`Read_write ~block_storage_sqlite3: configuration.experimental_features.block_storage_sqlite3 + ~wasm_runtime:configuration.experimental_features.next_wasm_runtime () in let*! (Qty next_blueprint_number) = Evm_context.next_blueprint_number () in diff --git a/etherlink/bin_node/lib_dev/wasm_runtime.ml b/etherlink/bin_node/lib_dev/wasm_runtime.ml index 4ed9c27a9370..f3b53ae9f580 100644 --- a/etherlink/bin_node/lib_dev/wasm_runtime.ml +++ b/etherlink/bin_node/lib_dev/wasm_runtime.ml @@ -5,6 +5,48 @@ (* *) (*****************************************************************************) -let run tree = - let open Lwt_syntax in - return (Evm_node_wasm_runtime.wasm_runtime_id tree) +let static_context = Evm_node_wasm_runtime.wasm_runtime_new_context () + +module Shared_inbox : sig + (** [wrap inbox] encapsulates [inbox] between [sol; ipl] and [eol]. These + messages are necessary for the proxy mode of the kernel, and they are + indirectly used by the delayed inbox implementation (because the index of + the deposit in the shared inbox is used to compute the hash). *) + val wrap : string list -> string list +end = struct + let sol = + Tezos_scoru_wasm.Pvm_input_kind.( + Internal_for_tests.to_binary_input (Internal Start_of_level) None) + + let ipl = + let block_hash = Block_hash.zero in + let timestamp = Time.Protocol.epoch in + let info = + Data_encoding.( + Binary.to_string_exn + (tup2 Time.Protocol.encoding Block_hash.encoding) + (timestamp, block_hash)) + in + Tezos_scoru_wasm.Pvm_input_kind.( + Internal_for_tests.to_binary_input (Internal Info_per_level) (Some info)) + + let eol = + Tezos_scoru_wasm.Pvm_input_kind.( + Internal_for_tests.to_binary_input (Internal End_of_level) None) + + let wrap inbox = (sol :: ipl :: inbox) @ [eol] +end + +let run ~preimages_dir ~entrypoint tree rollup_address inbox : + Irmin_context.tree Lwt.t = + Lwt_preemptive.detach + (fun () -> + Evm_node_wasm_runtime.wasm_runtime_run + ~preimages_dir + ~entrypoint + static_context + tree + (Tezos_crypto.Hashed.Smart_rollup_address.to_bytes rollup_address) + 0l + Shared_inbox.(wrap inbox)) + () diff --git a/etherlink/bin_node/lib_dev/wasm_runtime.mli b/etherlink/bin_node/lib_dev/wasm_runtime.mli index 5960ae89880a..f50b600025a8 100644 --- a/etherlink/bin_node/lib_dev/wasm_runtime.mli +++ b/etherlink/bin_node/lib_dev/wasm_runtime.mli @@ -5,6 +5,12 @@ (* *) (*****************************************************************************) -(** [run tree] calls the WASM runtime, feeding it [tree], and computing the - next [tree]. *) -val run : Irmin_context.tree -> Irmin_context.tree Lwt.t +(** [run entrypoint tree rollup_address blueprint] calls the WASM runtime over + [tree], and computing the next [tree]. *) +val run : + preimages_dir:string -> + entrypoint:string -> + Irmin_context.tree -> + Address.t -> + string list -> + Irmin_context.tree Lwt.t diff --git a/etherlink/bin_node/main.ml b/etherlink/bin_node/main.ml index 7472a95785be..88011536197d 100644 --- a/etherlink/bin_node/main.ml +++ b/etherlink/bin_node/main.ml @@ -1503,6 +1503,7 @@ let patch_kernel_command = ~preimages_endpoint:None ~fail_on_missing_blueprint:true ~block_storage_sqlite3:false + ~wasm_runtime:false () in Evm_context.patch_kernel ?block_number kernel_path @@ -2343,6 +2344,7 @@ let patch_state_command = ~preimages_endpoint:None ~fail_on_missing_blueprint:true ~block_storage_sqlite3:false + ~wasm_runtime:false () in Evm_context.patch_state ?block_number ~key ~value () diff --git a/etherlink/bin_node/test/test_wasm_runtime.ml b/etherlink/bin_node/test/test_wasm_runtime.ml index 9749e64e9b18..41b2fa9a40bc 100644 --- a/etherlink/bin_node/test/test_wasm_runtime.ml +++ b/etherlink/bin_node/test/test_wasm_runtime.ml @@ -23,14 +23,38 @@ let register ?(tags = []) = let context_hash_typ = Check.(convert Context_hash.to_b58check string) +let z_typ = Check.(convert Z.to_int64 int64) + let empty_tree = Irmin_context.PVMState.empty () +let expect_ok msg = function Ok x -> x | Error _err -> Test.fail msg + let test_wasm_runtime_id () = register ~title:"test wasm_runtime_run" @@ fun () -> - let hash = Irmin_context.Tree.hash empty_tree in - let* empty_tree_id = Wasm_runtime.run empty_tree in - let hash_id = Irmin_context.Tree.hash empty_tree_id in - Check.((hash = hash_id) context_hash_typ ~error_msg:"Hash should be the same") ; + let* tree = + Evm_state.init + ~kernel: + "etherlink/kernel_evm/kernel/tests/resources/mainnet_evm_kernel.wasm" + in + let tree = expect_ok "Should be able to create an initial state" tree in + let* tree = + Wasm_runtime.run + ~preimages_dir:Temp.(dir "wasm_2_0_0") + ~entrypoint:"kernel_run" + tree + Tezos_crypto.Hashed.Smart_rollup_address.zero + [] + in + let* quantity = + Durable_storage.current_block_number (fun key -> + let* candidate = Evm_state.inspect tree key in + return (Ok candidate)) + in + let (Qty number) = + expect_ok "Should be able to read the current number" quantity + in + Check.( + (number = Z.zero) z_typ ~error_msg:"Block number should be %R, but got %L") ; unit let () = test_wasm_runtime_id () diff --git a/etherlink/tezt/tests/expected/evm_sequencer.ml/Alpha- Configuration RPC.out b/etherlink/tezt/tests/expected/evm_sequencer.ml/Alpha- Configuration RPC.out index 4206583c3435..a0108d2f556f 100644 --- a/etherlink/tezt/tests/expected/evm_sequencer.ml/Alpha- Configuration RPC.out +++ b/etherlink/tezt/tests/expected/evm_sequencer.ml/Alpha- Configuration RPC.out @@ -15,7 +15,8 @@ "enable_send_raw_transaction": true, "node_transaction_validation": true, "block_storage_sqlite3": true, - "overwrite_simulation_tick_limit": false + "overwrite_simulation_tick_limit": false, + "next_wasm_runtime": false }, "proxy": { "ignore_block_param": false @@ -63,7 +64,8 @@ "enable_send_raw_transaction": true, "node_transaction_validation": true, "block_storage_sqlite3": true, - "overwrite_simulation_tick_limit": false + "overwrite_simulation_tick_limit": false, + "next_wasm_runtime": false }, "proxy": { "ignore_block_param": false @@ -104,7 +106,8 @@ "enable_send_raw_transaction": true, "node_transaction_validation": true, "block_storage_sqlite3": true, - "overwrite_simulation_tick_limit": false + "overwrite_simulation_tick_limit": false, + "next_wasm_runtime": false }, "proxy": { "evm_node_endpoint": "hidden", diff --git a/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- describe config.out b/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- describe config.out index 2a45b70e7adf..c41d3a4ab5e0 100644 --- a/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- describe config.out +++ b/etherlink/tezt/tests/expected/evm_sequencer.ml/EVM Node- describe config.out @@ -138,7 +138,11 @@ { /* Enables garbage collector in the node. */ "split_frequency_in_seconds": integer ∈ [-2^30, 2^30] - /* Frequency of irmin context split in seconds */ } }, + /* Frequency of irmin context split in seconds */ }, + "next_wasm_runtime"?: + boolean + /* Enable or disable the experimental WASM runtime that is expected + to replace the Smart Rollup’s Fast Exec runtime */ }, "proxy"?: { "finalized_view"?: boolean diff --git a/manifest/product_etherlink.ml b/manifest/product_etherlink.ml index d9f9436f38b8..e1423ad2fb58 100644 --- a/manifest/product_etherlink.ml +++ b/manifest/product_etherlink.ml @@ -308,7 +308,6 @@ let _evm_node = octez_sqlite |> open_; evm_node_lib_dev; evm_node_config |> open_; - octez_rust_deps; ] ~bisect_ppx:Yes diff --git a/opam/octez-evm-node.opam b/opam/octez-evm-node.opam index bcc83a609720..f37571ae8215 100644 --- a/opam/octez-evm-node.opam +++ b/opam/octez-evm-node.opam @@ -15,7 +15,6 @@ depends: [ "octez-shell-libs" "octez-l2-libs" "octez-evm-node-libs" { = version } - "octez-rust-deps" ] build: [ ["rm" "-r" "vendors" "contrib"] diff --git a/src/lib_wasm_debugger/wasm_debugger.ml b/src/lib_wasm_debugger/wasm_debugger.ml index 58f38d7475ae..bbb8423f3711 100644 --- a/src/lib_wasm_debugger/wasm_debugger.ml +++ b/src/lib_wasm_debugger/wasm_debugger.ml @@ -56,13 +56,13 @@ module Make (Wasm : Wasm_utils_intf.S) = struct Repl_helpers.trap_exn (fun () -> Tezos_webassembly_interpreter.Import.link module_) - let set_durable_value tree key value = + let set_durable_value ?edit_readonly tree key value = let open Lwt_syntax in let open Tezos_scoru_wasm.Durable in let* durable_storage = Wasm.wrap_as_durable_storage tree in let durable = Tezos_scoru_wasm.Durable.of_storage_exn durable_storage in let key = key_of_string_exn key in - let* durable = set_value_exn durable key value in + let* durable = set_value_exn ?edit_readonly durable key value in let durable_storage = Tezos_scoru_wasm.Durable.to_storage durable in let wrapped_tree = Durable_storage.to_tree_exn durable_storage in Wasm.Tree_encoding_runner.encode diff --git a/src/lib_wasm_runtime/Cargo.lock b/src/lib_wasm_runtime/Cargo.lock index c0bb7c1dabc0..864056edfdcf 100644 --- a/src/lib_wasm_runtime/Cargo.lock +++ b/src/lib_wasm_runtime/Cargo.lock @@ -28,6 +28,27 @@ dependencies = [ "version_check", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.6" @@ -55,6 +76,18 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bitflags" version = "1.3.2" @@ -79,6 +112,33 @@ dependencies = [ "wyz", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -147,6 +207,15 @@ dependencies = [ "windows-sys 0.33.0", ] +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + [[package]] name = "cranelift-bforest" version = "0.91.1" @@ -255,12 +324,82 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8658c15c5d921ddf980f7fe25b1e82f4b7a4083b2c4985fea4922edb8e43e07d" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "cryptoxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382ce8820a5bb815055d3553a610e8cb542b2d767bbacea99038afda96cd760d" + [[package]] name = "cty" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rustc_version", + "subtle", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + [[package]] name = "darling" version = "0.20.10" @@ -308,6 +447,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "der" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" + [[package]] name = "derivative" version = "2.2.0" @@ -319,12 +464,79 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + +[[package]] +name = "ecdsa" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" +dependencies = [ + "der", + "elliptic-curve", + "hmac", + "signature 1.3.2", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "signature 2.2.0", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "sha2 0.10.8", + "subtle", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "elliptic-curve" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83e5c176479da93a0983f0a6fdc3c1b8e7d5be0d7fe3fe05a99f15b96582b9a8" +dependencies = [ + "crypto-bigint", + "ff", + "generic-array", + "group", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "enum-iterator" version = "0.7.0" @@ -372,6 +584,22 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "ff" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "fnv" version = "1.0.7" @@ -402,6 +630,16 @@ dependencies = [ "byteorder", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -430,6 +668,17 @@ version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +[[package]] +name = "group" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -445,6 +694,31 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -498,6 +772,51 @@ version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64", + "digest 0.9.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + [[package]] name = "lock_api" version = "0.4.12" @@ -556,6 +875,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "miniz_oxide" version = "0.8.0" @@ -571,6 +896,45 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", + "serde", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "object" version = "0.36.4" @@ -636,8 +1000,10 @@ dependencies = [ name = "octez-evm-node-wasm-runtime" version = "0.0.0-dev" dependencies = [ + "hex", "ocaml", "ocaml-build", + "tezos_crypto_rs", "wasmer", "wasmer-compiler-cranelift", ] @@ -648,6 +1014,23 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "p256" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186" +dependencies = [ + "ecdsa", + "elliptic-curve", + "sha2 0.9.9", +] + [[package]] name = "parking_lot_core" version = "0.9.10" @@ -661,6 +1044,31 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "parse-display" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7271152b3c46c07c729698e7a5248e2744466b3446d222c97a0b1315925a97b1" +dependencies = [ + "once_cell", + "parse-display-derive", + "regex", +] + +[[package]] +name = "parse-display-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6a9f3e41b237b77c99c09686481c235964ff5878229412b226c451f3e809f4f" +dependencies = [ + "once_cell", + "proc-macro2", + "quote", + "regex", + "regex-syntax 0.6.29", + "syn 1.0.109", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -673,6 +1081,15 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -741,6 +1158,57 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "rand_chacha", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + [[package]] name = "rayon" version = "1.10.0" @@ -782,6 +1250,41 @@ dependencies = [ "smallvec", ] +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + [[package]] name = "region" version = "3.0.2" @@ -839,6 +1342,15 @@ version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + [[package]] name = "scopeguard" version = "1.2.0" @@ -851,6 +1363,12 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + [[package]] name = "serde" version = "1.0.210" @@ -882,12 +1400,52 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signature" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" +dependencies = [ + "digest 0.9.0", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" + [[package]] name = "simdutf8" version = "0.1.5" @@ -912,6 +1470,30 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "strum" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" + +[[package]] +name = "strum_macros" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8bc6b87a5112aeeab1f4a9f7ab634fe6cbefc4850006df31267f4cfb9e3149" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.109" @@ -946,6 +1528,64 @@ version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" +[[package]] +name = "tezos_crypto_rs" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8954f27b00228b1fc669cddfa0e604a40adc5ee443002d3d31abdea0b911fcb6" +dependencies = [ + "anyhow", + "bs58", + "byteorder", + "cryptoxide", + "ed25519-dalek", + "hex", + "libsecp256k1", + "nom", + "num-bigint", + "num-traits", + "p256", + "rand 0.7.3", + "serde", + "strum", + "strum_macros", + "tezos_data_encoding", + "thiserror", + "zeroize", +] + +[[package]] +name = "tezos_data_encoding" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1fff433d41c778d27df21b91e766e182b05d9a7c1331e1156ee081273d704a4" +dependencies = [ + "bit-vec", + "bitvec", + "hex", + "lazy_static", + "nom", + "num-bigint", + "num-traits", + "serde", + "tezos_data_encoding_derive", + "thiserror", +] + +[[package]] +name = "tezos_data_encoding_derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f614c81c10c1ac47fdb792ce23e928591fca685d534260e073f83bc5d5f080e0" +dependencies = [ + "lazy_static", + "once_cell", + "parse-display", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "thiserror" version = "1.0.64" @@ -1012,6 +1652,12 @@ dependencies = [ "once_cell", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -1034,10 +1680,10 @@ dependencies = [ ] [[package]] -name = "unicode-width" -version = "0.1.14" +name = "unicode-segmentation" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "url" @@ -1146,15 +1792,6 @@ version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" -[[package]] -name = "wasm-encoder" -version = "0.217.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b88b0814c9a2b323a9b46c687e726996c255ac8b64aa237dd11c81ed4854760" -dependencies = [ - "leb128", -] - [[package]] name = "wasmer" version = "3.3.0" @@ -1177,7 +1814,6 @@ dependencies = [ "wasmer-derive", "wasmer-types", "wasmer-vm", - "wat", "winapi", ] @@ -1278,28 +1914,6 @@ dependencies = [ "url", ] -[[package]] -name = "wast" -version = "217.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79004ecebded92d3c710d4841383368c7f04b63d0992ddd6b0c7d5029b7629b7" -dependencies = [ - "bumpalo", - "leb128", - "memchr", - "unicode-width", - "wasm-encoder", -] - -[[package]] -name = "wat" -version = "1.217.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c126271c3d92ca0f7c63e4e462e40c69cca52fd4245fcda730d1cf558fb55088" -dependencies = [ - "wast", -] - [[package]] name = "winapi" version = "0.3.9" @@ -1446,3 +2060,30 @@ checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" diff --git a/src/lib_wasm_runtime/Cargo.toml b/src/lib_wasm_runtime/Cargo.toml index b564de3e7432..5eba89eae01d 100644 --- a/src/lib_wasm_runtime/Cargo.toml +++ b/src/lib_wasm_runtime/Cargo.toml @@ -8,6 +8,8 @@ edition = "2021" ocaml-build = { version = "1.*", features = ["dune"] } [dependencies] +hex = "*" ocaml = { version = "1.*" } -wasmer = { path = "../../src/rust_deps/wasmer-3.3.0/lib/api", features = [] } +wasmer = { path = "../../src/rust_deps/wasmer-3.3.0/lib/api", default-features = false, features = ["cranelift", "jit"] } wasmer-compiler-cranelift = { path = "../../src/rust_deps/wasmer-3.3.0/lib/compiler-cranelift" } +tezos_crypto_rs = { version = "0.6", default-features = false } diff --git a/src/lib_wasm_runtime/ocaml-api/evm_node_wasm_runtime.ml b/src/lib_wasm_runtime/ocaml-api/evm_node_wasm_runtime.ml index 0572ac0f1eef..8365e0a948b7 100644 --- a/src/lib_wasm_runtime/ocaml-api/evm_node_wasm_runtime.ml +++ b/src/lib_wasm_runtime/ocaml-api/evm_node_wasm_runtime.ml @@ -8,3 +8,6 @@ let () = Wasm_runtime_callbacks.register () include Wasm_runtime_gen + +let wasm_runtime_run ~preimages_dir ~entrypoint ctxt = + wasm_runtime_run ctxt preimages_dir entrypoint diff --git a/src/lib_wasm_runtime/ocaml-api/evm_node_wasm_runtime.mli b/src/lib_wasm_runtime/ocaml-api/evm_node_wasm_runtime.mli index 1a7b4fbf8fee..10fadd9dddbb 100644 --- a/src/lib_wasm_runtime/ocaml-api/evm_node_wasm_runtime.mli +++ b/src/lib_wasm_runtime/ocaml-api/evm_node_wasm_runtime.mli @@ -5,9 +5,16 @@ (* *) (*****************************************************************************) -(** [id tree] is the identity function, returning [tree] untouched. +type context - It will be removed in a later version, but is introduced temporarily to - prove the library is working. *) -external wasm_runtime_id : Irmin_context.tree -> Irmin_context.tree - = "wasm_runtime_id" +external wasm_runtime_new_context : unit -> context = "wasm_runtime_new_context" + +val wasm_runtime_run : + preimages_dir:string -> + entrypoint:string -> + context -> + Irmin_context.tree -> + bytes -> + int32 -> + string list -> + Irmin_context.tree diff --git a/src/lib_wasm_runtime/ocaml-api/wasm_runtime_gen.ml b/src/lib_wasm_runtime/ocaml-api/wasm_runtime_gen.ml index c542b3f42d85..c1655e15ed2c 100644 --- a/src/lib_wasm_runtime/ocaml-api/wasm_runtime_gen.ml +++ b/src/lib_wasm_runtime/ocaml-api/wasm_runtime_gen.ml @@ -4,4 +4,6 @@ open! Bigarray (* file: api.rs *) -external wasm_runtime_id: Irmin_context.tree -> Irmin_context.tree = "wasm_runtime_id" +type context +external wasm_runtime_new_context: unit -> context = "wasm_runtime_new_context" +external wasm_runtime_run: context -> string -> string -> Irmin_context.tree -> bytes -> int32 -> string list -> Irmin_context.tree = "wasm_runtime_run_bytecode" "wasm_runtime_run" diff --git a/src/lib_wasm_runtime/ocaml-api/wasm_runtime_gen.mli b/src/lib_wasm_runtime/ocaml-api/wasm_runtime_gen.mli index c542b3f42d85..c1655e15ed2c 100644 --- a/src/lib_wasm_runtime/ocaml-api/wasm_runtime_gen.mli +++ b/src/lib_wasm_runtime/ocaml-api/wasm_runtime_gen.mli @@ -4,4 +4,6 @@ open! Bigarray (* file: api.rs *) -external wasm_runtime_id: Irmin_context.tree -> Irmin_context.tree = "wasm_runtime_id" +type context +external wasm_runtime_new_context: unit -> context = "wasm_runtime_new_context" +external wasm_runtime_run: context -> string -> string -> Irmin_context.tree -> bytes -> int32 -> string list -> Irmin_context.tree = "wasm_runtime_run_bytecode" "wasm_runtime_run" diff --git a/src/lib_wasm_runtime/rust-toolchain b/src/lib_wasm_runtime/rust-toolchain new file mode 100644 index 000000000000..1f3171c78fd2 --- /dev/null +++ b/src/lib_wasm_runtime/rust-toolchain @@ -0,0 +1 @@ +1.76.0 \ No newline at end of file diff --git a/src/lib_wasm_runtime/src/api.rs b/src/lib_wasm_runtime/src/api.rs index 2b92b8332da2..700a4461235d 100644 --- a/src/lib_wasm_runtime/src/api.rs +++ b/src/lib_wasm_runtime/src/api.rs @@ -1,9 +1,133 @@ // SPDX-FileCopyrightText: 2024 Nomadic Labs -use crate::types::EvmTree; +//! Module containing the types and functions exposed to OCaml. + +use crate::{ + bindings, + host::Host, + runtime::{self, InputsBuffer, RunStatus}, + types::{ContextHash, EvmTree, OCamlString, SmartRollupAddress}, +}; +use ocaml::{Error, List, Pointer, Value}; +use std::collections::BTreeMap; +use wasmer::{Engine, Features, Module, NativeEngineExt, Store, Target}; +use wasmer_compiler_cranelift::Cranelift; + +pub struct Kernel(Module); + +impl Kernel { + pub fn new(engine: &Engine, code: &[u8]) -> Result { + let store = Store::new(engine.clone()); + let module = Module::new(&store, code)?; + Ok(Kernel(module)) + } + + pub fn as_ref(&self) -> &Module { + &self.0 + } +} + +pub struct KernelsCache(BTreeMap<[u8; 32], Kernel>); + +impl KernelsCache { + pub fn new() -> Self { + KernelsCache(BTreeMap::new()) + } + + pub fn miss(&self, hash: &ContextHash) -> bool { + !self.0.contains_key(hash.as_bytes()) + } + + pub fn get(&self, hash: &ContextHash) -> &Kernel { + self.0.get(hash.as_bytes()).unwrap() + } + pub fn insert(&mut self, hash: &ContextHash, kernel: Kernel) { + self.0.insert(hash.as_bytes().to_owned(), kernel); + } + + pub fn load(&mut self, engine: &Engine, evm_tree: &EvmTree) -> Result<&Kernel, Error> { + const KERNEL_PATH: &'static str = "/kernel/boot.wasm"; + let hash = bindings::store_get_hash(evm_tree, &KERNEL_PATH)?; + + if self.miss(&hash) { + let code = bindings::read_value(&evm_tree, KERNEL_PATH)?; + let kernel = Kernel::new(engine, code.as_bytes())?; + let _previous = self.insert(&hash, kernel); + } + + Ok(self.get(&hash)) + } +} + +#[ocaml::sig] +pub struct Context { + engine: Engine, + kernels_cache: KernelsCache, +} + +ocaml::custom!(Context); + +impl Context { + pub fn new() -> Self { + let mut features = Features::new(); + features + .bulk_memory(false) + .memory64(false) + .module_linking(false) + .multi_memory(false) + .multi_value(false) + .reference_types(true) + .simd(true) + .tail_call(false) + .threads(false); + + let config = Cranelift::new(); + let engine = NativeEngineExt::new(Box::new(config), Target::default(), features); + + Context { + engine, + kernels_cache: KernelsCache::new(), + } + } +} + +#[ocaml::func] +#[ocaml::sig("unit -> context")] +pub fn wasm_runtime_new_context() -> Pointer { + Pointer::alloc_custom(Context::new()) +} #[ocaml::func] -#[ocaml::sig("Irmin_context.tree -> Irmin_context.tree")] -pub fn wasm_runtime_id(evm_tree: EvmTree) -> EvmTree { - evm_tree +#[ocaml::sig( + "context -> string -> string -> Irmin_context.tree -> bytes -> int32 -> string list -> Irmin_context.tree" +)] +pub fn wasm_runtime_run( + mut ctxt: Pointer, + preimages_dir: OCamlString, + entrypoint: OCamlString, + mut tree: EvmTree, + rollup_address: SmartRollupAddress, + level: u32, + inputs: List, +) -> Result { + let ctxt = ctxt.as_mut(); + let mut inputs_buffer = InputsBuffer::new(level, inputs.into_vec()); + + loop { + let host = Host::new(&tree, rollup_address, inputs_buffer, preimages_dir.clone()); + let mut runtime = runtime::load_runtime( + &ctxt.engine, + &mut ctxt.kernels_cache, + host, + entrypoint.as_str(), + )?; + + match runtime.run()? { + RunStatus::Done(evm_tree) => return Ok(evm_tree), + RunStatus::PendingKernelUpgrade(new_tree, remaining_inputs) => { + tree = new_tree; + inputs_buffer = remaining_inputs; + } + } + } } diff --git a/src/lib_wasm_runtime/src/bindings.rs b/src/lib_wasm_runtime/src/bindings.rs new file mode 100644 index 000000000000..ff0a1104a84d --- /dev/null +++ b/src/lib_wasm_runtime/src/bindings.rs @@ -0,0 +1,226 @@ +// SPDX-FileCopyrightText: 2024 Nomadic Labs + +//! Collections of functions exposed from OCaml and allowing Rust functions to interact with the +//! state manipulated by the kernel. + +use crate::types::{ContextHash, EvmTree, OCamlBytes}; +use std::{ + error::Error, + fmt::{Display, Formatter}, +}; + +pub trait Key { + fn as_str(&self) -> &str; +} + +impl Key for T +where + T: AsRef<[u8]>, +{ + fn as_str(&self) -> &str { + unsafe { std::str::from_utf8_unchecked(self.as_ref()) } + } +} + +#[derive(Debug)] +pub enum BindingsError { + HostFuncError(i32), + OCamlError(ocaml::Error), +} + +impl Display for BindingsError { + fn fmt(&self, f: &mut Formatter) -> std::fmt::Result { + match self { + Self::HostFuncError(err) => write!(f, "host func error: {}", err), + Self::OCamlError(err) => write!(f, "ocaml error: {:?}", err), + } + } +} + +impl Error for BindingsError {} + +#[allow(non_snake_case)] +mod ocaml_imports { + use crate::types::{ContextHash, EvmTree, OCamlBytes}; + + ocaml::import! { + pub fn layer2_store__read_durable_value(evm_tree: EvmTree, key: &str) -> Result; + pub fn layer2_store__mem_tree(evm_tree: EvmTree, key: &str) -> Result; + pub fn layer2_store__check_reboot_flag(evm_tree: EvmTree) -> (bool, EvmTree); + + pub fn layer2_store__store_get_hash(evm_tree: EvmTree, key: &str) -> Result; + pub fn layer2_store__store_delete(evm_tree: EvmTree, key: &str, is_value: bool) -> Result; + pub fn layer2_store__store_has(evm_tree: EvmTree, key: &str) -> Result; + pub fn layer2_store__store_copy(evm_tree: EvmTree, from: &str, to: &str) -> Result; + pub fn layer2_store__store_move(evm_tree: EvmTree, from: &str, to: &str) -> Result; + pub fn layer2_store__store_list_size(evm_tree: EvmTree, key: &str) -> Result; + pub fn layer2_store__store_value_size(evm_tree: EvmTree, key: &str) -> Result; + pub fn layer2_store__store_read(evm_tree: EvmTree, key: &str, offset: usize, num_bytes: usize) -> Result; + pub fn layer2_store__store_write(evm_tree: EvmTree, key: &str, offset: usize, bytes: &[u8]) -> Result<(EvmTree, isize), isize>; + } +} + +fn gc() -> ocaml::Runtime { + ocaml::Runtime::init() +} + +pub fn store_get_hash(evm_tree: &EvmTree, key: K) -> Result +where + K: Key, +{ + let res = unsafe { + ocaml_imports::layer2_store__store_get_hash(&gc(), evm_tree.clone(), key.as_str()) + .map_err(BindingsError::OCamlError)? + }; + + res.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn read_value(evm_tree: &EvmTree, key: K) -> Result +where + K: Key, +{ + let code = unsafe { + ocaml_imports::layer2_store__read_durable_value(&gc(), evm_tree.clone(), key.as_str()) + .map_err(BindingsError::OCamlError)? + }; + + code.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn mem_tree(evm_tree: &EvmTree, key: K) -> Result +where + K: Key, +{ + let mem = unsafe { + ocaml_imports::layer2_store__mem_tree(&gc(), evm_tree.clone(), key.as_str()) + .map_err(BindingsError::OCamlError)? + }; + + mem.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn store_has(evm_tree: &EvmTree, key: K) -> Result +where + K: Key, +{ + let mem = unsafe { + ocaml_imports::layer2_store__store_has(&gc(), evm_tree.clone(), key.as_str()) + .map_err(BindingsError::OCamlError)? + }; + + mem.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn store_delete(evm_tree: &EvmTree, key: K, is_value: bool) -> Result +where + K: Key, +{ + let mem = unsafe { + ocaml_imports::layer2_store__store_delete(&gc(), evm_tree.clone(), key.as_str(), is_value) + .map_err(BindingsError::OCamlError)? + }; + + mem.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn store_copy(evm_tree: &EvmTree, from: K, to: K) -> Result +where + K: Key, +{ + let res = unsafe { + ocaml_imports::layer2_store__store_copy(&gc(), evm_tree.clone(), from.as_str(), to.as_str()) + .map_err(BindingsError::OCamlError)? + }; + + res.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn store_move(evm_tree: &EvmTree, from: K, to: K) -> Result +where + K: Key, +{ + let res = unsafe { + ocaml_imports::layer2_store__store_copy(&gc(), evm_tree.clone(), from.as_str(), to.as_str()) + .map_err(BindingsError::OCamlError)? + }; + + res.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn store_list_size(evm_tree: &EvmTree, key: K) -> Result +where + K: Key, +{ + let res = unsafe { + ocaml_imports::layer2_store__store_list_size(&gc(), evm_tree.clone(), key.as_str()) + .map_err(BindingsError::OCamlError)? + }; + + res.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn store_value_size(evm_tree: &EvmTree, key: K) -> Result +where + K: Key, +{ + let res = unsafe { + ocaml_imports::layer2_store__store_value_size(&gc(), evm_tree.clone(), key.as_str()) + .map_err(BindingsError::OCamlError)? + }; + + res.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn store_read( + evm_tree: &EvmTree, + key: K, + offset: usize, + num_bytes: usize, +) -> Result +where + K: Key, +{ + let res = unsafe { + ocaml_imports::layer2_store__store_read( + &gc(), + evm_tree.clone(), + key.as_str(), + offset, + num_bytes, + ) + .map_err(BindingsError::OCamlError)? + }; + + res.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn store_write( + evm_tree: &EvmTree, + key: K, + offset: usize, + bytes: &[u8], +) -> Result<(EvmTree, isize), BindingsError> +where + K: Key, +{ + let res = unsafe { + ocaml_imports::layer2_store__store_write( + &gc(), + evm_tree.clone(), + key.as_str(), + offset, + bytes, + ) + .map_err(BindingsError::OCamlError)? + }; + + res.map_err(|i| BindingsError::HostFuncError(i as i32)) +} + +pub fn check_reboot_flag(evm_tree: &EvmTree) -> Result<(bool, EvmTree), BindingsError> { + unsafe { + ocaml_imports::layer2_store__check_reboot_flag(&gc(), evm_tree.clone()) + .map_err(BindingsError::OCamlError) + } +} diff --git a/src/lib_wasm_runtime/src/host.rs b/src/lib_wasm_runtime/src/host.rs new file mode 100644 index 000000000000..86cf63a8c541 --- /dev/null +++ b/src/lib_wasm_runtime/src/host.rs @@ -0,0 +1,126 @@ +// SPDX-FileCopyrightText: 2024 Nomadic Labs + +//! Low-level interactions with the persistent state manipulated by the kernel +//! (starting with the durable storage). + +use std::collections::VecDeque; + +use ocaml::Error; + +use crate::{ + bindings, + types::{EvmTree, OCamlString, SmartRollupAddress}, +}; + +#[derive(Clone)] +pub struct InputsBuffer { + inputs: VecDeque>, + level: u32, + next_message: u32, +} + +pub struct Input { + pub level: u32, + pub index: u32, + pub payload: Vec, +} + +impl InputsBuffer { + pub fn new(level: u32, inputs: Vec) -> Self { + InputsBuffer { + inputs: inputs + .into_iter() + .map(|x| x.as_bytes().to_owned()) + .collect(), + level, + next_message: 0, + } + } + + pub fn next_input(&mut self) -> Option { + self.inputs.pop_front().map(|payload| { + let res = Input { + level: self.level, + index: self.next_message, + payload, + }; + self.next_message += 1; + res + }) + } +} + +pub struct Host { + inputs_buffer: InputsBuffer, + tree: EvmTree, + rollup_address: SmartRollupAddress, + needs_kernel_reload: bool, + preimages_dir: OCamlString, +} + +impl Host { + pub fn new( + tree: &EvmTree, + rollup_address: SmartRollupAddress, + inputs_buffer: InputsBuffer, + preimages_dir: OCamlString, + ) -> Self { + Host { + inputs_buffer, + tree: tree.clone(), + rollup_address, + needs_kernel_reload: false, + preimages_dir, + } + } + + pub fn preimages_dir(&self) -> &str { + self.preimages_dir.as_str() + } + + pub fn request_kernel_reload(&mut self) { + self.needs_kernel_reload = true; + } + + pub fn needs_kernel_reload(&self) -> bool { + self.needs_kernel_reload + } + + pub fn rollup_address(&self) -> &SmartRollupAddress { + &self.rollup_address + } + + pub fn tree(&self) -> &EvmTree { + &self.tree + } + + pub fn set_tree(&mut self, evm_tree: EvmTree) { + self.tree = evm_tree; + } + + pub fn write_debug(&self, msg: &[u8]) { + print!("{}", String::from_utf8_lossy(msg)) + } + + pub fn next_input(&mut self) -> Option { + self.inputs_buffer.next_input() + } + + pub fn inputs_buffer(&self) -> &InputsBuffer { + &self.inputs_buffer + } + + pub fn reboot_requested(&mut self) -> Result { + let (reboot, evm_tree) = bindings::check_reboot_flag(&self.tree)?; + self.tree = evm_tree; + + Ok(reboot) + } + + pub fn create_reboot_flag(&mut self) -> Result<(), Error> { + let (evm_tree, _) = bindings::store_write(&self.tree, "/kernel/env/reboot", 0, &[])?; + self.tree = evm_tree; + + Ok(()) + } +} diff --git a/src/lib_wasm_runtime/src/lib.rs b/src/lib_wasm_runtime/src/lib.rs index eaaf49a899d7..d45399ac41ed 100644 --- a/src/lib_wasm_runtime/src/lib.rs +++ b/src/lib_wasm_runtime/src/lib.rs @@ -1,4 +1,7 @@ // SPDX-FileCopyrightText: 2024 Nomadic Labs pub mod api; +mod bindings; +mod host; +mod runtime; mod types; diff --git a/src/lib_wasm_runtime/src/runtime/env.rs b/src/lib_wasm_runtime/src/runtime/env.rs new file mode 100644 index 000000000000..2f089f70bcbf --- /dev/null +++ b/src/lib_wasm_runtime/src/runtime/env.rs @@ -0,0 +1,50 @@ +// SPDX-FileCopyrightText: 2024 Nomadic Labs + +//! State manipulated by the host functions (for kernels executed with Wasmer). + +use wasmer::Memory; + +use crate::host::Host; + +pub struct Env { + memory: Option, + host: Host, +} + +// `Env` implementing `Send` is a requirement from Wasmer to wrap it in a `FunctionEnv`. +// This way, instances created by Wasmer are thread-safe out of the box. +// +// It turns out, we don’t need to be thread-safe because +// - Wasmer executes WASM programs in the thread it is started +// - We don’t have a multi-threaded kernel +// +// Sadly, there is not an alternative version of `FunctionEnv` that reflects this use case. +// Instead, we declare `Env` thread, and it is safe as long as no threads are thrown in the mix. +// +// Note: The only reason why `Env` is not thread safe is because `EvmTree` is a wrapper around an +// OCaml `Value`. But this `Value` has no reason to be garbaged collected because it always comes +// from an OCaml function calling our Rust WASM Runtime, and keeping a reference to this EVM tree +// until the WASM runtime returns. +unsafe impl Send for Env {} + +impl Env { + pub fn new(host: Host) -> Self { + Env { memory: None, host } + } + + pub fn host(&self) -> &Host { + &self.host + } + + pub fn mut_host(&mut self) -> &mut Host { + &mut self.host + } + + pub fn set_memory(&mut self, memory: &Memory) { + self.memory = Some(memory.clone()) + } + + pub fn memory(&self) -> &Memory { + self.memory.as_ref().unwrap() + } +} diff --git a/src/lib_wasm_runtime/src/runtime/host_funcs.rs b/src/lib_wasm_runtime/src/runtime/host_funcs.rs new file mode 100644 index 000000000000..739da9af7318 --- /dev/null +++ b/src/lib_wasm_runtime/src/runtime/host_funcs.rs @@ -0,0 +1,456 @@ +// SPDX-FileCopyrightText: 2024 Nomadic Labs + +//! Implementations of the host functions defined by the PVM, and used by the kernel when executed +//! with Wasmer. + +use std::{fs, path::PathBuf}; + +use crate::bindings::{self, BindingsError}; + +use super::env::Env; +use tezos_crypto_rs::blake2b; +use wasmer::{ + imports, AsStoreRef, Function, FunctionEnv, FunctionEnvMut, Imports, MemoryView, RuntimeError, + Store, +}; + +#[allow(dead_code)] +mod error_code { + pub const STORE_KEY_TOO_LARGE: i32 = -1; + pub const STORE_INVALID_KEY: i32 = -2; + pub const STORE_NOT_A_VALUE: i32 = -3; + pub const STORE_INVALID_ACCESS: i32 = -4; + pub const STORE_VALUE_SIZE_EXCEEDED: i32 = -5; + pub const MEMORY_INVALID_ACCESS: i32 = -6; + pub const INPUT_OUTPUT_TOO_LARGE: i32 = -7; + pub const GENERIC_INVALID_ACCESS: i32 = -8; + pub const STORE_READONLY_VALUE: i32 = -9; + pub const STORE_NOT_A_NODE: i32 = -10; + pub const FULL_OUTBOX: i32 = -11; + pub const STORE_INVALID_SUBKEY_INDEX: i32 = -12; + pub const STORE_VALUE_ALREADY_EXISTS: i32 = -13; +} + +const INPUT_OUTPUT_MAX_SIZE: u32 = 4096; + +fn result_from_binding_error(err: BindingsError) -> Result { + match err { + BindingsError::HostFuncError(i) => Ok(i), + BindingsError::OCamlError(err) => Err(RuntimeError::new(format!( + "unexpected internal error: {:?}", + err + ))), + } +} + +fn i64_result_from_binding_error(err: BindingsError) -> Result { + match err { + BindingsError::HostFuncError(i) => Ok(i as i64), + BindingsError::OCamlError(_) => Err(RuntimeError::new("unexpected error")), + } +} + +fn read_from_memory(memory_view: &MemoryView, ptr: u32, len: u32) -> Result, RuntimeError> { + // TODO: Can we get a slice from `read_from_memory`? + let mut buffer = vec![0u8; len as usize]; + memory_view.read(ptr.into(), &mut buffer)?; + + Ok(buffer) +} + +fn write_debug(env: FunctionEnvMut, ptr: u32, length: u32) -> Result<(), RuntimeError> { + let store = env.as_store_ref(); + let runtime_env = env.data(); + let memory = runtime_env.memory(); + + let buffer = read_from_memory(&memory.view(&store), ptr, length)?; + + runtime_env.host().write_debug(&buffer); + + Ok(()) +} + +fn write_output(_env: FunctionEnvMut, _ptr: u32, length: u32) -> i32 { + // The EVM node has little reason to emulate the `write_output` host function, because it is + // only useful as part of the native bridge (i.e., as part of a published state). We do have to + // perform the sanity checks to deal with errors, though. + // + // We assume the kernel is implemented in safe Rust, and that memory safety is enforced by the + // compiler. This only leaves us the limit on the size of the input. + if length > INPUT_OUTPUT_MAX_SIZE { + return error_code::INPUT_OUTPUT_TOO_LARGE; + } + + return 0; +} + +fn read_input(mut env: FunctionEnvMut, info_addr: u32, dst: u32, max_bytes: u32) -> i32 { + let (runtime_env, store) = env.data_and_store_mut(); + + match runtime_env.mut_host().next_input() { + Some(input) => { + let memory = runtime_env.memory(); + let to_write = std::cmp::min(max_bytes as usize, input.payload.len()); + let memory_view = memory.view(&store); + + // No need to do sanity check if we assume Rust is a memory-safe language. + memory_view + .write(dst as u64, &input.payload[..to_write]) + .expect("memory bounds were checked"); + memory_view + .write(info_addr as u64, &input.level.to_le_bytes()) + .expect("memory bounds were checked"); + memory_view + .write(info_addr as u64 + 4, &input.index.to_le_bytes()) + .expect("memory bounds were checked"); + + to_write as i32 + } + None => 0, + } +} + +fn store_exists(env: FunctionEnvMut, key_ptr: u32, key_len: u32) -> Result { + let store = env.as_store_ref(); + let runtime_env = env.data(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let key = read_from_memory(&memory_view, key_ptr, key_len)?; + + match bindings::mem_tree(&runtime_env.host().tree(), key) { + Ok(true) => Ok(1), + Ok(false) => Ok(0), + Err(err) => result_from_binding_error(err), + } +} + +fn store_has(env: FunctionEnvMut, key_ptr: u32, key_len: u32) -> Result { + let store = env.as_store_ref(); + let runtime_env = env.data(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let key = read_from_memory(&memory_view, key_ptr, key_len)?; + + match bindings::store_has(&runtime_env.host().tree(), key) { + Ok(i) => Ok(i as i32), + Err(err) => result_from_binding_error(err), + } +} + +fn store_delete( + mut env: FunctionEnvMut, + key_ptr: u32, + key_len: u32, +) -> Result { + let (runtime_env, store) = env.data_and_store_mut(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let key = read_from_memory(&memory_view, key_ptr, key_len)?; + + match bindings::store_delete(&runtime_env.host().tree(), key, false) { + Ok(evm_tree) => { + runtime_env.mut_host().set_tree(evm_tree); + Ok(0) + } + Err(err) => result_from_binding_error(err), + } +} + +fn store_delete_value( + mut env: FunctionEnvMut, + key_ptr: u32, + key_len: u32, +) -> Result { + let (runtime_env, store) = env.data_and_store_mut(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let key = read_from_memory(&memory_view, key_ptr, key_len)?; + + match bindings::store_delete(&runtime_env.host().tree(), key, true) { + Ok(evm_tree) => { + runtime_env.mut_host().set_tree(evm_tree); + Ok(0) + } + Err(err) => result_from_binding_error(err), + } +} + +fn store_copy( + mut env: FunctionEnvMut, + from_ptr: u32, + from_len: u32, + to_ptr: u32, + to_len: u32, +) -> Result { + let (runtime_env, store) = env.data_and_store_mut(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let from = read_from_memory(&memory_view, from_ptr, from_len)?; + let to = read_from_memory(&memory_view, to_ptr, to_len)?; + + match bindings::store_copy(&runtime_env.host().tree(), from, to) { + Ok(evm_tree) => { + runtime_env.mut_host().set_tree(evm_tree); + Ok(0) + } + Err(err) => result_from_binding_error(err), + } +} + +fn store_move( + mut env: FunctionEnvMut, + from_ptr: u32, + from_len: u32, + to_ptr: u32, + to_len: u32, +) -> Result { + let (runtime_env, store) = env.data_and_store_mut(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let from = read_from_memory(&memory_view, from_ptr, from_len)?; + let to = read_from_memory(&memory_view, to_ptr, to_len)?; + + match bindings::store_move(&runtime_env.host().tree(), from, to) { + Ok(evm_tree) => { + runtime_env.mut_host().set_tree(evm_tree); + Ok(0) + } + Err(err) => result_from_binding_error(err), + } +} + +fn store_get_hash( + env: FunctionEnvMut, + key_ptr: u32, + key_len: u32, + dst_ptr: u32, + max_size: u32, +) -> Result { + let store = env.as_store_ref(); + let runtime_env = env.data(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let key = read_from_memory(&memory_view, key_ptr, key_len)?; + + match bindings::store_get_hash(&runtime_env.host().tree(), &key) { + Ok(hash) => { + let hash_bytes = hash.as_bytes(); + let to_write = std::cmp::min(hash_bytes.len(), max_size as usize); + memory_view.write(dst_ptr as u64, &hash_bytes[..to_write])?; + Ok(to_write as i32) + } + Err(err) => result_from_binding_error(err), + } +} + +fn store_list_size( + env: FunctionEnvMut, + key_ptr: u32, + key_len: u32, +) -> Result { + let store = env.as_store_ref(); + let runtime_env = env.data(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let key = read_from_memory(&memory_view, key_ptr, key_len)?; + + match bindings::store_list_size(&runtime_env.host().tree(), key) { + Ok(res) => Ok(res as i64), + Err(err) => i64_result_from_binding_error(err), + } +} + +fn store_value_size( + env: FunctionEnvMut, + key_ptr: u32, + key_len: u32, +) -> Result { + let store = env.as_store_ref(); + let runtime_env = env.data(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let key = read_from_memory(&memory_view, key_ptr, key_len)?; + + match bindings::store_value_size(&runtime_env.host().tree(), key) { + Ok(res) => Ok(res as i32), + Err(err) => result_from_binding_error(err), + } +} + +fn store_read( + mut env: FunctionEnvMut, + key_ptr: u32, + key_len: u32, + offset: u32, + dst_ptr: u32, + max_bytes: u32, +) -> Result { + let (runtime_env, store) = env.data_and_store_mut(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let key = read_from_memory(&memory_view, key_ptr, key_len)?; + + match bindings::store_read( + runtime_env.host().tree(), + key, + offset as usize, + max_bytes as usize, + ) { + Ok(buffer) => { + memory_view.write(dst_ptr as u64, buffer.as_bytes())?; + Ok(max_bytes as i32) + } + Err(err) => result_from_binding_error(err), + } +} + +fn store_write( + mut env: FunctionEnvMut, + key_ptr: u32, + key_len: u32, + offset: u32, + src_ptr: u32, + src_len: u32, +) -> Result { + let (runtime_env, store) = env.data_and_store_mut(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let key = read_from_memory(&memory_view, key_ptr, key_len)?; + let buffer = read_from_memory(&memory_view, src_ptr, src_len)?; + + match bindings::store_write(runtime_env.host().tree(), key, offset as usize, &buffer) { + Ok((evm_tree, res)) => { + runtime_env.mut_host().set_tree(evm_tree); + Ok(res as i32) + } + Err(err) => result_from_binding_error(err), + } +} + +fn reveal_metadata( + mut env: FunctionEnvMut, + dst_ptr: u32, + max_bytes: u32, +) -> Result { + let (runtime_env, store) = env.data_and_store_mut(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + // The metadata result consists in (1) the rollup address, and (2) the origination level. + // Etherlink kernel has no use for the origination level, so we default to the same behavior as + // the WASM Debugger (that is, `origination_level = 0l`). + + let address = runtime_env.host().rollup_address(); + let metadata_size = address.as_bytes().len() + core::mem::size_of::(); + let to_write = std::cmp::min(metadata_size, max_bytes as usize); + let address_to_write = std::cmp::min(address.as_bytes().len(), max_bytes as usize); + let level_to_write = to_write - address_to_write; + + memory_view.write(dst_ptr as u64, &address.as_bytes()[..address_to_write])?; + + if level_to_write > 0 { + memory_view.write( + dst_ptr as u64 + address.as_bytes().len() as u64, + &vec![0u8; level_to_write], + )?; + } + + Ok(to_write as i32) +} + +fn reveal_preimage( + mut env: FunctionEnvMut, + hash_ptr: u32, + hash_len: u32, + dst_ptr: u32, + max_bytes: u32, +) -> Result { + let (runtime_env, store) = env.data_and_store_mut(); + let memory = runtime_env.memory(); + let memory_view = memory.view(&store); + + let hash_bytes = read_from_memory(&memory_view, hash_ptr, hash_len)?; + let hash_hex = hex::encode(&hash_bytes); + + if hash_bytes[0] != 0u8 { + return Err(RuntimeError::new(format!( + "unsupported hash scheme for {} (only blake2b preimages are supposed to be used)", + hash_hex + ))); + } + + let mut path = PathBuf::from(runtime_env.host().preimages_dir()); + path.push(&hash_hex); + + let res = fs::read(path).map_err(|io_err| { + RuntimeError::new(format!( + "error when trying to load preimage {}: {}", + hash_hex, io_err + )) + })?; + + if !blake2b::digest_256(&res).eq(&hash_bytes[1..]) { + return Err(RuntimeError::new(format!( + "preimage for {} is corrupted", + hash_hex + ))); + } + + let to_write = std::cmp::min(res.len(), max_bytes as usize); + memory_view.write(dst_ptr as u64, &res[..to_write])?; + + // The only use case we have for revealing a preimage in the kernel at the moment is upgrading + // the kernel. So after a `kernel_run` call that used `reveal_preimage`, we will need to start + // using the new kernel. This is what this function call signals. + runtime_env.mut_host().request_kernel_reload(); + + Ok(res.len() as i32) +} + +fn reveal( + _env: FunctionEnvMut, + _payload_addr: u32, + _payload_size: u32, + _dst_ptr: u32, + _max_bytes: u32, +) -> Result { + // TODO: https://gitlab.com/tezos/tezos/-/issues/7532 + // We don’t support the `reveal` host function because it is not an immediate requirement of + // Etherlink, but it is required to enable the WASM Runtime with DAL+Etherlink. + todo!("reveal") +} + +pub fn imports(store: &mut Store, env: &FunctionEnv) -> Imports { + imports! { + "smart_rollup_core" => { + "write_debug" => Function::new_typed_with_env(store, env, write_debug), + "write_output" => Function::new_typed_with_env(store, env, write_output), + "read_input" => Function::new_typed_with_env(store, env, read_input), + "store_exists" => Function::new_typed_with_env(store, env, store_exists), + "store_has" => Function::new_typed_with_env(store, env, store_has), + "store_delete" => Function::new_typed_with_env(store, env, store_delete), + "store_delete_value" => Function::new_typed_with_env(store, env, store_delete_value), + "store_copy" => Function::new_typed_with_env(store, env, store_copy), + "store_move" => Function::new_typed_with_env(store, env, store_move), + "store_list_size" => Function::new_typed_with_env(store, env, store_list_size), + "store_value_size" => Function::new_typed_with_env(store, env, store_value_size), + "store_read" => Function::new_typed_with_env(store, env, store_read), + "store_write" => Function::new_typed_with_env(store, env, store_write), + "reveal_metadata" => Function::new_typed_with_env(store, env, reveal_metadata), + "reveal_preimage" => Function::new_typed_with_env(store, env, reveal_preimage), + "reveal" => Function::new_typed_with_env(store, env, reveal), + "__internal_store_get_hash" => Function::new_typed_with_env(store, env, store_get_hash), + } + } +} diff --git a/src/lib_wasm_runtime/src/runtime/mod.rs b/src/lib_wasm_runtime/src/runtime/mod.rs new file mode 100644 index 000000000000..bcf8e5fe0945 --- /dev/null +++ b/src/lib_wasm_runtime/src/runtime/mod.rs @@ -0,0 +1,117 @@ +// SPDX-FileCopyrightText: 2024 Nomadic Labs + +//! Abstraction layer hiding how a kernel is concretely executed. + +mod env; +mod host_funcs; + +pub use crate::host::{Host, InputsBuffer}; +use crate::{ + api::{Kernel, KernelsCache}, + types::EvmTree, +}; +pub use env::Env; +use ocaml::Error; +use wasmer::{Engine, Function, FunctionEnv, Instance, Store}; + +pub enum RunStatus { + Done(EvmTree), + PendingKernelUpgrade(EvmTree, InputsBuffer), +} + +pub trait Runtime { + fn host(&self) -> &Host; + + fn mut_host(&mut self) -> &mut Host; + + fn call(&mut self) -> Result<(), Error>; + + fn run(&mut self) -> Result { + // If the initial state was computed by the WASM PVM, then the reboot flag is set (because + // the first “reboot” is used to collect the shared inbox messages to fill the inputs + // buffer. We don’t need this in our case, but in order to remain compatible, (1) we assume + // the reboot flag can be set and we remove it, and (2) we will create it once the + // computation is over. + let _ = self.mut_host().reboot_requested()?; + + // We don’t modify the reboot counter, so the kernel will never print the `Kernel + // Invocation` header. We print it ourselves instead. + self.host() + .write_debug("------------------ Kernel Invocation ------------------\n".as_bytes()); + + loop { + self.call()?; + + if self.host().needs_kernel_reload() { + return Ok(RunStatus::PendingKernelUpgrade( + self.host().tree().clone(), + self.host().inputs_buffer().clone(), + )); + } + + if !self.mut_host().reboot_requested()? { + // We do that to be compatible with the WASM PVM, which creates it in the collect + // stage. + self.mut_host().create_reboot_flag()?; + return Ok(RunStatus::Done(self.host().tree().clone())); + } + } + } +} + +struct WasmRuntime { + store: Store, + env: FunctionEnv, + entrypoint: Function, +} + +impl WasmRuntime { + pub fn new( + engine: &Engine, + host: Host, + kernel: &Kernel, + entrypoint: &str, + ) -> Result { + let mut store = Store::new(engine.clone()); + let engine_env = Env::new(host); + let env = FunctionEnv::new(&mut store, engine_env); + let imports = host_funcs::imports(&mut store, &env); + let instance = Instance::new(&mut store, kernel.as_ref(), &imports)?; + let memory = instance.exports.get_memory("memory")?.clone(); + env.as_mut(&mut store).set_memory(&memory); + let entrypoint = instance.exports.get_function(entrypoint)?.clone(); + + Ok(Self { + store, + env, + entrypoint, + }) + } +} + +impl Runtime for WasmRuntime { + fn host(&self) -> &Host { + self.env.as_ref(&self.store).host() + } + + fn mut_host(&mut self) -> &mut Host { + self.env.as_mut(&mut self.store).mut_host() + } + + fn call(&mut self) -> Result<(), Error> { + let _result = self.entrypoint.call(&mut self.store, &[])?; + Ok(()) + } +} + +/// Returns an appropriate runtime that can be used to execute the current kernel. +pub fn load_runtime( + engine: &Engine, + kernels_cache: &mut KernelsCache, + host: Host, + entrypoint: &str, +) -> Result, Error> { + let kernel = kernels_cache.load(&engine, host.tree())?; + let runtime = WasmRuntime::new(&engine, host, kernel, entrypoint)?; + Ok(Box::new(runtime)) +} diff --git a/src/lib_wasm_runtime/src/types.rs b/src/lib_wasm_runtime/src/types.rs index 8fa16af9d6f0..113937eaeeed 100644 --- a/src/lib_wasm_runtime/src/types.rs +++ b/src/lib_wasm_runtime/src/types.rs @@ -1,5 +1,7 @@ // SPDX-FileCopyrightText: 2024 Nomadic Labs +//! Types for values creating in the OCaml side, and passed to Rust code and back. + use ocaml::{FromValue, Runtime, ToValue, Value}; #[derive(Clone)] @@ -16,3 +18,90 @@ unsafe impl FromValue for EvmTree { EvmTree(value) } } + +#[derive(Clone)] +pub struct OCamlString(Value); + +impl OCamlString { + pub fn as_str(&self) -> &str { + unsafe { Value::string_val(&self.0) } + } + + pub fn as_bytes(&self) -> &[u8] { + unsafe { Value::bytes_val(&self.0) } + } +} + +unsafe impl ToValue for OCamlString { + fn to_value(&self, gc: &Runtime) -> Value { + self.0.to_value(gc) + } +} + +unsafe impl FromValue for OCamlString { + fn from_value(value: Value) -> Self { + OCamlString(value) + } +} + +pub struct OCamlBytes(Value); + +impl OCamlBytes { + pub fn as_bytes(&self) -> &[u8] { + unsafe { Value::bytes_val(&self.0) } + } +} + +unsafe impl ToValue for OCamlBytes { + fn to_value(&self, gc: &Runtime) -> Value { + self.0.to_value(gc) + } +} + +unsafe impl FromValue for OCamlBytes { + fn from_value(value: Value) -> Self { + OCamlBytes(value) + } +} + +#[derive(PartialEq, Eq, PartialOrd, Clone, Ord)] +pub struct ContextHash([u8; 32]); + +impl ContextHash { + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } +} + +unsafe impl ToValue for ContextHash { + fn to_value(&self, gc: &Runtime) -> Value { + self.0.to_value(gc) + } +} + +unsafe impl FromValue for ContextHash { + fn from_value(value: Value) -> Self { + ContextHash(FromValue::from_value(value)) + } +} + +#[derive(PartialEq, Eq, PartialOrd, Clone, Ord, Copy)] +pub struct SmartRollupAddress([u8; 20]); + +impl SmartRollupAddress { + pub fn as_bytes(&self) -> &[u8; 20] { + &self.0 + } +} + +unsafe impl ToValue for SmartRollupAddress { + fn to_value(&self, gc: &Runtime) -> Value { + self.0.to_value(gc) + } +} + +unsafe impl FromValue for SmartRollupAddress { + fn from_value(value: Value) -> Self { + SmartRollupAddress(FromValue::from_value(value)) + } +} diff --git a/src/lib_wasm_runtime_callbacks/vector.ml b/src/lib_wasm_runtime_callbacks/vector.ml index 12d9540ebac5..4493aabb7dd3 100644 --- a/src/lib_wasm_runtime_callbacks/vector.ml +++ b/src/lib_wasm_runtime_callbacks/vector.ml @@ -130,12 +130,12 @@ let write_bytes vector offset bytes = in let rec write_chunks vector next ofs already_written = let open Lwt_syntax in - let to_write_step = min (chunk_size - ofs) (to_write - already_written) in - let* vector = - store_write_chunk vector next already_written ofs to_write_step - in - let already_written = already_written + to_write_step in if already_written < to_write then + let to_write_step = min (chunk_size - ofs) (to_write - already_written) in + let* vector = + store_write_chunk vector next already_written ofs to_write_step + in + let already_written = already_written + to_write_step in write_chunks vector (next + 1) 0 already_written else return vector in diff --git a/src/rust_deps/Cargo.lock b/src/rust_deps/Cargo.lock index a385d7a4b586..95c19cfcfece 100644 --- a/src/rust_deps/Cargo.lock +++ b/src/rust_deps/Cargo.lock @@ -4,11 +4,11 @@ version = 3 [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ - "gimli 0.31.0", + "gimli 0.31.1", ] [[package]] @@ -168,9 +168,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "backtrace" @@ -444,9 +444,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.21" +version = "1.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b1695e2c7e8fc85310cde85aeaab7e3097f593c91d209d3f9df76c928100f0" +checksum = "2e80e3b6a3ab07840e1cae9b0666a63970dc28e8ed5ffbcdacbfc760c281bfc1" dependencies = [ "shlex", ] @@ -508,9 +508,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" dependencies = [ "clap_builder", "clap_derive", @@ -518,9 +518,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" dependencies = [ "anstream", "anstyle", @@ -537,7 +537,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -824,7 +824,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -847,7 +847,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -858,7 +858,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -930,7 +930,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1122,7 +1122,7 @@ checksum = "1ccd72f8e71e242f71705868f5478fe7592a6e194c06330d8732421ffdbc554c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1143,7 +1143,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -1269,30 +1269,30 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", ] [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-task", @@ -1343,9 +1343,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "goblin" @@ -1456,6 +1456,12 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "hdwallet" version = "0.3.1" @@ -1556,9 +1562,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -1655,12 +1661,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -1674,9 +1680,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "is_terminal_polyfill" @@ -1727,9 +1733,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" [[package]] name = "libc" -version = "0.2.158" +version = "0.2.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libm" @@ -2132,14 +2138,14 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] @@ -2172,7 +2178,7 @@ checksum = "1d51b05aa0083eaec54b22a3f2a3d49175e04b4fb77ca7abb5a85731736239c3" dependencies = [ "cc", "proc-macro2", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2183,7 +2189,7 @@ checksum = "3de4a0decff0fd3ee0928dfa15dac08651157f8f814e93b34fdf962190354035" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -2200,8 +2206,10 @@ dependencies = [ name = "octez-evm-node-wasm-runtime" version = "0.0.0-dev" dependencies = [ + "hex", "ocaml", "ocaml-build", + "tezos_crypto_rs", "wasmer", "wasmer-compiler-cranelift", ] @@ -2246,9 +2254,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "opaque-debug" @@ -2383,7 +2391,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.4", + "redox_syscall 0.5.7", "smallvec", "windows-targets", ] @@ -2599,9 +2607,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" dependencies = [ "unicode-ident", ] @@ -2651,7 +2659,7 @@ dependencies = [ "crossbeam-utils", "libc", "once_cell", - "raw-cpuid 11.1.0", + "raw-cpuid 11.2.0", "wasi 0.11.0+wasi-snapshot-preview1", "web-sys", "winapi", @@ -2759,9 +2767,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.1.0" +version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ "bitflags 2.6.0", ] @@ -2814,9 +2822,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0884ad60e090bf1345b93da0a5de8923c93884cd03f40dfcfddd3b4bee661853" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] @@ -2846,14 +2854,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick 1.1.3", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -2867,13 +2875,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick 1.1.3", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2884,9 +2892,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "region" @@ -3042,7 +3050,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3112,7 +3120,7 @@ checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3302,7 +3310,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3324,9 +3332,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -3347,9 +3355,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -3441,7 +3449,7 @@ dependencies = [ name = "tezos-smart-rollup-utils" version = "0.2.2" dependencies = [ - "clap 4.5.18", + "clap 4.5.19", "hex", "quanta 0.12.3", "serde", @@ -3527,7 +3535,7 @@ checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3609,7 +3617,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3629,11 +3637,11 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.21" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b072cee73c449a636ffd6f32bd8de3a9f7119139aff882f44943ce2986dc5cf" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "toml_datetime", "winnow", ] @@ -3675,7 +3683,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -3731,9 +3739,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" @@ -3862,7 +3870,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-shared", ] @@ -3907,7 +3915,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3920,9 +3928,9 @@ checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasm-encoder" -version = "0.217.0" +version = "0.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b88b0814c9a2b323a9b46c687e726996c255ac8b64aa237dd11c81ed4854760" +checksum = "22b896fa8ceb71091ace9bcb81e853f54043183a1c9667cf93422c40252ffa0a" dependencies = [ "leb128", ] @@ -4097,9 +4105,9 @@ dependencies = [ [[package]] name = "wast" -version = "217.0.0" +version = "218.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79004ecebded92d3c710d4841383368c7f04b63d0992ddd6b0c7d5029b7629b7" +checksum = "8a53cd1f0fa505df97557e36a58bddb8296e2fcdcd089529545ebfdb18a1b9d7" dependencies = [ "bumpalo", "leb128", @@ -4110,9 +4118,9 @@ dependencies = [ [[package]] name = "wat" -version = "1.217.0" +version = "1.218.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c126271c3d92ca0f7c63e4e462e40c69cca52fd4245fcda730d1cf558fb55088" +checksum = "4f87f8e14e776762e07927c27c2054d2cf678aab9aae2d431a79b3e31e4dd391" dependencies = [ "wast", ] @@ -4297,9 +4305,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] @@ -4432,7 +4440,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] [[package]] @@ -4452,5 +4460,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.79", ] -- GitLab