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};
27use fuel_tx::{
28 Blob,
29 Create,
30 FeeParameters,
31 GasCosts,
32 Receipt,
33 Script,
34 Upgrade,
35 Upload,
36};
37
38#[cfg(any(test, feature = "test-helpers"))]
39use crate::interpreter::MemoryInstance;
40
41#[derive(Debug)]
42pub struct Transactor<M, S, Tx, Ecal = NotSupportedEcal>
50where
51 S: InterpreterStorage,
52{
53 interpreter: Interpreter<M, S, Tx, Ecal>,
54 program_state: Option<ProgramState>,
55 error: Option<InterpreterError<S::DataError>>,
56}
57
58impl<M, S, Tx, Ecal> Transactor<M, S, Tx, Ecal>
59where
60 S: InterpreterStorage,
61 Tx: ExecutableTransaction,
62 Ecal: EcalHandler + Default,
63{
64 pub fn new(memory: M, storage: S, interpreter_params: InterpreterParams) -> Self {
66 Self {
67 interpreter: Interpreter::<M, S, Tx, Ecal>::with_storage(
68 memory,
69 storage,
70 interpreter_params,
71 ),
72 program_state: None,
73 error: None,
74 }
75 }
76}
77impl<M, S, Tx, Ecal> Transactor<M, S, Tx, Ecal>
78where
79 S: InterpreterStorage,
80 Tx: ExecutableTransaction,
81 Ecal: EcalHandler,
82{
83 pub fn state_transition(&self) -> Option<StateTransitionRef<'_, Tx>> {
88 self.program_state.map(|state| {
89 StateTransitionRef::new(
90 state,
91 self.interpreter.transaction(),
92 self.interpreter.receipts(),
93 )
94 })
95 }
96
97 pub fn to_owned_state_transition(&self) -> Option<StateTransition<Tx>> {
102 self.program_state.map(|state| {
103 StateTransition::new(
104 state,
105 self.interpreter.transaction().clone(),
106 self.interpreter.receipts().to_vec(),
107 )
108 })
109 }
110
111 pub const fn error(&self) -> Option<&InterpreterError<S::DataError>> {
119 self.error.as_ref()
120 }
121
122 pub const fn is_success(&self) -> bool {
124 !self.is_reverted()
125 }
126
127 pub const fn is_reverted(&self) -> bool {
129 self.error.is_some()
130 || matches!(self.program_state, Some(ProgramState::Revert(_)))
131 }
132
133 pub fn result(
137 &self,
138 ) -> Result<StateTransitionRef<'_, Tx>, &InterpreterError<S::DataError>> {
139 let state = self.state_transition();
140 let error = self.error.as_ref();
141
142 match (state, error) {
143 (Some(s), None) => Ok(s),
144 (None, Some(e)) => Err(e),
145
146 _ => Err(&InterpreterError::NoTransactionInitialized),
148 }
149 }
150
151 pub fn interpreter(&self) -> &Interpreter<M, S, Tx, Ecal> {
153 &self.interpreter
154 }
155
156 pub fn gas_costs(&self) -> &GasCosts {
158 self.interpreter.gas_costs()
159 }
160
161 pub fn fee_params(&self) -> &FeeParameters {
163 self.interpreter.fee_params()
164 }
165
166 #[cfg(feature = "test-helpers")]
167 pub fn set_gas_price(&mut self, gas_price: u64) {
169 self.interpreter.set_gas_price(gas_price);
170 }
171
172 pub fn tx_offset(&self) -> usize {
174 self.interpreter.tx_offset()
175 }
176}
177
178impl<M, S, Ecal> Transactor<M, S, Script, Ecal>
179where
180 M: Memory,
181 S: InterpreterStorage,
182{
183 pub fn receipts(&self) -> Option<&[Receipt]> {
188 self.program_state
189 .is_some()
190 .then(|| self.interpreter.receipts())
191 }
192
193 pub fn backtrace(&self) -> Option<Backtrace> {
196 self.receipts()
197 .and_then(|r| r.iter().find_map(Receipt::result))
198 .copied()
199 .map(|result| Backtrace::from_vm_error(&self.interpreter, result))
200 }
201}
202
203impl<M, S, Tx, Ecal> Transactor<M, S, Tx, Ecal>
204where
205 S: InterpreterStorage,
206{
207 pub fn deploy(
209 &mut self,
210 checked: Checked<Create>,
211 ) -> Result<Create, InterpreterError<S::DataError>> {
212 let gas_price = self.interpreter.gas_price();
213 let gas_costs = self.interpreter.gas_costs();
214 let fee_params = self.interpreter.fee_params();
215
216 let ready = checked
217 .into_ready(gas_price, gas_costs, fee_params, None)
218 .map_err(InterpreterError::CheckError)?;
219
220 self.deploy_ready_tx(ready)
221 }
222
223 pub fn deploy_ready_tx(
225 &mut self,
226 ready_tx: Ready<Create>,
227 ) -> Result<Create, InterpreterError<S::DataError>> {
228 self.interpreter.deploy(ready_tx)
229 }
230
231 pub fn upgrade(
233 &mut self,
234 checked: Checked<Upgrade>,
235 ) -> Result<Upgrade, InterpreterError<S::DataError>> {
236 let gas_price = self.interpreter.gas_price();
237 let gas_costs = self.interpreter.gas_costs();
238 let fee_params = self.interpreter.fee_params();
239
240 let ready = checked
241 .into_ready(gas_price, gas_costs, fee_params, None)
242 .map_err(InterpreterError::CheckError)?;
243
244 self.execute_ready_upgrade_tx(ready)
245 }
246
247 pub fn execute_ready_upgrade_tx(
249 &mut self,
250 ready_tx: Ready<Upgrade>,
251 ) -> Result<Upgrade, InterpreterError<S::DataError>> {
252 self.interpreter.upgrade(ready_tx)
253 }
254
255 pub fn upload(
257 &mut self,
258 checked: Checked<Upload>,
259 ) -> Result<Upload, InterpreterError<S::DataError>> {
260 let gas_price = self.interpreter.gas_price();
261 let gas_costs = self.interpreter.gas_costs();
262 let fee_params = self.interpreter.fee_params();
263
264 let ready = checked
265 .into_ready(gas_price, gas_costs, fee_params, None)
266 .map_err(InterpreterError::CheckError)?;
267
268 self.execute_ready_upload_tx(ready)
269 }
270
271 pub fn execute_ready_upload_tx(
273 &mut self,
274 ready_tx: Ready<Upload>,
275 ) -> Result<Upload, InterpreterError<S::DataError>> {
276 self.interpreter.upload(ready_tx)
277 }
278
279 pub fn blob(
281 &mut self,
282 checked: Checked<Blob>,
283 ) -> Result<Blob, InterpreterError<S::DataError>> {
284 let gas_price = self.interpreter.gas_price();
285 let gas_costs = self.interpreter.gas_costs();
286 let fee_params = self.interpreter.fee_params();
287
288 let ready = checked
289 .into_ready(gas_price, gas_costs, fee_params, None)
290 .map_err(InterpreterError::CheckError)?;
291
292 self.execute_ready_blob_tx(ready)
293 }
294
295 pub fn execute_ready_blob_tx(
297 &mut self,
298 ready_tx: Ready<Blob>,
299 ) -> Result<Blob, InterpreterError<S::DataError>> {
300 self.interpreter.blob(ready_tx)
301 }
302}
303
304impl<M, S, Tx, Ecal> Transactor<M, S, Tx, Ecal>
305where
306 M: Memory,
307 S: InterpreterStorage,
308 Tx: ExecutableTransaction,
309 <Tx as IntoChecked>::Metadata: CheckedMetadata,
310 Ecal: EcalHandler,
311{
312 pub fn transact(&mut self, tx: Checked<Tx>) -> &mut Self {
314 let gas_price = self.interpreter.gas_price();
315 let gas_costs = self.interpreter.gas_costs();
316 let fee_params = self.interpreter.fee_params();
317 let block_height = self.interpreter.context().block_height();
318
319 match tx
320 .into_ready(gas_price, gas_costs, fee_params, block_height)
321 .map_err(InterpreterError::CheckError)
322 {
323 Ok(ready_tx) => self.transact_ready_tx(ready_tx),
324 Err(e) => self.handle_error(e),
325 }
326 }
327
328 pub fn transact_ready_tx(&mut self, ready_tx: Ready<Tx>) -> &mut Self {
330 match self.interpreter.transact(ready_tx) {
331 Ok(s) => {
332 self.program_state.replace(s.into());
333 self.error.take();
334 self
335 }
336
337 Err(e) => self.handle_error(e),
338 }
339 }
340
341 fn handle_error(&mut self, error: InterpreterError<S::DataError>) -> &mut Self {
342 self.program_state.take();
343 self.error.replace(error);
344 self
345 }
346}
347
348impl<M, S, Tx, Ecal> From<Interpreter<M, S, Tx, Ecal>> for Transactor<M, S, Tx, Ecal>
349where
350 Tx: ExecutableTransaction,
351 S: InterpreterStorage,
352{
353 fn from(interpreter: Interpreter<M, S, Tx, Ecal>) -> Self {
354 let program_state = None;
355 let error = None;
356
357 Self {
358 interpreter,
359 program_state,
360 error,
361 }
362 }
363}
364
365impl<M, S, Tx, Ecal> From<Transactor<M, S, Tx, Ecal>> for Interpreter<M, S, Tx, Ecal>
366where
367 Tx: ExecutableTransaction,
368 S: InterpreterStorage,
369{
370 fn from(transactor: Transactor<M, S, Tx, Ecal>) -> Self {
371 transactor.interpreter
372 }
373}
374
375impl<M, S, Tx, Ecal> AsRef<Interpreter<M, S, Tx, Ecal>> for Transactor<M, S, Tx, Ecal>
376where
377 Tx: ExecutableTransaction,
378 S: InterpreterStorage,
379 Ecal: EcalHandler,
380{
381 fn as_ref(&self) -> &Interpreter<M, S, Tx, Ecal> {
382 &self.interpreter
383 }
384}
385
386impl<M, S, Tx, Ecal> AsRef<S> for Transactor<M, S, Tx, Ecal>
387where
388 Tx: ExecutableTransaction,
389 S: InterpreterStorage,
390{
391 fn as_ref(&self) -> &S {
392 self.interpreter.as_ref()
393 }
394}
395
396impl<M, S, Tx, Ecal> AsMut<S> for Transactor<M, S, Tx, Ecal>
397where
398 Tx: ExecutableTransaction,
399 S: InterpreterStorage,
400{
401 fn as_mut(&mut self) -> &mut S {
402 self.interpreter.as_mut()
403 }
404}
405
406#[cfg(feature = "test-helpers")]
407impl<S, Tx, Ecal> Default for Transactor<MemoryInstance, S, Tx, Ecal>
408where
409 S: InterpreterStorage + Default,
410 Tx: ExecutableTransaction,
411 Ecal: EcalHandler + Default,
412{
413 fn default() -> Self {
414 Self::new(
415 MemoryInstance::new(),
416 S::default(),
417 InterpreterParams::default(),
418 )
419 }
420}