Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bin/remote-prover/src/server/prover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ impl Prover {
}
}

/// Proves a [`ProofRequest`] using the appropriate prover implementation as specified during
/// construction.
/// Proves a [`proto::ProofRequest`] using the appropriate prover implementation as specified
/// during construction.
pub fn prove(&self, request: proto::ProofRequest) -> Result<proto::Proof, tonic::Status> {
match self {
Prover::Transaction(prover) => prover.prove_request(request),
Expand Down
7 changes: 7 additions & 0 deletions crates/store/src/db/migrations/2025062000000_setup/up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ CREATE TABLE block_headers (
block_num INTEGER NOT NULL,
block_header BLOB NOT NULL,
signature BLOB NOT NULL,
commitment BLOB NOT NULL,

PRIMARY KEY (block_num),
CONSTRAINT block_header_block_num_is_u32 CHECK (block_num BETWEEN 0 AND 0xFFFFFFFF)
Expand Down Expand Up @@ -156,3 +157,9 @@ CREATE TABLE transactions (
CREATE INDEX idx_transactions_account_id ON transactions(account_id);
-- Index for joining with block_headers
CREATE INDEX idx_transactions_block_num ON transactions(block_num);

CREATE INDEX idx_vault_cleanup ON account_vault_assets(block_num) WHERE is_latest = 0;
CREATE INDEX idx_storage_cleanup ON account_storage_map_values(block_num) WHERE is_latest = 0;

CREATE INDEX idx_account_storage_map_latest_by_account_slot_key ON account_storage_map_values(account_id, slot_name, key, is_latest) WHERE is_latest = 1;
CREATE INDEX idx_account_vault_assets_latest_by_account_key ON account_vault_assets(account_id, vault_key, is_latest) WHERE is_latest = 1;

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

14 changes: 12 additions & 2 deletions crates/store/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ use tracing::{info, instrument};
use crate::COMPONENT;
use crate::db::migrations::apply_migrations;
use crate::db::models::conv::SqlTypeConvert;
use crate::db::models::queries::StorageMapValuesPage;
pub use crate::db::models::queries::{
AccountCommitmentsPage,
NullifiersPage,
PublicAccountIdsPage,
};
use crate::db::models::queries::{BlockHeaderCommitment, StorageMapValuesPage};
use crate::db::models::{Page, queries};
use crate::errors::{DatabaseError, NoteSyncError};
use crate::genesis::GenesisBlock;
Expand Down Expand Up @@ -266,7 +266,7 @@ impl Db {

/// Open a connection to the DB and apply any pending migrations.
#[instrument(target = COMPONENT, skip_all)]
pub async fn load(database_filepath: PathBuf) -> Result<Self, miden_node_db::DatabaseError> {
pub async fn load(database_filepath: PathBuf) -> Result<Self, DatabaseError> {
let db = miden_node_db::Db::new(&database_filepath)?;
info!(
target: COMPONENT,
Expand Down Expand Up @@ -359,6 +359,16 @@ impl Db {
.await
}

/// Loads all the block headers from the DB.
#[instrument(level = "debug", target = COMPONENT, skip_all, ret(level = "debug"), err)]
pub async fn select_all_block_header_commitments(&self) -> Result<Vec<BlockHeaderCommitment>> {
self.transact("all block headers", |conn| {
let raw = queries::select_all_block_header_commitments(conn)?;
Ok(raw)
})
.await
}

/// Returns a page of account commitments for tree rebuilding.
#[instrument(level = "debug", target = COMPONENT, skip_all, ret(level = "debug"), err)]
pub async fn select_account_commitments_paged(
Expand Down
32 changes: 30 additions & 2 deletions crates/store/src/db/models/conv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@
on relevant platforms"
)]

use miden_crypto::Word;
use miden_crypto::utils::Deserializable;
use miden_protocol::Felt;
use miden_protocol::account::{StorageSlotName, StorageSlotType};
use miden_protocol::block::BlockNumber;
use miden_protocol::block::{BlockHeader, BlockNumber};
use miden_protocol::note::NoteTag;

use crate::db::models::queries::NetworkAccountType;
use crate::db::models::queries::{BlockHeaderCommitment, NetworkAccountType};

#[derive(Debug, thiserror::Error)]
#[error("failed to convert from database type {from_type} into {into_type}")]
Expand Down Expand Up @@ -67,6 +69,32 @@ pub trait SqlTypeConvert: Sized {
}
}

impl SqlTypeConvert for BlockHeaderCommitment {
type Raw = Vec<u8>;
fn from_raw_sql(
raw: Self::Raw,
) -> Result<Self, crate::db::models::conv::DatabaseTypeConversionError> {
let inner =
<Word as Deserializable>::read_from_bytes(raw.as_slice()).map_err(Self::map_err)?;
Ok(BlockHeaderCommitment(inner))
}
fn to_raw_sql(self) -> Self::Raw {
self.0.as_bytes().to_vec()
}
}

impl SqlTypeConvert for BlockHeader {
type Raw = Vec<u8>;

fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
<Self as Deserializable>::read_from_bytes(raw.as_slice()).map_err(Self::map_err)
}

fn to_raw_sql(self) -> Self::Raw {
miden_crypto::utils::Serializable::to_bytes(&self)
}
}

impl SqlTypeConvert for NetworkAccountType {
type Raw = i32;

Expand Down
1 change: 1 addition & 0 deletions crates/store/src/db/models/queries/accounts/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ fn insert_block_header(conn: &mut SqliteConnection, block_num: BlockNumber) {
block_headers::block_num.eq(i64::from(block_num.as_u32())),
block_headers::block_header.eq(block_header.to_bytes()),
block_headers::signature.eq(signature.to_bytes()),
block_headers::commitment.eq(block_header.commitment().to_bytes()),
))
.execute(conn)
.expect("Failed to insert block header");
Expand Down
58 changes: 53 additions & 5 deletions crates/store/src/db/models/queries/block_headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use diesel::{
SelectableHelper,
SqliteConnection,
};
use miden_crypto::Word;
use miden_crypto::dsa::ecdsa_k256_keccak::Signature;
use miden_node_utils::limiter::{QueryParamBlockLimit, QueryParamLimiter};
use miden_protocol::block::{BlockHeader, BlockNumber};
Expand Down Expand Up @@ -125,6 +126,44 @@ pub fn select_all_block_headers(
vec_raw_try_into(raw_block_headers)
}

/// Select all block headers from the DB using the given [`SqliteConnection`].
///
/// # Returns
///
/// A vector of [`BlockHeader`] or an error.
///
/// # Raw SQL
///
/// ```sql
/// SELECT commitment
/// FROM block_headers
/// ORDER BY block_num ASC
/// ```
pub fn select_all_block_header_commitments(
conn: &mut SqliteConnection,
) -> Result<Vec<BlockHeaderCommitment>, DatabaseError> {
let raw_commitments =
QueryDsl::select(schema::block_headers::table, schema::block_headers::commitment)
.order(schema::block_headers::block_num.asc())
.load::<Vec<u8>>(conn)?;
let commitments =
Result::from_iter(raw_commitments.into_iter().map(BlockHeaderCommitment::from_raw_sql))?;
Ok(commitments)
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct BlockHeaderCommitment(pub(crate) Word);

impl BlockHeaderCommitment {
pub fn new(header: &BlockHeader) -> Self {
Self(header.commitment())
}
pub fn word(self) -> Word {
self.0
}
}

#[derive(Debug, Clone, Queryable, QueryableByName, Selectable)]
#[diesel(table_name = schema::block_headers)]
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
Expand All @@ -133,11 +172,18 @@ pub struct BlockHeaderRawRow {
pub block_num: i64,
pub block_header: Vec<u8>,
pub signature: Vec<u8>,
pub commitment: Vec<u8>,
}
impl TryInto<BlockHeader> for BlockHeaderRawRow {
type Error = DatabaseError;
fn try_into(self) -> Result<BlockHeader, Self::Error> {
let block_header = BlockHeader::read_from_bytes(&self.block_header[..])?;
let block_header = BlockHeader::from_raw_sql(self.block_header)?;
// we're bust if this invariant doesn't hold
debug_assert_eq!(
BlockHeaderCommitment::new(&block_header),
BlockHeaderCommitment::from_raw_sql(self.commitment)
.expect("Database always contains valid format commitments")
);
Ok(block_header)
}
}
Expand All @@ -158,13 +204,15 @@ pub struct BlockHeaderInsert {
pub block_num: i64,
pub block_header: Vec<u8>,
pub signature: Vec<u8>,
pub commitment: Vec<u8>,
}
impl From<(&BlockHeader, &Signature)> for BlockHeaderInsert {
fn from(from: (&BlockHeader, &Signature)) -> Self {
fn from((header, signature): (&BlockHeader, &Signature)) -> Self {
Self {
block_num: from.0.block_num().to_raw_sql(),
block_header: from.0.to_bytes(),
signature: from.1.to_bytes(),
block_num: header.block_num().to_raw_sql(),
block_header: header.to_bytes(),
signature: signature.to_bytes(),
commitment: header.commitment().to_bytes(),
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions crates/store/src/db/models/queries/transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,9 @@ pub(crate) fn insert_transactions(
block_num: BlockNumber,
transactions: &OrderedTransactionHeaders,
) -> Result<usize, DatabaseError> {
#[expect(clippy::into_iter_on_ref)] // false positive
let rows: Vec<_> = transactions
.as_slice()
.into_iter()
.iter()
.map(|tx| TransactionSummaryRowInsert::new(tx, block_num))
.collect();

Expand Down
12 changes: 1 addition & 11 deletions crates/store/src/db/models/utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use diesel::{Connection, RunQueryDsl, SqliteConnection};
use miden_protocol::note::Nullifier;
use miden_protocol::utils::{Deserializable, DeserializationError, Serializable};
use miden_protocol::utils::Serializable;

use crate::errors::DatabaseError;

Expand All @@ -14,16 +14,6 @@ pub(crate) fn vec_raw_try_into<D, R: TryInto<D>>(
)
}

#[expect(dead_code)]
/// Deserialize an iterable container full of byte blobs `B` to types `T`
pub(crate) fn deserialize_raw_vec<B: AsRef<[u8]>, T: Deserializable>(
raw: impl IntoIterator<Item = B>,
) -> Result<Vec<T>, DeserializationError> {
Result::<Vec<_>, DeserializationError>::from_iter(
raw.into_iter().map(|raw| T::read_from_bytes(raw.as_ref())),
)
}

/// Utility to convert an iterable container to a vector of byte blobs
pub(crate) fn serialize_vec<'a, D: Serializable + 'a>(
raw: impl IntoIterator<Item = &'a D>,
Expand Down
1 change: 1 addition & 0 deletions crates/store/src/db/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ diesel::table! {
block_num -> BigInt,
block_header -> Binary,
signature -> Binary,
commitment -> Binary,
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/store/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ pub enum StateInitializationError {
#[error("failed to load block store")]
BlockStoreLoadError(#[source] std::io::Error),
#[error("failed to load database")]
DatabaseLoadError(#[from] miden_node_db::DatabaseError),
DatabaseLoadError(#[source] DatabaseError),
#[error("inner forest error")]
InnerForestError(#[from] InnerForestError),
#[error(
Expand Down
15 changes: 7 additions & 8 deletions crates/store/src/state/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ use std::future::Future;
use std::num::NonZeroUsize;
use std::path::Path;

use miden_crypto::merkle::mmr::Mmr;
use miden_protocol::block::account_tree::{AccountTree, account_id_to_smt_key};
use miden_protocol::block::nullifier_tree::NullifierTree;
use miden_protocol::block::{BlockHeader, BlockNumber, Blockchain};
use miden_protocol::block::{BlockNumber, Blockchain};
#[cfg(not(feature = "rocksdb"))]
use miden_protocol::crypto::merkle::smt::MemoryStorage;
use miden_protocol::crypto::merkle::smt::{LargeSmt, LargeSmtError, SmtStorage};
Expand All @@ -30,6 +31,7 @@ use {

use crate::COMPONENT;
use crate::db::Db;
use crate::db::models::queries::BlockHeaderCommitment;
use crate::errors::{DatabaseError, StateInitializationError};
use crate::inner_forest::InnerForest;

Expand Down Expand Up @@ -331,16 +333,13 @@ pub fn load_smt<S: SmtStorage>(storage: S) -> Result<LargeSmt<S>, StateInitializ
/// Loads the blockchain MMR from all block headers in the database.
#[instrument(target = COMPONENT, skip_all)]
pub async fn load_mmr(db: &mut Db) -> Result<Blockchain, StateInitializationError> {
let block_commitments: Vec<miden_protocol::Word> = db
.select_all_block_headers()
.await?
.iter()
.map(BlockHeader::commitment)
.collect();
let block_commitments = db.select_all_block_header_commitments().await?;

// SAFETY: We assume the loaded MMR is valid and does not have more than u32::MAX
// entries.
let chain_mmr = Blockchain::from_mmr_unchecked(block_commitments.into());
let chain_mmr = Blockchain::from_mmr_unchecked(Mmr::from(
block_commitments.iter().copied().map(BlockHeaderCommitment::word),
));

Ok(chain_mmr)
}
Expand Down
Loading