Skip to content
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [Unreleased]

### Added

- [881](https://github.com/FuelLabs/fuel-vm/pull/881): Support for capturing execution traces.

### Fixed
- [879](https://github.com/FuelLabs/fuel-vm/pull/879): Debugger state wasn't propagated in contract contexts.
- [878](https://github.com/FuelLabs/fuel-vm/pull/878): Fix the transaction de/serialization that wasn't backward compatible with the addition of the new policy.
Expand Down
12 changes: 6 additions & 6 deletions fuel-vm/examples/external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ use fuel_vm::{
pub struct FileReadEcal;

impl EcalHandler for FileReadEcal {
fn ecal<M, S, Tx>(
vm: &mut Interpreter<M, S, Tx, Self>,
fn ecal<M, S, Tx, Trace>(
vm: &mut Interpreter<M, S, Tx, Self, Trace>,
a: RegId,
b: RegId,
c: RegId,
Expand Down Expand Up @@ -130,8 +130,8 @@ pub struct CounterEcal {
}

impl EcalHandler for CounterEcal {
fn ecal<M, S, Tx>(
vm: &mut Interpreter<M, S, Tx, Self>,
fn ecal<M, S, Tx, Trace>(
vm: &mut Interpreter<M, S, Tx, Self, Trace>,
a: RegId,
_b: RegId,
_c: RegId,
Expand Down Expand Up @@ -193,8 +193,8 @@ pub struct SharedCounterEcal {
}

impl EcalHandler for SharedCounterEcal {
fn ecal<M, S, Tx>(
vm: &mut Interpreter<M, S, Tx, Self>,
fn ecal<M, S, Tx, Trace>(
vm: &mut Interpreter<M, S, Tx, Self, Trace>,
a: RegId,
_b: RegId,
_c: RegId,
Expand Down
4 changes: 2 additions & 2 deletions fuel-vm/src/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ impl Backtrace {
/// Create a backtrace from a vm instance and instruction result.
///
/// This isn't copy-free and shouldn't be provided by default.
pub fn from_vm_error<M, S, Tx, Ecal>(
vm: &Interpreter<M, S, Tx, Ecal>,
pub fn from_vm_error<M, S, Tx, Ecal, Trace>(
vm: &Interpreter<M, S, Tx, Ecal, Trace>,
result: ScriptExecutionResult,
) -> Self
where
Expand Down
19 changes: 13 additions & 6 deletions fuel-vm/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ mod memory;
mod metadata;
mod post_execution;
mod receipts;
pub mod trace;

mod debug;
mod ecal;
Expand All @@ -86,6 +87,7 @@ pub use memory::{
Memory,
MemoryInstance,
MemoryRange,
MemorySliceChange,
};

use crate::checked_transaction::{
Expand All @@ -109,6 +111,10 @@ use self::receipts::ReceiptsCtx;
#[derive(Debug, Copy, Clone, Default)]
pub struct NotSupportedEcal;

/// Execution tracer is disabled.
#[derive(Debug, Copy, Clone, Default)]
pub struct NoTrace;

/// VM interpreter.
///
/// The internal state of the VM isn't expose because the intended usage is to
Expand All @@ -118,7 +124,7 @@ pub struct NotSupportedEcal;
/// These can be obtained with the help of a [`crate::transactor::Transactor`]
/// or a client implementation.
#[derive(Debug, Clone)]
pub struct Interpreter<M, S, Tx = (), Ecal = NotSupportedEcal> {
pub struct Interpreter<M, S, Tx = (), Ecal = NotSupportedEcal, Trace = NoTrace> {
registers: [Word; VM_REGISTER_COUNT],
memory: M,
frames: Vec<CallFrame>,
Expand All @@ -132,6 +138,7 @@ pub struct Interpreter<M, S, Tx = (), Ecal = NotSupportedEcal> {
context: Context,
balances: RuntimeBalances,
profiler: Profiler,
trace: Trace,
interpreter_params: InterpreterParams,
/// `PanicContext` after the latest execution. It is consumed by
/// `append_panic_receipt` and is `PanicContext::None` after consumption.
Expand Down Expand Up @@ -210,21 +217,21 @@ pub(crate) enum PanicContext {
ContractId(ContractId),
}

impl<M: Memory, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal> {
impl<M: Memory, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace> {
/// Returns the current state of the VM memory
pub fn memory(&self) -> &MemoryInstance {
self.memory.as_ref()
}
}

impl<M: AsMut<MemoryInstance>, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal> {
impl<M: AsMut<MemoryInstance>, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace> {
/// Returns mutable access to the vm memory
pub fn memory_mut(&mut self) -> &mut MemoryInstance {
self.memory.as_mut()
}
}

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal> {
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace> {
/// Returns the current state of the registers
pub const fn registers(&self) -> &[Word] {
&self.registers
Expand Down Expand Up @@ -356,13 +363,13 @@ fn current_location(
InstructionLocation::new(current_contract, offset)
}

impl<M, S, Tx, Ecal> AsRef<S> for Interpreter<M, S, Tx, Ecal> {
impl<M, S, Tx, Ecal, Trace> AsRef<S> for Interpreter<M, S, Tx, Ecal, Trace> {
fn as_ref(&self) -> &S {
&self.storage
}
}

impl<M, S, Tx, Ecal> AsMut<S> for Interpreter<M, S, Tx, Ecal> {
impl<M, S, Tx, Ecal, Trace> AsMut<S> for Interpreter<M, S, Tx, Ecal, Trace> {
fn as_mut(&mut self) -> &mut S {
&mut self.storage
}
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/alu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use fuel_types::{
mod muldiv;
mod wideint;

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
Tx: ExecutableTransaction,
{
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/alu/muldiv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use fuel_types::{
Word,
};

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
Tx: ExecutableTransaction,
{
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/alu/wideint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ macro_rules! wideint_ops {
$t::from_le_bytes(truncated)
}

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
M: Memory,
Tx: ExecutableTransaction,
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/balances.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl RuntimeBalances {

/// Write all assets into the start of VM stack, i.e. at $ssp.
/// Panics if the assets cannot fit.
pub fn to_vm<M, S, Tx, Ecal>(self, vm: &mut Interpreter<M, S, Tx, Ecal>)
pub fn to_vm<M, S, Tx, Ecal, Trace>(self, vm: &mut Interpreter<M, S, Tx, Ecal, Trace>)
where
M: Memory,
Tx: ExecutableTransaction,
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/blob.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use super::{
WriteRegKey,
};

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
M: Memory,
S: InterpreterStorage,
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ mod smo_tests;
#[cfg(test)]
mod test;

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
M: Memory,
Tx: ExecutableTransaction,
Expand Down
26 changes: 17 additions & 9 deletions fuel-vm/src/interpreter/constructors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#[cfg(any(test, feature = "test-helpers"))]
use super::{
trace::ExecutionTraceHooks,
ExecutableTransaction,
MemoryInstance,
};
Expand Down Expand Up @@ -33,10 +34,11 @@ use crate::{
storage::MemoryStorage,
};

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
Tx: Default,
Ecal: Default,
Trace: Default,
{
/// Create a new interpreter instance out of a storage implementation.
///
Expand All @@ -52,9 +54,10 @@ where
}
}

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
Tx: Default,
Trace: Default,
{
/// Create a new interpreter instance out of a storage implementation.
///
Expand All @@ -81,14 +84,15 @@ where
context: Context::default(),
balances: RuntimeBalances::default(),
profiler: Profiler::default(),
trace: Trace::default(),
interpreter_params,
panic_context: PanicContext::None,
ecal_state,
}
}
}

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal> {
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace> {
/// Sets a profiler for the VM
#[cfg(feature = "profile-any")]
pub fn with_profiler<P>(&mut self, receiver: P) -> &mut Self
Expand All @@ -101,14 +105,15 @@ impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal> {
}

#[cfg(any(test, feature = "test-helpers"))]
impl<S, Tx, Ecal> Default for Interpreter<MemoryInstance, S, Tx, Ecal>
impl<S, Tx, Ecal, Trace> Default for Interpreter<MemoryInstance, S, Tx, Ecal, Trace>
where
S: Default,
Tx: ExecutableTransaction,
Ecal: EcalHandler + Default,
Trace: Default,
{
fn default() -> Self {
Interpreter::<_, S, Tx, Ecal>::with_storage(
Interpreter::<_, S, Tx, Ecal, Trace>::with_storage(
MemoryInstance::new(),
Default::default(),
InterpreterParams::default(),
Expand All @@ -117,10 +122,11 @@ where
}

#[cfg(any(test, feature = "test-helpers"))]
impl<Tx, Ecal> Interpreter<MemoryInstance, (), Tx, Ecal>
impl<Tx, Ecal, Trace> Interpreter<MemoryInstance, (), Tx, Ecal, Trace>
where
Tx: ExecutableTransaction,
Ecal: EcalHandler + Default,
Trace: ExecutionTraceHooks + Default,
{
/// Create a new interpreter without a storage backend.
///
Expand All @@ -131,10 +137,11 @@ where
}

#[cfg(feature = "test-helpers")]
impl<Tx, Ecal> Interpreter<MemoryInstance, MemoryStorage, Tx, Ecal>
impl<Tx, Ecal, Trace> Interpreter<MemoryInstance, MemoryStorage, Tx, Ecal, Trace>
where
Tx: ExecutableTransaction,
Ecal: EcalHandler + Default,
Trace: ExecutionTraceHooks + Default,
{
/// Create a new storage with a provided in-memory storage.
///
Expand All @@ -145,16 +152,17 @@ where
}

#[cfg(feature = "test-helpers")]
impl<Tx, Ecal> Interpreter<MemoryInstance, MemoryStorage, Tx, Ecal>
impl<Tx, Ecal, Trace> Interpreter<MemoryInstance, MemoryStorage, Tx, Ecal, Trace>
where
Tx: ExecutableTransaction,
Ecal: EcalHandler,
Trace: ExecutionTraceHooks + Default,
{
/// Create a new storage with a provided in-memory storage.
///
/// It will have full capabilities.
pub fn with_memory_storage_and_ecal(ecal: Ecal) -> Self {
Interpreter::<_, MemoryStorage, Tx, Ecal>::with_storage_and_ecal(
Interpreter::<_, MemoryStorage, Tx, Ecal, Trace>::with_storage_and_ecal(
MemoryInstance::new(),
Default::default(),
InterpreterParams::default(),
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use fuel_types::{
ContractId,
};

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
M: Memory,
S: InterpreterStorage,
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use fuel_types::{
#[cfg(test)]
mod tests;

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
M: Memory,
Tx: ExecutableTransaction,
Expand Down
2 changes: 1 addition & 1 deletion fuel-vm/src/interpreter/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use super::Interpreter;
use crate::prelude::*;
use fuel_asm::RegId;

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
Tx: ExecutableTransaction,
{
Expand Down
8 changes: 4 additions & 4 deletions fuel-vm/src/interpreter/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use super::{
use crate::interpreter::memory::MemoryRollbackData;
use storage::*;

mod storage;
pub(crate) mod storage;

#[cfg(test)]
mod tests;
Expand Down Expand Up @@ -293,7 +293,7 @@ where
.map(|((index, a), b)| (index, a.cloned(), b.cloned()))
}

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
M: Memory,
{
Expand Down Expand Up @@ -363,7 +363,7 @@ where
}
}

impl<M, S, Tx, Ecal> Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> Interpreter<M, S, Tx, Ecal, Trace>
where
M: Memory,
{
Expand Down Expand Up @@ -444,7 +444,7 @@ fn invert_receipts_ctx(ctx: &mut ReceiptsCtx, value: &VecState<Option<Receipt>>)
invert_vec(ctx_mut.receipts_mut(), value);
}

impl<M, S, Tx, Ecal> PartialEq for Interpreter<M, S, Tx, Ecal>
impl<M, S, Tx, Ecal, Trace> PartialEq for Interpreter<M, S, Tx, Ecal, Trace>
where
M: Memory,
Tx: PartialEq,
Expand Down
Loading