linera_sdk/contract/
mod.rs1mod conversions_from_wit;
7mod conversions_to_wit;
8#[cfg(not(with_testing))]
9mod runtime;
10#[cfg(with_testing)]
11mod test_runtime;
12#[doc(hidden)]
13pub mod wit;
14
15#[cfg(not(with_testing))]
16pub use self::runtime::ContractRuntime;
17#[cfg(with_testing)]
18pub use self::test_runtime::MockContractRuntime;
19#[doc(hidden)]
20pub use self::wit::export_contract;
21use crate::{log::ContractLogger, util::BlockingWait};
22
23#[cfg(with_testing)]
25pub type ContractRuntime<Application> = MockContractRuntime<Application>;
26
27#[macro_export]
33macro_rules! contract {
34 ($contract:ident) => {
35 #[doc(hidden)]
36 static mut CONTRACT: Option<$contract> = None;
37
38 $crate::export_contract!($contract with_types_in $crate::contract::wit);
40
41 impl $crate::contract::wit::exports::linera::app::contract_entrypoints::Guest
43 for $contract
44 {
45 fn instantiate(argument: Vec<u8>) {
46 use $crate::util::BlockingWait as _;
47 $crate::contract::run_async_entrypoint::<$contract, _, _>(
48 unsafe { &mut CONTRACT },
49 move |contract| {
50 let argument = $crate::serde_json::from_slice(&argument)
51 .unwrap_or_else(|_| panic!("Failed to deserialize instantiation argument {argument:?}"));
52
53 contract.instantiate(argument).blocking_wait()
54 },
55 )
56 }
57
58 fn execute_operation(operation: Vec<u8>) -> Vec<u8> {
59 use $crate::util::BlockingWait as _;
60 $crate::contract::run_async_entrypoint::<$contract, _, _>(
61 unsafe { &mut CONTRACT },
62 move |contract| {
63 let operation = <$contract as $crate::abi::ContractAbi>::deserialize_operation(operation)
64 .expect("Failed to deserialize `Operation` in execute_operation");
65
66 let response = contract.execute_operation(operation).blocking_wait();
67
68 <$contract as $crate::abi::ContractAbi>::serialize_response(response)
69 .expect("Failed to serialize `Response` in execute_operation")
70 },
71 )
72 }
73
74 fn execute_message(message: Vec<u8>) {
75 use $crate::util::BlockingWait as _;
76 $crate::contract::run_async_entrypoint::<$contract, _, _>(
77 unsafe { &mut CONTRACT },
78 move |contract| {
79 let message: <$contract as $crate::Contract>::Message =
80 $crate::bcs::from_bytes(&message)
81 .expect("Failed to deserialize message");
82
83 contract.execute_message(message).blocking_wait()
84 },
85 )
86 }
87
88 fn process_streams(updates: Vec<
89 $crate::contract::wit::exports::linera::app::contract_entrypoints::StreamUpdate,
90 >) {
91 use $crate::util::BlockingWait as _;
92 $crate::contract::run_async_entrypoint::<$contract, _, _>(
93 unsafe { &mut CONTRACT },
94 move |contract| {
95 let updates = updates.into_iter().map(Into::into).collect();
96 contract.process_streams(updates).blocking_wait()
97 },
98 )
99 }
100
101 fn finalize() {
102 use $crate::util::BlockingWait as _;
103
104 let Some(contract) = (unsafe { CONTRACT.take() }) else {
105 $crate::ContractLogger::install();
106 panic!("Calling `store` on a `Contract` instance that wasn't loaded");
107 };
108
109 contract.store().blocking_wait();
110 }
111 }
112
113 #[cfg(not(target_arch = "wasm32"))]
116 fn main() {}
117 };
118}
119
120pub fn run_async_entrypoint<Contract, Output, RawOutput>(
123 contract: &mut Option<Contract>,
124 entrypoint: impl FnOnce(&mut Contract) -> Output + Send,
125) -> RawOutput
126where
127 Contract: crate::Contract,
128 Output: Into<RawOutput> + Send + 'static,
129{
130 ContractLogger::install();
131
132 let contract =
133 contract.get_or_insert_with(|| Contract::load(ContractRuntime::new()).blocking_wait());
134
135 entrypoint(contract).into()
136}