1use crate::method::{ExternalArgs, MethodFingerprint};
2use crate::{Address, ContractError, ShardIndex};
3use ab_contracts_io_type::trivial_type::TrivialType;
4use core::ffi::c_void;
5use core::marker::PhantomData;
6use core::ptr::NonNull;
7
8pub type Blake3Hash = [u8; 32];
10
11#[derive(Debug, Default, Copy, Clone, TrivialType)]
13#[repr(C)]
14pub struct Gas(u64);
15
16#[derive(Debug, Copy, Clone, TrivialType)]
17#[repr(C)]
18pub struct TransactionHeader {
19 pub block_hash: Blake3Hash,
20 pub gas_limit: Gas,
21 pub contract: Address,
23}
24
25#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash, TrivialType)]
26#[repr(C)]
27pub struct TransactionSlot {
28 pub owner: Address,
29 pub contract: Address,
30}
31
32#[derive(Debug, Copy, Clone)]
36pub struct Transaction<'a> {
37 pub header: &'a TransactionHeader,
38 pub read_slots: &'a [TransactionSlot],
44 pub write_slots: &'a [TransactionSlot],
46 pub payload: &'a [u128],
47 pub seal: &'a [u8],
48}
49
50#[derive(Debug, Copy, Clone, Eq, PartialEq, TrivialType)]
61#[repr(u8)]
62pub enum MethodContext {
63 Keep,
65 Reset,
67 Replace,
69}
70
71#[derive(Debug)]
73#[repr(C)]
74#[must_use]
75pub struct PreparedMethod<'a> {
76 pub contract: Address,
78 pub fingerprint: MethodFingerprint,
80 pub external_args: NonNull<NonNull<c_void>>,
83 pub method_context: MethodContext,
85 pub phantom: PhantomData<&'a ()>,
87}
88
89#[derive(Debug, Copy, Clone, TrivialType)]
91#[repr(C)]
92pub struct EnvState {
93 pub shard_index: ShardIndex,
95 pub padding_0: [u8; 4],
97 pub own_address: Address,
99 pub context: Address,
101 pub caller: Address,
103}
104
105#[cfg(feature = "executor")]
107pub trait ExecutorContext: core::fmt::Debug {
108 fn call(
110 &self,
111 previous_env_state: &EnvState,
112 prepared_methods: &mut PreparedMethod<'_>,
113 ) -> Result<(), ContractError>;
114}
115
116#[cfg(all(feature = "executor", feature = "guest", not(any(doc, unix, windows))))]
117compile_error!(
118 "`executor` and `guest` features are mutually exclusive due to it affecting `Env` layout"
119);
120
121#[derive(Debug)]
126#[repr(C)]
127pub struct Env<'a> {
128 state: EnvState,
129 #[cfg(feature = "executor")]
130 executor_context: &'a mut dyn ExecutorContext,
131 phantom_data: PhantomData<&'a ()>,
132}
133
134impl<'a> Env<'a> {
138 #[cfg(feature = "executor")]
140 #[inline(always)]
141 pub fn with_executor_context(
142 state: EnvState,
143 executor_context: &'a mut dyn ExecutorContext,
144 ) -> Self {
145 Self {
146 state,
147 executor_context,
148 phantom_data: PhantomData,
149 }
150 }
151
152 #[cfg(feature = "executor")]
154 #[inline(always)]
155 pub fn get_mut_executor_context(&mut self) -> &mut dyn ExecutorContext {
156 self.executor_context
157 }
158
159 #[inline]
161 pub fn shard_index(&self) -> ShardIndex {
162 self.state.shard_index
163 }
164
165 #[inline]
167 pub fn own_address(&self) -> Address {
168 self.state.own_address
169 }
170
171 #[inline]
173 pub fn context<'b>(self: &'b &'b mut Self) -> Address {
174 self.state.context
175 }
176
177 #[inline]
179 pub fn caller<'b>(self: &'b &'b mut Self) -> Address {
180 self.state.caller
181 }
182
183 #[inline]
187 pub fn call<Args>(
188 &self,
189 contract: Address,
190 args: &mut Args,
191 method_context: MethodContext,
192 ) -> Result<(), ContractError>
193 where
194 Args: ExternalArgs,
195 {
196 let prepared_method = Self::prepare_method_call(contract, args, method_context);
197 self.call_prepared(prepared_method)
198 }
199
200 #[inline]
204 pub fn prepare_method_call<Args>(
205 contract: Address,
206 args: &mut Args,
207 method_context: MethodContext,
208 ) -> PreparedMethod<'_>
209 where
210 Args: ExternalArgs,
211 {
212 PreparedMethod {
213 contract,
214 fingerprint: Args::FINGERPRINT,
215 external_args: NonNull::from_mut(args).cast::<NonNull<c_void>>(),
217 method_context,
218 phantom: PhantomData,
219 }
220 }
221
222 #[inline]
227 pub fn call_prepared(&self, method: PreparedMethod<'_>) -> Result<(), ContractError> {
228 #[cfg(feature = "executor")]
229 {
230 let mut method = method;
231 self.executor_context.call(&self.state, &mut method)
232 }
233 #[cfg(all(feature = "guest", not(feature = "executor")))]
234 {
235 let _ = method;
236 todo!()
237 }
238 #[cfg(not(any(feature = "executor", feature = "guest")))]
239 {
240 let _ = method;
241 Err(ContractError::InternalError)
242 }
243 }
244}