Skip to content
Merged
Show file tree
Hide file tree
Changes from 147 commits
Commits
Show all changes
148 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
3265406
add partial storage maps
drahnr Dec 4, 2025
e453faa
remoe useless comment
drahnr Dec 19, 2025
15af845
CI fixins
drahnr Dec 19, 2025
f6d1ce1
shorthandg pu
drahnr Dec 19, 2025
617c033
yay
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
6fb80fe
yay
drahnr Dec 22, 2025
efaa685
feedback
drahnr Dec 22, 2025
d6b31ef
minor
drahnr Dec 22, 2025
9c859fc
fmt
drahnr Dec 23, 2025
1dba957
Merge branch 'bernhard-integrate-smtforest' into bernhard-partial-sto…
drahnr Dec 23, 2025
2982002
fff
drahnr Dec 23, 2025
58ed218
remove get account details
drahnr Nov 25, 2025
7a0eab4
fix: remove broken fetch_wallet_account function
drahnr Dec 2, 2025
fd260ad
fix: properly implement fetch_wallet_account to sync nonce from RPC
drahnr Dec 2, 2025
2dd3f20
fix
drahnr Dec 23, 2025
687a4a1
fixup changelog
drahnr Dec 23, 2025
f000d5d
counter fetch wallet account impl
drahnr Dec 23, 2025
d2211e3
review comments
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
84f3bb2
y
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
f702791
mixed bag
drahnr Dec 29, 2025
16f5785
Merge remote-tracking branch 'origin/bernhard-integrate-smtforest' in…
drahnr Dec 29, 2025
b2eaa55
unity
drahnr Dec 29, 2025
c43a5a2
splits
drahnr Dec 29, 2025
68ed4d7
y
drahnr Dec 29, 2025
bd2709c
behaviour
drahnr Dec 29, 2025
3346d9f
cleanup
drahnr Dec 29, 2025
dbbc1eb
fmt
drahnr Dec 29, 2025
b3c91df
remove dead code
drahnr Dec 29, 2025
77443c2
foo
drahnr Dec 29, 2025
1efa4f0
fixup
drahnr Dec 29, 2025
69ee5a5
change log
drahnr Dec 29, 2025
3bd5451
Merge branch 'bernhard-db-schema-queries' into bernhard-integrate-smt…
drahnr Dec 30, 2025
c5a199a
Merge branch 'bernhard-db-schema-queries' into bernhard-integrate-smt…
drahnr Dec 30, 2025
5ed7cb2
Merge branch 'bernhard-integrate-smtforest' into bernhard-partial-sto…
drahnr Dec 30, 2025
4ecb76c
review
drahnr Dec 30, 2025
199a5cb
Merge branch 'bernhard-integrate-smtforest' into bernhard-partial-sto…
drahnr Dec 30, 2025
badee2d
Merge branch 'bernhard-partial-storage-map-queries' into bernhard-uni…
drahnr Dec 30, 2025
119ed10
Merge branch 'bernhard-integrate-smtforest' into bernhard-partial-sto…
drahnr Dec 30, 2025
890191f
Merge branch 'bernhard-partial-storage-map-queries' into bernhard-uni…
drahnr Dec 30, 2025
c64392c
lint clippy fmt
drahnr Dec 30, 2025
8d33f66
fix storage_header comment
drahnr Dec 30, 2025
635cb78
select_account_code_at_block -> select_account_code_by_commitment
drahnr Dec 30, 2025
7ca6999
add minor test xtension
drahnr Dec 30, 2025
b085793
y
drahnr Jan 3, 2026
39da912
merge fuckup
drahnr Jan 3, 2026
c712ba4
Merge branch 'bernhard-db-schema-queries' into bernhard-integrate-smt…
drahnr Jan 4, 2026
0874065
Merge branch 'bernhard-integrate-smtforest' into bernhard-partial-sto…
drahnr Jan 5, 2026
ba9ed1b
clippy
drahnr Jan 6, 2026
d9a666f
review
drahnr Jan 6, 2026
29b840c
remove dead code
drahnr Jan 6, 2026
1b22a34
chore: minor rename
bobbinth Jan 7, 2026
1cab5e2
review
drahnr Jan 9, 2026
c42d5f5
some more docs
drahnr Jan 9, 2026
f1655fe
Merge remote-tracking branch 'origin/next' into bernhard-integrate-sm…
drahnr Jan 9, 2026
9fe3979
add InnerForestError type, make asset addition non-panic
drahnr Jan 10, 2026
6f823e4
review
drahnr Jan 10, 2026
77eee02
remove dead code
drahnr Jan 10, 2026
5a8ea18
clippy
drahnr Jan 10, 2026
f6cd4b3
minor
drahnr Jan 10, 2026
38f3763
Merge remote-tracking branch 'origin/next' into bernhard-integrate-sm…
drahnr Jan 10, 2026
6e40652
Merge remote-tracking branch 'origin/bernhard-integrate-smtforest' in…
drahnr Jan 11, 2026
6e073f7
fixins
drahnr Jan 11, 2026
b9fdd4c
fixup
drahnr Jan 12, 2026
b72a2e9
Merge remote-tracking branch 'origin/next' into bernhard-partial-stor…
drahnr Jan 12, 2026
45b67f8
remove dead code
drahnr Jan 12, 2026
15a0b9a
better range patterns - composite keys are tricky
drahnr Jan 12, 2026
e73cb22
Merge branch 'bernhard-partial-storage-map-queries' into bernhard-uni…
drahnr Jan 12, 2026
bcafa1d
Merge remote-tracking branch 'origin/next' into bernhard-unify-get-de…
drahnr Jan 14, 2026
d328f86
better comment
drahnr Jan 14, 2026
0cc90d2
counter slot lookup by name
drahnr Jan 14, 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

