Skip to main content

neo_devpack_solidity/runtime/state/state_impl/
accounts.rs

1use super::*;
2
3impl StateManager {
4    /// Get account state
5    pub fn get_account(&self, address: &str) -> Option<&AccountState> {
6        self.accounts.get(address)
7    }
8
9    /// Get account balance
10    pub fn get_balance(&self, address: &str) -> Result<u64, RuntimeError> {
11        Ok(self
12            .accounts
13            .get(address)
14            .map(|account| account.balance)
15            .unwrap_or(0))
16    }
17
18    /// Set account balance
19    pub fn set_balance(&mut self, address: &str, balance: u64) -> Result<(), RuntimeError> {
20        let old_balance = self.get_balance(address)?;
21
22        let created_at = self.current_timestamp();
23        let account = self
24            .accounts
25            .entry(address.to_string())
26            .or_insert_with(|| AccountState {
27                address: address.to_string(),
28                balance: 0,
29                nonce: 0,
30                code: None,
31                code_hash: None,
32                storage_root: None,
33                created_at,
34            });
35
36        account.balance = balance;
37
38        // Record state change
39        self.record_change(StateChange {
40            change_type: StateChangeType::BalanceChange,
41            account: address.to_string(),
42            key: None,
43            old_value: Some(old_balance.to_le_bytes().to_vec()),
44            new_value: balance.to_le_bytes().to_vec(),
45        });
46
47        Ok(())
48    }
49
50    /// Get account nonce
51    pub fn get_nonce(&self, address: &str) -> Result<u64, RuntimeError> {
52        Ok(self
53            .accounts
54            .get(address)
55            .map(|account| account.nonce)
56            .unwrap_or(0))
57    }
58
59    /// Set account nonce
60    pub fn set_nonce(&mut self, address: &str, nonce: u64) -> Result<(), RuntimeError> {
61        let old_nonce = self.get_nonce(address)?;
62
63        let created_at = self.current_timestamp();
64        let account = self
65            .accounts
66            .entry(address.to_string())
67            .or_insert_with(|| AccountState {
68                address: address.to_string(),
69                balance: 0,
70                nonce: 0,
71                code: None,
72                code_hash: None,
73                storage_root: None,
74                created_at,
75            });
76
77        account.nonce = nonce;
78
79        // Record state change
80        self.record_change(StateChange {
81            change_type: StateChangeType::NonceChange,
82            account: address.to_string(),
83            key: None,
84            old_value: Some(old_nonce.to_le_bytes().to_vec()),
85            new_value: nonce.to_le_bytes().to_vec(),
86        });
87
88        Ok(())
89    }
90
91    /// Get contract code
92    pub fn get_code(&self, address: &str) -> Option<&[u8]> {
93        self.accounts
94            .get(address)
95            .and_then(|account| account.code.as_ref())
96            .map(|code| code.as_slice())
97    }
98
99    /// Set contract code
100    pub fn set_code(&mut self, address: &str, code: &[u8]) -> Result<(), RuntimeError> {
101        let old_code = self.get_code(address).map(|c| c.to_vec());
102
103        let created_at = self.current_timestamp();
104        let code_hash = self.calculate_hash(code);
105
106        let account = self
107            .accounts
108            .entry(address.to_string())
109            .or_insert_with(|| AccountState {
110                address: address.to_string(),
111                balance: 0,
112                nonce: 0,
113                code: None,
114                code_hash: None,
115                storage_root: None,
116                created_at,
117            });
118        account.code = Some(code.to_vec());
119        account.code_hash = Some(code_hash);
120
121        // Record state change
122        self.record_change(StateChange {
123            change_type: StateChangeType::CodeChange,
124            account: address.to_string(),
125            key: None,
126            old_value: old_code,
127            new_value: code.to_vec(),
128        });
129
130        Ok(())
131    }
132
133    /// Create new account
134    pub fn create_account(
135        &mut self,
136        address: &str,
137        initial_balance: u64,
138    ) -> Result<(), RuntimeError> {
139        if self.accounts.contains_key(address) {
140            return Err(RuntimeError::StateError {
141                message: format!("Account {address} already exists"),
142            });
143        }
144
145        let account = AccountState {
146            address: address.to_string(),
147            balance: initial_balance,
148            nonce: 0,
149            code: None,
150            code_hash: None,
151            storage_root: None,
152            created_at: self.current_timestamp(),
153        };
154
155        self.accounts.insert(address.to_string(), account);
156
157        // Record state change
158        self.record_change(StateChange {
159            change_type: StateChangeType::AccountCreation,
160            account: address.to_string(),
161            key: None,
162            old_value: None,
163            new_value: initial_balance.to_le_bytes().to_vec(),
164        });
165
166        Ok(())
167    }
168
169    /// Delete account
170    pub fn delete_account(&mut self, address: &str) -> Result<(), RuntimeError> {
171        if let Some(account) = self.accounts.remove(address) {
172            // Record state change
173            self.record_change(StateChange {
174                change_type: StateChangeType::AccountDeletion,
175                account: address.to_string(),
176                key: None,
177                old_value: Some(account.balance.to_le_bytes().to_vec()),
178                new_value: vec![],
179            });
180        }
181
182        Ok(())
183    }
184
185    /// Check if account exists
186    pub fn account_exists(&self, address: &str) -> bool {
187        self.accounts.contains_key(address)
188    }
189
190    /// Transfer balance between accounts
191    pub fn transfer(&mut self, from: &str, to: &str, amount: u64) -> Result<(), RuntimeError> {
192        let from_balance = self.get_balance(from)?;
193        let to_balance = self.get_balance(to)?;
194
195        if from_balance < amount {
196            return Err(RuntimeError::StateError {
197                message: "Insufficient balance".to_string(),
198            });
199        }
200
201        self.set_balance(from, from_balance - amount)?;
202        self.set_balance(to, to_balance + amount)?;
203
204        Ok(())
205    }
206}