linera_execution/
lib.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! This module manages the execution of the system application and the user applications in a
5//! Linera chain.
6
7#![deny(clippy::large_futures)]
8
9pub mod committee;
10mod execution;
11mod execution_state_actor;
12mod graphql;
13mod policy;
14mod resources;
15#[cfg(with_revm)]
16pub mod revm;
17mod runtime;
18pub mod system;
19#[cfg(with_testing)]
20pub mod test_utils;
21mod transaction_tracker;
22mod util;
23mod wasm;
24
25use std::{any::Any, fmt, str::FromStr, sync::Arc};
26
27use async_graphql::SimpleObject;
28use async_trait::async_trait;
29use committee::Epoch;
30use custom_debug_derive::Debug;
31use dashmap::DashMap;
32use derive_more::Display;
33#[cfg(web)]
34use js_sys::wasm_bindgen::JsValue;
35use linera_base::{
36    abi::Abi,
37    crypto::{BcsHashable, CryptoHash},
38    data_types::{
39        Amount, ApplicationDescription, ApplicationPermissions, ArithmeticError, Blob, BlockHeight,
40        DecompressionError, Resources, SendMessageRequest, Timestamp,
41    },
42    doc_scalar, hex_debug, http,
43    identifiers::{
44        Account, AccountOwner, ApplicationId, BlobId, BlobType, ChainId, ChannelName, Destination,
45        EventId, GenericApplicationId, MessageId, ModuleId, StreamName,
46    },
47    ownership::ChainOwnership,
48    task,
49};
50use linera_views::{batch::Batch, views::ViewError};
51use serde::{Deserialize, Serialize};
52use system::{AdminOperation, OpenChainConfig};
53use thiserror::Error;
54
55#[cfg(with_revm)]
56use crate::revm::EvmExecutionError;
57use crate::runtime::ContractSyncRuntime;
58#[cfg(all(with_testing, with_wasm_runtime))]
59pub use crate::wasm::test as wasm_test;
60#[cfg(with_wasm_runtime)]
61pub use crate::wasm::{
62    BaseRuntimeApi, ContractEntrypoints, ContractRuntimeApi, RuntimeApiData, ServiceEntrypoints,
63    ServiceRuntimeApi, WasmContractModule, WasmExecutionError, WasmServiceModule,
64};
65pub use crate::{
66    execution::{ExecutionStateView, ServiceRuntimeEndpoint},
67    execution_state_actor::ExecutionRequest,
68    policy::ResourceControlPolicy,
69    resources::{ResourceController, ResourceTracker},
70    runtime::{
71        ContractSyncRuntimeHandle, ServiceRuntimeRequest, ServiceSyncRuntime,
72        ServiceSyncRuntimeHandle,
73    },
74    system::{
75        SystemExecutionStateView, SystemMessage, SystemOperation, SystemQuery, SystemResponse,
76    },
77    transaction_tracker::{TransactionOutcome, TransactionTracker},
78};
79
80/// The maximum length of a stream name.
81const MAX_STREAM_NAME_LEN: usize = 64;
82
83/// An implementation of [`UserContractModule`].
84#[derive(Clone)]
85pub struct UserContractCode(Box<dyn UserContractModule>);
86
87/// An implementation of [`UserServiceModule`].
88#[derive(Clone)]
89pub struct UserServiceCode(Box<dyn UserServiceModule>);
90
91/// An implementation of [`UserContract`].
92pub type UserContractInstance = Box<dyn UserContract>;
93
94/// An implementation of [`UserService`].
95pub type UserServiceInstance = Box<dyn UserService>;
96
97/// A factory trait to obtain a [`UserContract`] from a [`UserContractModule`]
98pub trait UserContractModule: dyn_clone::DynClone + Any + task::Post + Send + Sync {
99    fn instantiate(
100        &self,
101        runtime: ContractSyncRuntimeHandle,
102    ) -> Result<UserContractInstance, ExecutionError>;
103}
104
105impl<T: UserContractModule + Send + Sync + 'static> From<T> for UserContractCode {
106    fn from(module: T) -> Self {
107        Self(Box::new(module))
108    }
109}
110
111dyn_clone::clone_trait_object!(UserContractModule);
112
113/// A factory trait to obtain a [`UserService`] from a [`UserServiceModule`]
114pub trait UserServiceModule: dyn_clone::DynClone + Any + task::Post + Send + Sync {
115    fn instantiate(
116        &self,
117        runtime: ServiceSyncRuntimeHandle,
118    ) -> Result<UserServiceInstance, ExecutionError>;
119}
120
121impl<T: UserServiceModule + Send + Sync + 'static> From<T> for UserServiceCode {
122    fn from(module: T) -> Self {
123        Self(Box::new(module))
124    }
125}
126
127dyn_clone::clone_trait_object!(UserServiceModule);
128
129impl UserServiceCode {
130    fn instantiate(
131        &self,
132        runtime: ServiceSyncRuntimeHandle,
133    ) -> Result<UserServiceInstance, ExecutionError> {
134        self.0.instantiate(runtime)
135    }
136}
137
138impl UserContractCode {
139    fn instantiate(
140        &self,
141        runtime: ContractSyncRuntimeHandle,
142    ) -> Result<UserContractInstance, ExecutionError> {
143        self.0.instantiate(runtime)
144    }
145}
146
147#[cfg(web)]
148const _: () = {
149    // TODO(#2775): add a vtable pointer into the JsValue rather than assuming the
150    // implementor
151
152    impl From<UserContractCode> for JsValue {
153        fn from(code: UserContractCode) -> JsValue {
154            let module: WasmContractModule = *(code.0 as Box<dyn Any>)
155                .downcast()
156                .expect("we only support Wasm modules on the Web for now");
157            module.into()
158        }
159    }
160
161    impl From<UserServiceCode> for JsValue {
162        fn from(code: UserServiceCode) -> JsValue {
163            let module: WasmServiceModule = *(code.0 as Box<dyn Any>)
164                .downcast()
165                .expect("we only support Wasm modules on the Web for now");
166            module.into()
167        }
168    }
169
170    impl TryFrom<JsValue> for UserContractCode {
171        type Error = JsValue;
172        fn try_from(value: JsValue) -> Result<Self, JsValue> {
173            WasmContractModule::try_from(value).map(Into::into)
174        }
175    }
176
177    impl TryFrom<JsValue> for UserServiceCode {
178        type Error = JsValue;
179        fn try_from(value: JsValue) -> Result<Self, JsValue> {
180            WasmServiceModule::try_from(value).map(Into::into)
181        }
182    }
183};
184
185/// A type for errors happening during execution.
186#[derive(Error, Debug)]
187pub enum ExecutionError {
188    #[error(transparent)]
189    ViewError(ViewError),
190    #[error(transparent)]
191    ArithmeticError(#[from] ArithmeticError),
192    #[error("User application reported an error: {0}")]
193    UserError(String),
194    #[cfg(with_wasm_runtime)]
195    #[error(transparent)]
196    WasmError(#[from] WasmExecutionError),
197    #[cfg(with_revm)]
198    #[error(transparent)]
199    EvmError(#[from] EvmExecutionError),
200    #[error(transparent)]
201    DecompressionError(#[from] DecompressionError),
202    #[error("The given promise is invalid or was polled once already")]
203    InvalidPromise,
204
205    #[error("Attempted to perform a reentrant call to application {0}")]
206    ReentrantCall(ApplicationId),
207    #[error(
208        "Application {caller_id} attempted to perform a cross-application to {callee_id} call \
209        from `finalize`"
210    )]
211    CrossApplicationCallInFinalize {
212        caller_id: Box<ApplicationId>,
213        callee_id: Box<ApplicationId>,
214    },
215    #[error("Attempt to write to storage from a contract")]
216    ServiceWriteAttempt,
217    #[error("Failed to load bytecode from storage {0:?}")]
218    ApplicationBytecodeNotFound(Box<ApplicationDescription>),
219    // TODO(#2927): support dynamic loading of modules on the Web
220    #[error("Unsupported dynamic application load: {0:?}")]
221    UnsupportedDynamicApplicationLoad(Box<ApplicationId>),
222
223    #[error("Excessive number of bytes read from storage")]
224    ExcessiveRead,
225    #[error("Excessive number of bytes written to storage")]
226    ExcessiveWrite,
227    #[error("Block execution required too much fuel")]
228    MaximumFuelExceeded,
229    #[error("Services running as oracles in block took longer than allowed")]
230    MaximumServiceOracleExecutionTimeExceeded,
231    #[error("Service running as an oracle produced a response that's too large")]
232    ServiceOracleResponseTooLarge,
233    #[error("Serialized size of the block exceeds limit")]
234    BlockTooLarge,
235    #[error("HTTP response exceeds the size limit of {limit} bytes, having at least {size} bytes")]
236    HttpResponseSizeLimitExceeded { limit: u64, size: u64 },
237    #[error("Runtime failed to respond to application")]
238    MissingRuntimeResponse,
239    #[error("Module ID {0:?} is invalid")]
240    InvalidModuleId(ModuleId),
241    #[error("AccountOwner is None")]
242    OwnerIsNone,
243    #[error("Application is not authorized to perform system operations on this chain: {0:}")]
244    UnauthorizedApplication(ApplicationId),
245    #[error("Failed to make network reqwest: {0}")]
246    ReqwestError(#[from] reqwest::Error),
247    #[error("Encountered I/O error: {0}")]
248    IoError(#[from] std::io::Error),
249    #[error("More recorded oracle responses than expected")]
250    UnexpectedOracleResponse,
251    #[error("Invalid JSON: {0}")]
252    JsonError(#[from] serde_json::Error),
253    #[error(transparent)]
254    BcsError(#[from] bcs::Error),
255    #[error("Recorded response for oracle query has the wrong type")]
256    OracleResponseMismatch,
257    #[error("Assertion failed: local time {local_time} is not earlier than {timestamp}")]
258    AssertBefore {
259        timestamp: Timestamp,
260        local_time: Timestamp,
261    },
262
263    #[error("Stream names can be at most {MAX_STREAM_NAME_LEN} bytes.")]
264    StreamNameTooLong,
265    #[error("Blob exceeds size limit")]
266    BlobTooLarge,
267    #[error("Bytecode exceeds size limit")]
268    BytecodeTooLarge,
269    #[error("Attempt to perform an HTTP request to an unauthorized host: {0:?}")]
270    UnauthorizedHttpRequest(reqwest::Url),
271    #[error("Attempt to perform an HTTP request to an invalid URL")]
272    InvalidUrlForHttpRequest(#[from] url::ParseError),
273    #[error("Failed to send contract code to worker thread: {0:?}")]
274    ContractModuleSend(#[from] linera_base::task::SendError<UserContractCode>),
275    #[error("Failed to send service code to worker thread: {0:?}")]
276    ServiceModuleSend(#[from] linera_base::task::SendError<UserServiceCode>),
277    #[error("Blobs not found: {0:?}")]
278    BlobsNotFound(Vec<BlobId>),
279
280    #[error("Invalid HTTP header name used for HTTP request")]
281    InvalidHeaderName(#[from] reqwest::header::InvalidHeaderName),
282    #[error("Invalid HTTP header value used for HTTP request")]
283    InvalidHeaderValue(#[from] reqwest::header::InvalidHeaderValue),
284
285    #[error("Invalid admin ID in new chain: {0}")]
286    InvalidNewChainAdminId(ChainId),
287    #[error("Invalid committees")]
288    InvalidCommittees,
289    #[error("{epoch:?} is not recognized by chain {chain_id:}")]
290    InvalidEpoch { chain_id: ChainId, epoch: Epoch },
291    #[error("Transfer must have positive amount")]
292    IncorrectTransferAmount,
293    #[error("Transfer from owned account must be authenticated by the right signer")]
294    UnauthenticatedTransferOwner,
295    #[error("The transferred amount must not exceed the balance of the current account {account}: {balance}")]
296    InsufficientFunding {
297        balance: Amount,
298        account: AccountOwner,
299    },
300    #[error("Required execution fees exceeded the total funding available: {balance}")]
301    InsufficientFundingForFees { balance: Amount },
302    #[error("Claim must have positive amount")]
303    IncorrectClaimAmount,
304    #[error("Claim must be authenticated by the right signer")]
305    UnauthenticatedClaimOwner,
306    #[error("Admin operations are only allowed on the admin chain.")]
307    AdminOperationOnNonAdminChain,
308    #[error("Failed to create new committee: expected {expected}, but got {provided}")]
309    InvalidCommitteeEpoch { expected: Epoch, provided: Epoch },
310    #[error("Failed to remove committee")]
311    InvalidCommitteeRemoval,
312    #[error("Amount overflow")]
313    AmountOverflow,
314    #[error("Amount underflow")]
315    AmountUnderflow,
316    #[error("Chain balance overflow")]
317    BalanceOverflow,
318    #[error("Chain balance underflow")]
319    BalanceUnderflow,
320    #[error("Cannot decrease the chain's timestamp")]
321    TicksOutOfOrder,
322    #[error("Application {0:?} is not registered by the chain")]
323    UnknownApplicationId(Box<ApplicationId>),
324    #[error("Chain is not active yet.")]
325    InactiveChain,
326    #[error("No recorded response for oracle query")]
327    MissingOracleResponse,
328    #[error("Internal error: {0}")]
329    InternalError(&'static str),
330}
331
332impl From<ViewError> for ExecutionError {
333    fn from(error: ViewError) -> Self {
334        match error {
335            ViewError::BlobsNotFound(blob_ids) => ExecutionError::BlobsNotFound(blob_ids),
336            error => ExecutionError::ViewError(error),
337        }
338    }
339}
340
341/// The public entry points provided by the contract part of an application.
342pub trait UserContract {
343    /// Instantiate the application state on the chain that owns the application.
344    fn instantiate(
345        &mut self,
346        context: OperationContext,
347        argument: Vec<u8>,
348    ) -> Result<(), ExecutionError>;
349
350    /// Applies an operation from the current block.
351    fn execute_operation(
352        &mut self,
353        context: OperationContext,
354        operation: Vec<u8>,
355    ) -> Result<Vec<u8>, ExecutionError>;
356
357    /// Applies a message originating from a cross-chain message.
358    fn execute_message(
359        &mut self,
360        context: MessageContext,
361        message: Vec<u8>,
362    ) -> Result<(), ExecutionError>;
363
364    /// Finishes execution of the current transaction.
365    fn finalize(&mut self, context: FinalizeContext) -> Result<(), ExecutionError>;
366}
367
368/// The public entry points provided by the service part of an application.
369pub trait UserService {
370    /// Executes unmetered read-only queries on the state of this application.
371    fn handle_query(
372        &mut self,
373        context: QueryContext,
374        argument: Vec<u8>,
375    ) -> Result<Vec<u8>, ExecutionError>;
376}
377
378/// Configuration options for the execution runtime available to applications.
379#[derive(Clone, Copy, Default)]
380pub struct ExecutionRuntimeConfig {}
381
382/// Requirements for the `extra` field in our state views (and notably the
383/// [`ExecutionStateView`]).
384#[cfg_attr(not(web), async_trait)]
385#[cfg_attr(web, async_trait(?Send))]
386pub trait ExecutionRuntimeContext {
387    fn chain_id(&self) -> ChainId;
388
389    fn execution_runtime_config(&self) -> ExecutionRuntimeConfig;
390
391    fn user_contracts(&self) -> &Arc<DashMap<ApplicationId, UserContractCode>>;
392
393    fn user_services(&self) -> &Arc<DashMap<ApplicationId, UserServiceCode>>;
394
395    async fn get_user_contract(
396        &self,
397        description: &ApplicationDescription,
398    ) -> Result<UserContractCode, ExecutionError>;
399
400    async fn get_user_service(
401        &self,
402        description: &ApplicationDescription,
403    ) -> Result<UserServiceCode, ExecutionError>;
404
405    async fn get_blob(&self, blob_id: BlobId) -> Result<Blob, ViewError>;
406
407    async fn get_event(&self, event_id: EventId) -> Result<Vec<u8>, ViewError>;
408
409    async fn contains_blob(&self, blob_id: BlobId) -> Result<bool, ViewError>;
410
411    #[cfg(with_testing)]
412    async fn add_blobs(
413        &self,
414        blobs: impl IntoIterator<Item = Blob> + Send,
415    ) -> Result<(), ViewError>;
416
417    #[cfg(with_testing)]
418    async fn add_events(
419        &self,
420        events: impl IntoIterator<Item = (EventId, Vec<u8>)> + Send,
421    ) -> Result<(), ViewError>;
422}
423
424#[derive(Clone, Copy, Debug)]
425pub struct OperationContext {
426    /// The current chain ID.
427    pub chain_id: ChainId,
428    /// The authenticated signer of the operation, if any.
429    #[debug(skip_if = Option::is_none)]
430    pub authenticated_signer: Option<AccountOwner>,
431    /// `None` if this is the transaction entrypoint or the caller doesn't want this particular
432    /// call to be authenticated (e.g. for safety reasons).
433    #[debug(skip_if = Option::is_none)]
434    pub authenticated_caller_id: Option<ApplicationId>,
435    /// The current block height.
436    pub height: BlockHeight,
437    /// The consensus round number, if this is a block that gets validated in a multi-leader round.
438    pub round: Option<u32>,
439    /// The current index of the operation.
440    #[debug(skip_if = Option::is_none)]
441    pub index: Option<u32>,
442}
443
444#[derive(Clone, Copy, Debug)]
445pub struct MessageContext {
446    /// The current chain ID.
447    pub chain_id: ChainId,
448    /// Whether the message was rejected by the original receiver and is now bouncing back.
449    pub is_bouncing: bool,
450    /// The authenticated signer of the operation that created the message, if any.
451    #[debug(skip_if = Option::is_none)]
452    pub authenticated_signer: Option<AccountOwner>,
453    /// Where to send a refund for the unused part of each grant after execution, if any.
454    #[debug(skip_if = Option::is_none)]
455    pub refund_grant_to: Option<Account>,
456    /// The current block height.
457    pub height: BlockHeight,
458    /// The consensus round number, if this is a block that gets validated in a multi-leader round.
459    pub round: Option<u32>,
460    /// The hash of the remote certificate that created the message.
461    pub certificate_hash: CryptoHash,
462    /// The ID of the message (based on the operation height and index in the remote
463    /// certificate).
464    pub message_id: MessageId,
465}
466
467#[derive(Clone, Copy, Debug)]
468pub struct FinalizeContext {
469    /// The current chain ID.
470    pub chain_id: ChainId,
471    /// The authenticated signer of the operation, if any.
472    #[debug(skip_if = Option::is_none)]
473    pub authenticated_signer: Option<AccountOwner>,
474    /// The current block height.
475    pub height: BlockHeight,
476    /// The consensus round number, if this is a block that gets validated in a multi-leader round.
477    pub round: Option<u32>,
478}
479
480#[derive(Clone, Copy, Debug, Eq, PartialEq)]
481pub struct QueryContext {
482    /// The current chain ID.
483    pub chain_id: ChainId,
484    /// The height of the next block on this chain.
485    pub next_block_height: BlockHeight,
486    /// The local time in the node executing the query.
487    pub local_time: Timestamp,
488}
489
490pub trait BaseRuntime {
491    type Read: fmt::Debug + Send + Sync;
492    type ContainsKey: fmt::Debug + Send + Sync;
493    type ContainsKeys: fmt::Debug + Send + Sync;
494    type ReadMultiValuesBytes: fmt::Debug + Send + Sync;
495    type ReadValueBytes: fmt::Debug + Send + Sync;
496    type FindKeysByPrefix: fmt::Debug + Send + Sync;
497    type FindKeyValuesByPrefix: fmt::Debug + Send + Sync;
498
499    /// The current chain ID.
500    fn chain_id(&mut self) -> Result<ChainId, ExecutionError>;
501
502    /// The current block height.
503    fn block_height(&mut self) -> Result<BlockHeight, ExecutionError>;
504
505    /// The current application ID.
506    fn application_id(&mut self) -> Result<ApplicationId, ExecutionError>;
507
508    /// The current application creator's chain ID.
509    fn application_creator_chain_id(&mut self) -> Result<ChainId, ExecutionError>;
510
511    /// The current application parameters.
512    fn application_parameters(&mut self) -> Result<Vec<u8>, ExecutionError>;
513
514    /// Reads the system timestamp.
515    fn read_system_timestamp(&mut self) -> Result<Timestamp, ExecutionError>;
516
517    /// Reads the balance of the chain.
518    fn read_chain_balance(&mut self) -> Result<Amount, ExecutionError>;
519
520    /// Reads the owner balance.
521    fn read_owner_balance(&mut self, owner: AccountOwner) -> Result<Amount, ExecutionError>;
522
523    /// Reads the balances from all owners.
524    fn read_owner_balances(&mut self) -> Result<Vec<(AccountOwner, Amount)>, ExecutionError>;
525
526    /// Reads balance owners.
527    fn read_balance_owners(&mut self) -> Result<Vec<AccountOwner>, ExecutionError>;
528
529    /// Reads the current ownership configuration for this chain.
530    fn chain_ownership(&mut self) -> Result<ChainOwnership, ExecutionError>;
531
532    /// Tests whether a key exists in the key-value store
533    #[cfg(feature = "test")]
534    fn contains_key(&mut self, key: Vec<u8>) -> Result<bool, ExecutionError> {
535        let promise = self.contains_key_new(key)?;
536        self.contains_key_wait(&promise)
537    }
538
539    /// Creates the promise to test whether a key exists in the key-value store
540    fn contains_key_new(&mut self, key: Vec<u8>) -> Result<Self::ContainsKey, ExecutionError>;
541
542    /// Resolves the promise to test whether a key exists in the key-value store
543    fn contains_key_wait(&mut self, promise: &Self::ContainsKey) -> Result<bool, ExecutionError>;
544
545    /// Tests whether multiple keys exist in the key-value store
546    #[cfg(feature = "test")]
547    fn contains_keys(&mut self, keys: Vec<Vec<u8>>) -> Result<Vec<bool>, ExecutionError> {
548        let promise = self.contains_keys_new(keys)?;
549        self.contains_keys_wait(&promise)
550    }
551
552    /// Creates the promise to test whether multiple keys exist in the key-value store
553    fn contains_keys_new(
554        &mut self,
555        keys: Vec<Vec<u8>>,
556    ) -> Result<Self::ContainsKeys, ExecutionError>;
557
558    /// Resolves the promise to test whether multiple keys exist in the key-value store
559    fn contains_keys_wait(
560        &mut self,
561        promise: &Self::ContainsKeys,
562    ) -> Result<Vec<bool>, ExecutionError>;
563
564    /// Reads several keys from the key-value store
565    #[cfg(feature = "test")]
566    fn read_multi_values_bytes(
567        &mut self,
568        keys: Vec<Vec<u8>>,
569    ) -> Result<Vec<Option<Vec<u8>>>, ExecutionError> {
570        let promise = self.read_multi_values_bytes_new(keys)?;
571        self.read_multi_values_bytes_wait(&promise)
572    }
573
574    /// Creates the promise to access several keys from the key-value store
575    fn read_multi_values_bytes_new(
576        &mut self,
577        keys: Vec<Vec<u8>>,
578    ) -> Result<Self::ReadMultiValuesBytes, ExecutionError>;
579
580    /// Resolves the promise to access several keys from the key-value store
581    fn read_multi_values_bytes_wait(
582        &mut self,
583        promise: &Self::ReadMultiValuesBytes,
584    ) -> Result<Vec<Option<Vec<u8>>>, ExecutionError>;
585
586    /// Reads the key from the key-value store
587    #[cfg(feature = "test")]
588    fn read_value_bytes(&mut self, key: Vec<u8>) -> Result<Option<Vec<u8>>, ExecutionError> {
589        let promise = self.read_value_bytes_new(key)?;
590        self.read_value_bytes_wait(&promise)
591    }
592
593    /// Creates the promise to access a key from the key-value store
594    fn read_value_bytes_new(
595        &mut self,
596        key: Vec<u8>,
597    ) -> Result<Self::ReadValueBytes, ExecutionError>;
598
599    /// Resolves the promise to access a key from the key-value store
600    fn read_value_bytes_wait(
601        &mut self,
602        promise: &Self::ReadValueBytes,
603    ) -> Result<Option<Vec<u8>>, ExecutionError>;
604
605    /// Creates the promise to access keys having a specific prefix
606    fn find_keys_by_prefix_new(
607        &mut self,
608        key_prefix: Vec<u8>,
609    ) -> Result<Self::FindKeysByPrefix, ExecutionError>;
610
611    /// Resolves the promise to access keys having a specific prefix
612    fn find_keys_by_prefix_wait(
613        &mut self,
614        promise: &Self::FindKeysByPrefix,
615    ) -> Result<Vec<Vec<u8>>, ExecutionError>;
616
617    /// Reads the data from the key/values having a specific prefix.
618    #[cfg(feature = "test")]
619    #[expect(clippy::type_complexity)]
620    fn find_key_values_by_prefix(
621        &mut self,
622        key_prefix: Vec<u8>,
623    ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, ExecutionError> {
624        let promise = self.find_key_values_by_prefix_new(key_prefix)?;
625        self.find_key_values_by_prefix_wait(&promise)
626    }
627
628    /// Creates the promise to access key/values having a specific prefix
629    fn find_key_values_by_prefix_new(
630        &mut self,
631        key_prefix: Vec<u8>,
632    ) -> Result<Self::FindKeyValuesByPrefix, ExecutionError>;
633
634    /// Resolves the promise to access key/values having a specific prefix
635    #[expect(clippy::type_complexity)]
636    fn find_key_values_by_prefix_wait(
637        &mut self,
638        promise: &Self::FindKeyValuesByPrefix,
639    ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, ExecutionError>;
640
641    /// Makes an HTTP request to the given URL and returns the answer, if any.
642    fn perform_http_request(
643        &mut self,
644        request: http::Request,
645    ) -> Result<http::Response, ExecutionError>;
646
647    /// Ensures that the current time at block validation is `< timestamp`. Note that block
648    /// validation happens at or after the block timestamp, but isn't necessarily the same.
649    ///
650    /// Cannot be used in fast blocks: A block using this call should be proposed by a regular
651    /// owner, not a super owner.
652    fn assert_before(&mut self, timestamp: Timestamp) -> Result<(), ExecutionError>;
653
654    /// Reads a data blob specified by a given hash.
655    fn read_data_blob(&mut self, hash: &CryptoHash) -> Result<Vec<u8>, ExecutionError>;
656
657    /// Asserts the existence of a data blob with the given hash.
658    fn assert_data_blob_exists(&mut self, hash: &CryptoHash) -> Result<(), ExecutionError>;
659}
660
661pub trait ServiceRuntime: BaseRuntime {
662    /// Queries another application.
663    fn try_query_application(
664        &mut self,
665        queried_id: ApplicationId,
666        argument: Vec<u8>,
667    ) -> Result<Vec<u8>, ExecutionError>;
668
669    /// Schedules an operation to be included in the block proposed after execution.
670    fn schedule_operation(&mut self, operation: Vec<u8>) -> Result<(), ExecutionError>;
671
672    /// Checks if the service has exceeded its execution time limit.
673    fn check_execution_time(&mut self) -> Result<(), ExecutionError>;
674}
675
676pub trait ContractRuntime: BaseRuntime {
677    /// The authenticated signer for this execution, if there is one.
678    fn authenticated_signer(&mut self) -> Result<Option<AccountOwner>, ExecutionError>;
679
680    /// The current message ID, if there is one.
681    fn message_id(&mut self) -> Result<Option<MessageId>, ExecutionError>;
682
683    /// If the current message (if there is one) was rejected by its destination and is now
684    /// bouncing back.
685    fn message_is_bouncing(&mut self) -> Result<Option<bool>, ExecutionError>;
686
687    /// The optional authenticated caller application ID, if it was provided and if there is one
688    /// based on the execution context.
689    fn authenticated_caller_id(&mut self) -> Result<Option<ApplicationId>, ExecutionError>;
690
691    /// Returns the amount of execution fuel remaining before execution is aborted.
692    fn remaining_fuel(&mut self) -> Result<u64, ExecutionError>;
693
694    /// Consumes some of the execution fuel.
695    fn consume_fuel(&mut self, fuel: u64) -> Result<(), ExecutionError>;
696
697    /// Schedules a message to be sent.
698    fn send_message(&mut self, message: SendMessageRequest<Vec<u8>>) -> Result<(), ExecutionError>;
699
700    /// Schedules to subscribe to some `channel` on a `chain`.
701    fn subscribe(&mut self, chain: ChainId, channel: ChannelName) -> Result<(), ExecutionError>;
702
703    /// Schedules to unsubscribe to some `channel` on a `chain`.
704    fn unsubscribe(&mut self, chain: ChainId, channel: ChannelName) -> Result<(), ExecutionError>;
705
706    /// Transfers amount from source to destination.
707    fn transfer(
708        &mut self,
709        source: AccountOwner,
710        destination: Account,
711        amount: Amount,
712    ) -> Result<(), ExecutionError>;
713
714    /// Claims amount from source to destination.
715    fn claim(
716        &mut self,
717        source: Account,
718        destination: Account,
719        amount: Amount,
720    ) -> Result<(), ExecutionError>;
721
722    /// Calls another application. Forwarded sessions will now be visible to
723    /// `callee_id` (but not to the caller any more).
724    fn try_call_application(
725        &mut self,
726        authenticated: bool,
727        callee_id: ApplicationId,
728        argument: Vec<u8>,
729    ) -> Result<Vec<u8>, ExecutionError>;
730
731    /// Adds a new item to an event stream. Returns the new event's index in the stream.
732    fn emit(&mut self, name: StreamName, value: Vec<u8>) -> Result<u32, ExecutionError>;
733
734    /// Reads an event from a stream. Returns the event's value.
735    ///
736    /// Returns an error if the event doesn't exist.
737    fn read_event(
738        &mut self,
739        chain_id: ChainId,
740        stream_name: StreamName,
741        index: u32,
742    ) -> Result<Vec<u8>, ExecutionError>;
743
744    /// Subscribes this application to an event stream.
745    fn subscribe_to_events(
746        &mut self,
747        chain_id: ChainId,
748        application_id: ApplicationId,
749        stream_name: StreamName,
750    ) -> Result<(), ExecutionError>;
751
752    /// Unsubscribes this application from an event stream.
753    fn unsubscribe_from_events(
754        &mut self,
755        chain_id: ChainId,
756        application_id: ApplicationId,
757        stream_name: StreamName,
758    ) -> Result<(), ExecutionError>;
759
760    /// Queries a service.
761    fn query_service(
762        &mut self,
763        application_id: ApplicationId,
764        query: Vec<u8>,
765    ) -> Result<Vec<u8>, ExecutionError>;
766
767    /// Opens a new chain.
768    fn open_chain(
769        &mut self,
770        ownership: ChainOwnership,
771        application_permissions: ApplicationPermissions,
772        balance: Amount,
773    ) -> Result<(MessageId, ChainId), ExecutionError>;
774
775    /// Closes the current chain.
776    fn close_chain(&mut self) -> Result<(), ExecutionError>;
777
778    /// Changes the application permissions on the current chain.
779    fn change_application_permissions(
780        &mut self,
781        application_permissions: ApplicationPermissions,
782    ) -> Result<(), ExecutionError>;
783
784    /// Creates a new application on chain.
785    fn create_application(
786        &mut self,
787        module_id: ModuleId,
788        parameters: Vec<u8>,
789        argument: Vec<u8>,
790        required_application_ids: Vec<ApplicationId>,
791    ) -> Result<ApplicationId, ExecutionError>;
792
793    /// Returns the round in which this block was validated.
794    fn validation_round(&mut self) -> Result<Option<u32>, ExecutionError>;
795
796    /// Writes a batch of changes.
797    fn write_batch(&mut self, batch: Batch) -> Result<(), ExecutionError>;
798}
799
800/// An operation to be executed in a block.
801#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
802pub enum Operation {
803    /// A system operation.
804    System(Box<SystemOperation>),
805    /// A user operation (in serialized form).
806    User {
807        application_id: ApplicationId,
808        #[serde(with = "serde_bytes")]
809        #[debug(with = "hex_debug")]
810        bytes: Vec<u8>,
811    },
812}
813
814impl BcsHashable<'_> for Operation {}
815
816/// A message to be sent and possibly executed in the receiver's block.
817#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
818pub enum Message {
819    /// A system message.
820    System(SystemMessage),
821    /// A user message (in serialized form).
822    User {
823        application_id: ApplicationId,
824        #[serde(with = "serde_bytes")]
825        #[debug(with = "hex_debug")]
826        bytes: Vec<u8>,
827    },
828}
829
830/// An query to be sent and possibly executed in the receiver's block.
831#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
832pub enum Query {
833    /// A system query.
834    System(SystemQuery),
835    /// A user query (in serialized form).
836    User {
837        application_id: ApplicationId,
838        #[serde(with = "serde_bytes")]
839        #[debug(with = "hex_debug")]
840        bytes: Vec<u8>,
841    },
842}
843
844/// The outcome of the execution of a query.
845#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
846pub struct QueryOutcome<Response = QueryResponse> {
847    pub response: Response,
848    pub operations: Vec<Operation>,
849}
850
851impl From<QueryOutcome<SystemResponse>> for QueryOutcome {
852    fn from(system_outcome: QueryOutcome<SystemResponse>) -> Self {
853        let QueryOutcome {
854            response,
855            operations,
856        } = system_outcome;
857
858        QueryOutcome {
859            response: QueryResponse::System(response),
860            operations,
861        }
862    }
863}
864
865impl From<QueryOutcome<Vec<u8>>> for QueryOutcome {
866    fn from(user_service_outcome: QueryOutcome<Vec<u8>>) -> Self {
867        let QueryOutcome {
868            response,
869            operations,
870        } = user_service_outcome;
871
872        QueryOutcome {
873            response: QueryResponse::User(response),
874            operations,
875        }
876    }
877}
878
879/// The response to a query.
880#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
881pub enum QueryResponse {
882    /// A system response.
883    System(SystemResponse),
884    /// A user response (in serialized form).
885    User(
886        #[serde(with = "serde_bytes")]
887        #[debug(with = "hex_debug")]
888        Vec<u8>,
889    ),
890}
891
892/// A message together with routing information.
893#[derive(Clone, Debug)]
894#[cfg_attr(with_testing, derive(Eq, PartialEq))]
895pub struct RawOutgoingMessage<Message, Grant> {
896    /// The destination of the message.
897    pub destination: Destination,
898    /// Whether the message is authenticated.
899    pub authenticated: bool,
900    /// The grant needed for message execution, typically specified as an `Amount` or as `Resources`.
901    pub grant: Grant,
902    /// The kind of outgoing message being sent.
903    pub kind: MessageKind,
904    /// The message itself.
905    pub message: Message,
906}
907
908impl<Message> From<SendMessageRequest<Message>> for RawOutgoingMessage<Message, Resources> {
909    fn from(request: SendMessageRequest<Message>) -> Self {
910        let SendMessageRequest {
911            destination,
912            authenticated,
913            grant,
914            is_tracked,
915            message,
916        } = request;
917
918        let kind = if is_tracked {
919            MessageKind::Tracked
920        } else {
921            MessageKind::Simple
922        };
923
924        RawOutgoingMessage {
925            destination,
926            authenticated,
927            grant,
928            kind,
929            message,
930        }
931    }
932}
933
934/// The kind of outgoing message being sent.
935#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, Copy)]
936pub enum MessageKind {
937    /// The message can be skipped or rejected. No receipt is requested.
938    Simple,
939    /// The message cannot be skipped nor rejected. No receipt is requested.
940    /// This only concerns certain system messages that cannot fail.
941    Protected,
942    /// The message cannot be skipped but can be rejected. A receipt must be sent
943    /// when the message is rejected in a block of the receiver.
944    Tracked,
945    /// This message is a receipt automatically created when the original message was rejected.
946    Bouncing,
947}
948
949/// A posted message together with routing information.
950#[derive(Debug, PartialEq, Eq, Hash, Clone, Serialize, Deserialize, SimpleObject)]
951pub struct OutgoingMessage {
952    /// The destination of the message.
953    pub destination: Destination,
954    /// The user authentication carried by the message, if any.
955    #[debug(skip_if = Option::is_none)]
956    pub authenticated_signer: Option<AccountOwner>,
957    /// A grant to pay for the message execution.
958    #[debug(skip_if = Amount::is_zero)]
959    pub grant: Amount,
960    /// Where to send a refund for the unused part of the grant after execution, if any.
961    #[debug(skip_if = Option::is_none)]
962    pub refund_grant_to: Option<Account>,
963    /// The kind of message being sent.
964    pub kind: MessageKind,
965    /// The message itself.
966    pub message: Message,
967}
968
969impl BcsHashable<'_> for OutgoingMessage {}
970
971impl OutgoingMessage {
972    /// Creates a new simple outgoing message with no grant and no authenticated signer.
973    pub fn new(recipient: ChainId, message: impl Into<Message>) -> Self {
974        OutgoingMessage {
975            destination: Destination::Recipient(recipient),
976            authenticated_signer: None,
977            grant: Amount::ZERO,
978            refund_grant_to: None,
979            kind: MessageKind::Simple,
980            message: message.into(),
981        }
982    }
983
984    /// Returns the same message, with the specified kind.
985    pub fn with_kind(mut self, kind: MessageKind) -> Self {
986        self.kind = kind;
987        self
988    }
989
990    /// Returns the same message, with the specified authenticated signer.
991    pub fn with_authenticated_signer(mut self, authenticated_signer: Option<AccountOwner>) -> Self {
992        self.authenticated_signer = authenticated_signer;
993        self
994    }
995}
996
997impl OperationContext {
998    /// Returns an account for the refund.
999    /// Returns `None` if there is no authenticated signer of the [`OperationContext`].
1000    fn refund_grant_to(&self) -> Option<Account> {
1001        self.authenticated_signer.map(|owner| Account {
1002            chain_id: self.chain_id,
1003            owner,
1004        })
1005    }
1006
1007    fn next_message_id(&self, next_message_index: u32) -> MessageId {
1008        MessageId {
1009            chain_id: self.chain_id,
1010            height: self.height,
1011            index: next_message_index,
1012        }
1013    }
1014}
1015
1016#[cfg(with_testing)]
1017#[derive(Clone)]
1018pub struct TestExecutionRuntimeContext {
1019    chain_id: ChainId,
1020    execution_runtime_config: ExecutionRuntimeConfig,
1021    user_contracts: Arc<DashMap<ApplicationId, UserContractCode>>,
1022    user_services: Arc<DashMap<ApplicationId, UserServiceCode>>,
1023    blobs: Arc<DashMap<BlobId, Blob>>,
1024    events: Arc<DashMap<EventId, Vec<u8>>>,
1025}
1026
1027#[cfg(with_testing)]
1028impl TestExecutionRuntimeContext {
1029    pub fn new(chain_id: ChainId, execution_runtime_config: ExecutionRuntimeConfig) -> Self {
1030        Self {
1031            chain_id,
1032            execution_runtime_config,
1033            user_contracts: Arc::default(),
1034            user_services: Arc::default(),
1035            blobs: Arc::default(),
1036            events: Arc::default(),
1037        }
1038    }
1039}
1040
1041#[cfg(with_testing)]
1042#[cfg_attr(not(web), async_trait)]
1043#[cfg_attr(web, async_trait(?Send))]
1044impl ExecutionRuntimeContext for TestExecutionRuntimeContext {
1045    fn chain_id(&self) -> ChainId {
1046        self.chain_id
1047    }
1048
1049    fn execution_runtime_config(&self) -> ExecutionRuntimeConfig {
1050        self.execution_runtime_config
1051    }
1052
1053    fn user_contracts(&self) -> &Arc<DashMap<ApplicationId, UserContractCode>> {
1054        &self.user_contracts
1055    }
1056
1057    fn user_services(&self) -> &Arc<DashMap<ApplicationId, UserServiceCode>> {
1058        &self.user_services
1059    }
1060
1061    async fn get_user_contract(
1062        &self,
1063        description: &ApplicationDescription,
1064    ) -> Result<UserContractCode, ExecutionError> {
1065        let application_id = description.into();
1066        Ok(self
1067            .user_contracts()
1068            .get(&application_id)
1069            .ok_or_else(|| {
1070                ExecutionError::ApplicationBytecodeNotFound(Box::new(description.clone()))
1071            })?
1072            .clone())
1073    }
1074
1075    async fn get_user_service(
1076        &self,
1077        description: &ApplicationDescription,
1078    ) -> Result<UserServiceCode, ExecutionError> {
1079        let application_id = description.into();
1080        Ok(self
1081            .user_services()
1082            .get(&application_id)
1083            .ok_or_else(|| {
1084                ExecutionError::ApplicationBytecodeNotFound(Box::new(description.clone()))
1085            })?
1086            .clone())
1087    }
1088
1089    async fn get_blob(&self, blob_id: BlobId) -> Result<Blob, ViewError> {
1090        Ok(self
1091            .blobs
1092            .get(&blob_id)
1093            .ok_or_else(|| ViewError::BlobsNotFound(vec![blob_id]))?
1094            .clone())
1095    }
1096
1097    async fn get_event(&self, event_id: EventId) -> Result<Vec<u8>, ViewError> {
1098        Ok(self
1099            .events
1100            .get(&event_id)
1101            .ok_or_else(|| ViewError::EventsNotFound(vec![event_id]))?
1102            .clone())
1103    }
1104
1105    async fn contains_blob(&self, blob_id: BlobId) -> Result<bool, ViewError> {
1106        Ok(self.blobs.contains_key(&blob_id))
1107    }
1108
1109    #[cfg(with_testing)]
1110    async fn add_blobs(
1111        &self,
1112        blobs: impl IntoIterator<Item = Blob> + Send,
1113    ) -> Result<(), ViewError> {
1114        for blob in blobs {
1115            self.blobs.insert(blob.id(), blob);
1116        }
1117
1118        Ok(())
1119    }
1120
1121    #[cfg(with_testing)]
1122    async fn add_events(
1123        &self,
1124        events: impl IntoIterator<Item = (EventId, Vec<u8>)> + Send,
1125    ) -> Result<(), ViewError> {
1126        for (event_id, bytes) in events {
1127            self.events.insert(event_id, bytes);
1128        }
1129
1130        Ok(())
1131    }
1132}
1133
1134impl From<SystemOperation> for Operation {
1135    fn from(operation: SystemOperation) -> Self {
1136        Operation::System(Box::new(operation))
1137    }
1138}
1139
1140impl Operation {
1141    pub fn system(operation: SystemOperation) -> Self {
1142        Operation::System(Box::new(operation))
1143    }
1144
1145    /// Creates a new user application operation following the `application_id`'s [`Abi`].
1146    #[cfg(with_testing)]
1147    pub fn user<A: Abi>(
1148        application_id: ApplicationId<A>,
1149        operation: &A::Operation,
1150    ) -> Result<Self, bcs::Error> {
1151        Self::user_without_abi(application_id.forget_abi(), operation)
1152    }
1153
1154    /// Creates a new user application operation assuming that the `operation` is valid for the
1155    /// `application_id`.
1156    #[cfg(with_testing)]
1157    pub fn user_without_abi(
1158        application_id: ApplicationId,
1159        operation: &impl Serialize,
1160    ) -> Result<Self, bcs::Error> {
1161        Ok(Operation::User {
1162            application_id,
1163            bytes: bcs::to_bytes(&operation)?,
1164        })
1165    }
1166
1167    /// Returns a reference to the [`SystemOperation`] in this [`Operation`], if this [`Operation`]
1168    /// is for the system application.
1169    pub fn as_system_operation(&self) -> Option<&SystemOperation> {
1170        match self {
1171            Operation::System(system_operation) => Some(system_operation),
1172            Operation::User { .. } => None,
1173        }
1174    }
1175
1176    pub fn application_id(&self) -> GenericApplicationId {
1177        match self {
1178            Self::System(_) => GenericApplicationId::System,
1179            Self::User { application_id, .. } => GenericApplicationId::User(*application_id),
1180        }
1181    }
1182
1183    /// Returns the IDs of all blobs published in this operation.
1184    pub fn published_blob_ids(&self) -> Vec<BlobId> {
1185        match self.as_system_operation() {
1186            Some(SystemOperation::PublishDataBlob { blob_hash }) => {
1187                vec![BlobId::new(*blob_hash, BlobType::Data)]
1188            }
1189            Some(SystemOperation::Admin(AdminOperation::PublishCommitteeBlob { blob_hash })) => {
1190                vec![BlobId::new(*blob_hash, BlobType::Committee)]
1191            }
1192            Some(SystemOperation::PublishModule { module_id }) => module_id.bytecode_blob_ids(),
1193            _ => vec![],
1194        }
1195    }
1196}
1197
1198impl From<SystemMessage> for Message {
1199    fn from(message: SystemMessage) -> Self {
1200        Message::System(message)
1201    }
1202}
1203
1204impl Message {
1205    pub fn system(message: SystemMessage) -> Self {
1206        Message::System(message)
1207    }
1208
1209    /// Creates a new user application message assuming that the `message` is valid for the
1210    /// `application_id`.
1211    pub fn user<A, M: Serialize>(
1212        application_id: ApplicationId<A>,
1213        message: &M,
1214    ) -> Result<Self, bcs::Error> {
1215        let application_id = application_id.forget_abi();
1216        let bytes = bcs::to_bytes(&message)?;
1217        Ok(Message::User {
1218            application_id,
1219            bytes,
1220        })
1221    }
1222
1223    pub fn application_id(&self) -> GenericApplicationId {
1224        match self {
1225            Self::System(_) => GenericApplicationId::System,
1226            Self::User { application_id, .. } => GenericApplicationId::User(*application_id),
1227        }
1228    }
1229
1230    pub fn matches_open_chain(&self) -> Option<&OpenChainConfig> {
1231        match self {
1232            Message::System(SystemMessage::OpenChain(config)) => Some(config),
1233            _ => None,
1234        }
1235    }
1236}
1237
1238impl From<SystemQuery> for Query {
1239    fn from(query: SystemQuery) -> Self {
1240        Query::System(query)
1241    }
1242}
1243
1244impl Query {
1245    pub fn system(query: SystemQuery) -> Self {
1246        Query::System(query)
1247    }
1248
1249    /// Creates a new user application query following the `application_id`'s [`Abi`].
1250    pub fn user<A: Abi>(
1251        application_id: ApplicationId<A>,
1252        query: &A::Query,
1253    ) -> Result<Self, serde_json::Error> {
1254        Self::user_without_abi(application_id.forget_abi(), query)
1255    }
1256
1257    /// Creates a new user application query assuming that the `query` is valid for the
1258    /// `application_id`.
1259    pub fn user_without_abi(
1260        application_id: ApplicationId,
1261        query: &impl Serialize,
1262    ) -> Result<Self, serde_json::Error> {
1263        Ok(Query::User {
1264            application_id,
1265            bytes: serde_json::to_vec(&query)?,
1266        })
1267    }
1268
1269    pub fn application_id(&self) -> GenericApplicationId {
1270        match self {
1271            Self::System(_) => GenericApplicationId::System,
1272            Self::User { application_id, .. } => GenericApplicationId::User(*application_id),
1273        }
1274    }
1275}
1276
1277impl From<SystemResponse> for QueryResponse {
1278    fn from(response: SystemResponse) -> Self {
1279        QueryResponse::System(response)
1280    }
1281}
1282
1283impl From<Vec<u8>> for QueryResponse {
1284    fn from(response: Vec<u8>) -> Self {
1285        QueryResponse::User(response)
1286    }
1287}
1288
1289/// The state of a blob of binary data.
1290#[derive(Eq, PartialEq, Debug, Hash, Clone, Serialize, Deserialize)]
1291pub struct BlobState {
1292    /// Hash of the last `Certificate` that published or used this blob.
1293    pub last_used_by: CryptoHash,
1294    /// The `ChainId` of the chain that published the change
1295    pub chain_id: ChainId,
1296    /// The `BlockHeight` of the chain that published the change
1297    pub block_height: BlockHeight,
1298    /// Epoch of the `last_used_by` certificate.
1299    pub epoch: Epoch,
1300}
1301
1302/// The runtime to use for running the application.
1303#[derive(Clone, Copy, Display)]
1304#[cfg_attr(with_wasm_runtime, derive(Debug, Default))]
1305pub enum WasmRuntime {
1306    #[cfg(with_wasmer)]
1307    #[default]
1308    #[display("wasmer")]
1309    Wasmer,
1310    #[cfg(with_wasmtime)]
1311    #[cfg_attr(not(with_wasmer), default)]
1312    #[display("wasmtime")]
1313    Wasmtime,
1314}
1315
1316#[derive(Clone, Copy, Display)]
1317#[cfg_attr(with_revm, derive(Debug, Default))]
1318pub enum EvmRuntime {
1319    #[cfg(with_revm)]
1320    #[default]
1321    #[display("revm")]
1322    Revm,
1323}
1324
1325/// Trait used to select a default `WasmRuntime`, if one is available.
1326pub trait WithWasmDefault {
1327    fn with_wasm_default(self) -> Self;
1328}
1329
1330impl WithWasmDefault for Option<WasmRuntime> {
1331    fn with_wasm_default(self) -> Self {
1332        #[cfg(with_wasm_runtime)]
1333        {
1334            Some(self.unwrap_or_default())
1335        }
1336        #[cfg(not(with_wasm_runtime))]
1337        {
1338            None
1339        }
1340    }
1341}
1342
1343impl FromStr for WasmRuntime {
1344    type Err = InvalidWasmRuntime;
1345
1346    fn from_str(string: &str) -> Result<Self, Self::Err> {
1347        match string {
1348            #[cfg(with_wasmer)]
1349            "wasmer" => Ok(WasmRuntime::Wasmer),
1350            #[cfg(with_wasmtime)]
1351            "wasmtime" => Ok(WasmRuntime::Wasmtime),
1352            unknown => Err(InvalidWasmRuntime(unknown.to_owned())),
1353        }
1354    }
1355}
1356
1357/// Attempts to create an invalid [`WasmRuntime`] instance from a string.
1358#[derive(Clone, Debug, Error)]
1359#[error("{0:?} is not a valid WebAssembly runtime")]
1360pub struct InvalidWasmRuntime(String);
1361
1362doc_scalar!(Operation, "An operation to be executed in a block");
1363doc_scalar!(
1364    Message,
1365    "A message to be sent and possibly executed in the receiver's block."
1366);
1367doc_scalar!(MessageKind, "The kind of outgoing message being sent");