1use crate::{
4 backtrace::Backtrace,
5 checked_transaction::{
6 Checked,
7 IntoChecked,
8 Ready,
9 },
10 error::InterpreterError,
11 interpreter::{
12 CheckedMetadata,
13 EcalHandler,
14 ExecutableTransaction,
15 Interpreter,
16 InterpreterParams,
17 Memory,
18 NotSupportedEcal,
19 },
20 state::{
21 ProgramState,
22 StateTransition,
23 StateTransitionRef,
24 },
25 storage::InterpreterStorage,
26 verification::{
27 Normal,
28 Verifier,
29 },
30};
31use fuel_tx::{
32 Blob,
33 Create,
34 FeeParameters,
35 GasCosts,
36 Receipt,
37 Script,
38 Upgrade,
39 Upload,
40};
41
42#[cfg(any(test, feature = "test-helpers"))]
43use crate::interpreter::MemoryInstance;
44
45#[derive(Debug)]
46pub struct Transactor<M, S, Tx, Ecal = NotSupportedEcal, V = Normal>
54where
55 S: InterpreterStorage,
56{
57 interpreter: Interpreter<M, S, Tx, Ecal, V>,
58 program_state: Option<ProgramState>,
59 error: Option<InterpreterError<S::DataError>>,
60}
61
62impl<M, S, Tx, Ecal, V> Transactor<M, S, Tx, Ecal, V>
63where
64 S: InterpreterStorage,
65 Tx: ExecutableTransaction,
66 Ecal: EcalHandler + Default,
67 V: Verifier + Default,
68{
69 pub fn new(memory: M, storage: S, interpreter_params: InterpreterParams) -> Self {
71 Self {
72 interpreter: Interpreter::<M, S, Tx, Ecal, V>::with_storage(
73 memory,
74 storage,
75 interpreter_params,
76 ),
77 program_state: None,
78 error: None,
79 }
80 }
81}
82impl<M, S, Tx, Ecal, V> Transactor<M, S, Tx, Ecal, V>
83where
84 S: InterpreterStorage,
85 Tx: ExecutableTransaction,
86 Ecal: EcalHandler,
87{
88 pub fn state_transition(&self) -> Option<StateTransitionRef<'_, Tx>> {
93 self.program_state.map(|state| {
94 StateTransitionRef::new(
95 state,
96 self.interpreter.transaction(),
97 self.interpreter.receipts(),
98 )
99 })
100 }
101
102 pub fn to_owned_state_transition(&self) -> Option<StateTransition<Tx>> {
107 self.program_state.map(|state| {
108 StateTransition::new(
109 state,
110 self.interpreter.transaction().clone(),
111 self.interpreter.receipts().to_vec(),
112 )
113 })
114 }
115
116 pub const fn error(&self) -> Option<&InterpreterError<S::DataError>> {
124 self.error.as_ref()
125 }
126
127 pub const fn is_success(&self) -> bool {
129 !self.is_reverted()
130 }
131
132 pub const fn is_reverted(&self) -> bool {
134 self.error.is_some()
135 || matches!(self.program_state, Some(ProgramState::Revert(_)))
136 }
137
138 pub fn result(
142 &self,
143 ) -> Result<StateTransitionRef<'_, Tx>, &InterpreterError<S::DataError>> {
144 let state = self.state_transition();
145 let error = self.error.as_ref();
146
147 match (state, error) {
148 (Some(s), None) => Ok(s),
149 (None, Some(e)) => Err(e),
150
151 _ => Err(&InterpreterError::NoTransactionInitialized),
153 }
154 }
155
156 pub fn interpreter(&self) -> &Interpreter<M, S, Tx, Ecal, V> {
158 &self.interpreter
159 }
160
161 pub fn gas_costs(&self) -> &GasCosts {
163 self.interpreter.gas_costs()
164 }
165
166 pub fn fee_params(&self) -> &FeeParameters {
168 self.interpreter.fee_params()
169 }
170
171 #[cfg(feature = "test-helpers")]
172 pub fn set_gas_price(&mut self, gas_price: u64) {
174 self.interpreter.set_gas_price(gas_price);
175 }
176
177 pub fn tx_offset(&self) -> usize {
179 self.interpreter.tx_offset()
180 }
181}
182
183impl<M, S, Ecal, V> Transactor<M, S, Script, Ecal, V>
184where
185 M: Memory,
186 S: InterpreterStorage,
187{
188 pub fn receipts(&self) -> Option<&[Receipt]> {
193 self.program_state
194 .is_some()
195 .then(|| self.interpreter.receipts())
196 }
197
198 pub fn backtrace(&self) -> Option<Backtrace> {
201 self.receipts()
202 .and_then(|r| r.iter().find_map(Receipt::result))
203 .copied()
204 .map(|result| Backtrace::from_vm_error(&self.interpreter, result))
205 }
206}
207
208impl<M, S, Tx, Ecal, V> Transactor<M, S, Tx, Ecal, V>
209where
210 S: InterpreterStorage,
211{
212 pub fn deploy(
214 &mut self,
215 checked: Checked<Create>,
216 ) -> Result<Create, InterpreterError<S::DataError>> {
217 let gas_price = self.interpreter.gas_price();
218 let gas_costs = self.interpreter.gas_costs();
219 let fee_params = self.interpreter.fee_params();
220
221 let ready = checked
222 .into_ready(gas_price, gas_costs, fee_params, None)
223 .map_err(InterpreterError::CheckError)?;
224
225 self.deploy_ready_tx(ready)
226 }
227
228 pub fn deploy_ready_tx(
230 &mut self,
231 ready_tx: Ready<Create>,
232 ) -> Result<Create, InterpreterError<S::DataError>> {
233 self.interpreter.deploy(ready_tx)
234 }
235
236 pub fn upgrade(
238 &mut self,
239 checked: Checked<Upgrade>,
240 ) -> Result<Upgrade, InterpreterError<S::DataError>> {
241 let gas_price = self.interpreter.gas_price();
242 let gas_costs = self.interpreter.gas_costs();
243 let fee_params = self.interpreter.fee_params();
244
245 let ready = checked
246 .into_ready(gas_price, gas_costs, fee_params, None)
247 .map_err(InterpreterError::CheckError)?;
248
249 self.execute_ready_upgrade_tx(ready)
250 }
251
252 pub fn execute_ready_upgrade_tx(
254 &mut self,
255 ready_tx: Ready<Upgrade>,
256 ) -> Result<Upgrade, InterpreterError<S::DataError>> {
257 self.interpreter.upgrade(ready_tx)
258 }
259
260 pub fn upload(
262 &mut self,
263 checked: Checked<Upload>,
264 ) -> Result<Upload, InterpreterError<S::DataError>> {
265 let gas_price = self.interpreter.gas_price();
266 let gas_costs = self.interpreter.gas_costs();
267 let fee_params = self.interpreter.fee_params();
268
269 let ready = checked
270 .into_ready(gas_price, gas_costs, fee_params, None)
271 .map_err(InterpreterError::CheckError)?;
272
273 self.execute_ready_upload_tx(ready)
274 }
275
276 pub fn execute_ready_upload_tx(
278 &mut self,
279 ready_tx: Ready<Upload>,
280 ) -> Result<Upload, InterpreterError<S::DataError>> {
281 self.interpreter.upload(ready_tx)
282 }
283
284 pub fn blob(
286 &mut self,
287 checked: Checked<Blob>,
288 ) -> Result<Blob, InterpreterError<S::DataError>> {
289 let gas_price = self.interpreter.gas_price();
290 let gas_costs = self.interpreter.gas_costs();
291 let fee_params = self.interpreter.fee_params();
292
293 let ready = checked
294 .into_ready(gas_price, gas_costs, fee_params, None)
295 .map_err(InterpreterError::CheckError)?;
296
297 self.execute_ready_blob_tx(ready)
298 }
299
300 pub fn execute_ready_blob_tx(
302 &mut self,
303 ready_tx: Ready<Blob>,
304 ) -> Result<Blob, InterpreterError<S::DataError>> {
305 self.interpreter.blob(ready_tx)
306 }
307}
308
309impl<M, S, Tx, Ecal, V> Transactor<M, S, Tx, Ecal, V>
310where
311 M: Memory,
312 S: InterpreterStorage,
313 Tx: ExecutableTransaction,
314 <Tx as IntoChecked>::Metadata: CheckedMetadata,
315 Ecal: EcalHandler,
316 V: Verifier,
317{
318 pub fn transact(&mut self, tx: Checked<Tx>) -> &mut Self {
320 let gas_price = self.interpreter.gas_price();
321 let gas_costs = self.interpreter.gas_costs();
322 let fee_params = self.interpreter.fee_params();
323 let block_height = self.interpreter.context().block_height();
324
325 match tx
326 .into_ready(gas_price, gas_costs, fee_params, block_height)
327 .map_err(InterpreterError::CheckError)
328 {
329 Ok(ready_tx) => self.transact_ready_tx(ready_tx),
330 Err(e) => self.handle_error(e),
331 }
332 }
333
334 pub fn transact_ready_tx(&mut self, ready_tx: Ready<Tx>) -> &mut Self {
336 match self.interpreter.transact(ready_tx) {
337 Ok(s) => {
338 self.program_state.replace(s.into());
339 self.error.take();
340 self
341 }
342
343 Err(e) => self.handle_error(e),
344 }
345 }
346
347 fn handle_error(&mut self, error: InterpreterError<S::DataError>) -> &mut Self {
348 self.program_state.take();
349 self.error.replace(error);
350 self
351 }
352}
353
354impl<M, S, Tx, Ecal, V> From<Interpreter<M, S, Tx, Ecal, V>>
355 for Transactor<M, S, Tx, Ecal, V>
356where
357 Tx: ExecutableTransaction,
358 S: InterpreterStorage,
359{
360 fn from(interpreter: Interpreter<M, S, Tx, Ecal, V>) -> Self {
361 let program_state = None;
362 let error = None;
363
364 Self {
365 interpreter,
366 program_state,
367 error,
368 }
369 }
370}
371
372impl<M, S, Tx, Ecal, V> From<Transactor<M, S, Tx, Ecal, V>>
373 for Interpreter<M, S, Tx, Ecal, V>
374where
375 Tx: ExecutableTransaction,
376 S: InterpreterStorage,
377{
378 fn from(transactor: Transactor<M, S, Tx, Ecal, V>) -> Self {
379 transactor.interpreter
380 }
381}
382
383impl<M, S, Tx, Ecal, V> AsRef<Interpreter<M, S, Tx, Ecal, V>>
384 for Transactor<M, S, Tx, Ecal, V>
385where
386 Tx: ExecutableTransaction,
387 S: InterpreterStorage,
388 Ecal: EcalHandler,
389{
390 fn as_ref(&self) -> &Interpreter<M, S, Tx, Ecal, V> {
391 &self.interpreter
392 }
393}
394
395impl<M, S, Tx, Ecal, V> AsRef<S> for Transactor<M, S, Tx, Ecal, V>
396where
397 Tx: ExecutableTransaction,
398 S: InterpreterStorage,
399{
400 fn as_ref(&self) -> &S {
401 self.interpreter.as_ref()
402 }
403}
404
405impl<M, S, Tx, Ecal, V> AsMut<S> for Transactor<M, S, Tx, Ecal, V>
406where
407 Tx: ExecutableTransaction,
408 S: InterpreterStorage,
409{
410 fn as_mut(&mut self) -> &mut S {
411 self.interpreter.as_mut()
412 }
413}
414
415#[cfg(feature = "test-helpers")]
416impl<S, Tx, Ecal, V> Default for Transactor<MemoryInstance, S, Tx, Ecal, V>
417where
418 S: InterpreterStorage + Default,
419 Tx: ExecutableTransaction,
420 Ecal: EcalHandler + Default,
421 V: Verifier + Default,
422{
423 fn default() -> Self {
424 Self::new(
425 MemoryInstance::new(),
426 S::default(),
427 InterpreterParams::default(),
428 )
429 }
430}