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, V>> {
93 self.program_state.map(|state| {
94 StateTransitionRef::new(
95 state,
96 self.interpreter.transaction(),
97 self.interpreter.receipts(),
98 self.interpreter.verifier(),
99 )
100 })
101 }
102}
103
104impl<M, S, Tx, Ecal, V> Transactor<M, S, Tx, Ecal, V>
105where
106 S: InterpreterStorage,
107 Tx: ExecutableTransaction,
108 Ecal: EcalHandler,
109 V: Clone,
110{
111 pub fn to_owned_state_transition(&self) -> Option<StateTransition<Tx, V>> {
116 self.program_state.map(|state| {
117 StateTransition::new(
118 state,
119 self.interpreter.transaction().clone(),
120 self.interpreter.receipts().to_vec(),
121 self.interpreter.verifier().clone(),
122 )
123 })
124 }
125}
126
127impl<M, S, Tx, Ecal, V> Transactor<M, S, Tx, Ecal, V>
128where
129 S: InterpreterStorage,
130 Tx: ExecutableTransaction,
131 Ecal: EcalHandler,
132{
133 pub const fn error(&self) -> Option<&InterpreterError<S::DataError>> {
141 self.error.as_ref()
142 }
143
144 pub const fn is_success(&self) -> bool {
146 !self.is_reverted()
147 }
148
149 pub const fn is_reverted(&self) -> bool {
151 self.error.is_some()
152 || matches!(self.program_state, Some(ProgramState::Revert(_)))
153 }
154
155 pub fn result(
159 &self,
160 ) -> Result<StateTransitionRef<'_, Tx, V>, &InterpreterError<S::DataError>> {
161 let state = self.state_transition();
162 let error = self.error.as_ref();
163
164 match (state, error) {
165 (Some(s), None) => Ok(s),
166 (None, Some(e)) => Err(e),
167
168 _ => Err(&InterpreterError::NoTransactionInitialized),
170 }
171 }
172
173 pub fn interpreter(&self) -> &Interpreter<M, S, Tx, Ecal, V> {
175 &self.interpreter
176 }
177
178 pub fn gas_costs(&self) -> &GasCosts {
180 self.interpreter.gas_costs()
181 }
182
183 pub fn fee_params(&self) -> &FeeParameters {
185 self.interpreter.fee_params()
186 }
187
188 #[cfg(feature = "test-helpers")]
189 pub fn set_gas_price(&mut self, gas_price: u64) {
191 self.interpreter.set_gas_price(gas_price);
192 }
193
194 pub fn tx_offset(&self) -> usize {
196 self.interpreter.tx_offset()
197 }
198}
199
200impl<M, S, Ecal, V> Transactor<M, S, Script, Ecal, V>
201where
202 M: Memory,
203 S: InterpreterStorage,
204{
205 pub fn receipts(&self) -> Option<&[Receipt]> {
210 self.program_state
211 .is_some()
212 .then(|| self.interpreter.receipts())
213 }
214
215 pub fn backtrace(&self) -> Option<Backtrace> {
218 self.receipts()
219 .and_then(|r| r.iter().find_map(Receipt::result))
220 .copied()
221 .map(|result| Backtrace::from_vm_error(&self.interpreter, result))
222 }
223}
224
225impl<M, S, Tx, Ecal, V> Transactor<M, S, Tx, Ecal, V>
226where
227 S: InterpreterStorage,
228{
229 pub fn deploy(
231 &mut self,
232 checked: Checked<Create>,
233 ) -> Result<Create, InterpreterError<S::DataError>> {
234 let gas_price = self.interpreter.gas_price();
235 let gas_costs = self.interpreter.gas_costs();
236 let fee_params = self.interpreter.fee_params();
237
238 let ready = checked
239 .into_ready(gas_price, gas_costs, fee_params, None)
240 .map_err(InterpreterError::CheckError)?;
241
242 self.deploy_ready_tx(ready)
243 }
244
245 pub fn deploy_ready_tx(
247 &mut self,
248 ready_tx: Ready<Create>,
249 ) -> Result<Create, InterpreterError<S::DataError>> {
250 self.interpreter.deploy(ready_tx)
251 }
252
253 pub fn upgrade(
255 &mut self,
256 checked: Checked<Upgrade>,
257 ) -> Result<Upgrade, InterpreterError<S::DataError>> {
258 let gas_price = self.interpreter.gas_price();
259 let gas_costs = self.interpreter.gas_costs();
260 let fee_params = self.interpreter.fee_params();
261
262 let ready = checked
263 .into_ready(gas_price, gas_costs, fee_params, None)
264 .map_err(InterpreterError::CheckError)?;
265
266 self.execute_ready_upgrade_tx(ready)
267 }
268
269 pub fn execute_ready_upgrade_tx(
271 &mut self,
272 ready_tx: Ready<Upgrade>,
273 ) -> Result<Upgrade, InterpreterError<S::DataError>> {
274 self.interpreter.upgrade(ready_tx)
275 }
276
277 pub fn upload(
279 &mut self,
280 checked: Checked<Upload>,
281 ) -> Result<Upload, InterpreterError<S::DataError>> {
282 let gas_price = self.interpreter.gas_price();
283 let gas_costs = self.interpreter.gas_costs();
284 let fee_params = self.interpreter.fee_params();
285
286 let ready = checked
287 .into_ready(gas_price, gas_costs, fee_params, None)
288 .map_err(InterpreterError::CheckError)?;
289
290 self.execute_ready_upload_tx(ready)
291 }
292
293 pub fn execute_ready_upload_tx(
295 &mut self,
296 ready_tx: Ready<Upload>,
297 ) -> Result<Upload, InterpreterError<S::DataError>> {
298 self.interpreter.upload(ready_tx)
299 }
300
301 pub fn blob(
303 &mut self,
304 checked: Checked<Blob>,
305 ) -> Result<Blob, InterpreterError<S::DataError>> {
306 let gas_price = self.interpreter.gas_price();
307 let gas_costs = self.interpreter.gas_costs();
308 let fee_params = self.interpreter.fee_params();
309
310 let ready = checked
311 .into_ready(gas_price, gas_costs, fee_params, None)
312 .map_err(InterpreterError::CheckError)?;
313
314 self.execute_ready_blob_tx(ready)
315 }
316
317 pub fn execute_ready_blob_tx(
319 &mut self,
320 ready_tx: Ready<Blob>,
321 ) -> Result<Blob, InterpreterError<S::DataError>> {
322 self.interpreter.blob(ready_tx)
323 }
324}
325
326impl<M, S, Tx, Ecal, V> Transactor<M, S, Tx, Ecal, V>
327where
328 M: Memory,
329 S: InterpreterStorage,
330 Tx: ExecutableTransaction,
331 <Tx as IntoChecked>::Metadata: CheckedMetadata,
332 Ecal: EcalHandler,
333 V: Verifier,
334{
335 pub fn transact(&mut self, tx: Checked<Tx>) -> &mut Self {
337 let gas_price = self.interpreter.gas_price();
338 let gas_costs = self.interpreter.gas_costs();
339 let fee_params = self.interpreter.fee_params();
340 let block_height = self.interpreter.context().block_height();
341
342 let res = tx
343 .into_ready(gas_price, gas_costs, fee_params, block_height)
344 .map_err(InterpreterError::CheckError);
345 match res {
346 Ok(ready_tx) => self.transact_ready_tx(ready_tx),
347 Err(e) => self.handle_error(e),
348 }
349 }
350
351 pub fn transact_ready_tx(&mut self, ready_tx: Ready<Tx>) -> &mut Self {
353 match self.interpreter.transact(ready_tx) {
354 Ok(s) => {
355 self.program_state.replace(s.into());
356 self.error.take();
357 self
358 }
359
360 Err(e) => self.handle_error(e),
361 }
362 }
363
364 fn handle_error(&mut self, error: InterpreterError<S::DataError>) -> &mut Self {
365 self.program_state.take();
366 self.error.replace(error);
367 self
368 }
369}
370
371impl<M, S, Tx, Ecal, V> From<Interpreter<M, S, Tx, Ecal, V>>
372 for Transactor<M, S, Tx, Ecal, V>
373where
374 Tx: ExecutableTransaction,
375 S: InterpreterStorage,
376{
377 fn from(interpreter: Interpreter<M, S, Tx, Ecal, V>) -> Self {
378 let program_state = None;
379 let error = None;
380
381 Self {
382 interpreter,
383 program_state,
384 error,
385 }
386 }
387}
388
389impl<M, S, Tx, Ecal, V> From<Transactor<M, S, Tx, Ecal, V>>
390 for Interpreter<M, S, Tx, Ecal, V>
391where
392 Tx: ExecutableTransaction,
393 S: InterpreterStorage,
394{
395 fn from(transactor: Transactor<M, S, Tx, Ecal, V>) -> Self {
396 transactor.interpreter
397 }
398}
399
400impl<M, S, Tx, Ecal, V> AsRef<Interpreter<M, S, Tx, Ecal, V>>
401 for Transactor<M, S, Tx, Ecal, V>
402where
403 Tx: ExecutableTransaction,
404 S: InterpreterStorage,
405 Ecal: EcalHandler,
406{
407 fn as_ref(&self) -> &Interpreter<M, S, Tx, Ecal, V> {
408 &self.interpreter
409 }
410}
411
412impl<M, S, Tx, Ecal, V> AsRef<S> for Transactor<M, S, Tx, Ecal, V>
413where
414 Tx: ExecutableTransaction,
415 S: InterpreterStorage,
416{
417 fn as_ref(&self) -> &S {
418 self.interpreter.as_ref()
419 }
420}
421
422impl<M, S, Tx, Ecal, V> AsMut<S> for Transactor<M, S, Tx, Ecal, V>
423where
424 Tx: ExecutableTransaction,
425 S: InterpreterStorage,
426{
427 fn as_mut(&mut self) -> &mut S {
428 self.interpreter.as_mut()
429 }
430}
431
432#[cfg(feature = "test-helpers")]
433impl<S, Tx, Ecal, V> Default for Transactor<MemoryInstance, S, Tx, Ecal, V>
434where
435 S: InterpreterStorage + Default,
436 Tx: ExecutableTransaction,
437 Ecal: EcalHandler + Default,
438 V: Verifier + Default,
439{
440 fn default() -> Self {
441 Self::new(
442 MemoryInstance::new(),
443 S::default(),
444 InterpreterParams::default(),
445 )
446 }
447}