1use std::{any::Any, collections::HashMap, marker::PhantomData};
5
6use linera_base::{
7 data_types::{
8 Amount, ApplicationPermissions, BlockHeight, Bytecode, SendMessageRequest, Timestamp,
9 },
10 http,
11 identifiers::{Account, AccountOwner, ApplicationId, ChainId, StreamName},
12 ownership::{ChainOwnership, ChangeApplicationPermissionsError, CloseChainError},
13 vm::VmRuntime,
14};
15use linera_views::batch::{Batch, WriteOperation};
16use linera_witty::{wit_export, Instance, RuntimeError};
17use tracing::log;
18
19use super::WasmExecutionError;
20use crate::{BaseRuntime, ContractRuntime, DataBlobHash, ExecutionError, ModuleId, ServiceRuntime};
21
22pub struct RuntimeApiData<Runtime> {
24 runtime: Runtime,
25 active_promises: HashMap<u32, Box<dyn Any + Send + Sync>>,
26 promise_counter: u32,
27}
28
29impl<Runtime> RuntimeApiData<Runtime> {
30 pub fn new(runtime: Runtime) -> Self {
32 RuntimeApiData {
33 runtime,
34 active_promises: HashMap::new(),
35 promise_counter: 0,
36 }
37 }
38
39 pub fn runtime_mut(&mut self) -> &mut Runtime {
41 &mut self.runtime
42 }
43
44 fn register_promise<Promise>(&mut self, promise: Promise) -> u32
47 where
48 Promise: Send + Sync + 'static,
49 {
50 let id = self.promise_counter;
51
52 self.active_promises.insert(id, Box::new(promise));
53 self.promise_counter += 1;
54
55 id
56 }
57
58 fn take_promise<Promise>(&mut self, promise_id: u32) -> Result<Promise, RuntimeError>
60 where
61 Promise: Send + Sync + 'static,
62 {
63 let type_erased_promise = self
64 .active_promises
65 .remove(&promise_id)
66 .ok_or_else(|| RuntimeError::Custom(WasmExecutionError::UnknownPromise.into()))?;
67
68 type_erased_promise
69 .downcast()
70 .map(|boxed_promise| *boxed_promise)
71 .map_err(|_| RuntimeError::Custom(WasmExecutionError::IncorrectPromise.into()))
72 }
73}
74
75#[derive(Default)]
78pub struct BaseRuntimeApi<Caller>(PhantomData<Caller>);
79
80#[wit_export(package = "linera:app")]
81impl<Caller, Runtime> BaseRuntimeApi<Caller>
82where
83 Caller: Instance<UserData = RuntimeApiData<Runtime>>,
84 Runtime: BaseRuntime + 'static,
85{
86 fn get_chain_id(caller: &mut Caller) -> Result<ChainId, RuntimeError> {
88 caller
89 .user_data_mut()
90 .runtime
91 .chain_id()
92 .map_err(|error| RuntimeError::Custom(error.into()))
93 }
94
95 fn get_block_height(caller: &mut Caller) -> Result<BlockHeight, RuntimeError> {
97 caller
98 .user_data_mut()
99 .runtime
100 .block_height()
101 .map_err(|error| RuntimeError::Custom(error.into()))
102 }
103
104 fn get_application_id(caller: &mut Caller) -> Result<ApplicationId, RuntimeError> {
106 caller
107 .user_data_mut()
108 .runtime
109 .application_id()
110 .map_err(|error| RuntimeError::Custom(error.into()))
111 }
112
113 fn get_application_creator_chain_id(caller: &mut Caller) -> Result<ChainId, RuntimeError> {
115 caller
116 .user_data_mut()
117 .runtime
118 .application_creator_chain_id()
119 .map_err(|error| RuntimeError::Custom(error.into()))
120 }
121
122 fn application_parameters(caller: &mut Caller) -> Result<Vec<u8>, RuntimeError> {
124 caller
125 .user_data_mut()
126 .runtime
127 .application_parameters()
128 .map_err(|error| RuntimeError::Custom(error.into()))
129 }
130
131 fn get_chain_ownership(caller: &mut Caller) -> Result<ChainOwnership, RuntimeError> {
133 caller
134 .user_data_mut()
135 .runtime
136 .chain_ownership()
137 .map_err(|error| RuntimeError::Custom(error.into()))
138 }
139
140 fn read_system_timestamp(caller: &mut Caller) -> Result<Timestamp, RuntimeError> {
142 caller
143 .user_data_mut()
144 .runtime
145 .read_system_timestamp()
146 .map_err(|error| RuntimeError::Custom(error.into()))
147 }
148
149 fn read_chain_balance(caller: &mut Caller) -> Result<Amount, RuntimeError> {
151 caller
152 .user_data_mut()
153 .runtime
154 .read_chain_balance()
155 .map_err(|error| RuntimeError::Custom(error.into()))
156 }
157
158 fn read_owner_balance(
160 caller: &mut Caller,
161 owner: AccountOwner,
162 ) -> Result<Amount, RuntimeError> {
163 caller
164 .user_data_mut()
165 .runtime
166 .read_owner_balance(owner)
167 .map_err(|error| RuntimeError::Custom(error.into()))
168 }
169
170 fn read_owner_balances(
172 caller: &mut Caller,
173 ) -> Result<Vec<(AccountOwner, Amount)>, RuntimeError> {
174 caller
175 .user_data_mut()
176 .runtime
177 .read_owner_balances()
178 .map_err(|error| RuntimeError::Custom(error.into()))
179 }
180
181 fn read_balance_owners(caller: &mut Caller) -> Result<Vec<AccountOwner>, RuntimeError> {
183 caller
184 .user_data_mut()
185 .runtime
186 .read_balance_owners()
187 .map_err(|error| RuntimeError::Custom(error.into()))
188 }
189
190 fn perform_http_request(
192 caller: &mut Caller,
193 request: http::Request,
194 ) -> Result<http::Response, RuntimeError> {
195 caller
196 .user_data_mut()
197 .runtime
198 .perform_http_request(request)
199 .map_err(|error| RuntimeError::Custom(error.into()))
200 }
201
202 fn assert_before(caller: &mut Caller, timestamp: Timestamp) -> Result<(), RuntimeError> {
206 caller
207 .user_data_mut()
208 .runtime
209 .assert_before(timestamp)
210 .map_err(|error| RuntimeError::Custom(error.into()))
211 }
212
213 fn read_data_blob(caller: &mut Caller, hash: DataBlobHash) -> Result<Vec<u8>, RuntimeError> {
215 caller
216 .user_data_mut()
217 .runtime
218 .read_data_blob(hash)
219 .map_err(|error| RuntimeError::Custom(error.into()))
220 }
221
222 fn assert_data_blob_exists(
224 caller: &mut Caller,
225 hash: DataBlobHash,
226 ) -> Result<(), RuntimeError> {
227 caller
228 .user_data_mut()
229 .runtime
230 .assert_data_blob_exists(hash)
231 .map_err(|error| RuntimeError::Custom(error.into()))
232 }
233
234 fn log(_caller: &mut Caller, message: String, level: log::Level) {
236 match level {
237 log::Level::Trace => tracing::trace!("{message}"),
238 log::Level::Debug => tracing::debug!("{message}"),
239 log::Level::Info => tracing::info!("{message}"),
240 log::Level::Warn => tracing::warn!("{message}"),
241 log::Level::Error => tracing::error!("{message}"),
242 }
243 }
244
245 fn contains_key_new(caller: &mut Caller, key: Vec<u8>) -> Result<u32, RuntimeError> {
247 let mut data = caller.user_data_mut();
248 let promise = data
249 .runtime
250 .contains_key_new(key)
251 .map_err(|error| RuntimeError::Custom(error.into()))?;
252
253 Ok(data.register_promise(promise))
254 }
255
256 fn contains_key_wait(caller: &mut Caller, promise_id: u32) -> Result<bool, RuntimeError> {
258 let mut data = caller.user_data_mut();
259 let promise = data.take_promise(promise_id)?;
260
261 data.runtime
262 .contains_key_wait(&promise)
263 .map_err(|error| RuntimeError::Custom(error.into()))
264 }
265
266 fn contains_keys_new(caller: &mut Caller, keys: Vec<Vec<u8>>) -> Result<u32, RuntimeError> {
268 let mut data = caller.user_data_mut();
269 let promise = data
270 .runtime
271 .contains_keys_new(keys)
272 .map_err(|error| RuntimeError::Custom(error.into()))?;
273
274 Ok(data.register_promise(promise))
275 }
276
277 fn contains_keys_wait(caller: &mut Caller, promise_id: u32) -> Result<Vec<bool>, RuntimeError> {
279 let mut data = caller.user_data_mut();
280 let promise = data.take_promise(promise_id)?;
281
282 data.runtime
283 .contains_keys_wait(&promise)
284 .map_err(|error| RuntimeError::Custom(error.into()))
285 }
286
287 fn read_multi_values_bytes_new(
289 caller: &mut Caller,
290 keys: Vec<Vec<u8>>,
291 ) -> Result<u32, RuntimeError> {
292 let mut data = caller.user_data_mut();
293 let promise = data
294 .runtime
295 .read_multi_values_bytes_new(keys)
296 .map_err(|error| RuntimeError::Custom(error.into()))?;
297
298 Ok(data.register_promise(promise))
299 }
300
301 fn read_multi_values_bytes_wait(
303 caller: &mut Caller,
304 promise_id: u32,
305 ) -> Result<Vec<Option<Vec<u8>>>, RuntimeError> {
306 let mut data = caller.user_data_mut();
307 let promise = data.take_promise(promise_id)?;
308
309 data.runtime
310 .read_multi_values_bytes_wait(&promise)
311 .map_err(|error| RuntimeError::Custom(error.into()))
312 }
313
314 fn read_value_bytes_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 .read_value_bytes_new(key)
320 .map_err(|error| RuntimeError::Custom(error.into()))?;
321
322 Ok(data.register_promise(promise))
323 }
324
325 fn read_value_bytes_wait(
327 caller: &mut Caller,
328 promise_id: u32,
329 ) -> Result<Option<Vec<u8>>, RuntimeError> {
330 let mut data = caller.user_data_mut();
331 let promise = data.take_promise(promise_id)?;
332
333 data.runtime
334 .read_value_bytes_wait(&promise)
335 .map_err(|error| RuntimeError::Custom(error.into()))
336 }
337
338 fn find_keys_new(caller: &mut Caller, key_prefix: Vec<u8>) -> Result<u32, RuntimeError> {
340 let mut data = caller.user_data_mut();
341 let promise = data
342 .runtime
343 .find_keys_by_prefix_new(key_prefix)
344 .map_err(|error| RuntimeError::Custom(error.into()))?;
345
346 Ok(data.register_promise(promise))
347 }
348
349 fn find_keys_wait(caller: &mut Caller, promise_id: u32) -> Result<Vec<Vec<u8>>, RuntimeError> {
351 let mut data = caller.user_data_mut();
352 let promise = data.take_promise(promise_id)?;
353
354 data.runtime
355 .find_keys_by_prefix_wait(&promise)
356 .map_err(|error| RuntimeError::Custom(error.into()))
357 }
358
359 fn find_key_values_new(caller: &mut Caller, key_prefix: Vec<u8>) -> Result<u32, RuntimeError> {
361 let mut data = caller.user_data_mut();
362 let promise = data
363 .runtime
364 .find_key_values_by_prefix_new(key_prefix)
365 .map_err(|error| RuntimeError::Custom(error.into()))?;
366
367 Ok(data.register_promise(promise))
368 }
369
370 #[expect(clippy::type_complexity)]
372 fn find_key_values_wait(
373 caller: &mut Caller,
374 promise_id: u32,
375 ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, RuntimeError> {
376 let mut data = caller.user_data_mut();
377 let promise = data.take_promise(promise_id)?;
378
379 data.runtime
380 .find_key_values_by_prefix_wait(&promise)
381 .map_err(|error| RuntimeError::Custom(error.into()))
382 }
383}
384
385#[derive(Default)]
387pub struct ContractRuntimeApi<Caller>(PhantomData<Caller>);
388
389#[wit_export(package = "linera:app")]
390impl<Caller, Runtime> ContractRuntimeApi<Caller>
391where
392 Caller: Instance<UserData = RuntimeApiData<Runtime>>,
393 Runtime: ContractRuntime + 'static,
394{
395 fn authenticated_owner(caller: &mut Caller) -> Result<Option<AccountOwner>, RuntimeError> {
397 caller
398 .user_data_mut()
399 .runtime
400 .authenticated_owner()
401 .map_err(|error| RuntimeError::Custom(error.into()))
402 }
403
404 fn message_is_bouncing(caller: &mut Caller) -> Result<Option<bool>, RuntimeError> {
408 caller
409 .user_data_mut()
410 .runtime
411 .message_is_bouncing()
412 .map_err(|error| RuntimeError::Custom(error.into()))
413 }
414
415 fn message_origin_chain_id(caller: &mut Caller) -> Result<Option<ChainId>, RuntimeError> {
418 caller
419 .user_data_mut()
420 .runtime
421 .message_origin_chain_id()
422 .map_err(|error| RuntimeError::Custom(error.into()))
423 }
424
425 fn authenticated_caller_id(caller: &mut Caller) -> Result<Option<ApplicationId>, RuntimeError> {
427 caller
428 .user_data_mut()
429 .runtime
430 .authenticated_caller_id()
431 .map_err(|error| RuntimeError::Custom(error.into()))
432 }
433
434 fn send_message(
436 caller: &mut Caller,
437 message: SendMessageRequest<Vec<u8>>,
438 ) -> Result<(), RuntimeError> {
439 caller
440 .user_data_mut()
441 .runtime
442 .send_message(message)
443 .map_err(|error| RuntimeError::Custom(error.into()))
444 }
445
446 fn transfer(
449 caller: &mut Caller,
450 source: AccountOwner,
451 destination: Account,
452 amount: Amount,
453 ) -> Result<(), RuntimeError> {
454 caller
455 .user_data_mut()
456 .runtime
457 .transfer(source, destination, amount)
458 .map_err(|error| RuntimeError::Custom(error.into()))
459 }
460
461 fn claim(
463 caller: &mut Caller,
464 source: Account,
465 destination: Account,
466 amount: Amount,
467 ) -> Result<(), RuntimeError> {
468 caller
469 .user_data_mut()
470 .runtime
471 .claim(source, destination, amount)
472 .map_err(|error| RuntimeError::Custom(error.into()))
473 }
474
475 fn open_chain(
478 caller: &mut Caller,
479 chain_ownership: ChainOwnership,
480 application_permissions: ApplicationPermissions,
481 balance: Amount,
482 ) -> Result<ChainId, RuntimeError> {
483 caller
484 .user_data_mut()
485 .runtime
486 .open_chain(chain_ownership, application_permissions, balance)
487 .map_err(|error| RuntimeError::Custom(error.into()))
488 }
489
490 fn close_chain(caller: &mut Caller) -> Result<Result<(), CloseChainError>, RuntimeError> {
493 match caller.user_data_mut().runtime.close_chain() {
494 Ok(()) => Ok(Ok(())),
495 Err(ExecutionError::UnauthorizedApplication(_)) => {
496 Ok(Err(CloseChainError::NotPermitted))
497 }
498 Err(error) => Err(RuntimeError::Custom(error.into())),
499 }
500 }
501
502 fn change_application_permissions(
505 caller: &mut Caller,
506 application_permissions: ApplicationPermissions,
507 ) -> Result<Result<(), ChangeApplicationPermissionsError>, RuntimeError> {
508 match caller
509 .user_data_mut()
510 .runtime
511 .change_application_permissions(application_permissions)
512 {
513 Ok(()) => Ok(Ok(())),
514 Err(ExecutionError::UnauthorizedApplication(_)) => {
515 Ok(Err(ChangeApplicationPermissionsError::NotPermitted))
516 }
517 Err(error) => Err(RuntimeError::Custom(error.into())),
518 }
519 }
520
521 fn create_application(
524 caller: &mut Caller,
525 module_id: ModuleId,
526 parameters: Vec<u8>,
527 argument: Vec<u8>,
528 required_application_ids: Vec<ApplicationId>,
529 ) -> Result<ApplicationId, RuntimeError> {
530 caller
531 .user_data_mut()
532 .runtime
533 .create_application(module_id, parameters, argument, required_application_ids)
534 .map_err(|error| RuntimeError::Custom(error.into()))
535 }
536
537 fn create_data_blob(caller: &mut Caller, bytes: Vec<u8>) -> Result<DataBlobHash, RuntimeError> {
539 caller
540 .user_data_mut()
541 .runtime
542 .create_data_blob(bytes)
543 .map_err(|error| RuntimeError::Custom(error.into()))
544 }
545
546 fn publish_module(
548 caller: &mut Caller,
549 contract: Bytecode,
550 service: Bytecode,
551 vm_runtime: VmRuntime,
552 ) -> Result<ModuleId, RuntimeError> {
553 caller
554 .user_data_mut()
555 .runtime
556 .publish_module(contract, service, vm_runtime)
557 .map_err(|error| RuntimeError::Custom(error.into()))
558 }
559
560 fn try_call_application(
562 caller: &mut Caller,
563 authenticated: bool,
564 callee_id: ApplicationId,
565 argument: Vec<u8>,
566 ) -> Result<Vec<u8>, RuntimeError> {
567 caller
568 .user_data_mut()
569 .runtime
570 .try_call_application(authenticated, callee_id, argument)
571 .map_err(|error| RuntimeError::Custom(error.into()))
572 }
573
574 fn emit(caller: &mut Caller, name: StreamName, value: Vec<u8>) -> Result<u32, RuntimeError> {
576 caller
577 .user_data_mut()
578 .runtime
579 .emit(name, value)
580 .map_err(|error| RuntimeError::Custom(error.into()))
581 }
582
583 fn read_event(
587 caller: &mut Caller,
588 chain_id: ChainId,
589 name: StreamName,
590 index: u32,
591 ) -> Result<Vec<u8>, RuntimeError> {
592 caller
593 .user_data_mut()
594 .runtime
595 .read_event(chain_id, name, index)
596 .map_err(|error| RuntimeError::Custom(error.into()))
597 }
598
599 fn subscribe_to_events(
601 caller: &mut Caller,
602 chain_id: ChainId,
603 application_id: ApplicationId,
604 name: StreamName,
605 ) -> Result<(), RuntimeError> {
606 caller
607 .user_data_mut()
608 .runtime
609 .subscribe_to_events(chain_id, application_id, name)
610 .map_err(|error| RuntimeError::Custom(error.into()))
611 }
612
613 fn unsubscribe_from_events(
615 caller: &mut Caller,
616 chain_id: ChainId,
617 application_id: ApplicationId,
618 name: StreamName,
619 ) -> Result<(), RuntimeError> {
620 caller
621 .user_data_mut()
622 .runtime
623 .unsubscribe_from_events(chain_id, application_id, name)
624 .map_err(|error| RuntimeError::Custom(error.into()))
625 }
626
627 fn query_service(
629 caller: &mut Caller,
630 application_id: ApplicationId,
631 query: Vec<u8>,
632 ) -> Result<Vec<u8>, RuntimeError> {
633 caller
634 .user_data_mut()
635 .runtime
636 .query_service(application_id, query)
637 .map_err(|error| RuntimeError::Custom(error.into()))
638 }
639
640 fn consume_fuel(caller: &mut Caller, fuel: u64) -> Result<(), RuntimeError> {
645 caller
646 .user_data_mut()
647 .runtime_mut()
648 .consume_fuel(fuel, VmRuntime::Wasm)
649 .map_err(|e| RuntimeError::Custom(e.into()))
650 }
651
652 fn validation_round(caller: &mut Caller) -> Result<Option<u32>, RuntimeError> {
654 caller
655 .user_data_mut()
656 .runtime_mut()
657 .validation_round()
658 .map_err(|error| RuntimeError::Custom(error.into()))
659 }
660
661 fn write_batch(
663 caller: &mut Caller,
664 operations: Vec<WriteOperation>,
665 ) -> Result<(), RuntimeError> {
666 caller
667 .user_data_mut()
668 .runtime_mut()
669 .write_batch(Batch { operations })
670 .map_err(|error| RuntimeError::Custom(error.into()))
671 }
672}
673
674#[derive(Default)]
676pub struct ServiceRuntimeApi<Caller>(PhantomData<Caller>);
677
678#[wit_export(package = "linera:app")]
679impl<Caller, Runtime> ServiceRuntimeApi<Caller>
680where
681 Caller: Instance<UserData = RuntimeApiData<Runtime>>,
682 Runtime: ServiceRuntime + 'static,
683{
684 fn schedule_operation(caller: &mut Caller, operation: Vec<u8>) -> Result<(), RuntimeError> {
686 caller
687 .user_data_mut()
688 .runtime
689 .schedule_operation(operation)
690 .map_err(|error| RuntimeError::Custom(error.into()))
691 }
692
693 fn try_query_application(
695 caller: &mut Caller,
696 application: ApplicationId,
697 argument: Vec<u8>,
698 ) -> Result<Vec<u8>, RuntimeError> {
699 caller
700 .user_data_mut()
701 .runtime
702 .try_query_application(application, argument)
703 .map_err(|error| RuntimeError::Custom(error.into()))
704 }
705
706 fn check_execution_time(caller: &mut Caller, _fuel_consumed: u64) -> Result<(), RuntimeError> {
711 caller
712 .user_data_mut()
713 .runtime_mut()
714 .check_execution_time()
715 .map_err(|error| RuntimeError::Custom(error.into()))
716 }
717}