From 9570014bb69be3f04bb1af609f05a9c71e7292b8 Mon Sep 17 00:00:00 2001 From: Mathieu Dutour Sikiric Date: Fri, 21 Feb 2025 22:25:53 +0100 Subject: [PATCH] Move the WasmRuntime / VmRuntime, etc. to linera-base. Integrate the VM type to the BytecodeId. --- Cargo.lock | 3 +- linera-base/Cargo.toml | 4 + linera-base/build.rs | 4 +- linera-base/src/identifiers.rs | 30 ++- linera-base/src/lib.rs | 1 + linera-base/src/unit_tests.rs | 3 + linera-base/src/vm.rs | 154 ++++++++++++++ linera-chain/src/unit_tests/chain_tests.rs | 6 +- linera-client/src/client_context.rs | 4 +- linera-client/src/client_options.rs | 11 +- linera-core/src/client/mod.rs | 13 +- .../src/unit_tests/wasm_client_tests.rs | 25 ++- .../src/unit_tests/wasm_worker_tests.rs | 7 +- linera-execution/Cargo.toml | 1 - linera-execution/build.rs | 3 - linera-execution/src/applications.rs | 4 +- linera-execution/src/execution_state_actor.rs | 5 +- linera-execution/src/lib.rs | 196 ++---------------- linera-execution/src/revm.rs | 4 +- linera-execution/src/runtime.rs | 4 +- linera-execution/src/system.rs | 8 +- linera-execution/src/test_utils/mod.rs | 7 +- .../src/unit_tests/applications_tests.rs | 5 +- .../src/unit_tests/runtime_tests.rs | 2 + .../src/unit_tests/system_tests.rs | 5 +- linera-execution/src/wasm/mod.rs | 53 ++++- linera-execution/src/wasm/system_api.rs | 11 +- .../tests/contract_runtime_apis.rs | 7 +- linera-execution/tests/wasm.rs | 4 +- .../src/contract/conversions_from_wit.rs | 18 ++ linera-sdk/src/contract/conversions_to_wit.rs | 18 ++ .../src/service/conversions_from_wit.rs | 18 ++ linera-sdk/src/service/conversions_to_wit.rs | 18 ++ linera-sdk/src/test/chain.rs | 8 +- linera-sdk/src/test/validator.rs | 10 +- linera-sdk/wit/contract-system-api.wit | 9 + linera-sdk/wit/service-system-api.wit | 9 + linera-service/src/linera/main.rs | 17 +- linera-service/src/node_service.rs | 7 +- linera-storage/Cargo.toml | 1 + linera-storage/src/lib.rs | 135 ++++++------ 41 files changed, 497 insertions(+), 355 deletions(-) create mode 100644 linera-base/src/vm.rs diff --git a/Cargo.lock b/Cargo.lock index f7535318beb9..a979153a0b07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4391,6 +4391,7 @@ dependencies = [ "cfg_aliases", "chrono", "custom_debug_derive", + "derive_more", "ed25519-dalek", "futures", "getrandom", @@ -4600,7 +4601,6 @@ dependencies = [ "clap", "custom_debug_derive", "dashmap 5.5.3", - "derive_more", "dyn-clone", "futures", "hex", @@ -4992,6 +4992,7 @@ dependencies = [ "anyhow", "async-trait", "bcs", + "cfg-if", "cfg_aliases", "dashmap 5.5.3", "futures", diff --git a/linera-base/Cargo.toml b/linera-base/Cargo.toml index 79c8ea6fd301..95c900e706f9 100644 --- a/linera-base/Cargo.toml +++ b/linera-base/Cargo.toml @@ -12,6 +12,9 @@ repository.workspace = true version.workspace = true [features] +wasmer = [] +wasmtime = [] +revm = [] metrics = ["prometheus"] reqwest = ["dep:reqwest"] test = ["test-strategy", "proptest"] @@ -39,6 +42,7 @@ bcs.workspace = true cfg-if.workspace = true chrono.workspace = true custom_debug_derive.workspace = true +derive_more = { workspace = true, features = ["display"] } ed25519-dalek.workspace = true futures.workspace = true getrandom = { workspace = true, optional = true } diff --git a/linera-base/build.rs b/linera-base/build.rs index de990fb6208c..93bd8a7e56a7 100644 --- a/linera-base/build.rs +++ b/linera-base/build.rs @@ -8,7 +8,9 @@ fn main() { with_metrics: { all(not(target_arch = "wasm32"), feature = "metrics") }, with_reqwest: { feature = "reqwest" }, with_testing: { any(test, feature = "test") }, - + with_revm: { feature = "revm" }, + with_wasmer: { feature = "wasmer" }, + with_wasmtime: { all(not(target_arch = "wasm32"), feature = "wasmtime") }, // the old version of `getrandom` we pin here is available on all targets, but // using it will panic if no suitable source of entropy is found with_getrandom: { any(web, not(target_arch = "wasm32")) }, diff --git a/linera-base/src/identifiers.rs b/linera-base/src/identifiers.rs index cc64398d6cfd..4fb678564d0e 100644 --- a/linera-base/src/identifiers.rs +++ b/linera-base/src/identifiers.rs @@ -21,6 +21,7 @@ use crate::{ crypto::{BcsHashable, CryptoError, CryptoHash}, data_types::BlockHeight, doc_scalar, hex_debug, + vm::VmRuntime, }; /// The owner of a chain. This is currently the hash of the owner's public key used to @@ -350,6 +351,8 @@ pub struct BytecodeId { pub contract_blob_hash: CryptoHash, /// The hash of the blob containing the service bytecode. pub service_blob_hash: CryptoHash, + /// The virtual machine being used. + pub vm_runtime: VmRuntime, #[witty(skip)] #[debug(skip)] _phantom: PhantomData<(Abi, Parameters, InstantiationArgument)>, @@ -568,10 +571,12 @@ impl PartialEq let BytecodeId { contract_blob_hash, service_blob_hash, + vm_runtime, _phantom, } = other; self.contract_blob_hash == *contract_blob_hash && self.service_blob_hash == *service_blob_hash + && self.vm_runtime == *vm_runtime } } @@ -595,10 +600,15 @@ impl Ord let BytecodeId { contract_blob_hash, service_blob_hash, + vm_runtime, _phantom, } = other; - (self.contract_blob_hash, self.service_blob_hash) - .cmp(&(*contract_blob_hash, *service_blob_hash)) + ( + self.contract_blob_hash, + self.service_blob_hash, + self.vm_runtime, + ) + .cmp(&(*contract_blob_hash, *service_blob_hash, *vm_runtime)) } } @@ -609,10 +619,12 @@ impl Hash let BytecodeId { contract_blob_hash: contract_blob_id, service_blob_hash: service_blob_id, + vm_runtime: vm_runtime_id, _phantom, } = self; contract_blob_id.hash(state); service_blob_id.hash(state); + vm_runtime_id.hash(state); } } @@ -621,6 +633,7 @@ impl Hash struct SerializableBytecodeId { contract_blob_hash: CryptoHash, service_blob_hash: CryptoHash, + vm_runtime: VmRuntime, } impl Serialize @@ -633,6 +646,7 @@ impl Serialize let serializable_bytecode_id = SerializableBytecodeId { contract_blob_hash: self.contract_blob_hash, service_blob_hash: self.service_blob_hash, + vm_runtime: self.vm_runtime, }; if serializer.is_human_readable() { let bytes = @@ -659,6 +673,7 @@ impl<'de, Abi, Parameters, InstantiationArgument> Deserialize<'de> Ok(BytecodeId { contract_blob_hash: serializable_bytecode_id.contract_blob_hash, service_blob_hash: serializable_bytecode_id.service_blob_hash, + vm_runtime: serializable_bytecode_id.vm_runtime, _phantom: PhantomData, }) } else { @@ -666,6 +681,7 @@ impl<'de, Abi, Parameters, InstantiationArgument> Deserialize<'de> Ok(BytecodeId { contract_blob_hash: serializable_bytecode_id.contract_blob_hash, service_blob_hash: serializable_bytecode_id.service_blob_hash, + vm_runtime: serializable_bytecode_id.vm_runtime, _phantom: PhantomData, }) } @@ -674,10 +690,15 @@ impl<'de, Abi, Parameters, InstantiationArgument> Deserialize<'de> impl BytecodeId { /// Creates a bytecode ID from contract/service hashes. - pub fn new(contract_blob_hash: CryptoHash, service_blob_hash: CryptoHash) -> Self { + pub fn new( + contract_blob_hash: CryptoHash, + service_blob_hash: CryptoHash, + vm_runtime: VmRuntime, + ) -> Self { BytecodeId { contract_blob_hash, service_blob_hash, + vm_runtime, _phantom: PhantomData, } } @@ -689,6 +710,7 @@ impl BytecodeId { BytecodeId { contract_blob_hash: self.contract_blob_hash, service_blob_hash: self.service_blob_hash, + vm_runtime: self.vm_runtime, _phantom: PhantomData, } } @@ -700,6 +722,7 @@ impl BytecodeId BytecodeId ApplicationId { bytecode_id: BytecodeId::new( CryptoHash::test_hash("contract bytecode"), CryptoHash::test_hash("service bytecode"), + VmRuntime::default(), ), creation: MessageId { chain_id: ChainId::root(0), @@ -117,6 +119,7 @@ fn bytecode_id_test_case() -> BytecodeId { BytecodeId::new( CryptoHash::test_hash("another contract bytecode"), CryptoHash::test_hash("another service bytecode"), + VmRuntime::default(), ) } diff --git a/linera-base/src/vm.rs b/linera-base/src/vm.rs new file mode 100644 index 000000000000..a6a54fa608ea --- /dev/null +++ b/linera-base/src/vm.rs @@ -0,0 +1,154 @@ +// Copyright (c) Zefchain Labs, Inc. +// SPDX-License-Identifier: Apache-2.0 + +//! The virtual machines being supported. + +use std::str::FromStr; + +use async_graphql::scalar; +use derive_more::Display; +use linera_witty::{WitLoad, WitStore, WitType}; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +/// The runtime to use for running the application. +#[derive( + Clone, + Copy, + Display, + Hash, + PartialEq, + Eq, + PartialOrd, + Ord, + Serialize, + Deserialize, + WitType, + WitStore, + WitLoad, + Debug, +)] +#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))] +pub enum WasmRuntime { + /// The choice of the Wasmer runtime for WebAssembly + #[display("wasmer")] + Wasmer, + /// The choice of the Wasmtime runtime for WebAssembly + #[display("wasmtime")] + Wasmtime, + /// The choice of the Wasmer with sanitizer runtime for WebAssembly + WasmerWithSanitizer, + /// The choice of the Wasmtime with sanitizer runtime for WebAssembly + WasmtimeWithSanitizer, +} + +impl WasmRuntime { + /// Returns whether we need a stabilizer or not. + pub fn needs_sanitizer(self) -> bool { + matches!( + self, + WasmRuntime::WasmerWithSanitizer | WasmRuntime::WasmtimeWithSanitizer + ) + } +} + +impl FromStr for WasmRuntime { + type Err = InvalidVmRuntime; + + fn from_str(string: &str) -> Result { + match string { + "wasmer" => Ok(WasmRuntime::Wasmer), + "wasmtime" => Ok(WasmRuntime::Wasmtime), + unknown => Err(InvalidVmRuntime(unknown.to_owned())), + } + } +} + +scalar!(WasmRuntime); + +#[derive( + Clone, + Copy, + Debug, + Display, + Hash, + PartialEq, + Eq, + PartialOrd, + Ord, + Serialize, + Deserialize, + WitType, + WitStore, + WitLoad, +)] +#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))] +/// The choice of runtime for handling the Evm. +pub enum EvmRuntime { + /// The choice of the Revm runtime for Evm. + Revm, +} + +scalar!(EvmRuntime); + +#[derive( + Clone, + Copy, + Display, + Hash, + PartialEq, + Eq, + PartialOrd, + Ord, + Serialize, + Deserialize, + WitType, + WitStore, + WitLoad, + Debug, +)] +#[cfg_attr(with_testing, derive(test_strategy::Arbitrary))] +/// The virtual machine runtime +pub enum VmRuntime { + /// The Wasm for the virtual machine + Wasm(WasmRuntime), + /// The Evm for the virtual machine + Evm(EvmRuntime), +} + +impl FromStr for VmRuntime { + type Err = InvalidVmRuntime; + + fn from_str(string: &str) -> Result { + match string { + "wasmer" => Ok(VmRuntime::Wasm(WasmRuntime::Wasmer)), + "wasmtime" => Ok(VmRuntime::Wasm(WasmRuntime::Wasmtime)), + "revm" => Ok(VmRuntime::Evm(EvmRuntime::Revm)), + unknown => Err(InvalidVmRuntime(unknown.to_owned())), + } + } +} + +scalar!(VmRuntime); + +#[cfg(with_testing)] +impl Default for VmRuntime { + fn default() -> Self { + cfg_if::cfg_if! { + if #[cfg(with_wasmer)] { + VmRuntime::Wasm(WasmRuntime::Wasmer) + } else if #[cfg(with_wasmtime)] { + VmRuntime::Wasm(WasmRuntime::Wasmtime) + } else if #[cfg(with_revm)] { + VmRuntime::Evm(EvmRuntime::Revm) + } else { + panic!("Cannot call default for VmRuntime without wasmer, or wasmtime or revm features"); + } + } + } +} + +/// Attempts to create an invalid [`VmRuntime`] instance from a string. +#[derive(Clone, Debug, Error)] +#[error("{0:?} is not a valid virtual machine runtime")] +pub struct InvalidVmRuntime(String); diff --git a/linera-chain/src/unit_tests/chain_tests.rs b/linera-chain/src/unit_tests/chain_tests.rs index d355d436a2df..9c8cee798e26 100644 --- a/linera-chain/src/unit_tests/chain_tests.rs +++ b/linera-chain/src/unit_tests/chain_tests.rs @@ -12,6 +12,7 @@ use linera_base::{ hashed::Hashed, identifiers::{ApplicationId, BytecodeId, ChainId, MessageId}, ownership::ChainOwnership, + vm::VmRuntime, }; use linera_execution::{ committee::{Committee, Epoch, ValidatorState}, @@ -19,7 +20,7 @@ use linera_execution::{ test_utils::{ExpectedCall, MockApplication}, ExecutionError, ExecutionRuntimeConfig, ExecutionRuntimeContext, Message, MessageKind, Operation, ResourceControlPolicy, SystemMessage, SystemOperation, TestExecutionRuntimeContext, - UserApplicationDescription, VmRuntime, + UserApplicationDescription, }; use linera_views::{ context::{Context as _, MemoryContext}, @@ -66,11 +67,10 @@ fn make_app_description() -> (UserApplicationDescription, Blob, Blob) { let service_blob = Blob::new_service_bytecode(service.compress()); let vm_runtime = VmRuntime::default(); - let bytecode_id = BytecodeId::new(contract_blob.id().hash, service_blob.id().hash); + let bytecode_id = BytecodeId::new(contract_blob.id().hash, service_blob.id().hash, vm_runtime); ( UserApplicationDescription { bytecode_id, - vm_runtime, creation: make_admin_message_id(BlockHeight(2)), required_application_ids: vec![], parameters: vec![], diff --git a/linera-client/src/client_context.rs b/linera-client/src/client_context.rs index 78dda4b5b0b1..4fb86966435e 100644 --- a/linera-client/src/client_context.rs +++ b/linera-client/src/client_context.rs @@ -13,6 +13,7 @@ use linera_base::{ identifiers::{Account, ChainId}, ownership::ChainOwnership, time::{Duration, Instant}, + vm::VmRuntime, }; use linera_chain::types::ConfirmedBlockCertificate; use linera_core::{ @@ -493,6 +494,7 @@ where chain_client: &ChainClient, contract: PathBuf, service: PathBuf, + vm_runtime: VmRuntime, ) -> Result { info!("Loading bytecode files"); let contract_bytecode = Bytecode::load_from_file(&contract) @@ -504,7 +506,7 @@ where info!("Publishing bytecode"); let (contract_blob, service_blob, bytecode_id) = - create_bytecode_blobs(contract_bytecode, service_bytecode).await; + create_bytecode_blobs(contract_bytecode, service_bytecode, vm_runtime).await; let (bytecode_id, _) = self .apply_client_command(chain_client, |chain_client| { let contract_blob = contract_blob.clone(); diff --git a/linera-client/src/client_options.rs b/linera-client/src/client_options.rs index 39b72b4cd55c..e3be71adf514 100644 --- a/linera-client/src/client_options.rs +++ b/linera-client/src/client_options.rs @@ -17,9 +17,10 @@ use linera_base::{ }, ownership::{ChainOwnership, TimeoutConfig}, time::Duration, + vm::VmRuntime, }; use linera_core::{client::BlanketMessagePolicy, DEFAULT_GRACE_PERIOD}; -use linera_execution::{ResourceControlPolicy, VmRuntime}; +use linera_execution::ResourceControlPolicy; use linera_views::store::CommonStoreConfig; #[cfg(feature = "fs")] @@ -768,6 +769,10 @@ pub enum ClientCommand { /// Path to the Wasm file for the application "service" bytecode. service: PathBuf, + /// The virtual machine runtime to use. + #[arg(long)] + vm_runtime: Option, + /// An optional chain ID to publish the bytecode. The default chain of the wallet /// is used otherwise. publisher: Option, @@ -797,10 +802,6 @@ pub enum ClientCommand { /// The bytecode ID of the application to create. bytecode_id: BytecodeId, - /// The virtual machine runtime to use. - #[arg(long)] - vm_runtime: Option, - /// An optional chain ID to host the application. The default chain of the wallet /// is used otherwise. creator: Option, diff --git a/linera-core/src/client/mod.rs b/linera-core/src/client/mod.rs index 92f7773a26ed..dbd4deee8712 100644 --- a/linera-core/src/client/mod.rs +++ b/linera-core/src/client/mod.rs @@ -39,6 +39,7 @@ use linera_base::{ Owner, UserApplicationId, }, ownership::{ChainOwnership, TimeoutConfig}, + vm::VmRuntime, }; use linera_chain::{ data_types::{ @@ -59,7 +60,7 @@ use linera_execution::{ CREATE_APPLICATION_MESSAGE_INDEX, OPEN_CHAIN_MESSAGE_INDEX, }, ExecutionError, Operation, Query, QueryOutcome, QueryResponse, SystemExecutionError, - SystemQuery, SystemResponse, VmRuntime, + SystemQuery, SystemResponse, }; use linera_storage::{Clock as _, Storage}; use linera_views::views::ViewError; @@ -737,6 +738,7 @@ enum CheckCertificateResult { pub async fn create_bytecode_blobs( contract: Bytecode, service: Bytecode, + vm_runtime: VmRuntime, ) -> (Blob, Blob, BytecodeId) { let (compressed_contract, compressed_service) = tokio::task::spawn_blocking(move || (contract.compress(), service.compress())) @@ -744,7 +746,7 @@ pub async fn create_bytecode_blobs( .expect("Compression should not panic"); let contract_blob = Blob::new_contract_bytecode(compressed_contract); let service_blob = Blob::new_service_bytecode(compressed_service); - let bytecode_id = BytecodeId::new(contract_blob.id().hash, service_blob.id().hash); + let bytecode_id = BytecodeId::new(contract_blob.id().hash, service_blob.id().hash, vm_runtime); (contract_blob, service_blob, bytecode_id) } @@ -2846,9 +2848,10 @@ where &self, contract: Bytecode, service: Bytecode, + vm_runtime: VmRuntime, ) -> Result, ChainClientError> { let (contract_blob, service_blob, bytecode_id) = - create_bytecode_blobs(contract, service).await; + create_bytecode_blobs(contract, service, vm_runtime).await; self.publish_bytecode_blobs(contract_blob, service_blob, bytecode_id) .await } @@ -2912,7 +2915,6 @@ where >( &self, bytecode_id: BytecodeId, - vm_runtime: VmRuntime, parameters: &Parameters, instantiation_argument: &InstantiationArgument, required_application_ids: Vec, @@ -2923,7 +2925,6 @@ where Ok(self .create_application_untyped( bytecode_id.forget_abi(), - vm_runtime, parameters, instantiation_argument, required_application_ids, @@ -2946,7 +2947,6 @@ where pub async fn create_application_untyped( &self, bytecode_id: BytecodeId, - vm_runtime: VmRuntime, parameters: Vec, instantiation_argument: Vec, required_application_ids: Vec, @@ -2954,7 +2954,6 @@ where { self.execute_operation(Operation::System(SystemOperation::CreateApplication { bytecode_id, - vm_runtime, parameters, instantiation_argument, required_application_ids, diff --git a/linera-core/src/unit_tests/wasm_client_tests.rs b/linera-core/src/unit_tests/wasm_client_tests.rs index 100bfe0a7d0b..58a31e075e9b 100644 --- a/linera-core/src/unit_tests/wasm_client_tests.rs +++ b/linera-core/src/unit_tests/wasm_client_tests.rs @@ -22,6 +22,7 @@ use linera_base::{ data_types::{Amount, Bytecode, Event, OracleResponse}, identifiers::{AccountOwner, ApplicationId, Destination, Owner, StreamId, StreamName}, ownership::{ChainOwnership, TimeoutConfig}, + vm::{VmRuntime, WasmRuntime}, }; use linera_chain::{ data_types::{MessageAction, OutgoingMessage}, @@ -29,7 +30,7 @@ use linera_chain::{ }; use linera_execution::{ ExecutionError, Message, MessageKind, Operation, QueryOutcome, ResourceControlPolicy, - SystemMessage, UserApplicationDescription, VmRuntime, WasmRuntime, + SystemMessage, UserApplicationDescription, }; use serde_json::json; use test_case::test_case; @@ -122,7 +123,7 @@ where let creator = builder.add_root_chain(1, Amount::ONE).await?; let (bytecode_id, _cert) = publisher - .publish_bytecode(contract_bytecode, service_bytecode) + .publish_bytecode(contract_bytecode, service_bytecode, vm_runtime) .await .unwrap() .unwrap(); @@ -137,7 +138,7 @@ where let initial_value = 10_u64; let (application_id, _) = creator - .create_application(bytecode_id, vm_runtime, &(), &initial_value, vec![]) + .create_application(bytecode_id, &(), &initial_value, vec![]) .await .unwrap() .unwrap(); @@ -170,7 +171,7 @@ where let small_bytecode = Bytecode::new(vec![]); // Publishing bytecode that exceeds the limit fails. let result = publisher - .publish_bytecode(large_bytecode.clone(), small_bytecode.clone()) + .publish_bytecode(large_bytecode.clone(), small_bytecode.clone(), vm_runtime) .await; assert_matches!( result, @@ -179,7 +180,7 @@ where ))) if matches!(*error, ExecutionError::BytecodeTooLarge) ); let result = publisher - .publish_bytecode(small_bytecode, large_bytecode) + .publish_bytecode(small_bytecode, large_bytecode, vm_runtime) .await; assert_matches!( result, @@ -295,6 +296,7 @@ where .publish_bytecode( Bytecode::load_from_file(contract_path).await?, Bytecode::load_from_file(service_path).await?, + vm_runtime, ) .await .unwrap() @@ -308,6 +310,7 @@ where .publish_bytecode( Bytecode::load_from_file(contract_path).await?, Bytecode::load_from_file(service_path).await?, + vm_runtime, ) .await .unwrap() @@ -320,14 +323,13 @@ where creator.synchronize_from_validators().await.unwrap(); let initial_value = 10_u64; let (application_id1, _) = creator - .create_application(bytecode_id1, vm_runtime, &(), &initial_value, vec![]) + .create_application(bytecode_id1, &(), &initial_value, vec![]) .await .unwrap() .unwrap(); let (application_id2, certificate) = creator .create_application( bytecode_id2, - vm_runtime, &application_id1, &(), vec![application_id1.forget_abi()], @@ -557,6 +559,7 @@ where .publish_bytecode( Bytecode::load_from_file(contract_path).await?, Bytecode::load_from_file(service_path).await?, + vm_runtime, ) .await .unwrap() @@ -573,7 +576,7 @@ where let state = fungible::InitialState { accounts }; let params = fungible::Parameters::new("FUN"); let (application_id, _cert) = sender - .create_application(bytecode_id, vm_runtime, ¶ms, &state, vec![]) + .create_application(bytecode_id, ¶ms, &state, vec![]) .await .unwrap() .unwrap(); @@ -761,6 +764,7 @@ where .publish_bytecode( Bytecode::load_from_file(contract_path).await?, Bytecode::load_from_file(service_path).await?, + vm_runtime, ) .await .unwrap() @@ -769,7 +773,7 @@ where let bytecode_id = bytecode_id.with_abi::(); let (application_id, _cert) = receiver - .create_application(bytecode_id, vm_runtime, &(), &(), vec![]) + .create_application(bytecode_id, &(), &(), vec![]) .await .unwrap() .unwrap(); @@ -919,6 +923,7 @@ async fn test_memory_fuel_limit(wasm_runtime: WasmRuntime) -> anyhow::Result<()> .publish_bytecode( Bytecode::load_from_file(contract_path).await?, Bytecode::load_from_file(service_path).await?, + vm_runtime, ) .await .unwrap() @@ -927,7 +932,7 @@ async fn test_memory_fuel_limit(wasm_runtime: WasmRuntime) -> anyhow::Result<()> let initial_value = 10_u64; let (application_id, _) = publisher - .create_application(bytecode_id, vm_runtime, &(), &initial_value, vec![]) + .create_application(bytecode_id, &(), &initial_value, vec![]) .await .unwrap() .unwrap(); diff --git a/linera-core/src/unit_tests/wasm_worker_tests.rs b/linera-core/src/unit_tests/wasm_worker_tests.rs index da36246e04f4..eba700d87ea0 100644 --- a/linera-core/src/unit_tests/wasm_worker_tests.rs +++ b/linera-core/src/unit_tests/wasm_worker_tests.rs @@ -21,6 +21,7 @@ use linera_base::{ BytecodeId, ChainDescription, ChainId, Destination, MessageId, UserApplicationId, }, ownership::ChainOwnership, + vm::{VmRuntime, WasmRuntime}, }; use linera_chain::{ data_types::{BlockExecutionOutcome, OutgoingMessage}, @@ -32,7 +33,7 @@ use linera_execution::{ system::{SystemMessage, SystemOperation}, test_utils::SystemExecutionState, Message, MessageKind, Operation, OperationContext, ResourceController, TransactionTracker, - UserApplicationDescription, VmRuntime, WasmContractModule, WasmRuntime, + UserApplicationDescription, WasmContractModule, }; use linera_storage::{DbStorage, Storage}; #[cfg(feature = "dynamodb")] @@ -127,7 +128,7 @@ where let contract_blob_hash = contract_blob_id.hash; let service_blob_hash = service_blob_id.hash; - let bytecode_id = BytecodeId::new(contract_blob_hash, service_blob_hash); + let bytecode_id = BytecodeId::new(contract_blob_hash, service_blob_hash, vm_runtime); let contract = WasmContractModule::new(contract_bytecode, wasm_runtime).await?; // Publish some bytecode. @@ -188,7 +189,6 @@ where let parameters_bytes = serde_json::to_vec(&())?; let create_operation = SystemOperation::CreateApplication { bytecode_id, - vm_runtime, parameters: parameters_bytes.clone(), instantiation_argument: initial_value_bytes.clone(), required_application_ids: vec![], @@ -203,7 +203,6 @@ where }; let application_description = UserApplicationDescription { bytecode_id, - vm_runtime, creation: application_id.creation, required_application_ids: vec![], parameters: parameters_bytes, diff --git a/linera-execution/Cargo.toml b/linera-execution/Cargo.toml index d2d2304f84ee..db9bf54ac104 100644 --- a/linera-execution/Cargo.toml +++ b/linera-execution/Cargo.toml @@ -51,7 +51,6 @@ cfg-if.workspace = true clap.workspace = true custom_debug_derive.workspace = true dashmap.workspace = true -derive_more = { workspace = true, features = ["display"] } dyn-clone.workspace = true futures.workspace = true hex = { workspace = true, optional = true } diff --git a/linera-execution/build.rs b/linera-execution/build.rs index ae9a0a85009b..516295bea701 100644 --- a/linera-execution/build.rs +++ b/linera-execution/build.rs @@ -12,9 +12,6 @@ fn main() { with_revm: { feature = "revm" }, with_wasmer: { feature = "wasmer" }, with_wasmtime: { all(not(target_arch = "wasm32"), feature = "wasmtime") }, - - // If you change this, don't forget to update `WasmRuntime` and - // `WasmRuntime::default_with_sanitizer` with_wasm_runtime: { any(with_wasmer, with_wasmtime) }, } } diff --git a/linera-execution/src/applications.rs b/linera-execution/src/applications.rs index d3bed6a6955b..866bfda0aaf1 100644 --- a/linera-execution/src/applications.rs +++ b/linera-execution/src/applications.rs @@ -16,7 +16,7 @@ use { std::collections::BTreeMap, }; -use crate::{SystemExecutionError, UserApplicationDescription, VmRuntime}; +use crate::{SystemExecutionError, UserApplicationDescription}; #[cfg(test)] #[path = "unit_tests/applications_tests.rs"] @@ -66,7 +66,6 @@ where pub async fn register_new_application( &mut self, application_id: UserApplicationId, - vm_runtime: VmRuntime, parameters: Vec, required_application_ids: Vec, ) -> Result<(), SystemExecutionError> { @@ -82,7 +81,6 @@ where let description = UserApplicationDescription { bytecode_id, parameters, - vm_runtime, creation, required_application_ids, }; diff --git a/linera-execution/src/execution_state_actor.rs b/linera-execution/src/execution_state_actor.rs index 85091a504260..dd511e6cc3f2 100644 --- a/linera-execution/src/execution_state_actor.rs +++ b/linera-execution/src/execution_state_actor.rs @@ -27,7 +27,7 @@ use crate::{ util::RespondExt, BytecodeId, ExecutionError, ExecutionRuntimeContext, ExecutionStateView, RawExecutionOutcome, RawOutgoingMessage, SystemExecutionError, SystemMessage, UserApplicationDescription, - UserApplicationId, UserContractCode, UserServiceCode, VmRuntime, + UserApplicationId, UserContractCode, UserServiceCode, }; #[cfg(with_metrics)] @@ -308,7 +308,6 @@ where CreateApplication { next_message_id, bytecode_id, - vm_runtime, parameters, required_application_ids, callback, @@ -318,7 +317,6 @@ where .create_application( next_message_id, bytecode_id, - vm_runtime, parameters, required_application_ids, ) @@ -513,7 +511,6 @@ pub enum ExecutionRequest { CreateApplication { next_message_id: MessageId, bytecode_id: BytecodeId, - vm_runtime: VmRuntime, parameters: Vec, required_application_ids: Vec, #[debug(skip)] diff --git a/linera-execution/src/lib.rs b/linera-execution/src/lib.rs index 2fe7e844557c..66d5e4a102ef 100644 --- a/linera-execution/src/lib.rs +++ b/linera-execution/src/lib.rs @@ -24,16 +24,17 @@ mod transaction_tracker; mod util; mod wasm; -use std::{any::Any, fmt, str::FromStr, sync::Arc}; +use std::{any::Any, fmt, sync::Arc}; -use async_graphql::{scalar, SimpleObject}; +use async_graphql::SimpleObject; use async_trait::async_trait; use committee::Epoch; use custom_debug_derive::Debug; use dashmap::DashMap; -use derive_more::Display; #[cfg(web)] use js_sys::wasm_bindgen::JsValue; +#[cfg(with_wasm_runtime)] +use linera_base::vm::WasmRuntime; use linera_base::{ abi::Abi, crypto::{BcsHashable, CryptoHash}, @@ -48,10 +49,9 @@ use linera_base::{ }, ownership::ChainOwnership, task, + vm::VmRuntime, }; use linera_views::{batch::Batch, views::ViewError}; -#[cfg(any(with_wasm_runtime, with_revm))] -use linera_witty::{WitLoad, WitType}; use serde::{Deserialize, Serialize}; use system::OpenChainConfig; use thiserror::Error; @@ -746,7 +746,6 @@ pub trait ContractRuntime: BaseRuntime { fn create_application( &mut self, bytecode_id: BytecodeId, - vm_runtime: VmRuntime, parameters: Vec, argument: Vec, required_application_ids: Vec, @@ -1314,176 +1313,28 @@ pub struct BlobState { pub epoch: Epoch, } -/// The runtime to use for running the application. -#[cfg(with_wasm_runtime)] -#[derive( - Clone, - Copy, - Display, - Hash, - PartialEq, - Eq, - Serialize, - Deserialize, - WitType, - WitLoad, - Debug, - Default, -)] -pub enum WasmRuntime { - #[cfg(with_wasmer)] - #[default] - #[display("wasmer")] - Wasmer, - #[cfg(with_wasmtime)] - #[cfg_attr(not(with_wasmer), default)] - #[display("wasmtime")] - Wasmtime, - #[cfg(with_wasmer)] - WasmerWithSanitizer, - #[cfg(with_wasmtime)] - WasmtimeWithSanitizer, -} - -#[cfg(with_wasm_runtime)] -scalar!(WasmRuntime); - -#[cfg(with_revm)] -#[derive( - Clone, - Copy, - Debug, - Display, - Hash, - PartialEq, - Eq, - Serialize, - Deserialize, - Default, - WitType, - WitLoad, -)] -pub enum EvmRuntime { - #[default] - #[display("revm")] - Revm, -} - -#[cfg(with_revm)] -scalar!(EvmRuntime); - -#[derive(Clone, Copy, Display, Hash, PartialEq, Eq, Serialize, Deserialize)] -#[cfg_attr(any(with_wasm_runtime, with_revm), derive(WitType, WitLoad))] -pub enum VmRuntime { - #[cfg(with_wasm_runtime)] - Wasm(WasmRuntime), - #[cfg(with_revm)] - Evm(EvmRuntime), -} - -impl fmt::Debug for VmRuntime { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - #[cfg(with_wasm_runtime)] - VmRuntime::Wasm(wasm_runtime) => write!(f, "{wasm_runtime:?}"), - #[cfg(with_revm)] - VmRuntime::Evm(evm_runtime) => write!(f, "{evm_runtime:?}"), - #[cfg(not(any(with_wasm_runtime, with_revm)))] - _ => write!(f, "No virtual machine selected"), - } - } -} - -#[cfg(any(with_wasm_runtime, with_revm))] -impl Default for VmRuntime { - #[cfg(with_wasm_runtime)] - fn default() -> Self { - VmRuntime::Wasm(WasmRuntime::default()) - } - - #[cfg(all(not(with_wasm_runtime), with_revm))] - fn default() -> Self { - VmRuntime::Evm(EvmRuntime::default()) - } -} - -scalar!(VmRuntime); - -/// Trait used to select a default `WasmRuntime`, if one is available. +/// Trait used to select a default `VmRuntime`, if one is available. pub trait WithVmDefault { fn with_vm_default(self) -> Self; } -#[cfg(with_wasm_runtime)] -impl WasmRuntime { - #[cfg(with_wasm_runtime)] - pub fn default_with_sanitizer() -> Self { - cfg_if::cfg_if! { - if #[cfg(with_wasmer)] { - WasmRuntime::WasmerWithSanitizer - } else if #[cfg(with_wasmtime)] { - WasmRuntime::WasmtimeWithSanitizer - } else { - compile_error!("BUG: Wasm runtime unhandled in `WasmRuntime::default_with_sanitizer`") - } - } - } - - pub fn needs_sanitizer(self) -> bool { - match self { - #[cfg(with_wasmer)] - WasmRuntime::WasmerWithSanitizer => true, - #[cfg(with_wasmtime)] - WasmRuntime::WasmtimeWithSanitizer => true, - #[cfg(with_wasm_runtime)] - _ => false, - } - } -} - impl WithVmDefault for Option { fn with_vm_default(self) -> Self { - let Some(vm_runtime) = self else { - #[cfg(any(with_wasm_runtime, with_revm))] - { - return Some(VmRuntime::default()); - } - #[cfg(not(any(with_wasm_runtime, with_revm)))] - { - return None; + match self { + Some(vm_runtime) => Some(vm_runtime), + None => { + cfg_if::cfg_if! { + if #[cfg(with_wasmer)] { + Some(VmRuntime::Wasm(WasmRuntime::Wasmer)) + } else if #[cfg(with_wasmtime)] { + Some(VmRuntime::Wasm(WasmRuntime::Wasmtime)) + } else if #[cfg(with_revm)] { + Some(VmRuntime::Evm(EvmRuntime::Revm)) + } else { + None + } + } } - }; - Some(vm_runtime) - } -} - -#[cfg(with_wasm_runtime)] -impl FromStr for WasmRuntime { - type Err = InvalidVmRuntime; - - fn from_str(string: &str) -> Result { - match string { - #[cfg(with_wasmer)] - "wasmer" => Ok(WasmRuntime::Wasmer), - #[cfg(with_wasmtime)] - "wasmtime" => Ok(WasmRuntime::Wasmtime), - unknown => Err(InvalidVmRuntime(unknown.to_owned())), - } - } -} - -impl FromStr for VmRuntime { - type Err = InvalidVmRuntime; - - fn from_str(string: &str) -> Result { - match string { - #[cfg(with_wasmer)] - "wasmer" => Ok(VmRuntime::Wasm(WasmRuntime::Wasmer)), - #[cfg(with_wasmtime)] - "wasmtime" => Ok(VmRuntime::Wasm(WasmRuntime::Wasmtime)), - #[cfg(with_revm)] - "revm" => Ok(VmRuntime::Evm(EvmRuntime::Revm)), - unknown => Err(InvalidVmRuntime(unknown.to_owned())), } } } @@ -1495,8 +1346,6 @@ pub struct UserApplicationDescription { pub bytecode_id: BytecodeId, /// The unique ID of the application's creation. pub creation: MessageId, - /// The virtual runtime being used - pub vm_runtime: VmRuntime, /// The parameters of the application. #[serde(with = "serde_bytes")] #[debug(with = "hex_debug")] @@ -1519,11 +1368,6 @@ doc_scalar!( "Description of the necessary information to run a user application" ); -/// Attempts to create an invalid [`VmRuntime`] instance from a string. -#[derive(Clone, Debug, Error)] -#[error("{0:?} is not a valid virtual machine runtime")] -pub struct InvalidVmRuntime(String); - doc_scalar!(Operation, "An operation to be executed in a block"); doc_scalar!( Message, diff --git a/linera-execution/src/revm.rs b/linera-execution/src/revm.rs index c5de22bc3c87..32dc52b842cb 100644 --- a/linera-execution/src/revm.rs +++ b/linera-execution/src/revm.rs @@ -9,7 +9,7 @@ use std::{ }; use alloy::primitives::{Address, B256, U256}; -use linera_base::{data_types::Bytecode, ensure, identifiers::StreamName}; +use linera_base::{data_types::Bytecode, ensure, identifiers::StreamName, vm::EvmRuntime}; use linera_views::common::from_bytes_option; use revm::{ db::AccountState, @@ -30,7 +30,7 @@ use { }; use crate::{ - BaseRuntime, Batch, ContractRuntime, ContractSyncRuntimeHandle, EvmRuntime, ExecutionError, + BaseRuntime, Batch, ContractRuntime, ContractSyncRuntimeHandle, ExecutionError, FinalizeContext, MessageContext, OperationContext, QueryContext, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract, UserContractInstance, UserContractModule, UserService, UserServiceInstance, UserServiceModule, ViewError, diff --git a/linera-execution/src/runtime.rs b/linera-execution/src/runtime.rs index 4301ef0bc960..01e87c751d3f 100644 --- a/linera-execution/src/runtime.rs +++ b/linera-execution/src/runtime.rs @@ -34,7 +34,7 @@ use crate::{ BaseRuntime, BytecodeId, ContractRuntime, ExecutionError, FinalizeContext, MessageContext, Operation, OperationContext, QueryContext, QueryOutcome, RawExecutionOutcome, ServiceRuntime, TransactionTracker, UserApplicationDescription, UserApplicationId, UserContractCode, - UserContractInstance, UserServiceCode, UserServiceInstance, VmRuntime, MAX_EVENT_KEY_LEN, + UserContractInstance, UserServiceCode, UserServiceInstance, MAX_EVENT_KEY_LEN, MAX_STREAM_NAME_LEN, }; @@ -1444,7 +1444,6 @@ impl ContractRuntime for ContractSyncRuntimeHandle { fn create_application( &mut self, bytecode_id: BytecodeId, - vm_runtime: VmRuntime, parameters: Vec, argument: Vec, required_application_ids: Vec, @@ -1469,7 +1468,6 @@ impl ContractRuntime for ContractSyncRuntimeHandle { .send_request(|callback| ExecutionRequest::CreateApplication { next_message_id: message_id, bytecode_id, - vm_runtime, parameters, required_application_ids, callback, diff --git a/linera-execution/src/system.rs b/linera-execution/src/system.rs index ec53dfea3dfb..b9bd65a2761d 100644 --- a/linera-execution/src/system.rs +++ b/linera-execution/src/system.rs @@ -47,7 +47,7 @@ use crate::{ ApplicationRegistryView, ChannelName, ChannelSubscription, Destination, ExecutionRuntimeContext, MessageContext, MessageKind, OperationContext, QueryContext, QueryOutcome, RawExecutionOutcome, RawOutgoingMessage, TransactionTracker, - UserApplicationDescription, UserApplicationId, VmRuntime, + UserApplicationDescription, UserApplicationId, }; /// The relative index of the `OpenChain` message created by the `OpenChain` operation. @@ -175,7 +175,6 @@ pub enum SystemOperation { /// Creates a new application. CreateApplication { bytecode_id: BytecodeId, - vm_runtime: VmRuntime, #[serde(with = "serde_bytes")] #[debug(with = "hex_debug")] parameters: Vec, @@ -643,7 +642,6 @@ where } CreateApplication { bytecode_id, - vm_runtime, parameters, instantiation_argument, required_application_ids, @@ -657,7 +655,6 @@ where .create_application( next_message_id, bytecode_id, - vm_runtime, parameters, required_application_ids, ) @@ -1033,7 +1030,6 @@ where &mut self, next_message_id: MessageId, bytecode_id: BytecodeId, - vm_runtime: VmRuntime, parameters: Vec, required_application_ids: Vec, ) -> Result { @@ -1055,7 +1051,7 @@ where } } self.registry - .register_new_application(id, vm_runtime, parameters, required_application_ids) + .register_new_application(id, parameters, required_application_ids) .await?; // Send a message to ourself to increment the message ID. let message = RawOutgoingMessage { diff --git a/linera-execution/src/test_utils/mod.rs b/linera-execution/src/test_utils/mod.rs index 832473c96e32..ff5b474722c7 100644 --- a/linera-execution/src/test_utils/mod.rs +++ b/linera-execution/src/test_utils/mod.rs @@ -50,8 +50,11 @@ pub fn create_dummy_user_application_description( let vm_runtime = VmRuntime::default(); ( UserApplicationDescription { - bytecode_id: BytecodeId::new(contract_blob.id().hash, service_blob.id().hash), - vm_runtime, + bytecode_id: BytecodeId::new( + contract_blob.id().hash, + service_blob.id().hash, + vm_runtime, + ), creation: MessageId { chain_id, height: BlockHeight(index), diff --git a/linera-execution/src/unit_tests/applications_tests.rs b/linera-execution/src/unit_tests/applications_tests.rs index ad56a3106a50..8e05d1319e04 100644 --- a/linera-execution/src/unit_tests/applications_tests.rs +++ b/linera-execution/src/unit_tests/applications_tests.rs @@ -5,11 +5,11 @@ use linera_base::{ crypto::CryptoHash, data_types::BlockHeight, identifiers::{BytecodeId, ChainId, MessageId}, + vm::VmRuntime, }; use super::{ ApplicationRegistry, ApplicationRegistryView, UserApplicationDescription, UserApplicationId, - VmRuntime, }; fn message_id(index: u32) -> MessageId { @@ -24,6 +24,7 @@ fn bytecode_id() -> BytecodeId { BytecodeId::new( CryptoHash::test_hash("contract"), CryptoHash::test_hash("service"), + VmRuntime::default(), ) } @@ -35,10 +36,8 @@ fn app_id(index: u32) -> UserApplicationId { } fn app_description(index: u32, deps: Vec) -> UserApplicationDescription { - let vm_runtime = VmRuntime::default(); UserApplicationDescription { bytecode_id: bytecode_id(), - vm_runtime, creation: message_id(index), parameters: vec![], required_application_ids: deps.into_iter().map(app_id).collect(), diff --git a/linera-execution/src/unit_tests/runtime_tests.rs b/linera-execution/src/unit_tests/runtime_tests.rs index a675e105bfd1..aded8fe5a257 100644 --- a/linera-execution/src/unit_tests/runtime_tests.rs +++ b/linera-execution/src/unit_tests/runtime_tests.rs @@ -15,6 +15,7 @@ use linera_base::{ crypto::CryptoHash, data_types::{BlockHeight, Timestamp}, identifiers::{ApplicationId, BytecodeId, ChainDescription, MessageId}, + vm::VmRuntime, }; use linera_views::batch::Batch; @@ -210,6 +211,7 @@ fn create_dummy_application_id() -> ApplicationId { bytecode_id: BytecodeId::new( CryptoHash::test_hash("contract"), CryptoHash::test_hash("service"), + VmRuntime::default(), ), creation: MessageId { chain_id, diff --git a/linera-execution/src/unit_tests/system_tests.rs b/linera-execution/src/unit_tests/system_tests.rs index 019d38550d4e..ef2585293a4f 100644 --- a/linera-execution/src/unit_tests/system_tests.rs +++ b/linera-execution/src/unit_tests/system_tests.rs @@ -1,6 +1,8 @@ // Copyright (c) Zefchain Labs, Inc. // SPDX-License-Identifier: Apache-2.0 +#[cfg(with_testing)] +use linera_base::vm::VmRuntime; use linera_base::{ data_types::{Blob, BlockHeight, Bytecode}, identifiers::ApplicationId, @@ -43,12 +45,11 @@ async fn application_message_index() -> anyhow::Result<()> { let service = Bytecode::new(b"service".into()); let contract_blob = Blob::new_contract_bytecode(contract.compress()); let service_blob = Blob::new_service_bytecode(service.compress()); - let bytecode_id = BytecodeId::new(contract_blob.id().hash, service_blob.id().hash); let vm_runtime = VmRuntime::default(); + let bytecode_id = BytecodeId::new(contract_blob.id().hash, service_blob.id().hash, vm_runtime); let operation = SystemOperation::CreateApplication { bytecode_id, - vm_runtime, parameters: vec![], instantiation_argument: vec![], required_application_ids: vec![], diff --git a/linera-execution/src/wasm/mod.rs b/linera-execution/src/wasm/mod.rs index 896b32c33cd7..a6fbd1ba991f 100644 --- a/linera-execution/src/wasm/mod.rs +++ b/linera-execution/src/wasm/mod.rs @@ -20,7 +20,7 @@ mod wasmer; #[cfg(with_wasmtime)] mod wasmtime; -use linera_base::data_types::Bytecode; +use linera_base::{data_types::Bytecode, vm::WasmRuntime}; use thiserror::Error; #[cfg(with_wasmer)] use wasmer::{WasmerContractInstance, WasmerServiceInstance}; @@ -40,7 +40,7 @@ pub use self::{ }; use crate::{ ContractSyncRuntimeHandle, ExecutionError, ServiceSyncRuntimeHandle, UserContractInstance, - UserContractModule, UserServiceInstance, UserServiceModule, WasmRuntime, + UserContractModule, UserServiceInstance, UserServiceModule, }; #[cfg(with_metrics)] @@ -89,13 +89,23 @@ impl WasmContractModule { contract_bytecode }; match runtime { - #[cfg(with_wasmer)] WasmRuntime::Wasmer | WasmRuntime::WasmerWithSanitizer => { - Self::from_wasmer(contract_bytecode).await + cfg_if::cfg_if! { + if #[cfg(with_wasmer)] { + Self::from_wasmer(contract_bytecode).await + } else { + panic!("Cannot use WasmRuntime::Wasmer when feature wasmer has not been used"); + } + } } - #[cfg(with_wasmtime)] WasmRuntime::Wasmtime | WasmRuntime::WasmtimeWithSanitizer => { - Self::from_wasmtime(contract_bytecode).await + cfg_if::cfg_if! { + if #[cfg(with_wasmtime)] { + Self::from_wasmtime(contract_bytecode).await + } else { + panic!("Cannot use WasmRuntime::Wasmtime when feature wasmtime has not been used"); + } + } } } } @@ -156,13 +166,23 @@ impl WasmServiceModule { runtime: WasmRuntime, ) -> Result { match runtime { - #[cfg(with_wasmer)] WasmRuntime::Wasmer | WasmRuntime::WasmerWithSanitizer => { - Self::from_wasmer(service_bytecode).await + cfg_if::cfg_if! { + if #[cfg(with_wasmer)] { + Self::from_wasmer(service_bytecode).await + } else { + panic!("Cannot use WasmRuntime::Wasmer when feature wasmer has not been used"); + } + } } - #[cfg(with_wasmtime)] WasmRuntime::Wasmtime | WasmRuntime::WasmtimeWithSanitizer => { - Self::from_wasmtime(service_bytecode).await + cfg_if::cfg_if! { + if #[cfg(with_wasmtime)] { + Self::from_wasmtime(service_bytecode).await + } else { + panic!("Cannot use WasmRuntime::Wasmtime when feature wasmtime has not been used"); + } + } } } } @@ -346,7 +366,18 @@ pub mod test { wasm_runtime: impl Into>, ) -> Result<(WasmContractModule, WasmServiceModule), anyhow::Error> { let (contract_path, service_path) = get_example_bytecode_paths(name)?; - let wasm_runtime = wasm_runtime.into().unwrap_or_default(); + let wasm_runtime = match wasm_runtime.into() { + Some(wasm_runtime) => wasm_runtime, + None => { + cfg_if::cfg_if! { + if #[cfg(with_wasmer)] { + WasmRuntime::Wasmer + } else { + WasmRuntime::Wasmtime + } + } + } + }; let contract = WasmContractModule::from_file(&contract_path, wasm_runtime).await?; let service = WasmServiceModule::from_file(&service_path, wasm_runtime).await?; Ok((contract, service)) diff --git a/linera-execution/src/wasm/system_api.rs b/linera-execution/src/wasm/system_api.rs index ceaaa94902ba..203d39ad4e2c 100644 --- a/linera-execution/src/wasm/system_api.rs +++ b/linera-execution/src/wasm/system_api.rs @@ -19,7 +19,7 @@ use tracing::log; use super::WasmExecutionError; use crate::{ BaseRuntime, BytecodeId, ContractRuntime, ContractSyncRuntimeHandle, ExecutionError, - ServiceRuntime, ServiceSyncRuntimeHandle, VmRuntime, + ServiceRuntime, ServiceSyncRuntimeHandle, }; /// Common host data used as the `UserData` of the system API implementations. @@ -326,7 +326,6 @@ where fn create_application( caller: &mut Caller, bytecode_id: BytecodeId, - vm_runtime: VmRuntime, parameters: Vec, argument: Vec, required_application_ids: Vec, @@ -334,13 +333,7 @@ where caller .user_data_mut() .runtime - .create_application( - bytecode_id, - vm_runtime, - parameters, - argument, - required_application_ids, - ) + .create_application(bytecode_id, parameters, argument, required_application_ids) .map_err(|error| RuntimeError::Custom(error.into())) } diff --git a/linera-execution/tests/contract_runtime_apis.rs b/linera-execution/tests/contract_runtime_apis.rs index 0fbe6ae0d445..d69c603df6c0 100644 --- a/linera-execution/tests/contract_runtime_apis.rs +++ b/linera-execution/tests/contract_runtime_apis.rs @@ -18,6 +18,7 @@ use linera_base::{ Owner, }, ownership::ChainOwnership, + vm::VmRuntime, }; use linera_execution::{ test_utils::{ @@ -27,7 +28,7 @@ use linera_execution::{ BaseRuntime, ContractRuntime, ExecutionError, ExecutionOutcome, Message, MessageContext, Operation, OperationContext, ResourceController, SystemExecutionError, SystemExecutionStateView, TestExecutionRuntimeContext, TransactionOutcome, TransactionTracker, - UserApplicationDescription, VmRuntime, + UserApplicationDescription, }; use linera_views::context::MemoryContext; use test_case::test_matrix; @@ -660,8 +661,7 @@ impl TransferTestEndpoint { let vm_runtime = VmRuntime::default(); UserApplicationDescription { - bytecode_id: BytecodeId::new(contract_id, service_id), - vm_runtime, + bytecode_id: BytecodeId::new(contract_id, service_id, vm_runtime), creation: MessageId { chain_id: ChainId::root(1000), height: BlockHeight(0), @@ -699,6 +699,7 @@ impl TransferTestEndpoint { bytecode_id: BytecodeId::new( CryptoHash::test_hash("recipient contract bytecode"), CryptoHash::test_hash("recipient service bytecode"), + VmRuntime::default(), ), creation: MessageId { chain_id: ChainId::root(2000), diff --git a/linera-execution/tests/wasm.rs b/linera-execution/tests/wasm.rs index b85b8a8383c7..1536eb14969b 100644 --- a/linera-execution/tests/wasm.rs +++ b/linera-execution/tests/wasm.rs @@ -8,13 +8,13 @@ use std::sync::Arc; use linera_base::{ data_types::{Amount, BlockHeight, Timestamp}, identifiers::{Account, ChainDescription, ChainId}, + vm::WasmRuntime, }; use linera_execution::{ test_utils::{create_dummy_user_application_description, SystemExecutionState}, ExecutionOutcome, ExecutionRuntimeConfig, ExecutionRuntimeContext, Operation, OperationContext, Query, QueryContext, QueryOutcome, QueryResponse, RawExecutionOutcome, ResourceControlPolicy, - ResourceController, ResourceTracker, TransactionTracker, WasmContractModule, WasmRuntime, - WasmServiceModule, + ResourceController, ResourceTracker, TransactionTracker, WasmContractModule, WasmServiceModule, }; use linera_views::{context::Context as _, views::View}; use serde_json::json; diff --git a/linera-sdk/src/contract/conversions_from_wit.rs b/linera-sdk/src/contract/conversions_from_wit.rs index 86013f146440..94e8ca6f6447 100644 --- a/linera-sdk/src/contract/conversions_from_wit.rs +++ b/linera-sdk/src/contract/conversions_from_wit.rs @@ -11,6 +11,7 @@ use linera_base::{ ownership::{ ChainOwnership, ChangeApplicationPermissionsError, CloseChainError, TimeoutConfig, }, + vm::{EvmRuntime, VmRuntime, WasmRuntime}, }; use super::wit::contract_system_api as wit_system_api; @@ -45,10 +46,27 @@ impl From for BytecodeId { BytecodeId::new( bytecode_id.contract_blob_hash.into(), bytecode_id.service_blob_hash.into(), + bytecode_id.vm_runtime.into(), ) } } +impl From for VmRuntime { + fn from(vm_runtime: wit_system_api::VmRuntime) -> Self { + match vm_runtime { + wit_system_api::VmRuntime::Wasmer => VmRuntime::Wasm(WasmRuntime::Wasmer), + wit_system_api::VmRuntime::Wasmtime => VmRuntime::Wasm(WasmRuntime::Wasmtime), + wit_system_api::VmRuntime::Wasmerwithsanitizer => { + VmRuntime::Wasm(WasmRuntime::WasmerWithSanitizer) + } + wit_system_api::VmRuntime::Wasmtimewithsanitizer => { + VmRuntime::Wasm(WasmRuntime::WasmtimeWithSanitizer) + } + wit_system_api::VmRuntime::Revm => VmRuntime::Evm(EvmRuntime::Revm), + } + } +} + impl From for ChainId { fn from(chain_id: wit_system_api::ChainId) -> Self { ChainId(chain_id.inner0.into()) diff --git a/linera-sdk/src/contract/conversions_to_wit.rs b/linera-sdk/src/contract/conversions_to_wit.rs index e65c376c09f2..363731980a77 100644 --- a/linera-sdk/src/contract/conversions_to_wit.rs +++ b/linera-sdk/src/contract/conversions_to_wit.rs @@ -15,6 +15,7 @@ use linera_base::{ MessageId, Owner, StreamName, }, ownership::{ChainOwnership, TimeoutConfig}, + vm::{VmRuntime, WasmRuntime}, }; use super::wit::contract_system_api as wit_system_api; @@ -104,6 +105,23 @@ impl From for wit_system_api::BytecodeId { wit_system_api::BytecodeId { contract_blob_hash: bytecode_id.contract_blob_hash.into(), service_blob_hash: bytecode_id.service_blob_hash.into(), + vm_runtime: bytecode_id.vm_runtime.into(), + } + } +} + +impl From for wit_system_api::VmRuntime { + fn from(vm_runtime: VmRuntime) -> Self { + match vm_runtime { + VmRuntime::Wasm(wasm_runtime) => match wasm_runtime { + WasmRuntime::Wasmer => wit_system_api::VmRuntime::Wasmer, + WasmRuntime::Wasmtime => wit_system_api::VmRuntime::Wasmtime, + WasmRuntime::WasmerWithSanitizer => wit_system_api::VmRuntime::Wasmerwithsanitizer, + WasmRuntime::WasmtimeWithSanitizer => { + wit_system_api::VmRuntime::Wasmtimewithsanitizer + } + }, + VmRuntime::Evm(_) => wit_system_api::VmRuntime::Revm, } } } diff --git a/linera-sdk/src/service/conversions_from_wit.rs b/linera-sdk/src/service/conversions_from_wit.rs index 889dad655ce8..4310529e788c 100644 --- a/linera-sdk/src/service/conversions_from_wit.rs +++ b/linera-sdk/src/service/conversions_from_wit.rs @@ -8,6 +8,7 @@ use linera_base::{ data_types::{Amount, BlockHeight, Timestamp}, http, identifiers::{AccountOwner, ApplicationId, BytecodeId, ChainId, MessageId, Owner}, + vm::{EvmRuntime, VmRuntime, WasmRuntime}, }; use super::wit::service_system_api as wit_system_api; @@ -90,10 +91,27 @@ impl From for BytecodeId { BytecodeId::new( bytecode_id.contract_blob_hash.into(), bytecode_id.service_blob_hash.into(), + bytecode_id.vm_runtime.into(), ) } } +impl From for VmRuntime { + fn from(vm_runtime: wit_system_api::VmRuntime) -> Self { + match vm_runtime { + wit_system_api::VmRuntime::Wasmer => VmRuntime::Wasm(WasmRuntime::Wasmer), + wit_system_api::VmRuntime::Wasmtime => VmRuntime::Wasm(WasmRuntime::Wasmtime), + wit_system_api::VmRuntime::Wasmerwithsanitizer => { + VmRuntime::Wasm(WasmRuntime::WasmerWithSanitizer) + } + wit_system_api::VmRuntime::Wasmtimewithsanitizer => { + VmRuntime::Wasm(WasmRuntime::WasmtimeWithSanitizer) + } + wit_system_api::VmRuntime::Revm => VmRuntime::Evm(EvmRuntime::Revm), + } + } +} + impl From for Timestamp { fn from(timestamp: wit_system_api::Timestamp) -> Self { Timestamp::from(timestamp.inner0) diff --git a/linera-sdk/src/service/conversions_to_wit.rs b/linera-sdk/src/service/conversions_to_wit.rs index 8bd32686f626..fbe5e60d7ba9 100644 --- a/linera-sdk/src/service/conversions_to_wit.rs +++ b/linera-sdk/src/service/conversions_to_wit.rs @@ -8,6 +8,7 @@ use linera_base::{ data_types::BlockHeight, http, identifiers::{AccountOwner, ApplicationId, BytecodeId, ChainId, MessageId, Owner}, + vm::{VmRuntime, WasmRuntime}, }; use super::wit::service_system_api as wit_system_api; @@ -86,6 +87,23 @@ impl From for wit_system_api::BytecodeId { wit_system_api::BytecodeId { contract_blob_hash: bytecode_id.contract_blob_hash.into(), service_blob_hash: bytecode_id.service_blob_hash.into(), + vm_runtime: bytecode_id.vm_runtime.into(), + } + } +} + +impl From for wit_system_api::VmRuntime { + fn from(vm_runtime: VmRuntime) -> Self { + match vm_runtime { + VmRuntime::Wasm(wasm_runtime) => match wasm_runtime { + WasmRuntime::Wasmer => wit_system_api::VmRuntime::Wasmer, + WasmRuntime::Wasmtime => wit_system_api::VmRuntime::Wasmtime, + WasmRuntime::WasmerWithSanitizer => wit_system_api::VmRuntime::Wasmerwithsanitizer, + WasmRuntime::WasmtimeWithSanitizer => { + wit_system_api::VmRuntime::Wasmtimewithsanitizer + } + }, + VmRuntime::Evm(_) => wit_system_api::VmRuntime::Revm, } } } diff --git a/linera-sdk/src/test/chain.rs b/linera-sdk/src/test/chain.rs index 93503f9a6309..fdf4e8312f77 100644 --- a/linera-sdk/src/test/chain.rs +++ b/linera-sdk/src/test/chain.rs @@ -16,12 +16,13 @@ use linera_base::{ crypto::{AccountPublicKey, AccountSecretKey}, data_types::{Blob, BlockHeight, Bytecode, CompressedBytecode}, identifiers::{ApplicationId, BytecodeId, ChainDescription, ChainId, MessageId}, + vm::VmRuntime, }; use linera_chain::{types::ConfirmedBlockCertificate, ChainError, ChainExecutionContext}; use linera_core::{data_types::ChainInfoQuery, worker::WorkerError}; use linera_execution::{ system::{SystemExecutionError, SystemOperation, CREATE_APPLICATION_MESSAGE_INDEX}, - ExecutionError, Query, QueryOutcome, QueryResponse, VmRuntime, + ExecutionError, Query, QueryOutcome, QueryResponse, }; use linera_storage::Storage as _; use serde::Serialize; @@ -214,8 +215,9 @@ impl ActiveChain { let service_blob = Blob::new_service_bytecode(service); let contract_blob_hash = contract_blob.id().hash; let service_blob_hash = service_blob.id().hash; + let vm_runtime = VmRuntime::default(); - let bytecode_id = BytecodeId::new(contract_blob_hash, service_blob_hash); + let bytecode_id = BytecodeId::new(contract_blob_hash, service_blob_hash, vm_runtime); let certificate = self .add_block_with_blobs( @@ -353,7 +355,6 @@ impl ActiveChain { pub async fn create_application( &mut self, bytecode_id: BytecodeId, - vm_runtime: VmRuntime, parameters: Parameters, instantiation_argument: InstantiationArgument, required_application_ids: Vec, @@ -374,7 +375,6 @@ impl ActiveChain { .add_block(|block| { block.with_system_operation(SystemOperation::CreateApplication { bytecode_id: bytecode_id.forget_abi(), - vm_runtime, parameters, instantiation_argument, required_application_ids, diff --git a/linera-sdk/src/test/validator.rs b/linera-sdk/src/test/validator.rs index 915469270d9c..b067462b4b27 100644 --- a/linera-sdk/src/test/validator.rs +++ b/linera-sdk/src/test/validator.rs @@ -20,7 +20,6 @@ use linera_core::worker::WorkerState; use linera_execution::{ committee::{Committee, Epoch}, system::{OpenChainConfig, SystemOperation, OPEN_CHAIN_MESSAGE_INDEX}, - VmRuntime, }; use linera_storage::{DbStorage, Storage, TestClock}; use linera_views::memory::MemoryStore; @@ -118,7 +117,6 @@ impl TestValidator { /// Returns the new [`TestValidator`], the [`ApplicationId`] of the created application, and /// the chain on which it was created. pub async fn with_current_application( - vm_runtime: VmRuntime, parameters: Parameters, instantiation_argument: InstantiationArgument, ) -> (TestValidator, ApplicationId, ActiveChain) @@ -133,13 +131,7 @@ impl TestValidator { let mut creator = validator.new_chain().await; let application_id = creator - .create_application( - bytecode_id, - vm_runtime, - parameters, - instantiation_argument, - vec![], - ) + .create_application(bytecode_id, parameters, instantiation_argument, vec![]) .await; (validator, application_id, creator) diff --git a/linera-sdk/wit/contract-system-api.wit b/linera-sdk/wit/contract-system-api.wit index 6d7c89ec6c89..74b98c98dc27 100644 --- a/linera-sdk/wit/contract-system-api.wit +++ b/linera-sdk/wit/contract-system-api.wit @@ -67,6 +67,15 @@ interface contract-system-api { record bytecode-id { contract-blob-hash: crypto-hash, service-blob-hash: crypto-hash, + vm-runtime: vm-runtime, + } + + enum vm-runtime { + wasmer, + wasmtime, + wasmerwithsanitizer, + wasmtimewithsanitizer, + revm, } record chain-id { diff --git a/linera-sdk/wit/service-system-api.wit b/linera-sdk/wit/service-system-api.wit index 18bee9ea510b..90f0c4dd7d46 100644 --- a/linera-sdk/wit/service-system-api.wit +++ b/linera-sdk/wit/service-system-api.wit @@ -41,6 +41,15 @@ interface service-system-api { record bytecode-id { contract-blob-hash: crypto-hash, service-blob-hash: crypto-hash, + vm-runtime: vm-runtime, + } + + enum vm-runtime { + wasmer, + wasmtime, + wasmerwithsanitizer, + wasmtimewithsanitizer, + revm, } record chain-id { diff --git a/linera-service/src/linera/main.rs b/linera-service/src/linera/main.rs index 6d3c12e44e86..b390cffc21c6 100644 --- a/linera-service/src/linera/main.rs +++ b/linera-service/src/linera/main.rs @@ -890,14 +890,18 @@ impl Runnable for Job { PublishBytecode { contract, service, + vm_runtime, publisher, } => { let start_time = Instant::now(); let publisher = publisher.unwrap_or_else(|| context.default_chain()); info!("Publishing bytecode on chain {}", publisher); let chain_client = context.make_chain_client(publisher)?; + let vm_runtime = vm_runtime + .with_vm_default() + .expect("A virtual machine to be available"); let bytecode_id = context - .publish_bytecode(&chain_client, contract, service) + .publish_bytecode(&chain_client, contract, service, vm_runtime) .await?; println!("{}", bytecode_id); info!( @@ -934,7 +938,6 @@ impl Runnable for Job { CreateApplication { bytecode_id, - vm_runtime, creator, json_parameters, json_parameters_path, @@ -949,9 +952,6 @@ impl Runnable for Job { let parameters = read_json(json_parameters, json_parameters_path)?; let argument = read_json(json_argument, json_argument_path)?; - let vm_runtime = vm_runtime - .with_vm_default() - .expect("A virtual machine to be available"); info!("Synchronizing"); let chain_client = chain_client; context.process_inbox(&chain_client).await?; @@ -966,7 +966,6 @@ impl Runnable for Job { chain_client .create_application_untyped( bytecode_id, - vm_runtime, parameters, argument, required_application_ids.unwrap_or_default(), @@ -1006,7 +1005,7 @@ impl Runnable for Job { .expect("A virtual machine should be available"); let bytecode_id = context - .publish_bytecode(&chain_client, contract, service) + .publish_bytecode(&chain_client, contract, service, vm_runtime) .await?; let (application_id, _) = context @@ -1019,7 +1018,6 @@ impl Runnable for Job { chain_client .create_application_untyped( bytecode_id, - vm_runtime, parameters, argument, required_application_ids.unwrap_or_default(), @@ -1110,7 +1108,7 @@ impl Runnable for Job { let (contract_path, service_path) = project.build(name)?; let bytecode_id = context - .publish_bytecode(&chain_client, contract_path, service_path) + .publish_bytecode(&chain_client, contract_path, service_path, vm_runtime) .await?; let (application_id, _) = context @@ -1123,7 +1121,6 @@ impl Runnable for Job { chain_client .create_application_untyped( bytecode_id, - vm_runtime, parameters, argument, required_application_ids.unwrap_or_default(), diff --git a/linera-service/src/node_service.rs b/linera-service/src/node_service.rs index 2f278bb0a39f..d12fcf2ed8a1 100644 --- a/linera-service/src/node_service.rs +++ b/linera-service/src/node_service.rs @@ -20,6 +20,7 @@ use linera_base::{ hashed::Hashed, identifiers::{ApplicationId, BytecodeId, ChainId, Owner, UserApplicationId}, ownership::{ChainOwnership, TimeoutConfig}, + vm::VmRuntime, BcsHexParseError, }; use linera_chain::{ @@ -36,7 +37,6 @@ use linera_execution::{ committee::{Committee, Epoch}, system::{AdminOperation, Recipient, SystemChannel}, Operation, Query, QueryOutcome, QueryResponse, SystemOperation, UserApplicationDescription, - VmRuntime, }; use linera_sdk::base::BlobContent; use linera_storage::Storage; @@ -564,13 +564,14 @@ where chain_id: ChainId, contract: Bytecode, service: Bytecode, + vm_runtime: VmRuntime, ) -> Result { self.apply_client_command(&chain_id, move |client| { let contract = contract.clone(); let service = service.clone(); async move { let result = client - .publish_bytecode(contract, service) + .publish_bytecode(contract, service, vm_runtime) .await .map_err(Error::from) .map(|outcome| outcome.map(|(bytecode_id, _)| bytecode_id)); @@ -603,7 +604,6 @@ where &self, chain_id: ChainId, bytecode_id: BytecodeId, - vm_runtime: VmRuntime, parameters: String, instantiation_argument: String, required_application_ids: Vec, @@ -616,7 +616,6 @@ where let result = client .create_application_untyped( bytecode_id, - vm_runtime, parameters, instantiation_argument, required_application_ids, diff --git a/linera-storage/Cargo.toml b/linera-storage/Cargo.toml index eba1aa75338d..df798bed59d2 100644 --- a/linera-storage/Cargo.toml +++ b/linera-storage/Cargo.toml @@ -32,6 +32,7 @@ web = [ [dependencies] async-trait.workspace = true bcs.workspace = true +cfg-if.workspace = true dashmap.workspace = true futures.workspace = true linera-base.workspace = true diff --git a/linera-storage/src/lib.rs b/linera-storage/src/lib.rs index 13b0fb53d1a1..ef07060fb93d 100644 --- a/linera-storage/src/lib.rs +++ b/linera-storage/src/lib.rs @@ -13,10 +13,11 @@ use async_trait::async_trait; use dashmap::{mapref::entry::Entry, DashMap}; use linera_base::{ crypto::CryptoHash, - data_types::{Amount, Blob, BlockHeight, TimeDelta, Timestamp}, + data_types::{Amount, Blob, BlockHeight, CompressedBytecode, TimeDelta, Timestamp}, hashed::Hashed, - identifiers::{BlobId, ChainDescription, ChainId, EventId, Owner, UserApplicationId}, + identifiers::{BlobId, BlobType, ChainDescription, ChainId, EventId, Owner, UserApplicationId}, ownership::ChainOwnership, + vm::VmRuntime, }; use linera_chain::{ types::{ConfirmedBlock, ConfirmedBlockCertificate}, @@ -24,23 +25,18 @@ use linera_chain::{ }; #[cfg(with_revm)] use linera_execution::revm::{EvmContractModule, EvmServiceModule}; -#[cfg(any(with_wasm_runtime, with_revm))] -use linera_execution::VmRuntime; use linera_execution::{ committee::{Committee, Epoch}, system::SystemChannel, BlobState, ChannelSubscription, ExecutionError, ExecutionRuntimeConfig, ExecutionRuntimeContext, UserApplicationDescription, UserContractCode, UserServiceCode, }; +#[cfg(with_wasm_runtime)] +use linera_execution::{WasmContractModule, WasmServiceModule}; use linera_views::{ context::Context, views::{CryptoHashView, RootView, ViewError}, }; -#[cfg(with_wasm_runtime)] -use { - linera_base::{data_types::CompressedBytecode, identifiers::BlobType}, - linera_execution::{WasmContractModule, WasmServiceModule}, -}; #[cfg(with_testing)] pub use crate::db_storage::TestClock; @@ -263,7 +259,6 @@ pub trait Storage: Sized { /// Creates a [`UserContractCode`] instance using the bytecode in storage referenced /// by the `application_description`. - #[cfg(any(with_wasm_runtime, with_revm))] async fn load_contract( &self, application_description: &UserApplicationDescription, @@ -276,44 +271,49 @@ pub trait Storage: Sized { let compressed_contract_bytecode = CompressedBytecode { compressed_bytes: contract_blob.into_bytes().to_vec(), }; - let contract_bytecode = + let _contract_bytecode = linera_base::task::Blocking::::spawn( move |_| async move { compressed_contract_bytecode.decompress() }, ) .await .join() .await?; - match application_description.vm_runtime { - VmRuntime::Wasm(wasm_runtime) => { - Ok(WasmContractModule::new(contract_bytecode, wasm_runtime) - .await? - .into()) + match application_description.bytecode_id.vm_runtime { + VmRuntime::Wasm(_wasm_runtime) => { + cfg_if::cfg_if! { + if #[cfg(with_wasm_runtime)] { + Ok(WasmContractModule::new(_contract_bytecode, _wasm_runtime) + .await? + .into()) + } else { + panic!( + "A Wasm runtime is required to load user applications. \ + Please enable the `wasmer` or the `wasmtime` feature flags \ + when compiling `linera-storage`." + ); + } + } } - #[cfg(with_revm)] - VmRuntime::Evm(evm_runtime) => { - Ok(EvmContractModule::new(contract_bytecode, evm_runtime) - .await? - .into()) + VmRuntime::Evm(_evm_runtime) => { + cfg_if::cfg_if! { + if #[cfg(with_revm)] { + Ok(EvmContractModule::new(_contract_bytecode, _evm_runtime) + .await? + .into()) + } else { + panic!( + "An Evm runtime is required to load user applications. \ + Please enable the `revm` feature flags \ + when compiling `linera-storage`." + ); + } + } } } } - #[cfg(not(any(with_wasm_runtime, with_revm)))] - #[allow(clippy::diverging_sub_expression)] - async fn load_contract( - &self, - _application_description: &UserApplicationDescription, - ) -> Result { - panic!( - "A Wasm runtime is required to load user applications. \ - Please enable the `wasmer` or the `wasmtime` feature flags \ - when compiling `linera-storage`." - ); - } - /// Creates a [`linera-sdk::UserContract`] instance using the bytecode in storage referenced /// by the `application_description`. - #[cfg(any(with_wasm_runtime, with_revm))] async fn load_service( &self, application_description: &UserApplicationDescription, @@ -326,37 +326,46 @@ pub trait Storage: Sized { let compressed_service_bytecode = CompressedBytecode { compressed_bytes: service_blob.into_bytes().to_vec(), }; - let service_bytecode = linera_base::task::Blocking::::spawn( - move |_| async move { compressed_service_bytecode.decompress() }, - ) - .await - .join() - .await?; - match application_description.vm_runtime { - VmRuntime::Wasm(wasm_runtime) => { - Ok(WasmServiceModule::new(service_bytecode, wasm_runtime) - .await? - .into()) + let _service_bytecode = + linera_base::task::Blocking::::spawn( + move |_| async move { compressed_service_bytecode.decompress() }, + ) + .await + .join() + .await?; + match application_description.bytecode_id.vm_runtime { + VmRuntime::Wasm(_wasm_runtime) => { + cfg_if::cfg_if! { + if #[cfg(with_wasm_runtime)] { + Ok(WasmServiceModule::new(_service_bytecode, _wasm_runtime) + .await? + .into()) + } else { + panic!( + "A Wasm runtime is required to load user applications. \ + Please enable the `wasmer` or the `wasmtime` feature flags \ + when compiling `linera-storage`." + ); + } + } + } + VmRuntime::Evm(_evm_runtime) => { + cfg_if::cfg_if! { + if #[cfg(with_revm)] { + Ok(EvmServiceModule::new(_service_bytecode, _evm_runtime) + .await? + .into()) + } else { + panic!( + "An Evm runtime is required to load user applications. \ + Please enable the `revm` feature flags \ + when compiling `linera-storage`." + ); + } + } } - #[cfg(with_revm)] - VmRuntime::Evm(evm_runtime) => Ok(EvmServiceModule::new(service_bytecode, evm_runtime) - .await? - .into()), } } - - #[cfg(not(any(with_wasm_runtime, with_revm)))] - #[allow(clippy::diverging_sub_expression)] - async fn load_service( - &self, - _application_description: &UserApplicationDescription, - ) -> Result { - panic!( - "A Wasm runtime is required to load user applications. \ - Please enable the `wasmer` or the `wasmtime` feature flags \ - when compiling `linera-storage`." - ); - } } #[derive(Clone)]