diff --git a/etherlink/bin_node/config/configuration.ml b/etherlink/bin_node/config/configuration.ml index dab339f69ce470b8b964b3808b8c845ec2afcfe8..06c551c30851a434ebe0c96fb35c70801721c2b3 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 bef93f6a479a17e8c67936cbecfe70073ffe5b45..1d849cf61e2b39bb0dfa3599c861a89a5e2a678a 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 d8a33c193562346dafdf8216425ec1e1d4335280..beacb55d4c00f362eb4c8f37b1ed27de5f789756 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 287650c91b42240a6bbccd3c452682374fe5a1cf..afe94fde54bf711e53caf097bbee3f17388a37ba 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 5bd5fce47ac2be2e6f83cf0f36a5cc35b16a7cec..919a8f50b644ddcf1a1dae6a78b45601ce6cba9f 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 f413fa17d5bc7a7852b710bd6d6d3f9c5dbfd4f8..6613757c3b5a6b61eb2d828db41170fffc117e80 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 9d9f2f18102071da45a2fc3705ba8ab9efc69cf4..0ff106eb16e5891b80d3c21ef9177853b638cb04 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 9497f07c658fd8d8f47ab16f5ccc6a878db20861..686b84a333fb3e21fb390abd09d8669e0f1561d2 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 75505027518c4ff6887b044b9443a189e117ff08..421e05507db089c7b2e73821449c4dddff719f17 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 ac831cc79d6d3eb09dc6f0c9d4ce9e0a07c4d329..759f717f0d2c267678218ec62343ad429677c298 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 531d8c74857648450225fe730a5b459aa9827faa..3dcd8974ed94d150698e4f647fa9e58d9379d203 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 9b546b70a2a5a696a66913c7bf8b2b50d241c281..77ccef8defaa6fa6d66f5951d00075a91a9c3f7e 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 1b58215e14e2ab213785bb45732caa61a06f459f..0472220703576c11c31e5d04632537ecf11648e2 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 8ee5e62e1cb5c831ccdf1e2e4b71cb923d8cede7..8014e9396a39ad8e95345e7bb45226f13931d021 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 4ed9c27a9370c3e59d52bfbc38e4dd148f5ab7a6..f3b53ae9f58092904f472fe9bd570d6d3bea874d 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 5960ae89880a8b93e55d2d7d37c6eec50bd3426c..f50b600025a892e596b1fa093fe7a77045cac44e 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 7472a95785be0706e7c726e60481ed9c558558cc..88011536197d02802955d5097f013fcecff490ad 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 9749e64e9b186a73e2fab0cbb9613d01ecaab971..41b2fa9a40bce6a775f5a987d1e17e984f00180b 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 4206583c3435dd61cb0383261909f7d6d4a8ad6a..a0108d2f556ff6a50c1e02c2f455dcb73d2e2914 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 2a45b70e7adf9c5ef3fb0ee592c58b7fd066140a..c41d3a4ab5e00e60bd24c053371ef4b94b381f2b 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 d9f9436f38b8f13d5510160cdcd4f7a08a24310b..e1423ad2fb58114d73ffb11734f21cbabc606bc8 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 bcc83a6097203024c62a083a0f51cfa608432db5..f37571ae82150b3e07206d9b88b5cec5b21e8342 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 58f38d7475aec2492a01c1fd626602528b3664ae..bbb8423f3711f70ad84dc55fa6632bb5ddbcd64c 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 c0bb7c1dabc08397c5b058402a85a323e1f8c782..864056edfdcf4da594325067b712c4bb42b89e70 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 b564de3e74325cde2b4cdd47f370cb49582c3198..5eba89eae01d1d71a7c94ed3c03bcbceb2d5294a 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 0572ac0f1eef16f5243db9848fbd888d26c11560..8365e0a948b7a198cbbb945f6775b7b1c6fb09e0 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 1a7b4fbf8feefa0cd0409775889e57a38102d339..10fadd9dddbb27a22d52c9059f6a47906066a95e 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 c542b3f42d8585a4a5b0f79d3040e3f7606e16c8..c1655e15ed2c582009c3450491f9f63cffff4f6d 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 c542b3f42d8585a4a5b0f79d3040e3f7606e16c8..c1655e15ed2c582009c3450491f9f63cffff4f6d 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 0000000000000000000000000000000000000000..1f3171c78fd2cb65f3f30cfc8f29f0dc46ca95ad --- /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 2b92b8332da264e1f46f109d007045f64644d7c7..700a4461235da0bdf438f784231e266bedaa559c 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 0000000000000000000000000000000000000000..ff0a1104a84d5fd2b8e1174d9bab8e4bb54a65c4 --- /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 0000000000000000000000000000000000000000..86cf63a8c5417747741f3e77bd4712dc73239dcc --- /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 eaaf49a899d7f2532194da8d707c949e6052fde9..d45399ac41ed5447ac7b2ac1490ee7273503d763 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 0000000000000000000000000000000000000000..2f089f70bcbf9aba051936d31a8cc9dfc3624c4f --- /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 0000000000000000000000000000000000000000..739da9af73185a6430b103eda9d8ea908199efd4 --- /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 0000000000000000000000000000000000000000..bcf8e5fe0945f8683c51952c889bacb757fac939 --- /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 8fa16af9d6f0615d50d8aceb50ed48bb2856533e..113937eaeeedad81859ac86146c1d4ef612b500a 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 12d9540ebac56800481bf945d6123eeb1ae826fc..4493aabb7dd30d72c4c56983d94607e7f647878a 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 a385d7a4b5864e8a0f17f7cfa18cddebb970926f..95c19cfcfece356249c99881e6536939a93dcd97 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", ]