Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 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 @@ -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 RPC stack with Validator component for transaction validation ([#1457](https://github.com/0xMiden/miden-node/pull/1457)).

### Changes

Expand Down
16 changes: 9 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions bin/network-monitor/src/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::sync::atomic::{AtomicU64, Ordering};
use anyhow::{Context, Result};
use miden_lib::AuthScheme;
use miden_lib::account::interface::AccountInterface;
use miden_lib::utils::ScriptBuilder;
use miden_lib::utils::CodeBuilder;
use miden_node_proto::clients::RpcClient;
use miden_node_proto::generated::rpc::BlockHeaderByNumberRequest;
use miden_node_proto::generated::transaction::ProvenTransaction;
Expand Down Expand Up @@ -528,7 +528,7 @@ async fn create_and_submit_network_note(
fn create_increment_script() -> Result<(NoteScript, Library)> {
let library = get_counter_library()?;

let script_builder = ScriptBuilder::new(true)
let script_builder = CodeBuilder::new(true)
.with_dynamically_linked_library(&library)
.context("Failed to create script builder with library")?;

Expand Down
13 changes: 6 additions & 7 deletions bin/network-monitor/src/deploy/counter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::path::Path;

use anyhow::Result;
use miden_lib::testing::account_component::IncrNonceAuthComponent;
use miden_lib::transaction::TransactionKernel;
use miden_lib::utils::CodeBuilder;
use miden_objects::account::{
Account,
AccountBuilder,
Expand Down Expand Up @@ -50,12 +50,11 @@ pub fn create_counter_account(owner_account_id: AccountId) -> Result<Account> {

let counter_slot = StorageSlot::with_value(COUNTER_SLOT_NAME.clone(), Word::empty());

let account_code = AccountComponent::compile(
script,
TransactionKernel::assembler(),
vec![counter_slot, owner_id_slot],
)?
.with_supports_all_types();
let component_code =
CodeBuilder::default().compile_component_code("counter::program", script)?;

let account_code = AccountComponent::new(component_code, vec![counter_slot, owner_id_slot])?
.with_supports_all_types();

let incr_nonce_auth: AccountComponent = IncrNonceAuthComponent.into();

Expand Down
3 changes: 3 additions & 0 deletions bin/node/src/commands/bundled.rs
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,13 @@ impl BundledCommand {
.context("Failed to parse URL")?;
let block_producer_url = Url::parse(&format!("http://{block_producer_address}"))
.context("Failed to parse URL")?;
let validator_url = Url::parse(&format!("http://{validator_address}"))
.context("Failed to parse URL")?;
Rpc {
listener: grpc_rpc,
store_url,
block_producer_url: Some(block_producer_url),
validator_url,
grpc_timeout,
}
.serve()
Expand Down
8 changes: 7 additions & 1 deletion bin/node/src/commands/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use miden_node_rpc::Rpc;
use miden_node_utils::grpc::UrlExt;
use url::Url;

use super::{ENV_BLOCK_PRODUCER_URL, ENV_RPC_URL, ENV_STORE_RPC_URL};
use super::{ENV_BLOCK_PRODUCER_URL, ENV_RPC_URL, ENV_STORE_RPC_URL, ENV_VALIDATOR_URL};
use crate::commands::{DEFAULT_TIMEOUT, ENV_ENABLE_OTEL, duration_to_human_readable_string};

#[derive(clap::Subcommand)]
Expand All @@ -25,6 +25,10 @@ pub enum RpcCommand {
#[arg(long = "block-producer.url", env = ENV_BLOCK_PRODUCER_URL, value_name = "URL")]
block_producer_url: Option<Url>,

/// The validator's gRPC url.
#[arg(long = "validator.url", env = ENV_VALIDATOR_URL, value_name = "URL")]
validator_url: Url,

/// Enables the exporting of traces for OpenTelemetry.
///
/// This can be further configured using environment variables as defined in the official
Expand All @@ -51,6 +55,7 @@ impl RpcCommand {
url,
store_url,
block_producer_url,
validator_url,
enable_otel: _,
grpc_timeout,
} = self;
Expand All @@ -64,6 +69,7 @@ impl RpcCommand {
listener,
store_url,
block_producer_url,
validator_url,
grpc_timeout,
}
.serve()
Expand Down
8 changes: 3 additions & 5 deletions bin/stress-test/src/seeding/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,13 +443,11 @@ fn create_emit_note_tx(
) -> ProvenTransaction {
let initial_account_hash = faucet.commitment();

let slot = faucet.storage().get_item(BasicFungibleFaucet::metadata_slot_name()).unwrap();
let metadata_slot_name = AccountStorage::faucet_sysdata_slot();
let slot = faucet.storage().get_item(metadata_slot_name).unwrap();
faucet
.storage_mut()
.set_item(
AccountStorage::faucet_metadata_slot(),
[slot[0], slot[1], slot[2], slot[3] + Felt::new(10)].into(),
)
.set_item(metadata_slot_name, [slot[0], slot[1], slot[2], slot[3] + Felt::new(10)].into())
.unwrap();

faucet.increment_nonce(ONE).unwrap();
Expand Down
20 changes: 10 additions & 10 deletions crates/proto/src/domain/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ use miden_objects::account::{
AccountId,
AccountStorageHeader,
StorageMap,
StorageSlotHeader,
StorageSlotName,
StorageSlotType,
};
use miden_objects::asset::{Asset, AssetVault};
use miden_objects::block::{AccountWitness, BlockNumber};
use miden_objects::block::BlockNumber;
use miden_objects::block::account_tree::AccountWitness;
use miden_objects::crypto::merkle::SparseMerklePath;
use miden_objects::note::{NoteExecutionMode, NoteTag};
use miden_objects::utils::{Deserializable, DeserializationError, Serializable};
Expand Down Expand Up @@ -167,18 +169,18 @@ impl TryFrom<proto::account::AccountStorageHeader> for AccountStorageHeader {
fn try_from(value: proto::account::AccountStorageHeader) -> Result<Self, Self::Error> {
let proto::account::AccountStorageHeader { slots } = value;

let items = slots
let slot_headers = slots
.into_iter()
.map(|slot| {
let slot_name = StorageSlotName::new(slot.slot_name)?;
let slot_type = storage_slot_type_from_raw(slot.slot_type)?;
let commitment =
slot.commitment.ok_or(ConversionError::NotAValidFelt)?.try_into()?;
Ok((slot_name, slot_type, commitment))
Ok(StorageSlotHeader::new(slot_name, slot_type, commitment))
})
.collect::<Result<Vec<_>, ConversionError>>()?;

Ok(AccountStorageHeader::new(items)?)
Ok(AccountStorageHeader::new(slot_headers)?)
}
}

Expand Down Expand Up @@ -333,12 +335,10 @@ impl From<AccountStorageHeader> for proto::account::AccountStorageHeader {
fn from(value: AccountStorageHeader) -> Self {
let slots = value
.slots()
.map(|(slot_name, slot_type, slot_value)| {
proto::account::account_storage_header::StorageSlot {
slot_name: slot_name.to_string(),
slot_type: storage_slot_type_to_raw(*slot_type),
commitment: Some(proto::primitives::Digest::from(*slot_value)),
}
.map(|slot_header| proto::account::account_storage_header::StorageSlot {
slot_name: slot_header.name().to_string(),
slot_type: storage_slot_type_to_raw(slot_header.slot_type()),
commitment: Some(proto::primitives::Digest::from(slot_header.value())),
})
.collect();

Expand Down
9 changes: 2 additions & 7 deletions crates/proto/src/domain/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@ use std::collections::BTreeMap;
use std::ops::RangeInclusive;

use miden_objects::account::AccountId;
use miden_objects::block::{
BlockHeader,
BlockInputs,
BlockNumber,
FeeParameters,
NullifierWitness,
};
use miden_objects::block::nullifier_tree::NullifierWitness;
use miden_objects::block::{BlockHeader, BlockInputs, BlockNumber, FeeParameters};
use miden_objects::crypto::dsa::ecdsa_k256_keccak::{PublicKey, Signature};
use miden_objects::note::{NoteId, NoteInclusionProof};
use miden_objects::transaction::PartialBlockchain;
Expand Down
45 changes: 26 additions & 19 deletions crates/rpc/src/server/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::sync::Arc;
use std::time::Duration;

use anyhow::Context;
use miden_node_proto::clients::{BlockProducerClient, Builder, StoreRpcClient};
use miden_node_proto::clients::{BlockProducerClient, Builder, StoreRpcClient, ValidatorClient};
use miden_node_proto::errors::ConversionError;
use miden_node_proto::generated::rpc::MempoolStats;
use miden_node_proto::generated::rpc::api_server::{self, Api};
Expand All @@ -20,12 +20,7 @@ use miden_objects::account::AccountId;
use miden_objects::batch::ProvenBatch;
use miden_objects::block::{BlockHeader, BlockNumber};
use miden_objects::note::{Note, NoteRecipient, NoteScript};
use miden_objects::transaction::{
OutputNote,
ProvenTransaction,
ProvenTransactionBuilder,
TransactionInputs,
};
use miden_objects::transaction::{OutputNote, ProvenTransaction, ProvenTransactionBuilder};
use miden_objects::utils::serde::{Deserializable, Serializable};
use miden_objects::{MIN_PROOF_SECURITY_LEVEL, Word};
use miden_tx::TransactionVerifier;
Expand All @@ -34,19 +29,19 @@ use tracing::{debug, info, instrument, warn};
use url::Url;

use crate::COMPONENT;
use crate::server::validator;

// RPC SERVICE
// ================================================================================================

pub struct RpcService {
store: StoreRpcClient,
block_producer: Option<BlockProducerClient>,
validator: ValidatorClient,
genesis_commitment: Option<Word>,
}

impl RpcService {
pub(super) fn new(store_url: Url, block_producer_url: Option<Url>) -> Self {
pub(super) fn new(store_url: Url, block_producer_url: Option<Url>, validator_url: Url) -> Self {
let store = {
info!(target: COMPONENT, store_endpoint = %store_url, "Initializing store client");
Builder::new(store_url)
Expand All @@ -73,9 +68,25 @@ impl RpcService {
.connect_lazy::<BlockProducerClient>()
});

let validator = {
info!(
target: COMPONENT,
validator_endpoint = %validator_url,
"Initializing validator client",
);
Builder::new(validator_url)
.without_tls()
.without_timeout()
.without_metadata_version()
.without_metadata_genesis()
.with_otel_context_injection()
.connect_lazy::<ValidatorClient>()
};

Self {
store,
block_producer,
validator,
genesis_commitment: None,
}
}
Expand Down Expand Up @@ -379,26 +390,22 @@ impl api_server::Api for RpcService {
})?;

// If transaction inputs are provided, re-execute the transaction to validate it.
if let Some(tx_inputs_bytes) = &request.transaction_inputs {
// Deserialize the transaction inputs.
let tx_inputs = TransactionInputs::read_from_bytes(tx_inputs_bytes).map_err(|err| {
Status::invalid_argument(err.as_report_context("Invalid transaction inputs"))
})?;
// Re-execute the transaction.
match validator::re_execute_transaction(tx_inputs).await {
Ok(_executed_tx) => {
if request.transaction_inputs.is_some() {
// Re-execute the transaction via the Validator.
match self.validator.clone().submit_proven_transaction(request.clone()).await {
Ok(_) => {
debug!(
target = COMPONENT,
tx_id = %tx.id().to_hex(),
"Transaction re-execution successful"
"Transaction validation successful"
);
},
Err(e) => {
warn!(
target = COMPONENT,
tx_id = %tx.id().to_hex(),
error = %e,
"Transaction re-execution failed, but continuing with submission"
"Transaction validation failed, but continuing with submission"
);
},
}
Expand Down
10 changes: 7 additions & 3 deletions crates/rpc/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ use crate::server::health::HealthCheckLayer;
mod accept;
mod api;
mod health;
mod validator;

/// The RPC server component.
///
/// On startup, binds to the provided listener and starts serving the RPC API.
/// It connects lazily to the store and block producer components as needed.
/// It connects lazily to the store, validator and block producer components as needed.
/// Requests will fail if the components are not available.
pub struct Rpc {
pub listener: TcpListener,
pub store_url: Url,
pub block_producer_url: Option<Url>,
pub validator_url: Url,
/// Server-side timeout for an individual gRPC request.
///
/// If the handler takes longer than this duration, the server cancels the call.
Expand All @@ -44,7 +44,11 @@ impl Rpc {
/// Note: Executes in place (i.e. not spawned) and will run indefinitely until
/// a fatal error is encountered.
pub async fn serve(self) -> anyhow::Result<()> {
let mut api = api::RpcService::new(self.store_url.clone(), self.block_producer_url.clone());
let mut api = api::RpcService::new(
self.store_url.clone(),
self.block_producer_url.clone(),
self.validator_url,
);

let genesis = api
.get_genesis_header_with_retry()
Expand Down
Loading