ab_contracts_common/
lib.rs

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