Skip to main content

linera_execution/wasm/
runtime_api.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{any::Any, collections::HashMap, marker::PhantomData};
5
6use linera_base::{
7    data_types::{
8        Amount, ApplicationDescription, ApplicationPermissions, BlockHeight, Bytecode,
9        SendMessageRequest, Timestamp,
10    },
11    http,
12    identifiers::{Account, AccountOwner, ApplicationId, ChainId, StreamName},
13    ownership::{ChainOwnership, ManageChainError},
14    vm::VmRuntime,
15};
16use linera_views::batch::{Batch, WriteOperation};
17use linera_witty::{wit_export, Instance, RuntimeError};
18use tracing::log;
19
20use super::WasmExecutionError;
21use crate::{BaseRuntime, ContractRuntime, DataBlobHash, ExecutionError, ModuleId, ServiceRuntime};
22
23/// Common host data used as the `UserData` of the system API implementations.
24pub struct RuntimeApiData<Runtime> {
25    runtime: Runtime,
26    active_promises: HashMap<u32, Box<dyn Any + Send + Sync>>,
27    promise_counter: u32,
28}
29
30impl<Runtime> RuntimeApiData<Runtime> {
31    /// Creates a new [`RuntimeApiData`] using the provided `runtime` to execute the system APIs.
32    pub fn new(runtime: Runtime) -> Self {
33        RuntimeApiData {
34            runtime,
35            active_promises: HashMap::new(),
36            promise_counter: 0,
37        }
38    }
39
40    /// Returns a mutable reference the system API `Runtime`.
41    pub fn runtime_mut(&mut self) -> &mut Runtime {
42        &mut self.runtime
43    }
44
45    /// Registers a `promise` internally, returning an ID that is unique for the lifetime of this
46    /// [`RuntimeApiData`].
47    fn register_promise<Promise>(&mut self, promise: Promise) -> u32
48    where
49        Promise: Send + Sync + 'static,
50    {
51        let id = self.promise_counter;
52
53        self.active_promises.insert(id, Box::new(promise));
54        self.promise_counter += 1;
55
56        id
57    }
58
59    /// Returns a `Promise` registered to the provided `promise_id`.
60    fn take_promise<Promise>(&mut self, promise_id: u32) -> Result<Promise, RuntimeError>
61    where
62        Promise: Send + Sync + 'static,
63    {
64        let type_erased_promise = self
65            .active_promises
66            .remove(&promise_id)
67            .ok_or_else(|| RuntimeError::Custom(WasmExecutionError::UnknownPromise.into()))?;
68
69        type_erased_promise
70            .downcast()
71            .map(|boxed_promise| *boxed_promise)
72            .map_err(|_| RuntimeError::Custom(WasmExecutionError::IncorrectPromise.into()))
73    }
74}
75
76/// An implementation of the runtime API used to access the common behaviour and the view storage for both contracts and
77/// services.
78#[derive(Default)]
79pub struct BaseRuntimeApi<Caller>(PhantomData<Caller>);
80
81#[wit_export(package = "linera:app")]
82impl<Caller, Runtime> BaseRuntimeApi<Caller>
83where
84    Caller: Instance<UserData = RuntimeApiData<Runtime>>,
85    Runtime: BaseRuntime + 'static,
86{
87    /// Returns the ID of the current chain.
88    fn get_chain_id(caller: &mut Caller) -> Result<ChainId, RuntimeError> {
89        caller
90            .user_data_mut()
91            .runtime
92            .chain_id()
93            .map_err(|error| RuntimeError::Custom(error.into()))
94    }
95
96    /// Returns the height of the current block that is executing.
97    fn get_block_height(caller: &mut Caller) -> Result<BlockHeight, RuntimeError> {
98        caller
99            .user_data_mut()
100            .runtime
101            .block_height()
102            .map_err(|error| RuntimeError::Custom(error.into()))
103    }
104
105    /// Returns the ID of the current application.
106    fn get_application_id(caller: &mut Caller) -> Result<ApplicationId, RuntimeError> {
107        caller
108            .user_data_mut()
109            .runtime
110            .application_id()
111            .map_err(|error| RuntimeError::Custom(error.into()))
112    }
113
114    /// Returns the chain ID of the current application creator.
115    fn get_application_creator_chain_id(caller: &mut Caller) -> Result<ChainId, RuntimeError> {
116        caller
117            .user_data_mut()
118            .runtime
119            .application_creator_chain_id()
120            .map_err(|error| RuntimeError::Custom(error.into()))
121    }
122
123    /// Returns the description of the given application.
124    fn read_application_description(
125        caller: &mut Caller,
126        application_id: ApplicationId,
127    ) -> Result<ApplicationDescription, RuntimeError> {
128        caller
129            .user_data_mut()
130            .runtime
131            .read_application_description(application_id)
132            .map_err(|error| RuntimeError::Custom(error.into()))
133    }
134
135    /// Returns the application parameters provided when the application was created.
136    fn application_parameters(caller: &mut Caller) -> Result<Vec<u8>, RuntimeError> {
137        caller
138            .user_data_mut()
139            .runtime
140            .application_parameters()
141            .map_err(|error| RuntimeError::Custom(error.into()))
142    }
143
144    /// Retrieves the owner configuration for the current chain.
145    fn get_chain_ownership(caller: &mut Caller) -> Result<ChainOwnership, RuntimeError> {
146        caller
147            .user_data_mut()
148            .runtime
149            .chain_ownership()
150            .map_err(|error| RuntimeError::Custom(error.into()))
151    }
152
153    /// Retrieves the application permissions for the current chain.
154    fn get_application_permissions(
155        caller: &mut Caller,
156    ) -> Result<ApplicationPermissions, RuntimeError> {
157        caller
158            .user_data_mut()
159            .runtime
160            .application_permissions()
161            .map_err(|error| RuntimeError::Custom(error.into()))
162    }
163
164    /// Retrieves the current system time, i.e. the timestamp of the block in which this is called.
165    fn read_system_timestamp(caller: &mut Caller) -> Result<Timestamp, RuntimeError> {
166        caller
167            .user_data_mut()
168            .runtime
169            .read_system_timestamp()
170            .map_err(|error| RuntimeError::Custom(error.into()))
171    }
172
173    /// Returns the current chain balance.
174    fn read_chain_balance(caller: &mut Caller) -> Result<Amount, RuntimeError> {
175        caller
176            .user_data_mut()
177            .runtime
178            .read_chain_balance()
179            .map_err(|error| RuntimeError::Custom(error.into()))
180    }
181
182    /// Returns the balance of one of the accounts on this chain.
183    fn read_owner_balance(
184        caller: &mut Caller,
185        owner: AccountOwner,
186    ) -> Result<Amount, RuntimeError> {
187        caller
188            .user_data_mut()
189            .runtime
190            .read_owner_balance(owner)
191            .map_err(|error| RuntimeError::Custom(error.into()))
192    }
193
194    /// Returns the balances of all accounts on the chain.
195    fn read_owner_balances(
196        caller: &mut Caller,
197    ) -> Result<Vec<(AccountOwner, Amount)>, RuntimeError> {
198        caller
199            .user_data_mut()
200            .runtime
201            .read_owner_balances()
202            .map_err(|error| RuntimeError::Custom(error.into()))
203    }
204
205    /// Returns the owners of accounts on this chain.
206    fn read_balance_owners(caller: &mut Caller) -> Result<Vec<AccountOwner>, RuntimeError> {
207        caller
208            .user_data_mut()
209            .runtime
210            .read_balance_owners()
211            .map_err(|error| RuntimeError::Custom(error.into()))
212    }
213
214    /// Returns the allowance for a given owner-spender pair.
215    fn read_allowance(
216        caller: &mut Caller,
217        owner: AccountOwner,
218        spender: AccountOwner,
219    ) -> Result<Amount, RuntimeError> {
220        caller
221            .user_data_mut()
222            .runtime
223            .read_allowance(owner, spender)
224            .map_err(|error| RuntimeError::Custom(error.into()))
225    }
226
227    /// Returns all allowances on this chain.
228    fn read_allowances(
229        caller: &mut Caller,
230    ) -> Result<Vec<(AccountOwner, AccountOwner, Amount)>, RuntimeError> {
231        caller
232            .user_data_mut()
233            .runtime
234            .read_allowances()
235            .map_err(|error| RuntimeError::Custom(error.into()))
236    }
237
238    /// Makes an HTTP request to the given URL and returns the response body.
239    fn perform_http_request(
240        caller: &mut Caller,
241        request: http::Request,
242    ) -> Result<http::Response, RuntimeError> {
243        caller
244            .user_data_mut()
245            .runtime
246            .perform_http_request(request)
247            .map_err(|error| RuntimeError::Custom(error.into()))
248    }
249
250    /// Rejects the transaction if the current time at block validation is `>= timestamp`. Note
251    /// that block validation happens at or after the block timestamp, but isn't necessarily the
252    /// same.
253    fn assert_before(caller: &mut Caller, timestamp: Timestamp) -> Result<(), RuntimeError> {
254        caller
255            .user_data_mut()
256            .runtime
257            .assert_before(timestamp)
258            .map_err(|error| RuntimeError::Custom(error.into()))
259    }
260
261    /// Reads a data blob from storage.
262    fn read_data_blob(caller: &mut Caller, hash: DataBlobHash) -> Result<Vec<u8>, RuntimeError> {
263        caller
264            .user_data_mut()
265            .runtime
266            .read_data_blob(hash)
267            .map_err(|error| RuntimeError::Custom(error.into()))
268    }
269
270    /// Asserts the existence of a data blob with the given hash.
271    fn assert_data_blob_exists(
272        caller: &mut Caller,
273        hash: DataBlobHash,
274    ) -> Result<(), RuntimeError> {
275        caller
276            .user_data_mut()
277            .runtime
278            .assert_data_blob_exists(hash)
279            .map_err(|error| RuntimeError::Custom(error.into()))
280    }
281
282    /// Logs a `message` with the provided information `level`.
283    fn log(caller: &mut Caller, message: String, level: log::Level) -> Result<(), RuntimeError> {
284        let allowed = caller
285            .user_data_mut()
286            .runtime
287            .allow_application_logs()
288            .map_err(|error| RuntimeError::Custom(error.into()))?;
289
290        if !allowed {
291            return Ok(());
292        }
293
294        #[cfg(web)]
295        {
296            // Send log through the execution channel to the main thread
297            caller
298                .user_data_mut()
299                .runtime
300                .send_log(message.clone(), level);
301        }
302
303        // Also use tracing for native builds (and as a fallback on web)
304        match level {
305            log::Level::Trace => tracing::trace!("{message}"),
306            log::Level::Debug => tracing::debug!("{message}"),
307            log::Level::Info => tracing::info!("{message}"),
308            log::Level::Warn => tracing::warn!("{message}"),
309            log::Level::Error => tracing::error!("{message}"),
310        }
311        Ok(())
312    }
313
314    /// Creates a new promise to check if the `key` is in storage.
315    fn contains_key_new(caller: &mut Caller, key: Vec<u8>) -> Result<u32, RuntimeError> {
316        let mut data = caller.user_data_mut();
317        let promise = data
318            .runtime
319            .contains_key_new(key)
320            .map_err(|error| RuntimeError::Custom(error.into()))?;
321
322        Ok(data.register_promise(promise))
323    }
324
325    /// Waits for the promise to check if the `key` is in storage.
326    fn contains_key_wait(caller: &mut Caller, promise_id: u32) -> Result<bool, RuntimeError> {
327        let mut data = caller.user_data_mut();
328        let promise = data.take_promise(promise_id)?;
329
330        data.runtime
331            .contains_key_wait(&promise)
332            .map_err(|error| RuntimeError::Custom(error.into()))
333    }
334
335    /// Creates a new promise to check if the `keys` are in storage.
336    fn contains_keys_new(caller: &mut Caller, keys: Vec<Vec<u8>>) -> Result<u32, RuntimeError> {
337        let mut data = caller.user_data_mut();
338        let promise = data
339            .runtime
340            .contains_keys_new(keys)
341            .map_err(|error| RuntimeError::Custom(error.into()))?;
342
343        Ok(data.register_promise(promise))
344    }
345
346    /// Waits for the promise to check if the `keys` are in storage.
347    fn contains_keys_wait(caller: &mut Caller, promise_id: u32) -> Result<Vec<bool>, RuntimeError> {
348        let mut data = caller.user_data_mut();
349        let promise = data.take_promise(promise_id)?;
350
351        data.runtime
352            .contains_keys_wait(&promise)
353            .map_err(|error| RuntimeError::Custom(error.into()))
354    }
355
356    /// Creates a new promise to read multiple entries from storage.
357    fn read_multi_values_bytes_new(
358        caller: &mut Caller,
359        keys: Vec<Vec<u8>>,
360    ) -> Result<u32, RuntimeError> {
361        let mut data = caller.user_data_mut();
362        let promise = data
363            .runtime
364            .read_multi_values_bytes_new(keys)
365            .map_err(|error| RuntimeError::Custom(error.into()))?;
366
367        Ok(data.register_promise(promise))
368    }
369
370    /// Waits for the promise to read multiple entries from storage.
371    fn read_multi_values_bytes_wait(
372        caller: &mut Caller,
373        promise_id: u32,
374    ) -> Result<Vec<Option<Vec<u8>>>, RuntimeError> {
375        let mut data = caller.user_data_mut();
376        let promise = data.take_promise(promise_id)?;
377
378        data.runtime
379            .read_multi_values_bytes_wait(&promise)
380            .map_err(|error| RuntimeError::Custom(error.into()))
381    }
382
383    /// Creates a new promise to read a single entry from storage.
384    fn read_value_bytes_new(caller: &mut Caller, key: Vec<u8>) -> Result<u32, RuntimeError> {
385        let mut data = caller.user_data_mut();
386        let promise = data
387            .runtime
388            .read_value_bytes_new(key)
389            .map_err(|error| RuntimeError::Custom(error.into()))?;
390
391        Ok(data.register_promise(promise))
392    }
393
394    /// Waits for the promise to read a single entry from storage.
395    fn read_value_bytes_wait(
396        caller: &mut Caller,
397        promise_id: u32,
398    ) -> Result<Option<Vec<u8>>, RuntimeError> {
399        let mut data = caller.user_data_mut();
400        let promise = data.take_promise(promise_id)?;
401
402        data.runtime
403            .read_value_bytes_wait(&promise)
404            .map_err(|error| RuntimeError::Custom(error.into()))
405    }
406
407    /// Creates a new promise to search for keys that start with the `key_prefix`.
408    fn find_keys_new(caller: &mut Caller, key_prefix: Vec<u8>) -> Result<u32, RuntimeError> {
409        let mut data = caller.user_data_mut();
410        let promise = data
411            .runtime
412            .find_keys_by_prefix_new(key_prefix)
413            .map_err(|error| RuntimeError::Custom(error.into()))?;
414
415        Ok(data.register_promise(promise))
416    }
417
418    /// Waits for the promise to search for keys that start with the `key_prefix`.
419    fn find_keys_wait(caller: &mut Caller, promise_id: u32) -> Result<Vec<Vec<u8>>, RuntimeError> {
420        let mut data = caller.user_data_mut();
421        let promise = data.take_promise(promise_id)?;
422
423        data.runtime
424            .find_keys_by_prefix_wait(&promise)
425            .map_err(|error| RuntimeError::Custom(error.into()))
426    }
427
428    /// Creates a new promise to search for entries whose keys that start with the `key_prefix`.
429    fn find_key_values_new(caller: &mut Caller, key_prefix: Vec<u8>) -> Result<u32, RuntimeError> {
430        let mut data = caller.user_data_mut();
431        let promise = data
432            .runtime
433            .find_key_values_by_prefix_new(key_prefix)
434            .map_err(|error| RuntimeError::Custom(error.into()))?;
435
436        Ok(data.register_promise(promise))
437    }
438
439    /// Waits for the promise to search for entries whose keys that start with the `key_prefix`.
440    #[expect(clippy::type_complexity)]
441    fn find_key_values_wait(
442        caller: &mut Caller,
443        promise_id: u32,
444    ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, RuntimeError> {
445        let mut data = caller.user_data_mut();
446        let promise = data.take_promise(promise_id)?;
447
448        data.runtime
449            .find_key_values_by_prefix_wait(&promise)
450            .map_err(|error| RuntimeError::Custom(error.into()))
451    }
452}
453
454/// An implementation of the system API made available to contracts.
455#[derive(Default)]
456pub struct ContractRuntimeApi<Caller>(PhantomData<Caller>);
457
458#[wit_export(package = "linera:app")]
459impl<Caller, Runtime> ContractRuntimeApi<Caller>
460where
461    Caller: Instance<UserData = RuntimeApiData<Runtime>>,
462    Runtime: ContractRuntime + 'static,
463{
464    /// Returns the authenticated owner for this execution, if there is one.
465    fn authenticated_owner(caller: &mut Caller) -> Result<Option<AccountOwner>, RuntimeError> {
466        caller
467            .user_data_mut()
468            .runtime
469            .authenticated_owner()
470            .map_err(|error| RuntimeError::Custom(error.into()))
471    }
472
473    /// Returns `Some(true)` if the incoming message was rejected from the original destination and
474    /// is now bouncing back, `Some(false)` if the message is being currently being delivered to
475    /// its original destination, or [`None`] if not executing an incoming message.
476    fn message_is_bouncing(caller: &mut Caller) -> Result<Option<bool>, RuntimeError> {
477        caller
478            .user_data_mut()
479            .runtime
480            .message_is_bouncing()
481            .map_err(|error| RuntimeError::Custom(error.into()))
482    }
483
484    /// Returns the chain ID where the current message originated from, or [`None`] if not executing
485    /// an incoming message.
486    fn message_origin_chain_id(caller: &mut Caller) -> Result<Option<ChainId>, RuntimeError> {
487        caller
488            .user_data_mut()
489            .runtime
490            .message_origin_chain_id()
491            .map_err(|error| RuntimeError::Custom(error.into()))
492    }
493
494    /// Returns the timestamp of the block on the origin chain that sent the current message,
495    /// or [`None`] if not executing an incoming message.
496    fn message_origin_timestamp(caller: &mut Caller) -> Result<Option<Timestamp>, RuntimeError> {
497        caller
498            .user_data_mut()
499            .runtime
500            .message_origin_timestamp()
501            .map_err(|error| RuntimeError::Custom(error.into()))
502    }
503
504    /// Returns the authenticated caller ID, if the caller configured it and if the current context.
505    fn authenticated_caller_id(caller: &mut Caller) -> Result<Option<ApplicationId>, RuntimeError> {
506        caller
507            .user_data_mut()
508            .runtime
509            .authenticated_caller_id()
510            .map_err(|error| RuntimeError::Custom(error.into()))
511    }
512
513    /// Schedules a message to be sent to this application on another chain.
514    fn send_message(
515        caller: &mut Caller,
516        message: SendMessageRequest<Vec<u8>>,
517    ) -> Result<(), RuntimeError> {
518        caller
519            .user_data_mut()
520            .runtime
521            .send_message(message)
522            .map_err(|error| RuntimeError::Custom(error.into()))
523    }
524
525    /// Transfers an `amount` of native tokens from `source` owner account (or the current chain's
526    /// balance) to `destination`.
527    fn transfer(
528        caller: &mut Caller,
529        source: AccountOwner,
530        destination: Account,
531        amount: Amount,
532    ) -> Result<(), RuntimeError> {
533        caller
534            .user_data_mut()
535            .runtime
536            .transfer(source, destination, amount)
537            .map_err(|error| RuntimeError::Custom(error.into()))
538    }
539
540    /// Claims an `amount` of native tokens from a `source` account to a `destination` account.
541    fn claim(
542        caller: &mut Caller,
543        source: Account,
544        destination: Account,
545        amount: Amount,
546    ) -> Result<(), RuntimeError> {
547        caller
548            .user_data_mut()
549            .runtime
550            .claim(source, destination, amount)
551            .map_err(|error| RuntimeError::Custom(error.into()))
552    }
553
554    /// Approves a `spender` to withdraw an `amount` of native tokens from the `owner`'s account.
555    fn approve(
556        caller: &mut Caller,
557        owner: AccountOwner,
558        spender: AccountOwner,
559        amount: Amount,
560    ) -> Result<(), RuntimeError> {
561        caller
562            .user_data_mut()
563            .runtime
564            .approve(owner, spender, amount)
565            .map_err(|error| RuntimeError::Custom(error.into()))
566    }
567
568    /// Transfers an `amount` of native tokens from `owner` to `destination` using `spender`'s allowance.
569    fn transfer_from(
570        caller: &mut Caller,
571        owner: AccountOwner,
572        spender: AccountOwner,
573        destination: Account,
574        amount: Amount,
575    ) -> Result<(), RuntimeError> {
576        caller
577            .user_data_mut()
578            .runtime
579            .transfer_from(owner, spender, destination, amount)
580            .map_err(|error| RuntimeError::Custom(error.into()))
581    }
582
583    /// Opens a new chain, configuring it with the provided `chain_ownership`,
584    /// `application_permissions` and initial `balance` (debited from the current chain).
585    fn open_chain(
586        caller: &mut Caller,
587        chain_ownership: ChainOwnership,
588        application_permissions: ApplicationPermissions,
589        balance: Amount,
590    ) -> Result<ChainId, RuntimeError> {
591        caller
592            .user_data_mut()
593            .runtime
594            .open_chain(chain_ownership, application_permissions, balance)
595            .map_err(|error| RuntimeError::Custom(error.into()))
596    }
597
598    /// Closes the current chain. Returns an error if the application doesn't have
599    /// permission to do so.
600    fn close_chain(caller: &mut Caller) -> Result<Result<(), ManageChainError>, RuntimeError> {
601        match caller.user_data_mut().runtime.close_chain() {
602            Ok(()) => Ok(Ok(())),
603            Err(ExecutionError::UnauthorizedApplication(_)) => {
604                Ok(Err(ManageChainError::NotPermitted))
605            }
606            Err(error) => Err(RuntimeError::Custom(error.into())),
607        }
608    }
609
610    /// Changes the ownership of the current chain. Returns an error if the application doesn't
611    /// have permission to do so.
612    fn change_ownership(
613        caller: &mut Caller,
614        ownership: ChainOwnership,
615    ) -> Result<Result<(), ManageChainError>, RuntimeError> {
616        match caller.user_data_mut().runtime.change_ownership(ownership) {
617            Ok(()) => Ok(Ok(())),
618            Err(ExecutionError::UnauthorizedApplication(_)) => {
619                Ok(Err(ManageChainError::NotPermitted))
620            }
621            Err(error) => Err(RuntimeError::Custom(error.into())),
622        }
623    }
624
625    /// Changes the application permissions for the current chain. Returns an error if the
626    /// application doesn't have permission to do so.
627    fn change_application_permissions(
628        caller: &mut Caller,
629        application_permissions: ApplicationPermissions,
630    ) -> Result<Result<(), ManageChainError>, RuntimeError> {
631        match caller
632            .user_data_mut()
633            .runtime
634            .change_application_permissions(application_permissions)
635        {
636            Ok(()) => Ok(Ok(())),
637            Err(ExecutionError::UnauthorizedApplication(_)) => {
638                Ok(Err(ManageChainError::NotPermitted))
639            }
640            Err(error) => Err(RuntimeError::Custom(error.into())),
641        }
642    }
643
644    /// Creates a new application on the chain, based on the supplied bytecode and
645    /// parameters.
646    fn create_application(
647        caller: &mut Caller,
648        module_id: ModuleId,
649        parameters: Vec<u8>,
650        argument: Vec<u8>,
651        required_application_ids: Vec<ApplicationId>,
652    ) -> Result<ApplicationId, RuntimeError> {
653        caller
654            .user_data_mut()
655            .runtime
656            .create_application(module_id, parameters, argument, required_application_ids)
657            .map_err(|error| RuntimeError::Custom(error.into()))
658    }
659
660    /// Creates a new data blob and returns its hash.
661    fn create_data_blob(caller: &mut Caller, bytes: Vec<u8>) -> Result<DataBlobHash, RuntimeError> {
662        caller
663            .user_data_mut()
664            .runtime
665            .create_data_blob(bytes)
666            .map_err(|error| RuntimeError::Custom(error.into()))
667    }
668
669    /// Publishes a module with contract and service bytecode and an optional
670    /// JSON-encoded `Formats` description, returning the module ID.
671    fn publish_module(
672        caller: &mut Caller,
673        contract: Bytecode,
674        service: Bytecode,
675        vm_runtime: VmRuntime,
676        formats: Option<Vec<u8>>,
677    ) -> Result<ModuleId, RuntimeError> {
678        caller
679            .user_data_mut()
680            .runtime
681            .publish_module(contract, service, vm_runtime, formats)
682            .map_err(|error| RuntimeError::Custom(error.into()))
683    }
684
685    /// Calls another application.
686    fn try_call_application(
687        caller: &mut Caller,
688        authenticated: bool,
689        callee_id: ApplicationId,
690        argument: Vec<u8>,
691    ) -> Result<Vec<u8>, RuntimeError> {
692        caller
693            .user_data_mut()
694            .runtime
695            .try_call_application(authenticated, callee_id, argument)
696            .map_err(|error| RuntimeError::Custom(error.into()))
697    }
698
699    /// Adds a new item to an event stream. Returns the new event's index in the stream.
700    fn emit(caller: &mut Caller, name: StreamName, value: Vec<u8>) -> Result<u32, RuntimeError> {
701        caller
702            .user_data_mut()
703            .runtime
704            .emit(name, value)
705            .map_err(|error| RuntimeError::Custom(error.into()))
706    }
707
708    /// Reads an event from a stream. Returns the event's value.
709    ///
710    /// Returns an error if the event doesn't exist.
711    fn read_event(
712        caller: &mut Caller,
713        chain_id: ChainId,
714        name: StreamName,
715        index: u32,
716    ) -> Result<Vec<u8>, RuntimeError> {
717        caller
718            .user_data_mut()
719            .runtime
720            .read_event(chain_id, name, index)
721            .map_err(|error| RuntimeError::Custom(error.into()))
722    }
723
724    /// Subscribes this application to an event stream.
725    fn subscribe_to_events(
726        caller: &mut Caller,
727        chain_id: ChainId,
728        application_id: ApplicationId,
729        name: StreamName,
730    ) -> Result<(), RuntimeError> {
731        caller
732            .user_data_mut()
733            .runtime
734            .subscribe_to_events(chain_id, application_id, name)
735            .map_err(|error| RuntimeError::Custom(error.into()))
736    }
737
738    /// Unsubscribes this application from an event stream.
739    fn unsubscribe_from_events(
740        caller: &mut Caller,
741        chain_id: ChainId,
742        application_id: ApplicationId,
743        name: StreamName,
744    ) -> Result<(), RuntimeError> {
745        caller
746            .user_data_mut()
747            .runtime
748            .unsubscribe_from_events(chain_id, application_id, name)
749            .map_err(|error| RuntimeError::Custom(error.into()))
750    }
751
752    /// Queries a service and returns the response.
753    fn query_service(
754        caller: &mut Caller,
755        application_id: ApplicationId,
756        query: Vec<u8>,
757    ) -> Result<Vec<u8>, RuntimeError> {
758        caller
759            .user_data_mut()
760            .runtime
761            .query_service(application_id, query)
762            .map_err(|error| RuntimeError::Custom(error.into()))
763    }
764
765    /// Consume some fuel.
766    ///
767    /// This is intended for the metering instrumentation, but if the user wants to donate
768    /// some extra fuel, more power to them!
769    fn consume_fuel(caller: &mut Caller, fuel: u64) -> Result<(), RuntimeError> {
770        caller
771            .user_data_mut()
772            .runtime_mut()
773            .consume_fuel(fuel, VmRuntime::Wasm)
774            .map_err(|e| RuntimeError::Custom(e.into()))
775    }
776
777    /// Returns the amount of execution fuel remaining before execution is aborted.
778    fn remaining_fuel(caller: &mut Caller) -> Result<u64, RuntimeError> {
779        caller
780            .user_data_mut()
781            .runtime_mut()
782            .remaining_fuel(VmRuntime::Wasm)
783            .map_err(|error| RuntimeError::Custom(error.into()))
784    }
785
786    /// Returns the multi-leader round in which this block was validated.
787    fn validation_round(caller: &mut Caller) -> Result<Option<u32>, RuntimeError> {
788        caller
789            .user_data_mut()
790            .runtime_mut()
791            .validation_round()
792            .map_err(|error| RuntimeError::Custom(error.into()))
793    }
794
795    /// Writes a batch of `operations` to storage.
796    fn write_batch(
797        caller: &mut Caller,
798        operations: Vec<WriteOperation>,
799    ) -> Result<(), RuntimeError> {
800        caller
801            .user_data_mut()
802            .runtime_mut()
803            .write_batch(Batch { operations })
804            .map_err(|error| RuntimeError::Custom(error.into()))
805    }
806
807    /// Returns true if the corresponding contract uses a zero amount of storage.
808    fn has_empty_storage(
809        caller: &mut Caller,
810        application: ApplicationId,
811    ) -> Result<bool, RuntimeError> {
812        caller
813            .user_data_mut()
814            .runtime_mut()
815            .has_empty_storage(application)
816            .map_err(|error| RuntimeError::Custom(error.into()))
817    }
818}
819
820/// An implementation of the system API made available to services.
821#[derive(Default)]
822pub struct ServiceRuntimeApi<Caller>(PhantomData<Caller>);
823
824#[wit_export(package = "linera:app")]
825impl<Caller, Runtime> ServiceRuntimeApi<Caller>
826where
827    Caller: Instance<UserData = RuntimeApiData<Runtime>>,
828    Runtime: ServiceRuntime + 'static,
829{
830    /// Schedules an operation to be included in the block being built by this query.
831    fn schedule_operation(caller: &mut Caller, operation: Vec<u8>) -> Result<(), RuntimeError> {
832        caller
833            .user_data_mut()
834            .runtime
835            .schedule_operation(operation)
836            .map_err(|error| RuntimeError::Custom(error.into()))
837    }
838
839    /// Queries another application.
840    fn try_query_application(
841        caller: &mut Caller,
842        application: ApplicationId,
843        argument: Vec<u8>,
844    ) -> Result<Vec<u8>, RuntimeError> {
845        caller
846            .user_data_mut()
847            .runtime
848            .try_query_application(application, argument)
849            .map_err(|error| RuntimeError::Custom(error.into()))
850    }
851
852    /// Checks if the service has exceeded its execution time limit.
853    ///
854    /// This is called by the metering instrumentation, but the fuel consumed argument is
855    /// ignored.
856    #[expect(unused_variables)]
857    fn check_execution_time(caller: &mut Caller, fuel_consumed: u64) -> Result<(), RuntimeError> {
858        caller
859            .user_data_mut()
860            .runtime_mut()
861            .check_execution_time()
862            .map_err(|error| RuntimeError::Custom(error.into()))
863    }
864}