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