use alloc::string::ToString;
use alloc::vec::Vec;
use miden_core::{Felt, ZERO};
use super::{Account, AccountCode, AccountId, PartialStorage};
use crate::Word;
use crate::account::{AccountHeader, validate_account_seed};
use crate::asset::PartialVault;
use crate::crypto::SequentialCommit;
use crate::errors::AccountError;
use crate::utils::serde::{
ByteReader,
ByteWriter,
Deserializable,
DeserializationError,
Serializable,
};
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PartialAccount {
id: AccountId,
partial_vault: PartialVault,
partial_storage: PartialStorage,
code: AccountCode,
nonce: Felt,
seed: Option<Word>,
}
impl PartialAccount {
pub fn new(
id: AccountId,
nonce: Felt,
code: AccountCode,
partial_storage: PartialStorage,
partial_vault: PartialVault,
seed: Option<Word>,
) -> Result<Self, AccountError> {
validate_account_seed(id, code.commitment(), partial_storage.commitment(), seed, nonce)?;
let account = Self {
id,
nonce,
code,
partial_storage,
partial_vault,
seed,
};
Ok(account)
}
pub fn id(&self) -> AccountId {
self.id
}
pub fn nonce(&self) -> Felt {
self.nonce
}
pub fn code(&self) -> &AccountCode {
&self.code
}
pub fn storage(&self) -> &PartialStorage {
&self.partial_storage
}
pub fn vault(&self) -> &PartialVault {
&self.partial_vault
}
pub fn seed(&self) -> Option<Word> {
self.seed
}
pub fn is_new(&self) -> bool {
self.nonce == ZERO
}
pub fn to_commitment(&self) -> Word {
AccountHeader::from(self).to_commitment()
}
pub fn initial_commitment(&self) -> Word {
if self.is_new() {
Word::empty()
} else {
self.to_commitment()
}
}
pub fn has_public_state(&self) -> bool {
self.id.has_public_state()
}
pub fn into_parts(
self,
) -> (AccountId, PartialVault, PartialStorage, AccountCode, Felt, Option<Word>) {
(
self.id,
self.partial_vault,
self.partial_storage,
self.code,
self.nonce,
self.seed,
)
}
}
impl From<&Account> for PartialAccount {
fn from(account: &Account) -> Self {
let partial_storage = if account.is_new() {
PartialStorage::new_full(account.storage.clone())
} else {
PartialStorage::new_minimal(account.storage())
};
Self::new(
account.id(),
account.nonce(),
account.code().clone(),
partial_storage,
PartialVault::new_minimal(account.vault()),
account.seed(),
)
.expect("account should ensure that seed is valid for account")
}
}
impl SequentialCommit for PartialAccount {
type Commitment = Word;
fn to_elements(&self) -> Vec<Felt> {
AccountHeader::from(self).to_elements()
}
fn to_commitment(&self) -> Self::Commitment {
AccountHeader::from(self).to_commitment()
}
}
impl Serializable for PartialAccount {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write(self.id);
target.write(self.nonce);
target.write(&self.code);
target.write(&self.partial_storage);
target.write(&self.partial_vault);
target.write(self.seed);
}
}
impl Deserializable for PartialAccount {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let account_id = source.read()?;
let nonce = source.read()?;
let account_code = source.read()?;
let partial_storage = source.read()?;
let partial_vault = source.read()?;
let seed: Option<Word> = source.read()?;
PartialAccount::new(account_id, nonce, account_code, partial_storage, partial_vault, seed)
.map_err(|err| DeserializationError::InvalidValue(err.to_string()))
}
}