Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -16,6 +16,7 @@
- Fixed `TransactionHeader` serialization for row insertion on database & fixed transaction cursor on retrievals ([#1701](https://github.com/0xMiden/node/issues/1701)).
- Added KMS signing support in validator ([#1677](https://github.com/0xMiden/node/pull/1677)).
- Added per-IP gRPC rate limiting across services as well as global concurrent connection limit ([#1746](https://github.com/0xMiden/node/issues/1746)).
- Network transaction actors now share the same gRPC clients, limiting the number of file descriptors being used ([#1806](https://github.com/0xMiden/node/issues/1806)).

### Changes

Expand Down
15 changes: 3 additions & 12 deletions crates/ntx-builder/src/actor/execute.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::collections::{BTreeMap, BTreeSet};
use std::sync::Arc;

use miden_node_proto::clients::ValidatorClient;
use miden_node_proto::generated::{self as proto};
use miden_node_utils::ErrorReport;
use miden_node_utils::lru_cache::LruCache;
use miden_node_utils::tracing::OpenTelemetrySpanExt;
Expand Down Expand Up @@ -35,7 +33,6 @@ use miden_protocol::transaction::{
use miden_protocol::vm::FutureMaybeSend;
use miden_remote_prover_client::RemoteTransactionProver;
use miden_tx::auth::UnreachableAuth;
use miden_tx::utils::Serializable;
use miden_tx::{
DataStore,
DataStoreError,
Expand All @@ -56,7 +53,7 @@ use tracing::{Instrument, instrument};

use crate::COMPONENT;
use crate::actor::candidate::TransactionCandidate;
use crate::clients::{BlockProducerClient, StoreClient};
use crate::clients::{BlockProducerClient, StoreClient, ValidatorClient};
use crate::db::Db;

#[derive(Debug, thiserror::Error)]
Expand Down Expand Up @@ -327,16 +324,10 @@ impl NtxContext {
proven_tx: &ProvenTransaction,
tx_inputs: &TransactionInputs,
) -> NtxResult<()> {
let request = proto::transaction::ProvenTransaction {
transaction: proven_tx.to_bytes(),
transaction_inputs: Some(tx_inputs.to_bytes()),
};
self.validator
.clone()
.submit_proven_transaction(request)
.submit_proven_transaction(proven_tx, tx_inputs)
.await
.map_err(NtxError::Submission)?;
Ok(())
.map_err(NtxError::Submission)
}
}

Expand Down
39 changes: 14 additions & 25 deletions crates/ntx-builder/src/actor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use std::time::Duration;
use anyhow::Context;
use candidate::TransactionCandidate;
use futures::FutureExt;
use miden_node_proto::clients::{Builder, ValidatorClient};
use miden_node_proto::domain::account::NetworkAccountId;
use miden_node_utils::ErrorReport;
use miden_node_utils::lru_cache::LruCache;
Expand All @@ -21,11 +20,10 @@ use miden_remote_prover_client::RemoteTransactionProver;
use miden_tx::FailedNote;
use tokio::sync::{Notify, RwLock, Semaphore, mpsc};
use tokio_util::sync::CancellationToken;
use url::Url;

use crate::NoteError;
use crate::chain_state::ChainState;
use crate::clients::{BlockProducerClient, StoreClient};
use crate::clients::{BlockProducerClient, StoreClient, ValidatorClient};
use crate::db::Db;

// ACTOR REQUESTS
Expand Down Expand Up @@ -54,13 +52,13 @@ pub enum ActorRequest {
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 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<Url>,
/// Client for interacting with the block producer.
pub block_producer: BlockProducerClient,
/// Client for interacting with the validator.
pub validator: ValidatorClient,
/// Client for remote transaction proving. If `None`, transactions will be proven locally,
/// which is undesirable due to the performance impact.
pub prover: Option<RemoteTransactionProver>,
/// The latest chain state that account all actors can rely on. A single chain state is shared
/// among all actors.
pub chain_state: Arc<RwLock<ChainState>>,
Expand Down Expand Up @@ -101,9 +99,9 @@ impl AccountActorContext {
let (request_tx, _request_rx) = mpsc::channel(1);

Self {
block_producer_url: url.clone(),
validator_url: url.clone(),
tx_prover_url: None,
block_producer: BlockProducerClient::new(url.clone()),
validator: ValidatorClient::new(url.clone()),
prover: None,
chain_state,
store: StoreClient::new(url),
script_cache: LruCache::new(NonZeroUsize::new(1).unwrap()),
Expand Down Expand Up @@ -229,25 +227,16 @@ impl AccountActor {
notify: Arc<Notify>,
cancel_token: CancellationToken,
) -> Self {
let block_producer = BlockProducerClient::new(actor_context.block_producer_url.clone());
let validator = Builder::new(actor_context.validator_url.clone())
.without_tls()
.with_timeout(Duration::from_secs(10))
.without_metadata_version()
.without_metadata_genesis()
.with_otel_context_injection()
.connect_lazy::<ValidatorClient>();
let prover = actor_context.tx_prover_url.clone().map(RemoteTransactionProver::new);
Self {
origin,
store: actor_context.store.clone(),
db: actor_context.db.clone(),
mode: ActorMode::NoViableNotes,
notify,
cancel_token,
block_producer,
validator,
prover,
block_producer: actor_context.block_producer.clone(),
validator: actor_context.validator.clone(),
prover: actor_context.prover.clone(),
chain_state: actor_context.chain_state.clone(),
script_cache: actor_context.script_cache.clone(),
max_notes_per_tx: actor_context.max_notes_per_tx,
Expand Down
2 changes: 2 additions & 0 deletions crates/ntx-builder/src/clients/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
mod block_producer;
mod store;
mod validator;

pub use block_producer::BlockProducerClient;
pub use store::StoreClient;
pub use validator::ValidatorClient;
56 changes: 56 additions & 0 deletions crates/ntx-builder/src/clients/validator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
use std::time::Duration;

use miden_node_proto::clients::{Builder, ValidatorClient as InnerValidatorClient};
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;

// CLIENT
// ================================================================================================

/// Interface to the validator's gRPC API.
///
/// Thin wrapper around the generated gRPC client which encapsulates the connection
/// configuration and improves type safety. Cloning this client shares the underlying
/// gRPC channel.
#[derive(Clone, Debug)]
pub struct ValidatorClient {
client: InnerValidatorClient,
}

impl ValidatorClient {
/// Creates a new validator client with a lazy connection and a 10-second timeout.
pub fn new(validator_url: Url) -> Self {
info!(target: COMPONENT, validator_endpoint = %validator_url, "Initializing validator client with lazy connection");

let validator = Builder::new(validator_url)
.without_tls()
.with_timeout(Duration::from_secs(10))
.without_metadata_version()
.without_metadata_genesis()
.with_otel_context_injection()
.connect_lazy::<InnerValidatorClient>();

Self { client: validator }
}

/// Submits a proven transaction with its inputs to the validator for re-execution.
#[instrument(target = COMPONENT, name = "ntx.validator.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(())
}
}
11 changes: 7 additions & 4 deletions crates/ntx-builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ use actor::AccountActorContext;
use anyhow::Context;
use builder::MempoolEventStream;
use chain_state::ChainState;
use clients::{BlockProducerClient, StoreClient};
use clients::{BlockProducerClient, StoreClient, ValidatorClient};
use coordinator::Coordinator;
use db::Db;
use futures::TryStreamExt;
use miden_node_utils::ErrorReport;
use miden_node_utils::lru_cache::LruCache;
use miden_remote_prover_client::RemoteTransactionProver;
use tokio::sync::{RwLock, mpsc};
use url::Url;

Expand Down Expand Up @@ -247,6 +248,8 @@ impl NtxBuilderConfig {

let store = StoreClient::new(self.store_url.clone());
let block_producer = BlockProducerClient::new(self.block_producer_url.clone());
let validator = ValidatorClient::new(self.validator_url.clone());
let prover = self.tx_prover_url.clone().map(RemoteTransactionProver::new);

// Subscribe to mempool first to ensure we don't miss any events. The subscription
// replays all inflight transactions, so the subscriber's state is fully reconstructed.
Expand All @@ -272,9 +275,9 @@ impl NtxBuilderConfig {
let (request_tx, actor_request_rx) = mpsc::channel(1);

let actor_context = AccountActorContext {
block_producer_url: self.block_producer_url.clone(),
validator_url: self.validator_url.clone(),
tx_prover_url: self.tx_prover_url.clone(),
block_producer: block_producer.clone(),
validator,
prover,
chain_state: chain_state.clone(),
store: store.clone(),
script_cache,
Expand Down
Loading