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 _;
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#[derive(Clone)]
17pub struct GrpcNodeProvider {
18    pool: GrpcConnectionPool,
19    retry_delay: Duration,
20    max_retries: u32,
21    max_backoff: Duration,
22    /// Shared across all `GrpcClient` instances. When a subscription to a validator
23    /// fails, the failure time is recorded here so that other chains (which share the
24    /// same provider) skip retrying the same dead validator.
25    subscription_cooldowns: papaya::HashMap<String, Instant>,
26}
27
28impl GrpcNodeProvider {
29    pub fn new(options: NodeOptions) -> Self {
30        let transport_options = transport::Options::from(&options);
31        let retry_delay = options.retry_delay;
32        let max_retries = options.max_retries;
33        let max_backoff = options.max_backoff;
34        let pool = GrpcConnectionPool::new(transport_options);
35        Self {
36            pool,
37            retry_delay,
38            max_retries,
39            max_backoff,
40            subscription_cooldowns: papaya::HashMap::new(),
41        }
42    }
43}
44
45impl ValidatorNodeProvider for GrpcNodeProvider {
46    type Node = GrpcClient;
47
48    fn make_node(&self, address: &str) -> Result<Self::Node, NodeError> {
49        let network = ValidatorPublicNetworkConfig::from_str(address).map_err(|_| {
50            NodeError::CannotResolveValidatorAddress {
51                address: address.to_string(),
52            }
53        })?;
54        let http_address = network.http_address();
55        let channel =
56            self.pool
57                .channel(http_address.clone())
58                .map_err(|error| NodeError::GrpcError {
59                    error: format!("error creating channel: {error}"),
60                })?;
61
62        Ok(GrpcClient::new(
63            http_address,
64            channel,
65            self.retry_delay,
66            self.max_retries,
67            self.max_backoff,
68            self.subscription_cooldowns.clone(),
69        ))
70    }
71}