use std::num::NonZeroUsize;
use std::path::Path;
use anyhow::Context;
use miden_node_store::BlockStore;
use miden_node_store::genesis::GenesisBlock;
use miden_node_utils::fs::ensure_empty_directory;
use miden_node_utils::genesis::read_genesis_block;
use miden_node_utils::tracing::info;
use miden_validator::DataDirectory;
pub async fn bootstrap(
data_directory: &Path,
sqlite_connection_pool_size: NonZeroUsize,
genesis_block_file: &Path,
) -> anyhow::Result<()> {
info!(
target: miden_validator::LOG_TARGET,
"Bootstrapping validator",
service.name = "miden-validator",
service.version = env!("CARGO_PKG_VERSION"),
genesis.file = genesis_block_file,
data.directory = data_directory
);
ensure_empty_directory(data_directory)?;
let dirs = DataDirectory::load(data_directory.to_path_buf())
.context("failed to load the data directory")?;
let signed_block =
read_genesis_block(genesis_block_file).context("failed to read genesis block file")?;
let genesis_block =
GenesisBlock::try_from(signed_block).context("genesis block validation failed")?;
let genesis_commitment = genesis_block.inner().header().commitment();
let _ = BlockStore::bootstrap(dirs.block_store_dir(), &genesis_block)?;
let (genesis_header, ..) = genesis_block.into_inner().into_parts();
miden_validator::db::bootstrap(
dirs.database_path(),
sqlite_connection_pool_size,
genesis_header,
)
.await
.context("failed to bootstrap the validator database")?;
info!(
target: miden_validator::LOG_TARGET,
"Validator bootstrap complete",
genesis.commitment = genesis_commitment,
data.directory = data_directory
);
Ok(())
}
#[cfg(test)]
mod tests {
use miden_protocol::crypto::dsa::ecdsa_k256_keccak::SigningKey;
use miden_protocol::utils::serde::Deserializable;
use super::*;
#[tokio::test]
async fn bootstrap_writes_all_outputs_before_returning_success() {
let root = tempfile::tempdir().unwrap();
let genesis_directory = root.path().join("genesis");
let accounts_directory = root.path().join("accounts");
let data_directory = root.path().join("data");
let validator_key = SigningKey::read_from_bytes(&[7; 32])
.expect("test signing key should decode")
.public_key();
super::super::genesis::generate(
&genesis_directory,
&accounts_directory,
None,
vec![validator_key],
)
.expect("genesis should complete");
bootstrap(
&data_directory,
NonZeroUsize::new(2).unwrap(),
&genesis_directory.join("genesis.dat"),
)
.await
.expect("bootstrap should complete");
assert!(genesis_directory.join("genesis.dat").is_file());
assert!(data_directory.join("validator.sqlite3").is_file());
assert!(
fs_err::read_dir(&accounts_directory)
.expect("accounts directory should be readable")
.next()
.is_some(),
"genesis should write generated account files",
);
assert!(
accounts_directory.join("native_faucet.mac").is_file(),
"genesis should write the generated native faucet account file",
);
}
}