Skip to content

chore: add accounts creation for network monitor#1276

Merged
SantiagoPittella merged 33 commits intonextfrom
santiagopittella-deploy-test-account-network-monitor
Nov 6, 2025
Merged

chore: add accounts creation for network monitor#1276
SantiagoPittella merged 33 commits intonextfrom
santiagopittella-deploy-test-account-network-monitor

Conversation

@SantiagoPittella
Copy link
Collaborator

@SantiagoPittella SantiagoPittella commented Oct 7, 2025

part of #1190

Added the account creations and deployment in this first version.
I'm working on another PR in the periodic value increments, and i'm leaving authentication as the last part.

@SantiagoPittella SantiagoPittella force-pushed the santiagopittella-deploy-test-account-network-monitor branch 2 times, most recently from 1cb7884 to d11a4ea Compare October 7, 2025 22:11
Copy link
Collaborator

@igamigo igamigo left a comment

Choose a reason for hiding this comment

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

Leaving some comments after the offline discussion

use.external_contract::counter_contract

begin
call.counter_contract::increment
Copy link
Collaborator

Choose a reason for hiding this comment

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

If this is used as a transaction script on #1280 (should it be moved to that PR?), it will fail every time because the get_sender call only applies at the moment of note processing (and in general, any getter under active_note)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I removed the sender validations temporarily, since it was complicating things i wanted to first have a simpler version working and then add it after.
Since this change made the deployment to be easier, I merge #1280 here and now we have the complete workflow. I will now work on sending the increment counter requests and display it in the frontend.

Copy link
Contributor

Choose a reason for hiding this comment

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

I would maybe put the authentication logic into counter_contract::increment since we want the counter contract to decide which notes to accept (rather than for notes to decide which accounts can consume them). To do this, we'd need to store the "owner" account ID in the storage slot together with the counter as well, and then before we increment, check that owner_id == note.sender.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I added it here, but fixed some small things in #1295 where it is actually tested.

Comment on lines +27 to +31
push.0
# => [0]

exec.account::get_item
# => [count]
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: Some of these could be grouped for better readability:

Suggested change
push.0
# => [0]
exec.account::get_item
# => [count]
push.0 exec.account::get_item
# => [count]

@SantiagoPittella SantiagoPittella force-pushed the santiagopittella-deploy-test-account-network-monitor branch from e1f2703 to 0040d14 Compare October 9, 2025 20:33
SantiagoPittella and others added 2 commits October 9, 2025 18:13
* chore: add accounts creation command

* wip: deploy accounts

* chore: deploy counter account
@SantiagoPittella SantiagoPittella changed the title chore: add accounts creation command chore: add accounts creation for network monitor Oct 9, 2025
let prover_url_clone = prover_url.clone();
let name_clone = name.clone();
// SAFETY: we matched Some above
let proof_type = proof_type.unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: would do .expect("proof type is not none") instead of safety comment

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you. I left some comments inline.

@SantiagoPittella
Copy link
Collaborator Author

I would maybe put the authentication logic into counter_contract::increment since we want the counter contract to decide which notes to accept (rather than for notes to decide which accounts can consume them). To do this, we'd need to store the "owner" account ID in the storage slot together with the counter as well, and then before we increment, check that owner_id == note.sender.

Yes. I did exactly that in the first implementation that I did of the procedures, but ATM I'm using the increment to deploy the network account too, so it was incompatible due to the account ID check failing (the sender was the network account itself and not the wallet)

@SantiagoPittella
Copy link
Collaborator Author

I replaced the deployment, adding authentication and a call to get_count instead of the counter increase, so the nonce is increased but we dont need to go through the account ID match verification for deployment.

Comment on lines +33 to +53
let account_code = AccountComponent::compile(
script,
TransactionKernel::assembler(),
vec![StorageSlot::empty_value(), StorageSlot::Value(owner_word)],
)?
.with_supports_all_types();

