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;