1use fuel_core_executor::executor::ExecutionOptions;
2use fuel_core_storage::transactional::Changes;
3use fuel_core_types::{
4 blockchain::block::Block,
5 services::{
6 Uncommitted,
7 block_producer::Components,
8 executor::{
9 Error as ExecutorError,
10 ExecutionResult,
11 UncommittedResult,
12 ValidationResult,
13 },
14 },
15};
16#[cfg(feature = "std")]
17use fuel_core_types_v0::services::executor::Error as ExecutorErrorV0;
18
19pub fn pack_ptr_and_len(ptr: u32, len: u32) -> u64 {
21 (u64::from(len) << 32) | u64::from(ptr)
22}
23
24pub fn unpack_ptr_and_len(val: u64) -> (u32, u32) {
26 let ptr = u32::try_from(val & (u32::MAX as u64))
27 .expect("It only contains first 32 bytes; qed");
28 let len = u32::try_from(val >> 32).expect("It only contains first 32 bytes; qed");
29
30 (ptr, len)
31}
32
33pub fn pack_exists_size_result(exists: bool, size: u32, result: u16) -> u64 {
35 ((u64::from(result) << 33) | (u64::from(size) << 1)) | u64::from(exists)
36}
37
38pub fn unpack_exists_size_result(val: u64) -> (bool, u32, u16) {
40 let exists = (val & 1u64) != 0;
41 let size = u32::try_from((val >> 1) & (u32::MAX as u64))
42 .expect("It only contains first 32 bytes; qed");
43 let result = u16::try_from((val >> 33) & (u16::MAX as u64))
44 .expect("It only contains first 16 bytes; qed");
45
46 (exists, size, result)
47}
48
49#[derive(Debug, serde::Serialize)]
52pub enum InputSerializationType<'a> {
53 V1 {
54 block: WasmSerializationBlockTypes<'a, ()>,
55 options: ExecutionOptions,
56 },
57}
58
59#[derive(Debug, serde::Deserialize)]
60pub enum InputDeserializationType {
61 V1 {
62 block: WasmDeserializationBlockTypes<()>,
63 options: ExecutionOptions,
64 },
65}
66
67#[derive(Debug, serde::Serialize)]
68pub enum WasmSerializationBlockTypes<'a, TxSource> {
69 DryRun(Components<TxSource>),
71 Production(Components<TxSource>),
73 Validation(&'a Block),
75}
76
77#[derive(Debug, serde::Deserialize)]
78pub enum WasmDeserializationBlockTypes<TxSource> {
79 DryRun(Components<TxSource>),
81 Production(Components<TxSource>),
83 Validation(Block),
85}
86
87#[derive(Debug, serde::Serialize, serde::Deserialize)]
94pub struct JSONError(String);
95
96#[cfg(feature = "std")]
97impl From<ExecutorErrorV0> for JSONError {
98 fn from(value: ExecutorErrorV0) -> Self {
99 let json = serde_json::to_string(&value).unwrap_or_else(|e| {
100 anyhow::anyhow!("Failed to serialize the V0 error: {:?}", e).to_string()
101 });
102 JSONError(json)
103 }
104}
105
106impl From<ExecutorError> for JSONError {
107 fn from(value: ExecutorError) -> Self {
108 let json = serde_json::to_string(&value).unwrap_or_else(|e| {
109 anyhow::anyhow!("Failed to serialize the error: {:?}", e).to_string()
110 });
111 JSONError(json)
112 }
113}
114
115impl From<JSONError> for ExecutorError {
116 fn from(value: JSONError) -> Self {
117 serde_json::from_str(&value.0).unwrap_or(ExecutorError::Other(value.0))
118 }
119}
120
121#[cfg(feature = "std")]
124#[derive(Debug, serde::Serialize, serde::Deserialize)]
125pub enum ReturnType {
126 ExecutionV0(
127 Result<Uncommitted<ExecutionResult<ExecutorErrorV0>, Changes>, ExecutorErrorV0>,
128 ),
129 ExecutionV1(Result<Uncommitted<ExecutionResult<JSONError>, Changes>, JSONError>),
130 Validation(Result<Uncommitted<ValidationResult, Changes>, JSONError>),
131}
132
133#[cfg(not(feature = "std"))]
136#[derive(Debug, serde::Serialize, serde::Deserialize)]
137#[allow(clippy::large_enum_variant)]
138pub enum ReturnType {
139 ExecutionV0,
141 ExecutionV1(Result<Uncommitted<ExecutionResult<JSONError>, Changes>, JSONError>),
142 Validation(Result<Uncommitted<ValidationResult, Changes>, JSONError>),
143}
144
145pub fn convert_to_v1_execution_result(
147 result: Result<UncommittedResult<Changes>, ExecutorError>,
148) -> Result<Uncommitted<ExecutionResult<JSONError>, Changes>, JSONError> {
149 result
150 .map(|result| {
151 let (result, changes) = result.into();
152 let ExecutionResult {
153 block,
154 skipped_transactions,
155 tx_status,
156 events,
157 } = result;
158
159 let skipped_transactions: Vec<_> = skipped_transactions
160 .into_iter()
161 .map(|(id, error)| (id, JSONError::from(error)))
162 .collect();
163
164 let result = ExecutionResult {
165 block,
166 skipped_transactions,
167 tx_status,
168 events,
169 };
170
171 Uncommitted::new(result, changes)
172 })
173 .map_err(JSONError::from)
174}
175
176pub fn convert_from_v1_execution_result(
178 result: Result<Uncommitted<ExecutionResult<JSONError>, Changes>, JSONError>,
179) -> Result<UncommittedResult<Changes>, ExecutorError> {
180 result
181 .map(|result| {
182 let (result, changes) = result.into();
183 let ExecutionResult {
184 block,
185 skipped_transactions,
186 tx_status,
187 events,
188 } = result;
189
190 let skipped_transactions: Vec<_> = skipped_transactions
191 .into_iter()
192 .map(|(id, error)| (id, ExecutorError::from(error)))
193 .collect();
194
195 let result = ExecutionResult {
196 block,
197 skipped_transactions,
198 tx_status,
199 events,
200 };
201
202 Uncommitted::new(result, changes)
203 })
204 .map_err(ExecutorError::from)
205}
206
207#[cfg(feature = "std")]
209pub fn convert_from_v0_execution_result(
210 result: Result<
211 Uncommitted<ExecutionResult<ExecutorErrorV0>, Changes>,
212 ExecutorErrorV0,
213 >,
214) -> Result<UncommittedResult<Changes>, ExecutorError> {
215 result
216 .map(|result| {
217 let (result, changes) = result.into();
218 let ExecutionResult {
219 block,
220 skipped_transactions,
221 tx_status,
222 events,
223 } = result;
224
225 let skipped_transactions: Vec<_> = skipped_transactions
226 .into_iter()
227 .map(|(id, error)| (id, ExecutorError::from(JSONError::from(error))))
228 .collect();
229
230 let result = ExecutionResult {
231 block,
232 skipped_transactions,
233 tx_status,
234 events,
235 };
236
237 Uncommitted::new(result, changes)
238 })
239 .map_err(JSONError::from)
240 .map_err(ExecutorError::from)
241}
242
243#[cfg(test)]
244mod tests {
245 use super::*;
246 use fuel_core_types::services::executor::TransactionValidityError;
247 #[cfg(feature = "std")]
248 use fuel_core_types_v0::services::executor::TransactionValidityError as TransactionValidityErrorV0;
249 use proptest::prelude::prop::*;
250
251 proptest::proptest! {
252 #[test]
253 fn can_pack_any_values(exists: bool, size: u32, result: u16) {
254 pack_exists_size_result(exists, size, result);
255 }
256
257 #[test]
258 fn can_unpack_any_values(value: u64) {
259 let _ = unpack_exists_size_result(value);
260 }
261
262
263 #[test]
264 fn unpacks_packed_values(exists: bool, size: u32, result: u16) {
265 let packed = pack_exists_size_result(exists, size, result);
266 let (unpacked_exists, unpacked_size, unpacked_result) =
267 unpack_exists_size_result(packed);
268
269 proptest::prop_assert_eq!(exists, unpacked_exists);
270 proptest::prop_assert_eq!(size, unpacked_size);
271 proptest::prop_assert_eq!(result, unpacked_result);
272 }
273 }
274
275 #[cfg(feature = "std")]
276 #[test]
277 fn can_convert_v0_error_to_v1() {
278 let v0 = ExecutorErrorV0::TransactionValidity(
280 TransactionValidityErrorV0::CoinDoesNotExist(Default::default()),
281 );
282
283 let json: JSONError = v0.into();
285 let v1: ExecutorError = json.into();
286
287 assert_eq!(
289 v1,
290 ExecutorError::TransactionValidity(
291 TransactionValidityError::CoinDoesNotExist(Default::default())
292 )
293 );
294 }
295}