ab_contracts_common/
lib.rs

1#![feature(non_null_from_ref)]
2#![no_std]
3
4mod address;
5mod balance;
6pub mod block;
7pub mod env;
8mod error;
9pub mod metadata;
10pub mod method;
11
12use crate::method::MethodFingerprint;
13use ab_contracts_io_type::IoType;
14use ab_contracts_io_type::trivial_type::TrivialType;
15use ab_contracts_io_type::variable_bytes::VariableBytes;
16pub use address::Address;
17pub use balance::Balance;
18use core::ffi::c_void;
19use core::num::{NonZeroU32, NonZeroU128};
20use core::ops::Deref;
21use core::ptr::NonNull;
22use derive_more::Display;
23pub use error::{ContractError, CustomContractErrorCode, ExitCode};
24
25/// Max allowed size of the contract code
26pub const MAX_CODE_SIZE: u32 = 1024 * 1024;
27/// Max number of arguments in a method.
28///
29/// NOTE: Both `self` and return type that is not `()` or `Result<(), ContractError>` count towards
30/// the total number of method arguments.
31pub const MAX_TOTAL_METHOD_ARGS: u8 = 8;
32
33/// Method details used by native execution environment.
34///
35/// `ffi_fn`'s argument is actually `NonNull<InternalArgs>` of corresponding method and must have
36/// corresponding ABI.
37///
38/// NOTE: It is unlikely to be necessary to interact with this directly.
39#[derive(Debug, Copy, Clone)]
40#[doc(hidden)]
41pub struct NativeExecutorContactMethod {
42    pub method_fingerprint: &'static MethodFingerprint,
43    pub method_metadata: &'static [u8],
44    pub ffi_fn: unsafe extern "C" fn(NonNull<NonNull<c_void>>) -> ExitCode,
45}
46
47/// A trait that indicates the struct is a contact.
48///
49/// **Do not implement this trait explicitly!** Implementation is automatically generated by the
50/// macro which generates contract implementation. This trait is required, but not sufficient for
51/// proper contract implementation, use `#[contract]` attribute macro instead.
52pub trait Contract: IoType {
53    /// Main contract metadata, see [`ContractMetadataKind`] for encoding details.
54    ///
55    /// More metadata can be contributed by trait implementations.
56    ///
57    /// [`ContractMetadataKind`]: crate::metadata::ContractMetadataKind
58    const MAIN_CONTRACT_METADATA: &[u8];
59    /// Something that can be used as "code" in native execution environment.
60    ///
61    /// NOTE: It is unlikely to be necessary to interact with this directly.
62    #[doc(hidden)]
63    const CODE: &str;
64    /// Methods of a contract used in native execution environment.
65    ///
66    /// NOTE: It is unlikely to be necessary to interact with this directly.
67    #[doc(hidden)]
68    const NATIVE_EXECUTOR_METHODS: &[NativeExecutorContactMethod];
69    // Default value is provided to only fail to compile when contract that uses
70    // `ab-contracts-common` has feature specified, but `ab-contracts-common` does not, but not the
71    // other way around (as will be the case with dependencies where `guest` feature must not be
72    // enabled)
73    #[cfg(feature = "guest")]
74    #[doc(hidden)]
75    const GUEST_FEATURE_ENABLED: () = ();
76    /// Slot type used by this contract
77    type Slot: IoType;
78    /// Tmp type used by this contract
79    type Tmp: IoType;
80    /// Something that can be used as "code" in native execution environment and primarily used for
81    /// testing.
82    ///
83    /// This is NOT the code compiled for guest architecture!
84    // TODO: Make `const` when possible
85    fn code() -> impl Deref<Target = VariableBytes<MAX_CODE_SIZE>>;
86}
87
88/// A trait that indicates the implementation of a contract trait by a contract.
89///
90/// `DynTrait` here is `dyn ContractTrait`, which is a bit of a hack that allows treating a trait as
91/// a type for convenient API in native execution environment.
92///
93/// **Do not implement this trait explicitly!** Implementation is automatically generated by the
94/// macro which generates contract trait implementation. This trait is required, but not sufficient
95/// for proper trait implementation, use `#[contract]` attribute macro instead.
96///
97/// NOTE: It is unlikely to be necessary to interact with this directly.
98pub trait ContractTrait<DynTrait>
99where
100    DynTrait: ?Sized,
101{
102    /// Methods of a trait used in native execution environment
103    #[doc(hidden)]
104    const NATIVE_EXECUTOR_METHODS: &[NativeExecutorContactMethod];
105}
106
107/// A trait that is implemented for `dyn ContractTrait` and includes constants related to trait
108/// definition.
109///
110/// `dyn ContractTrait` here is a bit of a hack that allows treating a trait as a type. These
111/// constants specifically can't be implemented on a trait itself because that'll make trait
112/// not object safe, which is needed for [`ContractTrait`] that uses a similar hack with
113/// `dyn ContractTrait`.
114///
115/// **Do not implement this trait explicitly!** Implementation is automatically generated by the
116/// macro which generates trait definition. This trait is required, but not sufficient for
117/// proper trait implementation, use `#[contract]` attribute macro instead.
118///
119/// NOTE: It is unlikely to be necessary to interact with this directly.
120pub trait ContractTraitDefinition {
121    // Default value is provided to only fail to compile when trait that uses
122    // `ab-contracts-common` has feature specified, but `ab-contracts-common` does not, but not the
123    // other way around (as will be the case with dependencies where `guest` feature must not be
124    // enabled)
125    #[cfg(feature = "guest")]
126    #[doc(hidden)]
127    const GUEST_FEATURE_ENABLED: () = ();
128    /// Trait metadata, see [`ContractMetadataKind`] for encoding details"]
129    /// Trait metadata, see [`ContractMetadataKind`] for encoding details"]
130    ///
131    /// [`ContractMetadataKind`]: crate::metadata::ContractMetadataKind
132    const METADATA: &[::core::primitive::u8];
133}
134
135/// Shard index
136#[derive(Debug, Display, Copy, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, TrivialType)]
137#[repr(transparent)]
138pub struct ShardIndex(u32);
139
140impl ShardIndex {
141    /// Max possible shard index
142    pub const MAX_SHARD_INDEX: u32 = Self::MAX_SHARDS.get() - 1;
143    /// Max possible number of shards
144    pub const MAX_SHARDS: NonZeroU32 = NonZeroU32::new(2u32.pow(20)).expect("Not zero; qed");
145    /// Max possible number of addresses per shard
146    pub const MAX_ADDRESSES_PER_SHARD: NonZeroU128 =
147        NonZeroU128::new((u128::MAX / 2 + 1) / (Self::MAX_SHARDS.get() as u128 / 2))
148            .expect("Not zero; qed");
149
150    // TODO: Remove once traits work in const environment and `From` could be used
151    /// Convert shard index to `u32`.
152    ///
153    /// This is typically only necessary for low-level code.
154    #[inline(always)]
155    pub const fn to_u32(self) -> u32 {
156        self.0
157    }
158
159    // TODO: Remove once traits work in const environment and `From` could be used
160    /// Create shard index from `u32`.
161    ///
162    /// Returns `None` if `shard_index > ShardIndex::MAX_SHARD_INDEX`
163    ///
164    /// This is typically only necessary for low-level code.
165    #[inline(always)]
166    pub const fn from_u32(shard_index: u32) -> Option<Self> {
167        if shard_index > Self::MAX_SHARD_INDEX {
168            return None;
169        }
170
171        Some(Self(shard_index))
172    }
173}