Fallback nodes for eth1 access (#1918)

## Issue Addressed

part of  #1883

## Proposed Changes

Adds a new cli argument `--eth1-endpoints` that can be used instead of `--eth1-endpoint` to specify a comma-separated list of endpoints. If the first endpoint returns an error for some request the other endpoints are tried in the given order.

## Additional Info

Currently if the first endpoint fails the fallbacks are used silently (except for `try_fallback_test_endpoint` that is used in `do_update` which logs a `WARN` for each endpoint that is not reachable). A question is if we should add more logs so that the user gets warned if his main endpoint is for example just slow and sometimes hits timeouts.
This commit is contained in:
blacktemplar
2020-11-27 08:37:44 +00:00
parent 1312844f29
commit 38b15deccb
20 changed files with 930 additions and 225 deletions

View File

@@ -3,6 +3,7 @@ use environment::Environment;
use eth2_testnet_config::Eth2TestnetConfig;
use genesis::{Eth1Config, Eth1GenesisService};
use ssz::Encode;
use std::cmp::max;
use std::path::PathBuf;
use std::time::Duration;
use types::EthSpec;
@@ -11,9 +12,14 @@ use types::EthSpec;
pub const ETH1_GENESIS_UPDATE_INTERVAL: Duration = Duration::from_millis(7_000);
pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches<'_>) -> Result<(), String> {
let endpoint = matches
let endpoints = matches
.value_of("eth1-endpoint")
.ok_or_else(|| "eth1-endpoint not specified")?;
.map(|e| vec![String::from(e)])
.or_else(|| {
matches
.value_of("eth1-endpoints")
.map(|s| s.split(',').map(String::from).collect())
});
let testnet_dir = matches
.value_of("testnet-dir")
@@ -40,11 +46,14 @@ pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches<'_>) -> Res
})?;
let mut config = Eth1Config::default();
config.endpoint = endpoint.to_string();
if let Some(v) = endpoints.clone() {
config.endpoints = v;
}
config.deposit_contract_address = format!("{:?}", spec.deposit_contract_address);
config.deposit_contract_deploy_block = eth2_testnet_config.deposit_contract_deploy_block;
config.lowest_cached_block_number = eth2_testnet_config.deposit_contract_deploy_block;
config.follow_distance = spec.eth1_follow_distance / 2;
config.node_far_behind_seconds = max(5, config.follow_distance) * spec.seconds_per_eth1_block;
let genesis_service =
Eth1GenesisService::new(config, env.core_context().log().clone(), spec.clone());
@@ -60,7 +69,7 @@ pub fn run<T: EthSpec>(mut env: Environment<T>, matches: &ArgMatches<'_>) -> Res
.map_err(|e| format!("Failed to find genesis: {}", e))?;
info!("Starting service to produce genesis BeaconState from eth1");
info!("Connecting to eth1 http endpoint: {}", endpoint);
info!("Connecting to eth1 http endpoints: {:?}", endpoints);
Ok(())
})

View File

@@ -233,8 +233,17 @@ fn main() {
.long("eth1-endpoint")
.value_name("HTTP_SERVER")
.takes_value(true)
.default_value("http://localhost:8545")
.help("The URL to the eth1 JSON-RPC http API."),
.help("Deprecated. Use --eth1-endpoints."),
)
.arg(
Arg::with_name("eth1-endpoints")
.long("eth1-endpoints")
.value_name("HTTP_SERVER_LIST")
.takes_value(true)
.conflicts_with("eth1-endpoint")
.help("One or more comma-delimited URLs to eth1 JSON-RPC http APIs. \
If multiple endpoints are given the endpoints are used as \
fallback in the given order."),
)
)
.subcommand(