Skip to content
Open
Show file tree
Hide file tree
Changes from 70 commits
Commits
Show all changes
89 commits
Select commit Hold shift + click to select a range
4ff0970
for account queries, now return partials too
drahnr Dec 1, 2025
5ee1043
drop all tables as part of migration
drahnr Dec 1, 2025
8eca359
externalize storage and vault blobs to separate tables
drahnr Dec 1, 2025
e7f17ed
trailing .
drahnr Dec 1, 2025
c8b43ab
smt forest
drahnr Dec 1, 2025
19164be
changset, should go away after rebase
drahnr Dec 1, 2025
8eb49af
improve
drahnr Dec 1, 2025
6725461
TODO and deprecation
drahnr Dec 1, 2025
ee65a88
account queries
drahnr Dec 1, 2025
741df6f
yes
drahnr Dec 2, 2025
6a64077
why
drahnr Dec 2, 2025
9d5806e
y
drahnr Dec 2, 2025
2964a93
y
drahnr Dec 2, 2025
9416a63
review comments
drahnr Dec 2, 2025
ccc2d63
sanitize comments
drahnr Dec 2, 2025
66ea831
remove
drahnr Dec 4, 2025
1c4f8b1
cleanup
drahnr Dec 4, 2025
80e0393
fix queries with _at suffix
drahnr Dec 4, 2025
e7bf1aa
cleanup
drahnr Dec 4, 2025
dad90e7
simplify
drahnr Dec 4, 2025
e441245
fix
drahnr Dec 4, 2025
0a319d1
cleanup
drahnr Dec 4, 2025
8897939
remove dead code
drahnr Dec 4, 2025
7d7fefc
add test
drahnr Dec 5, 2025
0f53fa9
add block exists helper
drahnr Dec 5, 2025
7400134
Merge remote-tracking branch 'origin' into bernhard-integrate-smtforest
drahnr Dec 9, 2025
0e2d871
simplify
drahnr Dec 9, 2025
f78103e
better docs
drahnr Dec 9, 2025
ea05b01
split long function in State
drahnr Dec 9, 2025
3cd457a
better
drahnr Dec 9, 2025
c8f0eb1
clippy et al
drahnr Dec 9, 2025
ed7224e
review
drahnr Dec 10, 2025
6336f41
address review comments
drahnr Dec 10, 2025
a1173f7
Revert "address review comments"
drahnr Dec 11, 2025
36470a5
improve
drahnr Dec 11, 2025
928fdb4
yes
drahnr Dec 18, 2025
5de3936
tuple ticks
drahnr Dec 18, 2025
f5b4898
Merge remote-tracking branch 'origin' into bernhard-integrate-smtforest
drahnr Dec 18, 2025
ca5ef9a
docs
drahnr Dec 18, 2025
17fd95b
from_iter
drahnr Dec 18, 2025
22f3ca9
simplify
drahnr Dec 18, 2025
3ee1884
docs
drahnr Dec 18, 2025
eaf7242
undo
drahnr Dec 18, 2025
72126e1
one more enum
drahnr Dec 18, 2025
be9071b
docs
drahnr Dec 18, 2025
a0f8fc9
unneces
drahnr Dec 18, 2025
88c058b
simplify
drahnr Dec 18, 2025
b84f25f
misleading
drahnr Dec 18, 2025
25b5550
bound
drahnr Dec 18, 2025
31dacdd
fmt
drahnr Dec 18, 2025
55f4a46
changelog
drahnr Dec 18, 2025
bf67ce8
0 ->1; 1->0
drahnr Dec 19, 2025
0c0e32b
avoid full paths
drahnr Dec 19, 2025
ec4318e
fn
drahnr Dec 19, 2025
4bfee30
refactor, simplify
drahnr Dec 19, 2025
b8d2e66
yuk
drahnr Dec 19, 2025
e453faa
remoe useless comment
drahnr Dec 19, 2025
f6d1ce1
shorthandg pu
drahnr Dec 19, 2025
b1f9cf6
delete unused
drahnr Dec 19, 2025
d2d9e8c
review
drahnr Dec 20, 2025
2781db8
simplify
drahnr Dec 22, 2025
b0e537c
Merge remote-tracking branch 'origin' into bernhard-integrate-smtforest
drahnr Dec 22, 2025
d6b31ef
minor
drahnr Dec 22, 2025
9c859fc
fmt
drahnr Dec 23, 2025
b016495
Merge branch 'next' into bernhard-integrate-smtforest
bobbinth Dec 27, 2025
579b9dc
chore: fix merge conflicts
bobbinth Dec 27, 2025
3336edb
chore: fix test
bobbinth Dec 27, 2025
2aa8c8b
chore: minor formatting changes
bobbinth Dec 27, 2025
354d586
chore: move InnerForest module
bobbinth Dec 27, 2025
a96def0
chore: refactor SMT forest initialization
bobbinth Dec 27, 2025
e8cdad1
chore: re-organize account queries
bobbinth Dec 27, 2025
3009bf7
nope
drahnr Dec 29, 2025
3110962
fix inconsistency
drahnr Dec 29, 2025
53cb5e8
faster
drahnr Dec 29, 2025
0cc0c61
undue changes
drahnr Dec 29, 2025
ac7b8f9
move fn to innerforest
drahnr Dec 29, 2025
369db2f
y
drahnr Dec 29, 2025
6cd1033
another
drahnr Dec 29, 2025
7613624
test re-review
drahnr Dec 29, 2025
e04ff10
fuckup
drahnr Dec 29, 2025
9d8c220
update
drahnr Dec 29, 2025
5ed1a4f
sync docs
drahnr Dec 29, 2025
3346d9f
cleanup
drahnr Dec 29, 2025
dbbc1eb
fmt
drahnr Dec 29, 2025
c5a199a
Merge branch 'bernhard-db-schema-queries' into bernhard-integrate-smt…
drahnr Dec 30, 2025
c712ba4
Merge branch 'bernhard-db-schema-queries' into bernhard-integrate-smt…
drahnr Jan 4, 2026
d9a666f
review
drahnr Jan 6, 2026
29b840c
remove dead code
drahnr Jan 6, 2026
1b22a34
chore: minor rename
bobbinth Jan 7, 2026
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
7 changes: 4 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
- Remove `trait AccountTreeStorage` ([#1352](https://github.com/0xMiden/miden-node/issues/1352)).
- [BREAKING] `SubmitProvenTransaction` now **requires** that the network's genesis commitment is set in the request's `ACCEPT` header ([#1298](https://github.com/0xMiden/miden-node/pull/1298), [#1436](https://github.com/0xMiden/miden-node/pull/1436)).
- Add `S` generic to `NullifierTree` to allow usage with `LargeSmt`s ([#1353](https://github.com/0xMiden/miden-node/issues/1353)).
- Removed internal errors from the `miden-network-monitor` ([#1424](https://github.com/0xMiden/miden-node/pull/1424)).
- Track network transactions latency in `miden-network-monitor` ([#1430](https://github.com/0xMiden/miden-node/pull/1430)).
- Refactor account table and introduce tracking forest ([#1394](https://github.com/0xMiden/miden-node/pull/1394)).
- [BREAKING] Re-organized RPC protobuf schema to be independent of internal schema ([#1401](https://github.com/0xMiden/miden-node/pull/1401)).
- Increased the maximum query limit for the store ([#1443](https://github.com/0xMiden/miden-node/pull/1443)).
- Removed internal errors from the `miden-network-monitor` ([#1424](https://github.com/0xMiden/miden-node/pull/1424)).
- [BREAKING] Added block signing capabilities to Validator component and updated gensis bootstrap to sign blocks with configured signer ([#1426](https://github.com/0xMiden/miden-node/pull/1426)).
- Track network transactions latency in `miden-network-monitor` ([#1430](https://github.com/0xMiden/miden-node/pull/1430)).
- Reduced default block interval from `5s` to `2s` ([#1438](https://github.com/0xMiden/miden-node/pull/1438)).
- Increased retained account tree history from 33 to 100 blocks to account for the reduced block interval ([#1438](https://github.com/0xMiden/miden-node/pull/1438)).
- Increased the maximum query limit for the store ([#1443](https://github.com/0xMiden/miden-node/pull/1443)).
- [BREAKING] Migrated to version `v0.20` of the VM ([#1476](https://github.com/0xMiden/miden-node/pull/1476)).

### Fixes
Expand Down
239 changes: 150 additions & 89 deletions crates/proto/src/domain/account.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::fmt::{Debug, Display, Formatter};

use miden_node_utils::formatting::format_opt;
use miden_protocol::Word;
use miden_protocol::account::{
Account,
AccountHeader,
Expand All @@ -18,6 +17,7 @@ use miden_protocol::block::account_tree::AccountWitness;
use miden_protocol::crypto::merkle::SparseMerklePath;
use miden_protocol::note::{NoteExecutionMode, NoteTag};
use miden_protocol::utils::{Deserializable, DeserializationError, Serializable};
use miden_protocol::{AssetError, Word};
use thiserror::Error;

use super::try_convert;
Expand Down Expand Up @@ -72,6 +72,7 @@ impl From<AccountId> for proto::account::AccountId {
// ACCOUNT UPDATE
// ================================================================================================

// TODO should be called `AccountStateRef` or so
#[derive(Debug, PartialEq)]
pub struct AccountSummary {
pub account_id: AccountId,
Expand Down Expand Up @@ -99,7 +100,7 @@ impl From<&AccountInfo> for proto::account::AccountDetails {
fn from(AccountInfo { summary, details }: &AccountInfo) -> Self {
Self {
summary: Some(summary.into()),
details: details.as_ref().map(miden_protocol::utils::Serializable::to_bytes),
details: details.as_ref().map(Serializable::to_bytes),
}
}
}
Expand Down Expand Up @@ -192,6 +193,7 @@ impl TryFrom<proto::rpc::account_storage_details::AccountStorageMapDetails>
fn try_from(
value: proto::rpc::account_storage_details::AccountStorageMapDetails,
) -> Result<Self, Self::Error> {
use proto::rpc::account_storage_details::account_storage_map_details::map_entries::StorageMapEntry;
let proto::rpc::account_storage_details::AccountStorageMapDetails {
slot_name,
too_many_entries,
Expand All @@ -200,32 +202,32 @@ impl TryFrom<proto::rpc::account_storage_details::AccountStorageMapDetails>

let slot_name = StorageSlotName::new(slot_name)?;

// Extract map_entries from the MapEntries message
let map_entries = if let Some(entries) = entries {
entries
.entries
.into_iter()
.map(|entry| {
let key = entry
.key
.ok_or(proto::rpc::account_storage_details::account_storage_map_details::map_entries::StorageMapEntry::missing_field(
stringify!(key),
))?
.try_into()?;
let value = entry
.value
.ok_or(proto::rpc::account_storage_details::account_storage_map_details::map_entries::StorageMapEntry::missing_field(
stringify!(value),
))?
.try_into()?;
Ok((key, value))
})
.collect::<Result<Vec<_>, ConversionError>>()?
let entries = if too_many_entries {
StorageMapEntries::LimitExceeded
} else {
Vec::new()
let map_entries = if let Some(entries) = entries {
entries
.entries
.into_iter()
.map(|entry| {
let key = entry
.key
.ok_or(StorageMapEntry::missing_field(stringify!(key)))?
.try_into()?;
let value = entry
.value
.ok_or(StorageMapEntry::missing_field(stringify!(value)))?
.try_into()?;
Ok((key, value))
})
.collect::<Result<Vec<_>, ConversionError>>()?
} else {
Vec::new()
};
StorageMapEntries::Entries(map_entries)
};

Ok(Self { slot_name, too_many_entries, map_entries })
Ok(Self { slot_name, entries })
}
}

Expand Down Expand Up @@ -346,37 +348,64 @@ impl From<AccountStorageHeader> for proto::account::AccountStorageHeader {
}
}

/// Account vault details
///
/// When an account contains a large number of assets (>
/// [`AccountVaultDetails::MAX_RETURN_ENTRIES`]), including all assets in a single RPC response
/// creates performance issues. In such cases, the `LimitExceeded` variant indicates to the client
/// to use the `SyncAccountVault` endpoint instead.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccountVaultDetails {
pub too_many_assets: bool,
pub assets: Vec<Asset>,
pub enum AccountVaultDetails {
/// The vault has too many assets to return inline.
/// Clients must use `SyncAccountVault` endpoint instead.
LimitExceeded,

/// The assets in the vault (up to `MAX_RETURN_ENTRIES`).
Assets(Vec<Asset>),
}

impl AccountVaultDetails {
const MAX_RETURN_ENTRIES: usize = 1000;
/// Maximum number of vault entries that can be returned in a single response.
/// Accounts with more assets will have `LimitExceeded` variant.
pub const MAX_RETURN_ENTRIES: usize = 1000;

pub fn new(vault: &AssetVault) -> Self {
if vault.assets().nth(Self::MAX_RETURN_ENTRIES).is_some() {
Self::too_many()
Self::LimitExceeded
} else {
Self {
too_many_assets: false,
assets: Vec::from_iter(vault.assets()),
}
Self::Assets(Vec::from_iter(vault.assets()))
}
}

pub fn empty() -> Self {
Self {
too_many_assets: false,
assets: Vec::new(),
Self::Assets(Vec::new())
}

/// Creates `AccountVaultDetails` from a list of assets.
pub fn from_assets(assets: Vec<Asset>) -> Self {
if assets.len() > Self::MAX_RETURN_ENTRIES {
Self::LimitExceeded
} else {
Self::Assets(assets)
}
}

fn too_many() -> Self {
Self {
too_many_assets: true,
assets: Vec::new(),
/// Creates `AccountVaultDetails` from vault entries (key-value pairs).
///
/// This is useful when entries have been fetched directly from the database
/// rather than extracted from an `AssetVault`.
///
/// The entries are `(vault_key, asset)` pairs where `asset` is a Word representation.
pub fn from_entries(entries: Vec<(Word, Word)>) -> Result<Self, AssetError> {
if entries.len() > Self::MAX_RETURN_ENTRIES {
return Ok(Self::LimitExceeded);
}

let assets = Result::<Vec<_>, _>::from_iter(
entries.into_iter().map(|(_key, asset_word)| Asset::try_from(asset_word)),
)?;

Ok(Self::Assets(assets))
}
}

Expand All @@ -386,40 +415,66 @@ impl TryFrom<proto::rpc::AccountVaultDetails> for AccountVaultDetails {
fn try_from(value: proto::rpc::AccountVaultDetails) -> Result<Self, Self::Error> {
let proto::rpc::AccountVaultDetails { too_many_assets, assets } = value;

let assets =
Result::<Vec<_>, ConversionError>::from_iter(assets.into_iter().map(|asset| {
let asset = asset
.asset
.ok_or(proto::primitives::Asset::missing_field(stringify!(asset)))?;
let asset = Word::try_from(asset)?;
Asset::try_from(asset).map_err(ConversionError::AssetError)
}))?;
Ok(Self { too_many_assets, assets })
if too_many_assets {
Ok(Self::LimitExceeded)
} else {
let parsed_assets =
Result::<Vec<_>, ConversionError>::from_iter(assets.into_iter().map(|asset| {
let asset = asset
.asset
.ok_or(proto::primitives::Asset::missing_field(stringify!(asset)))?;
let asset = Word::try_from(asset)?;
Asset::try_from(asset).map_err(ConversionError::AssetError)
}))?;
Ok(Self::Assets(parsed_assets))
}
}
}

impl From<AccountVaultDetails> for proto::rpc::AccountVaultDetails {
fn from(value: AccountVaultDetails) -> Self {
let AccountVaultDetails { too_many_assets, assets } = value;

Self {
too_many_assets,
assets: Vec::from_iter(assets.into_iter().map(|asset| proto::primitives::Asset {
asset: Some(proto::primitives::Digest::from(Word::from(asset))),
})),
match value {
AccountVaultDetails::LimitExceeded => Self {
too_many_assets: true,
assets: Vec::new(),
},
AccountVaultDetails::Assets(assets) => Self {
too_many_assets: false,
assets: Vec::from_iter(assets.into_iter().map(|asset| proto::primitives::Asset {
asset: Some(proto::primitives::Digest::from(Word::from(asset))),
})),
},
}
}
}

/// Storage map entries for an account storage slot.
///
/// When a storage map contains many entries (> [`AccountStorageMapDetails::MAX_RETURN_ENTRIES`]),
/// returning all entries in a single RPC response creates performance issues. In such cases,
/// the `LimitExceeded` variant indicates to the client to use the `SyncStorageMaps` endpoint
/// instead.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum StorageMapEntries {
/// The map has too many entries to return inline.
/// Clients must use `SyncStorageMaps` endpoint instead.
LimitExceeded,

/// The storage map entries (key-value pairs), up to `MAX_RETURN_ENTRIES`.
/// TODO: For partial responses, also include Merkle proofs and inner SMT nodes.
Entries(Vec<(Word, Word)>),
}

/// Details about an account storage map slot.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccountStorageMapDetails {
pub slot_name: StorageSlotName,
pub too_many_entries: bool,
pub map_entries: Vec<(Word, Word)>,
pub entries: StorageMapEntries,
}

impl AccountStorageMapDetails {
const MAX_RETURN_ENTRIES: usize = 1000;
/// Maximum number of storage map entries that can be returned in a single response.
pub const MAX_RETURN_ENTRIES: usize = 1000;

pub fn new(slot_name: StorageSlotName, slot_data: SlotData, storage_map: &StorageMap) -> Self {
match slot_data {
Expand All @@ -430,13 +485,15 @@ impl AccountStorageMapDetails {

fn from_all_entries(slot_name: StorageSlotName, storage_map: &StorageMap) -> Self {
if storage_map.num_entries() > Self::MAX_RETURN_ENTRIES {
Self::too_many_entries(slot_name)
Self {
slot_name,
entries: StorageMapEntries::LimitExceeded,
}
} else {
let map_entries = Vec::from_iter(storage_map.entries().map(|(k, v)| (*k, *v)));
Self {
slot_name,
too_many_entries: false,
map_entries,
entries: StorageMapEntries::Entries(map_entries),
}
}
}
Expand All @@ -447,20 +504,15 @@ impl AccountStorageMapDetails {
storage_map: &StorageMap,
) -> Self {
if keys.len() > Self::MAX_RETURN_ENTRIES {
Self::too_many_entries(slot_name)
Self {
slot_name,
entries: StorageMapEntries::LimitExceeded,
}
} else {
// TODO For now, we return all entries instead of specific keys with proofs
Self::from_all_entries(slot_name, storage_map)
}
}

pub fn too_many_entries(slot_name: StorageSlotName) -> Self {
Self {
slot_name,
too_many_entries: true,
map_entries: Vec::new(),
}
}
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -498,16 +550,16 @@ impl From<AccountStorageDetails> for proto::rpc::AccountStorageDetails {

const fn storage_slot_type_from_raw(slot_type: u32) -> Result<StorageSlotType, ConversionError> {
Ok(match slot_type {
0 => StorageSlotType::Map,
1 => StorageSlotType::Value,
0 => StorageSlotType::Value,
1 => StorageSlotType::Map,
_ => return Err(ConversionError::EnumDiscriminantOutOfRange),
})
}

const fn storage_slot_type_to_raw(slot_type: StorageSlotType) -> u32 {
match slot_type {
StorageSlotType::Map => 0,
StorageSlotType::Value => 1,
StorageSlotType::Value => 0,
StorageSlotType::Map => 1,
}
}

Expand Down Expand Up @@ -628,21 +680,30 @@ impl From<AccountStorageMapDetails>
fn from(value: AccountStorageMapDetails) -> Self {
use proto::rpc::account_storage_details::account_storage_map_details;

let AccountStorageMapDetails { slot_name, too_many_entries, map_entries } = value;
let AccountStorageMapDetails { slot_name, entries } = value;

let entries = Some(account_storage_map_details::MapEntries {
entries: Vec::from_iter(map_entries.into_iter().map(|(key, value)| {
account_storage_map_details::map_entries::StorageMapEntry {
key: Some(key.into()),
value: Some(value.into()),
match entries {
StorageMapEntries::LimitExceeded => Self {
slot_name: slot_name.to_string(),
too_many_entries: true,
entries: Some(account_storage_map_details::MapEntries { entries: Vec::new() }),
},
StorageMapEntries::Entries(map_entries) => {
let entries = Some(account_storage_map_details::MapEntries {
entries: Vec::from_iter(map_entries.into_iter().map(|(key, value)| {
account_storage_map_details::map_entries::StorageMapEntry {
key: Some(key.into()),
value: Some(value.into()),
}
})),
});

Self {
slot_name: slot_name.to_string(),
too_many_entries: false,
entries,
}
})),
});

Self {
slot_name: slot_name.to_string(),
too_many_entries,
entries,
},
}
}
}
Expand Down
Loading