miden_node_store/genesis/
mod.rs1use miden_protocol::Word;
2use miden_protocol::account::{Account, AccountPatch, AccountUpdateDetails};
3use miden_protocol::block::account_tree::{AccountIdKey, AccountTree};
4use miden_protocol::block::{
5 BlockAccountUpdate,
6 BlockBody,
7 BlockHeader,
8 BlockNoteTree,
9 BlockNumber,
10 BlockSignatures,
11 FeeParameters,
12 SignedBlock,
13 ValidatorKeys,
14};
15use miden_protocol::crypto::merkle::mmr::{Forest, MmrPeaks};
16use miden_protocol::crypto::merkle::smt::Smt;
17use miden_protocol::errors::AccountError;
18use miden_protocol::note::Nullifier;
19use miden_protocol::transaction::{OrderedTransactionHeaders, TransactionKernel};
20
21pub mod config;
22
23#[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 pub validator_keys: ValidatorKeys,
34}
35
36#[derive(Debug)]
39pub struct GenesisBlock(SignedBlock);
40
41impl GenesisBlock {
42 pub fn inner(&self) -> &SignedBlock {
43 &self.0
44 }
45
46 pub fn into_inner(self) -> SignedBlock {
47 self.0
48 }
49}
50
51impl TryFrom<SignedBlock> for GenesisBlock {
52 type Error = anyhow::Error;
53
54 fn try_from(block: SignedBlock) -> anyhow::Result<Self> {
55 anyhow::ensure!(
56 block.header().block_num() == BlockNumber::GENESIS,
57 "expected genesis block number (0), got {}",
58 block.header().block_num(),
59 );
60
61 anyhow::ensure!(
65 block.signatures().is_empty(),
66 "genesis block must not carry signatures, got {}",
67 block.signatures().len(),
68 );
69
70 Ok(Self(block))
71 }
72}
73
74impl GenesisState {
75 pub fn new(
76 accounts: Vec<Account>,
77 fee_parameters: FeeParameters,
78 version: u32,
79 timestamp: u32,
80 validator_keys: ValidatorKeys,
81 ) -> Self {
82 Self {
83 accounts,
84 fee_parameters,
85 version,
86 timestamp,
87 validator_keys,
88 }
89 }
90
91 pub fn into_block(self) -> anyhow::Result<GenesisBlock> {
97 let accounts: Vec<BlockAccountUpdate> = self
98 .accounts
99 .iter()
100 .map(|account| {
101 let account_update_details = if account.id().is_private() {
102 AccountUpdateDetails::Private
103 } else {
104 AccountUpdateDetails::Public(AccountPatch::try_from(account.clone())?)
105 };
106
107 Ok(BlockAccountUpdate::new(
108 account.id(),
109 account.to_commitment(),
110 account_update_details,
111 ))
112 })
113 .collect::<Result<Vec<_>, AccountError>>()?;
114
115 let smt_entries = accounts.iter().map(|update| {
117 (
118 AccountIdKey::from(update.account_id()).as_word(),
119 update.final_state_commitment(),
120 )
121 });
122
123 let smt =
124 Smt::with_entries(smt_entries).expect("Failed to create LargeSmt for genesis accounts");
125
126 let account_smt = AccountTree::new(smt).expect("Failed to create AccountTree for genesis");
127
128 let empty_nullifiers: Vec<Nullifier> = Vec::new();
129 let empty_nullifier_tree = Smt::new();
130
131 let empty_output_notes = Vec::new();
132 let empty_block_note_tree = BlockNoteTree::empty();
133
134 let empty_transactions = OrderedTransactionHeaders::new_unchecked(Vec::new());
135
136 let validator_keys = self.validator_keys;
137
138 let header = BlockHeader::new(
139 self.version,
140 Word::empty(),
141 BlockNumber::GENESIS,
142 MmrPeaks::new(Forest::empty(), Vec::new()).unwrap().hash_peaks(),
143 account_smt.root(),
144 empty_nullifier_tree.root(),
145 empty_block_note_tree.root(),
146 Word::empty(),
147 TransactionKernel.to_commitment(),
148 validator_keys,
149 self.fee_parameters,
150 self.timestamp,
151 );
152
153 let body = BlockBody::new_unchecked(
154 accounts,
155 empty_output_notes,
156 empty_nullifiers,
157 empty_transactions,
158 );
159
160 let signatures = BlockSignatures::new(Vec::new())
161 .map_err(|err| anyhow::anyhow!("failed to build empty genesis signatures: {err}"))?;
162
163 Ok(GenesisBlock(SignedBlock::new(header, body, signatures)?))
164 }
165}