diff --git a/core/Cargo.toml b/core/Cargo.toml index 5a83eef991..ea3cc487d0 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -53,7 +53,7 @@ eyre = { workspace = true } futures = { workspace = true, features = ["std", "async-await"] } parity-scale-codec = { workspace = true, features = ["derive"] } rand = { workspace = true } -serde = { workspace = true, features = ["derive"] } +serde = { workspace = true, features = ["derive", "rc"] } serde_json = { workspace = true } tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "rt-multi-thread", "macros", "fs"] } crossbeam-queue = { workspace = true } diff --git a/core/src/executor.rs b/core/src/executor.rs index 64187c3c37..bbdc58f159 100644 --- a/core/src/executor.rs +++ b/core/src/executor.rs @@ -1,17 +1,19 @@ //! Structures and impls related to *runtime* `Executor`s processing. +use std::sync::Arc; + use derive_more::DebugCustom; use iroha_data_model::{ account::AccountId, executor as data_model_executor, isi::InstructionBox, query::{AnyQueryBox, QueryRequest}, - transaction::{base64_util::Base64Wrapper, Executable, SignedTransaction}, + transaction::{Executable, SignedTransaction}, ValidationFail, }; use iroha_logger::trace; use serde::{ - de::{DeserializeSeed, MapAccess, VariantAccess, Visitor}, + de::{DeserializeSeed, VariantAccess, Visitor}, Deserialize, Deserializer, Serialize, }; @@ -245,7 +247,7 @@ impl Executor { /// - Failed to execute entrypoint of the WASM blob. pub fn migrate( &mut self, - raw_executor: &data_model_executor::Executor, + raw_executor: data_model_executor::Executor, state_transaction: &mut StateTransaction<'_, '_>, authority: &AccountId, ) -> Result<(), wasm::error::Error> { @@ -276,21 +278,21 @@ impl Executor { #[derive(DebugCustom, Clone, Serialize)] #[debug(fmt = "LoadedExecutor {{ module: }}")] pub struct LoadedExecutor { - #[serde(serialize_with = "wasm::serialize_module_base64")] + #[serde(skip)] module: wasmtime::Module, + /// Arc is needed so cloning of executor will be fast. + /// See [`crate::tx::TransactionExecutor::validate_with_runtime_executor`]. + raw_executor: Arc, } impl LoadedExecutor { - fn new(module: wasmtime::Module) -> Self { - Self { module } - } - fn load( engine: &wasmtime::Engine, - raw_executor: &data_model_executor::Executor, + raw_executor: data_model_executor::Executor, ) -> Result { Ok(Self { module: wasm::load_module(engine, &raw_executor.wasm)?, + raw_executor: Arc::new(raw_executor), }) } } @@ -302,37 +304,15 @@ impl<'de> DeserializeSeed<'de> for WasmSeed<'_, LoadedExecutor> { where D: serde::Deserializer<'de>, { - struct LoadedExecutorVisitor<'l> { - loader: &'l WasmSeed<'l, LoadedExecutor>, + // a copy of `LoadedExecutor` without the `module` field + #[derive(Deserialize)] + struct LoadedExecutor { + raw_executor: data_model_executor::Executor, } - impl<'de> Visitor<'de> for LoadedExecutorVisitor<'_> { - type Value = LoadedExecutor; + let executor = LoadedExecutor::deserialize(deserializer)?; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { - formatter.write_str("struct LoadedExecutor") - } - - fn visit_map(self, mut map: M) -> Result - where - M: MapAccess<'de>, - { - while let Some(key) = map.next_key::()? { - if key.as_str() == "module" { - let wrapper: Base64Wrapper = map.next_value()?; - let module = wasm::deserialize_module(self.loader.engine, wrapper.0) - .map_err(serde::de::Error::custom)?; - return Ok(LoadedExecutor::new(module)); - } - } - Err(serde::de::Error::missing_field("module")) - } - } - - deserializer.deserialize_struct( - "LoadedExecutor", - &["module"], - LoadedExecutorVisitor { loader: &self }, - ) + self::LoadedExecutor::load(self.engine, executor.raw_executor) + .map_err(serde::de::Error::custom) } } diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index 97ae16b967..fffe50369a 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -408,7 +408,7 @@ pub mod isi { // Also it's a cheap operation. let mut upgraded_executor = state_transaction.world.executor.clone(); upgraded_executor - .migrate(&raw_executor, state_transaction, authority) + .migrate(raw_executor, state_transaction, authority) .map_err(|migration_error| { InvalidParameterError::Wasm(format!( "{:?}", diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 2b8066fcd2..269735c2c7 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -14,14 +14,12 @@ use iroha_data_model::{ prelude::*, query::{parameters::QueryId, AnyQueryBox, QueryOutput, QueryRequest, QueryResponse}, smart_contract::payloads::{self, Validate}, - transaction::base64_util::Base64Wrapper, Level as LogLevel, ValidationFail, }; use iroha_logger::debug; // NOTE: Using error_span so that span info is logged on every event use iroha_logger::{error_span as wasm_log_span, prelude::tracing::Span}; use iroha_wasm_codec::{self as codec, WasmUsize}; -use serde::Serialize; use wasmtime::{ Caller, Config as WasmtimeConfig, Engine, Linker, Module, Store, StoreLimits, StoreLimitsBuilder, TypedFunc, @@ -129,8 +127,6 @@ pub mod error { Finalization(#[source] crate::query::store::Error), /// Failed to load module ModuleLoading(#[source] WasmtimeError), - /// Failed to deserialize module - ModuleDeserialization(#[source] WasmtimeError), /// Module could not be instantiated Instantiation(#[from] InstantiationError), /// Export error @@ -255,23 +251,6 @@ pub fn load_module(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result(module: &Module, serializer: S) -> Result -where - S: serde::Serializer, -{ - let bytes = module.serialize().map_err(serde::ser::Error::custom)?; - let wrapper = Base64Wrapper(bytes); - wrapper.serialize(serializer) -} - -/// Deserialize [`Module`]. Accepts only output of [`Module::serialize`]. -#[allow(unsafe_code)] -pub(crate) fn deserialize_module(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result { - // SAFETY: `Module::deserialize` is safe when calling for bytes received from `Module::serialize`. - // We store serialization result on disk and then load it back so should be ok. - unsafe { Module::deserialize(engine, bytes).map_err(Error::ModuleDeserialization) } -} - /// Create [`Engine`] with a predefined configuration. /// /// # Panics diff --git a/data_model/src/transaction.rs b/data_model/src/transaction.rs index e1efd11e90..ab1a2505a6 100644 --- a/data_model/src/transaction.rs +++ b/data_model/src/transaction.rs @@ -427,17 +427,6 @@ mod base64 { } } -/// Internal module for use in `iroha_core` -#[cfg(feature = "transparent_api")] -pub mod base64_util { - use serde::{Deserialize, Serialize}; - - /// Wrapper for `Vec` which can be serialized and deserialized as base64 - #[derive(Deserialize, Serialize)] - #[serde(transparent)] - pub struct Base64Wrapper(#[serde(with = "super::base64")] pub Vec); -} - pub mod error { //! Module containing errors that can occur in transaction lifecycle pub use self::model::*;