miden_node_store/genesis/
mod.rs

1use miden_lib::transaction::TransactionKernel;
2use miden_objects::Word;
3use miden_objects::account::delta::AccountUpdateDetails;
4use miden_objects::account::{Account, AccountDelta};
5use miden_objects::block::account_tree::{AccountTree, account_id_to_smt_key};
6use miden_objects::block::{
7    BlockAccountUpdate,
8    BlockHeader,
9    BlockNoteTree,
10    BlockNumber,
11    FeeParameters,
12    ProvenBlock,
13};
14use miden_objects::crypto::merkle::{Forest, LargeSmt, MemoryStorage, MmrPeaks, Smt};
15use miden_objects::note::Nullifier;
16use miden_objects::transaction::OrderedTransactionHeaders;
17use miden_objects::utils::serde::{ByteReader, Deserializable, DeserializationError};
18
19use crate::errors::GenesisError;
20
21pub mod config;
22
23// GENESIS STATE
24// ================================================================================================
25
26/// Represents the state at genesis, which will be used to derive the genesis block.
27#[derive(Clone, Debug, PartialEq, Eq)]
28pub struct GenesisState {
29    pub accounts: Vec<Account>,
30    pub fee_parameters: FeeParameters,
31    pub version: u32,
32    pub timestamp: u32,
33}
34
35/// A type-safety wrapper ensuring that genesis block data can only be created from
36/// [`GenesisState`].
37pub struct GenesisBlock(ProvenBlock);
38
39impl GenesisBlock {
40    pub fn inner(&self) -> &ProvenBlock {
41        &self.0
42    }
43
44    pub fn into_inner(self) -> ProvenBlock {
45        self.0
46    }
47}
48
49impl GenesisState {
50    pub fn new(
51        accounts: Vec<Account>,
52        fee_parameters: FeeParameters,
53        version: u32,
54        timestamp: u32,
55    ) -> Self {
56        Self {
57            accounts,
58            fee_parameters,
59            version,
60            timestamp,
61        }
62    }
63
64    /// Returns the block header and the account SMT
65    pub fn into_block(self) -> Result<GenesisBlock, GenesisError> {
66        let accounts: Vec<BlockAccountUpdate> = self
67            .accounts
68            .iter()
69            .map(|account| {
70                let account_update_details = if account.id().is_public() {
71                    AccountUpdateDetails::Delta(
72                        AccountDelta::try_from(account.clone())
73                            .map_err(GenesisError::AccountDelta)?,
74                    )
75                } else {
76                    AccountUpdateDetails::Private
77                };
78
79                Ok(BlockAccountUpdate::new(
80                    account.id(),
81                    account.commitment(),
82                    account_update_details,
83                ))
84            })
85            .collect::<Result<Vec<_>, GenesisError>>()?;
86
87        // Convert account updates to SMT entries using account_id_to_smt_key
88        let smt_entries = accounts.iter().map(|update| {
89            (account_id_to_smt_key(update.account_id()), update.final_state_commitment())
90        });
91
92        // Create LargeSmt with MemoryStorage
93        let smt = LargeSmt::with_entries(MemoryStorage::default(), smt_entries)
94            .expect("Failed to create LargeSmt for genesis accounts");
95
96        let account_smt = AccountTree::new(smt).expect("Failed to create AccountTree for genesis");
97
98        let empty_nullifiers: Vec<Nullifier> = Vec::new();
99        let empty_nullifier_tree = Smt::new();
100
101        let empty_output_notes = Vec::new();
102        let empty_block_note_tree = BlockNoteTree::empty();
103
104        let empty_transactions = OrderedTransactionHeaders::new_unchecked(Vec::new());
105
106        let header = BlockHeader::new(
107            self.version,
108            Word::empty(),
109            BlockNumber::GENESIS,
110            MmrPeaks::new(Forest::empty(), Vec::new()).unwrap().hash_peaks(),
111            account_smt.root(),
112            empty_nullifier_tree.root(),
113            empty_block_note_tree.root(),
114            Word::empty(),
115            TransactionKernel.to_commitment(),
116            Word::empty(),
117            self.fee_parameters,
118            self.timestamp,
119        );
120
121        // SAFETY: Header and accounts should be valid by construction.
122        // No notes or nullifiers are created at genesis, which is consistent with the above empty
123        // block note tree root and empty nullifier tree root.
124        Ok(GenesisBlock(ProvenBlock::new_unchecked(
125            header,
126            accounts,
127            empty_output_notes,
128            empty_nullifiers,
129            empty_transactions,
130        )))
131    }
132}
133
134// SERIALIZATION
135// ================================================================================================
136
137impl Deserializable for GenesisState {
138    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
139        let num_accounts = source.read_usize()?;
140        let accounts = source.read_many::<Account>(num_accounts)?;
141
142        let version = source.read_u32()?;
143        let timestamp = source.read_u32()?;
144        let fee_parameters = source.read::<FeeParameters>()?;
145
146        Ok(Self::new(accounts, fee_parameters, version, timestamp))
147    }
148}