miden_node_store/genesis/
mod.rs1use anyhow::Context;
2use miden_protocol::Word;
3use miden_protocol::account::{Account, AccountPatch, AccountUpdateDetails};
4use miden_protocol::block::account_tree::{AccountIdKey, AccountTree};
5use miden_protocol::block::{
6 BlockAccountUpdate,
7 BlockBody,
8 BlockHeader,
9 BlockNoteTree,
10 BlockNumber,
11 BlockSignatures,
12 FeeParameters,
13 SignedBlock,
14 ValidatorKeys,
15};
16use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{PublicKey, Signature, SigningKey};
17use miden_protocol::crypto::merkle::mmr::{Forest, MmrPeaks};
18use miden_protocol::crypto::merkle::smt::Smt;
19use miden_protocol::errors::AccountError;
20use miden_protocol::note::Nullifier;
21use miden_protocol::transaction::{OrderedTransactionHeaders, TransactionKernel};
22
23pub mod config;
24
25#[derive(Clone, Debug, PartialEq, Eq)]
30pub struct GenesisState {
31 pub accounts: Vec<Account>,
32 pub fee_parameters: FeeParameters,
33 pub version: u32,
34 pub timestamp: u32,
35 pub validator_key: PublicKey,
36}
37
38pub struct GenesisBlock(SignedBlock);
41
42pub struct UnsignedGenesisBlock {
44 header: BlockHeader,
45 body: BlockBody,
46}
47
48impl UnsignedGenesisBlock {
49 pub fn header(&self) -> &BlockHeader {
50 &self.header
51 }
52
53 pub fn into_block(self, signature: Signature) -> anyhow::Result<GenesisBlock> {
54 let signatures = BlockSignatures::new(vec![signature])?;
55 signatures
56 .verify_against(self.header.commitment(), self.header.validator_keys())
57 .context("genesis block signature verification failed")?;
58
59 Ok(GenesisBlock(SignedBlock::new(self.header, self.body, signatures)?))
60 }
61}
62
63impl GenesisBlock {
64 pub fn inner(&self) -> &SignedBlock {
65 &self.0
66 }
67
68 pub fn into_inner(self) -> SignedBlock {
69 self.0
70 }
71}
72
73impl TryFrom<SignedBlock> for GenesisBlock {
74 type Error = anyhow::Error;
75
76 fn try_from(block: SignedBlock) -> anyhow::Result<Self> {
77 anyhow::ensure!(
78 block.header().block_num() == BlockNumber::GENESIS,
79 "expected genesis block number (0), got {}",
80 block.header().block_num(),
81 );
82
83 block
84 .signatures()
85 .verify_against(block.header().commitment(), block.header().validator_keys())
86 .context("genesis block signature verification failed")?;
87
88 Ok(Self(block))
89 }
90}
91
92impl GenesisState {
93 pub fn new(
94 accounts: Vec<Account>,
95 fee_parameters: FeeParameters,
96 version: u32,
97 timestamp: u32,
98 validator_key: PublicKey,
99 ) -> Self {
100 Self {
101 accounts,
102 fee_parameters,
103 version,
104 timestamp,
105 validator_key,
106 }
107 }
108
109 pub fn into_unsigned_block(self) -> anyhow::Result<UnsignedGenesisBlock> {
111 let accounts: Vec<BlockAccountUpdate> = self
112 .accounts
113 .iter()
114 .map(|account| {
115 let account_update_details = if account.id().is_private() {
116 AccountUpdateDetails::Private
117 } else {
118 AccountUpdateDetails::Public(AccountPatch::try_from(account.clone())?)
119 };
120
121 Ok(BlockAccountUpdate::new(
122 account.id(),
123 account.to_commitment(),
124 account_update_details,
125 ))
126 })
127 .collect::<Result<Vec<_>, AccountError>>()?;
128
129 let smt_entries = accounts.iter().map(|update| {
131 (
132 AccountIdKey::from(update.account_id()).as_word(),
133 update.final_state_commitment(),
134 )
135 });
136
137 let smt =
138 Smt::with_entries(smt_entries).expect("Failed to create LargeSmt for genesis accounts");
139
140 let account_smt = AccountTree::new(smt).expect("Failed to create AccountTree for genesis");
141
142 let empty_nullifiers: Vec<Nullifier> = Vec::new();
143 let empty_nullifier_tree = Smt::new();
144
145 let empty_output_notes = Vec::new();
146 let empty_block_note_tree = BlockNoteTree::empty();
147
148 let empty_transactions = OrderedTransactionHeaders::new_unchecked(Vec::new());
149
150 let validator_keys = ValidatorKeys::new(vec![self.validator_key])?;
151
152 let header = BlockHeader::new(
153 self.version,
154 Word::empty(),
155 BlockNumber::GENESIS,
156 MmrPeaks::new(Forest::empty(), Vec::new()).unwrap().hash_peaks(),
157 account_smt.root(),
158 empty_nullifier_tree.root(),
159 empty_block_note_tree.root(),
160 Word::empty(),
161 TransactionKernel.to_commitment(),
162 validator_keys,
163 self.fee_parameters,
164 self.timestamp,
165 );
166
167 let body = BlockBody::new_unchecked(
168 accounts,
169 empty_output_notes,
170 empty_nullifiers,
171 empty_transactions,
172 );
173
174 Ok(UnsignedGenesisBlock { header, body })
175 }
176
177 pub fn into_block(self, signer: &SigningKey) -> anyhow::Result<GenesisBlock> {
179 let unsigned_block = self.into_unsigned_block()?;
180 let signature = signer.sign(unsigned_block.header().commitment());
181 unsigned_block.into_block(signature)
182 }
183}