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,
FeeParameters,
SignedBlock,
};
use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{PublicKey, Signature, SigningKey};
use miden_protocol::crypto::merkle::mmr::{Forest, MmrPeaks};
use miden_protocol::crypto::merkle::smt::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 {
pub accounts: Vec<Account>,
pub fee_parameters: FeeParameters,
pub version: u32,
pub timestamp: u32,
pub validator_key: PublicKey,
}
pub struct GenesisBlock(SignedBlock);
pub struct UnsignedGenesisBlock {
header: BlockHeader,
body: BlockBody,
}
impl UnsignedGenesisBlock {
pub fn header(&self) -> &BlockHeader {
&self.header
}
pub fn into_block(self, signature: Signature) -> anyhow::Result<GenesisBlock> {
anyhow::ensure!(
signature.verify(self.header.commitment(), self.header.validator_key()),
"genesis block signature verification failed",
);
Ok(GenesisBlock(SignedBlock::new(self.header, self.body, signature)?))
}
}
impl GenesisBlock {
pub fn inner(&self) -> &SignedBlock {
&self.0
}
pub fn into_inner(self) -> SignedBlock {
self.0
}
}
impl TryFrom<SignedBlock> for GenesisBlock {
type Error = anyhow::Error;
fn try_from(block: SignedBlock) -> 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 GenesisState {
pub fn new(
accounts: Vec<Account>,
fee_parameters: FeeParameters,
version: u32,
timestamp: u32,
validator_key: PublicKey,
) -> Self {
Self {
accounts,
fee_parameters,
version,
timestamp,
validator_key,
}
}
pub fn into_unsigned_block(self) -> anyhow::Result<UnsignedGenesisBlock> {
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 =
Smt::with_entries(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.validator_key,
self.fee_parameters,
self.timestamp,
);
let body = BlockBody::new_unchecked(
accounts,
empty_output_notes,
empty_nullifiers,
empty_transactions,
);
Ok(UnsignedGenesisBlock { header, body })
}
pub fn into_block(self, signer: &SigningKey) -> anyhow::Result<GenesisBlock> {
let unsigned_block = self.into_unsigned_block()?;
let signature = signer.sign(unsigned_block.header().commitment());
unsigned_block.into_block(signature)
}
}