miden_objects/account/
data.rs

1#[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
18// ACCOUNT DATA
19// ================================================================================================
20
21/// Account data contains a complete description of an account, including the [Account] struct as
22/// well as account seed and account authentication info.
23///
24/// The intent of this struct is to provide an easy way to serialize and deserialize all
25/// account-related data as a single unit (e.g., to/from files).
26#[derive(Debug, Clone)]
27pub struct AccountData {
28    pub account: Account,
29    pub account_seed: Option<Word>,
30    pub auth_secret_key: AuthSecretKey,
31}
32
33impl AccountData {
34    pub fn new(account: Account, account_seed: Option<Word>, auth: AuthSecretKey) -> Self {
35        Self {
36            account,
37            account_seed,
38            auth_secret_key: auth,
39        }
40    }
41
42    #[cfg(feature = "std")]
43    /// Serialises and writes binary AccountData to specified file
44    pub fn write(&self, filepath: impl AsRef<Path>) -> io::Result<()> {
45        fs::write(filepath, self.to_bytes())
46    }
47
48    #[cfg(feature = "std")]
49    /// Reads from file and tries to deserialise an AccountData
50    pub fn read(filepath: impl AsRef<Path>) -> io::Result<Self> {
51        let mut file = File::open(filepath)?;
52        let mut buffer = Vec::new();
53
54        file.read_to_end(&mut buffer)?;
55        let mut reader = SliceReader::new(&buffer);
56
57        Ok(AccountData::read_from(&mut reader).map_err(|_| io::ErrorKind::InvalidData)?)
58    }
59}
60
61// SERIALIZATION
62// ================================================================================================
63
64impl Serializable for AccountData {
65    fn write_into<W: ByteWriter>(&self, target: &mut W) {
66        let AccountData {
67            account,
68            account_seed,
69            auth_secret_key: auth,
70        } = self;
71
72        account.write_into(target);
73        account_seed.write_into(target);
74        auth.write_into(target);
75    }
76}
77
78impl Deserializable for AccountData {
79    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
80        let account = Account::read_from(source)?;
81        let account_seed = <Option<Word>>::read_from(source)?;
82        let auth_secret_key = AuthSecretKey::read_from(source)?;
83
84        Ok(Self::new(account, account_seed, auth_secret_key))
85    }
86
87    fn read_from_bytes(bytes: &[u8]) -> Result<Self, DeserializationError> {
88        Self::read_from(&mut SliceReader::new(bytes))
89    }
90}
91
92// TESTS
93// ================================================================================================
94
95#[cfg(test)]
96mod tests {
97    use miden_crypto::{
98        dsa::rpo_falcon512::SecretKey,
99        utils::{Deserializable, Serializable},
100    };
101    use storage::AccountStorage;
102    #[cfg(feature = "std")]
103    use tempfile::tempdir;
104
105    use super::AccountData;
106    use crate::{
107        account::{storage, Account, AccountCode, AccountId, AuthSecretKey, Felt, Word},
108        asset::AssetVault,
109        testing::account_id::ACCOUNT_ID_REGULAR_ACCOUNT_IMMUTABLE_CODE_ON_CHAIN,
110    };
111
112    fn build_account_data() -> AccountData {
113        let id = AccountId::try_from(ACCOUNT_ID_REGULAR_ACCOUNT_IMMUTABLE_CODE_ON_CHAIN).unwrap();
114        let code = AccountCode::mock();
115
116        // create account and auth
117        let vault = AssetVault::new(&[]).unwrap();
118        let storage = AccountStorage::new(vec![]).unwrap();
119        let nonce = Felt::new(0);
120        let account = Account::from_parts(id, vault, storage, code, nonce);
121        let account_seed = Some(Word::default());
122        let auth_secret_key = AuthSecretKey::RpoFalcon512(SecretKey::new());
123
124        AccountData::new(account, account_seed, auth_secret_key)
125    }
126
127    #[test]
128    fn test_serde() {
129        let account_data = build_account_data();
130        let serialized = account_data.to_bytes();
131        let deserialized = AccountData::read_from_bytes(&serialized).unwrap();
132        assert_eq!(deserialized.account, account_data.account);
133        assert_eq!(deserialized.account_seed, account_data.account_seed);
134        assert_eq!(
135            deserialized.auth_secret_key.to_bytes(),
136            account_data.auth_secret_key.to_bytes()
137        );
138    }
139
140    #[cfg(feature = "std")]
141    #[test]
142    fn test_serde_file() {
143        let dir = tempdir().unwrap();
144        let filepath = dir.path().join("account_data.mac");
145
146        let account_data = build_account_data();
147        account_data.write(filepath.as_path()).unwrap();
148        let deserialized = AccountData::read(filepath.as_path()).unwrap();
149
150        assert_eq!(deserialized.account, account_data.account);
151        assert_eq!(deserialized.account_seed, account_data.account_seed);
152        assert_eq!(
153            deserialized.auth_secret_key.to_bytes(),
154            account_data.auth_secret_key.to_bytes()
155        );
156    }
157}