diff --git a/linera-views/src/collection_view.rs b/linera-views/src/collection_view.rs index ee9c372f9812..af1e95db196f 100644 --- a/linera-views/src/collection_view.rs +++ b/linera-views/src/collection_view.rs @@ -173,7 +173,6 @@ where /// # }) /// ``` pub async fn load_entry_mut(&mut self, short_key: Vec) -> Result<&mut W, ViewError> { - *self.hash.get_mut() = None; self.do_load_entry_mut(short_key).await } @@ -277,7 +276,6 @@ where /// # }) /// ``` pub async fn reset_entry_to_default(&mut self, short_key: Vec) -> Result<(), ViewError> { - *self.hash.get_mut() = None; let view = self.load_entry_mut(short_key).await?; view.clear(); Ok(()) @@ -316,6 +314,7 @@ where } async fn do_load_entry_mut(&mut self, short_key: Vec) -> Result<&mut W, ViewError> { + *self.hash.get_mut() = None; match self.updates.get_mut().entry(short_key.clone()) { btree_map::Entry::Occupied(entry) => { let entry = entry.into_mut(); diff --git a/linera-views/src/map_view.rs b/linera-views/src/map_view.rs index 90e1c868110d..80ea2c3222c4 100644 --- a/linera-views/src/map_view.rs +++ b/linera-views/src/map_view.rs @@ -273,6 +273,7 @@ where /// # }) /// ``` pub async fn get_mut(&mut self, short_key: Vec) -> Result, ViewError> { + *self.hash.get_mut() = None; self.load_value(&short_key).await?; if let Some(update) = self.updates.get_mut(&short_key) { let value = match update { @@ -698,6 +699,7 @@ where pub async fn get_mut_or_default(&mut self, short_key: Vec) -> Result<&mut V, ViewError> { use std::collections::btree_map::Entry; + *self.hash.get_mut() = None; let update = match self.updates.entry(short_key.clone()) { Entry::Vacant(e) if self.delete_storage_first => e.insert(Update::Set(V::default())), Entry::Vacant(e) => { diff --git a/linera-views/tests/map_view_tests.rs b/linera-views/tests/map_view_tests.rs index bb522a0f206d..5c56a2942cad 100644 --- a/linera-views/tests/map_view_tests.rs +++ b/linera-views/tests/map_view_tests.rs @@ -4,7 +4,7 @@ use linera_views::{ map_view::ByteMapView, memory::create_memory_context, - views::{CryptoHashRootView, RootView, View}, + views::{CryptoHashRootView, CryptoHashView, RootView, View}, }; use rand::{distributions::Uniform, Rng, RngCore, SeedableRng}; use std::collections::{BTreeMap, BTreeSet}; @@ -27,6 +27,7 @@ async fn run_map_view_mutability(rng: &mut R) { let mut view = StateView::load(context.clone()).await.unwrap(); let save = rng.gen::(); let read_state = view.map.key_values().await.unwrap(); + let read_hash = view.crypto_hash().await.unwrap(); let state_vec = state_map.clone().into_iter().collect::>(); assert_eq!(state_vec, read_state); // @@ -34,7 +35,7 @@ async fn run_map_view_mutability(rng: &mut R) { let mut new_state_map = state_map.clone(); let mut new_state_vec = state_vec.clone(); for _ in 0..count_oper { - let choice = rng.gen_range(0..5); + let choice = rng.gen_range(0..7); let count = view.map.count().await.unwrap(); if choice == 0 { // inserting random stuff @@ -79,7 +80,45 @@ async fn run_map_view_mutability(rng: &mut R) { view.rollback(); new_state_map = state_map.clone(); } + if choice == 5 && count > 0 { + let pos = rng.gen_range(0..count); + let vec = new_state_vec[pos].clone(); + let key = vec.0; + let result = view.map.get_mut(key.clone()).await.unwrap().unwrap(); + let new_value = rng.gen::(); + *result = new_value; + new_state_map.insert(key, new_value); + } + if choice == 6 && count > 0 { + let choice = rng.gen_range(0..count); + let key = match choice { + 0 => { + // Scenario 1 of using existing key + let pos = rng.gen_range(0..count); + let vec = new_state_vec[pos].clone(); + vec.0 + } + _ => { + let len = rng.gen_range(1..6); + rng.clone() + .sample_iter(Uniform::from(0..4)) + .take(len) + .collect::>() + } + }; + let result = view.map.get_mut_or_default(key.clone()).await.unwrap(); + let new_value = rng.gen::(); + *result = new_value; + new_state_map.insert(key, new_value); + } new_state_vec = new_state_map.clone().into_iter().collect(); + let new_hash = view.crypto_hash().await.unwrap(); + if state_vec == new_state_vec { + assert_eq!(new_hash, read_hash); + } else { + // Hash equality is a bug or a hash collision (unlikely) + assert_ne!(new_hash, read_hash); + } let new_key_values = view.map.key_values().await.unwrap(); assert_eq!(new_state_vec, new_key_values); for u in 0..4 {