fuel_vm/
backtrace.rs

1//! Backtrace implementation to track script errors.
2//!
3//! As of the moment, doesn't support predicates.
4
5use alloc::{
6    borrow::ToOwned,
7    vec::Vec,
8};
9
10use crate::{
11    call::CallFrame,
12    consts::*,
13    interpreter::{
14        InitialBalances,
15        Interpreter,
16    },
17};
18use educe::Educe;
19
20use crate::interpreter::{
21    Memory,
22    MemoryInstance,
23};
24use fuel_tx::ScriptExecutionResult;
25use fuel_types::{
26    ContractId,
27    Word,
28};
29
30#[derive(Educe)]
31#[educe(Debug)]
32/// Runtime description derived from a VM error.
33pub struct Backtrace {
34    call_stack: Vec<CallFrame>,
35    contract: ContractId,
36    registers: [Word; VM_REGISTER_COUNT],
37    memory: MemoryInstance,
38    result: ScriptExecutionResult,
39    initial_balances: InitialBalances,
40}
41
42impl Backtrace {
43    /// Create a backtrace from a vm instance and instruction result.
44    ///
45    /// This isn't copy-free and shouldn't be provided by default.
46    pub fn from_vm_error<M, S, Tx, Ecal>(
47        vm: &Interpreter<M, S, Tx, Ecal>,
48        result: ScriptExecutionResult,
49    ) -> Self
50    where
51        M: Memory,
52    {
53        let call_stack = vm.call_stack().to_owned();
54        let contract = vm.internal_contract().unwrap_or_default();
55        let memory = vm.memory().clone();
56        let initial_balances = vm.initial_balances().clone();
57        let mut registers = [0; VM_REGISTER_COUNT];
58
59        registers.copy_from_slice(vm.registers());
60
61        Self {
62            call_stack,
63            contract,
64            registers,
65            memory,
66            result,
67            initial_balances,
68        }
69    }
70
71    /// Call stack of the VM when the error occurred.
72    pub fn call_stack(&self) -> &[CallFrame] {
73        self.call_stack.as_slice()
74    }
75
76    /// Last contract of the context when the error occurred.
77    pub const fn contract(&self) -> &ContractId {
78        &self.contract
79    }
80
81    /// Register set when the error occurred.
82    pub const fn registers(&self) -> &[Word] {
83        &self.registers
84    }
85
86    /// Memory of the VM when the error occurred.
87    pub fn memory(&self) -> &MemoryInstance {
88        &self.memory
89    }
90
91    /// [`ScriptExecutionResult`] of the error that caused this backtrace.
92    pub const fn result(&self) -> &ScriptExecutionResult {
93        &self.result
94    }
95
96    /// The initial balances.
97    pub const fn initial_balances(&self) -> &InitialBalances {
98        &self.initial_balances
99    }
100
101    /// Expose the internal attributes of the backtrace.
102    pub fn into_inner(
103        self,
104    ) -> (
105        Vec<CallFrame>,
106        ContractId,
107        [Word; VM_REGISTER_COUNT],
108        MemoryInstance,
109        ScriptExecutionResult,
110        InitialBalances,
111    ) {
112        let Self {
113            call_stack,
114            contract,
115            registers,
116            memory,
117            result,
118            initial_balances,
119        } = self;
120
121        (
122            call_stack,
123            contract,
124            registers,
125            memory,
126            result,
127            initial_balances,
128        )
129    }
130}