miden_validator/server/
mod.rs1use std::net::SocketAddr;
2use std::num::NonZeroUsize;
3
4use anyhow::Context;
5use miden_node_proto::server::validator_api;
6use miden_node_proto_build::validator_api_descriptor;
7use miden_node_store::BlockStore;
8use miden_node_utils::clap::GrpcOptionsInternal;
9use miden_node_utils::panic::catch_panic_layer_fn;
10use miden_node_utils::shutdown::CancellationToken;
11use miden_node_utils::tracing::grpc::grpc_trace_fn;
12use tokio::net::TcpListener;
13use tokio_stream::wrappers::TcpListenerStream;
14use tower_http::catch_panic::CatchPanicLayer;
15use tower_http::trace::TraceLayer;
16
17use crate::db::{
18 count_signed_blocks,
19 count_validated_transactions,
20 load_chain_tip,
21 load_with_pool_size,
22};
23use crate::{DataDirectory, LOG_TARGET, ValidatorSigner};
24
25mod validator_service;
26
27use validator_service::ValidatorService;
28
29pub struct ValidatorServer {
36 pub address: SocketAddr,
38 pub grpc_options: GrpcOptionsInternal,
42
43 pub signer: ValidatorSigner,
45
46 pub data_directory: DataDirectory,
48
49 pub sqlite_connection_pool_size: NonZeroUsize,
51}
52
53impl ValidatorServer {
54 pub async fn serve(self, shutdown: CancellationToken) -> anyhow::Result<()> {
59 tracing::info!(target: LOG_TARGET, endpoint=?self.address, "Initializing server");
60
61 let db = load_with_pool_size(
63 self.data_directory.database_path(),
64 self.sqlite_connection_pool_size,
65 )
66 .await
67 .context("failed to initialize validator database")?;
68
69 let block_store = BlockStore::load(self.data_directory.block_store_dir())
71 .context("failed to load block store")?;
72
73 let (initial_chain_tip, initial_tx_count, initial_block_count) = db
75 .query("load_initial_metrics", |conn| {
76 let tip = load_chain_tip(conn)?.map_or(0, |h| h.block_num().as_u32());
77 let tx_count = u64::try_from(count_validated_transactions(conn)?).unwrap_or(0);
78 let block_count = u64::try_from(count_signed_blocks(conn)?).unwrap_or(0);
79 Ok::<_, miden_node_db::DatabaseError>((tip, tx_count, block_count))
80 })
81 .await
82 .context("failed to load initial metrics")?;
83
84 let listener = TcpListener::bind(self.address)
85 .await
86 .context("failed to bind to block producer address")?;
87
88 let reflection_service = tonic_reflection::server::Builder::configure()
89 .register_file_descriptor_set(validator_api_descriptor())
90 .build_v1()
91 .context("failed to build reflection service")?;
92
93 tonic::transport::Server::builder()
95 .layer(CatchPanicLayer::custom(catch_panic_layer_fn))
96 .layer(TraceLayer::new_for_grpc().make_span_with(grpc_trace_fn))
97 .timeout(self.grpc_options.request_timeout)
98 .add_service(validator_api::service(
99 ValidatorService::new(
100 self.signer,
101 db,
102 block_store,
103 initial_chain_tip,
104 initial_tx_count,
105 initial_block_count,
106 )
107 .await
108 .context("failed to initialize validator server")?,
109 ))
110 .add_service(reflection_service)
111 .serve_with_incoming_shutdown(
112 TcpListenerStream::new(listener),
113 shutdown.cancelled_owned(),
114 )
115 .await
116 .context("failed to serve validator API")
117 }
118}