diff --git a/Cargo.lock b/Cargo.lock index 937b773a28..84eebf4ecc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10267,8 +10267,10 @@ dependencies = [ "forkable-jellyfish-merkle", "parking_lot 0.12.0", "serde 1.0.136", + "starcoin-config", "starcoin-crypto", "starcoin-state-store-api", + "starcoin-storage", "starcoin-types", "starcoin-vm-types", ] diff --git a/state/state-tree/Cargo.toml b/state/state-tree/Cargo.toml index b3d080a85e..f62dd615db 100644 --- a/state/state-tree/Cargo.toml +++ b/state/state-tree/Cargo.toml @@ -17,3 +17,7 @@ serde = { version = "1.0.130" } forkable-jellyfish-merkle = { path = "../../commons/forkable-jellyfish-merkle"} starcoin-state-store-api = {path = "../state-store-api"} bcs-ext = { package="bcs-ext", path = "../../commons/bcs_ext" } + +[dev-dependencies] +starcoin-config= { path = "../../config"} +starcoin-storage = { path = "../../storage"} diff --git a/state/state-tree/src/state_tree_test.rs b/state/state-tree/src/state_tree_test.rs index a1d6f4282c..20c528909a 100644 --- a/state/state-tree/src/state_tree_test.rs +++ b/state/state-tree/src/state_tree_test.rs @@ -3,7 +3,11 @@ use crate::mock::MockStateNodeStore; use anyhow::Result; use forkable_jellyfish_merkle::blob::Blob; use forkable_jellyfish_merkle::{HashValueKey, RawKey}; +use starcoin_config::RocksdbConfig; use starcoin_crypto::hash::*; +use starcoin_storage::db_storage::DBStorage; +use starcoin_storage::storage::StorageInstance; +use starcoin_storage::Storage; use std::collections::HashMap; use std::sync::Arc; @@ -211,3 +215,69 @@ pub fn test_state_storage_dump() -> Result<()> { assert_eq!(kv1, kv2); Ok(()) } + +#[test] +pub fn test_state_multi_commit_missing_node() -> Result<()> { + let tmpdir = starcoin_config::temp_dir(); + let instance = StorageInstance::new_db_instance(DBStorage::new( + tmpdir.path(), + RocksdbConfig::default(), + None, + )?); + let storage = Storage::new(instance)?; + let state = StateTree::new(Arc::new(storage.clone()), None); + let hash_value1 = HashValueKey(HashValue::random()); + let value1 = vec![1u8, 2u8]; + state.put(hash_value1, value1); + state.commit()?; + let root_hash1 = state.root_hash(); + let hash_value2 = HashValueKey(HashValue::random()); + let value12 = vec![12u8, 2u8]; + let value2 = vec![3u8, 4u8]; + state.put(hash_value1, value12.clone()); + state.put(hash_value2, value2.clone()); + state.commit()?; + state.flush()?; + let root_hash2 = state.root_hash(); + let state1 = StateTree::new(Arc::new(storage.clone()), Some(root_hash1)); + let result = state1.get(&hash_value1); + assert!(result.is_err(), "Missing node at HashValue"); + + let state2 = StateTree::new(Arc::new(storage), Some(root_hash2)); + assert_eq!(state2.get(&hash_value1)?, Some(value12)); + assert_eq!(state2.get(&hash_value2)?, Some(value2)); + Ok(()) +} + +#[test] +pub fn test_state_multi_commit_and_flush() -> Result<()> { + let tmpdir = starcoin_config::temp_dir(); + let instance = StorageInstance::new_db_instance(DBStorage::new( + tmpdir.path(), + RocksdbConfig::default(), + None, + )?); + let storage = Storage::new(instance)?; + let state = StateTree::new(Arc::new(storage.clone()), None); + let hash_value1 = HashValueKey(HashValue::random()); + let value1 = vec![1u8, 2u8]; + state.put(hash_value1, value1.clone()); + state.commit()?; + state.flush()?; + let root_hash1 = state.root_hash(); + let hash_value2 = HashValueKey(HashValue::random()); + let value12 = vec![12u8, 2u8]; + let value2 = vec![3u8, 4u8]; + state.put(hash_value1, value12.clone()); + state.put(hash_value2, value2.clone()); + state.commit()?; + state.flush()?; + let root_hash2 = state.root_hash(); + let state1 = StateTree::new(Arc::new(storage.clone()), Some(root_hash1)); + assert_eq!(state1.get(&hash_value1)?, Some(value1)); + + let state2 = StateTree::new(Arc::new(storage), Some(root_hash2)); + assert_eq!(state2.get(&hash_value1)?, Some(value12)); + assert_eq!(state2.get(&hash_value2)?, Some(value2)); + Ok(()) +}