use miden_node_utils::signer::BlockSigner;
use miden_protocol::Word;
use miden_protocol::account::delta::AccountUpdateDetails;
use miden_protocol::account::{Account, AccountDelta};
use miden_protocol::block::account_tree::{AccountIdKey, AccountTree};
use miden_protocol::block::{
BlockAccountUpdate,
BlockBody,
BlockHeader,
BlockNoteTree,
BlockNumber,
BlockProof,
FeeParameters,
ProvenBlock,
};
use miden_protocol::crypto::merkle::mmr::{Forest, MmrPeaks};
use miden_protocol::crypto::merkle::smt::{LargeSmt, MemoryStorage, Smt};
use miden_protocol::errors::AccountError;
use miden_protocol::note::Nullifier;
use miden_protocol::transaction::{OrderedTransactionHeaders, TransactionKernel};
pub mod config;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GenesisState<S> {
pub accounts: Vec<Account>,
pub fee_parameters: FeeParameters,
pub version: u32,
pub timestamp: u32,
pub block_signer: S,
}
pub struct GenesisBlock(ProvenBlock);
impl GenesisBlock {
pub fn inner(&self) -> &ProvenBlock {
&self.0
}
pub fn into_inner(self) -> ProvenBlock {
self.0
}
}
impl TryFrom<ProvenBlock> for GenesisBlock {
type Error = anyhow::Error;
fn try_from(block: ProvenBlock) -> anyhow::Result<Self> {
anyhow::ensure!(
block.header().block_num() == BlockNumber::GENESIS,
"expected genesis block number (0), got {}",
block.header().block_num(),
);
anyhow::ensure!(
block
.signature()
.verify(block.header().commitment(), block.header().validator_key()),
"genesis block signature verification failed",
);
Ok(Self(block))
}
}
impl<S> GenesisState<S> {
pub fn new(
accounts: Vec<Account>,
fee_parameters: FeeParameters,
version: u32,
timestamp: u32,
signer: S,
) -> Self {
Self {
accounts,
fee_parameters,
version,
timestamp,
block_signer: signer,
}
}
}
impl<S: BlockSigner> GenesisState<S> {
pub async fn into_block(self) -> anyhow::Result<GenesisBlock> {
let accounts: Vec<BlockAccountUpdate> = self
.accounts
.iter()
.map(|account| {
let account_update_details = if account.id().is_private() {
AccountUpdateDetails::Private
} else {
AccountUpdateDetails::Delta(AccountDelta::try_from(account.clone())?)
};
Ok(BlockAccountUpdate::new(
account.id(),
account.to_commitment(),
account_update_details,
))
})
.collect::<Result<Vec<_>, AccountError>>()?;
let smt_entries = accounts.iter().map(|update| {
(
AccountIdKey::from(update.account_id()).as_word(),
update.final_state_commitment(),
)
});
let smt = LargeSmt::with_entries(MemoryStorage::default(), smt_entries)
.expect("Failed to create LargeSmt for genesis accounts");
let account_smt = AccountTree::new(smt).expect("Failed to create AccountTree for genesis");
let empty_nullifiers: Vec<Nullifier> = Vec::new();
let empty_nullifier_tree = Smt::new();
let empty_output_notes = Vec::new();
let empty_block_note_tree = BlockNoteTree::empty();
let empty_transactions = OrderedTransactionHeaders::new_unchecked(Vec::new());
let header = BlockHeader::new(
self.version,
Word::empty(),
BlockNumber::GENESIS,
MmrPeaks::new(Forest::empty(), Vec::new()).unwrap().hash_peaks(),
account_smt.root(),
empty_nullifier_tree.root(),
empty_block_note_tree.root(),
Word::empty(),
TransactionKernel.to_commitment(),
self.block_signer.public_key(),
self.fee_parameters,
self.timestamp,
);
let body = BlockBody::new_unchecked(
accounts,
empty_output_notes,
empty_nullifiers,
empty_transactions,
);
let block_proof = BlockProof::new_dummy();
let signature = self.block_signer.sign(&header).await?;
assert!(signature.verify(header.commitment(), &self.block_signer.public_key()));
Ok(GenesisBlock(ProvenBlock::new_unchecked(header, body, signature, block_proof)))
}
}