use crate::context::Context;
use crate::storage::ContractsState;
use crate::storage::MemoryStorage;
use super::*;
use fuel_storage::StorageAsMut;
use test_case::test_case;
struct SRWQInput {
input: StateReadQWord,
storage_slots: Vec<([u8; 32], [u8; 32])>,
memory: Vec<u8>,
}
impl StateReadQWord {
fn test(
destination_memory_address: Word,
origin_key_memory_address: Word,
num_slots: Word,
) -> Result<Self, RuntimeError> {
let r = OwnershipRegisters {
sp: u64::MAX / 2,
ssp: 0,
hp: u64::MAX / 2 + 1,
prev_hp: u64::MAX,
context: crate::context::Context::Call { block_height: 0 },
};
Self::new(destination_memory_address, origin_key_memory_address, num_slots, r)
}
}
#[test_case(
SRWQInput{
input: StateReadQWord::test(1, 2, 1).unwrap(),
storage_slots: vec![(key(27), [5; 32])],
memory: mem(&[&[0; 2], &key(27)]),
} => (mem(&[&[0], &[5; 32], &[27]]), true)
)]
#[test_case(
SRWQInput{
input: StateReadQWord::test(0, 0, 2).unwrap(),
storage_slots: vec![(key(27), [5; 32]), (key(28), [6; 32])],
memory: mem(&[&key(27)]),
} => (mem(&[&[5; 32], &[6; 32]]), true)
)]
#[test_case(
SRWQInput{
input: StateReadQWord::test(0, 0, 3).unwrap(),
storage_slots: vec![(key(27), [5; 32]), (key(28), [6; 32]), (key(29), [7; 32])],
memory: mem(&[&key(27)]),
} => (mem(&[&[5; 32], &[6; 32], &[7; 32]]), true)
)]
#[test_case(
SRWQInput{
input: StateReadQWord::test(0, 0, 2).unwrap(),
storage_slots: vec![(key(27), [5; 32]), (key(28), [6; 32]), (key(29), [7; 32])],
memory: mem(&[&key(27)]),
} => (mem(&[&[5; 32], &[6; 32]]), true)
)]
#[test_case(
SRWQInput{
input: StateReadQWord::test(0, 0, 3).unwrap(),
storage_slots: vec![(key(27), [5; 32]), (key(30), [6; 32]), (key(29), [7; 32])],
memory: mem(&[&key(27)]),
} => (mem(&[&[5; 32], &[0; 32], &[7; 32]]), false)
)]
#[test_case(
SRWQInput{
input: StateReadQWord::test(0, 0, 3).unwrap(),
storage_slots: vec![(key(27), [5; 32]), (key(28), [7; 32])],
memory: mem(&[&key(27)]),
} => (mem(&[&[5; 32], &[7; 32], &[0; 32]]), false)
)]
#[test_case(
SRWQInput{
input: StateReadQWord::test(0, 0, 3).unwrap(),
storage_slots: vec![(key(26), [5; 32]), (key(28), [6; 32]), (key(29), [7; 32])],
memory: mem(&[&key(27)]),
} => (mem(&[&[0; 32], &[6; 32], &[7; 32]]), false)
)]
#[test_case(
SRWQInput{
input: StateReadQWord::test(0, 0, 3).unwrap(),
storage_slots: vec![(key(28), [6; 32]), (key(29), [7; 32])],
memory: mem(&[&key(27)]),
} => (mem(&[&[0; 32], &[6; 32], &[7; 32]]), false)
)]
fn test_state_read_qword(input: SRWQInput) -> (Vec<u8>, bool) {
let SRWQInput {
input,
storage_slots,
mut 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_read_qword(&Default::default(), &storage, &mut memory, &mut result_register, input).unwrap();
(memory, result_register != 0)
}
#[test_case(
0, 0, 1, OwnershipRegisters::test(0..100, 100..200, Context::Call{ block_height: 0})
=> matches Ok(())
; "Ownership check passes when destination is within allocated stack"
)]
#[test_case(
2, 0, 1, OwnershipRegisters::test(0..1, 3..4, Context::Call{ block_height: 0})
=> matches Err(_)
; "Ownership check fails when destination is in-between stack and heap"
)]
#[test_case(
2, 0, 1, OwnershipRegisters::test(0..4, 5..6, Context::Call {block_height: 0})
=> matches Err(_)
; "Ownership check fails when stack is too small"
)]
#[test_case(
3, 0, 1, OwnershipRegisters::test(0..1, 2..35, Context::Call{ block_height: 0})
=> matches Ok(_)
; "Ownership check passes when heap is large enough"
)]
#[test_case(
VM_MAX_RAM, 0, 1, OwnershipRegisters::test(0..1, 3..u64::MAX, Context::Call{ block_height: 0})
=> matches Err(_)
; "Ownership check fails when destination range exceeds VM MAX"
)]
#[test_case(
4, VM_MAX_RAM, 1, OwnershipRegisters::test(0..1, 3..u64::MAX, Context::Call{ block_height: 0})
=> matches Err(_)
; "Fail when start key memory range exceeds VM_MAX_RAM"
)]
#[test_case(
4, u64::MAX, 1, OwnershipRegisters::test(0..1, 3..u64::MAX, Context::Call{ block_height: 0})
=> matches Err(_)
; "Fail when start key memory range exceeds u64::MAX"
)]
#[test_case(
4, 0, 1, OwnershipRegisters::test(0..1, 3..u64::MAX, Context::Script { block_height: 0})
=> matches Err(_)
; "Fail when context is not inside of a call"
)]
fn test_state_read_qword_input(
destination_memory_address: Word,
origin_key_memory_address: Word,
num_slots: Word,
ownership_registers: OwnershipRegisters,
) -> Result<(), RuntimeError> {
StateReadQWord::new(
destination_memory_address,
origin_key_memory_address,
num_slots,
ownership_registers,
)
.map(|_| ())
}