fuel-vm 0.2.0

FuelVM interpreter.
Documentation
use super::Interpreter;
use crate::consts::*;
use crate::context::Context;
use crate::error::InterpreterError;
use crate::storage::InterpreterStorage;

use fuel_tx::consts::*;
use fuel_tx::{Input, Transaction};
use fuel_types::bytes::{SerializableVec, SizedBytes};
use fuel_types::{Color, Word};
use itertools::Itertools;

use std::{io, mem};

const WORD_SIZE: usize = mem::size_of::<Word>();

impl<S> Interpreter<S>
where
    S: InterpreterStorage,
{
    pub(crate) fn init(&mut self, mut tx: Transaction) -> Result<(), InterpreterError> {
        tx.validate(self.block_height() as Word)?;
        tx.precompute_metadata();

        self.block_height = self.storage.block_height().map_err(InterpreterError::from_io)?;
        self.context = Context::from(&tx);

        self.frames.clear();
        self.receipts.clear();

        // Optimized for memset
        self.registers.iter_mut().for_each(|r| *r = 0);

        self.registers[REG_ONE] = 1;
        self.registers[REG_SSP] = 0;

        // Set heap area
        self.registers[REG_HP] = VM_MAX_RAM - 1;

        self.push_stack(tx.id().as_ref())
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

        let zeroes = &[0; MAX_INPUTS as usize * (Color::LEN + WORD_SIZE)];
        let ssp = self.registers[REG_SSP] as usize;

        self.push_stack(zeroes)
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

        if tx.is_script() {
            tx.inputs()
                .iter()
                .filter_map(|input| match input {
                    Input::Coin { color, amount, .. } => Some((color, amount)),
                    _ => None,
                })
                .sorted_by_key(|i| i.0)
                .take(MAX_INPUTS as usize)
                .fold(ssp, |mut ssp, (color, amount)| {
                    self.memory[ssp..ssp + Color::LEN].copy_from_slice(color.as_ref());
                    ssp += Color::LEN;

                    self.memory[ssp..ssp + WORD_SIZE].copy_from_slice(&amount.to_be_bytes());
                    ssp += WORD_SIZE;

                    ssp
                });
        }

        let tx_size = tx.serialized_size() as Word;

        if tx.is_script() {
            self.registers[REG_GGAS] = tx.gas_limit();
            self.registers[REG_CGAS] = tx.gas_limit();
        }

        self.push_stack(&tx_size.to_be_bytes())
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
        self.push_stack(tx.to_bytes().as_slice())
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

        self.registers[REG_SP] = self.registers[REG_SSP];

        self.tx = tx;

        Ok(())
    }
}