From 53b4ea4655527521672d1b081ed1ce13d3ddc658 Mon Sep 17 00:00:00 2001 From: Ollie202 Date: Tue, 26 May 2026 05:56:22 +0100 Subject: [PATCH] fix(network-monitor): move local proving off async runtime --- CHANGELOG.md | 1 + bin/network-monitor/src/counter.rs | 49 +++++++++++++---------- bin/network-monitor/src/deploy/mod.rs | 56 +++++++++++++++++---------- 3 files changed, 66 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 52c4ac070..e40502f42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - [BREAKING] Removed `CheckNullifiers` endpoint ([#2049](https://github.com/0xMiden/node/pull/2049)). - Replaced blocking-in-async operations in the validator, remote prover, and ntx-builder with `spawn_blocking` to avoid starving the Tokio runtime ([#2041](https://github.com/0xMiden/node/pull/2041)). - Replaced local store block proving with `spawn_blocking` to avoid starving the Tokio runtime ([#1976](https://github.com/0xMiden/node/issues/1976)). +- Replaced local network monitor transaction execution and proving with `spawn_blocking` to avoid starving the Tokio runtime ([#1976](https://github.com/0xMiden/node/issues/1976)). - Implemented persistent RocksDB backend for `AccountStateForest`, improving startup time ([#2020](https://github.com/0xMiden/node/pull/2020)). - [BREAKING] Replaced binding URL env vars and CLI flags with listen socket addresses ([#2054](https://github.com/0xMiden/node/pull/2054)). - [BREAKING] `BlockRange.block_to` is now required for all RPC endpoints ([#2056](https://github.com/0xMiden/node/pull/2056)). diff --git a/bin/network-monitor/src/counter.rs b/bin/network-monitor/src/counter.rs index 68ae3ff71..358af21ec 100644 --- a/bin/network-monitor/src/counter.rs +++ b/bin/network-monitor/src/counter.rs @@ -11,6 +11,7 @@ use anyhow::{Context, Result}; use miden_node_proto::clients::RpcClient; use miden_node_proto::generated::rpc::BlockHeaderByNumberRequest; use miden_node_proto::generated::transaction::ProvenTransaction; +use miden_node_utils::spawn::spawn_blocking_in_current_span; use miden_protocol::account::auth::AuthSecretKey; use miden_protocol::account::{Account, AccountCode, AccountHeader, AccountId}; use miden_protocol::asset::AssetVault; @@ -271,10 +272,6 @@ impl IncrementService { err )] async fn submit_increment(&mut self) -> Result<(String, AccountHeader, BlockNumber)> { - let authenticator = BasicAuthenticator::new(&[AuthSecretKey::Falcon512Poseidon2( - self.tx.secret_key.clone(), - )]); - let account_interface = AccountInterface::from_account(&self.tx.wallet_account); let (network_note, note_recipient) = create_network_note( @@ -285,26 +282,38 @@ impl IncrementService { )?; let script = account_interface.build_send_notes_script(&[network_note.into()], None)?; - let executor = - TransactionExecutor::new(&self.tx.data_store).with_authenticator(&authenticator); - let mut tx_args = TransactionArgs::default().with_tx_script(script); tx_args.add_output_note_recipient(Box::new(note_recipient)); - let executed_tx = Box::pin(executor.execute_transaction( - self.tx.wallet_account.id(), - self.tx.block_header.block_num(), - InputNotes::default(), - tx_args, - )) + let data_store = self.tx.data_store.clone(); + let secret_key = self.tx.secret_key.clone(); + let account_id = self.tx.wallet_account.id(); + let block_num = self.tx.block_header.block_num(); + let handle = tokio::runtime::Handle::current(); + let (proven_tx, tx_inputs, final_account) = spawn_blocking_in_current_span(move || { + let authenticator = + BasicAuthenticator::new(&[AuthSecretKey::Falcon512Poseidon2(secret_key)]); + let executor = TransactionExecutor::new(&data_store).with_authenticator(&authenticator); + + let executed_tx = handle + .block_on(executor.execute_transaction( + account_id, + block_num, + InputNotes::default(), + tx_args, + )) + .context("Failed to execute transaction")?; + + let tx_inputs = executed_tx.tx_inputs().to_bytes(); + let final_account = executed_tx.final_account().clone(); + let proven_tx = handle + .block_on(LocalTransactionProver::default().prove(executed_tx)) + .context("Failed to prove transaction")?; + + Ok::<_, anyhow::Error>((proven_tx, tx_inputs, final_account)) + }) .await - .context("Failed to execute transaction")?; - - let tx_inputs = executed_tx.tx_inputs().to_bytes(); - let final_account = executed_tx.final_account().clone(); - - let prover = LocalTransactionProver::default(); - let proven_tx = prover.prove(executed_tx).await.context("Failed to prove transaction")?; + .context("counter increment task failed")??; let request = ProvenTransaction { transaction: proven_tx.to_bytes(), diff --git a/bin/network-monitor/src/deploy/mod.rs b/bin/network-monitor/src/deploy/mod.rs index e4c8c60a8..2b6cf9b14 100644 --- a/bin/network-monitor/src/deploy/mod.rs +++ b/bin/network-monitor/src/deploy/mod.rs @@ -10,6 +10,7 @@ use anyhow::{Context, Result}; use miden_node_proto::clients::{Builder, RpcClient}; use miden_node_proto::generated::rpc::BlockHeaderByNumberRequest; use miden_node_proto::generated::transaction::ProvenTransaction; +use miden_node_utils::spawn::spawn_blocking_in_current_span; use miden_protocol::account::{Account, AccountId, PartialAccount, StorageMapKey}; use miden_protocol::asset::{AssetVaultKey, AssetWitness}; use miden_protocol::block::{BlockHeader, BlockNumber}; @@ -141,26 +142,31 @@ pub async fn deploy_counter_account(counter_account: &Account, rpc_url: &Url) -> let mut data_store = MonitorDataStore::new(genesis_header, genesis_chain_mmr); data_store.add_account(counter_account.clone()); - let executor: TransactionExecutor<'_, '_, _, BasicAuthenticator> = - TransactionExecutor::new(&data_store).with_debug_mode(); - - let tx_args = TransactionArgs::default(); - - let executed_tx = executor - .execute_transaction( - counter_account.id(), - BlockNumber::GENESIS, - InputNotes::default(), - tx_args, - ) - .await - .context("Failed to execute transaction")?; - - let transaction_inputs = executed_tx.tx_inputs().to_bytes(); - - let prover = LocalTransactionProver::default(); - - let proven_tx = prover.prove(executed_tx).await.context("Failed to prove transaction")?; + let account_id = counter_account.id(); + let handle = tokio::runtime::Handle::current(); + let (proven_tx, transaction_inputs) = spawn_blocking_in_current_span(move || { + let executor: TransactionExecutor<'_, '_, _, BasicAuthenticator> = + TransactionExecutor::new(&data_store).with_debug_mode(); + + let tx_args = TransactionArgs::default(); + let executed_tx = handle + .block_on(executor.execute_transaction( + account_id, + BlockNumber::GENESIS, + InputNotes::default(), + tx_args, + )) + .context("Failed to execute transaction")?; + + let transaction_inputs = executed_tx.tx_inputs().to_bytes(); + let proven_tx = handle + .block_on(LocalTransactionProver::default().prove(executed_tx)) + .context("Failed to prove transaction")?; + + Ok::<_, anyhow::Error>((proven_tx, transaction_inputs)) + }) + .await + .context("counter account deployment task failed")??; let request = ProvenTransaction { transaction: proven_tx.to_bytes(), @@ -186,6 +192,16 @@ pub struct MonitorDataStore { mast_store: TransactionMastStore, } +impl Clone for MonitorDataStore { + fn clone(&self) -> Self { + let mut cloned = Self::new(self.block_header.clone(), self.partial_block_chain.clone()); + for account in self.accounts.values() { + cloned.add_account(account.clone()); + } + cloned + } +} + impl MonitorDataStore { pub fn new(block_header: BlockHeader, partial_block_chain: PartialBlockchain) -> Self { Self {