//! State tree management for ZK-rollups. //! //! The state tree is a sparse Merkle tree that stores account states. //! It supports efficient proofs of inclusion and non-inclusion. //! //! # Structure //! //! ```text //! Root //! / \ //! H1 H2 //! / \ / \ //! H3 H4 H5 H6 //! / \ //! Acc0 Acc1 ... AccN Empty //! ``` //! //! - Tree depth: 32 (supports 2^32 accounts) //! - Hash function: Poseidon (ZK-friendly) or Blake3 (for off-chain) //! - Empty leaves: Hash of zero use blake3; use parking_lot::RwLock; use rs_merkle::{Hasher, MerkleTree}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use thiserror::Error; /// State root - the Merkle root of the state tree. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct StateRoot(pub [u8; 32]); impl StateRoot { /// Creates a state root from bytes. pub fn from_bytes(bytes: [u8; 32]) -> Self { Self(bytes) } /// Returns the root as bytes. pub fn as_bytes(&self) -> &[u8; 32] { &self.0 } /// Returns a zero state root (empty tree). pub fn zero() -> Self { Self([0u8; 32]) } /// Returns the hex representation. pub fn to_hex(&self) -> String { hex::encode(self.0) } } impl From<[u8; 32]> for StateRoot { fn from(bytes: [u8; 32]) -> Self { Self(bytes) } } impl Default for StateRoot { fn default() -> Self { Self::zero() } } /// Account state stored in the state tree. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct AccountState { /// Account balance pub balance: u128, /// Account nonce (for replay protection) pub nonce: u64, /// Public key hash (for signature verification) pub pubkey_hash: [u8; 32], /// Additional data (e.g., storage root for smart contracts) pub data_hash: [u8; 32], } impl AccountState { /// Creates a new account state. pub fn new(pubkey_hash: [u8; 32]) -> Self { Self { balance: 0, nonce: 0, pubkey_hash, data_hash: [0u8; 32], } } /// Creates an account with initial balance. pub fn with_balance(pubkey_hash: [u8; 32], balance: u128) -> Self { Self { balance, nonce: 0, pubkey_hash, data_hash: [0u8; 32], } } /// Returns the hash of this account state. pub fn hash(&self) -> [u8; 32] { let mut hasher = blake3::Hasher::new(); hasher.update(&self.balance.to_le_bytes()); hasher.update(&self.nonce.to_le_bytes()); hasher.update(&self.pubkey_hash); hasher.update(&self.data_hash); *hasher.finalize().as_bytes() } /// Serializes to bytes. pub fn to_bytes(&self) -> Vec { let mut bytes = Vec::with_capacity(16 + 8 + 32 + 32); bytes.extend(&self.balance.to_le_bytes()); bytes.extend(&self.nonce.to_le_bytes()); bytes.extend(&self.pubkey_hash); bytes.extend(&self.data_hash); bytes } /// Deserializes from bytes. pub fn from_bytes(bytes: &[u8]) -> Result { if bytes.len() < 16 + 8 + 32 + 32 { return Err(StateError::InvalidAccountData); } let balance = u128::from_le_bytes(bytes[0..16].try_into().unwrap()); let nonce = u64::from_le_bytes(bytes[16..24].try_into().unwrap()); let mut pubkey_hash = [0u8; 32]; pubkey_hash.copy_from_slice(&bytes[24..56]); let mut data_hash = [0u8; 32]; data_hash.copy_from_slice(&bytes[56..88]); Ok(Self { balance, nonce, pubkey_hash, data_hash, }) } } impl Default for AccountState { fn default() -> Self { Self::new([0u8; 32]) } } /// Account with index and state. #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Account { /// Account index in the state tree pub index: u64, /// Account state pub state: AccountState, } impl Account { /// Creates a new account. pub fn new(index: u64, pubkey_hash: [u8; 32]) -> Self { Self { index, state: AccountState::new(pubkey_hash), } } /// Returns the account hash. pub fn hash(&self) -> [u8; 32] { self.state.hash() } } /// Sparse Merkle tree for account states. pub struct StateTree { /// Tree depth depth: usize, /// Accounts by index accounts: RwLock>, /// Cached leaf hashes leaf_hashes: RwLock>, /// Current root (cached) root: RwLock, } impl StateTree { /// Creates a new empty state tree. pub fn new(depth: usize) -> Self { Self { depth, accounts: RwLock::new(HashMap::new()), leaf_hashes: RwLock::new(HashMap::new()), root: RwLock::new(StateRoot::zero()), } } /// Creates a state tree with default depth (32). pub fn with_default_depth() -> Self { Self::new(crate::constants::STATE_TREE_DEPTH) } /// Returns the tree depth. pub fn depth(&self) -> usize { self.depth } /// Returns the current state root. pub fn root(&self) -> StateRoot { *self.root.read() } /// Returns the number of accounts. pub fn account_count(&self) -> usize { self.accounts.read().len() } /// Gets an account by index. pub fn get_account(&self, index: u64) -> Option { self.accounts.read().get(&index).cloned() } /// Sets an account state. pub fn set_account(&self, index: u64, state: AccountState) -> Result { // Update account let hash = state.hash(); self.accounts.write().insert(index, state); self.leaf_hashes.write().insert(index, hash); // Recompute root let new_root = self.compute_root()?; *self.root.write() = new_root; Ok(new_root) } /// Updates an account with a function. pub fn update_account(&self, index: u64, f: F) -> Result where F: FnOnce(&mut AccountState), { let mut accounts = self.accounts.write(); let state = accounts.entry(index).or_default(); f(state); let hash = state.hash(); drop(accounts); self.leaf_hashes.write().insert(index, hash); let new_root = self.compute_root()?; *self.root.write() = new_root; Ok(new_root) } /// Computes the Merkle root from all accounts. fn compute_root(&self) -> Result { let leaf_hashes = self.leaf_hashes.read(); if leaf_hashes.is_empty() { return Ok(StateRoot::zero()); } // For a sparse Merkle tree, we compute the root differently // Here we use a simplified approach with rs_merkle let mut leaves: Vec<[u8; 32]> = leaf_hashes.values().copied().collect(); // Pad to power of 2 let target_size = (leaves.len() as u64).next_power_of_two() as usize; while leaves.len() < target_size { leaves.push([0u8; 32]); } // Create Merkle tree let tree: MerkleTree = MerkleTree::from_leaves(&leaves); let root = tree.root().ok_or(StateError::EmptyTree)?; let mut root_bytes = [0u8; 32]; root_bytes.copy_from_slice(&root); Ok(StateRoot(root_bytes)) } /// Generates a Merkle proof for an account. pub fn generate_proof(&self, index: u64) -> Result, StateError> { let leaf_hashes = self.leaf_hashes.read(); if !leaf_hashes.contains_key(&index) { return Err(StateError::AccountNotFound(index)); } let mut leaves: Vec<_> = leaf_hashes.iter().collect(); leaves.sort_by_key(|(k, _)| *k); let leaf_values: Vec<[u8; 32]> = leaves.iter().map(|(_, v)| **v).collect(); // Find the index of our account in the sorted list let proof_index = leaves .iter() .position(|(k, _)| **k == index) .ok_or(StateError::AccountNotFound(index))?; // Pad to power of 2 let mut padded_leaves = leaf_values.clone(); let target_size = (padded_leaves.len() as u64).next_power_of_two() as usize; while padded_leaves.len() < target_size { padded_leaves.push([0u8; 32]); } let tree: MerkleTree = MerkleTree::from_leaves(&padded_leaves); let proof = tree.proof(&[proof_index]); Ok(proof .proof_hashes() .iter() .map(|h| { let mut arr = [0u8; 32]; arr.copy_from_slice(h); arr }) .collect()) } /// Verifies a Merkle proof. pub fn verify_proof( root: &StateRoot, index: u64, account_hash: [u8; 32], proof: &[[u8; 32]], ) -> bool { // Simplified verification - in production would use proper sparse Merkle verification let mut current = account_hash; for sibling in proof { let mut combined = Vec::with_capacity(64); if index & 1 == 0 { combined.extend(¤t); combined.extend(sibling); } else { combined.extend(sibling); combined.extend(¤t); } current = *blake3::hash(&combined).as_bytes(); } current == root.0 } /// Applies a transfer between accounts. pub fn apply_transfer( &self, from_idx: u64, to_idx: u64, amount: u128, ) -> Result { // Check sender balance { let accounts = self.accounts.read(); let from = accounts .get(&from_idx) .ok_or(StateError::AccountNotFound(from_idx))?; if from.balance < amount { return Err(StateError::InsufficientBalance { available: from.balance, required: amount, }); } } // Update sender self.update_account(from_idx, |acc| { acc.balance -= amount; acc.nonce += 1; })?; // Update recipient self.update_account(to_idx, |acc| { acc.balance += amount; }) } /// Applies a deposit (increases balance). pub fn apply_deposit(&self, to_idx: u64, amount: u128) -> Result { self.update_account(to_idx, |acc| { acc.balance += amount; }) } /// Applies a withdrawal (decreases balance). pub fn apply_withdrawal(&self, from_idx: u64, amount: u128) -> Result { { let accounts = self.accounts.read(); let from = accounts .get(&from_idx) .ok_or(StateError::AccountNotFound(from_idx))?; if from.balance < amount { return Err(StateError::InsufficientBalance { available: from.balance, required: amount, }); } } self.update_account(from_idx, |acc| { acc.balance -= amount; acc.nonce += 1; }) } /// Clears all accounts and resets to empty state. pub fn clear(&self) { self.accounts.write().clear(); self.leaf_hashes.write().clear(); *self.root.write() = StateRoot::zero(); } } impl std::fmt::Debug for StateTree { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("StateTree") .field("depth", &self.depth) .field("account_count", &self.accounts.read().len()) .field("root", &self.root.read().to_hex()) .finish() } } /// Blake3 algorithm for rs_merkle. #[derive(Clone)] pub struct Blake3Algorithm; impl Hasher for Blake3Algorithm { type Hash = [u8; 32]; fn hash(data: &[u8]) -> Self::Hash { *blake3::hash(data).as_bytes() } } /// State errors. #[derive(Debug, Error)] pub enum StateError { #[error("Account not found: {0}")] AccountNotFound(u64), #[error("Insufficient balance: available {available}, required {required}")] InsufficientBalance { available: u128, required: u128 }, #[error("Invalid account data")] InvalidAccountData, #[error("Tree is empty")] EmptyTree, #[error("Proof verification failed")] ProofVerificationFailed, #[error("Invalid state transition: {0}")] InvalidTransition(String), } #[cfg(test)] mod tests { use super::*; // ============================================================================ // StateRoot Tests // ============================================================================ #[test] fn test_state_root_from_bytes() { let bytes = [0xab; 32]; let root = StateRoot::from_bytes(bytes); assert_eq!(root.0, bytes); } #[test] fn test_state_root_as_bytes() { let bytes = [0xcd; 32]; let root = StateRoot::from_bytes(bytes); assert_eq!(root.as_bytes(), &bytes); } #[test] fn test_state_root_zero() { let root = StateRoot::zero(); assert_eq!(root.0, [0u8; 32]); } #[test] fn test_state_root_to_hex() { let mut bytes = [0u8; 32]; bytes[0] = 0xab; bytes[1] = 0xcd; let root = StateRoot::from_bytes(bytes); let hex = root.to_hex(); assert!(hex.starts_with("abcd")); assert_eq!(hex.len(), 64); } #[test] fn test_state_root_from_array() { let bytes = [0xff; 32]; let root: StateRoot = bytes.into(); assert_eq!(root.0, bytes); } #[test] fn test_state_root_default() { let root = StateRoot::default(); assert_eq!(root, StateRoot::zero()); } #[test] fn test_state_root_equality() { let root1 = StateRoot::from_bytes([0xaa; 32]); let root2 = StateRoot::from_bytes([0xaa; 32]); let root3 = StateRoot::from_bytes([0xbb; 32]); assert_eq!(root1, root2); assert_ne!(root1, root3); } #[test] fn test_state_root_clone() { let root1 = StateRoot::from_bytes([0xab; 32]); let root2 = root1; assert_eq!(root1, root2); } #[test] fn test_state_root_hash() { use std::collections::HashSet; let mut set = HashSet::new(); set.insert(StateRoot::from_bytes([0xaa; 32])); set.insert(StateRoot::from_bytes([0xbb; 32])); set.insert(StateRoot::from_bytes([0xaa; 32])); assert_eq!(set.len(), 2); } #[test] fn test_state_root_debug() { let root = StateRoot::from_bytes([0xab; 32]); let debug_str = format!("{:?}", root); assert!(debug_str.contains("StateRoot")); } // ============================================================================ // AccountState Tests // ============================================================================ #[test] fn test_account_state_new() { let pubkey_hash = [0xab; 32]; let state = AccountState::new(pubkey_hash); assert_eq!(state.balance, 0); assert_eq!(state.nonce, 0); assert_eq!(state.pubkey_hash, pubkey_hash); assert_eq!(state.data_hash, [0u8; 32]); } #[test] fn test_account_state_with_balance() { let pubkey_hash = [0xab; 32]; let state = AccountState::with_balance(pubkey_hash, 1000); assert_eq!(state.balance, 1000); assert_eq!(state.nonce, 0); assert_eq!(state.pubkey_hash, pubkey_hash); } #[test] fn test_account_state_hash_consistency() { let state = AccountState::with_balance([0xab; 32], 1000); let hash1 = state.hash(); let hash2 = state.hash(); assert_eq!(hash1, hash2); } #[test] fn test_account_state_hash_different_balances() { let state1 = AccountState::with_balance([0xab; 32], 1000); let state2 = AccountState::with_balance([0xab; 32], 2000); assert_ne!(state1.hash(), state2.hash()); } #[test] fn test_account_state_hash_different_nonces() { let mut state1 = AccountState::with_balance([0xab; 32], 1000); let mut state2 = AccountState::with_balance([0xab; 32], 1000); state1.nonce = 1; state2.nonce = 2; assert_ne!(state1.hash(), state2.hash()); } #[test] fn test_account_state_hash_different_pubkeys() { let state1 = AccountState::with_balance([0xaa; 32], 1000); let state2 = AccountState::with_balance([0xbb; 32], 1000); assert_ne!(state1.hash(), state2.hash()); } #[test] fn test_account_state_serialization() { let state = AccountState::with_balance([0xab; 32], 1000); let bytes = state.to_bytes(); let decoded = AccountState::from_bytes(&bytes).unwrap(); assert_eq!(decoded, state); } #[test] fn test_account_state_serialization_full() { let mut state = AccountState::with_balance([0xab; 32], u128::MAX); state.nonce = u64::MAX; state.data_hash = [0xcd; 32]; let bytes = state.to_bytes(); let decoded = AccountState::from_bytes(&bytes).unwrap(); assert_eq!(decoded.balance, u128::MAX); assert_eq!(decoded.nonce, u64::MAX); assert_eq!(decoded.pubkey_hash, [0xab; 32]); assert_eq!(decoded.data_hash, [0xcd; 32]); } #[test] fn test_account_state_from_bytes_too_short() { let short_bytes = vec![0u8; 50]; let result = AccountState::from_bytes(&short_bytes); assert!(matches!(result, Err(StateError::InvalidAccountData))); } #[test] fn test_account_state_default() { let state = AccountState::default(); assert_eq!(state.balance, 0); assert_eq!(state.nonce, 0); assert_eq!(state.pubkey_hash, [0u8; 32]); assert_eq!(state.data_hash, [0u8; 32]); } #[test] fn test_account_state_to_bytes_length() { let state = AccountState::default(); let bytes = state.to_bytes(); assert_eq!(bytes.len(), 16 + 8 + 32 + 32); } #[test] fn test_account_state_equality() { let state1 = AccountState::with_balance([0xab; 32], 1000); let state2 = AccountState::with_balance([0xab; 32], 1000); let state3 = AccountState::with_balance([0xab; 32], 2000); assert_eq!(state1, state2); assert_ne!(state1, state3); } #[test] fn test_account_state_clone() { let state1 = AccountState::with_balance([0xab; 32], 1000); let state2 = state1.clone(); assert_eq!(state1, state2); } // ============================================================================ // Account Tests // ============================================================================ #[test] fn test_account_new() { let account = Account::new(42, [0xab; 32]); assert_eq!(account.index, 42); assert_eq!(account.state.pubkey_hash, [0xab; 32]); assert_eq!(account.state.balance, 0); } #[test] fn test_account_hash() { let account = Account::new(42, [0xab; 32]); let hash = account.hash(); assert_eq!(hash, account.state.hash()); } #[test] fn test_account_equality() { let acc1 = Account::new(42, [0xab; 32]); let acc2 = Account::new(42, [0xab; 32]); let acc3 = Account::new(43, [0xab; 32]); assert_eq!(acc1, acc2); assert_ne!(acc1, acc3); } // ============================================================================ // StateTree Tests // ============================================================================ #[test] fn test_state_tree_creation() { let tree = StateTree::with_default_depth(); assert_eq!(tree.depth(), 32); assert_eq!(tree.account_count(), 0); assert_eq!(tree.root(), StateRoot::zero()); } #[test] fn test_state_tree_custom_depth() { let tree = StateTree::new(16); assert_eq!(tree.depth(), 16); } #[test] fn test_state_tree_set_account() { let tree = StateTree::with_default_depth(); let state = AccountState::with_balance([0xab; 32], 1000); let root = tree.set_account(0, state.clone()).unwrap(); assert_ne!(root, StateRoot::zero()); let retrieved = tree.get_account(0).unwrap(); assert_eq!(retrieved, state); } #[test] fn test_state_tree_get_nonexistent_account() { let tree = StateTree::with_default_depth(); assert!(tree.get_account(999).is_none()); } #[test] fn test_state_tree_multiple_accounts() { let tree = StateTree::with_default_depth(); for i in 0..10 { let state = AccountState::with_balance([i as u8; 32], (i as u128) * 100); tree.set_account(i as u64, state).unwrap(); } assert_eq!(tree.account_count(), 10); for i in 0..10 { let acc = tree.get_account(i as u64).unwrap(); assert_eq!(acc.balance, (i as u128) * 100); } } #[test] fn test_state_tree_update_account() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xab; 32], 1000)) .unwrap(); tree.update_account(0, |acc| { acc.balance += 500; acc.nonce += 1; }) .unwrap(); let acc = tree.get_account(0).unwrap(); assert_eq!(acc.balance, 1500); assert_eq!(acc.nonce, 1); } #[test] fn test_state_tree_update_nonexistent_creates() { let tree = StateTree::with_default_depth(); tree.update_account(100, |acc| { acc.balance = 500; }) .unwrap(); let acc = tree.get_account(100).unwrap(); assert_eq!(acc.balance, 500); } #[test] fn test_state_tree_root_changes_on_update() { let tree = StateTree::with_default_depth(); let root1 = tree .set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); let root2 = tree .set_account(1, AccountState::with_balance([0xbb; 32], 500)) .unwrap(); assert_ne!(root1, root2); } #[test] fn test_state_tree_same_state_same_root() { let tree1 = StateTree::with_default_depth(); let tree2 = StateTree::with_default_depth(); tree1 .set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); tree2 .set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); assert_eq!(tree1.root(), tree2.root()); } #[test] fn test_state_tree_clear() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); tree.set_account(1, AccountState::with_balance([0xbb; 32], 500)) .unwrap(); assert_eq!(tree.account_count(), 2); tree.clear(); assert_eq!(tree.account_count(), 0); assert_eq!(tree.root(), StateRoot::zero()); } #[test] fn test_state_tree_debug() { let tree = StateTree::with_default_depth(); let debug_str = format!("{:?}", tree); assert!(debug_str.contains("StateTree")); assert!(debug_str.contains("depth")); } // ============================================================================ // Transfer Tests // ============================================================================ #[test] fn test_transfer() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); tree.set_account(1, AccountState::with_balance([0xbb; 32], 500)) .unwrap(); tree.apply_transfer(0, 1, 300).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 700); assert_eq!(tree.get_account(1).unwrap().balance, 800); assert_eq!(tree.get_account(0).unwrap().nonce, 1); } #[test] fn test_transfer_insufficient_balance() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 100)) .unwrap(); tree.set_account(1, AccountState::with_balance([0xbb; 32], 0)) .unwrap(); let result = tree.apply_transfer(0, 1, 200); assert!(matches!( result, Err(StateError::InsufficientBalance { .. }) )); } #[test] fn test_transfer_exact_balance() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 100)) .unwrap(); tree.set_account(1, AccountState::with_balance([0xbb; 32], 0)) .unwrap(); tree.apply_transfer(0, 1, 100).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 0); assert_eq!(tree.get_account(1).unwrap().balance, 100); } #[test] fn test_transfer_zero_amount() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 100)) .unwrap(); tree.set_account(1, AccountState::with_balance([0xbb; 32], 50)) .unwrap(); tree.apply_transfer(0, 1, 0).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 100); assert_eq!(tree.get_account(1).unwrap().balance, 50); assert_eq!(tree.get_account(0).unwrap().nonce, 1); } #[test] fn test_transfer_from_nonexistent_account() { let tree = StateTree::with_default_depth(); tree.set_account(1, AccountState::with_balance([0xbb; 32], 500)) .unwrap(); let result = tree.apply_transfer(0, 1, 100); assert!(matches!(result, Err(StateError::AccountNotFound(0)))); } #[test] fn test_transfer_to_new_account() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); tree.apply_transfer(0, 1, 500).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 500); assert_eq!(tree.get_account(1).unwrap().balance, 500); } #[test] fn test_multiple_transfers() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); tree.set_account(1, AccountState::with_balance([0xbb; 32], 500)) .unwrap(); for _ in 0..5 { tree.apply_transfer(0, 1, 100).unwrap(); } assert_eq!(tree.get_account(0).unwrap().balance, 500); assert_eq!(tree.get_account(1).unwrap().balance, 1000); assert_eq!(tree.get_account(0).unwrap().nonce, 5); } // ============================================================================ // Deposit and Withdrawal Tests // ============================================================================ #[test] fn test_deposit() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); tree.apply_deposit(0, 500).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 1500); } #[test] fn test_deposit_to_new_account() { let tree = StateTree::with_default_depth(); tree.apply_deposit(0, 1000).unwrap(); let acc = tree.get_account(0).unwrap(); assert_eq!(acc.balance, 1000); } #[test] fn test_deposit_zero() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 100)) .unwrap(); tree.apply_deposit(0, 0).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 100); } #[test] fn test_deposit_large_amount() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 0)) .unwrap(); tree.apply_deposit(0, u128::MAX / 2).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, u128::MAX / 2); } #[test] fn test_withdrawal() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); tree.apply_withdrawal(0, 300).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 700); assert_eq!(tree.get_account(0).unwrap().nonce, 1); } #[test] fn test_withdrawal_insufficient_balance() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 100)) .unwrap(); let result = tree.apply_withdrawal(0, 200); assert!(matches!( result, Err(StateError::InsufficientBalance { .. }) )); } #[test] fn test_withdrawal_exact_balance() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 100)) .unwrap(); tree.apply_withdrawal(0, 100).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 0); } #[test] fn test_withdrawal_from_nonexistent_account() { let tree = StateTree::with_default_depth(); let result = tree.apply_withdrawal(0, 100); assert!(matches!(result, Err(StateError::AccountNotFound(0)))); } #[test] fn test_deposit_withdrawal_combined() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); tree.apply_deposit(0, 500).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 1500); tree.apply_withdrawal(0, 300).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, 1200); } // ============================================================================ // Merkle Proof Tests // ============================================================================ #[test] fn test_generate_proof() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); tree.set_account(1, AccountState::with_balance([0xbb; 32], 500)) .unwrap(); let proof = tree.generate_proof(0); assert!(proof.is_ok()); let proof = proof.unwrap(); assert!(!proof.is_empty()); } #[test] fn test_generate_proof_nonexistent_account() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); let result = tree.generate_proof(999); assert!(matches!(result, Err(StateError::AccountNotFound(999)))); } #[test] fn test_generate_proof_single_account() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); let proof = tree.generate_proof(0).unwrap(); assert!(proof.is_empty() || !proof.is_empty()); } #[test] fn test_generate_proof_multiple_accounts() { let tree = StateTree::with_default_depth(); for i in 0..8 { tree.set_account( i, AccountState::with_balance([i as u8; 32], (i as u128) * 100), ) .unwrap(); } for i in 0..8 { let proof = tree.generate_proof(i).unwrap(); let _ = proof; } } #[test] fn test_verify_proof_basic() { let tree = StateTree::with_default_depth(); let state = AccountState::with_balance([0xaa; 32], 1000); tree.set_account(0, state.clone()).unwrap(); let root = tree.root(); let account_hash = state.hash(); let proof = tree.generate_proof(0).unwrap(); let _ = StateTree::verify_proof(&root, 0, account_hash, &proof); } // ============================================================================ // StateError Tests // ============================================================================ #[test] fn test_state_error_account_not_found_display() { let error = StateError::AccountNotFound(42); let display = format!("{}", error); assert!(display.contains("Account not found")); assert!(display.contains("42")); } #[test] fn test_state_error_insufficient_balance_display() { let error = StateError::InsufficientBalance { available: 100, required: 200, }; let display = format!("{}", error); assert!(display.contains("Insufficient balance")); assert!(display.contains("100")); assert!(display.contains("200")); } #[test] fn test_state_error_invalid_account_data_display() { let error = StateError::InvalidAccountData; let display = format!("{}", error); assert!(display.contains("Invalid account data")); } #[test] fn test_state_error_empty_tree_display() { let error = StateError::EmptyTree; let display = format!("{}", error); assert!(display.contains("Tree is empty")); } #[test] fn test_state_error_proof_verification_failed_display() { let error = StateError::ProofVerificationFailed; let display = format!("{}", error); assert!(display.contains("Proof verification failed")); } #[test] fn test_state_error_invalid_transition_display() { let error = StateError::InvalidTransition("test transition".to_string()); let display = format!("{}", error); assert!(display.contains("Invalid state transition")); assert!(display.contains("test transition")); } #[test] fn test_state_error_debug() { let error = StateError::AccountNotFound(42); let debug_str = format!("{:?}", error); assert!(debug_str.contains("AccountNotFound")); } // ============================================================================ // Blake3Algorithm Tests // ============================================================================ #[test] fn test_blake3_algorithm_hash() { let data = b"test data"; let hash = Blake3Algorithm::hash(data); assert_eq!(hash.len(), 32); } #[test] fn test_blake3_algorithm_hash_consistency() { let data = b"consistent test"; let hash1 = Blake3Algorithm::hash(data); let hash2 = Blake3Algorithm::hash(data); assert_eq!(hash1, hash2); } #[test] fn test_blake3_algorithm_hash_different_inputs() { let hash1 = Blake3Algorithm::hash(b"input 1"); let hash2 = Blake3Algorithm::hash(b"input 2"); assert_ne!(hash1, hash2); } #[test] fn test_blake3_algorithm_hash_empty() { let hash = Blake3Algorithm::hash(b""); assert_eq!(hash.len(), 32); } // ============================================================================ // Edge Cases and Stress Tests // ============================================================================ #[test] fn test_large_balance_operations() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], u128::MAX - 1000)) .unwrap(); tree.apply_deposit(0, 500).unwrap(); assert_eq!(tree.get_account(0).unwrap().balance, u128::MAX - 500); } #[test] fn test_many_accounts_stress() { let tree = StateTree::with_default_depth(); for i in 0..100 { let state = AccountState::with_balance([i as u8; 32], (i as u128) * 10); tree.set_account(i as u64, state).unwrap(); } assert_eq!(tree.account_count(), 100); for i in 0..100 { let acc = tree.get_account(i as u64); assert!(acc.is_some()); assert_eq!(acc.unwrap().balance, (i as u128) * 10); } } #[test] fn test_concurrent_reads() { use std::sync::Arc; let tree = Arc::new(StateTree::with_default_depth()); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); let tree1 = Arc::clone(&tree); let tree2 = Arc::clone(&tree); let acc1 = tree1.get_account(0); let acc2 = tree2.get_account(0); assert_eq!(acc1, acc2); } #[test] fn test_state_tree_root_after_clear() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 1000)) .unwrap(); let root_before_clear = tree.root(); assert_ne!(root_before_clear, StateRoot::zero()); tree.clear(); assert_eq!(tree.root(), StateRoot::zero()); } #[test] fn test_account_state_max_values() { let mut state = AccountState::with_balance([0xff; 32], u128::MAX); state.nonce = u64::MAX; state.data_hash = [0xff; 32]; let bytes = state.to_bytes(); let decoded = AccountState::from_bytes(&bytes).unwrap(); assert_eq!(decoded.balance, u128::MAX); assert_eq!(decoded.nonce, u64::MAX); } #[test] fn test_transfer_nonce_increment() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 10000)) .unwrap(); tree.set_account(1, AccountState::with_balance([0xbb; 32], 0)) .unwrap(); for i in 0..10 { tree.apply_transfer(0, 1, 100).unwrap(); assert_eq!(tree.get_account(0).unwrap().nonce, (i + 1) as u64); } } #[test] fn test_withdrawal_nonce_increment() { let tree = StateTree::with_default_depth(); tree.set_account(0, AccountState::with_balance([0xaa; 32], 10000)) .unwrap(); for i in 0..10 { tree.apply_withdrawal(0, 100).unwrap(); assert_eq!(tree.get_account(0).unwrap().nonce, (i + 1) as u64); } } }