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    /// Makes an HTTP request to the given URL and returns the response body.
215    fn perform_http_request(
216        caller: &mut Caller,
217        request: http::Request,
218    ) -> Result<http::Response, RuntimeError> {
219        caller
220            .user_data_mut()
221            .runtime
222            .perform_http_request(request)
223            .map_err(|error| RuntimeError::Custom(error.into()))
224    }
225
226    /// Rejects the transaction if the current time at block validation is `>= timestamp`. Note
227    /// that block validation happens at or after the block timestamp, but isn't necessarily the
228    /// same.
229    fn assert_before(caller: &mut Caller, timestamp: Timestamp) -> Result<(), RuntimeError> {
230        caller
231            .user_data_mut()
232            .runtime
233            .assert_before(timestamp)
234            .map_err(|error| RuntimeError::Custom(error.into()))
235    }
236
237    /// Reads a data blob from storage.
238    fn read_data_blob(caller: &mut Caller, hash: DataBlobHash) -> Result<Vec<u8>, RuntimeError> {
239        caller
240            .user_data_mut()
241            .runtime
242            .read_data_blob(hash)
243            .map_err(|error| RuntimeError::Custom(error.into()))
244    }
245
246    /// Asserts the existence of a data blob with the given hash.
247    fn assert_data_blob_exists(
248        caller: &mut Caller,
249        hash: DataBlobHash,
250    ) -> Result<(), RuntimeError> {
251        caller
252            .user_data_mut()
253            .runtime
254            .assert_data_blob_exists(hash)
255            .map_err(|error| RuntimeError::Custom(error.into()))
256    }
257
258    /// Logs a `message` with the provided information `level`.
259    fn log(caller: &mut Caller, message: String, level: log::Level) -> Result<(), RuntimeError> {
260        let allowed = caller
261            .user_data_mut()
262            .runtime
263            .allow_application_logs()
264            .map_err(|error| RuntimeError::Custom(error.into()))?;
265
266        if !allowed {
267            return Ok(());
268        }
269
270        #[cfg(web)]
271        {
272            // Send log through the execution channel to the main thread
273            caller
274                .user_data_mut()
275                .runtime
276                .send_log(message.clone(), level);
277        }
278
279        // Also use tracing for native builds (and as a fallback on web)
280        match level {
281            log::Level::Trace => tracing::trace!("{message}"),
282            log::Level::Debug => tracing::debug!("{message}"),
283            log::Level::Info => tracing::info!("{message}"),
284            log::Level::Warn => tracing::warn!("{message}"),
285            log::Level::Error => tracing::error!("{message}"),
286        }
287        Ok(())
288    }
289
290    /// Creates a new promise to check if the `key` is in storage.
291    fn contains_key_new(caller: &mut Caller, key: Vec<u8>) -> Result<u32, RuntimeError> {
292        let mut data = caller.user_data_mut();
293        let promise = data
294            .runtime
295            .contains_key_new(key)
296            .map_err(|error| RuntimeError::Custom(error.into()))?;
297
298        Ok(data.register_promise(promise))
299    }
300
301    /// Waits for the promise to check if the `key` is in storage.
302    fn contains_key_wait(caller: &mut Caller, promise_id: u32) -> Result<bool, RuntimeError> {
303        let mut data = caller.user_data_mut();
304        let promise = data.take_promise(promise_id)?;
305
306        data.runtime
307            .contains_key_wait(&promise)
308            .map_err(|error| RuntimeError::Custom(error.into()))
309    }
310
311    /// Creates a new promise to check if the `keys` are in storage.
312    fn contains_keys_new(caller: &mut Caller, keys: Vec<Vec<u8>>) -> Result<u32, RuntimeError> {
313        let mut data = caller.user_data_mut();
314        let promise = data
315            .runtime
316            .contains_keys_new(keys)
317            .map_err(|error| RuntimeError::Custom(error.into()))?;
318
319        Ok(data.register_promise(promise))
320    }
321
322    /// Waits for the promise to check if the `keys` are in storage.
323    fn contains_keys_wait(caller: &mut Caller, promise_id: u32) -> Result<Vec<bool>, RuntimeError> {
324        let mut data = caller.user_data_mut();
325        let promise = data.take_promise(promise_id)?;
326
327        data.runtime
328            .contains_keys_wait(&promise)
329            .map_err(|error| RuntimeError::Custom(error.into()))
330    }
331
332    /// Creates a new promise to read multiple entries from storage.
333    fn read_multi_values_bytes_new(
334        caller: &mut Caller,
335        keys: Vec<Vec<u8>>,
336    ) -> Result<u32, RuntimeError> {
337        let mut data = caller.user_data_mut();
338        let promise = data
339            .runtime
340            .read_multi_values_bytes_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 read multiple entries from storage.
347    fn read_multi_values_bytes_wait(
348        caller: &mut Caller,
349        promise_id: u32,
350    ) -> Result<Vec<Option<Vec<u8>>>, RuntimeError> {
351        let mut data = caller.user_data_mut();
352        let promise = data.take_promise(promise_id)?;
353
354        data.runtime
355            .read_multi_values_bytes_wait(&promise)
356            .map_err(|error| RuntimeError::Custom(error.into()))
357    }
358
359    /// Creates a new promise to read a single entry from storage.
360    fn read_value_bytes_new(caller: &mut Caller, key: Vec<u8>) -> Result<u32, RuntimeError> {
361        let mut data = caller.user_data_mut();
362        let promise = data
363            .runtime
364            .read_value_bytes_new(key)
365            .map_err(|error| RuntimeError::Custom(error.into()))?;
366
367        Ok(data.register_promise(promise))
368    }
369
370    /// Waits for the promise to read a single entry from storage.
371    fn read_value_bytes_wait(
372        caller: &mut Caller,
373        promise_id: u32,
374    ) -> Result<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_value_bytes_wait(&promise)
380            .map_err(|error| RuntimeError::Custom(error.into()))
381    }
382
383    /// Creates a new promise to search for keys that start with the `key_prefix`.
384    fn find_keys_new(caller: &mut Caller, key_prefix: Vec<u8>) -> Result<u32, RuntimeError> {
385        let mut data = caller.user_data_mut();
386        let promise = data
387            .runtime
388            .find_keys_by_prefix_new(key_prefix)
389            .map_err(|error| RuntimeError::Custom(error.into()))?;
390
391        Ok(data.register_promise(promise))
392    }
393
394    /// Waits for the promise to search for keys that start with the `key_prefix`.
395    fn find_keys_wait(caller: &mut Caller, promise_id: u32) -> Result<Vec<Vec<u8>>, RuntimeError> {
396        let mut data = caller.user_data_mut();
397        let promise = data.take_promise(promise_id)?;
398
399        data.runtime
400            .find_keys_by_prefix_wait(&promise)
401            .map_err(|error| RuntimeError::Custom(error.into()))
402    }
403
404    /// Creates a new promise to search for entries whose keys that start with the `key_prefix`.
405    fn find_key_values_new(caller: &mut Caller, key_prefix: Vec<u8>) -> Result<u32, RuntimeError> {
406        let mut data = caller.user_data_mut();
407        let promise = data
408            .runtime
409            .find_key_values_by_prefix_new(key_prefix)
410            .map_err(|error| RuntimeError::Custom(error.into()))?;
411
412        Ok(data.register_promise(promise))
413    }
414
415    /// Waits for the promise to search for entries whose keys that start with the `key_prefix`.
416    #[expect(clippy::type_complexity)]
417    fn find_key_values_wait(
418        caller: &mut Caller,
419        promise_id: u32,
420    ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, RuntimeError> {
421        let mut data = caller.user_data_mut();
422        let promise = data.take_promise(promise_id)?;
423
424        data.runtime
425            .find_key_values_by_prefix_wait(&promise)
426            .map_err(|error| RuntimeError::Custom(error.into()))
427    }
428}
429
430/// An implementation of the system API made available to contracts.
431#[derive(Default)]
432pub struct ContractRuntimeApi<Caller>(PhantomData<Caller>);
433
434#[wit_export(package = "linera:app")]
435impl<Caller, Runtime> ContractRuntimeApi<Caller>
436where
437    Caller: Instance<UserData = RuntimeApiData<Runtime>>,
438    Runtime: ContractRuntime + 'static,
439{
440    /// Returns the authenticated owner for this execution, if there is one.
441    fn authenticated_owner(caller: &mut Caller) -> Result<Option<AccountOwner>, RuntimeError> {
442        caller
443            .user_data_mut()
444            .runtime
445            .authenticated_owner()
446            .map_err(|error| RuntimeError::Custom(error.into()))
447    }
448
449    /// Returns `Some(true)` if the incoming message was rejected from the original destination and
450    /// is now bouncing back, `Some(false)` if the message is being currently being delivered to
451    /// its original destination, or [`None`] if not executing an incoming message.
452    fn message_is_bouncing(caller: &mut Caller) -> Result<Option<bool>, RuntimeError> {
453        caller
454            .user_data_mut()
455            .runtime
456            .message_is_bouncing()
457            .map_err(|error| RuntimeError::Custom(error.into()))
458    }
459
460    /// Returns the chain ID where the current message originated from, or [`None`] if not executing
461    /// an incoming message.
462    fn message_origin_chain_id(caller: &mut Caller) -> Result<Option<ChainId>, RuntimeError> {
463        caller
464            .user_data_mut()
465            .runtime
466            .message_origin_chain_id()
467            .map_err(|error| RuntimeError::Custom(error.into()))
468    }
469
470    /// Returns the authenticated caller ID, if the caller configured it and if the current context.
471    fn authenticated_caller_id(caller: &mut Caller) -> Result<Option<ApplicationId>, RuntimeError> {
472        caller
473            .user_data_mut()
474            .runtime
475            .authenticated_caller_id()
476            .map_err(|error| RuntimeError::Custom(error.into()))
477    }
478
479    /// Schedules a message to be sent to this application on another chain.
480    fn send_message(
481        caller: &mut Caller,
482        message: SendMessageRequest<Vec<u8>>,
483    ) -> Result<(), RuntimeError> {
484        caller
485            .user_data_mut()
486            .runtime
487            .send_message(message)
488            .map_err(|error| RuntimeError::Custom(error.into()))
489    }
490
491    /// Transfers an `amount` of native tokens from `source` owner account (or the current chain's
492    /// balance) to `destination`.
493    fn transfer(
494        caller: &mut Caller,
495        source: AccountOwner,
496        destination: Account,
497        amount: Amount,
498    ) -> Result<(), RuntimeError> {
499        caller
500            .user_data_mut()
501            .runtime
502            .transfer(source, destination, amount)
503            .map_err(|error| RuntimeError::Custom(error.into()))
504    }
505
506    /// Claims an `amount` of native tokens from a `source` account to a `destination` account.
507    fn claim(
508        caller: &mut Caller,
509        source: Account,
510        destination: Account,
511        amount: Amount,
512    ) -> Result<(), RuntimeError> {
513        caller
514            .user_data_mut()
515            .runtime
516            .claim(source, destination, amount)
517            .map_err(|error| RuntimeError::Custom(error.into()))
518    }
519
520    /// Opens a new chain, configuring it with the provided `chain_ownership`,
521    /// `application_permissions` and initial `balance` (debited from the current chain).
522    fn open_chain(
523        caller: &mut Caller,
524        chain_ownership: ChainOwnership,
525        application_permissions: ApplicationPermissions,
526        balance: Amount,
527    ) -> Result<ChainId, RuntimeError> {
528        caller
529            .user_data_mut()
530            .runtime
531            .open_chain(chain_ownership, application_permissions, balance)
532            .map_err(|error| RuntimeError::Custom(error.into()))
533    }
534
535    /// Closes the current chain. Returns an error if the application doesn't have
536    /// permission to do so.
537    fn close_chain(caller: &mut Caller) -> Result<Result<(), ManageChainError>, RuntimeError> {
538        match caller.user_data_mut().runtime.close_chain() {
539            Ok(()) => Ok(Ok(())),
540            Err(ExecutionError::UnauthorizedApplication(_)) => {
541                Ok(Err(ManageChainError::NotPermitted))
542            }
543            Err(error) => Err(RuntimeError::Custom(error.into())),
544        }
545    }
546
547    /// Changes the ownership of the current chain. Returns an error if the application doesn't
548    /// have permission to do so.
549    fn change_ownership(
550        caller: &mut Caller,
551        ownership: ChainOwnership,
552    ) -> Result<Result<(), ManageChainError>, RuntimeError> {
553        match caller.user_data_mut().runtime.change_ownership(ownership) {
554            Ok(()) => Ok(Ok(())),
555            Err(ExecutionError::UnauthorizedApplication(_)) => {
556                Ok(Err(ManageChainError::NotPermitted))
557            }
558            Err(error) => Err(RuntimeError::Custom(error.into())),
559        }
560    }
561
562    /// Changes the application permissions for the current chain. Returns an error if the
563    /// application doesn't have permission to do so.
564    fn change_application_permissions(
565        caller: &mut Caller,
566        application_permissions: ApplicationPermissions,
567    ) -> Result<Result<(), ManageChainError>, RuntimeError> {
568        match caller
569            .user_data_mut()
570            .runtime
571            .change_application_permissions(application_permissions)
572        {
573            Ok(()) => Ok(Ok(())),
574            Err(ExecutionError::UnauthorizedApplication(_)) => {
575                Ok(Err(ManageChainError::NotPermitted))
576            }
577            Err(error) => Err(RuntimeError::Custom(error.into())),
578        }
579    }
580
581    /// Creates a new application on the chain, based on the supplied bytecode and
582    /// parameters.
583    fn create_application(
584        caller: &mut Caller,
585        module_id: ModuleId,
586        parameters: Vec<u8>,
587        argument: Vec<u8>,
588        required_application_ids: Vec<ApplicationId>,
589    ) -> Result<ApplicationId, RuntimeError> {
590        caller
591            .user_data_mut()
592            .runtime
593            .create_application(module_id, parameters, argument, required_application_ids)
594            .map_err(|error| RuntimeError::Custom(error.into()))
595    }
596
597    /// Creates a new data blob and returns its hash.
598    fn create_data_blob(caller: &mut Caller, bytes: Vec<u8>) -> Result<DataBlobHash, RuntimeError> {
599        caller
600            .user_data_mut()
601            .runtime
602            .create_data_blob(bytes)
603            .map_err(|error| RuntimeError::Custom(error.into()))
604    }
605
606    /// Publishes a module with contract and service bytecode and returns the module ID.
607    fn publish_module(
608        caller: &mut Caller,
609        contract: Bytecode,
610        service: Bytecode,
611        vm_runtime: VmRuntime,
612    ) -> Result<ModuleId, RuntimeError> {
613        caller
614            .user_data_mut()
615            .runtime
616            .publish_module(contract, service, vm_runtime)
617            .map_err(|error| RuntimeError::Custom(error.into()))
618    }
619
620    /// Calls another application.
621    fn try_call_application(
622        caller: &mut Caller,
623        authenticated: bool,
624        callee_id: ApplicationId,
625        argument: Vec<u8>,
626    ) -> Result<Vec<u8>, RuntimeError> {
627        caller
628            .user_data_mut()
629            .runtime
630            .try_call_application(authenticated, callee_id, argument)
631            .map_err(|error| RuntimeError::Custom(error.into()))
632    }
633
634    /// Adds a new item to an event stream. Returns the new event's index in the stream.
635    fn emit(caller: &mut Caller, name: StreamName, value: Vec<u8>) -> Result<u32, RuntimeError> {
636        caller
637            .user_data_mut()
638            .runtime
639            .emit(name, value)
640            .map_err(|error| RuntimeError::Custom(error.into()))
641    }
642
643    /// Reads an event from a stream. Returns the event's value.
644    ///
645    /// Returns an error if the event doesn't exist.
646    fn read_event(
647        caller: &mut Caller,
648        chain_id: ChainId,
649        name: StreamName,
650        index: u32,
651    ) -> Result<Vec<u8>, RuntimeError> {
652        caller
653            .user_data_mut()
654            .runtime
655            .read_event(chain_id, name, index)
656            .map_err(|error| RuntimeError::Custom(error.into()))
657    }
658
659    /// Subscribes this application to an event stream.
660    fn subscribe_to_events(
661        caller: &mut Caller,
662        chain_id: ChainId,
663        application_id: ApplicationId,
664        name: StreamName,
665    ) -> Result<(), RuntimeError> {
666        caller
667            .user_data_mut()
668            .runtime
669            .subscribe_to_events(chain_id, application_id, name)
670            .map_err(|error| RuntimeError::Custom(error.into()))
671    }
672
673    /// Unsubscribes this application from an event stream.
674    fn unsubscribe_from_events(
675        caller: &mut Caller,
676        chain_id: ChainId,
677        application_id: ApplicationId,
678        name: StreamName,
679    ) -> Result<(), RuntimeError> {
680        caller
681            .user_data_mut()
682            .runtime
683            .unsubscribe_from_events(chain_id, application_id, name)
684            .map_err(|error| RuntimeError::Custom(error.into()))
685    }
686
687    /// Queries a service and returns the response.
688    fn query_service(
689        caller: &mut Caller,
690        application_id: ApplicationId,
691        query: Vec<u8>,
692    ) -> Result<Vec<u8>, RuntimeError> {
693        caller
694            .user_data_mut()
695            .runtime
696            .query_service(application_id, query)
697            .map_err(|error| RuntimeError::Custom(error.into()))
698    }
699
700    /// Consume some fuel.
701    ///
702    /// This is intended for the metering instrumentation, but if the user wants to donate
703    /// some extra fuel, more power to them!
704    fn consume_fuel(caller: &mut Caller, fuel: u64) -> Result<(), RuntimeError> {
705        caller
706            .user_data_mut()
707            .runtime_mut()
708            .consume_fuel(fuel, VmRuntime::Wasm)
709            .map_err(|e| RuntimeError::Custom(e.into()))
710    }
711
712    /// Returns the multi-leader round in which this block was validated.
713    fn validation_round(caller: &mut Caller) -> Result<Option<u32>, RuntimeError> {
714        caller
715            .user_data_mut()
716            .runtime_mut()
717            .validation_round()
718            .map_err(|error| RuntimeError::Custom(error.into()))
719    }
720
721    /// Writes a batch of `operations` to storage.
722    fn write_batch(
723        caller: &mut Caller,
724        operations: Vec<WriteOperation>,
725    ) -> Result<(), RuntimeError> {
726        caller
727            .user_data_mut()
728            .runtime_mut()
729            .write_batch(Batch { operations })
730            .map_err(|error| RuntimeError::Custom(error.into()))
731    }
732
733    /// Returns true if the corresponding contract uses a zero amount of storage.
734    fn has_empty_storage(
735        caller: &mut Caller,
736        application: ApplicationId,
737    ) -> Result<bool, RuntimeError> {
738        caller
739            .user_data_mut()
740            .runtime_mut()
741            .has_empty_storage(application)
742            .map_err(|error| RuntimeError::Custom(error.into()))
743    }
744}
745
746/// An implementation of the system API made available to services.
747#[derive(Default)]
748pub struct ServiceRuntimeApi<Caller>(PhantomData<Caller>);
749
750#[wit_export(package = "linera:app")]
751impl<Caller, Runtime> ServiceRuntimeApi<Caller>
752where
753    Caller: Instance<UserData = RuntimeApiData<Runtime>>,
754    Runtime: ServiceRuntime + 'static,
755{
756    /// Schedules an operation to be included in the block being built by this query.
757    fn schedule_operation(caller: &mut Caller, operation: Vec<u8>) -> Result<(), RuntimeError> {
758        caller
759            .user_data_mut()
760            .runtime
761            .schedule_operation(operation)
762            .map_err(|error| RuntimeError::Custom(error.into()))
763    }
764
765    /// Queries another application.
766    fn try_query_application(
767        caller: &mut Caller,
768        application: ApplicationId,
769        argument: Vec<u8>,
770    ) -> Result<Vec<u8>, RuntimeError> {
771        caller
772            .user_data_mut()
773            .runtime
774            .try_query_application(application, argument)
775            .map_err(|error| RuntimeError::Custom(error.into()))
776    }
777
778    /// Checks if the service has exceeded its execution time limit.
779    ///
780    /// This is called by the metering instrumentation, but the fuel consumed argument is
781    /// ignored.
782    fn check_execution_time(caller: &mut Caller, _fuel_consumed: u64) -> Result<(), RuntimeError> {
783        caller
784            .user_data_mut()
785            .runtime_mut()
786            .check_execution_time()
787            .map_err(|error| RuntimeError::Custom(error.into()))
788    }
789}