From d907308fbe5bfa928cd71df35a91b08a77e8341f Mon Sep 17 00:00:00 2001 From: sergerad Date: Mon, 15 Dec 2025 10:00:40 +1300 Subject: [PATCH 1/6] Revert "Revert "Use RPC to submit proven tx in ntx-builder"" This reverts commit ab880c510fb5ba04894a0146fc1593e9b76eef9b. --- bin/node/src/commands/bundled.rs | 1 + crates/ntx-builder/src/actor/execute.rs | 40 +++++++++++------------- crates/ntx-builder/src/actor/mod.rs | 14 ++++----- crates/ntx-builder/src/block_producer.rs | 16 ---------- crates/ntx-builder/src/builder.rs | 6 +++- crates/ntx-builder/src/lib.rs | 1 + 6 files changed, 33 insertions(+), 45 deletions(-) diff --git a/bin/node/src/commands/bundled.rs b/bin/node/src/commands/bundled.rs index 09bdcf025..b928222da 100644 --- a/bin/node/src/commands/bundled.rs +++ b/bin/node/src/commands/bundled.rs @@ -275,6 +275,7 @@ impl BundledCommand { NetworkTransactionBuilder::new( store_ntx_builder_url, block_producer_url, + rpc_url, ntx_builder.tx_prover_url, ntx_builder.ticker_interval, checkpoint, diff --git a/crates/ntx-builder/src/actor/execute.rs b/crates/ntx-builder/src/actor/execute.rs index ff306b84d..2449f3880 100644 --- a/crates/ntx-builder/src/actor/execute.rs +++ b/crates/ntx-builder/src/actor/execute.rs @@ -46,7 +46,7 @@ use tracing::{Instrument, instrument}; use crate::COMPONENT; use crate::actor::account_state::TransactionCandidate; -use crate::block_producer::BlockProducerClient; +use crate::rpc::RpcClient; use crate::store::StoreClient; #[derive(Debug, thiserror::Error)] @@ -75,7 +75,8 @@ type NtxResult = Result; /// Provides the context for execution [network transaction candidates](TransactionCandidate). #[derive(Clone)] pub struct NtxContext { - block_producer: BlockProducerClient, + /// Client for submitting transactions to the network. + rpc_client: RpcClient, /// The prover to delegate proofs to. /// @@ -93,17 +94,12 @@ pub struct NtxContext { impl NtxContext { /// Creates a new [`NtxContext`] instance. pub fn new( - block_producer: BlockProducerClient, + rpc_client: RpcClient, prover: Option, store: StoreClient, script_cache: LruCache, ) -> Self { - Self { - block_producer, - prover, - store, - script_cache, - } + Self { rpc_client, prover, store, script_cache } } /// Executes a transaction end-to-end: filtering, executing, proving, and submitted to the block @@ -147,7 +143,7 @@ impl NtxContext { .set_attribute("reference_block.number", chain_tip_header.block_num()); async move { - async move { + Box::pin(async move { let data_store = NtxDataStore::new( account, chain_tip_header, @@ -157,13 +153,15 @@ impl NtxContext { ); let notes = notes.into_iter().map(Note::from).collect::>(); - let (successful, failed) = self.filter_notes(&data_store, notes).await?; - let executed = Box::pin(self.execute(&data_store, successful)).await?; - let proven = Box::pin(self.prove(executed.into())).await?; - let tx_id = proven.id(); - self.submit(proven).await?; - Ok((tx_id, failed)) - } + let (successful_notes, failed_notes) = + self.filter_notes(&data_store, notes).await?; + let executed_tx = Box::pin(self.execute(&data_store, successful_notes)).await?; + let tx_inputs: TransactionInputs = executed_tx.into(); + let proven_tx = Box::pin(self.prove(tx_inputs.clone())).await?; + let tx_id = proven_tx.id(); + self.submit(proven_tx, tx_inputs).await?; + Ok((tx_id, failed_notes)) + }) .in_current_span() .await .inspect_err(|err| tracing::Span::current().set_error(err)) @@ -256,11 +254,11 @@ impl NtxContext { .map_err(NtxError::Proving) } - /// Submits the transaction to the block producer. + /// Submits the transaction to the RPC server with transaction inputs. #[instrument(target = COMPONENT, name = "ntx.execute_transaction.submit", skip_all, err)] - async fn submit(&self, tx: ProvenTransaction) -> NtxResult<()> { - self.block_producer - .submit_proven_transaction(tx) + async fn submit(&self, tx: ProvenTransaction, tx_inputs: TransactionInputs) -> NtxResult<()> { + self.rpc_client + .submit_proven_transaction(tx, tx_inputs) .await .map_err(NtxError::Submission) } diff --git a/crates/ntx-builder/src/actor/mod.rs b/crates/ntx-builder/src/actor/mod.rs index 947890ede..d5a1ab794 100644 --- a/crates/ntx-builder/src/actor/mod.rs +++ b/crates/ntx-builder/src/actor/mod.rs @@ -22,8 +22,8 @@ use tokio::sync::{AcquireError, RwLock, Semaphore, mpsc}; use tokio_util::sync::CancellationToken; use url::Url; -use crate::block_producer::BlockProducerClient; use crate::builder::ChainState; +use crate::rpc::RpcClient; use crate::store::StoreClient; // ACTOR SHUTDOWN REASON @@ -52,8 +52,8 @@ pub enum ActorShutdownReason { pub struct AccountActorContext { /// Client for interacting with the store in order to load account state. pub store: StoreClient, - /// Address of the block producer gRPC server. - pub block_producer_url: Url, + /// Address of the RPC gRPC server. + pub rpc_url: Url, /// Address of the remote prover. If `None`, transactions will be proven locally, which is // undesirable due to the performance impact. pub tx_prover_url: Option, @@ -153,7 +153,7 @@ pub struct AccountActor { mode: ActorMode, event_rx: mpsc::Receiver>, cancel_token: CancellationToken, - block_producer: BlockProducerClient, + rpc_client: RpcClient, prover: Option, chain_state: Arc>, script_cache: LruCache, @@ -168,7 +168,7 @@ impl AccountActor { event_rx: mpsc::Receiver>, cancel_token: CancellationToken, ) -> Self { - let block_producer = BlockProducerClient::new(actor_context.block_producer_url.clone()); + let rpc_client = RpcClient::new(actor_context.rpc_url.clone()); let prover = actor_context.tx_prover_url.clone().map(RemoteTransactionProver::new); Self { origin, @@ -176,7 +176,7 @@ impl AccountActor { mode: ActorMode::NoViableNotes, event_rx, cancel_token, - block_producer, + rpc_client, prover, chain_state: actor_context.chain_state.clone(), script_cache: actor_context.script_cache.clone(), @@ -275,7 +275,7 @@ impl AccountActor { // Execute the selected transaction. let context = execute::NtxContext::new( - self.block_producer.clone(), + self.rpc_client.clone(), self.prover.clone(), self.store.clone(), self.script_cache.clone(), diff --git a/crates/ntx-builder/src/block_producer.rs b/crates/ntx-builder/src/block_producer.rs index b8926e1ec..2c85d5b51 100644 --- a/crates/ntx-builder/src/block_producer.rs +++ b/crates/ntx-builder/src/block_producer.rs @@ -6,8 +6,6 @@ use miden_node_proto::domain::mempool::MempoolEvent; use miden_node_proto::generated::{self as proto}; use miden_node_utils::FlattenResult; use miden_objects::block::BlockNumber; -use miden_objects::transaction::ProvenTransaction; -use miden_tx::utils::Serializable; use tokio_stream::StreamExt; use tonic::Status; use tracing::{info, instrument}; @@ -41,20 +39,6 @@ impl BlockProducerClient { Self { client: block_producer } } - #[instrument(target = COMPONENT, name = "ntx.block_producer.client.submit_proven_transaction", skip_all, err)] - pub async fn submit_proven_transaction( - &self, - proven_tx: ProvenTransaction, - ) -> Result<(), Status> { - let request = proto::transaction::ProvenTransaction { - transaction: proven_tx.to_bytes(), - transaction_inputs: None, - }; - - self.client.clone().submit_proven_transaction(request).await?; - - Ok(()) - } #[instrument(target = COMPONENT, name = "ntx.block_producer.client.subscribe_to_mempool", skip_all, err)] pub async fn subscribe_to_mempool_with_retry( diff --git a/crates/ntx-builder/src/builder.rs b/crates/ntx-builder/src/builder.rs index c74f2dacd..be80f8a18 100644 --- a/crates/ntx-builder/src/builder.rs +++ b/crates/ntx-builder/src/builder.rs @@ -73,6 +73,8 @@ pub struct NetworkTransactionBuilder { store_url: Url, /// Address of the block producer gRPC server. block_producer_url: Url, + /// Address of the RPC gRPC server. + rpc_url: Url, /// Address of the remote prover. If `None`, transactions will be proven locally, which is /// undesirable due to the performance impact. tx_prover_url: Option, @@ -101,6 +103,7 @@ impl NetworkTransactionBuilder { pub fn new( store_url: Url, block_producer_url: Url, + rpc_url: Url, tx_prover_url: Option, ticker_interval: Duration, bp_checkpoint: Arc, @@ -110,6 +113,7 @@ impl NetworkTransactionBuilder { Self { store_url, block_producer_url, + rpc_url, tx_prover_url, ticker_interval, bp_checkpoint, @@ -145,7 +149,7 @@ impl NetworkTransactionBuilder { let chain_state = Arc::new(RwLock::new(ChainState::new(chain_tip_header, chain_mmr))); let actor_context = AccountActorContext { - block_producer_url: self.block_producer_url.clone(), + rpc_url: self.rpc_url.clone(), tx_prover_url: self.tx_prover_url.clone(), chain_state: chain_state.clone(), store: store.clone(), diff --git a/crates/ntx-builder/src/lib.rs b/crates/ntx-builder/src/lib.rs index b0d89f94c..5b71ff060 100644 --- a/crates/ntx-builder/src/lib.rs +++ b/crates/ntx-builder/src/lib.rs @@ -4,6 +4,7 @@ mod actor; mod block_producer; mod builder; mod coordinator; +mod rpc; mod store; pub use builder::NetworkTransactionBuilder; From c3948e7dc32471c4af398e39c5ecf186c538482a Mon Sep 17 00:00:00 2001 From: sergerad Date: Mon, 15 Dec 2025 11:25:14 +1300 Subject: [PATCH 2/6] Missing file --- crates/ntx-builder/src/rpc.rs | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 crates/ntx-builder/src/rpc.rs diff --git a/crates/ntx-builder/src/rpc.rs b/crates/ntx-builder/src/rpc.rs new file mode 100644 index 000000000..6667d78ca --- /dev/null +++ b/crates/ntx-builder/src/rpc.rs @@ -0,0 +1,54 @@ +use miden_node_proto::clients::{Builder, RpcClient as InnerRpcClient}; +use miden_node_proto::generated::{self as proto}; +use miden_objects::transaction::{ProvenTransaction, TransactionInputs}; +use miden_tx::utils::Serializable; +use tonic::Status; +use tracing::{info, instrument}; +use url::Url; + +use crate::COMPONENT; + +// CLIENT +// ================================================================================================ + +/// Interface to the RPC server's gRPC API. +/// +/// Essentially just a thin wrapper around the generated gRPC client which improves type safety. +#[derive(Clone, Debug)] +pub struct RpcClient { + client: InnerRpcClient, +} + +impl RpcClient { + /// Creates a new RPC client with a lazy connection. + pub fn new(rpc_url: Url) -> Self { + info!(target: COMPONENT, rpc_endpoint = %rpc_url, "Initializing RPC client with lazy connection"); + + let rpc = Builder::new(rpc_url) + .without_tls() + .without_timeout() + .without_metadata_version() + .without_metadata_genesis() + .with_otel_context_injection() + .connect_lazy::(); + + Self { client: rpc } + } + + /// Submits a proven transaction with transaction inputs to the RPC server. + #[instrument(target = COMPONENT, name = "ntx.rpc.client.submit_proven_transaction", skip_all, err)] + pub async fn submit_proven_transaction( + &self, + proven_tx: ProvenTransaction, + tx_inputs: TransactionInputs, + ) -> Result<(), Status> { + let request = proto::transaction::ProvenTransaction { + transaction: proven_tx.to_bytes(), + transaction_inputs: Some(tx_inputs.to_bytes()), + }; + + self.client.clone().submit_proven_transaction(request).await?; + + Ok(()) + } +} From 2337bfc855d24fb3987877a94b77bd285b2ea318 Mon Sep 17 00:00:00 2001 From: sergerad Date: Mon, 15 Dec 2025 11:28:13 +1300 Subject: [PATCH 3/6] Changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9df3c1b3..6b5152792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Added chain tip to the block producer status ([#1419](https://github.com/0xMiden/miden-node/pull/1419)). - The mempool's transaction capacity is now configurable ([#1433](https://github.com/0xMiden/miden-node/pull/1433)). - Renamed card's names in the `miden-network-monitor` binary ([#1441](https://github.com/0xMiden/miden-node/pull/1441)). +- Integrated NTX Builder with validator via `SubmitProvenTransaction` RPC ([#1453](https://github.com/0xMiden/miden-node/pull/1453)). ### Changes From 11045cc46c522c117468ab63279f3616c25d9b8f Mon Sep 17 00:00:00 2001 From: sergerad Date: Mon, 15 Dec 2025 11:33:17 +1300 Subject: [PATCH 4/6] Comment --- crates/ntx-builder/src/rpc.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/crates/ntx-builder/src/rpc.rs b/crates/ntx-builder/src/rpc.rs index 6667d78ca..7baa3dc2f 100644 --- a/crates/ntx-builder/src/rpc.rs +++ b/crates/ntx-builder/src/rpc.rs @@ -8,12 +8,10 @@ use url::Url; use crate::COMPONENT; -// CLIENT +// RPC CLIENT // ================================================================================================ /// Interface to the RPC server's gRPC API. -/// -/// Essentially just a thin wrapper around the generated gRPC client which improves type safety. #[derive(Clone, Debug)] pub struct RpcClient { client: InnerRpcClient, From 5e16311b46300c9fedd6a8cbbecc74ecae1dd1cd Mon Sep 17 00:00:00 2001 From: sergerad Date: Tue, 6 Jan 2026 14:14:59 +1300 Subject: [PATCH 5/6] Replace rpc submission with validator --- bin/node/src/commands/bundled.rs | 4 +- crates/ntx-builder/src/actor/execute.rs | 37 ++++++++++++------ crates/ntx-builder/src/actor/mod.rs | 20 ++++++---- crates/ntx-builder/src/builder.rs | 10 ++--- crates/ntx-builder/src/lib.rs | 1 - crates/ntx-builder/src/rpc.rs | 52 ------------------------- 6 files changed, 46 insertions(+), 78 deletions(-) delete mode 100644 crates/ntx-builder/src/rpc.rs diff --git a/bin/node/src/commands/bundled.rs b/bin/node/src/commands/bundled.rs index 7e669eb02..67db7cd7f 100644 --- a/bin/node/src/commands/bundled.rs +++ b/bin/node/src/commands/bundled.rs @@ -311,6 +311,8 @@ impl BundledCommand { .context("Failed to parse URL")?; if should_start_ntx_builder { + let validator_url = Url::parse(&format!("http://{validator_address}")) + .context("Failed to parse URL")?; let id = join_set .spawn(async move { let block_producer_url = @@ -319,7 +321,7 @@ impl BundledCommand { NetworkTransactionBuilder::new( store_ntx_builder_url, block_producer_url, - rpc_url, + validator_url, ntx_builder.tx_prover_url, ntx_builder.ticker_interval, checkpoint, diff --git a/crates/ntx-builder/src/actor/execute.rs b/crates/ntx-builder/src/actor/execute.rs index 2285296b2..a2e183046 100644 --- a/crates/ntx-builder/src/actor/execute.rs +++ b/crates/ntx-builder/src/actor/execute.rs @@ -1,5 +1,7 @@ use std::collections::BTreeSet; +use miden_node_proto::clients::ValidatorClient; +use miden_node_proto::generated::{self as proto}; use miden_node_utils::lru_cache::LruCache; use miden_node_utils::tracing::OpenTelemetrySpanExt; use miden_protocol::account::{ @@ -27,6 +29,7 @@ use miden_protocol::vm::FutureMaybeSend; use miden_protocol::{TransactionInputError, Word}; use miden_remote_prover_client::remote_prover::tx_prover::RemoteTransactionProver; use miden_tx::auth::UnreachableAuth; +use miden_tx::utils::Serializable; use miden_tx::{ DataStore, DataStoreError, @@ -46,7 +49,6 @@ use tracing::{Instrument, instrument}; use crate::COMPONENT; use crate::actor::account_state::TransactionCandidate; -use crate::rpc::RpcClient; use crate::store::StoreClient; #[derive(Debug, thiserror::Error)] @@ -75,8 +77,8 @@ type NtxResult = Result; /// Provides the context for execution [network transaction candidates](TransactionCandidate). #[derive(Clone)] pub struct NtxContext { - /// Client for submitting transactions to the network. - rpc_client: RpcClient, + /// Client for validating transactions via the Validator. + validator_client: ValidatorClient, /// The prover to delegate proofs to. /// @@ -94,12 +96,17 @@ pub struct NtxContext { impl NtxContext { /// Creates a new [`NtxContext`] instance. pub fn new( - rpc_client: RpcClient, + validator_client: ValidatorClient, prover: Option, store: StoreClient, script_cache: LruCache, ) -> Self { - Self { rpc_client, prover, store, script_cache } + Self { + validator_client, + prover, + store, + script_cache, + } } /// Executes a transaction end-to-end: filtering, executing, proving, and submitted to the block @@ -159,7 +166,7 @@ impl NtxContext { let tx_inputs: TransactionInputs = executed_tx.into(); let proven_tx = Box::pin(self.prove(tx_inputs.clone())).await?; let tx_id = proven_tx.id(); - self.submit(proven_tx, tx_inputs).await?; + self.validate(proven_tx, tx_inputs).await?; Ok((tx_id, failed_notes)) }) .in_current_span() @@ -254,13 +261,19 @@ impl NtxContext { .map_err(NtxError::Proving) } - /// Submits the transaction to the RPC server with transaction inputs. - #[instrument(target = COMPONENT, name = "ntx.execute_transaction.submit", skip_all, err)] - async fn submit(&self, tx: ProvenTransaction, tx_inputs: TransactionInputs) -> NtxResult<()> { - self.rpc_client - .submit_proven_transaction(tx, tx_inputs) + /// Validates the transaction against the Validator. + #[instrument(target = COMPONENT, name = "ntx.execute_transaction.validate", skip_all, err)] + async fn validate(&self, tx: ProvenTransaction, tx_inputs: TransactionInputs) -> NtxResult<()> { + let request = proto::transaction::ProvenTransaction { + transaction: tx.to_bytes(), + transaction_inputs: Some(tx_inputs.to_bytes()), + }; + self.validator_client + .clone() + .submit_proven_transaction(request) .await - .map_err(NtxError::Submission) + .map_err(NtxError::Submission)?; + Ok(()) } } diff --git a/crates/ntx-builder/src/actor/mod.rs b/crates/ntx-builder/src/actor/mod.rs index f79758f45..374e217fd 100644 --- a/crates/ntx-builder/src/actor/mod.rs +++ b/crates/ntx-builder/src/actor/mod.rs @@ -8,6 +8,7 @@ use std::sync::Arc; use account_state::{NetworkAccountState, TransactionCandidate}; use execute::NtxError; use futures::FutureExt; +use miden_node_proto::clients::{Builder, ValidatorClient}; use miden_node_proto::domain::account::NetworkAccountPrefix; use miden_node_proto::domain::mempool::MempoolEvent; use miden_node_utils::ErrorReport; @@ -23,7 +24,6 @@ use tokio_util::sync::CancellationToken; use url::Url; use crate::builder::ChainState; -use crate::rpc::RpcClient; use crate::store::StoreClient; // ACTOR SHUTDOWN REASON @@ -52,8 +52,8 @@ pub enum ActorShutdownReason { pub struct AccountActorContext { /// Client for interacting with the store in order to load account state. pub store: StoreClient, - /// Address of the RPC gRPC server. - pub rpc_url: Url, + /// Address of the Validator server. + pub validator_url: Url, /// Address of the remote prover. If `None`, transactions will be proven locally, which is // undesirable due to the performance impact. pub tx_prover_url: Option, @@ -153,7 +153,7 @@ pub struct AccountActor { mode: ActorMode, event_rx: mpsc::Receiver>, cancel_token: CancellationToken, - rpc_client: RpcClient, + validator_client: ValidatorClient, prover: Option, chain_state: Arc>, script_cache: LruCache, @@ -168,7 +168,13 @@ impl AccountActor { event_rx: mpsc::Receiver>, cancel_token: CancellationToken, ) -> Self { - let rpc_client = RpcClient::new(actor_context.rpc_url.clone()); + let validator_client = Builder::new(actor_context.validator_url.clone()) + .without_tls() + .without_timeout() + .without_metadata_version() + .without_metadata_genesis() + .with_otel_context_injection() + .connect_lazy::(); let prover = actor_context.tx_prover_url.clone().map(RemoteTransactionProver::new); Self { origin, @@ -176,7 +182,7 @@ impl AccountActor { mode: ActorMode::NoViableNotes, event_rx, cancel_token, - rpc_client, + validator_client, prover, chain_state: actor_context.chain_state.clone(), script_cache: actor_context.script_cache.clone(), @@ -275,7 +281,7 @@ impl AccountActor { // Execute the selected transaction. let context = execute::NtxContext::new( - self.rpc_client.clone(), + self.validator_client.clone(), self.prover.clone(), self.store.clone(), self.script_cache.clone(), diff --git a/crates/ntx-builder/src/builder.rs b/crates/ntx-builder/src/builder.rs index 32db8b60f..79146e11f 100644 --- a/crates/ntx-builder/src/builder.rs +++ b/crates/ntx-builder/src/builder.rs @@ -73,8 +73,8 @@ pub struct NetworkTransactionBuilder { store_url: Url, /// Address of the block producer gRPC server. block_producer_url: Url, - /// Address of the RPC gRPC server. - rpc_url: Url, + /// Address of the Validator server. + validator_url: Url, /// Address of the remote prover. If `None`, transactions will be proven locally, which is /// undesirable due to the performance impact. tx_prover_url: Option, @@ -103,7 +103,7 @@ impl NetworkTransactionBuilder { pub fn new( store_url: Url, block_producer_url: Url, - rpc_url: Url, + validator_url: Url, tx_prover_url: Option, ticker_interval: Duration, bp_checkpoint: Arc, @@ -113,7 +113,7 @@ impl NetworkTransactionBuilder { Self { store_url, block_producer_url, - rpc_url, + validator_url, tx_prover_url, ticker_interval, bp_checkpoint, @@ -149,7 +149,7 @@ impl NetworkTransactionBuilder { let chain_state = Arc::new(RwLock::new(ChainState::new(chain_tip_header, chain_mmr))); let actor_context = AccountActorContext { - rpc_url: self.rpc_url.clone(), + validator_url: self.validator_url.clone(), tx_prover_url: self.tx_prover_url.clone(), chain_state: chain_state.clone(), store: store.clone(), diff --git a/crates/ntx-builder/src/lib.rs b/crates/ntx-builder/src/lib.rs index 5b71ff060..b0d89f94c 100644 --- a/crates/ntx-builder/src/lib.rs +++ b/crates/ntx-builder/src/lib.rs @@ -4,7 +4,6 @@ mod actor; mod block_producer; mod builder; mod coordinator; -mod rpc; mod store; pub use builder::NetworkTransactionBuilder; diff --git a/crates/ntx-builder/src/rpc.rs b/crates/ntx-builder/src/rpc.rs deleted file mode 100644 index 46916a199..000000000 --- a/crates/ntx-builder/src/rpc.rs +++ /dev/null @@ -1,52 +0,0 @@ -use miden_node_proto::clients::{Builder, RpcClient as InnerRpcClient}; -use miden_node_proto::generated::{self as proto}; -use miden_protocol::transaction::{ProvenTransaction, TransactionInputs}; -use miden_tx::utils::Serializable; -use tonic::Status; -use tracing::{info, instrument}; -use url::Url; - -use crate::COMPONENT; - -// RPC CLIENT -// ================================================================================================ - -/// Interface to the RPC server's gRPC API. -#[derive(Clone, Debug)] -pub struct RpcClient { - client: InnerRpcClient, -} - -impl RpcClient { - /// Creates a new RPC client with a lazy connection. - pub fn new(rpc_url: Url) -> Self { - info!(target: COMPONENT, rpc_endpoint = %rpc_url, "Initializing RPC client with lazy connection"); - - let rpc = Builder::new(rpc_url) - .without_tls() - .without_timeout() - .without_metadata_version() - .without_metadata_genesis() - .with_otel_context_injection() - .connect_lazy::(); - - Self { client: rpc } - } - - /// Submits a proven transaction with transaction inputs to the RPC server. - #[instrument(target = COMPONENT, name = "ntx.rpc.client.submit_proven_transaction", skip_all, err)] - pub async fn submit_proven_transaction( - &self, - proven_tx: ProvenTransaction, - tx_inputs: TransactionInputs, - ) -> Result<(), Status> { - let request = proto::transaction::ProvenTransaction { - transaction: proven_tx.to_bytes(), - transaction_inputs: Some(tx_inputs.to_bytes()), - }; - - self.client.clone().submit_proven_transaction(request).await?; - - Ok(()) - } -} From 8efd76f49e5197f87e80ccc99046c5ba4a3f9870 Mon Sep 17 00:00:00 2001 From: sergerad Date: Tue, 6 Jan 2026 14:18:53 +1300 Subject: [PATCH 6/6] Comments --- crates/ntx-builder/src/actor/execute.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/ntx-builder/src/actor/execute.rs b/crates/ntx-builder/src/actor/execute.rs index a2e183046..90a3698b2 100644 --- a/crates/ntx-builder/src/actor/execute.rs +++ b/crates/ntx-builder/src/actor/execute.rs @@ -159,14 +159,22 @@ impl NtxContext { self.script_cache.clone(), ); + // Filter notes. let notes = notes.into_iter().map(Note::from).collect::>(); let (successful_notes, failed_notes) = self.filter_notes(&data_store, notes).await?; + + // Execute transaction. let executed_tx = Box::pin(self.execute(&data_store, successful_notes)).await?; + + // Prove transaction. let tx_inputs: TransactionInputs = executed_tx.into(); let proven_tx = Box::pin(self.prove(tx_inputs.clone())).await?; let tx_id = proven_tx.id(); + + // Validate proven transaction. self.validate(proven_tx, tx_inputs).await?; + Ok((tx_id, failed_notes)) }) .in_current_span()