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