Skip to content

Commit c6abc0e

Browse files
committed
Fixing TrackingCopy caching mechanism so it doesn't return Some(_) when a key was pruned. Fixing Vector implementation.
1 parent 5b14ced commit c6abc0e

File tree

8 files changed

+196
-92
lines changed

8 files changed

+196
-92
lines changed

executor/wasm/tests/collections.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,11 +152,11 @@ fn inserting_into_non_existing_vec_index_fails() {
152152
.expect("should build");
153153
let res = run_wasm_session(&mut executor, &global_state, state_root_hash, run_method);
154154
assert!(res.is_ok());
155+
155156
if let Ok(res) = res {
156-
let host_error = res.host_error;
157-
assert!(host_error.is_some());
158-
if let Some(err) = host_error {
159-
println!("XXX {:?}", err);
160-
}
157+
assert!(matches!(
158+
res.host_error,
159+
Some(casper_executor_wasm_common::error::CallError::NotCallable)
160+
));
161161
}
162162
}

executor/wasm_host/src/host/global_state.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ pub(crate) fn host_write<S: GlobalStateReader + 'static>(
354354
Keyspace::EntryPoint(_) => return Ok(HOST_ERROR_INVALID_INPUT),
355355
};
356356

357+
error!("XXXX2");
357358
metered_write(caller, global_state_key, stored_value)?;
358359

359360
Ok(HOST_ERROR_SUCCESS)

smart_contracts/contracts/vm2/vm2-collections-test/src/vector/assert.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use core::{panic, ptr::NonNull};
1+
use core::ptr::NonNull;
22

