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}