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