Skip to content

Commit

Permalink
Storage tests
Browse files Browse the repository at this point in the history
  • Loading branch information
virgil-serbanuta committed Dec 5, 2024
1 parent cbe1185 commit 250e6ac
Show file tree
Hide file tree
Showing 7 changed files with 216 additions and 28 deletions.
1 change: 1 addition & 0 deletions tests/ulm/erc20/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ mod ulm;
mod ulm_hooks;

mod encoding_tests;
mod storage_tests;
mod unsigned_tests;
28 changes: 15 additions & 13 deletions tests/ulm/erc20/rust/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
// let my_value = storage.get();

use core::marker::PhantomData;
use std::cell::RefCell;
use std::convert::TryFrom;
use std::convert::Into;
use std::rc::Rc;

use crate::assertions::fail;
use crate::encoder::Encodable;
Expand All @@ -40,28 +42,28 @@ pub struct SingleChunkStorage<'a, ValueType>
ValueType: Into<U256> + TryFrom<U256>,
{
phantom_value: PhantomData<&'a ValueType>,
api: &'a mut dyn ulm::Ulm,
api: Rc<RefCell<dyn ulm::Ulm>>,
fingerprint: U256,
}

impl<'a, ValueType> SingleChunkStorage<'a, ValueType>
where
ValueType: Into<U256> + TryFrom<U256, Error = &'static str>,
ValueType: Into<U256> + TryFrom<U256>,
{
pub fn new(api: &'a mut dyn ulm::Ulm, fingerprint: U256) -> Self {
pub fn new(api: Rc<RefCell<dyn ulm::Ulm>>, fingerprint: U256) -> Self {
SingleChunkStorage::<ValueType> { phantom_value: PhantomData, api, fingerprint }
}

pub fn set(&mut self, value: ValueType) {
let converted: U256 = value.into();
ulm::set_account_storage(self.api, &self.fingerprint, &converted);
ulm::set_account_storage(&mut *self.api.borrow_mut(), &self.fingerprint, &converted);
}

pub fn get(&self) -> ValueType {
let u256 = ulm::get_account_storage(self.api, &self.fingerprint);
let u256 = ulm::get_account_storage(&*self.api.borrow(), &self.fingerprint);
match u256.try_into() {
Ok(v) => v,
Err(reason) => fail(reason),
Err(_) => fail("Conversion from U256 failed for storage"),
}
}
}
Expand All @@ -71,22 +73,22 @@ pub struct SingleChunkStorageBuilder<'a, ValueType>
ValueType: Into<U256> + TryFrom<U256>,
{
phantom_value: PhantomData<&'a ValueType>,
api: &'a mut dyn ulm::Ulm,
hooks_api: &'a mut dyn ulm_hooks::UlmHooks,
api: Rc<RefCell<dyn ulm::Ulm>>,
hooks_api: Rc<RefCell<dyn ulm_hooks::UlmHooks>>,
encoder: Encoder,
}

impl<'a, ValueType> SingleChunkStorageBuilder<'a, ValueType>
where
ValueType: Into<U256> + TryFrom<U256, Error = &'static str>,
ValueType: Into<U256> + TryFrom<U256>,
{
pub fn new(api: &'a mut dyn ulm::Ulm, hooks_api: &'a mut dyn ulm_hooks::UlmHooks, name: &String) -> Self {
pub fn new(api: Rc<RefCell<dyn ulm::Ulm>>, hooks_api: Rc<RefCell<dyn ulm_hooks::UlmHooks>>, name: &String) -> Self {
let mut encoder = Encoder::new();
encoder.add(name);
Self::from_encoder(api, hooks_api, encoder)
}

fn from_encoder(api: &'a mut dyn ulm::Ulm, hooks_api: &'a mut dyn ulm_hooks::UlmHooks, encoder: Encoder) -> Self {
fn from_encoder(api: Rc<RefCell<dyn ulm::Ulm>>, hooks_api: Rc<RefCell<dyn ulm_hooks::UlmHooks>>, encoder: Encoder) -> Self {
SingleChunkStorageBuilder::<ValueType> {
phantom_value: PhantomData,
api,
Expand All @@ -101,7 +103,7 @@ impl<'a, ValueType> SingleChunkStorageBuilder<'a, ValueType>

pub fn build(&mut self) -> SingleChunkStorage<ValueType> {
let bytes = self.encoder.encode();
let fingerprint = ulm_hooks::keccak_hash_int(self.hooks_api, &bytes);
SingleChunkStorage::new(self.api, fingerprint)
let fingerprint = ulm_hooks::keccak_hash_int(&*self.hooks_api.borrow(), &bytes);
SingleChunkStorage::new(self.api.clone(), fingerprint)
}
}
102 changes: 102 additions & 0 deletions tests/ulm/erc20/rust/src/storage_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
#[cfg(test)]
mod encoding_tests {
use crate::storage::*;
use crate::ulm;
use crate::ulm_hooks;
use crate::unsigned::*;

#[test]
fn read_value_not_set() {
let api = ulm::mock::UlmMock::new();
let hooks_api = ulm_hooks::mock::UlmHooksMock::new();
let mut builder = SingleChunkStorageBuilder::<U256>::new(api, hooks_api, &("my_storage".to_string()));

let storage = builder.build();
let value: U256 = storage.get();

assert_eq!(U256::from_u64(0), value);
}

#[test]
fn write_read_u256() {
let api = ulm::mock::UlmMock::new();
let hooks_api = ulm_hooks::mock::UlmHooksMock::new();
let mut builder = SingleChunkStorageBuilder::<U256>::new(api, hooks_api, &("my_storage".to_string()));

let mut storage = builder.build();
storage.set(U256::from_u64(123456789));
let value: U256 = storage.get();

assert_eq!(U256::from_u64(123456789), value);
}

#[test]
fn write_read_u8() {
let api = ulm::mock::UlmMock::new();
let hooks_api = ulm_hooks::mock::UlmHooksMock::new();
let mut builder = SingleChunkStorageBuilder::<Unsigned::<1>>::new(api, hooks_api, &("my_storage".to_string()));

let mut storage = builder.build();
storage.set(Unsigned::<1>::from_u64(123));
let value: Unsigned<1> = storage.get();

assert_eq!(Unsigned::<1>::from_u64(123), value);
}

#[test]
fn write_read_args() {
let api = ulm::mock::UlmMock::new();
let hooks_api = ulm_hooks::mock::UlmHooksMock::new();

let mut builder = SingleChunkStorageBuilder::<U256>::new(api, hooks_api, &("my_storage".to_string()));

builder.add_arg(&U256::from_u64(5));

let mut storage = builder.build();
storage.set(U256::from_u64(123456789));
let value: U256 = storage.get();

assert_eq!(U256::from_u64(123456789), value);
}

#[test]
fn no_confusion() {
let api = ulm::mock::UlmMock::new();
let hooks_api = ulm_hooks::mock::UlmHooksMock::new();

let mut builder1 = SingleChunkStorageBuilder::<U256>::new(api.clone(), hooks_api.clone(), &("my_storage".to_string()));
let mut builder2 = SingleChunkStorageBuilder::<U256>::new(api.clone(), hooks_api.clone(), &("my_storage1".to_string()));
let mut builder3 = SingleChunkStorageBuilder::<U256>::new(api.clone(), hooks_api.clone(), &("my_storage".to_string()));
let mut builder4 = SingleChunkStorageBuilder::<U256>::new(api.clone(), hooks_api.clone(), &("my_storage".to_string()));
let mut builder5 = SingleChunkStorageBuilder::<U256>::new(api, hooks_api, &("my_storage".to_string()));

builder3.add_arg(&U256::from_u64(3));
builder4.add_arg(&U256::from_u64(4));
builder5.add_arg(&U256::from_u64(3));
builder5.add_arg(&U256::from_u64(4));

let mut storage1 = builder1.build();
let mut storage2 = builder2.build();
let mut storage3 = builder3.build();
let mut storage4 = builder4.build();
let mut storage5 = builder5.build();

storage1.set(U256::from_u64(1));
storage2.set(U256::from_u64(2));
storage3.set(U256::from_u64(3));
storage4.set(U256::from_u64(4));
storage5.set(U256::from_u64(5));

let value1: U256 = storage1.get();
let value2: U256 = storage2.get();
let value3: U256 = storage3.get();
let value4: U256 = storage4.get();
let value5: U256 = storage5.get();

assert_eq!(U256::from_u64(1), value1);
assert_eq!(U256::from_u64(2), value2);
assert_eq!(U256::from_u64(3), value3);
assert_eq!(U256::from_u64(4), value4);
assert_eq!(U256::from_u64(5), value5);
}
}
15 changes: 11 additions & 4 deletions tests/ulm/erc20/rust/src/ulm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::unsigned::U256;

#[cfg(not(test))]
extern "C" {
// key and value must have a length of exactly 32.
#[allow(non_snake_case)]
Expand Down Expand Up @@ -30,9 +31,11 @@ impl Ulm for UlmImpl {
}

#[cfg(test)]
mod ulm_mock {
pub mod mock {
use bytes::{Bytes, Buf};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;

use crate::assertions::fail;
use crate::require;
Expand All @@ -43,8 +46,8 @@ mod ulm_mock {
}

impl UlmMock {
pub fn new() -> UlmMock {
UlmMock { storage: HashMap::new() }
pub fn new() -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(UlmMock { storage: HashMap::new() }))
}
}

Expand All @@ -57,7 +60,11 @@ mod ulm_mock {
require!(bytes_value.len() == 32, "unexpected value length in storage");
value.copy_from_slice(bytes_value);
},
None => fail("Key not found in storage"),
None => {
for i in 0 .. value.len() {
value[i] = 0;
}
},
}
}

Expand Down
16 changes: 12 additions & 4 deletions tests/ulm/erc20/rust/src/ulm_hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use bytes::{Bytes, Buf};

use crate::unsigned::U256;

#[cfg(not(test))]
extern "C" {
#[allow(dead_code)]
pub fn fail(msg: *const u8, msg_len: usize) -> !;
Expand Down Expand Up @@ -35,28 +36,35 @@ pub trait UlmHooks {
fn keccak_hash(&self, value: &[u8], result: &mut [u8; 32]);
}

#[cfg(not(test))]
struct UlmHooksImpl {
}

#[cfg(not(test))]
impl UlmHooksImpl {
pub fn new() -> Self {
UlmHooksImpl {}
}
}

#[cfg(not(test))]
impl UlmHooks for UlmHooksImpl {
fn keccak_hash(&self, value: &[u8], result: &mut [u8; 32]) {
unsafe { keccakHash(value.as_ptr(), value.len(), result.as_mut_ptr()); }
}
}

mod mock {
#[cfg(test)]
pub mod mock {
use std::cell::RefCell;
use std::rc::Rc;

use crate::ulm_hooks::UlmHooks;

struct UlmHooksMock {}
pub struct UlmHooksMock {}
impl UlmHooksMock {
pub fn new() -> Self {
UlmHooksMock {}
pub fn new() -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(UlmHooksMock {}))
}
}
impl UlmHooks for UlmHooksMock {
Expand Down
Loading

0 comments on commit 250e6ac

Please sign in to comment.