Skip to main content

miden_node_store/genesis/
mod.rs

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