Skip to content

Commit fecc84f

Browse files
authored
refactor(proto): deprecate tonic-prost generated gRPC server types (#2263)
1 parent d629e10 commit fecc84f

10 files changed

Lines changed: 128 additions & 40 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bin/ntx-builder/src/server.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use anyhow::Context;
2-
use miden_node_proto::generated::ntx_builder::api_server;
2+
use miden_node_proto::server::ntx_builder_api;
33
use miden_node_proto_build::ntx_builder_api_descriptor;
44
use miden_node_utils::panic::{CatchPanicLayer, catch_panic_layer_fn};
55
use miden_node_utils::tracing::grpc::grpc_trace_fn;
@@ -32,7 +32,7 @@ impl NtxBuilderRpcServer {
3232

3333
/// Starts the gRPC server on the given listener.
3434
pub async fn serve(self, listener: TcpListener) -> anyhow::Result<()> {
35-
let api_service = api_server::ApiServer::new(self);
35+
let api_service = ntx_builder_api::service(self);
3636
let reflection_service = server::Builder::configure()
3737
.register_file_descriptor_set(ntx_builder_api_descriptor())
3838
.build_v1()

bin/remote-prover/src/server/mod.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use std::num::NonZeroUsize;
22

33
use anyhow::Context;
4-
use miden_node_proto::generated::remote_prover::api_server::ApiServer;
5-
use miden_node_proto::generated::remote_prover::worker_status_api_server::WorkerStatusApiServer;
4+
use miden_node_proto::server::{remote_prover_api, remote_prover_worker_status_api};
65
use miden_node_utils::cors::cors_for_grpc_web_layer;
76
use miden_node_utils::logging::OpenTelemetry;
87
use miden_node_utils::panic::catch_panic_layer_fn;
@@ -74,9 +73,10 @@ impl Server {
7473
"proof server listening"
7574
);
7675

77-
let status_service = WorkerStatusApiServer::new(status::StatusService::new(self.kind));
76+
let status_service =
77+
remote_prover_worker_status_api::service(status::StatusService::new(self.kind));
7878
let prover_service = ProverService::with_capacity(self.kind, self.capacity);
79-
let prover_service = ApiServer::new(prover_service);
79+
let prover_service = remote_prover_api::service(prover_service);
8080

8181
let reflection_service = tonic_reflection::server::Builder::configure()
8282
.register_file_descriptor_set(miden_node_proto_build::remote_prover_api_descriptor())
@@ -88,7 +88,12 @@ impl Server {
8888
let (health_reporter, health_service) = tonic_health::server::health_reporter();
8989

9090
// Mark the service as serving
91-
health_reporter.set_serving::<ApiServer<ProverService>>().await;
91+
health_reporter
92+
.set_service_status(
93+
remote_prover_api::service_name(),
94+
tonic_health::ServingStatus::Serving,
95+
)
96+
.await;
9297

9398
let server = tonic::transport::Server::builder()
9499
.accept_http1(true)

bin/validator/src/server/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::net::SocketAddr;
22
use std::num::NonZeroUsize;
33

44
use anyhow::Context;
5-
use miden_node_proto::generated::validator::api_server;
5+
use miden_node_proto::server::validator_api;
66
use miden_node_proto_build::validator_api_descriptor;
77
use miden_node_store::BlockStore;
88
use miden_node_utils::clap::GrpcOptionsInternal;
@@ -94,7 +94,7 @@ impl ValidatorServer {
9494
.layer(CatchPanicLayer::custom(catch_panic_layer_fn))
9595
.layer(TraceLayer::new_for_grpc().make_span_with(grpc_trace_fn))
9696
.timeout(self.grpc_options.request_timeout)
97-
.add_service(api_server::ApiServer::new(
97+
.add_service(validator_api::service(
9898
ValidatorService::new(
9999
self.signer,
100100
db,

bin/validator/src/server/validator_service/tests.rs

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::BTreeMap;
22

3-
use miden_node_proto::generated::validator::api_server;
43
use miden_node_proto::generated::{self as proto};
4+
use miden_node_proto::server::validator_api;
55
use miden_node_store::{BlockStore, GenesisState};
66
use miden_node_utils::fee::test_fee_params;
77
use miden_protocol::Word;
@@ -50,11 +50,11 @@ impl TestValidator {
5050
async fn call_sign_block(
5151
&self,
5252
proposed_block: &ProposedBlock,
53-
) -> Result<tonic::Response<proto::blockchain::SignBlockResponse>, tonic::Status> {
53+
) -> Result<proto::blockchain::SignBlockResponse, tonic::Status> {
5454
let request = tonic::Request::new(proto::blockchain::ProposedBlock {
5555
proposed_block: proposed_block.to_bytes(),
5656
});
57-
api_server::Api::sign_block(&self.server, request).await
57+
validator_api::SignBlock::full(&self.server, request).await
5858
}
5959

6060
/// Opens a block subscription starting from `block_from`.
@@ -64,10 +64,9 @@ impl TestValidator {
6464
) -> <ValidatorService as proto::server::validator_api::BlockSubscription>::ItemStream {
6565
let request =
6666
tonic::Request::new(proto::validator::BlockSubscriptionRequest { block_from });
67-
api_server::Api::block_subscription(&self.server, request)
67+
validator_api::BlockSubscription::full(&self.server, request)
6868
.await
6969
.expect("subscription should open")
70-
.into_inner()
7170
}
7271

7372
/// Loads the current chain tip from the validator's database.
@@ -163,11 +162,7 @@ async fn sign_block_returns_signed_commitment() {
163162
let tv = TestValidator::new().await;
164163

165164
let proposed = tv.propose_empty_block();
166-
let response = tv
167-
.call_sign_block(&proposed)
168-
.await
169-
.expect("block should be signed")
170-
.into_inner();
165+
let response = tv.call_sign_block(&proposed).await.expect("block should be signed");
171166

172167
let (header, _) = proposed.into_header_and_body().unwrap();
173168
let returned: Word = response

crates/proto/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ prost = { workspace = true }
2626
thiserror = { workspace = true }
2727
tonic = { default-features = true, workspace = true }
2828
tonic-prost = { workspace = true }
29+
tower = { workspace = true }
2930
url = { workspace = true }
3031

3132
[dev-dependencies]
@@ -44,4 +45,10 @@ tonic-prost-build = { workspace = true }
4445
[package.metadata.cargo-machete]
4546
ignored = [
4647
"tonic-prost", # used in generated OUT_DIR code
48+
"tower", # used in generated OUT_DIR code
49+
]
50+
51+
[package.metadata.cargo-shear]
52+
ignored = [
53+
"tower", # used in generated OUT_DIR code
4754
]

crates/proto/build.rs

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ fn main() -> miette::Result<()> {
3232
];
3333

3434
for file_descriptors in &descriptor_sets {
35-
generate_bindings(file_descriptors.clone(), &dst_dir)?;
35+
generate_bindings(file_descriptors, &dst_dir)?;
3636
}
3737

3838
let server_dst_dir = dst_dir.join("server");
@@ -54,14 +54,19 @@ fn main() -> miette::Result<()> {
5454

5555
/// Generates protobuf bindings from the given file descriptor set and stores them in the given
5656
/// destination directory.
57-
fn generate_bindings(file_descriptors: FileDescriptorSet, dst_dir: &Path) -> miette::Result<()> {
57+
fn generate_bindings(file_descriptors: &FileDescriptorSet, dst_dir: &Path) -> miette::Result<()> {
5858
let mut prost_config = tonic_prost_build::Config::new();
5959
prost_config.skip_debug(["AccountId", "Digest"]);
6060

6161
// Generate the stub of the user facing server from its proto file
6262
tonic_prost_build::configure()
63+
.server_mod_attribute(".", "#[allow(deprecated, clippy::mixed_attributes_style)]")
64+
.server_attribute(
65+
".",
66+
r#"#[deprecated(note = "use the service constructors in `miden_node_proto::server` instead")]"#,
67+
)
6368
.out_dir(dst_dir)
64-
.compile_fds_with_config(file_descriptors, prost_config)
69+
.compile_fds_with_config(file_descriptors.clone(), prost_config)
6570
.into_diagnostic()
6671
.wrap_err("compiling protobufs")?;
6772

@@ -216,6 +221,8 @@ impl Service {
216221
fn generate(&self) -> Module {
217222
let mut module = Module::new(&self.name);
218223

224+
module.push_fn(self.service_constructor());
225+
module.push_fn(self.service_name());
219226
module.push_trait(self.service_trait());
220227
module.push_impl(self.blanket_impl());
221228
module.push_impl(self.tonic_impl());
@@ -302,12 +309,7 @@ impl Service {
302309
/// }
303310
/// ```
304311
fn tonic_impl(&self) -> Impl {
305-
let tonic_path = format!(
306-
"crate::generated::{}::{}_server::{}",
307-
self.package,
308-
to_snake_case(&self.name),
309-
self.name
310-
);
312+
let tonic_path = self.tonic_trait_path();
311313

312314
let mut ret = Impl::new("T");
313315
ret.generic("T")
@@ -329,6 +331,60 @@ impl Service {
329331

330332
ret
331333
}
334+
335+
/// Constructs the underlying tonic server for this service behind an opaque tower service type.
336+
fn service_constructor(&self) -> Function {
337+
let mut ret = Function::new("service");
338+
ret.vis("pub")
339+
.attr("allow(deprecated)")
340+
.generic("T")
341+
.arg("service", "T")
342+
.ret(
343+
"impl tower::Service<
344+
http::Request<tonic::body::Body>,
345+
Response = http::Response<tonic::body::Body>,
346+
Error = std::convert::Infallible,
347+
Future: Send + 'static,
348+
> + tonic::server::NamedService
349+
+ Clone
350+
+ Send
351+
+ Sync
352+
+ 'static",
353+
)
354+
.bound("T", self.service_trait().ty())
355+
.bound("T", "Send")
356+
.bound("T", "Sync")
357+
.bound("T", "'static")
358+
.line(format!("{}::new(service)", self.tonic_server_path()));
359+
360+
ret
361+
}
362+
363+
/// Returns the gRPC service name used by tonic routing and health reporting.
364+
fn service_name(&self) -> Function {
365+
let mut ret = Function::new("service_name");
366+
ret.vis("pub").attr("allow(deprecated)").ret("&'static str").line(format!(
367+
"<{}::<()> as tonic::server::NamedService>::NAME",
368+
self.tonic_server_path()
369+
));
370+
371+
ret
372+
}
373+
374+
/// Returns the full path to the service's trait.
375+
fn tonic_trait_path(&self) -> String {
376+
format!(
377+
"crate::generated::{}::{}_server::{}",
378+
self.package,
379+
to_snake_case(&self.name),
380+
self.name
381+
)
382+
}
383+
384+
/// Returns the full path to the generated server struct.
385+
fn tonic_server_path(&self) -> String {
386+
format!("{}Server", self.tonic_trait_path())
387+
}
332388
}
333389

334390
impl UnaryMethod {

crates/proto/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ pub mod generated;
1212
pub use domain::account::AccountWitnessRecord;
1313
pub use domain::proof_request::BlockProofRequest;
1414
pub use domain::{convert, try_convert};
15+
pub use generated::server;
1516
pub use prost;

crates/rpc/src/server/mod.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use accept::AcceptHeaderLayer;
55
use anyhow::Context;
66
use miden_node_block_producer::{BlockProducerApi, RpcReadiness, RpcSync};
77
use miden_node_proto::clients::{NtxBuilderClient, RpcClient as SourceRpcClient, ValidatorClient};
8-
use miden_node_proto::generated::rpc::api_server;
8+
use miden_node_proto::server::rpc_api;
99
use miden_node_proto_build::rpc_api_descriptor;
1010
use miden_node_store::state::State;
1111
use miden_node_utils::clap::GrpcOptionsExternal;
@@ -105,7 +105,7 @@ impl Rpc {
105105

106106
api.set_genesis_commitment(genesis.commitment())?;
107107

108-
let api_service = api_server::ApiServer::new(api);
108+
let api_service = rpc_api::service(api);
109109

110110
info!(target: COMPONENT, endpoint=?self.listener, mode=?self.mode, "Server initialized");
111111

@@ -115,11 +115,19 @@ impl Rpc {
115115
let (health_reporter, health_service) = tonic_health::server::health_reporter();
116116
match self.mode {
117117
RpcMode::Sequencer { .. } => {
118-
health_reporter.set_serving::<api_server::ApiServer<api::RpcService>>().await;
118+
health_reporter
119+
.set_service_status(
120+
rpc_api::service_name(),
121+
tonic_health::ServingStatus::Serving,
122+
)
123+
.await;
119124
},
120125
RpcMode::FullNode { source_rpc, readiness_threshold } => {
121126
health_reporter
122-
.set_not_serving::<api_server::ApiServer<api::RpcService>>()
127+
.set_service_status(
128+
rpc_api::service_name(),
129+
tonic_health::ServingStatus::NotServing,
130+
)
123131
.await;
124132
let readiness = RpcReadiness::new(health_reporter, readiness_threshold);
125133
tasks.spawn(

crates/rpc/src/tests.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ use miden_node_proto::clients::{
1515
RpcClient,
1616
ValidatorClient,
1717
};
18-
use miden_node_proto::generated::ntx_builder::api_server::ApiServer as NtxBuilderApiServer;
1918
use miden_node_proto::generated::rpc::api_client::ApiClient as ProtoClient;
20-
use miden_node_proto::generated::rpc::api_server::{Api, ApiServer as RpcApiServer};
19+
use miden_node_proto::generated::rpc::api_server::Api;
2120
use miden_node_proto::generated::{self as proto};
21+
use miden_node_proto::server::{ntx_builder_api, rpc_api};
2222
use miden_node_store::genesis::config::GenesisConfig;
2323
use miden_node_store::state::State;
2424
use miden_node_utils::clap::{GrpcOptionsExternal, StorageOptions};
@@ -502,19 +502,34 @@ struct FixedNtxBuilder {
502502
}
503503

504504
#[tonic::async_trait]
505-
impl proto::ntx_builder::api_server::Api for FixedNtxBuilder {
506-
async fn get_network_note_status(
505+
impl ntx_builder_api::GetNetworkNoteStatus for FixedNtxBuilder {
506+
type Input = proto::note::NoteId;
507+
type Output = proto::rpc::GetNetworkNoteStatusResponse;
508+
509+
fn decode(request: proto::note::NoteId) -> tonic::Result<Self::Input> {
510+
Ok(request)
511+
}
512+
513+
fn encode(output: Self::Output) -> tonic::Result<proto::rpc::GetNetworkNoteStatusResponse> {
514+
Ok(output)
515+
}
516+
517+
async fn handle(&self, _input: Self::Input) -> tonic::Result<Self::Output> {
518+
Ok(self.response.clone())
519+
}
520+
521+
async fn full(
507522
&self,
508523
request: Request<proto::note::NoteId>,
509-
) -> Result<tonic::Response<proto::rpc::GetNetworkNoteStatusResponse>, tonic::Status> {
524+
) -> tonic::Result<proto::rpc::GetNetworkNoteStatusResponse> {
510525
self.call_count.fetch_add(1, Ordering::SeqCst);
511526
let accept = request
512527
.metadata()
513528
.get(ACCEPT.as_str())
514529
.and_then(|value| value.to_str().ok())
515530
.map(str::to_string);
516531
*self.last_accept.lock().expect("last_accept mutex should not be poisoned") = accept;
517-
Ok(tonic::Response::new(self.response.clone()))
532+
self.handle(request.into_inner()).await.and_then(Self::encode)
518533
}
519534
}
520535

@@ -533,7 +548,7 @@ async fn start_ntx_builder(
533548

534549
task::spawn(async move {
535550
tonic::transport::Server::builder()
536-
.add_service(NtxBuilderApiServer::new(service))
551+
.add_service(ntx_builder_api::service(service))
537552
.serve_with_incoming(TcpListenerStream::new(listener))
538553
.await
539554
.expect("Failed to serve ntx-builder");
@@ -583,7 +598,7 @@ async fn start_source_rpc(ntx_builder: NtxBuilderClient) -> (RpcClient, TestStor
583598
);
584599

585600
tonic::transport::Server::builder()
586-
.add_service(RpcApiServer::new(source_rpc))
601+
.add_service(rpc_api::service(source_rpc))
587602
.serve_with_incoming(TcpListenerStream::new(listener))
588603
.await
589604
.expect("Failed to serve source RPC");

0 commit comments

Comments
 (0)