use crate::{
address::Address, error::NssaError, program::Program, public_transaction::PublicTransaction,
};
use nssa_core::{account::Account, program::ProgramId};
use std::collections::HashMap;
pub struct V01State {
pub(crate) public_state: HashMap
,
pub(crate) builtin_programs: HashMap,
}
impl V01State {
pub fn new_with_genesis_accounts(initial_data: &[([u8; 32], u128)]) -> Self {
let authenticated_transfer_program = Program::authenticated_transfer_program();
let public_state = initial_data
.iter()
.copied()
.map(|(address_value, balance)| {
let account = Account {
balance,
program_owner: authenticated_transfer_program.id(),
..Account::default()
};
let address = Address::new(address_value);
(address, account)
})
.collect();
let mut this = Self {
public_state,
builtin_programs: HashMap::new(),
};
this.insert_program(Program::authenticated_transfer_program());
this
}
pub(crate) fn insert_program(&mut self, program: Program) {
self.builtin_programs.insert(program.id(), program);
}
pub fn transition_from_public_transaction(
&mut self,
tx: &PublicTransaction,
) -> Result<(), NssaError> {
let state_diff = tx.validate_and_compute_post_states(self)?;
for (address, post) in state_diff.into_iter() {
let current_account = self.get_account_by_address_mut(address);
*current_account = post;
}
for address in tx.signer_addresses() {
let current_account = self.get_account_by_address_mut(address);
current_account.nonce += 1;
}
Ok(())
}
fn get_account_by_address_mut(&mut self, address: Address) -> &mut Account {
self.public_state.entry(address).or_default()
}
pub fn get_account_by_address(&self, address: &Address) -> Account {
self.public_state
.get(address)
.cloned()
.unwrap_or(Account::default())
}
pub(crate) fn builtin_programs(&self) -> &HashMap {
&self.builtin_programs
}
#[cfg(test)]
pub fn force_insert_account(&mut self, address: Address, account: Account) {
self.public_state.insert(address, account);
}
}