Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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: BlockHeaderCommitment::new(header).to_raw_sql(),
}
}
}
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