fuel_vm/interpreter/
ecal.rs

1//! See `fuel-vm/examples/external.rs` for example usage.
2
3use fuel_asm::{
4    PanicReason,
5    RegId,
6};
7
8use crate::{
9    constraints::reg_key::{
10        split_registers,
11        SystemRegisters,
12    },
13    error::SimpleResult,
14    interpreter::NotSupportedEcal,
15};
16
17use super::{
18    internal::inc_pc,
19    Interpreter,
20    Memory,
21};
22
23/// ECAL opcode handler
24pub trait EcalHandler: Clone
25where
26    Self: Sized,
27{
28    /// Whether to increment PC after executing ECAL. If this is false,
29    /// the handler must increment PC itself.
30    const INC_PC: bool = true;
31
32    /// ECAL opcode handler
33    fn ecal<M, S, Tx>(
34        vm: &mut Interpreter<M, S, Tx, Self>,
35        a: RegId,
36        b: RegId,
37        c: RegId,
38        d: RegId,
39    ) -> SimpleResult<()>
40    where
41        M: Memory;
42}
43
44/// Default ECAL opcode handler function, which just errors immediately.
45impl EcalHandler for NotSupportedEcal {
46    fn ecal<M, S, Tx>(
47        _: &mut Interpreter<M, S, Tx, Self>,
48        _: RegId,
49        _: RegId,
50        _: RegId,
51        _: RegId,
52    ) -> SimpleResult<()> {
53        Err(PanicReason::EcalError)?
54    }
55}
56
57/// ECAL is not allowed in predicates
58#[derive(Debug, Clone, Copy, Default)]
59pub struct PredicateErrorEcal;
60
61/// ECAL is not allowed in predicates
62impl EcalHandler for PredicateErrorEcal {
63    fn ecal<M, S, Tx>(
64        _vm: &mut Interpreter<M, S, Tx, Self>,
65        _: RegId,
66        _: RegId,
67        _: RegId,
68        _: RegId,
69    ) -> SimpleResult<()> {
70        Err(PanicReason::ContractInstructionNotAllowed)?
71    }
72}
73
74impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
75where
76    M: Memory,
77    Ecal: EcalHandler,
78{
79    /// Executes ECAL opcode handler function and increments PC
80    pub(crate) fn external_call(
81        &mut self,
82        a: RegId,
83        b: RegId,
84        c: RegId,
85        d: RegId,
86    ) -> SimpleResult<()> {
87        Ecal::ecal(self, a, b, c, d)?;
88        let (SystemRegisters { pc, .. }, _) = split_registers(&mut self.registers);
89        if Ecal::INC_PC {
90            Ok(inc_pc(pc)?)
91        } else {
92            Ok(())
93        }
94    }
95}
96
97impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
98where
99    Ecal: EcalHandler,
100{
101    /// Read access to the ECAL state
102    pub fn ecal_state(&self) -> &Ecal {
103        &self.ecal_state
104    }
105
106    /// Write access to the ECAL state
107    pub fn ecal_state_mut(&mut self) -> &mut Ecal {
108        &mut self.ecal_state
109    }
110}