Skip to main content

ab_contracts_common/
lib.rs

1#![feature(
2    const_convert,
3    const_index,
4    const_result_trait_fn,
5    const_split_off_first_last,
6    const_trait_impl,
7    const_try,
8    mut_restriction
9)]
10#![no_std]
11
12pub mod env;
13mod error;
14pub mod metadata;
15pub mod method;
16pub mod output;
17
18use crate::method::MethodFingerprint;
19use ab_io_type::IoType;
20use ab_io_type::variable_bytes::VariableBytes;
21use core::ffi::c_void;
22use core::ops::Deref;
23use core::ptr::NonNull;
24pub use error::{ContractError, CustomContractErrorCode, ExitCode};
25
26/// Function name used to make calls from guest to host
27pub const HOST_CALL_FN: &str = "__ab_host_call";
28/// Import function name used to make calls from guest to host
29pub const HOST_CALL_FN_IMPORT: &str = "__ab_host_call_import";
30/// The name of the static variable that contains contract metadata
31pub const METADATA_STATIC_NAME_PREFIX: &str = "__ab_metadata_";
32/// Max allowed size of the contract code
33pub const MAX_CODE_SIZE: u32 = 1024 * 1024;
34/// Max number of arguments in a method.
35///
36/// NOTE: Both `self` and return type that is not `()` or `Result<(), ContractError>` count towards
37/// the total number of method arguments.
38pub const MAX_TOTAL_METHOD_ARGS: u8 = 8;
39
40/// Method details used by the native execution environment.
41///
42/// `ffi_fn`'s argument is actually `NonNull<InternalArgs>` of a corresponding method and must have
43/// corresponding ABI.
44///
45/// NOTE: It is unlikely to be necessary to interact with this directly.
46#[derive(Debug, Copy, Clone)]
47#[doc(hidden)]
48pub struct NativeExecutorContactMethod {
49    pub method_fingerprint: &'static MethodFingerprint,
50    pub method_metadata: &'static [u8],
51    pub ffi_fn: unsafe extern "C" fn(NonNull<c_void>) -> ExitCode,
52}
53
54/// A trait that indicates the struct is a contact.
55///
56/// **Do not implement this trait explicitly!** Implementation is automatically generated by the
57/// macro which generates contract implementation. This trait is required, but not sufficient for
58/// proper contract implementation, use `#[contract]` attribute macro instead.
59///
60/// # Safety
61/// The native executor relies on implementations instead of checking them:
62/// * [`Self::MAIN_CONTRACT_METADATA`] must describe this contract
63/// * each entry of [`Self::NATIVE_EXECUTOR_METHODS`] must contain the fingerprint and metadata of a
64///   method of this contract, and an FFI function that accepts arguments of that exact method and
65///   handles them the way the FFI functions generated by `#[contract]` do
66pub unsafe trait Contract: IoType {
67    /// Main contract metadata, see [`ContractMetadataKind`] for encoding details.
68    ///
69    /// More metadata can be contributed by trait implementations.
70    ///
71    /// [`ContractMetadataKind`]: crate::metadata::ContractMetadataKind
72    const MAIN_CONTRACT_METADATA: &[u8];
73    /// Something that can be used as "code" in native execution environment.
74    ///
75    /// NOTE: It is unlikely to be necessary to interact with this directly.
76    #[doc(hidden)]
77    const CODE: &str;
78    /// Methods of a contract used in native execution environment.
79    ///
80    /// NOTE: It is unlikely to be necessary to interact with this directly.
81    #[doc(hidden)]
82    const NATIVE_EXECUTOR_METHODS: &[NativeExecutorContactMethod];
83    // Default value is provided to only fail to compile when contract that uses
84    // `ab-contracts-common` has feature specified, but `ab-contracts-common` does not, but not the
85    // other way around (as will be the case with dependencies where `guest` feature must not be
86    // enabled)
87    #[cfg(feature = "guest")]
88    #[doc(hidden)]
89    const GUEST_FEATURE_ENABLED: () = ();
90    /// Slot type used by this contract
91    type Slot: IoType;
92    /// Tmp type used by this contract
93    type Tmp: IoType;
94    /// Something that can be used as "code" in native execution environment and primarily used for
95    /// testing.
96    ///
97    /// This is NOT the code compiled for guest architecture!
98    // TODO: Make `const` when possible
99    fn code() -> impl Deref<Target = VariableBytes<MAX_CODE_SIZE>>;
100}
101
102/// A trait that indicates the implementation of a contract trait by a contract.
103///
104/// `DynTrait` here is `dyn ContractTrait`, which is a bit of a hack that allows treating a trait as
105/// a type for convenient API in native execution environment.
106///
107/// **Do not implement this trait explicitly!** Implementation is automatically generated by the
108/// macro which generates contract trait implementation. This trait is required, but not sufficient
109/// for proper trait implementation, use `#[contract]` attribute macro instead.
110///
111/// NOTE: It is unlikely to be necessary to interact with this directly.
112///
113/// # Safety
114/// The native executor relies on each entry of [`Self::NATIVE_EXECUTOR_METHODS`] containing the
115/// fingerprint and metadata of a method of this trait, and an FFI function that accepts arguments
116/// of that exact method and handles them the way the FFI functions generated by `#[contract]` do.
117pub unsafe trait ContractTrait<DynTrait>
118where
119    DynTrait: ?Sized,
120{
121    /// Methods of a trait used in native execution environment
122    #[doc(hidden)]
123    const NATIVE_EXECUTOR_METHODS: &[NativeExecutorContactMethod];
124}
125
126/// A trait that is implemented for `dyn ContractTrait` and includes constants related to trait
127/// definition.
128///
129/// `dyn ContractTrait` here is a bit of a hack that allows treating a trait as a type. These
130/// constants specifically can't be implemented on a trait itself because that'll make trait
131/// not object safe, which is needed for [`ContractTrait`] that uses a similar hack with
132/// `dyn ContractTrait`.
133///
134/// **Do not implement this trait explicitly!** Implementation is automatically generated by the
135/// macro which generates trait definition. This trait is required, but not sufficient for
136/// proper trait implementation, use `#[contract]` attribute macro instead.
137///
138/// NOTE: It is unlikely to be necessary to interact with this directly.
139pub trait ContractTraitDefinition {
140    // Default value is provided to only fail to compile when trait that uses
141    // `ab-contracts-common` has feature specified, but `ab-contracts-common` does not, but not the
142    // other way around (as will be the case with dependencies where `guest` feature must not be
143    // enabled)
144    #[cfg(feature = "guest")]
145    #[doc(hidden)]
146    const GUEST_FEATURE_ENABLED: () = ();
147    /// Trait metadata, see [`ContractMetadataKind`] for encoding details"]
148    /// Trait metadata, see [`ContractMetadataKind`] for encoding details"]
149    ///
150    /// [`ContractMetadataKind`]: crate::metadata::ContractMetadataKind
151    const METADATA: &[::core::primitive::u8];
152}