neo3/neo_wallets/wallet/
backup.rs

1use crate::neo_wallets::{Wallet, WalletError};
2use std::{fs::File, io::Write, path::PathBuf};
3
4/// Provides functionality for backing up and recovering Neo wallets.
5pub struct WalletBackup;
6
7impl WalletBackup {
8	/// Backs up a wallet to the specified file path.
9	///
10	/// This method serializes the wallet to JSON format and saves it to the specified file.
11	/// It's recommended to store backups in a secure location.
12	///
13	/// # Arguments
14	///
15	/// * `wallet` - The wallet to back up
16	/// * `path` - The file path where the backup will be saved
17	///
18	/// # Returns
19	///
20	/// A `Result` indicating success or failure
21	///
22	/// # Example
23	///
24	/// ```no_run
25	/// use std::path::PathBuf;
26	/// use neo3::prelude::*;
27	///
28	/// let wallet = wallets::Wallet::new();
29	/// let backup_path = PathBuf::from("wallet_backup.json");
30	/// wallets::WalletBackup::backup(&wallet, backup_path).unwrap();
31	/// ```
32	pub fn backup(wallet: &Wallet, path: PathBuf) -> Result<(), WalletError> {
33		// Convert wallet to NEP6
34		let nep6 = wallet.to_nep6()?;
35
36		// Encode as JSON
37		let json = serde_json::to_string_pretty(&nep6)
38			.map_err(|e| WalletError::AccountState(format!("Serialization error: {e}")))?;
39
40		// Write to file at path
41		let mut file = File::create(path).map_err(|e| WalletError::IoError(e))?;
42
43		file.write_all(json.as_bytes()).map_err(|e| WalletError::IoError(e))?;
44
45		Ok(())
46	}
47
48	/// Recovers a wallet from a backup file.
49	///
50	/// This method reads a wallet backup file in JSON format and deserializes it into a Wallet.
51	///
52	/// # Arguments
53	///
54	/// * `path` - The file path of the backup
55	///
56	/// # Returns
57	///
58	/// A `Result` containing the recovered wallet or an error
59	///
60	/// # Example
61	///
62	/// ```no_run
63	/// use std::path::PathBuf;
64	/// use neo3::prelude::*;
65	///
66	/// let backup_path = PathBuf::from("wallet_backup.json");
67	/// let recovered_wallet = wallets::WalletBackup::recover(backup_path).unwrap();
68	/// ```
69	pub fn recover(path: PathBuf) -> Result<Wallet, WalletError> {
70		// Read file content
71		let file_content = std::fs::read_to_string(path).map_err(|e| WalletError::IoError(e))?;
72
73		// Parse JSON to Nep6Wallet
74		let nep6_wallet = serde_json::from_str(&file_content)
75			.map_err(|e| WalletError::AccountState(format!("Deserialization error: {e}")))?;
76
77		// Convert Nep6Wallet to Wallet
78		Wallet::from_nep6(nep6_wallet)
79	}
80}
81
82#[cfg(test)]
83mod tests {
84	use std::{fs, path::PathBuf};
85
86	use crate::{
87		neo_protocol::{Account, AccountTrait},
88		neo_wallets::{Wallet, WalletBackup, WalletTrait},
89	};
90
91	#[test]
92	fn test_backup_and_recover() {
93		// Create a wallet with an account
94		let mut wallet = Wallet::new();
95		let account = Account::create().expect("Should be able to create account in test");
96		wallet.add_account(account);
97
98		// Encrypt the accounts to avoid the "Account private key is available but not encrypted" error
99		wallet.encrypt_accounts("test_password");
100
101		// Create a secure temporary backup file
102		let temp_file = tempfile::NamedTempFile::new()
103			.expect("Should be able to create temporary file in test");
104		let backup_path = temp_file.path().with_extension("json");
105
106		// Backup the wallet
107		WalletBackup::backup(&wallet, backup_path.clone())
108			.expect("Should be able to backup wallet in test");
109
110		// Verify the backup file exists
111		assert!(backup_path.exists());
112
113		// Recover the wallet
114		let recovered_wallet = WalletBackup::recover(backup_path.clone())
115			.expect("Should be able to recover wallet in test");
116
117		// Verify the recovered wallet has the same properties
118		assert_eq!(wallet.name(), recovered_wallet.name());
119		assert_eq!(wallet.version(), recovered_wallet.version());
120		assert_eq!(wallet.accounts().len(), recovered_wallet.accounts().len());
121
122		// Clean up
123		fs::remove_file(backup_path).expect("Should be able to remove backup file in test");
124	}
125}