miden_validator/server/
mod.rs1use std::net::SocketAddr;
2
3use anyhow::Context;
4use miden_node_proto::server::miden_validator_v1_validator_service;
5use miden_node_proto_build::validator_api_descriptor;
6use miden_node_store::BlockStore;
7use miden_node_tracing::grpc::grpc_trace_fn;
8use miden_node_tracing::info;
9use miden_node_tracing::panic::catch_panic_layer_fn;
10use miden_node_utils::clap::GrpcOptions;
11use miden_node_utils::shutdown::CancellationToken;
12use tokio::net::TcpListener;
13use tokio_stream::wrappers::TcpListenerStream;
14use tower_http::catch_panic::CatchPanicLayer;
15use tower_http::trace::TraceLayer;
16
17use crate::db::{ValidatorDbReader, ValidatorDbWriter};
18use crate::{
19 DataDirectory,
20 GoldenOperatorKey,
21 LOG_TARGET,
22 PrivateRecordSealer,
23 TransactionInputDecrypter,
24 ValidatorSigner,
25};
26
27mod admin_service;
28mod validator_service;
29
30use validator_service::ValidatorService;
31
32pub struct ValidatorServer {
39 pub address: SocketAddr,
41 pub grpc_options: GrpcOptions,
45
46 pub signer: ValidatorSigner,
48
49 pub decrypter: std::sync::Arc<dyn TransactionInputDecrypter>,
52
53 pub private_record_sealer: PrivateRecordSealer,
55
56 pub data_directory: DataDirectory,
58
59 pub db: ValidatorDbWriter,
62}
63
64pub struct ValidatorAdminServer {
66 pub address: SocketAddr,
68 pub operator_key: GoldenOperatorKey,
70 pub reader: ValidatorDbReader,
73}
74
75impl ValidatorAdminServer {
76 pub async fn serve(self, shutdown: CancellationToken) -> anyhow::Result<()> {
78 let listener =
79 TcpListener::bind(self.address).await.context("failed to bind admin address")?;
80 self.serve_on(listener, shutdown).await
81 }
82
83 async fn serve_on(
84 self,
85 listener: TcpListener,
86 shutdown: CancellationToken,
87 ) -> anyhow::Result<()> {
88 let endpoint =
89 listener.local_addr().context("failed to read validator admin listen address")?;
90 info!(
91 target: LOG_TARGET,
92 "Validator admin server ready",
93 service.name = "miden-validator-admin",
94 validator.admin_listen = endpoint.to_string()
95 );
96
97 axum::serve(listener, admin_service::router(self.operator_key, self.reader))
98 .with_graceful_shutdown(shutdown.cancelled_owned())
99 .await
100 .context("failed to serve validator admin API")
101 }
102}
103
104impl ValidatorServer {
105 pub async fn serve(self, shutdown: CancellationToken) -> anyhow::Result<()> {
110 let db = self.db;
113
114 let block_store = BlockStore::load(self.data_directory.block_store_dir())
116 .context("failed to load block store")?;
117
118 let metrics = db.load_initial_metrics().await.context("failed to load initial metrics")?;
120
121 let listener = TcpListener::bind(self.address)
122 .await
123 .context("failed to bind to block producer address")?;
124
125 let reflection_service = tonic_reflection::server::Builder::configure()
126 .register_file_descriptor_set(validator_api_descriptor())
127 .build_v1()
128 .context("failed to build reflection service")?;
129
130 let service = ValidatorService::new(
131 self.signer,
132 db,
133 self.decrypter,
134 self.private_record_sealer,
135 block_store,
136 metrics,
137 )
138 .await
139 .context("failed to initialize validator server")?;
140 let endpoint = listener.local_addr().context("failed to read validator listen address")?;
141 info!(
142 target: LOG_TARGET,
143 "Validator ready",
144 service.name = "miden-validator",
145 service.version = env!("CARGO_PKG_VERSION"),
146 validator.listen = endpoint.to_string(),
147 block.number = metrics.chain_tip
148 );
149
150 tonic::transport::Server::builder()
152 .layer(CatchPanicLayer::custom(catch_panic_layer_fn))
153 .layer(TraceLayer::new_for_grpc().make_span_with(grpc_trace_fn))
154 .timeout(self.grpc_options.request_timeout)
155 .add_service(miden_validator_v1_validator_service::service(service))
156 .add_service(reflection_service)
157 .serve_with_incoming_shutdown(
158 TcpListenerStream::new(listener),
159 shutdown.cancelled_owned(),
160 )
161 .await
162 .context("failed to serve validator API")
163 }
164}