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}