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