fuel-vm 0.25.2

FuelVM interpreter.
Documentation
#![allow(clippy::type_complexity)]

use crate::storage::ContractsState;
use crate::storage::MemoryStorage;

use super::*;
use fuel_storage::StorageAsMut;
use test_case::test_case;

struct SWWQInput {
    input: StateWriteQWord,
    storage_slots: Vec<([u8; 32], [u8; 32])>,
    memory: Vec<u8>,
}

#[test_case(
    SWWQInput{
        input: StateWriteQWord::new(2, 34, 1).unwrap(),
        storage_slots: vec![],
        memory: mem(&[&[0; 2], &key(27), &[5; 32]]),
    } => (vec![(key(27), [5; 32])], false)
    ; "Single slot write w/ offset key in memory"
)]
#[test_case(
    SWWQInput{
        input: StateWriteQWord::new(0, 32, 2).unwrap(),
        storage_slots: vec![],
        memory: mem(&[&key(27), &[5; 32], &[6; 32]]),
    } => (vec![(key(27), [5; 32]), (key(28), [6; 32])], false)
    ; "Two slot write"
)]
#[test_case(
    SWWQInput{
        input: StateWriteQWord::new(0, 32, 2).unwrap(),
        storage_slots: vec![(key(27), [2; 32])],
        memory: mem(&[&key(27), &[5; 32], &[6; 32]]),
    } => (vec![(key(27), [5; 32]), (key(28), [6; 32])], false)
    ; "Two slot writes with one pre-existing slot set"
)]
#[test_case(
    SWWQInput{
        input: StateWriteQWord::new(0, 32, 2).unwrap(),
        storage_slots: vec![],
        memory: mem(&[&key(27), &[5; 32], &[6; 32], &[7; 32]]),
    } => (vec![(key(27), [5; 32]), (key(28), [6; 32])], false)
    ; "Only writes two slots when memory has more data available"
)]
#[test_case(
    SWWQInput{
        input: StateWriteQWord::new(0, 32, 3).unwrap(),
        storage_slots: vec![],
        memory: mem(&[&key(27), &[5; 32], &[6; 32], &[7; 32]]),
    } => (vec![(key(27), [5; 32]), (key(28), [6; 32]), (key(29), [7; 32])], false)
    ; "Three slot write"
)]
#[test_case(
    SWWQInput{
        input: StateWriteQWord::new(0, 32, 3).unwrap(),
        storage_slots: vec![(key(29), [8; 32])],
        memory: mem(&[&key(27), &[5; 32], &[6; 32], &[7; 32]]),
    } => (vec![(key(27), [5; 32]), (key(28), [6; 32]), (key(29), [7; 32])], false)
    ; "Three slot write with one pre-existing slot set"
)]
#[test_case(
    SWWQInput{
        input: StateWriteQWord::new(0, 32, 3).unwrap(),
        storage_slots: vec![(key(27), [5; 32]), (key(28), [6; 32]), (key(29), [7; 32])],
        memory: mem(&[&key(27), &[5; 32], &[6; 32], &[7; 32]]),
    } => (vec![(key(27), [5; 32]), (key(28), [6; 32]), (key(29), [7; 32])], true)
    ; "Three slot write with all slots previously set"
)]
#[test_case(
    SWWQInput{
        input: StateWriteQWord::new(0, 32, 2).unwrap(),
        storage_slots: vec![(key(29), [8; 32])],
        memory: mem(&[&key(27), &[5; 32], &[6; 32], &[7; 32]]),
    } => (vec![(key(27), [5; 32]), (key(28), [6; 32]), (key(29), [8; 32])], false)
    ; "Does not override slots that aren't being written to (adjacent)"
)]
#[test_case(
    SWWQInput{
        input: StateWriteQWord::new(0, 32, 3).unwrap(),
        storage_slots: vec![(key(100), [8; 32])],
        memory: mem(&[&key(27), &[5; 32], &[6; 32], &[7; 32]]),
    } => (vec![(key(27), [5; 32]), (key(28), [6; 32]), (key(29), [7; 32]), (key(100), [8; 32])], false)
    ; "Does not override slots that aren't being written to (non-adjacent)"
)]
fn test_state_write_qword(input: SWWQInput) -> (Vec<([u8; 32], [u8; 32])>, bool) {
    let SWWQInput {
        input,
        storage_slots,
        memory,
    } = input;
    let mut storage = MemoryStorage::new(0, Default::default());

    for (k, v) in storage_slots {
        storage
            .storage::<ContractsState>()
            .insert(&(&ContractId::default(), &Bytes32::new(k)).into(), &Bytes32::new(v))
            .unwrap();
    }

    let mut result_register = 0u64;
    state_write_qword(&Default::default(), &mut storage, &memory, &mut result_register, input).unwrap();

    let results = storage
        .all_contract_state()
        .map(|(key, v)| (**key.state_key(), **v))
        .collect();
    (results, result_register != 0)
}

#[test_case(
    0, 0, 1
    => matches Ok(_)
    ; "Pass when values are within valid ranges"
)]
#[test_case(
    u64::MAX, 0, 1
    => matches Err(_)
    ; "Fail when rA + 32 overflows"
)]
#[test_case(
    0, u64::MAX, 1
    => matches Err(_)
    ; "Fail when rC + 32 * d overflows (rC too high)"
)]
#[test_case(
    0, 0, u64::MAX
    => matches Err(_)
    ; "Fail when rC + 32 * d overflows (rD too high)"
)]
#[test_case(
    VM_MAX_RAM - 1, 0, 1
    => matches Err(_)
    ; "Fail when rA + 32 > VM_MAX_RAM"
)]
#[test_case(
    VM_MAX_RAM - 32, 0, 1
    => matches Ok(_)
    ; "Pass when rA + 32 == VM_MAX_RAM"
)]
#[test_case(
    0, VM_MAX_RAM - 1, 1
    => matches Err(_)
    ; "Fail when rC + 32 * rD > VM_MAX_RAM"
)]
#[test_case(
    0, VM_MAX_RAM - 32, 1
    => matches Ok(_)
    ; "Pass when rC + 32 * rD == VM_MAX_RAM"
)]
#[test_case(
    0, VM_MAX_RAM - 63, 2
    => matches Err(_)
    ; "Fail when rC + 32 * rD == VM_MAX_RAM (rD too high)"
)]
fn test_state_write_qword_input(
    start_key_memory_address: Word,
    source_memory_address: Word,
    num_slots: Word,
) -> Result<(), RuntimeError> {
    StateWriteQWord::new(start_key_memory_address, source_memory_address, num_slots).map(|_| ())
}