### Changes

- [BREAKING] Removed `GetAccountDetails` RPC endpoint. Use `GetAccount` instead ([#1185](https://github.com/0xMiden/miden-node/issues/1185)).
- [BREAKING] Renamed `SyncTransactions` response fields ([#1357](https://github.com/0xMiden/miden-node/pull/1357)).
- Normalize response size in endpoints to 4 MB ([#1357](https://github.com/0xMiden/miden-node/pull/1357)).
- [BREAKING] Renamed `ProxyWorkerStatus::address` to `ProxyWorkerStatus::name` ([#1348](https://github.com/0xMiden/miden-node/pull/1348)).
Expand Down
218 changes: 188 additions & 30 deletions bin/network-monitor/src/counter.rs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: not for this PR, but I'd try to break up this file into a couple of smaller files.

Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ use tracing::{error, info, instrument, warn};

use crate::COMPONENT;
use crate::config::MonitorConfig;
use crate::deploy::counter::COUNTER_SLOT_NAME;
use crate::deploy::{MonitorDataStore, create_genesis_aware_rpc_client, get_counter_library};
use crate::status::{
CounterTrackingDetails,
Expand Down Expand Up @@ -84,55 +83,216 @@ async fn get_genesis_block_header(rpc_client: &mut RpcClient) -> Result<BlockHea
Ok(block_header)
}

/// Fetch the latest counter value of the given account from RPC.
/// Fetch the storage header of the given account from RPC.
///
/// Returns `None` if the account does not exist or has no details available.
async fn fetch_account_storage_header(
rpc_client: &mut RpcClient,
account_id: AccountId,
) -> Result<Option<miden_node_proto::generated::account::AccountStorageHeader>> {
let request = build_account_request(account_id, false);
let resp = rpc_client.get_account(request).await?.into_inner();

let Some(details) = resp.details else {
return Ok(None);
};

let storage_details = details.storage_details.context("missing storage details")?;
let storage_header = storage_details.header.context("missing storage header")?;

Ok(Some(storage_header))
}

/// Fetch the latest nonce of the given account from RPC.
async fn fetch_counter_value(
rpc_client: &mut RpcClient,
account_id: AccountId,
) -> Result<Option<u64>> {
let id_bytes: [u8; 15] = account_id.into();
let req = miden_node_proto::generated::account::AccountId { id: id_bytes.to_vec() };
let resp = rpc_client.get_account_details(req).await?.into_inner();
if let Some(raw) = resp.details {
let account = Account::read_from_bytes(&raw)
.map_err(|e| anyhow::anyhow!("failed to deserialize account details: {e}"))?;
let Some(storage_header) = fetch_account_storage_header(rpc_client, account_id).await? else {
return Ok(None);
};

let first_slot = storage_header.slots.first().context("no storage slots found")?;

// The counter value is stored as a Word, with the actual u64 value in the last element
let slot_value: Word = first_slot
.commitment
.as_ref()
.context("missing storage slot value")?
.try_into()
.context("failed to convert slot value to word")?;

// Access the counter slot by name to avoid index-ordering issues
let word = account
.storage()
.get_item(&COUNTER_SLOT_NAME)
.context("failed to get counter storage slot")?;
let value = slot_value.as_elements().last().expect("Word has 4 elements").as_int();

let value = word[0].as_int();
Ok(Some(value))
}

Ok(Some(value))
/// Build an account request for the given account ID.
///
/// If `include_code_and_vault` is true, uses dummy commitments to force the server
/// to return code and vault data (server only returns data when our commitment differs).
fn build_account_request(
account_id: AccountId,
include_code_and_vault: bool,
) -> miden_node_proto::generated::rpc::AccountRequest {
let id_bytes: [u8; 15] = account_id.into();
let account_id_proto =
miden_node_proto::generated::account::AccountId { id: id_bytes.to_vec() };

let (code_commitment, asset_vault_commitment) = if include_code_and_vault {
let dummy: miden_node_proto::generated::primitives::Digest = Word::default().into();
(Some(dummy), Some(dummy))
} else {
Ok(None)
(None, None)
};

miden_node_proto::generated::rpc::AccountRequest {
account_id: Some(account_id_proto),
block_num: None,
details: Some(miden_node_proto::generated::rpc::account_request::AccountDetailRequest {
code_commitment,
asset_vault_commitment,
storage_maps: vec![],
}),
}
}

/// Fetch an account from RPC and reconstruct the full Account.
///
/// Uses dummy commitments to force the server to return all data (code, vault, storage header).
/// Only supports accounts with value slots; returns an error if storage maps are present.
async fn fetch_wallet_account(
rpc_client: &mut RpcClient,
account_id: AccountId,
) -> Result<Option<Account>> {
let id_bytes: [u8; 15] = account_id.into();
let req = miden_node_proto::generated::account::AccountId { id: id_bytes.to_vec() };
let resp = rpc_client.get_account_details(req).await;
use miden_protocol::account::AccountCode;
use miden_protocol::asset::AssetVault;

// If the RPC call fails, return None
if resp.is_err() {
return Ok(None);
}
let request = build_account_request(account_id, true);

let Some(account_details) = resp.expect("Previously checked for error").into_inner().details
else {
let response = match rpc_client.get_account(request).await {
Ok(response) => response.into_inner(),
Err(e) => {
warn!(account.id = %account_id, err = %e, "failed to fetch wallet account via RPC");
return Ok(None);
},
};

let Some(details) = response.details else {
if response.witness.is_some() {
info!(
account.id = %account_id,
"account found on-chain but cannot reconstruct full account from RPC response"
);
}
return Ok(None);
};
let account = Account::read_from_bytes(&account_details)
.map_err(|e| anyhow::anyhow!("failed to deserialize account details: {e}"))?;

let header = details.header.context("missing account header")?;
let nonce: u64 = header.nonce;

let code = details
.code
.map(|code_bytes| AccountCode::read_from_bytes(&code_bytes))
.transpose()
.context("failed to deserialize account code")?
.context("server did not return account code")?;

let vault = match details.vault_details {
Some(vault_details) if vault_details.too_many_assets => {
anyhow::bail!("account {account_id} has too many assets, cannot fetch full account");
},
Some(vault_details) => {
let assets: Vec<miden_protocol::asset::Asset> = vault_details
.assets
.into_iter()
.map(TryInto::try_into)
.collect::<Result<_, _>>()
.context("failed to convert assets")?;
AssetVault::new(&assets).context("failed to create vault")?
},
None => anyhow::bail!("server did not return asset vault for account {account_id}"),
};

let storage_details = details.storage_details.context("missing storage details")?;
let storage = build_account_storage(storage_details)?;

let account = Account::new(account_id, vault, storage, code, Felt::new(nonce), None)
.context("failed to create account")?;

// Sanity check: verify reconstructed account matches header commitments
let expected_code_commitment: Word = header
.code_commitment
.context("missing code commitment in header")?
.try_into()
.context("invalid code commitment")?;
let expected_vault_root: Word = header
.vault_root
.context("missing vault root in header")?
.try_into()
.context("invalid vault root")?;
let expected_storage_commitment: Word = header
.storage_commitment
.context("missing storage commitment in header")?
.try_into()
.context("invalid storage commitment")?;

anyhow::ensure!(
account.code().commitment() == expected_code_commitment,
"code commitment mismatch: rebuilt={:?}, expected={:?}",
account.code().commitment(),
expected_code_commitment
);
anyhow::ensure!(
account.vault().root() == expected_vault_root,
"vault root mismatch: rebuilt={:?}, expected={:?}",
account.vault().root(),
expected_vault_root
);
anyhow::ensure!(
account.storage().to_commitment() == expected_storage_commitment,
"storage commitment mismatch: rebuilt={:?}, expected={:?}",
account.storage().to_commitment(),
expected_storage_commitment
);

info!(account.id = %account_id, "fetched wallet account from RPC");
Ok(Some(account))
}

/// Build account storage from the storage details returned by the server.
///
/// This function only supports accounts with value slots. If any storage map slots
/// are encountered, an error is returned since the monitor only uses simple accounts.
fn build_account_storage(
storage_details: miden_node_proto::generated::rpc::AccountStorageDetails,
) -> Result<miden_protocol::account::AccountStorage> {
use miden_protocol::account::{AccountStorage, StorageSlot};

let storage_header = storage_details.header.context("missing storage header")?;

let mut slots = Vec::new();
for slot in storage_header.slots {
let slot_name = miden_protocol::account::StorageSlotName::new(slot.slot_name.clone())
.context("invalid slot name")?;
let value: Word = slot
.commitment
.context("missing slot value")?
.try_into()
.context("invalid slot value")?;

// slot_type: 0 = Value, 1 = Map
anyhow::ensure!(
slot.slot_type == 0,
"storage map slots are not supported for this account"
);

slots.push(StorageSlot::with_value(slot_name, value));
}

AccountStorage::new(slots).context("failed to create account storage")
}

async fn setup_increment_task(
config: MonitorConfig,
rpc_client: &mut RpcClient,
Expand Down Expand Up @@ -649,16 +809,14 @@ async fn create_and_submit_network_note(

let final_account = executed_tx.final_account().clone();

let transaction_inputs = executed_tx.tx_inputs().to_bytes();

// Prove the transaction
let prover = LocalTransactionProver::default();
let proven_tx = prover.prove(executed_tx).context("Failed to prove transaction")?;

// Submit the proven transaction
let request = ProvenTransaction {
transaction: proven_tx.to_bytes(),
transaction_inputs: Some(transaction_inputs),
transaction_inputs: None,
};

let block_height: BlockNumber = rpc_client
Expand Down
Loading