1use 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
23pub 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 pub fn new(runtime: Runtime) -> Self {
33 RuntimeApiData {
34 runtime,
35 active_promises: HashMap::new(),
36 promise_counter: 0,
37 }
38 }
39
40 pub fn runtime_mut(&mut self) -> &mut Runtime {
42 &mut self.runtime
43 }
44
45 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 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#[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 caller
274 .user_data_mut()
275 .runtime
276 .send_log(message.clone(), level);
277 }
278
279 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 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 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 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 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 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 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 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 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 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 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 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 #[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#[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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#[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 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 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 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}