33
use alloc::{vec, vec::Vec};
44
use casper_contract_sdk::{
@@ -54,7 +54,21 @@ pub(crate) fn should_retain_assert(vec: &mut Vector<u64>) {
5454
assert_eq!(vec, vec![2, 4]);
5555
}
5656

57-
pub(crate) fn test_vec_assert(vec: &mut Vector<u64>) {
57+
// Assert for scenario in which deletes happen in previous
58+
// state hash
59+
pub(crate) fn test_vec_1_assert() {
60+
assert_eq!(
61+
get_vec_elements_from_storage("test_vec_1"),
62+
vec![41, 43, 42, 111, 222, 333]
63+
);
64+
65+
let vec2 = Vector::<u64>::new("test1");
66+
assert_eq!(vec2.get(0), None);
67+
68+
assert_eq!(get_vec_elements_from_storage("test1"), Vec::<u64>::new());
69+
}
70+
71+
pub(crate) fn test_vec_2_assert(vec: &mut Vector<u64>) {
5872
assert_eq!(vec.remove(5), Some(334));
5973
assert_eq!(vec.remove(55), None);
6074

@@ -81,7 +95,7 @@ pub(crate) fn test_vec_assert(vec: &mut Vector<u64>) {
8195
}
8296

8397
assert_eq!(
84-
get_vec_elements_from_storage("test_vec"),
98+
get_vec_elements_from_storage("test_vec_2"),
8599
vec![41, 43, 42, 111, 222, 333]
86100
);
87101

smart_contracts/contracts/vm2/vm2-collections-test/src/vector/mod.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ use prepare::*;
99

1010
#[casper]
1111
pub(crate) struct VectorTestData {
12-
should_not_panic_with_empty: Vector<u64>,
1312
should_retain: Vector<u64>,
14-
test_vec: Vector<u64>,
13+
should_not_panic_with_empty: Vector<u64>,
14+
test_vec_1: Vector<u64>,
15+
test_vec_2: Vector<u64>,
1516
test_pop: Vector<u64>,
1617
test_contains: Vector<u64>,
1718
test_clear: Vector<u64>,
@@ -26,9 +27,10 @@ pub(crate) struct VectorTestData {
2627
impl VectorTestData {
2728
pub(crate) fn new() -> Self {
2829
Self {
29-
should_not_panic_with_empty: should_not_panic_with_empty_prepare(),
3030
should_retain: should_retain_prepare(),
31-
test_vec: test_vec_prepare(),
31+
should_not_panic_with_empty: should_not_panic_with_empty_prepare(),
32+
test_vec_1: test_vec_1_prepare(),
33+
test_vec_2: test_vec_2_prepare(),
3234
test_pop: test_pop_prepare(),
3335
test_contains: test_contains_prepare(),
3436
test_clear: test_clear_prepare(),
@@ -44,7 +46,7 @@ impl VectorTestData {
4446
pub(crate) fn do_assertions(&mut self) {
4547
let should_not_panic_with_empty = &mut self.should_not_panic_with_empty;
4648
let should_retain = &mut self.should_retain;
47-
let test_vec = &mut self.test_vec;
49+
let test_vec_2 = &mut self.test_vec_2;
4850
let test_pop = &mut self.test_pop;
4951
let test_contains = &mut self.test_contains;
5052
let test_clear = &mut self.test_clear;
@@ -56,7 +58,8 @@ impl VectorTestData {
5658
let test_remove_invalid_index = &mut self.test_remove_invalid_index;
5759
should_not_panic_with_empty_assert(should_not_panic_with_empty);
5860
should_retain_assert(should_retain);
59-
test_vec_assert(test_vec);
61+
test_vec_1_assert();
62+
test_vec_2_assert(test_vec_2);
6063
test_pop_assert(test_pop);
6164
test_contains_assert(test_contains);
6265
test_clear_assert(test_clear);

smart_contracts/contracts/vm2/vm2-collections-test/src/vector/prepare.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use casper_contract_sdk::{casper, collections::Vector};
1+
use casper_contract_sdk::collections::Vector;
22

33
use crate::types::VectorTestStruct;
44

@@ -22,8 +22,51 @@ pub(crate) fn should_retain_prepare() -> Vector<u64> {
2222
vec
2323
}
2424

25-
pub(crate) fn test_vec_prepare() -> Vector<u64> {
26-
let mut vec = Vector::new("test_vec");
25+
pub(crate) fn test_vec_1_prepare() -> Vector<u64> {
26+
let mut vec = Vector::new("test_vec_1");
27+
28+
assert!(vec.get(0).is_none());
29+
vec.push(111);
30+
assert_eq!(vec.get(0), Some(111));
31+
vec.push(222);
32+
assert_eq!(vec.get(1), Some(222));
33+
34+
vec.insert(0, 42);
35+
vec.insert(0, 41);
36+
vec.insert(1, 43);
37+
vec.insert(5, 333);
38+
vec.insert(5, 334);
39+
assert_eq!(vec.remove(5), Some(334));
40+
assert_eq!(vec.remove(55), None);
41+
42+
/*let to_return = vec.clone();
43+
let mut iter = (&vec).iter();
44+
assert_eq!(iter.next(), Some(41));
45+
assert_eq!(iter.next(), Some(43));
46+
assert_eq!(iter.next(), Some(42));
47+
assert_eq!(iter.next(), Some(111));
48+
assert_eq!(iter.next(), Some(222));
49+
assert_eq!(iter.next(), Some(333));
50+
assert_eq!(iter.next(), None);
51+
*/
52+
{
53+
let ser = borsh::to_vec(&vec).unwrap();
54+
let deser: Vector<u64> = borsh::from_slice(&ser).unwrap();
55+
let mut iter = deser.iter();
56+
assert_eq!(iter.next(), Some(41));
57+
assert_eq!(iter.next(), Some(43));
58+
assert_eq!(iter.next(), Some(42));
59+
assert_eq!(iter.next(), Some(111));
60+
assert_eq!(iter.next(), Some(222));
61+
assert_eq!(iter.next(), Some(333));
62+
assert_eq!(iter.next(), None);
63+
}
64+
65+
vec
66+
}
67+
68+
pub(crate) fn test_vec_2_prepare() -> Vector<u64> {
69+
let mut vec = Vector::new("test_vec_2");
2770

2871
assert!(vec.get(0).is_none());
2972
vec.push(111);

smart_contracts/vm2/sdk/src/collections/vector.rs

Lines changed: 17 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use const_fnv1a_hash::fnv1a_hash_str_64;
1414
#[cfg(all(not(target_arch = "wasm32"), feature = "std"))]
1515
use crate::abi::{AbiDeclaration, CasperABI, Definition, StructField};
1616

17-
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone)]
17+
#[derive(BorshSerialize, BorshDeserialize, Debug)]
1818
#[borsh(crate = "crate::serializers::borsh")]
1919
pub struct Vector<T> {
2020
pub(crate) prefix: String,
@@ -71,19 +71,8 @@ where
7171

7272
/// Appends an element to the back of a collection.
7373
pub fn push(&mut self, value: T) {
74-
let prefix_bytes = self.compute_prefix_bytes_for_index(self.length);
75-
let collection_prefix = fnv1a_hash_str_64(self.prefix.as_str()).to_le_bytes();
76-
let addr = CollectionAddrInner::new(
77-
*casper::get_callee().address(),
78-
CollectionTypeTag::Vector,
79-
collection_prefix,
80-
casper::generic_hash(&prefix_bytes, crate::types::HashAlgorithm::Blake2b).unwrap(),
81-
);
82-
casper::write(
83-
Keyspace::Context(ContextAddr::from(addr)),
84-
&borsh::to_vec(&value).unwrap(),
85-
)
86-
.unwrap();
74+
let addr = self.calculate_addr(self.length);
75+
casper::write(Keyspace::Context(addr), &borsh::to_vec(&value).unwrap()).unwrap();
8776
self.length += 1;
8877
}
8978

@@ -107,15 +96,8 @@ where
10796

10897
/// Returns an element at index, deserialized.
10998
pub fn get(&self, index: u64) -> Option<T> {
110-
let prefix = self.compute_prefix_bytes_for_index(index);
111-
let collection_prefix = fnv1a_hash_str_64(self.prefix.as_str()).to_le_bytes();
112-
let addr = CollectionAddrInner::new(
113-
*casper::get_callee().address(),
114-
CollectionTypeTag::Vector,
115-
collection_prefix,
116-
casper::generic_hash(&prefix, crate::types::HashAlgorithm::Blake2b).unwrap(),
117-
);
118-
let item_keyspace = Keyspace::Context(ContextAddr::from(addr));
99+
let addr = self.calculate_addr(index);
100+
let item_keyspace = Keyspace::Context(addr);
119101
read_into_vec(item_keyspace)
120102
.unwrap()
121103
.map(|vec| borsh::from_slice(&vec).unwrap())
@@ -149,15 +131,8 @@ where
149131
/// from the global state.
150132
pub fn clear(&mut self) {
151133
for i in 0..self.length {
152-
let prefix_bytes = self.compute_prefix_bytes_for_index(i);
153-
let collection_prefix = fnv1a_hash_str_64(self.prefix.as_str()).to_le_bytes();
154-
let addr = CollectionAddrInner::new(
155-
*casper::get_callee().address(),
156-
CollectionTypeTag::Vector,
157-
collection_prefix,
158-
casper::generic_hash(&prefix_bytes, crate::types::HashAlgorithm::Blake2b).unwrap(),
159-
);
160-
casper::remove(Keyspace::Context(ContextAddr::from(addr))).unwrap();
134+
let addr = self.calculate_addr(i);
135+
casper::remove(Keyspace::Context(addr)).unwrap();
161136
}
162137
self.length = 0;
163138
}
@@ -239,7 +214,6 @@ where
239214
if index >= self.length {
240215
return None;
241216
}
242-
243217
let value_to_remove = self.get(index).unwrap();
244218

245219
// Shift elements to the left
@@ -248,20 +222,10 @@ where
248222
self.write(i, next_value);
249223
}
250224
}
251-
252225
// Remove the last element from storage
253226
self.length -= 1;
254-
let addr = CollectionAddrInner::new(
255-
*casper::get_callee().address(),
256-
CollectionTypeTag::Vector,
257-
[0u8; 8],
258-
casper::generic_hash(
259-
&self.compute_prefix_bytes_for_index(self.length),
260-
crate::types::HashAlgorithm::Blake2b,
261-
)
262-
.unwrap(),
263-
);
264-
casper::remove(Keyspace::Context(ContextAddr::from(addr))).unwrap();
227+
let addr = self.calculate_addr(self.length);
228+
casper::remove(Keyspace::Context(addr)).unwrap();
265229

266230
Some(value_to_remove)
267231
}
@@ -283,17 +247,8 @@ where
283247
}
284248

285249
self.length -= 1;
286-
let addr = CollectionAddrInner::new(
287-
*casper::get_callee().address(),
288-
CollectionTypeTag::Vector,
289-
[0u8; 8],
290-
casper::generic_hash(
291-
&self.compute_prefix_bytes_for_index(self.length),
292-
crate::types::HashAlgorithm::Blake2b,
293-
)
294-
.unwrap(),
295-
);
296-
casper::remove(Keyspace::Context(ContextAddr::from(addr))).unwrap();
250+
let addr = self.calculate_addr(self.length);
251+
casper::remove(Keyspace::Context(addr)).unwrap();
297252

298253
Some(value_to_remove)
299254
}
@@ -319,6 +274,11 @@ where
319274
}
320275

321276
fn write(&self, index: u64, value: T) {
277+
let addr = self.calculate_addr(index);
278+
casper::write(Keyspace::Context(addr), &borsh::to_vec(&value).unwrap()).unwrap();
279+
}
280+
281+
fn calculate_addr(&self, index: u64) -> ContextAddr {
322282
let prefix_bytes = self.compute_prefix_bytes_for_index(index);
323283
let collection_prefix = fnv1a_hash_str_64(self.prefix.as_str()).to_le_bytes();
324284
let addr = CollectionAddrInner::new(
@@ -327,11 +287,7 @@ where
327287
collection_prefix,
328288
casper::generic_hash(&prefix_bytes, crate::types::HashAlgorithm::Blake2b).unwrap(),
329289
);
330-
casper::write(
331-
Keyspace::Context(ContextAddr::from(addr)),
332-
&borsh::to_vec(&value).unwrap(),
333-
)
334-
.unwrap();
290+
ContextAddr::from(addr)
335291
}
336292
}
337293

storage/src/tracking_copy/mod.rs

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use std::{
1414
borrow::Borrow,
1515
collections::{BTreeMap, BTreeSet, HashSet, VecDeque},
1616
convert::{From, TryInto},
17-
fmt::Debug,
17+
fmt::{Debug, Display},
1818
sync::Arc,
1919
};
2020

@@ -101,6 +101,27 @@ impl TrackingCopyQueryResult {
101101
}
102102
}
103103

104+
#[derive(Error, Debug, PartialEq, Eq)]
105+
/// Enum encapsulating data returned by the cache
106+
pub enum CacheEntry<'a> {
107+
/// This entry was pruned
108+
Pruned,
109+
/// Cache is not aware of this element
110+
NotFound,
111+
/// Cache contains an unpruned version of this entry
112+
Exists(&'a StoredValue),
113+
}
114+
115+
impl Display for CacheEntry<'_> {
116+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
117+
match self {
118+
CacheEntry::Pruned => write!(f, "TrackingCopyEntry::Pruned"),
119+
CacheEntry::NotFound => write!(f, "TrackingCopyEntry::NotFound"),
120+
CacheEntry::Exists(_) => write!(f, "TrackingCopyEntry::Exists"),
121+
}
122+
}
123+
}
124+
104125
/// Struct containing state relating to a given query.
105126
struct Query {
106127
/// The key from where the search starts.
@@ -238,22 +259,27 @@ impl<M: Meter<Key, StoredValue> + Copy + Default> GenericTrackingCopyCache<M> {
238259

239260
/// Inserts `key` and `value` pair to Write/Add cache.
240261
pub fn insert_prune(&mut self, key: Key) {
262+
let kb = KeyWithByteRepr::new(key.clone());
263+
self.muts_cached.remove(&kb);
241264
self.prunes_cached.insert(key);
242265
}
243266

244267
/// Gets value from `key` in the cache.
245-
pub fn get(&mut self, key: &Key) -> Option<&StoredValue> {
268+
pub fn get<'a>(&'a mut self, key: &Key) -> CacheEntry<'a> {
246269
if self.prunes_cached.contains(key) {
247270
// the item is marked for pruning and therefore
248271
// is no longer accessible.
249-
return None;
272+
return CacheEntry::Pruned;
250273
}
251274
let kb = KeyWithByteRepr::new(*key);
252275
if let Some(value) = self.muts_cached.get(&kb) {
253-
return Some(value);
276+
return CacheEntry::Exists(value);
254277
};
255278

256-
self.reads_cached.get_refresh(key).map(|v| &*v)
279+
match self.reads_cached.get_refresh(key).map(|v| &*v) {
280+
Some(v) => CacheEntry::Exists(v),
281+
None => CacheEntry::NotFound,
282+
}
257283
}
258284

259285
/// Get cached items by prefix.
@@ -485,9 +511,13 @@ where
485511

486512
/// Get record by key.
487513
pub fn get(&mut self, key: &Key) -> Result<Option<StoredValue>, TrackingCopyError> {
488-
if let Some(value) = self.cache.get(key) {
514+
let get = self.cache.get(key);
515+
if let CacheEntry::Exists(value) = get {
489516
return Ok(Some(value.to_owned()));
490517
}
518+
if let CacheEntry::Pruned = get {
519+
return Ok(None);
520+
}
491521
match self.reader.read(key) {
492522
Ok(ret) => {
493523
if let Some(value) = ret {

0 commit comments

Comments
 (0)