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