essential-vm 0.13.0

The Essential VM
Documentation
use std::collections::HashMap;

use essential_types::convert::word_4_from_u8_32;

use super::*;

#[test]
fn test_pop_memory_address() {
    let mut stack = Stack::default();
    stack.push(10).unwrap();
    let addr = pop_memory_address(&mut stack).unwrap();
    assert_eq!(addr, 10);

    stack.push(-10).unwrap();
    pop_memory_address(&mut stack).unwrap_err();
}

#[test]
fn test_pop_key_range_args() {
    let mut stack = Stack::default();
    stack.extend(vec![1, 2, 3, 4, 4, 10]).unwrap();
    let (key, num_keys) = pop_key_range_args(&mut stack).unwrap();
    assert_eq!(key, vec![1, 2, 3, 4]);
    assert_eq!(num_keys, 10);

    stack.extend(vec![1, 2, 3, 4, 5, 10]).unwrap();
    pop_key_range_args(&mut stack).unwrap_err();

    stack.extend(vec![1, 2, 3, 4, -4, 10]).unwrap();
    pop_key_range_args(&mut stack).unwrap_err();

    stack.extend(vec![1, 2, 3, 4, 4, -10]).unwrap();
    pop_key_range_args(&mut stack).unwrap_err();
}

#[test]
fn test_write_values_to_memory() {
    let mut memory = Memory::default();
    write_values_to_memory(0, vec![], &mut memory).unwrap();
    let expected: &[i64] = &[];
    assert_eq!(memory.get(..).unwrap(), expected);

    let mut memory = Memory::default();
    memory.alloc(4 + 3).unwrap();
    write_values_to_memory(0, vec![vec![42, 43], vec![44]], &mut memory).unwrap();
    let expected: &[i64] = &[4, 2, 6, 1, 42, 43, 44];
    assert_eq!(memory.get(..).unwrap(), expected);

    let mut memory = Memory::default();
    memory.alloc(4 + 3).unwrap();
    write_values_to_memory(1, vec![vec![42, 43], vec![44]], &mut memory).unwrap_err();

    let mut memory = Memory::default();
    write_values_to_memory(0, vec![vec![42, 43], vec![44]], &mut memory).unwrap_err();
}

#[test]
fn test_read_key_range() {
    let mut state = State::default();
    let mut stack = Stack::default();
    let mut memory = Memory::default();
    let contract_addr = ContentAddress([1; 32]);

    stack.extend([42, 43, 2, 2, 0]).unwrap();
    key_range(&state, &contract_addr, &mut stack, &mut memory).unwrap();
    let expected: &[i64] = &[];
    assert_eq!(memory.get(..).unwrap(), expected);

    memory.alloc(2 + 2).unwrap();
    state.contracts.insert(
        contract_addr.clone(),
        [(vec![42, 43], vec![1, 2])].into_iter().collect(),
    );

    stack.extend([42, 43, 2, 2, 0]).unwrap();
    key_range(&state, &contract_addr, &mut stack, &mut memory).unwrap();
    let expected: &[i64] = &[2, 2, 1, 2];
    assert_eq!(memory.get(..).unwrap(), expected);
}

#[test]
fn test_read_key_range_ext() {
    let mut state = State::default();
    let mut stack = Stack::default();
    let mut memory = Memory::default();
    let contract_addr = ContentAddress([1; 32]);
    let contract_words = word_4_from_u8_32(contract_addr.0);

    stack.extend(contract_words).unwrap();
    stack.extend([42, 43, 2, 2, 0]).unwrap();
    key_range_ext(&state, &mut stack, &mut memory).unwrap();
    let expected: &[i64] = &[];
    assert_eq!(memory.get(..).unwrap(), expected);

    memory.alloc(2 + 2).unwrap();
    state.contracts.insert(
        contract_addr.clone(),
        [(vec![42, 43], vec![1, 2])].into_iter().collect(),
    );

    stack.extend(contract_words).unwrap();
    stack.extend([42, 43, 2, 2, 0]).unwrap();
    key_range_ext(&state, &mut stack, &mut memory).unwrap();
    let expected: &[i64] = &[2, 2, 1, 2];
    assert_eq!(memory.get(..).unwrap(), expected);
}

#[derive(Default)]
struct State {
    contracts: HashMap<ContentAddress, HashMap<Key, Value>>,
}

impl StateRead for State {
    type Error = String;

    fn key_range(
        &self,
        contract_addr: ContentAddress,
        mut key: Key,
        num_keys: usize,
    ) -> Result<Vec<Value>, Self::Error> {
        let Some(contracts) = self.contracts.get(&contract_addr) else {
            return Ok(Vec::new());
        };
        let mut values = Vec::new();
        for _ in 0..num_keys {
            let Some(value) = contracts.get(&key).cloned() else {
                return Ok(values);
            };
            values.push(value);
            let Some(k) = next_key(key) else {
                return Ok(values);
            };
            key = k;
        }
        Ok(values)
    }
}
fn next_key(mut key: Key) -> Option<Key> {
    for w in key.iter_mut().rev() {
        match *w {
            Word::MAX => *w = Word::MIN,
            _ => {
                *w += 1;
                return Some(key);
            }
        }
    }
    None
}