fuel-vm 0.2.0

FuelVM interpreter.
Documentation
use super::Interpreter;
use crate::call::CallFrame;
use crate::consts::*;
use crate::state::{Breakpoint, DebugEval, ProgramState};

impl<S> Interpreter<S> {
    /// Set a new breakpoint for the provided location.
    pub fn set_breakpoint(&mut self, breakpoint: Breakpoint) {
        self.debugger.set_breakpoint(breakpoint)
    }

    /// Remove a previously set breakpoint.
    pub fn remove_breakpoint(&mut self, breakpoint: &Breakpoint) {
        self.debugger.remove_breakpoint(breakpoint)
    }

    pub(crate) fn eval_debugger_state(&mut self) -> DebugEval {
        let debugger = &mut self.debugger;

        let contract = self.frames.last().map(CallFrame::to);
        let pc = self.registers[REG_PC].saturating_sub(self.registers[REG_IS]);

        debugger.eval_state(contract, pc)
    }

    pub(crate) fn debugger_set_last_state(&mut self, state: ProgramState) {
        self.debugger.set_last_state(state)
    }

    pub(crate) const fn debugger_last_state(&self) -> &Option<ProgramState> {
        self.debugger.last_state()
    }
}

#[test]
fn breakpoint_script() {
    use crate::consts::*;
    use crate::prelude::*;

    let mut vm = Interpreter::with_memory_storage();

    let gas_price = 0;
    let gas_limit = 1_000_000;
    let maturity = 0;

    let script = vec![
        Opcode::ADDI(0x10, REG_ZERO, 8),
        Opcode::ADDI(0x11, REG_ZERO, 16),
        Opcode::ADDI(0x12, REG_ZERO, 32),
        Opcode::ADDI(0x13, REG_ZERO, 64),
        Opcode::ADDI(0x14, REG_ZERO, 128),
        Opcode::RET(0x10),
    ]
    .iter()
    .copied()
    .collect();

    let tx = Transaction::script(gas_price, gas_limit, maturity, script, vec![], vec![], vec![], vec![]);

    let suite = vec![
        (
            Breakpoint::script(0),
            vec![(0x10, 0), (0x11, 0), (0x12, 0), (0x13, 0), (0x14, 0)],
        ),
        (
            Breakpoint::script(2),
            vec![(0x10, 8), (0x11, 16), (0x12, 0), (0x13, 0), (0x14, 0)],
        ),
        (
            Breakpoint::script(3),
            vec![(0x10, 8), (0x11, 16), (0x12, 32), (0x13, 0), (0x14, 0)],
        ),
        (
            Breakpoint::script(5),
            vec![(0x10, 8), (0x11, 16), (0x12, 32), (0x13, 64), (0x14, 128)],
        ),
    ];

    suite.iter().for_each(|(b, _)| vm.set_breakpoint(*b));

    let state = vm
        .transact(tx)
        .map(ProgramState::from)
        .expect("Failed to execute script!");

    suite.into_iter().fold(state, |state, (breakpoint, registers)| {
        let debug = state.debug_ref().expect("Expected breakpoint");
        let b = debug.breakpoint().expect("State without expected breakpoint");

        assert_eq!(&breakpoint, b);
        registers.into_iter().for_each(|(r, w)| {
            assert_eq!(w, vm.registers()[r]);
        });

        vm.resume().expect("Failed to resume")
    });
}