Skip to main content

linera_rpc/grpc/
node_provider.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4use std::{str::FromStr as _, sync::Arc};
5
6use linera_base::time::{Duration, Instant};
7use linera_core::node::{NodeError, ValidatorNodeProvider};
8
9use super::GrpcClient;
10use crate::{
11    config::ValidatorPublicNetworkConfig,
12    grpc::{pool::GrpcConnectionPool, transport},
13    node_provider::NodeOptions,
14};
15
16/// A node provider that creates gRPC clients backed by a shared connection pool.
17#[derive(Clone)]
18pub struct GrpcNodeProvider {
19    pool: GrpcConnectionPool,
20    retry_delay: Duration,
21    max_retries: u32,
22    max_backoff: Duration,
23    /// Shared across all `GrpcClient` instances. When a subscription to a validator
24    /// fails, the failure time is recorded here so that other chains (which share the
25    /// same provider) skip retrying the same dead validator.
26    subscription_cooldowns: Arc<papaya::HashMap<String, Instant>>,
27}
28
29impl GrpcNodeProvider {
30    /// Creates a new [`GrpcNodeProvider`] with the given node options.
31    pub fn new(options: NodeOptions) -> Self {
32        let transport_options = transport::Options::from(&options);
33        let retry_delay = options.retry_delay;
34        let max_retries = options.max_retries;
35        let max_backoff = options.max_backoff;
36        let pool = GrpcConnectionPool::new(transport_options);
37        Self {
38            pool,
39            retry_delay,
40            max_retries,
41            max_backoff,
42            subscription_cooldowns: Arc::new(papaya::HashMap::new()),
43        }
44    }
45}
46
47impl ValidatorNodeProvider for GrpcNodeProvider {
48    type Node = GrpcClient;
49
50    fn make_node(&self, address: &str) -> Result<Self::Node, NodeError> {
51        let network = ValidatorPublicNetworkConfig::from_str(address).map_err(|_| {
52            NodeError::CannotResolveValidatorAddress {
53                address: address.to_string(),
54            }
55        })?;
56        let http_address = network.http_address();
57        let channel =
58            self.pool
59                .channel(http_address.clone())
60                .map_err(|error| NodeError::GrpcError {
61                    error: format!("error creating channel: {error}"),
62                })?;
63
64        Ok(GrpcClient::new(
65            http_address,
66            channel,
67            self.retry_delay,
68            self.max_retries,
69            self.max_backoff,
70            self.subscription_cooldowns.clone(),
71        ))
72    }
73}