miden_node_validator/server/
mod.rs

1use std::net::SocketAddr;
2use std::time::Duration;
3
4use anyhow::Context;
5use miden_node_proto::generated::validator::api_server;
6use miden_node_proto::generated::{self as proto};
7use miden_node_proto_build::validator_api_descriptor;
8use miden_node_utils::panic::catch_panic_layer_fn;
9use miden_node_utils::tracing::grpc::grpc_trace_fn;
10use tokio::net::TcpListener;
11use tokio_stream::wrappers::TcpListenerStream;
12use tower_http::catch_panic::CatchPanicLayer;
13use tower_http::trace::TraceLayer;
14
15use crate::COMPONENT;
16
17// VALIDATOR
18// ================================================================================
19
20/// The handle into running the gRPC validator server.
21///
22/// Facilitates the running of the gRPC server which implements the validator API.
23pub struct Validator {
24    /// The address of the validator component.
25    pub address: SocketAddr,
26    /// Server-side timeout for an individual gRPC request.
27    ///
28    /// If the handler takes longer than this duration, the server cancels the call.
29    pub grpc_timeout: Duration,
30}
31
32impl Validator {
33    /// Serves the validator RPC API.
34    ///
35    /// Executes in place (i.e. not spawned) and will run indefinitely until a fatal error is
36    /// encountered.
37    pub async fn serve(self) -> anyhow::Result<()> {
38        tracing::info!(target: COMPONENT, endpoint=?self.address, "Initializing server");
39
40        let listener = TcpListener::bind(self.address)
41            .await
42            .context("failed to bind to block producer address")?;
43
44        let reflection_service = tonic_reflection::server::Builder::configure()
45            .register_file_descriptor_set(validator_api_descriptor())
46            .build_v1()
47            .context("failed to build reflection service")?;
48
49        // This is currently required for postman to work properly because
50        // it doesn't support the new version yet.
51        //
52        // See: <https://github.com/postmanlabs/postman-app-support/issues/13120>.
53        let reflection_service_alpha = tonic_reflection::server::Builder::configure()
54            .register_file_descriptor_set(validator_api_descriptor())
55            .build_v1alpha()
56            .context("failed to build reflection service")?;
57
58        // Build the gRPC server with the API service and trace layer.
59        tonic::transport::Server::builder()
60            .layer(CatchPanicLayer::custom(catch_panic_layer_fn))
61            .layer(TraceLayer::new_for_grpc().make_span_with(grpc_trace_fn))
62            .timeout(self.grpc_timeout)
63            .add_service(api_server::ApiServer::new(ValidatorServer {}))
64            .add_service(reflection_service)
65            .add_service(reflection_service_alpha)
66            .serve_with_incoming(TcpListenerStream::new(listener))
67            .await
68            .context("failed to serve validator API")
69    }
70}
71
72// VALIDATOR SERVER
73// ================================================================================
74
75/// The underlying implementation of the gRPC validator server.
76///
77/// Implements the gRPC API for the validator.
78struct ValidatorServer {}
79
80#[tonic::async_trait]
81impl api_server::Api for ValidatorServer {
82    /// Returns the status of the validator.
83    async fn status(
84        &self,
85        _request: tonic::Request<()>,
86    ) -> Result<tonic::Response<proto::validator::ValidatorStatus>, tonic::Status> {
87        Ok(tonic::Response::new(proto::validator::ValidatorStatus {
88            version: env!("CARGO_PKG_VERSION").to_string(),
89            status: "OK".to_string(),
90        }))
91    }
92
93    /// Receives a proven transaction, then validates and stores it.
94    async fn submit_proven_transaction(
95        &self,
96        _request: tonic::Request<proto::transaction::ProvenTransaction>,
97    ) -> Result<tonic::Response<()>, tonic::Status> {
98        todo!()
99    }
100}