//! Shard state management. //! //! Each shard maintains its own Merkle state tree for accounts and storage. use std::collections::HashMap; use std::sync::Arc; use parking_lot::RwLock; use serde::{Deserialize, Serialize}; use synor_types::Hash256; use crate::{ShardError, ShardId, ShardResult}; /// Individual shard state with Merkle tree. #[derive(Clone, Debug)] pub struct ShardState { /// Shard identifier. pub shard_id: ShardId, /// State root hash. pub state_root: Hash256, /// Account states (simplified - production would use Merkle Patricia Trie). accounts: HashMap, /// Block height within this shard. pub block_height: u64, /// Last finalized block hash. pub last_finalized: Hash256, } /// Account state within a shard. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AccountState { /// Account address. pub address: Hash256, /// Balance in smallest unit. pub balance: u128, /// Account nonce (transaction count). pub nonce: u64, /// Storage root for contract accounts. pub storage_root: Hash256, /// Code hash for contract accounts. pub code_hash: Hash256, } impl Default for AccountState { fn default() -> Self { Self { address: Hash256::from_bytes([0u8; 32]), balance: 0, nonce: 0, storage_root: Hash256::from_bytes([0u8; 32]), code_hash: Hash256::from_bytes([0u8; 32]), } } } impl ShardState { /// Creates a new empty shard state. pub fn new(shard_id: ShardId) -> Self { Self { shard_id, state_root: Hash256::from_bytes([0u8; 32]), accounts: HashMap::new(), block_height: 0, last_finalized: Hash256::from_bytes([0u8; 32]), } } /// Gets an account state. pub fn get_account(&self, address: &Hash256) -> Option<&AccountState> { self.accounts.get(address) } /// Updates an account state. pub fn update_account(&mut self, address: Hash256, state: AccountState) { self.accounts.insert(address, state); self.update_state_root(); } /// Gets the account balance. pub fn get_balance(&self, address: &Hash256) -> u128 { self.accounts.get(address).map(|a| a.balance).unwrap_or(0) } /// Transfers balance between accounts (within same shard). pub fn transfer( &mut self, from: &Hash256, to: &Hash256, amount: u128, ) -> ShardResult<()> { let from_balance = self.get_balance(from); if from_balance < amount { return Err(ShardError::Internal("Insufficient balance".into())); } // Update sender let mut from_state = self.accounts.get(from).cloned().unwrap_or_default(); from_state.address = *from; from_state.balance = from_balance - amount; from_state.nonce += 1; self.accounts.insert(*from, from_state); // Update receiver let mut to_state = self.accounts.get(to).cloned().unwrap_or_default(); to_state.address = *to; to_state.balance += amount; self.accounts.insert(*to, to_state); self.update_state_root(); Ok(()) } /// Updates the state root after modifications. fn update_state_root(&mut self) { // Simplified: hash all account states // Production would use proper Merkle Patricia Trie let mut hasher = blake3::Hasher::new(); hasher.update(&self.shard_id.to_le_bytes()); hasher.update(&self.block_height.to_le_bytes()); let mut sorted_accounts: Vec<_> = self.accounts.iter().collect(); sorted_accounts.sort_by_key(|(k, _)| *k); for (addr, state) in sorted_accounts { hasher.update(addr.as_bytes()); hasher.update(&state.balance.to_le_bytes()); hasher.update(&state.nonce.to_le_bytes()); } let hash = hasher.finalize(); self.state_root = Hash256::from_bytes(*hash.as_bytes()); } /// Advances to the next block. pub fn advance_block(&mut self, block_hash: Hash256) { self.block_height += 1; self.last_finalized = block_hash; self.update_state_root(); } /// Returns the number of accounts. pub fn account_count(&self) -> usize { self.accounts.len() } /// Generates a state proof for an account. pub fn generate_proof(&self, address: &Hash256) -> StateProof { StateProof { shard_id: self.shard_id, state_root: self.state_root, address: *address, account: self.accounts.get(address).cloned(), // Simplified: production would include Merkle path merkle_path: vec![], } } } /// Merkle state proof for cross-shard verification. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct StateProof { /// Shard the proof is from. pub shard_id: ShardId, /// State root at time of proof. pub state_root: Hash256, /// Account address being proved. pub address: Hash256, /// Account state (None if doesn't exist). pub account: Option, /// Merkle path from account to root. pub merkle_path: Vec, } impl StateProof { /// Verifies the proof against a known state root. pub fn verify(&self, expected_root: &Hash256) -> bool { // Simplified verification // Production would verify full Merkle path &self.state_root == expected_root } } /// Manages state across all shards. pub struct ShardStateManager { /// Per-shard states. shards: Arc>>, /// Number of shards. num_shards: u16, } impl ShardStateManager { /// Creates a new state manager with initialized shards. pub fn new(num_shards: u16) -> Self { let mut shards = HashMap::new(); for i in 0..num_shards { shards.insert(i, ShardState::new(i)); } Self { shards: Arc::new(RwLock::new(shards)), num_shards, } } /// Gets the state root for a shard. pub fn get_state_root(&self, shard_id: ShardId) -> Option { self.shards.read().get(&shard_id).map(|s| s.state_root) } /// Gets a shard state (read-only). pub fn get_shard(&self, shard_id: ShardId) -> Option { self.shards.read().get(&shard_id).cloned() } /// Updates a shard state. pub fn update_shard(&self, shard_id: ShardId, state: ShardState) { self.shards.write().insert(shard_id, state); } /// Executes a function on a shard's state. pub fn with_shard_mut(&self, shard_id: ShardId, f: F) -> Option where F: FnOnce(&mut ShardState) -> R, { self.shards.write().get_mut(&shard_id).map(f) } /// Splits a shard into multiple new shards (for dynamic resharding). pub fn split_shard(&self, shard_id: ShardId, new_shard_ids: &[ShardId]) { let mut shards = self.shards.write(); if let Some(old_shard) = shards.remove(&shard_id) { // Distribute accounts to new shards based on address let mut new_shards: HashMap = new_shard_ids .iter() .map(|&id| (id, ShardState::new(id))) .collect(); for (addr, account) in old_shard.accounts { // Determine which new shard this account belongs to let bytes = addr.as_bytes(); let shard_num = u16::from_le_bytes([bytes[0], bytes[1]]); let new_shard_id = new_shard_ids[shard_num as usize % new_shard_ids.len()]; if let Some(shard) = new_shards.get_mut(&new_shard_id) { shard.update_account(addr, account); } } // Add new shards for (id, shard) in new_shards { shards.insert(id, shard); } } } /// Merges multiple shards into one (for dynamic resharding). pub fn merge_shards(&self, shard_ids: &[ShardId], into: ShardId) { let mut shards = self.shards.write(); let mut merged = ShardState::new(into); // Collect all accounts from shards being merged for &shard_id in shard_ids { if let Some(shard) = shards.remove(&shard_id) { for (addr, account) in shard.accounts { merged.update_account(addr, account); } } } shards.insert(into, merged); } /// Gets all shard state roots for beacon chain commitment. pub fn get_all_state_roots(&self) -> Vec<(ShardId, Hash256)> { self.shards .read() .iter() .map(|(&id, state)| (id, state.state_root)) .collect() } /// Returns the total number of accounts across all shards. pub fn total_accounts(&self) -> usize { self.shards.read().values().map(|s| s.account_count()).sum() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_shard_state_new() { let state = ShardState::new(5); assert_eq!(state.shard_id, 5); assert_eq!(state.block_height, 0); assert_eq!(state.account_count(), 0); } #[test] fn test_account_update() { let mut state = ShardState::new(0); let addr = Hash256::from_bytes([1u8; 32]); let account = AccountState { address: addr, balance: 1000, nonce: 0, ..Default::default() }; state.update_account(addr, account); assert_eq!(state.get_balance(&addr), 1000); assert_eq!(state.account_count(), 1); } #[test] fn test_transfer() { let mut state = ShardState::new(0); let alice = Hash256::from_bytes([1u8; 32]); let bob = Hash256::from_bytes([2u8; 32]); // Give Alice some balance state.update_account( alice, AccountState { address: alice, balance: 1000, nonce: 0, ..Default::default() }, ); // Transfer to Bob state.transfer(&alice, &bob, 300).unwrap(); assert_eq!(state.get_balance(&alice), 700); assert_eq!(state.get_balance(&bob), 300); } #[test] fn test_state_manager() { let manager = ShardStateManager::new(4); // Check all shards initialized for i in 0..4 { assert!(manager.get_state_root(i).is_some()); } // Update a shard manager.with_shard_mut(0, |shard| { let addr = Hash256::from_bytes([1u8; 32]); shard.update_account( addr, AccountState { address: addr, balance: 500, ..Default::default() }, ); }); assert_eq!(manager.total_accounts(), 1); } #[test] fn test_state_proof() { let mut state = ShardState::new(0); let addr = Hash256::from_bytes([1u8; 32]); state.update_account( addr, AccountState { address: addr, balance: 1000, ..Default::default() }, ); let proof = state.generate_proof(&addr); assert!(proof.verify(&state.state_root)); assert_eq!(proof.account.unwrap().balance, 1000); } }