fuel_vm/
state.rs

1//! Runtime state representation for the VM
2
3use alloc::vec::Vec;
4
5use fuel_tx::Receipt;
6use fuel_types::{
7    Bytes32,
8    Word,
9};
10
11mod debug;
12
13mod debugger;
14
15pub use debug::{
16    Breakpoint,
17    DebugEval,
18};
19
20pub use debugger::Debugger;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23/// Resulting state of an instruction set execution.
24pub enum ExecuteState {
25    /// The VM should proceed normally with the execution.
26    Proceed,
27    /// The current context returned a [`Word`].
28    Return(Word),
29    /// The current context returned some data represented as its digest.
30    ReturnData(Bytes32),
31    /// The set execution resulted in a `RVRT` instruction.
32    Revert(Word),
33
34    /// A debug event was reached.
35    DebugEvent(DebugEval),
36}
37
38impl ExecuteState {
39    /// Return true if the VM execution should continue.
40    pub const fn should_continue(&self) -> bool {
41        matches!(self, Self::Proceed | Self::DebugEvent(DebugEval::Continue))
42    }
43}
44
45impl Default for ExecuteState {
46    fn default() -> Self {
47        Self::Proceed
48    }
49}
50
51impl From<DebugEval> for ExecuteState {
52    fn from(d: DebugEval) -> Self {
53        Self::DebugEvent(d)
54    }
55}
56
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
58#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
59/// Resulting state of a transaction/program execution.
60pub enum ProgramState {
61    /// The transaction returned a [`Word`].
62    Return(Word),
63    /// The transaction returned some data represented as its digest.
64    ReturnData(Bytes32),
65    /// The transaction execution resulted in a `RVRT` instruction.
66    Revert(Word),
67
68    /// A debug event was reached for the transaction. The VM is suspended.
69    RunProgram(DebugEval),
70
71    /// A debug event was reached for a predicate verification. The VM is
72    /// suspended.
73    VerifyPredicate(DebugEval),
74}
75
76impl PartialEq<Breakpoint> for ProgramState {
77    fn eq(&self, other: &Breakpoint) -> bool {
78        match self.debug_ref() {
79            Some(&DebugEval::Breakpoint(b)) => &b == other,
80            _ => false,
81        }
82    }
83}
84
85impl ProgramState {
86    /// Debug event representation.
87    ///
88    /// Will return `None` if no debug event was reached.
89    pub const fn debug_ref(&self) -> Option<&DebugEval> {
90        match self {
91            Self::RunProgram(d) | Self::VerifyPredicate(d) => Some(d),
92            _ => None,
93        }
94    }
95
96    /// Return `true` if a debug event was reached.
97    pub const fn is_debug(&self) -> bool {
98        self.debug_ref().is_some()
99    }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
103/// Representation of the result of a transaction execution.
104pub struct StateTransition<Tx> {
105    state: ProgramState,
106    tx: Tx,
107    receipts: Vec<Receipt>,
108}
109
110impl<Tx> StateTransition<Tx> {
111    /// Create a new state transition representation.
112    pub const fn new(state: ProgramState, tx: Tx, receipts: Vec<Receipt>) -> Self {
113        Self {
114            state,
115            tx,
116            receipts,
117        }
118    }
119
120    /// Program state representation.
121    pub const fn state(&self) -> &ProgramState {
122        &self.state
123    }
124
125    /// Resulting mutated transaction after VM execution.
126    pub const fn tx(&self) -> &Tx {
127        &self.tx
128    }
129
130    /// Flag whether the client should revert after execution.
131    pub fn should_revert(&self) -> bool {
132        self.receipts
133            .iter()
134            .any(|r| matches!(r, Receipt::Revert { .. } | Receipt::Panic { .. }))
135    }
136
137    /// Transaction receipts representing the state transition.
138    pub fn receipts(&self) -> &[Receipt] {
139        self.receipts.as_slice()
140    }
141
142    /// Convert this instance into its internal attributes.
143    pub fn into_inner(self) -> (ProgramState, Tx, Vec<Receipt>) {
144        (self.state, self.tx, self.receipts)
145    }
146}
147
148impl<Tx> From<StateTransition<Tx>> for ProgramState {
149    fn from(t: StateTransition<Tx>) -> ProgramState {
150        t.state
151    }
152}
153
154#[derive(Debug, Clone, Copy, PartialEq, Eq)]
155/// Zero-copy Representation of the result of a transaction execution bound to
156/// the lifetime of the VM.
157pub struct StateTransitionRef<'a, Tx> {
158    state: ProgramState,
159    tx: &'a Tx,
160    receipts: &'a [Receipt],
161}
162
163impl<'a, Tx> StateTransitionRef<'a, Tx> {
164    /// Create a new by reference state transition representation.
165    pub const fn new(state: ProgramState, tx: &'a Tx, receipts: &'a [Receipt]) -> Self {
166        Self {
167            state,
168            tx,
169            receipts,
170        }
171    }
172
173    /// Program state representation.
174    pub const fn state(&self) -> &ProgramState {
175        &self.state
176    }
177
178    /// Resulting mutated transaction after VM execution.
179    pub const fn tx(&self) -> &Tx {
180        self.tx
181    }
182
183    /// Transaction receipts representing the state transition.
184    pub const fn receipts(&self) -> &[Receipt] {
185        self.receipts
186    }
187
188    /// Flag whether the client should revert after execution.
189    pub fn should_revert(&self) -> bool {
190        self.receipts
191            .iter()
192            .any(|r| matches!(r, Receipt::Revert { .. } | Receipt::Panic { .. }))
193    }
194}
195
196impl<'a, Tx> From<&'a StateTransition<Tx>> for StateTransitionRef<'a, Tx> {
197    fn from(t: &'a StateTransition<Tx>) -> StateTransitionRef<'a, Tx> {
198        Self {
199            state: *t.state(),
200            tx: t.tx(),
201            receipts: t.receipts(),
202        }
203    }
204}
205
206impl<'a, Tx: Clone> From<StateTransitionRef<'a, Tx>> for StateTransition<Tx> {
207    fn from(t: StateTransitionRef<Tx>) -> StateTransition<Tx> {
208        StateTransition {
209            state: *t.state(),
210            tx: t.tx().clone(),
211            receipts: t.receipts().to_vec(),
212        }
213    }
214}
215
216impl<'a, Tx: Clone> From<StateTransitionRef<'a, Tx>> for ProgramState {
217    fn from(t: StateTransitionRef<'a, Tx>) -> ProgramState {
218        t.state
219    }
220}