const INCR_NONCE_AUTH_CODE: &str = r"
use.miden::account
use.std::sys

export.auth__basic
exec.account::incr_nonce
drop
end
";

let incr_nonce_auth =
AccountComponent::compile(INCR_NONCE_AUTH_CODE, TransactionKernel::assembler(), vec![])
.context("failed to compile increment nonce auth component")?
.with_supports_all_types();
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if IncrNonce component from the mock tools from miden-testing can be used here instead (I think they are pretty much equivalent).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes! It is equivalent. I;m replacing it since we already use miden testing.

use.miden::account
use.std::sys

export.auth__basic
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: I'm not 100% sure, but I believe having two underscores is not required anymore (ie, auth_basic would work)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It was removed in the replacement with miden testing


// Compile the account code
let owner_felts: [Felt; 2] = owner_account_id.into();
let owner_word = Word::from([owner_felts[0], owner_felts[1], Felt::new(0), Felt::new(0)]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Based on how these will be used, would it be better to arrange them differently?

Suggested change
let owner_word = Word::from([owner_felts[0], owner_felts[1], Felt::new(0), Felt::new(0)]);
let owner_word = Word::from([Felt::ZERO, Felt::ZERO, owner_felts[1], owner_felts[0]]);

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Should it like this? It the prefix first and then the suffix

Suggested change
let owner_word = Word::from([owner_felts[0], owner_felts[1], Felt::new(0), Felt::new(0)]);
let owner_word = Word::from([Felt::new(0), Felt::new(0), owner_felts[0], owner_felts[1]]);

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh no, you're right, i see why.

.with_auth_component(incr_nonce_auth)
.build()?;

Ok(counter_program)
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: "program" is a bit misleading, I've seen people name this "counter contract" or "counter account"

Comment on lines +16 to +25
# Ensure the note sender matches the authorized wallet stored in slot 1.
push.0 exec.input_note::get_sender
# => [sender_prefix, sender_suffix]
push.1 exec.account::get_item
# => [sender_prefix, sender_suffix, owner_prefix, owner_suffix, 0, 0]
movup.3 drop
movup.2 drop
# => [sender_prefix, sender_suffix, owner_prefix, owner_suffix]
exec.account_id::is_equal
assert
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think the ordering on the stack comments may not be correct here. Now that I see how the account is set up, I also think what I commented offline was not fully correct either. If the ordering of the owner word is as in this other comment, I believe you should be able to do something like:

    push.1 exec.account::get_item
    # => [owner_prefix, owner_suffix, 0, 0]

    exec.active_note::get_sender
    # => [sender_prefix, sender_suffix, owner_prefix, owner_suffix, 0, 0]

    exec.account_id::is_equal
    # => [are_equal, 0, 0]
    
    assert drop drop

(but maybe this is not fully correct either, I have not run it)

Comment on lines +68 to +71
if wallet_exists && counter_exists {
tracing::info!("Account files already exist, skipping account creation");
return Ok(());
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this shouldn't matter too much outside of testing (where one may want to reset the state of at least one of the accounts), but if somehow only one of these were false, both accounts would be created again. Maybe this was intended but mentioning it just in case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

If only the wallet does not exists, the counter needs to be created again (since it is coupled to a wallet). The other way (wallet exists but not the counter) might be possible and should work

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Despite that it should work to deploy a new counter with an existing account, we probably want to use a new wallet to keep some consistency between accounts, wdyt? I can comment it in the check

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah yes, thanks for the explanation. Makes sense! I think always re-creating both should be fine.

1. Checks for existing account files on startup
2. Creates new accounts if files don't exist
3. Deploys accounts to the network via RPC
4. Uses the specified file paths (default: `wallet_account.bin` and `counter_program.bin`)
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: When using AccountFile, we've used the .mac suffix for files. Also, I'd mention that the files are saved in the paths:

Suggested change
4. Uses the specified file paths (default: `wallet_account.bin` and `counter_program.bin`)
4. Saves the wallet and counter contract account in the specified file paths (default: `wallet_account.mac` and `counter_program.mac`)

Copy link
Collaborator

Choose a reason for hiding this comment

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

I was trying to test this locally and saw that the default port does not match with the node's default (altohugh in the env file it seems to be correct). Should it be changed here as well?

Suggested change
const DEFAULT_RPC_URL: &str = "http://localhost:57291";

Copy link
Contributor

@bobbinth bobbinth left a comment

Choose a reason for hiding this comment

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

Looks good! Thank you! I left a few more small comments inline, and I think there are some comments from @igamigo that still need to be addressed.

Also, we should rebase this from the latest next now that it is updated to v0.12.0 miden-base.

Copy link
Collaborator

@igamigo igamigo left a comment

Choose a reason for hiding this comment

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

LGTM! Left a few comments. Let me know if they are not clear. Overall though, they are mostly optional and so this should be good to merge.

One more thing: it would be great to test this somehow to make sure we catch functional drifts without having to manually run the monitor (similar to the stress test). This would include either mocking the node or running an integration test, so it could be left for a different issue.

.map_err(|e| anyhow::anyhow!("Failed to assemble library: {e}"))
}

// MONITOR DATA STORE
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: I'd probably move this to its own mod

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since it is not too large and only used in this same file, I think that leaving it here is fine. Maybe we can consider to move it if we start to use it somewhere else, wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yeah, sounds good. Not a strong opinion bjut it felt like the executor side of things could be refactored into its own submodule, but I agree it's probably premature

Comment on lines +88 to +97
/// Deploy accounts to the network.
///
/// This function creates both a wallet account and a counter program account,
/// then saves them to the specified files.
#[instrument(target = COMPONENT, name = "deploy-accounts", skip_all, ret(level = "debug"))]
pub async fn deploy_accounts(
wallet_account: &Account,
counter_account: &Account,
rpc_url: &Url,
) -> Result<()> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think part of the doc comment is outdated. Also, really only the counter account gets deployed to the network, right? So maybe it could be named deploy_counter_contract

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It was already changed with deploy_counter_account in the follow up PR https://github.com/0xMiden/miden-node/pull/1295/files already

Comment on lines +1 to +2
# Transaction script used during deployment to bump the counter contract nonce
# without changing the counter value.
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think transaction scripts are not needed anymore for this. I'd try removing it and executing without a script.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Awesome, tested it and works. I remvoed the deploy tx script.

Comment on lines +260 to +284
let account = self.wallet_account.lock().await;

let account = if account_id == account.id() {
account.to_owned()
} else {
self.counter_account.lock().await.to_owned()
};

let mut map_witness = None;
for slot in account.storage().slots() {
if let StorageSlot::Map(map) = slot {
if map.root() == map_root {
map_witness = Some(map.open(&map_key));
}
}
}

if let Some(map_witness) = map_witness {
Ok(map_witness)
} else {
Err(DataStoreError::Other {
error_msg: "account storage does not contain the expected root".into(),
source: None,
})
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

In get_transaction_inputs you are instantiating the partial accounts with PartialAccount::from. If you include all the account data (I think you'd need to use PartialAccount::new), I think you should be able to remove the implementations of these methods. I would test removing them. We can also keep them, but it's more maintenance overhead + more code to test.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removing the get_storage_map_witness worked when removing while using PartialAccount::new, that was not the case for get_vault_asset_witness.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Interesting, I wonder why that was? I don't think assets are involved in these flows.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'll do further investigation after merging this PR 👍🏼

@SantiagoPittella SantiagoPittella merged commit 6a8dea2 into next Nov 6, 2025
6 checks passed
@SantiagoPittella SantiagoPittella deleted the santiagopittella-deploy-test-account-network-monitor branch November 6, 2025 21:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants