Skip to content

Commit

Permalink
Add debug test case for tx script
Browse files Browse the repository at this point in the history
  • Loading branch information
vlopes11 committed Jun 18, 2021
1 parent 15aae2d commit 2845d03
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 23 deletions.
24 changes: 21 additions & 3 deletions src/debug/debugger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ impl Breakpoint {
Self { contract, pc }
}

pub fn script(pc: Word) -> Self {
let contract = Default::default();

Self::new(contract, pc)
}

pub const fn contract(&self) -> &ContractAddress {
&self.contract
}
Expand Down Expand Up @@ -50,6 +56,13 @@ impl DebugEval {
_ => false,
}
}

pub const fn breakpoint(&self) -> Option<&Breakpoint> {
match self {
Self::Breakpoint(b) => Some(b),
_ => None,
}
}
}

#[derive(Debug, Default, Clone)]
Expand All @@ -59,7 +72,10 @@ pub struct Debugger {
}

impl Debugger {
pub fn set_breakpoint(&mut self, contract: ContractAddress, pc: Word) {
pub fn set_breakpoint(&mut self, breakpoint: Breakpoint) {
let contract = *breakpoint.contract();
let pc = breakpoint.pc();

self.breakpoints
.get_mut(&contract)
.map(|set| set.insert(pc))
Expand All @@ -73,8 +89,10 @@ impl Debugger {
});
}

pub fn remove_breakpoint(&mut self, contract: &ContractAddress, pc: Word) {
self.breakpoints.get_mut(contract).map(|set| set.remove(&pc));
pub fn remove_breakpoint(&mut self, breakpoint: &Breakpoint) {
self.breakpoints
.get_mut(breakpoint.contract())
.map(|set| set.remove(&breakpoint.pc()));
}

pub fn eval_state(&mut self, contract: ContractAddress, pc: Word) -> DebugEval {
Expand Down
22 changes: 6 additions & 16 deletions src/interpreter/debug.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,21 @@
use super::{Interpreter, ProgramState};
use crate::consts::*;
use crate::debug::DebugEval;

use fuel_asm::Word;
use fuel_tx::ContractAddress;
use crate::debug::{Breakpoint, DebugEval};

impl<S> Interpreter<S> {
pub fn set_breakpoint(&mut self, contract: Option<ContractAddress>, pc: Word) {
let contract = contract.unwrap_or_default();

self.debugger.set_breakpoint(contract, pc)
pub fn set_breakpoint(&mut self, breakpoint: Breakpoint) {
self.debugger.set_breakpoint(breakpoint)
}

pub fn remove_breakpoint(&mut self, contract: Option<ContractAddress>, pc: Word) {
let contract = contract.unwrap_or_default();

self.debugger.remove_breakpoint(&contract, pc)
pub fn remove_breakpoint(&mut self, breakpoint: &Breakpoint) {
self.debugger.remove_breakpoint(breakpoint)
}

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

let contract = self.frames.last().map(|f| f.to()).copied();
let pc = match &contract {
Some(_) => self.registers[REG_PC].saturating_sub(self.registers[REG_IS]),
None => self.registers[REG_PC],
};
let pc = self.registers[REG_PC].saturating_sub(self.registers[REG_IS]);

// Default contract address maps to unset contract target
let contract = contract.unwrap_or_default();
Expand Down
16 changes: 13 additions & 3 deletions src/interpreter/executors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,16 +225,23 @@ where

#[cfg(feature = "debug")]
pub fn resume(&mut self) -> Result<ProgramState, ExecuteError> {
match self
let state = self
.debugger_last_state()
.ok_or(ExecuteError::DebugStateNotInitialized)?
{
.ok_or(ExecuteError::DebugStateNotInitialized)?;

let state = match state {
ProgramState::Return(w) => Ok(ProgramState::Return(w)),

ProgramState::RunProgram(_) => self.run_program(),

ProgramState::VerifyPredicate(_) => unimplemented!(),
}?;

if state.is_debug() {
self.debugger_set_last_state(state.clone());
}

Ok(state)
}

pub fn run_program(&mut self) -> Result<ProgramState, ExecuteError> {
Expand All @@ -249,6 +256,8 @@ where
.map(Opcode::from_bytes_unchecked)
.ok_or(ExecuteError::ProgramOverflow)?;

println!("LEAK {:?}", op);

match self.execute(op)? {
ExecuteState::Return(r) => {
return Ok(ProgramState::Return(r));
Expand Down Expand Up @@ -324,6 +333,7 @@ where
#[cfg(feature = "debug")]
{
let debug = self.eval_debugger_state();
println!("EVAL {:?}", debug);
if !debug.should_continue() {
return Ok(debug.into());
}
Expand Down
7 changes: 6 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ pub mod interpreter;
pub mod prelude {
pub use crate::data::{InterpreterStorage, MemoryStorage, Storage};
pub use crate::debug::Debugger;
pub use crate::interpreter::{Call, CallFrame, Contract, ExecuteError, Interpreter, LogEvent, MemoryRange};
pub use crate::interpreter::{
Call, CallFrame, Contract, ExecuteError, Interpreter, LogEvent, MemoryRange, ProgramState,
};
pub use fuel_asm::{Immediate06, Immediate12, Immediate18, Immediate24, Opcode, RegisterId, Word};
pub use fuel_tx::{
bytes::{Deserializable, SerializableVec, SizedBytes},
Address, Color, ContractAddress, Hash, Input, Output, Salt, Transaction, ValidationError, Witness,
};

#[cfg(feature = "debug")]
pub use crate::debug::{Breakpoint, DebugEval};
}
61 changes: 61 additions & 0 deletions tests/interpreter/debug.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
use super::program_to_bytes;
use fuel_vm::consts::*;
use fuel_vm::prelude::*;

#[test]
fn breakpoint_script() {
let storage = MemoryStorage::default();
let mut vm = Interpreter::with_storage(storage);

let gas_price = 10;
let gas_limit = 1_000_000;
let maturity = 100;

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),
];
let script = program_to_bytes(script.as_slice());

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

vm.init(tx).expect("Failed to init VM!");

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

suite.iter().for_each(|(b, _)| vm.set_breakpoint(*b));
let state = vm.run().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")
});
}
3 changes: 3 additions & 0 deletions tests/interpreter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ mod flow;
mod memory;
mod predicate;

#[cfg(feature = "debug")]
mod debug;

pub use super::common;

pub fn program_to_bytes(program: &[Opcode]) -> Vec<u8> {
Expand Down

0 comments on commit 2845d03

Please sign in to comment.