fuel-vm 0.66.3

FuelVM interpreter.
Documentation
use alloc::vec;

use crate::{
    consts::*,
    prelude::*,
};
use fuel_asm::{
    RegId,
    op,
};

#[test]
fn backtrace() {
    let mut test_context = TestBuilder::new(2322u64);
    let gas_limit = 1_000_000;
    let zero_gas_price = 0;

    #[rustfmt::skip]
    let invalid_instruction_bytecode = vec![op::noop()];

    let contract_undefined = test_context
        .setup_contract(invalid_instruction_bytecode, None, None)
        .contract_id;

    #[rustfmt::skip]
    let mut function_call = vec![
        op::movi(0x10,  (contract_undefined.as_ref().len() + WORD_SIZE * 2 + 1) as Immediate18),
        op::aloc(0x10),
    ];

    contract_undefined
        .as_ref()
        .iter()
        .enumerate()
        .for_each(|(i, b)| {
            function_call.push(op::movi(0x10, *b as Immediate18));
            function_call.push(op::sb(RegId::HP, 0x10, 1 + i as Immediate12));
        });

    function_call.push(op::addi(0x10, RegId::HP, 1));
    function_call.push(op::call(0x10, RegId::ZERO, 0x10, RegId::CGAS));
    function_call.push(op::ret(RegId::ONE));

    let contract_call = test_context
        .setup_contract(function_call, None, None)
        .contract_id;

    #[rustfmt::skip]
    let mut script = vec![
        op::movi(0x10, (contract_call.as_ref().len() + WORD_SIZE * 2 + 1) as Immediate18),
        op::aloc(0x10),
    ];

    contract_call
        .as_ref()
        .iter()
        .enumerate()
        .for_each(|(i, b)| {
            script.push(op::movi(0x10, *b as Immediate18));
            script.push(op::sb(RegId::HP, 0x10, i as Immediate12));
        });

    script.push(op::call(RegId::HP, RegId::ZERO, RegId::ZERO, RegId::CGAS));
    script.push(op::ret(RegId::ONE));

    let tx = test_context
        .start_script(script, vec![])
        .script_gas_limit(gas_limit)
        .contract_input(contract_undefined)
        .contract_input(contract_call)
        .fee_input()
        .contract_output(&contract_undefined)
        .contract_output(&contract_call)
        .build();

    let (_, backtrace) = test_context
        .execute_tx_with_backtrace(tx, zero_gas_price)
        .expect("Should execute tx");

    let backtrace = backtrace.expect("Expected erroneous state for undefined opcode");

    assert_eq!(backtrace.contract(), &contract_undefined);

    let id = backtrace.call_stack().last().expect("Caller expected").to();
    assert_eq!(id, &contract_undefined);

    let id = backtrace
        .call_stack()
        .first()
        .expect("Caller expected")
        .to();
    assert_eq!(id, &contract_call);
}