Removed collections and lazy
Fixed comment
Showing 4 of 56 files from the diff.
Newly tracked file
crates/storage/src/test_utils.rs
changed.
Newly tracked file
crates/storage/src/traits/mod.rs
changed.
Newly tracked file
crates/storage/src/traits/optspec.rs
changed.
Newly tracked file
crates/storage/src/lazy/mapping.rs
changed.
Other files ignored by Codecov
crates/storage/src/collections/hashmap/storage.rs
was deleted.
crates/storage/src/lazy/lazy_imap.rs
was deleted.
crates/storage/src/collections/stash/tests.rs
was deleted.
crates/storage/src/collections/bitvec/bitsref.rs
was deleted.
crates/storage/src/hashmap_entry_api_tests.rs
was deleted.
crates/storage/src/collections/smallvec/mod.rs
was deleted.
crates/storage/src/collections/hashmap/impls.rs
was deleted.
crates/storage/src/collections/bitvec/impls.rs
was deleted.
crates/storage/src/collections/smallvec/tests.rs
was deleted.
crates/storage/src/collections/bitstash/counts.rs
was deleted.
crates/storage/src/collections/vec/tests.rs
was deleted.
crates/storage/src/collections/bitvec/tests.rs
was deleted.
crates/storage/src/collections/smallvec/iter.rs
was deleted.
crates/storage/src/collections/vec/iter.rs
was deleted.
crates/storage/src/collections/mod.rs
was deleted.
crates/storage/src/collections/stash/iter.rs
was deleted.
crates/storage/src/lazy/mod.rs
has changed.
crates/storage/src/collections/smallvec/impls.rs
was deleted.
crates/storage/src/collections/vec/storage.rs
was deleted.
crates/storage/src/collections/binary_heap/mod.rs
was deleted.
crates/storage/src/collections/stash/mod.rs
was deleted.
crates/storage/src/collections/vec/fuzz_tests.rs
was deleted.
crates/storage/src/lazy/cache_cell.rs
was deleted.
crates/storage/src/collections/bitvec/bitref.rs
was deleted.
crates/storage/src/lazy/lazy_array.rs
was deleted.
crates/storage/src/collections/bitvec/iter.rs
was deleted.
crates/storage/src/lazy/lazy_hmap.rs
was deleted.
crates/storage/src/lazy/entry.rs
was deleted.
crates/storage/src/collections/hashmap/iter.rs
was deleted.
crates/storage/src/collections/bitvec/storage.rs
was deleted.
crates/storage/src/collections/bitstash/mod.rs
was deleted.
crates/storage/src/collections/bitvec/mod.rs
was deleted.
crates/storage/src/lib.rs
has changed.
crates/storage/src/collections/stash/storage.rs
was deleted.
crates/storage/src/collections/bitstash/storage.rs
was deleted.
crates/storage/src/collections/hashmap/tests.rs
was deleted.
crates/storage/src/collections/bitvec/bits256.rs
was deleted.
crates/storage/src/collections/hashmap/mod.rs
was deleted.
crates/storage/src/collections/vec/mod.rs
was deleted.
crates/storage/src/collections/stash/impls.rs
was deleted.
crates/storage/src/collections/smallvec/storage.rs
was deleted.
crates/storage/src/lazy/lazy_cell.rs
was deleted.
crates/storage/src/collections/bitstash/tests.rs
was deleted.
crates/storage/src/collections/vec/impls.rs
was deleted.
@@ -76,139 +76,3 @@
Loading
76 | 76 | } |
|
77 | 77 | }; |
|
78 | 78 | } |
|
79 | - | ||
80 | - | /// A trait to enable running some fuzz tests on a collection. |
|
81 | - | pub trait FuzzCollection { |
|
82 | - | type Collection; |
|
83 | - | type Item; |
|
84 | - | ||
85 | - | /// Executes a series of operations on `self` in order to make it |
|
86 | - | /// equal to `template`. |
|
87 | - | fn equalize(&mut self, template: &Self::Collection); |
|
88 | - | ||
89 | - | /// Takes a value from `self` and puts it into `item`. |
|
90 | - | fn assign(&mut self, item: Self::Item); |
|
91 | - | } |
|
92 | - | ||
93 | - | /// Creates two fuzz tests. Both tests have the same flow: |
|
94 | - | /// - Take two instances of the collection, generated by our fuzzer |
|
95 | - | /// - Push `instance2` to storage, pull it out and assert that what |
|
96 | - | /// is pulled out is what was pushed. |
|
97 | - | /// - Do some mutations on the `pulled` object. Here the two tests |
|
98 | - | /// behave differently: |
|
99 | - | /// |
|
100 | - | /// * `fuzz_ $id _mutate_some` Mutates some entries of the data |
|
101 | - | /// structure based on the content of `instance2`. |
|
102 | - | /// |
|
103 | - | /// * `fuzz_ $id _mutate_all` Mutates the entire data structure, |
|
104 | - | /// so that it has the same content as `instance2`. |
|
105 | - | /// |
|
106 | - | /// - Push the mutated `pulled` object into storage again, pull it |
|
107 | - | /// out as `pulled2` and assert that both objects are equal. |
|
108 | - | /// - Clear the object from storage and assert that storage was |
|
109 | - | /// cleared up properly, without any leftovers. |
|
110 | - | #[macro_export] |
|
111 | - | macro_rules! fuzz_storage { |
|
112 | - | ($id:literal, $collection_type:ty) => { |
|
113 | - | ::paste::paste! { |
|
114 | - | /// Does some basic storage interaction tests whilst mutating |
|
115 | - | /// *some* of the data structure's entries. |
|
116 | - | #[allow(trivial_casts)] |
|
117 | - | #[quickcheck] |
|
118 | - | fn [< fuzz_ $id _mutate_some >] ( |
|
119 | - | instance1: $collection_type, |
|
120 | - | mut instance2: $collection_type, |
|
121 | - | ) { |
|
122 | - | ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| { |
|
123 | - | // we push the generated object into storage |
|
124 | - | let root_key = ink_primitives::Key::from([0x42; 32]); |
|
125 | - | let ptr = KeyPtr::from(root_key); |
|
126 | - | $crate::traits::push_spread_root(&instance1, &root_key.clone()); |
|
127 | - | ||
128 | - | // we pull what's in storage and assert that this is what was just pushed |
|
129 | - | let mut pulled: $collection_type = $crate::traits::pull_spread_root(&root_key.clone()); |
|
130 | - | assert_eq!(instance1, pulled); |
|
131 | - | ||
132 | - | // we iterate over what was pulled and call `assign` for all entries. |
|
133 | - | // this function may or may not modify elements of `pulled`. |
|
134 | - | pulled.iter_mut().for_each(|item| { |
|
135 | - | // this may leave some entries of `pulled` in `State::Preserved`. |
|
136 | - | // even though the instance which is supposed to be mutated is |
|
137 | - | // `pulled`, we still need to call this on a mutable `instance2`, |
|
138 | - | // since e.g. Vec does a `pop()` in assign, so that we don't always |
|
139 | - | // execute the same operation. |
|
140 | - | (&mut instance2).assign(item); |
|
141 | - | }); |
|
142 | - | ||
143 | - | // we push the `pulled` object, on which we just executed mutations |
|
144 | - | // back into storage and asserts it can be pulled out intact again. |
|
145 | - | $crate::traits::push_spread_root(&pulled, &root_key.clone()); |
|
146 | - | let pulled2: $collection_type = $crate::traits::pull_spread_root(&root_key.clone()); |
|
147 | - | assert_eq!(pulled, pulled2); |
|
148 | - | ||
149 | - | // we clear the objects from storage and assert that everything was |
|
150 | - | // removed without any leftovers. |
|
151 | - | SpreadLayout::clear_spread(&pulled2, &mut ptr.clone()); |
|
152 | - | SpreadLayout::clear_spread(&pulled, &mut ptr.clone()); |
|
153 | - | $crate::test_utils::assert_storage_clean(); |
|
154 | - | ||
155 | - | Ok(()) |
|
156 | - | }) |
|
157 | - | .unwrap() |
|
158 | - | } |
|
159 | - | ||
160 | - | /// Does some basic storage interaction tests whilst mutating |
|
161 | - | /// *all* the data structure's entries. |
|
162 | - | #[allow(trivial_casts)] |
|
163 | - | #[quickcheck] |
|
164 | - | fn [< fuzz_ $id _mutate_all >] ( |
|
165 | - | instance1: $collection_type, |
|
166 | - | instance2: $collection_type, |
|
167 | - | ) { |
|
168 | - | ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| { |
|
169 | - | // we push the generated object into storage |
|
170 | - | let root_key = ink_primitives::Key::from([0x42; 32]); |
|
171 | - | let ptr = KeyPtr::from(root_key); |
|
172 | - | $crate::traits::push_spread_root(&instance1, &root_key.clone()); |
|
173 | - | ||
174 | - | // we pull what's in storage and assert that this is what was just pushed |
|
175 | - | let mut pulled: $collection_type = $crate::traits::pull_spread_root(&root_key.clone()); |
|
176 | - | assert_eq!(instance1, pulled); |
|
177 | - | ||
178 | - | // `pulled` is going to be equalized to ` |
|
179 | - | (&mut pulled).equalize(&instance2); |
|
180 | - | ||
181 | - | // we push the `pulled` object, on which we just executed mutations |
|
182 | - | // back into storage and assert it can be pulled out intact again and |
|
183 | - | // is equal to `instance2`. |
|
184 | - | $crate::traits::push_spread_root(&pulled, &root_key.clone()); |
|
185 | - | let pulled2: $collection_type = $crate::traits::pull_spread_root(&root_key.clone()); |
|
186 | - | assert_eq!(pulled, pulled2); |
|
187 | - | assert_eq!(pulled2, instance2); |
|
188 | - | ||
189 | - | // we clear the objects from storage and assert that everything was |
|
190 | - | // removed without any leftovers. |
|
191 | - | SpreadLayout::clear_spread(&pulled2, &mut ptr.clone()); |
|
192 | - | SpreadLayout::clear_spread(&pulled, &mut ptr.clone()); |
|
193 | - | $crate::test_utils::assert_storage_clean(); |
|
194 | - | ||
195 | - | Ok(()) |
|
196 | - | ||
197 | - | }) |
|
198 | - | .unwrap() |
|
199 | - | } |
|
200 | - | } |
|
201 | - | }; |
|
202 | - | } |
|
203 | - | ||
204 | - | /// Asserts that the storage is empty, without any leftovers. |
|
205 | - | #[cfg(all(test, feature = "ink-fuzz-tests"))] |
|
206 | - | pub fn assert_storage_clean() { |
|
207 | - | let contract_id = ink_env::test::callee::<ink_env::DefaultEnvironment>(); |
|
208 | - | let used_cells = |
|
209 | - | ink_env::test::count_used_storage_cells::<ink_env::DefaultEnvironment>( |
|
210 | - | &contract_id, |
|
211 | - | ) |
|
212 | - | .expect("used cells must be returned"); |
|
213 | - | assert_eq!(used_cells, 0); |
|
214 | - | } |
@@ -37,13 +37,7 @@
Loading
37 | 37 | LayoutCryptoHasher, |
|
38 | 38 | StorageLayout, |
|
39 | 39 | }; |
|
40 | - | pub(crate) use self::optspec::{ |
|
41 | - | clear_spread_root_opt, |
|
42 | - | pull_packed_root_opt, |
|
43 | - | pull_spread_root_opt, |
|
44 | - | push_packed_root_opt, |
|
45 | - | push_spread_root_opt, |
|
46 | - | }; |
|
40 | + | pub(crate) use self::optspec::pull_packed_root_opt; |
|
47 | 41 | pub use self::{ |
|
48 | 42 | impls::{ |
|
49 | 43 | forward_allocate_packed, |
@@ -18,86 +18,9 @@
Loading
18 | 18 | //! The specializations make use of the storage entry state (occupied or vacant) |
|
19 | 19 | //! in order to store the option's state thus using less storage in total. |
|
20 | 20 | ||
21 | - | use super::{ |
|
22 | - | KeyPtr, |
|
23 | - | PackedLayout, |
|
24 | - | SpreadLayout, |
|
25 | - | }; |
|
21 | + | use super::PackedLayout; |
|
26 | 22 | use ink_primitives::Key; |
|
27 | 23 | ||
28 | - | pub fn pull_spread_root_opt<T>(root_key: &Key) -> Option<T> |
|
29 | - | where |
|
30 | - | T: SpreadLayout, |
|
31 | - | { |
|
32 | - | // In case the contract storage is occupied we handle |
|
33 | - | // the Option<T> as if it was a T. |
|
34 | - | ink_env::get_contract_storage::<()>(root_key) |
|
35 | - | .ok() |
|
36 | - | .flatten() |
|
37 | - | .map(|_| super::pull_spread_root::<T>(root_key)) |
|
38 | - | } |
|
39 | - | ||
40 | - | pub fn push_spread_root_opt<T>(entity: Option<&T>, root_key: &Key) |
|
41 | - | where |
|
42 | - | T: SpreadLayout, |
|
43 | - | { |
|
44 | - | match entity { |
|
45 | - | Some(value) => { |
|
46 | - | // Handle the Option<T> as if it was a T. |
|
47 | - | // |
|
48 | - | // Sadly this does not not work well with `Option<Option<T>>`. |
|
49 | - | // For this we'd need specialization in Rust or similar. |
|
50 | - | super::push_spread_root(value, root_key) |
|
51 | - | } |
|
52 | - | None => clear_spread_root_opt::<T, _>(root_key, || entity), |
|
53 | - | } |
|
54 | - | } |
|
55 | - | ||
56 | - | pub fn clear_spread_root_opt<'a, T: 'a, F>(root_key: &Key, f: F) |
|
57 | - | where |
|
58 | - | T: SpreadLayout, |
|
59 | - | F: FnOnce() -> Option<&'a T>, |
|
60 | - | { |
|
61 | - | // We can clean up some storage entity using its `SpreadLayout::clear_spread` |
|
62 | - | // implementation or its defined storage footprint. |
|
63 | - | // |
|
64 | - | // While using its `SpreadLayout::clear_spread` implementation is more precise |
|
65 | - | // and will only clean-up what is necessary it requires an actual instance. |
|
66 | - | // Loading such an instance if it is not already in the memory cache of some |
|
67 | - | // lazy abstraction will incur significant overhead. |
|
68 | - | // Using its defined storage footprint this procedure can eagerly clean-up |
|
69 | - | // the associated contract storage region, however, this might clean-up more |
|
70 | - | // cells than needed. |
|
71 | - | // |
|
72 | - | // There are types that need a so-called "deep" clean-up. An example for this |
|
73 | - | // is `storage::Box<storage::Box<T>>` where the outer storage box definitely |
|
74 | - | // needs to propagate clearing signals onto its inner `storage::Box` in order |
|
75 | - | // to properly clean-up the whole associate contract storage region. |
|
76 | - | // This is when we cannot avoid loading the entity for the clean-up procedure. |
|
77 | - | // |
|
78 | - | // If the entity that shall be cleaned-up does not require deep clean-up we |
|
79 | - | // check if its storage footprint exceeds a certain threshold and only then |
|
80 | - | // we will still load it first in order to not clean-up too many unneeded |
|
81 | - | // storage cells. |
|
82 | - | let footprint = <T as SpreadLayout>::FOOTPRINT; |
|
83 | - | if footprint >= super::FOOTPRINT_CLEANUP_THRESHOLD |
|
84 | - | || <T as SpreadLayout>::REQUIRES_DEEP_CLEAN_UP |
|
85 | - | { |
|
86 | - | // We need to load the entity before we remove its associated contract storage |
|
87 | - | // because it requires a deep clean-up which propagates clearing to its fields, |
|
88 | - | // for example in the case of `T` being a `storage::Box`. |
|
89 | - | if let Some(value) = f() { |
|
90 | - | super::clear_spread_root(value, root_key); |
|
91 | - | return |
|
92 | - | } |
|
93 | - | } |
|
94 | - | // Clean-up eagerly without potentially loading the entity from storage: |
|
95 | - | let mut ptr = KeyPtr::from(*root_key); |
|
96 | - | for _ in 0..footprint { |
|
97 | - | ink_env::clear_contract_storage(ptr.advance_by(1)); |
|
98 | - | } |
|
99 | - | } |
|
100 | - | ||
101 | 24 | pub fn pull_packed_root_opt<T>(root_key: &Key) -> Option<T> |
|
102 | 25 | where |
|
103 | 26 | T: PackedLayout, |
@@ -116,22 +39,3 @@
Loading
116 | 39 | value |
|
117 | 40 | }) |
|
118 | 41 | } |
|
119 | - | ||
120 | - | pub fn push_packed_root_opt<T>(entity: Option<&T>, root_key: &Key) |
|
121 | - | where |
|
122 | - | T: PackedLayout, |
|
123 | - | { |
|
124 | - | match entity { |
|
125 | - | Some(value) => { |
|
126 | - | // Handle the Option<T> as if it was a T. |
|
127 | - | // |
|
128 | - | // Sadly this does not work well with `Option<Option<T>>`. |
|
129 | - | // For this we'd need specialization in Rust or similar. |
|
130 | - | super::push_packed_root(value, root_key); |
|
131 | - | } |
|
132 | - | None => { |
|
133 | - | // Clear the associated storage cell since the entity is `None`. |
|
134 | - | ink_env::clear_contract_storage(root_key); |
|
135 | - | } |
|
136 | - | } |
|
137 | - | } |
@@ -298,7 +298,7 @@
Loading
298 | 298 | fn can_clear_entries() { |
|
299 | 299 | ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| { |
|
300 | 300 | // We use `Pack` here since it `REQUIRES_DEEP_CLEAN_UP` |
|
301 | - | use crate::Pack; |
|
301 | + | use crate::pack::Pack; |
|
302 | 302 | ||
303 | 303 | // Given |
|
304 | 304 | let mut mapping: Mapping<u8, u8> = Mapping::new([0u8; 32].into()); |
@@ -327,7 +327,7 @@
Loading
327 | 327 | fn can_clear_unexistent_entries() { |
|
328 | 328 | ink_env::test::run_test::<ink_env::DefaultEnvironment, _>(|_| { |
|
329 | 329 | // We use `Pack` here since it `REQUIRES_DEEP_CLEAN_UP` |
|
330 | - | use crate::Pack; |
|
330 | + | use crate::pack::Pack; |
|
331 | 331 | ||
332 | 332 | // Given |
|
333 | 333 | let mapping: Mapping<u8, u8> = Mapping::new([0u8; 32].into()); |
Files | Coverage |
---|---|
crates | 47.94% |
Project Totals (176 files) | 47.94% |
Sunburst
The inner-most circle is the entire project, moving away from the center are folders then, finally, a single file.
The size and color of each slice is representing the number of statements and the coverage, respectively.
Icicle
The top section represents the entire project. Proceeding with folders and finally individual files.
The size and color of each slice is representing the number of statements and the coverage, respectively.