Skip to main content

linera_rpc/
lib.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! This module provides network abstractions and the data schemas for remote procedure
5//! calls (RPCs) in the Linera protocol.
6
7#![recursion_limit = "256"]
8#![deny(missing_docs)]
9// `tracing::instrument` is not compatible with this nightly Clippy lint
10#![allow(unknown_lints)]
11
12/// Network configuration types for validators, shards, and cross-chain messaging.
13pub mod config;
14/// Construction of validator-node clients from network configuration.
15pub mod node_provider;
16
17/// A network-agnostic client for talking to a validator node.
18pub mod client;
19
20mod cross_chain_message_queue;
21mod message;
22/// The simple custom-TCP/UDP network transport.
23#[cfg(with_simple_network)]
24pub mod simple;
25
26/// The gRPC network transport.
27pub mod grpc;
28
29/// Propagation of OpenTelemetry trace context across RPC boundaries.
30#[cfg(feature = "opentelemetry")]
31pub mod propagation;
32
33pub use client::Client;
34pub use message::{RpcMessage, ShardInfo};
35pub use node_provider::{NodeOptions, NodeProvider, DEFAULT_MAX_BACKOFF};
36
37/// A request to handle a lite certificate.
38#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
39#[cfg_attr(with_testing, derive(Eq, PartialEq))]
40pub struct HandleLiteCertRequest<'a> {
41    /// The lite certificate to handle.
42    pub certificate: linera_chain::types::LiteCertificate<'a>,
43    /// Whether to wait for the resulting cross-chain messages to be delivered.
44    pub wait_for_outgoing_messages: bool,
45}
46
47/// A request to handle a confirmed-block certificate.
48#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
49#[cfg_attr(with_testing, derive(Eq, PartialEq))]
50pub struct HandleConfirmedCertificateRequest {
51    /// The confirmed-block certificate to handle.
52    pub certificate: linera_chain::types::ConfirmedBlockCertificate,
53    /// Whether to wait for the resulting cross-chain messages to be delivered.
54    pub wait_for_outgoing_messages: bool,
55}
56
57/// A request to handle a validated-block certificate.
58#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
59#[cfg_attr(with_testing, derive(Eq, PartialEq))]
60pub struct HandleValidatedCertificateRequest {
61    /// The validated-block certificate to handle.
62    pub certificate: linera_chain::types::ValidatedBlockCertificate,
63}
64
65/// A request to handle a timeout certificate.
66#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
67#[cfg_attr(with_testing, derive(Eq, PartialEq))]
68pub struct HandleTimeoutCertificateRequest {
69    /// The timeout certificate to handle.
70    pub certificate: linera_chain::types::TimeoutCertificate,
71}
72
73/// The protobuf file descriptor set for the RPC service, used for gRPC reflection.
74pub const FILE_DESCRIPTOR_SET: &[u8] = tonic::include_file_descriptor_set!("file_descriptor_set");
75
76/// A self-signed TLS certificate (PEM), generated at build time for local testing.
77#[cfg(not(target_arch = "wasm32"))]
78pub const CERT_PEM: &str = include_str!(concat!(env!("OUT_DIR"), "/self_signed_cert.pem"));
79/// The private key (PEM) matching [`CERT_PEM`], generated at build time for local testing.
80#[cfg(not(target_arch = "wasm32"))]
81pub const KEY_PEM: &str = include_str!(concat!(env!("OUT_DIR"), "/private_key.pem"));
82
83/// Computes a jittered exponential backoff delay.
84///
85/// Uses the gRPC-recommended approach: compute `min(cap, base * 2^attempt)`,
86/// then apply ±20% jitter. This guarantees a minimum delay of 80% of the
87/// computed backoff, preventing instant retries.
88///
89/// Reference: <https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md>
90pub(crate) fn jittered_backoff_delay(
91    base_delay: std::time::Duration,
92    attempt: u32,
93    max_backoff: std::time::Duration,
94) -> std::time::Duration {
95    use rand::Rng as _;
96    let exponential_delay =
97        base_delay.saturating_mul(1u32.checked_shl(attempt).unwrap_or(u32::MAX));
98    #[expect(
99        clippy::cast_possible_truncation,
100        reason = "delay is capped by max_backoff, which fits in u64 milliseconds"
101    )]
102    let capped_delay_ms = exponential_delay.min(max_backoff).as_millis() as u64;
103    let min_delay_ms = capped_delay_ms * 4 / 5; // 80%
104    let max_delay_ms = capped_delay_ms * 6 / 5; // 120%
105    std::time::Duration::from_millis(rand::thread_rng().gen_range(min_delay_ms..=max_delay_ms))
106}