1use std::{any::Any, collections::HashMap, marker::PhantomData};
5
6use linera_base::{
7 crypto::CryptoHash,
8 data_types::{
9 Amount, ApplicationPermissions, BlockHeight, Bytecode, SendMessageRequest, Timestamp,
10 },
11 http,
12 identifiers::{Account, AccountOwner, ApplicationId, BlobId, ChainId, StreamName},
13 ownership::{ChainOwnership, ChangeApplicationPermissionsError, CloseChainError},
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, 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) -> Result<u32, RuntimeError>
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 Ok(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 application_parameters(caller: &mut Caller) -> Result<Vec<u8>, RuntimeError> {
125 caller
126 .user_data_mut()
127 .runtime
128 .application_parameters()
129 .map_err(|error| RuntimeError::Custom(error.into()))
130 }
131
132 fn get_chain_ownership(caller: &mut Caller) -> Result<ChainOwnership, RuntimeError> {
134 caller
135 .user_data_mut()
136 .runtime
137 .chain_ownership()
138 .map_err(|error| RuntimeError::Custom(error.into()))
139 }
140
141 fn read_system_timestamp(caller: &mut Caller) -> Result<Timestamp, RuntimeError> {
143 caller
144 .user_data_mut()
145 .runtime
146 .read_system_timestamp()
147 .map_err(|error| RuntimeError::Custom(error.into()))
148 }
149
150 fn read_chain_balance(caller: &mut Caller) -> Result<Amount, RuntimeError> {
152 caller
153 .user_data_mut()
154 .runtime
155 .read_chain_balance()
156 .map_err(|error| RuntimeError::Custom(error.into()))
157 }
158
159 fn read_owner_balance(
161 caller: &mut Caller,
162 owner: AccountOwner,
163 ) -> Result<Amount, RuntimeError> {
164 caller
165 .user_data_mut()
166 .runtime
167 .read_owner_balance(owner)
168 .map_err(|error| RuntimeError::Custom(error.into()))
169 }
170
171 fn read_owner_balances(
173 caller: &mut Caller,
174 ) -> Result<Vec<(AccountOwner, Amount)>, RuntimeError> {
175 caller
176 .user_data_mut()
177 .runtime
178 .read_owner_balances()
179 .map_err(|error| RuntimeError::Custom(error.into()))
180 }
181
182 fn read_balance_owners(caller: &mut Caller) -> Result<Vec<AccountOwner>, RuntimeError> {
184 caller
185 .user_data_mut()
186 .runtime
187 .read_balance_owners()
188 .map_err(|error| RuntimeError::Custom(error.into()))
189 }
190
191 fn perform_http_request(
193 caller: &mut Caller,
194 request: http::Request,
195 ) -> Result<http::Response, RuntimeError> {
196 caller
197 .user_data_mut()
198 .runtime
199 .perform_http_request(request)
200 .map_err(|error| RuntimeError::Custom(error.into()))
201 }
202
203 fn assert_before(caller: &mut Caller, timestamp: Timestamp) -> Result<(), RuntimeError> {
207 caller
208 .user_data_mut()
209 .runtime
210 .assert_before(timestamp)
211 .map_err(|error| RuntimeError::Custom(error.into()))
212 }
213
214 fn read_data_blob(caller: &mut Caller, hash: CryptoHash) -> Result<Vec<u8>, RuntimeError> {
216 caller
217 .user_data_mut()
218 .runtime
219 .read_data_blob(&hash)
220 .map_err(|error| RuntimeError::Custom(error.into()))
221 }
222
223 fn assert_data_blob_exists(caller: &mut Caller, hash: CryptoHash) -> Result<(), RuntimeError> {
225 caller
226 .user_data_mut()
227 .runtime
228 .assert_data_blob_exists(&hash)
229 .map_err(|error| RuntimeError::Custom(error.into()))
230 }
231
232 fn log(_caller: &mut Caller, message: String, level: log::Level) -> Result<(), RuntimeError> {
234 match level {
235 log::Level::Trace => tracing::trace!("{message}"),
236 log::Level::Debug => tracing::debug!("{message}"),
237 log::Level::Info => tracing::info!("{message}"),
238 log::Level::Warn => tracing::warn!("{message}"),
239 log::Level::Error => tracing::error!("{message}"),
240 }
241 Ok(())
242 }
243
244 fn contains_key_new(caller: &mut Caller, key: Vec<u8>) -> Result<u32, RuntimeError> {
246 let mut data = caller.user_data_mut();
247 let promise = data
248 .runtime
249 .contains_key_new(key)
250 .map_err(|error| RuntimeError::Custom(error.into()))?;
251
252 data.register_promise(promise)
253 }
254
255 fn contains_key_wait(caller: &mut Caller, promise_id: u32) -> Result<bool, RuntimeError> {
257 let mut data = caller.user_data_mut();
258 let promise = data.take_promise(promise_id)?;
259
260 data.runtime
261 .contains_key_wait(&promise)
262 .map_err(|error| RuntimeError::Custom(error.into()))
263 }
264
265 fn contains_keys_new(caller: &mut Caller, keys: Vec<Vec<u8>>) -> Result<u32, RuntimeError> {
267 let mut data = caller.user_data_mut();
268 let promise = data
269 .runtime
270 .contains_keys_new(keys)
271 .map_err(|error| RuntimeError::Custom(error.into()))?;
272
273 data.register_promise(promise)
274 }
275
276 fn contains_keys_wait(caller: &mut Caller, promise_id: u32) -> Result<Vec<bool>, RuntimeError> {
278 let mut data = caller.user_data_mut();
279 let promise = data.take_promise(promise_id)?;
280
281 data.runtime
282 .contains_keys_wait(&promise)
283 .map_err(|error| RuntimeError::Custom(error.into()))
284 }
285
286 fn read_multi_values_bytes_new(
288 caller: &mut Caller,
289 keys: Vec<Vec<u8>>,
290 ) -> Result<u32, RuntimeError> {
291 let mut data = caller.user_data_mut();
292 let promise = data
293 .runtime
294 .read_multi_values_bytes_new(keys)
295 .map_err(|error| RuntimeError::Custom(error.into()))?;
296
297 data.register_promise(promise)
298 }
299
300 fn read_multi_values_bytes_wait(
302 caller: &mut Caller,
303 promise_id: u32,
304 ) -> Result<Vec<Option<Vec<u8>>>, RuntimeError> {
305 let mut data = caller.user_data_mut();
306 let promise = data.take_promise(promise_id)?;
307
308 data.runtime
309 .read_multi_values_bytes_wait(&promise)
310 .map_err(|error| RuntimeError::Custom(error.into()))
311 }
312
313 fn read_value_bytes_new(caller: &mut Caller, key: Vec<u8>) -> Result<u32, RuntimeError> {
315 let mut data = caller.user_data_mut();
316 let promise = data
317 .runtime
318 .read_value_bytes_new(key)
319 .map_err(|error| RuntimeError::Custom(error.into()))?;
320
321 data.register_promise(promise)
322 }
323
324 fn read_value_bytes_wait(
326 caller: &mut Caller,
327 promise_id: u32,
328 ) -> Result<Option<Vec<u8>>, RuntimeError> {
329 let mut data = caller.user_data_mut();
330 let promise = data.take_promise(promise_id)?;
331
332 data.runtime
333 .read_value_bytes_wait(&promise)
334 .map_err(|error| RuntimeError::Custom(error.into()))
335 }
336
337 fn find_keys_new(caller: &mut Caller, key_prefix: Vec<u8>) -> Result<u32, RuntimeError> {
339 let mut data = caller.user_data_mut();
340 let promise = data
341 .runtime
342 .find_keys_by_prefix_new(key_prefix)
343 .map_err(|error| RuntimeError::Custom(error.into()))?;
344
345 data.register_promise(promise)
346 }
347
348 fn find_keys_wait(caller: &mut Caller, promise_id: u32) -> Result<Vec<Vec<u8>>, RuntimeError> {
350 let mut data = caller.user_data_mut();
351 let promise = data.take_promise(promise_id)?;
352
353 data.runtime
354 .find_keys_by_prefix_wait(&promise)
355 .map_err(|error| RuntimeError::Custom(error.into()))
356 }
357
358 fn find_key_values_new(caller: &mut Caller, key_prefix: Vec<u8>) -> Result<u32, RuntimeError> {
360 let mut data = caller.user_data_mut();
361 let promise = data
362 .runtime
363 .find_key_values_by_prefix_new(key_prefix)
364 .map_err(|error| RuntimeError::Custom(error.into()))?;
365
366 data.register_promise(promise)
367 }
368
369 #[expect(clippy::type_complexity)]
371 fn find_key_values_wait(
372 caller: &mut Caller,
373 promise_id: u32,
374 ) -> Result<Vec<(Vec<u8>, Vec<u8>)>, RuntimeError> {
375 let mut data = caller.user_data_mut();
376 let promise = data.take_promise(promise_id)?;
377
378 data.runtime
379 .find_key_values_by_prefix_wait(&promise)
380 .map_err(|error| RuntimeError::Custom(error.into()))
381 }
382}
383
384#[derive(Default)]
386pub struct ContractRuntimeApi<Caller>(PhantomData<Caller>);
387
388#[wit_export(package = "linera:app")]
389impl<Caller, Runtime> ContractRuntimeApi<Caller>
390where
391 Caller: Instance<UserData = RuntimeApiData<Runtime>>,
392 Runtime: ContractRuntime + 'static,
393{
394 fn authenticated_signer(caller: &mut Caller) -> Result<Option<AccountOwner>, RuntimeError> {
396 caller
397 .user_data_mut()
398 .runtime
399 .authenticated_signer()
400 .map_err(|error| RuntimeError::Custom(error.into()))
401 }
402
403 fn message_is_bouncing(caller: &mut Caller) -> Result<Option<bool>, RuntimeError> {
407 caller
408 .user_data_mut()
409 .runtime
410 .message_is_bouncing()
411 .map_err(|error| RuntimeError::Custom(error.into()))
412 }
413
414 fn message_origin_chain_id(caller: &mut Caller) -> Result<Option<ChainId>, RuntimeError> {
417 caller
418 .user_data_mut()
419 .runtime
420 .message_origin_chain_id()
421 .map_err(|error| RuntimeError::Custom(error.into()))
422 }
423
424 fn authenticated_caller_id(caller: &mut Caller) -> Result<Option<ApplicationId>, RuntimeError> {
426 caller
427 .user_data_mut()
428 .runtime
429 .authenticated_caller_id()
430 .map_err(|error| RuntimeError::Custom(error.into()))
431 }
432
433 fn send_message(
435 caller: &mut Caller,
436 message: SendMessageRequest<Vec<u8>>,
437 ) -> Result<(), RuntimeError> {
438 caller
439 .user_data_mut()
440 .runtime
441 .send_message(message)
442 .map_err(|error| RuntimeError::Custom(error.into()))
443 }
444
445 fn transfer(
448 caller: &mut Caller,
449 source: AccountOwner,
450 destination: Account,
451 amount: Amount,
452 ) -> Result<(), RuntimeError> {
453 caller
454 .user_data_mut()
455 .runtime
456 .transfer(source, destination, amount)
457 .map_err(|error| RuntimeError::Custom(error.into()))
458 }
459
460 fn claim(
462 caller: &mut Caller,
463 source: Account,
464 destination: Account,
465 amount: Amount,
466 ) -> Result<(), RuntimeError> {
467 caller
468 .user_data_mut()
469 .runtime
470 .claim(source, destination, amount)
471 .map_err(|error| RuntimeError::Custom(error.into()))
472 }
473
474 fn open_chain(
477 caller: &mut Caller,
478 chain_ownership: ChainOwnership,
479 application_permissions: ApplicationPermissions,
480 balance: Amount,
481 ) -> Result<ChainId, RuntimeError> {
482 caller
483 .user_data_mut()
484 .runtime
485 .open_chain(chain_ownership, application_permissions, balance)
486 .map_err(|error| RuntimeError::Custom(error.into()))
487 }
488
489 fn close_chain(caller: &mut Caller) -> Result<Result<(), CloseChainError>, RuntimeError> {
492 match caller.user_data_mut().runtime.close_chain() {
493 Ok(()) => Ok(Ok(())),
494 Err(ExecutionError::UnauthorizedApplication(_)) => {
495 Ok(Err(CloseChainError::NotPermitted))
496 }
497 Err(error) => Err(RuntimeError::Custom(error.into())),
498 }
499 }
500
501 fn change_application_permissions(
504 caller: &mut Caller,
505 application_permissions: ApplicationPermissions,
506 ) -> Result<Result<(), ChangeApplicationPermissionsError>, RuntimeError> {
507 match caller
508 .user_data_mut()
509 .runtime
510 .change_application_permissions(application_permissions)
511 {
512 Ok(()) => Ok(Ok(())),
513 Err(ExecutionError::UnauthorizedApplication(_)) => {
514 Ok(Err(ChangeApplicationPermissionsError::NotPermitted))
515 }
516 Err(error) => Err(RuntimeError::Custom(error.into())),
517 }
518 }
519
520 fn create_application(
523 caller: &mut Caller,
524 module_id: ModuleId,
525 parameters: Vec<u8>,
526 argument: Vec<u8>,
527 required_application_ids: Vec<ApplicationId>,
528 ) -> Result<ApplicationId, RuntimeError> {
529 caller
530 .user_data_mut()
531 .runtime
532 .create_application(module_id, parameters, argument, required_application_ids)
533 .map_err(|error| RuntimeError::Custom(error.into()))
534 }
535
536 fn create_data_blob(caller: &mut Caller, bytes: Vec<u8>) -> Result<BlobId, RuntimeError> {
538 caller
539 .user_data_mut()
540 .runtime
541 .create_data_blob(bytes)
542 .map_err(|error| RuntimeError::Custom(error.into()))
543 }
544
545 fn publish_module(
547 caller: &mut Caller,
548 contract: Bytecode,
549 service: Bytecode,
550 vm_runtime: VmRuntime,
551 ) -> Result<ModuleId, RuntimeError> {
552 caller
553 .user_data_mut()
554 .runtime
555 .publish_module(contract, service, vm_runtime)
556 .map_err(|error| RuntimeError::Custom(error.into()))
557 }
558
559 fn try_call_application(
561 caller: &mut Caller,
562 authenticated: bool,
563 callee_id: ApplicationId,
564 argument: Vec<u8>,
565 ) -> Result<Vec<u8>, RuntimeError> {
566 caller
567 .user_data_mut()
568 .runtime
569 .try_call_application(authenticated, callee_id, argument)
570 .map_err(|error| RuntimeError::Custom(error.into()))
571 }
572
573 fn emit(caller: &mut Caller, name: StreamName, value: Vec<u8>) -> Result<u32, RuntimeError> {
575 caller
576 .user_data_mut()
577 .runtime
578 .emit(name, value)
579 .map_err(|error| RuntimeError::Custom(error.into()))
580 }
581
582 fn read_event(
586 caller: &mut Caller,
587 chain_id: ChainId,
588 name: StreamName,
589 index: u32,
590 ) -> Result<Vec<u8>, RuntimeError> {
591 caller
592 .user_data_mut()
593 .runtime
594 .read_event(chain_id, name, index)
595 .map_err(|error| RuntimeError::Custom(error.into()))
596 }
597
598 fn subscribe_to_events(
600 caller: &mut Caller,
601 chain_id: ChainId,
602 application_id: ApplicationId,
603 name: StreamName,
604 ) -> Result<(), RuntimeError> {
605 caller
606 .user_data_mut()
607 .runtime
608 .subscribe_to_events(chain_id, application_id, name)
609 .map_err(|error| RuntimeError::Custom(error.into()))
610 }
611
612 fn unsubscribe_from_events(
614 caller: &mut Caller,
615 chain_id: ChainId,
616 application_id: ApplicationId,
617 name: StreamName,
618 ) -> Result<(), RuntimeError> {
619 caller
620 .user_data_mut()
621 .runtime
622 .unsubscribe_from_events(chain_id, application_id, name)
623 .map_err(|error| RuntimeError::Custom(error.into()))
624 }
625
626 fn query_service(
628 caller: &mut Caller,
629 application_id: ApplicationId,
630 query: Vec<u8>,
631 ) -> Result<Vec<u8>, RuntimeError> {
632 caller
633 .user_data_mut()
634 .runtime
635 .query_service(application_id, query)
636 .map_err(|error| RuntimeError::Custom(error.into()))
637 }
638
639 fn consume_fuel(caller: &mut Caller, fuel: u64) -> Result<(), RuntimeError> {
644 caller
645 .user_data_mut()
646 .runtime_mut()
647 .consume_fuel(fuel, VmRuntime::Wasm)
648 .map_err(|e| RuntimeError::Custom(e.into()))
649 }
650
651 fn validation_round(caller: &mut Caller) -> Result<Option<u32>, RuntimeError> {
653 caller
654 .user_data_mut()
655 .runtime_mut()
656 .validation_round()
657 .map_err(|error| RuntimeError::Custom(error.into()))
658 }
659
660 fn write_batch(
662 caller: &mut Caller,
663 operations: Vec<WriteOperation>,
664 ) -> Result<(), RuntimeError> {
665 caller
666 .user_data_mut()
667 .runtime_mut()
668 .write_batch(Batch { operations })
669 .map_err(|error| RuntimeError::Custom(error.into()))
670 }
671}
672
673#[derive(Default)]
675pub struct ServiceRuntimeApi<Caller>(PhantomData<Caller>);
676
677#[wit_export(package = "linera:app")]
678impl<Caller, Runtime> ServiceRuntimeApi<Caller>
679where
680 Caller: Instance<UserData = RuntimeApiData<Runtime>>,
681 Runtime: ServiceRuntime + 'static,
682{
683 fn schedule_operation(caller: &mut Caller, operation: Vec<u8>) -> Result<(), RuntimeError> {
685 caller
686 .user_data_mut()
687 .runtime
688 .schedule_operation(operation)
689 .map_err(|error| RuntimeError::Custom(error.into()))
690 }
691
692 fn try_query_application(
694 caller: &mut Caller,
695 application: ApplicationId,
696 argument: Vec<u8>,
697 ) -> Result<Vec<u8>, RuntimeError> {
698 caller
699 .user_data_mut()
700 .runtime
701 .try_query_application(application, argument)
702 .map_err(|error| RuntimeError::Custom(error.into()))
703 }
704
705 fn check_execution_time(caller: &mut Caller, _fuel_consumed: u64) -> Result<(), RuntimeError> {
710 caller
711 .user_data_mut()
712 .runtime_mut()
713 .check_execution_time()
714 .map_err(|error| RuntimeError::Custom(error.into()))
715 }
716}