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