ab_contracts_macros/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
//! Macros for contracts
#[doc(hidden)]
pub mod __private;

// TODO: Should size + capacity be a single tuple struct that can be passed down as a single
//  pointer?
/// `#[contract]` macro to derive smart contract implementation.
///
/// This macro is supposed to be applied to an implementation of the struct that in turn implements
/// [`IoType`] trait. [`IoType`] is most commonly obtained by deriving [`TrivialType`] ([`IoType`]
/// is implemented for all types that implement [`TrivialType`]).
///
/// `#[contract]` macro will process *public* methods annotated with the following attributes:
/// * `#[init]` - method that can be called to produce an initial state of the contract,
///   called once during contacts lifetime
/// * `#[update]` - method that can read and/or modify state and/or slots of the contact, may be
///   called by user transaction directly or by another contract
/// * `#[view]` - method that can only read blockchain data, can read state or slots of the
///   contract, but can't modify their contents
///
/// Each argument (except `self`) of these methods has to be annotated with one of the following
/// attributes (must be in this order):
/// * `#[env]` - environment variable, used to access ephemeral execution environment, call methods
///   on other contracts, etc.
/// * `#[tmp]` - temporary ephemeral value to store auxiliary data while processing a transaction
/// * `#[slot]` - slot corresponding to this contract
/// * `#[input]` - method input coming from user transaction or invocation from another contract
/// * `#[output]` - method output
/// * `#[result]` - a single optional method result as an alternative to returning values from a
///   function directly, useful to reduce stack usage
///
/// # For struct implementation
///
/// ## #\[init]
///
/// Initializer's purpose is to produce the initial state of the contract.
///
/// The following arguments are supported by this method (must be in this order):
/// * `#[env]` read-only and read-write
/// * `#[tmp]` read-only and read-write
/// * `#[slot]` read-only and read-write
/// * `#[input]`
/// * `#[output]`
/// * `#[result]`
///
/// `self` argument is not supported in any way in this context since the state of the contract is
/// just being created.
///
/// ## #\[update]
///
/// Generic method contract that can both update contract's own state and contents of slots.
///
/// The following arguments are supported by this method (must be in this order):
/// * `&self` or `&mut self` depending on whether state reads and/or modification are required
/// * `#[env]` read-only and read-write
/// * `#[tmp]` read-only and read-write
/// * `#[slot]` read-only and read-write
/// * `#[input]`
/// * `#[output]`
/// * `#[result]`
///
/// ## #\[view]
///
/// Similar to `#[update]`, but can only access read-only view of the state and slots, can be called
/// outside of block context and can only call other `#[view]` methods.
///
/// The following arguments are supported by this method (must be in this order):
/// * `&self`
/// * `#[env]` read-only
/// * `#[slot]` read-only
/// * `#[input]`
/// * `#[output]`
/// * `#[result]`
///
/// # For trait definition and trait implementation
///
/// ## #\[update]
///
/// Generic method contract that can (in case of trait indirectly) both update contract's own state
/// and contents of slots.
///
/// The following arguments are supported by this method in trait context (must be in this order):
/// * `#[env]` read-only and read-write
/// * `#[input]`
/// * `#[output]`
/// * `#[result]`
///
/// ## #\[view]
///
/// Similar to `#[update]`, but can only access (in case of trait indirectly) read-only view of the
/// state and slots, can be called outside of block context and can only call other `#[view]`
/// methods.
///
/// The following arguments are supported by this method in trait context (must be in this order):
/// * `#[env]` read-only
/// * `#[input]`
/// * `#[output]`
/// * `#[result]`
///
/// # Generated code
///
/// This macro will produce several key outputs:
/// * [`Contract`] trait implementation (for struct implementation)
/// * FFI function for every method, which can be used by the host to call into the guest
///   environment (for struct and trait implementation)
/// * `InternalArgs` struct corresponding to each method, used as its sole input for FFI function
/// * Struct implementing [`ExternalArgs`] trait for each method, usable by other contracts to call
///   into this contract through the host, host will interpret it based on metadata and generate
///   `InternalArgs` (for struct and trait implementation, trait definitions)
/// * Extension trait (for struct and trait implementation) that simplifies interaction with host
///   and removes the need to construct [`ExternalArgs`] manually, providing nice strongly typed
///   methods instead, implemented for [`Env`] struct (for struct and trait implementation, trait
///   definitions)
/// * Metadata as defined in [`ContractMetadataKind`] stored in `CONTRACT_METADATA` link section
///   when compiled with `guest` feature enabled (for method, struct and trait implementation)
///
/// ## [`Contract`] trait implementation
///
/// [`Contract`] trait is required by a few other components in the system, so it is automatically
/// implemented by the macro, see trait details.
///
/// ## FFI function
///
/// Macro generates FFI function with C ABI that looks like this:
/// ```ignore
/// #[cfg_attr(feature = "guest", unsafe(no_mangle))]
/// pub unsafe extern "C" fn {prefix}_{method}(
///     args: NonNull<InternalArgs>,
/// ) -> ExitCode {
///     // ...
/// }
/// ```
///
/// Where `{prefix}` is derived from struct or trait name and `{method}` is the original method name
/// from struct or trait implementation.
///
/// Example with struct implementation:
/// ```ignore
/// // This
/// #[contract]
/// impl Example {
///     #[view]
///     pub fn hello() {}
/// }
///
/// // Will generate this
/// #[cfg_attr(feature = "guest", unsafe(no_mangle))]
/// pub unsafe extern "C" fn example_hello(
///     args: NonNull<InternalArgs>,
/// ) -> ExitCode {
///     // ...
/// }
/// ```
///
/// Example with trait implementation:
/// ```ignore
/// // This
/// #[contract]
/// impl Fungible for Token {
///     #[view]
///     pub fn balance(#[slot] address: &Address) -> Balance {}
/// }
///
/// // Will generate this
/// #[cfg_attr(feature = "guest", unsafe(no_mangle))]
/// pub unsafe extern "C" fn fungible_balance(
///     args: NonNull<InternalArgs>,
/// ) -> ExitCode {
///     // ...
/// }
/// ```
///
/// These generated functions are public and available in generated submodules, but there should
/// generally be no need to call them directly.
///
/// ## `InternalArgs` struct
///
/// `InternalArgs` is generated for each method and is used as input to the above FFI functions. Its
/// fields are generated based on function arguments, processing them in the same order as in
/// function signature. It is possible for host to build this data structure dynamically using
/// available contact metadata.
///
/// All fields in the data structure are pointers, some are read-only, some can be written to if
/// changes need to be communicated back to the host.
///
/// ### `&self`
///
/// `&self` is a read-only state of the contract and generates two fields, both of which are
/// read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     pub state_ptr: NonNull<<StructName as IoType>::PointerType>,
///     pub state_size: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// This allows a contract to read the current state of the contract.
///
/// ### `&mut self`
///
/// `&mut self` is a read-write state of the contract and generates three fields, `state_ptr` and
/// `state_size` can be written to, while `state_capacity` is read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     pub state_ptr: NonNull<<StructName as IoType>::PointerType>,
///     pub state_size: *mut u32,
///     pub state_capacity: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// This allows a contract to not only read, but also change the current state of the contract.
/// `state_capacity` is defined by both the type used and the size of the value used (whichever is
/// bigger in case of a variable-sized types) and corresponds to the amount of memory that host
/// allocated for the guest behind `state_ptr`. In the case of a variable-sized types, guest can
/// replace`state_ptr` with a pointer to a guest-allocated region of memory that host must read
/// updated value from. This is helpful in case increase of the value size beyond allocated capacity
/// is needed.
///
/// ### `#[env] env: &Env`
///
/// `#[env] env: &Env` is for accessing ephemeral environment with method calls restricted to
/// `#[view]`. Since this is a system-provided data structure with known layout, only read-only
/// pointer field is generated:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     // ...
///     pub env_ptr: NonNull<Env>,
///     // ...
/// }
/// ```
///
/// ### `#[env] env: &mut Env`
///
/// `#[env] env: &Env` is for accessing ephemeral environment without method calls restrictions.
/// Since this is a system-provided data structure with known layout, only read-write pointer field
/// is generated:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     // ...
///     pub env_ptr: NonNull<Env>,
///     // ...
/// }
/// ```
///
/// ### `#[tmp] tmp: &MaybeData<Tmp>`
///
/// `#[tmp] tmp: &MaybeData<Tmp>` is for accessing ephemeral value with auxiliary data and generates
/// two fields, both of which are read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     // ...
///     pub tmp_ptr: NonNull<
///         <
///             <StructName as Contract>::Tmp as IoType
///         >::PointerType,
///     >,
///     pub tmp_size: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// This allows a contract to read the current ephemeral value of the contract.
///
/// ### `#[tmp] tmp: &mut MaybeData<Tmp>`
///
/// `#[tmp] tmp: &MaybeData<Tmp>` is for accessing ephemeral value with auxiliary data and generates
/// three fields, `tmp_ptr` and `tmp_size` can be written to, while `tmp_capacity` is read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     // ...
///     pub tmp_ptr: NonNull<
///         <
///             <StructName as Contract>::Tmp as IoType
///         >::PointerType,
///     >,
///     pub tmp_size: *mut u32,
///     pub tmp_capacity: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// This allows a contract to not only read, but also change the ephemeral value of the contract.
/// `tmp_capacity` is defined by both the type used and the size of the value used (whichever is
/// bigger in case of a variable-sized types) and corresponds to the amount of memory that host
/// allocated for the guest behind `tmp_ptr`. In the case of a variable-sized types, guest can
/// replace`tmp_ptr` with a pointer to a guest-allocated region of memory that host must read
/// updated value from. This is helpful in case increase of the value size beyond allocated capacity
/// is needed.
///
/// ### `#[slot] slot: &MaybeData<Slot>` and `#[slot] (address, slot): (&Address, &MaybeData<Slot>)`
///
/// `#[slot] slot: &MaybeData<Slot>` and its variant with explicit address argument are for
/// accessing slot data (that corresponds to optional `address` argument) and generates 3 fields,
/// all of which are read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     // ...
///     pub slot_address_ptr: NonNull<Address>,
///     pub slot_ptr: NonNull<
///         <
///             <StructName as Contract>::Slot as IoType
///         >::PointerType,
///     >,
///     pub slot_size: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// This allows a contract to read slot data.
///
/// ### `#[slot] slot: &mut MaybeData<Slot>` and
/// ### `#[slot] (address, slot): (&Address, &mut MaybeData<Slot>)`
///
/// `#[slot] slot: &mut MaybeData<Slot>` and its variant with explicit address argument are for
/// accessing slot data (that corresponds to optional `address` argument) and generates 4 fields,
/// `slot_ptr` and `slot_size` can be written to, while `slot_address_ptr` and `slot_capacity` are
/// read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     // ...
///     pub slot_address_ptr: NonNull<Address>,
///     pub slot_ptr: NonNull<
///         <
///             <StructName as Contract>::Slot as IoType
///         >::PointerType,
///     >,
///     pub slot_size: *mut u32,
///     pub slot_capacity: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// This allows a contract to not only read, but also change slot data.
/// `slot_capacity` is defined by both the type used and the size of the value used (whichever is
/// bigger in case of a variable-sized types) and corresponds to the amount of memory that host
/// allocated for the guest behind `slot_ptr`. In the case of a variable-sized types, guest can
/// replace`slot_ptr` with a pointer to a guest-allocated region of memory that host must read
/// updated value from. This is helpful in case increase of the value size beyond allocated capacity
/// is needed.
///
/// ### `#[input] input: &InputValue`
///
/// `#[input] input: &InputValue` is a read-only input to the contract call and generates two
/// fields, both of which are read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     // ...
///     pub input_ptr: NonNull<<InputValue as IoType>::PointerType>,
///     pub input_size: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// ### `#[output] output: &mut MaybeData<OutputValue>`
///
/// `#[output] output: &mut MaybeData<OutputValue>` is a read-write output to the contract call and
/// generates tree fields, `output_ptr` and `output_size` can be written to, while `output_capacity`
/// is read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     // ...
///     pub output_ptr: NonNull<<OutputValue as IoType>::PointerType>,
///     pub output_size: *mut u32,
///     pub output_capacity: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// Initially output is empty, but contract can write something useful there and written value will
/// be propagated back to the caller to observe. `output_ptr` pointer must not be changed as the
/// host will not follow it to the new address, the output size is fully constrained by capacity
/// specified in `output_capacity`.
///
/// ### `#[result] result: &mut MaybeData<ResultValue>` and `-> Result<ResultValue, ContractError>`
///
/// `#[result] result: &mut MaybeData<ResultValue>` and regular return type (only one of those can
/// be used at a time) is almost identical and has a very similar behavior to `#[output]`:
/// ```ignore
/// #[repr(C)]
/// pub struct InternalArgs {
///     // ...
///     pub result_ptr: NonNull<<ResultValue as IoType>::PointerType>,
///     pub result_size: *mut u32,
///     pub result_capacity: NonNull<u32>,
/// }
/// ```
///
/// `#[result]` is an alternative to `-> Result<ResultValue, ContractError>` in case the data
/// structure is large and allocation on the stack is undesirable, which is especially helpful in
/// case of a variable-sized contract state.
///
/// The only big difference from `#[output]` is that in case of `#[init]` method result will be
/// returning contract's initial state, in which case its pointer can be changed to point to a
/// different data structure and not being limited by `result_capacity` allocation from the host.
///
/// ## [`ExternalArgs`] implementation
///
/// Macro generates a struct that implements [`ExternalArgs`] for each method that other contracts
/// give to the host when they want to call into another (or even the same) contract.
///
/// Here is an example with struct implementation, but it works the same way with trait definition
/// and implementation too:
/// ```ignore
/// // This
/// #[contract]
/// impl Example {
///     #[view]
///     pub fn hello() {}
/// }
///
/// #[repr(C)]
/// pub struct ExampleHelloArgs {
///     // ...
/// }
///
/// #[automatically_derived]
/// unsafe impl ExternalArgs for ExampleHelloArgs {
///     // ...
/// }
/// ```
///
/// Struct name if generated by concatenating struct or trait name on which name wsa generated,
/// method name and `Args` suffix, which is done to make it more convenient to use externally.
///
/// `&self`, `&mut self`, `#[env]` and `#[tmp]` arguments of the method are controlled fully by the
/// host and not present in `ExternalArgs`.
///
/// ### `#[slot]`
///
/// Each `#[slot]` argument in `ExternalArgs` is represented by a single read-only address pointer:
/// ```ignore
/// #[repr(C)]
/// pub struct ExternalArgs {
///     // ...
///     pub slot_ptr: NonNull<Address>,
///     // ...
/// }
/// ```
///
/// ### `#[input]`
///
/// Each `#[input]` argument in `ExternalArgs` is represented by two read-only fields, pointer to
/// data and its size:
/// ```ignore
/// #[repr(C)]
/// pub struct ExternalArgs {
///     // ...
///     pub input_ptr: NonNull<<InputValue as IoType>::PointerType>,
///     pub input_size: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// ### `#[output]`
///
/// Each `#[output]` argument in `ExternalArgs` is represented by three fields, `output_ptr` and
/// `output_size` can be written to, while `output_capacity` is read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct ExternalArgs {
///     // ...
///     pub output_ptr: NonNull<<OutputValue as IoType>::PointerType>,
///     pub output_size: *mut u32,
///     pub output_capacity: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// ### `#[result]` and `-> Result<T, E>`
///
/// The result is present in `ExternalArgs` except when method is `#[init]` or the type is `()`. For
/// `#[init]` method's return value is contract's initial state and is processed by execution
/// environment itself. When the value is `()` then there is no point in having a pointer for it.
///
/// `#[result]` argument and `-> Result<T, E>` in `ExternalArgs` is represented by three fields,
/// `result_ptr` and `result_size` can be written to, while `result_capacity` is read-only:
/// ```ignore
/// #[repr(C)]
/// pub struct ExternalArgs {
///     // ...
///     pub result_ptr: NonNull<<ResultValue as IoType>::PointerType>,
///     pub result_size: *mut u32,
///     pub result_capacity: NonNull<u32>,
///     // ...
/// }
/// ```
///
/// ## Extension trait
///
/// Extension trait is just a convenient wrapper, whose safe methods take strongly typed arguments,
/// construct `ExternalArgs` while respecting Rust safety invariants and calls [`Env::call()`] with
/// it. Extension trait usage is not mandatory, but it does make method calls much more convenient
/// in most simple cases.
///
/// Generated methods reflect `ExternalArgs` fields with just context (except when calling `#[view]`
/// method where context is not applicable) and the address of the contract being called added at
/// the beginning:
/// ```ignore
/// // This
/// impl Token {
///     // ...
///
///     #[view]
///     pub fn balance(#[slot] target: &MaybeData<Slot>) -> Balance {
///         // ...
///     }
///
///     #[update]
///     pub fn transfer(
///         #[env] env: &mut Env,
///         #[slot] (from_address, from): (&Address, &mut MaybeData<Slot>),
///         #[slot] to: &mut MaybeData<Slot>,
///         #[input] &amount: &Balance,
///     ) -> Result<(), ContractError> {
///         // ...
///     }
/// }
///
/// // Will generate this
/// pub trait TokenExt {
///     fn balance(
///         &self,
///         contract: &Address,
///         target: &Address,
///     ) -> Result<Balance, ContractError>;
///
///     fn transfer(
///         self: &&mut Self,
///         method_context: &MethodContext,
///         contract: &Address,
///         from: &Address,
///         to: &Address,
///         amount: &Balance,
///     ) -> Result<(), ContractError>;
/// }
///
/// impl TokenExt for Env {
///     fn balance(
///         &self,
///         contract: &Address,
///         target: &Address,
///     ) -> Result<Balance, ContractError> {
///         // ...
///     }
///
///     fn transfer(
///         self: &&mut Self,
///         method_context: &MethodContext,
///         contract: &Address,
///         from: &Address,
///         to: &Address,
///         amount: &Balance,
///     ) -> Result<(), ContractError> {
///         // ...
///     }
/// }
/// ```
///
/// The name of the extension trait is created as struct or trait name followed by `Ext` suffix.
///
/// ## Metadata
///
/// There are several places where metadata is being generated, see [`ContractMetadataKind`] for
/// details.
///
/// First, `#[contract]` macro generates a public `METADATA` constant for each method individually.
///
/// Second, for each trait that contract can implement `#[contract]` macro generates an associated
/// constant `METADATA` that essentially aggregates metadata of all annotated methods.
///
/// Third, [`Contract`] trait implementation generated by `#[contract]` macro contains
/// `MAIN_CONTRACT_METADATA` associated constant, which is similar in nature to `METADATA` constant
/// for traits described above.
///
/// Lastly, for the whole contract as a project, both trait and contract metadata is concatenated
/// and stored in `CONTRACT_METADATA` link section that can later be inspected externally to
/// understand everything about contract's interfaces, auto-generate UI, etc.
///
/// [`Contract`]: ab_contracts_common::Contract
/// [`TrivialType`]: ab_contracts_io_type::trivial_type::TrivialType
/// [`IoType`]: ab_contracts_io_type::IoType
/// [`ExternalArgs`]: ab_contracts_common::method::ExternalArgs
/// [`Env`]: ab_contracts_common::env::Env
/// [`Env::call()`]: ab_contracts_common::env::Env::call()
/// [`ContractMetadataKind`]: ab_contracts_common::metadata::ContractMetadataKind
pub use ab_contracts_macros_impl::contract;