miden_objects/account/
file.rs1use alloc::vec::Vec;
2#[cfg(feature = "std")]
3use std::{
4 fs::{self, File},
5 io::{self, Read},
6 path::Path,
7};
8
9use miden_crypto::utils::SliceReader;
10
11use super::super::utils::serde::{
12 ByteReader,
13 ByteWriter,
14 Deserializable,
15 DeserializationError,
16 Serializable,
17};
18use super::{Account, AuthSecretKey, Word};
19
20const MAGIC: &str = "acct";
21
22#[derive(Debug, Clone)]
34pub struct AccountFile {
35 pub account: Account,
36 pub account_seed: Option<Word>,
37 pub auth_secret_keys: Vec<AuthSecretKey>,
38}
39
40impl AccountFile {
41 pub fn new(
42 account: Account,
43 account_seed: Option<Word>,
44 auth_keys: Vec<AuthSecretKey>,
45 ) -> Self {
46 Self {
47 account,
48 account_seed,
49 auth_secret_keys: auth_keys,
50 }
51 }
52}
53
54#[cfg(feature = "std")]
55impl AccountFile {
56 pub fn write(&self, filepath: impl AsRef<Path>) -> io::Result<()> {
58 fs::write(filepath, self.to_bytes())
59 }
60
61 pub fn read(filepath: impl AsRef<Path>) -> io::Result<Self> {
63 let mut file = File::open(filepath)?;
64 let mut buffer = Vec::new();
65
66 file.read_to_end(&mut buffer)?;
67 let mut reader = SliceReader::new(&buffer);
68
69 Ok(AccountFile::read_from(&mut reader).map_err(|_| io::ErrorKind::InvalidData)?)
70 }
71}
72
73impl Serializable for AccountFile {
77 fn write_into<W: ByteWriter>(&self, target: &mut W) {
78 target.write_bytes(MAGIC.as_bytes());
79 let AccountFile {
80 account,
81 account_seed,
82 auth_secret_keys: auth,
83 } = self;
84
85 account.write_into(target);
86 account_seed.write_into(target);
87 auth.write_into(target);
88 }
89}
90
91impl Deserializable for AccountFile {
92 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
93 let magic_value = source.read_string(4)?;
94 if magic_value != MAGIC {
95 return Err(DeserializationError::InvalidValue(format!(
96 "invalid account file marker: {magic_value}"
97 )));
98 }
99 let account = Account::read_from(source)?;
100 let account_seed = <Option<Word>>::read_from(source)?;
101 let auth_secret_keys = <Vec<AuthSecretKey>>::read_from(source)?;
102
103 Ok(Self::new(account, account_seed, auth_secret_keys))
104 }
105
106 fn read_from_bytes(bytes: &[u8]) -> Result<Self, DeserializationError> {
107 Self::read_from(&mut SliceReader::new(bytes))
108 }
109}
110
111#[cfg(test)]
115mod tests {
116 use miden_crypto::dsa::rpo_falcon512::SecretKey;
117 use miden_crypto::utils::{Deserializable, Serializable};
118 use storage::AccountStorage;
119 #[cfg(feature = "std")]
120 use tempfile::tempdir;
121
122 use super::AccountFile;
123 use crate::account::{Account, AccountCode, AccountId, AuthSecretKey, Felt, Word, storage};
124 use crate::asset::AssetVault;
125 use crate::testing::account_id::ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE;
126
127 fn build_account_file() -> AccountFile {
128 let id = AccountId::try_from(ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_IMMUTABLE_CODE).unwrap();
129 let code = AccountCode::mock();
130
131 let vault = AssetVault::new(&[]).unwrap();
133 let storage = AccountStorage::new(vec![]).unwrap();
134 let nonce = Felt::new(0);
135 let account = Account::from_parts(id, vault, storage, code, nonce);
136 let account_seed = Some(Word::empty());
137 let auth_secret_key = AuthSecretKey::RpoFalcon512(SecretKey::new());
138 let auth_secret_key_2 = AuthSecretKey::RpoFalcon512(SecretKey::new());
139
140 AccountFile::new(account, account_seed, vec![auth_secret_key, auth_secret_key_2])
141 }
142
143 #[test]
144 fn test_serde() {
145 let account_file = build_account_file();
146 let serialized = account_file.to_bytes();
147 let deserialized = AccountFile::read_from_bytes(&serialized).unwrap();
148 assert_eq!(deserialized.account, account_file.account);
149 assert_eq!(deserialized.account_seed, account_file.account_seed);
150 assert_eq!(
151 deserialized.auth_secret_keys.to_bytes(),
152 account_file.auth_secret_keys.to_bytes()
153 );
154 }
155
156 #[cfg(feature = "std")]
157 #[test]
158 fn test_serde_file() {
159 let dir = tempdir().unwrap();
160 let filepath = dir.path().join("account_file.mac");
161
162 let account_file = build_account_file();
163 account_file.write(filepath.as_path()).unwrap();
164 let deserialized = AccountFile::read(filepath.as_path()).unwrap();
165
166 assert_eq!(deserialized.account, account_file.account);
167 assert_eq!(deserialized.account_seed, account_file.account_seed);
168 assert_eq!(
169 deserialized.auth_secret_keys.to_bytes(),
170 account_file.auth_secret_keys.to_bytes()
171 );
172 }
173}