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