ab_contracts_macros/lib.rs
1//! Macros for contracts
2#![no_std]
3
4#[doc(hidden)]
5pub mod __private;
6
7/// `#[contract]` macro to derive contract implementation.
8///
9/// This macro is supposed to be applied to an implementation of the struct that in turn
10/// implements [`IoType`] trait. [`IoType`] is most commonly obtained by deriving
11/// [`TrivialType`] ([`IoType`] is implemented for all types that implement [`TrivialType`]).
12///
13/// `#[contract]` macro will process *public* methods annotated with the following attributes:
14/// * `#[init]` - a method that can be called to produce an initial state of the contract,
15/// called once during contacts lifetime
16/// * `#[update]` - a method that can read and/or modify state and/or slots of the contact;
17/// might be called by user transaction directly or by another contract
18/// * `#[view]` - a method that can only read blockchain data, can read state or slots of the
19/// contract, but can't modify their contents
20///
21/// Each argument (except `self`) of these methods has to be annotated with one of the
22/// following attributes (must be in this order):
23/// * `#[env]` - an environment variable, used to access ephemeral execution environment, call
24/// methods on other contracts, etc.
25/// * `#[tmp]` - a temporary ephemeral value to store auxiliary data while processing a
26/// transaction
27/// * `#[slot]` - a slot corresponding to this contract
28/// * `#[input]` - a method input coming from user transaction or invocation from another
29/// contract
30/// * `#[output]` - a method output serving as an alternative to returning values from a
31/// function directly, useful to reduce stack usage
32///
33/// # For struct implementation
34///
35/// ## #\[init]
36///
37/// Initializer's purpose is to produce the initial state of the contract.
38///
39/// This method type supports the following arguments (must be in this order):
40/// * `#[env]` read-only and read-write
41/// * `#[tmp]` read-only and read-write
42/// * `#[slot]` read-only and read-write
43/// * `#[input]`
44/// * `#[output]`
45///
46/// `self` argument is not supported in any way in this context since the state of the contract
47/// is just being created.
48///
49/// ## #\[update]
50///
51/// Generic method contract that can both update the contract's own state and contents of
52/// slots.
53///
54/// This method type supports the following arguments (must be in this order):
55/// * `&self` or `&mut self` depending on whether state reads and/or modification are required
56/// * `#[env]` read-only and read-write
57/// * `#[tmp]` read-only and read-write
58/// * `#[slot]` read-only and read-write
59/// * `#[input]`
60/// * `#[output]`
61///
62/// ## #\[view]
63///
64/// Similar to `#[update]`, but can only access read-only view of the state and slots, can be
65/// called outside of the block context and can only call other `#[view]` methods.
66///
67/// This method type supports the following arguments (must be in this order):
68/// * `&self`
69/// * `#[env]` read-only
70/// * `#[slot]` read-only
71/// * `#[input]`
72/// * `#[output]`
73///
74/// # For trait definition and trait implementation
75///
76/// ## #\[update]
77///
78/// Generic method contract that can (in case of trait indirectly) both update the contract's
79/// own state and contents of slots.
80///
81/// This method type supports the following arguments in the trait context (must be in this
82/// order):
83/// * `#[env]` read-only and read-write
84/// * `#[input]`
85/// * `#[output]`
86///
87/// ## #\[view]
88///
89/// Similar to `#[update]`, but can only access (in case of trait indirectly) read-only view of
90/// the state and slots, can be called outside of the block context and can only call other
91/// `#[view]` methods.
92///
93/// This method type supports the following arguments in the trait context (must be in this
94/// order):
95/// * `#[env]` read-only
96/// * `#[input]`
97/// * `#[output]`
98///
99/// # Generated code
100///
101/// This macro will produce several key outputs:
102/// * [`Contract`] trait implementation (for struct implementation)
103/// * FFI function for every method, which can be used by the host to call into the guest
104/// environment (for struct and trait implementation)
105/// * `InternalArgs` struct corresponding to each method, used as its sole input for FFI
106/// function
107/// * Struct implementing [`ExternalArgs`] trait for each method, usable by other contracts to
108/// call into this contract through the host, host will interpret it based on metadata and
109/// generate `InternalArgs` (for struct and trait implementation, trait definitions)
110/// * Extension trait (for struct and trait implementation) that simplifies interaction with
111/// host and removes the need to construct [`ExternalArgs`] manually, providing nice strongly
112/// typed methods instead, implemented for [`Env`] struct (for struct and trait
113/// implementation, trait definitions)
114/// * Metadata as defined in [`ContractMetadataKind`] stored in the `ab-contract-metadata` link
115/// section when compiled with `guest` feature enabled (for method, struct, and trait
116/// implementation)
117///
118/// ## [`Contract`] trait implementation
119///
120/// [`Contract`] trait is required by a few other components in the system, so it is
121/// automatically implemented by the macro, see trait details.
122///
123/// ## FFI function
124///
125/// Macro generates an FFI function with C ABI that looks like this:
126/// ```ignore
127/// #[cfg_attr(feature = "guest", unsafe(no_mangle))]
128/// pub unsafe extern "C" fn {prefix}_{method}(
129/// args: NonNull<InternalArgs>,
130/// ) -> ExitCode {
131/// // ...
132/// }
133/// ```
134///
135/// Where `{prefix}` is derived from struct or trait name and `{method}` is the original method
136/// name from struct or trait implementation.
137///
138/// Example with struct implementation:
139/// ```ignore
140/// // This
141/// #[contract]
142/// impl Example {
143/// #[view]
144/// pub fn hello() {}
145/// }
146///
147/// // Will generate this
148/// #[cfg_attr(feature = "guest", unsafe(no_mangle))]
149/// pub unsafe extern "C" fn example_hello(
150/// args: NonNull<InternalArgs>,
151/// ) -> ExitCode {
152/// // ...
153/// }
154/// ```
155///
156/// Example with trait implementation:
157/// ```ignore
158/// // This
159/// #[contract]
160/// impl Fungible for Token {
161/// #[view]
162/// pub fn balance(#[slot] address: &Address) -> Balance {}
163/// }
164///
165/// // Will generate this
166/// #[cfg_attr(feature = "guest", unsafe(no_mangle))]
167/// pub unsafe extern "C" fn fungible_balance(
168/// args: NonNull<InternalArgs>,
169/// ) -> ExitCode {
170/// // ...
171/// }
172/// ```
173///
174/// These generated functions are public and available in generated submodules, but there
175/// should generally be no need to call them directly.
176///
177/// ## `InternalArgs` struct
178///
179/// `InternalArgs` is generated for each method and is used as input to the above FFI
180/// functions. Its fields are generated based on function arguments, processing them in the
181/// same order as in function signature. It is possible for the host to build this data
182/// structure dynamically using available contact metadata.
183///
184/// All fields in the data structure are pointers, some are read-only, some can be written to
185/// if changes need to be communicated back to the host. `read-only` here means that the host
186/// will not read the value, even if the contract modifies it.
187///
188/// ### `&self`
189///
190/// `&self` is a read-only state of the contract and generates three fields, all of which are
191/// read-only:
192/// ```ignore
193/// #[repr(C)]
194/// pub struct InternalArgs {
195/// pub state_ptr: NonNull<<StructName as IoType>::PointerType>,
196/// pub state_size: u32,
197/// pub state_capacity: u32,
198/// // ...
199/// }
200/// ```
201///
202/// This allows a contract to read the current state of the contract.
203///
204/// ### `&mut self`
205///
206/// `&mut self` is a read-write state of the contract and generates three fields, `state_ptr`
207/// and `state_size` can be written to, while `state_capacity` is read-only:
208/// ```ignore
209/// #[repr(C)]
210/// pub struct InternalArgs {
211/// pub state_ptr: NonNull<<StructName as IoType>::PointerType>,
212/// pub state_size: u32,
213/// pub state_capacity: u32,
214/// // ...
215/// }
216/// ```
217///
218/// This allows a contract to not only read, but also change the current state of the contract.
219/// `state_capacity` is defined by both the type used and the size of the value used (whichever
220/// is bigger in the case of variable-sized types) and corresponds to the amount of memory that
221/// host allocated for the guest behind `state_ptr`. In the case of variable-sized types, guest
222/// can replace`state_ptr` with a pointer to a guest-allocated region of memory that the host
223/// must read updated value from. This is helpful in case an increase of the value size beyond
224/// allocated capacity is needed.
225///
226/// ### `#[env] env: &Env`
227///
228/// `#[env] env: &Env` is for accessing an ephemeral environment with method calls restricted
229/// to `#[view]`. Since this is a system-provided data structure with a known layout, only
230/// read-only pointer field is generated:
231/// ```ignore
232/// #[repr(C)]
233/// pub struct InternalArgs<'internal_args> {
234/// // ...
235/// pub env_ptr: NonNull<Env<'internal_args>>,
236/// // ...
237/// }
238/// ```
239///
240/// ### `#[env] env: &mut Env`
241///
242/// `#[env] env: &Env` is for accessing ephemeral environment without method calls
243/// restrictions. Since this is a system-provided data structure with a known layout, only
244/// read-write pointer field is generated:
245/// ```ignore
246/// #[repr(C)]
247/// pub struct InternalArgs<'internal_args> {
248/// // ...
249/// pub env_ptr: NonNull<Env<'internal_args>>,
250/// // ...
251/// }
252/// ```
253///
254/// ### `#[tmp] tmp: &MaybeData<Tmp>`
255///
256/// `#[tmp] tmp: &MaybeData<Tmp>` is for accessing ephemeral value with auxiliary data and
257/// generates two fields, both of which are read-only:
258/// ```ignore
259/// #[repr(C)]
260/// pub struct InternalArgs {
261/// // ...
262/// pub tmp_ptr: NonNull<
263/// <
264/// <StructName as Contract>::Tmp as IoType
265/// >::PointerType,
266/// >,
267/// pub tmp_size: NonNull<u32>,
268/// // ...
269/// }
270/// ```
271///
272/// This allows a contract to read the current ephemeral value of the contract.
273///
274/// ### `#[tmp] tmp: &mut MaybeData<Tmp>`
275///
276/// `#[tmp] tmp: &MaybeData<Tmp>` is for accessing ephemeral value with auxiliary data and
277/// generates three fields, `tmp_ptr` and `tmp_size` can be written to, while `tmp_capacity` is
278/// read-only:
279/// ```ignore
280/// #[repr(C)]
281/// pub struct InternalArgs {
282/// // ...
283/// pub tmp_ptr: NonNull<
284/// <
285/// <StructName as Contract>::Tmp as IoType
286/// >::PointerType,
287/// >,
288/// pub tmp_size: u32,
289/// pub tmp_capacity: u32,
290/// // ...
291/// }
292/// ```
293///
294/// This allows a contract to not only read, but also change the ephemeral value of the
295/// contract. `tmp_capacity` is defined by both the type used and the size of the value used
296/// (whichever is bigger in the case of variable-sized types) and corresponds to the amount of
297/// memory that host allocated for the guest behind `tmp_ptr`. In the case of variable-sized
298/// types, guest can replace`tmp_ptr` with a pointer to a guest-allocated region of memory that
299/// the host must read updated value from. This is helpful in case an increase of the value
300/// size beyond allocated capacity is needed.
301///
302/// ### `#[slot] slot: &MaybeData<Slot>` and `#[slot] (address, slot): (&Address, &MaybeData<Slot>)`
303///
304/// `#[slot] slot: &MaybeData<Slot>` and its variant with explicit address argument is for
305/// accessing slot data (that corresponds to an optional `address` argument) and generates four
306/// fields, all of which are read-only:
307/// ```ignore
308/// #[repr(C)]
309/// pub struct InternalArgs {
310/// // ...
311/// pub slot_address_ptr: NonNull<Address>,
312/// pub slot_ptr: NonNull<
313/// <
314/// <StructName as Contract>::Slot as IoType
315/// >::PointerType,
316/// >,
317/// pub slot_size: u32,
318/// pub slot_capacity: u32,
319/// // ...
320/// }
321/// ```
322///
323/// This allows a contract to read slot data.
324///
325/// ### `#[slot] slot: &mut MaybeData<Slot>` and `#[slot] (address, slot): (&Address, &mut MaybeData<Slot>)`
326///
327/// `#[slot] slot: &mut MaybeData<Slot>` and its variant with explicit address argument are for
328/// accessing slot data (that corresponds to optional `address` argument) and generates four
329/// fields, `slot_ptr` and `slot_size` can be written to, while `slot_address_ptr` and
330/// `slot_capacity` are read-only:
331/// ```ignore
332/// #[repr(C)]
333/// pub struct InternalArgs {
334/// // ...
335/// pub slot_address_ptr: NonNull<Address>,
336/// pub slot_ptr: NonNull<
337/// <
338/// <StructName as Contract>::Slot as IoType
339/// >::PointerType,
340/// >,
341/// pub slot_size: u32,
342/// pub slot_capacity: u32,
343/// // ...
344/// }
345/// ```
346///
347/// This allows a contract to not only read, but also change slot data.
348/// `slot_capacity` is defined by both the type used and the size of the value used (whichever
349/// is bigger in the case of variable-sized types) and corresponds to the amount of memory that
350/// host allocated for the guest behind `slot_ptr`. In the case of variable-sized types,
351/// guest can replace`slot_ptr` with a pointer to a guest-allocated region of memory that the
352/// host must read updated value from. This is helpful in case an increase of the value size
353/// beyond allocated capacity is needed.
354///
355/// Slot changes done by the method call will not be persisted if it returns an error.
356///
357/// ### `#[input] input: &InputValue`
358///
359/// `#[input] input: &InputValue` is a read-only input to the contract call and generates three
360/// fields, both of which are read-only:
361/// ```ignore
362/// #[repr(C)]
363/// pub struct InternalArgs {
364/// // ...
365/// pub input_ptr: NonNull<<InputValue as IoType>::PointerType>,
366/// pub input_size: u32,
367/// pub input_capacity: u32,
368/// // ...
369/// }
370/// ```
371///
372/// ### `#[output] output: &mut MaybeData<OutputValue>`
373///
374/// `#[output] output: &mut MaybeData<OutputValue>` and regular return value is a read-write
375/// output to the contract call and generates three fields, `output_ptr` and `output_size` can
376/// be written to, while `output_capacity` is read-only:
377/// ```ignore
378/// #[repr(C)]
379/// pub struct InternalArgs {
380/// // ...
381/// pub output_ptr: NonNull<<OutputValue as IoType>::PointerType>,
382/// pub output_size: u32,
383/// pub output_capacity: u32,
384/// // ...
385/// }
386/// ```
387///
388/// Initially output is initialized by the caller (typically empty), but contract can write
389/// something useful there and written value will be propagated back to the caller to observe.
390/// `output_ptr` pointer *must not be changed* as the host will not follow it to the new
391/// address, the output size is fully constrained by capacity specified in `output_capacity`.
392/// The only exception is the last `#[output]` of `#[init]` method, which is the contract's
393/// initial state. In this case, its pointer can be changed to point to a different memory
394/// location and not being limited by `result_capacity` allocation from the host.
395///
396/// `#[output]` may be used as an alternative to `-> ReturnValue` and
397/// `-> Result<ReturnValue, ContractError>` in case the data structure is large and allocation
398/// on the stack is undesirable, which is especially helpful in case of a variable-sized
399/// contract state.
400///
401/// ### `-> ReturnValue` and `-> Result<ReturnValue, ContractError>`
402///
403/// Return values (wrapped in `Result` or not) are only possible with [`TrivialType`] types,
404/// hence they don't need size and capacity as separate fields:
405/// ```ignore
406/// #[repr(C)]
407/// pub struct InternalArgs {
408/// // ...
409/// pub ok_result_ptr: NonNull<ReturnValue>,
410/// }
411/// ```
412///
413/// NOTE: In case `ReturnValue` in `-> ReturnValue` or `-> Result<ReturnValue, ContractError>`
414/// is `()`, it will be omitted in `InternalArgs`.
415///
416///
417/// ## [`ExternalArgs`] implementation
418///
419/// Macro generates a struct that implements [`ExternalArgs`] for each method that other
420/// contracts give to the host when they want to call into another (or even the same) contract.
421///
422/// Here is an example with struct implementation, but it works the same way with trait
423/// definition and implementation too:
424/// ```ignore
425/// // This
426/// #[contract]
427/// impl Example {
428/// #[view]
429/// pub fn hello() {}
430/// }
431///
432/// #[repr(C)]
433/// pub struct ExampleHelloArgs {
434/// // ...
435/// }
436///
437/// #[automatically_derived]
438/// unsafe impl ExternalArgs for ExampleHelloArgs {
439/// // ...
440/// }
441///
442/// impl ExternalArgs {
443/// pub fn new(
444/// // ...
445/// ) -> Self {
446/// // ...
447/// }
448/// }
449/// ```
450///
451/// Struct name if generated by concatenating struct or trait name on which name was generated,
452/// method name, and `Args` suffix, which is done to make it more convenient to use externally.
453///
454/// `&self`, `&mut self`, `#[env]` and `#[tmp]` arguments of the method are controlled fully by
455/// the host and not present in `ExternalArgs`.
456///
457/// `ExternalArgs::new()` method is generated for convenient construction of the instance,
458/// though in most cases [Extension trait] is used with a more convenient API.
459///
460/// [Extension trait]: #extension-trait
461///
462/// ### `#[slot]`
463///
464/// Each `#[slot]` argument in `ExternalArgs` is represented by a single read-only address
465/// pointer:
466/// ```ignore
467/// #[repr(C)]
468/// pub struct ExternalArgs {
469/// // ...
470/// pub slot_ptr: NonNull<Address>,
471/// // ...
472/// }
473/// ```
474///
475/// ### `#[input]`
476///
477/// Each `#[input]` argument in `ExternalArgs` is represented by three read-only fields,
478/// a pointer to data, and size + capacity:
479/// ```ignore
480/// #[repr(C)]
481/// pub struct ExternalArgs {
482/// // ...
483/// pub input_ptr: NonNull<<InputValue as IoType>::PointerType>,
484/// pub input_size: u32,
485/// pub input_capacity: u32,
486/// // ...
487/// }
488/// ```
489///
490/// ### `#[output]`, `-> ReturnValue` and `-> Result<ReturnValue, ContractError>`
491///
492/// Each `#[output]` argument in `ExternalArgs` is represented by three fields, `output_ptr`
493/// and `output_size` can be written to, while `output_capacity` is read-only:
494/// ```ignore
495/// #[repr(C)]
496/// pub struct ExternalArgs {
497/// // ...
498/// pub output_ptr: NonNull<<OutputValue as IoType>::PointerType>,
499/// pub output_size: u32,
500/// pub output_capacity: u32,
501/// // ...
502/// }
503/// ```
504///
505/// Each return value is represented by just a pointer since return type is [`TrivialType`] and
506/// don't need separate size and capacity fields:
507/// ```ignore
508/// #[repr(C)]
509/// pub struct ExternalArgs {
510/// // ...
511/// pub ok_result_ptr: NonNull<ReturnValue>,
512/// }
513/// ```
514///
515/// The arguments are omitted in `ExternalArgs` for the last `#[output]` or `ReturnValue` when
516/// method is `#[init]` or when `ReturnValue` is `()` in other cases. For `#[init]` method's
517/// return value is the contract's initial state and is processed by the execution environment
518/// itself. When `ReturnValue` is `()`, then there is no point in having a pointer for it.
519///
520/// The host will propagate the current value that `output_size` points to to the caller, so
521/// that the callee can both read and write to it.
522///
523/// ## Extension trait
524///
525/// Extension trait is just a convenient wrapper, whose safe methods take strongly typed
526/// arguments, construct `ExternalArgs` while respecting Rust safety invariants, and calls
527/// [`Env::call()`] with it. Extension trait usage is not mandatory, but it does make method
528/// calls much more convenient in most simple cases.
529///
530/// Generated methods reflect `ExternalArgs` fields with just context (except when calling
531/// `#[view]` method where context is not applicable), and the address of the contract being
532/// called is added at the beginning:
533/// ```ignore
534/// // This
535/// impl Token {
536/// // ...
537///
538/// #[view]
539/// pub fn balance(#[slot] target: &MaybeData<Slot>) -> Balance {
540/// // ...
541/// }
542///
543/// #[update]
544/// pub fn transfer(
545/// #[env] env: &mut Env<'_>,
546/// #[slot] (from_address, from): (&Address, &mut MaybeData<Slot>),
547/// #[slot] to: &mut MaybeData<Slot>,
548/// #[input] &amount: &Balance,
549/// ) -> Result<(), ContractError> {
550/// // ...
551/// }
552/// }
553///
554/// // Will generate this
555/// pub trait TokenExt {
556/// fn balance(
557/// &self,
558/// contract: &Address,
559/// target: &Address,
560/// ) -> Result<Balance, ContractError>;
561///
562/// fn transfer(
563/// self: &&mut Self,
564/// method_context: &MethodContext,
565/// contract: &Address,
566/// from: &Address,
567/// to: &Address,
568/// amount: &Balance,
569/// ) -> Result<(), ContractError>;
570/// }
571///
572/// impl TokenExt for Env {
573/// fn balance(
574/// &self,
575/// contract: &Address,
576/// target: &Address,
577/// ) -> Result<Balance, ContractError> {
578/// // ...
579/// }
580///
581/// fn transfer(
582/// self: &&mut Self,
583/// method_context: &MethodContext,
584/// contract: &Address,
585/// from: &Address,
586/// to: &Address,
587/// amount: &Balance,
588/// ) -> Result<(), ContractError> {
589/// // ...
590/// }
591/// }
592/// ```
593///
594/// The name of the extension trait is created as struct or trait name followed by `Ext`
595/// suffix.
596///
597/// ## Metadata
598///
599/// There are several places where metadata is being generated, see [`ContractMetadataKind`]
600/// for details.
601///
602/// First, the `#[contract]` macro generates a public `METADATA` constant for each method
603/// individually.
604///
605/// Second, for each trait that contract can implement `#[contract]` macro generates an
606/// associated constant `METADATA` that essentially aggregates metadata of all annotated
607/// methods.
608///
609/// Third, [`Contract`] trait implementation generated by `#[contract]` macro contains
610/// `MAIN_CONTRACT_METADATA` associated constant, which is similar in nature to `METADATA`
611/// constant for traits described above.
612///
613/// Lastly, for the whole contract as a project, both trait and contract metadata is
614/// concatenated and stored in the `ab-contract-metadata` link section that can later be
615/// inspected externally to understand everything about the contract's interfaces,
616/// auto-generate UI, etc.
617///
618/// [`Contract`]: ab_contracts_common::Contract
619/// [`TrivialType`]: ab_io_type::trivial_type::TrivialType
620/// [`IoType`]: ab_io_type::IoType
621/// [`ExternalArgs`]: ab_contracts_common::method::ExternalArgs
622/// [`Env`]: ab_contracts_common::env::Env
623/// [`Env::call()`]: ab_contracts_common::env::Env::call()
624/// [`ContractMetadataKind`]: ab_contracts_common::metadata::ContractMetadataKind
625pub use ab_contracts_macros_impl::contract;