wevm-core 0.4.1

Waves Enterprise Virtual Machine for WASM smart-contracts
Documentation
use crate::{
    error::{Error, ExecutableError, Result},
    runtime::utils,
};

#[derive(Debug, Eq, PartialEq)]
pub enum DataEntry {
    Integer(i64),
    Boolean(i32),
    Binary(Vec<u8>),
    String(Vec<u8>),
}

impl DataEntry {
    pub fn serialize(&self, key: Option<&[u8]>) -> Vec<u8> {
        let mut result: Vec<u8> = vec![];

        match key {
            Some(bytes) => {
                result.extend_from_slice(&(bytes.len() as u16).to_be_bytes());
                result.extend_from_slice(bytes);
            }
            None => result.extend_from_slice(&0u16.to_be_bytes()),
        }

        match self {
            Self::Integer(value) => {
                result.push(0u8);
                result.extend_from_slice(&value.to_be_bytes());
            }
            Self::Boolean(value) => {
                result.push(1u8);
                result.push(*value as u8);
            }
            Self::Binary(value) => {
                result.push(2u8);
                result.extend_from_slice(&(value.len() as u32).to_be_bytes());
                result.extend_from_slice(value);
            }
            Self::String(value) => {
                result.push(3u8);
                result.extend_from_slice(&(value.len() as u32).to_be_bytes());
                result.extend_from_slice(value);
            }
        }

        result
    }

    pub fn deserialize(input: &[u8]) -> Result<Self> {
        let mut offset_input: usize = 0;

        Self::skip_key(input, &mut offset_input)?;
        Self::get_value(input, &mut offset_input)
    }

    pub fn deserialize_params(
        input: &[u8],
        output: &mut [u8],
        offset_output: &mut usize,
    ) -> Result<Vec<String>> {
        let mut offset_input: usize = 0;

        let mut params: Vec<String> = vec![];

        if input.is_empty() {
            return Ok(params);
        }

        let mut count = utils::get_u16(input, &mut offset_input)?;
        while count > 0 {
            Self::skip_key(input, &mut offset_input)?;
            match Self::get_value(input, &mut offset_input)? {
                Self::Integer(value) => params.push(format!("{}", value)),
                Self::Boolean(value) => params.push(format!("{}", value)),
                Self::Binary(value) => {
                    let length = value.len();
                    let offset_o = *offset_output;
                    output[offset_o..offset_o + length].copy_from_slice(value.as_slice());
                    params.push(format!("{}", *offset_output));
                    params.push(format!("{}", length));
                    *offset_output += length;
                }
                Self::String(value) => {
                    let length = value.len();
                    let offset_o = *offset_output;
                    output[offset_o..offset_o + length].copy_from_slice(value.as_slice());
                    params.push(format!("{}", *offset_output));
                    params.push(format!("{}", length));
                    *offset_output += length;
                }
            }
            count -= 1;
        }

        Ok(params)
    }

    fn skip_key(input: &[u8], offset: &mut usize) -> Result<()> {
        let length = utils::get_u16(input, offset)?;
        *offset += length as usize;
        Ok(())
    }

    fn get_value(input: &[u8], offset: &mut usize) -> Result<Self> {
        let byte = utils::get_u8(input, offset)?;

        match byte {
            0u8 => {
                let integer = utils::get_u64(input, offset)?;
                Ok(Self::Integer(integer as i64))
            }
            1u8 => {
                let boolean = utils::get_u8(input, offset)?;
                Ok(Self::Boolean(boolean as i32))
            }
            2u8 => {
                let length = utils::get_u32(input, offset)?;
                let binary = utils::get_bytes(input, offset, length as usize)?;
                Ok(Self::Binary(binary))
            }
            3u8 => {
                let length = utils::get_u32(input, offset)?;
                let string = utils::get_bytes(input, offset, length as usize)?;
                Ok(Self::String(string))
            }
            _ => Err(Error::Executable(ExecutableError::FailedDeserialize)),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::str::FromStr;

    #[test]
    fn test_deserialize() {
        let input = [
            0, 8, 116, 101, 115, 116, 95, 107, 101, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1,
        ];
        let result = DataEntry::deserialize(&input).expect("Error deserialize DataEntry");
        assert_eq!(result, DataEntry::Integer(1));

        let input = [0, 8, 116, 101, 115, 116, 95, 107, 101, 121, 1, 1];
        let result = DataEntry::deserialize(&input).expect("Error deserialize DataEntry");
        assert_eq!(result, DataEntry::Boolean(1));

        let vec: Vec<u8> = vec![116, 101, 115, 116, 95, 118, 97, 108, 117, 101];

        let input = [
            0, 8, 116, 101, 115, 116, 95, 107, 101, 121, 2, 0, 0, 0, 10, 116, 101, 115, 116, 95,
            118, 97, 108, 117, 101,
        ];
        let result = DataEntry::deserialize(&input).expect("Error deserialize DataEntry");
        assert_eq!(result, DataEntry::Binary(vec.clone()));

        let input = [
            0, 8, 116, 101, 115, 116, 95, 107, 101, 121, 3, 0, 0, 0, 10, 116, 101, 115, 116, 95,
            118, 97, 108, 117, 101,
        ];
        let result = DataEntry::deserialize(&input).expect("Error deserialize DataEntry");
        assert_eq!(result, DataEntry::String(vec.clone()));
    }

    #[test]
    fn test_deserialize_params() {
        let input = [
            0, 4, 0, 8, 116, 101, 115, 116, 95, 107, 101, 121, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 8,
            116, 101, 115, 116, 95, 107, 101, 121, 1, 1, 0, 8, 116, 101, 115, 116, 95, 107, 101,
            121, 2, 0, 0, 0, 10, 116, 101, 115, 116, 95, 118, 97, 108, 117, 101, 0, 8, 116, 101,
            115, 116, 95, 107, 101, 121, 3, 0, 0, 0, 10, 116, 101, 115, 116, 95, 118, 97, 108, 117,
            101,
        ];

        let mut memory = [0u8; 1000];
        let mut offset_memory = 100;

        let result = DataEntry::deserialize_params(&input, &mut memory, &mut offset_memory)
            .expect("Error deserialize DataEntry");

        assert_eq!(result.len(), 6);
        assert_eq!(result[0], "1");
        assert_eq!(result[1], "1");

        let data = [116, 101, 115, 116, 95, 118, 97, 108, 117, 101];

        let offset = usize::from_str(&result[2]).expect("Failed usize from_str");
        let length = usize::from_str(&result[3]).expect("Failed usize from_str");
        assert_eq!(memory[offset..offset + length], data);

        let offset = usize::from_str(&result[4]).expect("Failed usize from_str");
        let length = usize::from_str(&result[5]).expect("Failed usize from_str");
        assert_eq!(memory[offset..offset + length], data);
    }
}