Validator registration request failures do not cause us to mark BNs offline (#3488)

## Issue Addressed

Relates to https://github.com/sigp/lighthouse/issues/3416

## Proposed Changes

- Add an `OfflineOnFailure` enum to the `first_success` method for querying beacon nodes so that a val registration request failure from the BN -> builder does not result in the BN being marked offline. This seems important because these failures could be coming directly from a connected relay and actually have no bearing on BN health.  Other messages that are sent to a relay have a local fallback so shouldn't result in errors 

- Downgrade the following log to a `WARN`

```
ERRO Unable to publish validator registrations to the builder network, error: All endpoints failed https://BN_B => RequestFailed(ServerMessage(ErrorMessage { code: 500, message: "UNHANDLED_ERROR: BuilderMissing", stacktraces: [] })), https://XXXX/ => Unavailable(Offline), [omitted]
```

## Additional Info

I think this change at least improves the UX of having a VC connected to some builder and some non-builder beacon nodes. I think we need to balance potentially alerting users that there is a BN <> VC misconfiguration and also allowing this type of fallback to work. 

If we want to fully support this type of configuration we may want to consider adding a flag `--builder-beacon-nodes` and track whether a VC should be making builder queries on a per-beacon node basis.  But I think the changes in this PR are independent of that type of extension.

PS: Sorry for the big diff here, it's mostly formatting changes after I added a new arg to a bunch of methods calls.




Co-authored-by: realbigsean <sean@sigmaprime.io>
This commit is contained in:
realbigsean 2022-08-29 11:35:59 +00:00
parent 66eca1a882
commit 2ce86a0830
9 changed files with 339 additions and 241 deletions

View File

@ -3,6 +3,7 @@ use crate::{
duties_service::{DutiesService, DutyAndProof}, duties_service::{DutiesService, DutyAndProof},
http_metrics::metrics, http_metrics::metrics,
validator_store::ValidatorStore, validator_store::ValidatorStore,
OfflineOnFailure,
}; };
use environment::RuntimeContext; use environment::RuntimeContext;
use futures::future::join_all; use futures::future::join_all;
@ -337,7 +338,10 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
let attestation_data = self let attestation_data = self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async move {
let _timer = metrics::start_timer_vec( let _timer = metrics::start_timer_vec(
&metrics::ATTESTATION_SERVICE_TIMES, &metrics::ATTESTATION_SERVICE_TIMES,
&[metrics::ATTESTATIONS_HTTP_GET], &[metrics::ATTESTATIONS_HTTP_GET],
@ -347,7 +351,8 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
.await .await
.map_err(|e| format!("Failed to produce attestation data: {:?}", e)) .map_err(|e| format!("Failed to produce attestation data: {:?}", e))
.map(|result| result.data) .map(|result| result.data)
}) },
)
.await .await
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
@ -414,7 +419,10 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
// Post the attestations to the BN. // Post the attestations to the BN.
match self match self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async move {
let _timer = metrics::start_timer_vec( let _timer = metrics::start_timer_vec(
&metrics::ATTESTATION_SERVICE_TIMES, &metrics::ATTESTATION_SERVICE_TIMES,
&[metrics::ATTESTATIONS_HTTP_POST], &[metrics::ATTESTATIONS_HTTP_POST],
@ -422,7 +430,8 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
beacon_node beacon_node
.post_beacon_pool_attestations(attestations) .post_beacon_pool_attestations(attestations)
.await .await
}) },
)
.await .await
{ {
Ok(()) => info!( Ok(()) => info!(
@ -470,7 +479,10 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
let aggregated_attestation = &self let aggregated_attestation = &self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async move {
let _timer = metrics::start_timer_vec( let _timer = metrics::start_timer_vec(
&metrics::ATTESTATION_SERVICE_TIMES, &metrics::ATTESTATION_SERVICE_TIMES,
&[metrics::AGGREGATES_HTTP_GET], &[metrics::AGGREGATES_HTTP_GET],
@ -481,10 +493,13 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
attestation_data.tree_hash_root(), attestation_data.tree_hash_root(),
) )
.await .await
.map_err(|e| format!("Failed to produce an aggregate attestation: {:?}", e))? .map_err(|e| {
format!("Failed to produce an aggregate attestation: {:?}", e)
})?
.ok_or_else(|| format!("No aggregate available for {:?}", attestation_data)) .ok_or_else(|| format!("No aggregate available for {:?}", attestation_data))
.map(|result| result.data) .map(|result| result.data)
}) },
)
.await .await
.map_err(|e| e.to_string())?; .map_err(|e| e.to_string())?;
@ -535,7 +550,10 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
let signed_aggregate_and_proofs_slice = signed_aggregate_and_proofs.as_slice(); let signed_aggregate_and_proofs_slice = signed_aggregate_and_proofs.as_slice();
match self match self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async move {
let _timer = metrics::start_timer_vec( let _timer = metrics::start_timer_vec(
&metrics::ATTESTATION_SERVICE_TIMES, &metrics::ATTESTATION_SERVICE_TIMES,
&[metrics::AGGREGATES_HTTP_POST], &[metrics::AGGREGATES_HTTP_POST],
@ -543,7 +561,8 @@ impl<T: SlotClock + 'static, E: EthSpec> AttestationService<T, E> {
beacon_node beacon_node
.post_validator_aggregate_and_proof(signed_aggregate_and_proofs_slice) .post_validator_aggregate_and_proof(signed_aggregate_and_proofs_slice)
.await .await
}) },
)
.await .await
{ {
Ok(()) => { Ok(()) => {

View File

@ -70,6 +70,13 @@ pub enum RequireSynced {
No, No,
} }
/// Indicates if a beacon node should be set to `Offline` if a request fails.
#[derive(PartialEq, Clone, Copy)]
pub enum OfflineOnFailure {
Yes,
No,
}
impl PartialEq<bool> for RequireSynced { impl PartialEq<bool> for RequireSynced {
fn eq(&self, other: &bool) -> bool { fn eq(&self, other: &bool) -> bool {
if *other { if *other {
@ -387,6 +394,7 @@ impl<T: SlotClock, E: EthSpec> BeaconNodeFallback<T, E> {
pub async fn first_success<'a, F, O, Err, R>( pub async fn first_success<'a, F, O, Err, R>(
&'a self, &'a self,
require_synced: RequireSynced, require_synced: RequireSynced,
offline_on_failure: OfflineOnFailure,
func: F, func: F,
) -> Result<O, AllErrored<Err>> ) -> Result<O, AllErrored<Err>>
where where
@ -415,7 +423,9 @@ impl<T: SlotClock, E: EthSpec> BeaconNodeFallback<T, E> {
// There exists a race condition where the candidate may have been marked // There exists a race condition where the candidate may have been marked
// as ready between the `func` call and now. We deem this an acceptable // as ready between the `func` call and now. We deem this an acceptable
// inefficiency. // inefficiency.
if matches!(offline_on_failure, OfflineOnFailure::Yes) {
$candidate.set_offline().await; $candidate.set_offline().await;
}
errors.push(($candidate.beacon_node.to_string(), Error::RequestFailed(e))); errors.push(($candidate.beacon_node.to_string(), Error::RequestFailed(e)));
inc_counter_vec(&ENDPOINT_ERRORS, &[$candidate.beacon_node.as_ref()]); inc_counter_vec(&ENDPOINT_ERRORS, &[$candidate.beacon_node.as_ref()]);
} }

View File

@ -2,6 +2,7 @@ use crate::beacon_node_fallback::{AllErrored, Error as FallbackError};
use crate::{ use crate::{
beacon_node_fallback::{BeaconNodeFallback, RequireSynced}, beacon_node_fallback::{BeaconNodeFallback, RequireSynced},
graffiti_file::GraffitiFile, graffiti_file::GraffitiFile,
OfflineOnFailure,
}; };
use crate::{http_metrics::metrics, validator_store::ValidatorStore}; use crate::{http_metrics::metrics, validator_store::ValidatorStore};
use environment::RuntimeContext; use environment::RuntimeContext;
@ -329,7 +330,10 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
// Request block from first responsive beacon node. // Request block from first responsive beacon node.
let block = self let block = self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async move {
let block = match Payload::block_type() { let block = match Payload::block_type() {
BlockType::Full => { BlockType::Full => {
let _get_timer = metrics::start_timer_vec( let _get_timer = metrics::start_timer_vec(
@ -392,7 +396,8 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
} }
Ok::<_, BlockError>(block) Ok::<_, BlockError>(block)
}) },
)
.await?; .await?;
let signed_block = self_ref let signed_block = self_ref
@ -403,7 +408,10 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
// Publish block with first available beacon node. // Publish block with first available beacon node.
self.beacon_nodes self.beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async {
match Payload::block_type() { match Payload::block_type() {
BlockType::Full => { BlockType::Full => {
let _post_timer = metrics::start_timer_vec( let _post_timer = metrics::start_timer_vec(
@ -437,7 +445,8 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
} }
} }
Ok::<_, BlockError>(()) Ok::<_, BlockError>(())
}) },
)
.await?; .await?;
info!( info!(

View File

@ -31,6 +31,7 @@
use crate::beacon_node_fallback::{BeaconNodeFallback, RequireSynced}; use crate::beacon_node_fallback::{BeaconNodeFallback, RequireSynced};
use crate::validator_store::ValidatorStore; use crate::validator_store::ValidatorStore;
use crate::OfflineOnFailure;
use environment::RuntimeContext; use environment::RuntimeContext;
use eth2::types::LivenessResponseData; use eth2::types::LivenessResponseData;
use parking_lot::RwLock; use parking_lot::RwLock;
@ -176,13 +177,17 @@ async fn beacon_node_liveness<'a, T: 'static + SlotClock, E: EthSpec>(
} else { } else {
// Request the previous epoch liveness state from the beacon node. // Request the previous epoch liveness state from the beacon node.
beacon_nodes beacon_nodes
.first_success(RequireSynced::Yes, |beacon_node| async move { .first_success(
RequireSynced::Yes,
OfflineOnFailure::Yes,
|beacon_node| async move {
beacon_node beacon_node
.post_lighthouse_liveness(validator_indices, previous_epoch) .post_lighthouse_liveness(validator_indices, previous_epoch)
.await .await
.map_err(|e| format!("Failed query for validator liveness: {:?}", e)) .map_err(|e| format!("Failed query for validator liveness: {:?}", e))
.map(|result| result.data) .map(|result| result.data)
}) },
)
.await .await
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
crit!( crit!(
@ -199,13 +204,17 @@ async fn beacon_node_liveness<'a, T: 'static + SlotClock, E: EthSpec>(
// Request the current epoch liveness state from the beacon node. // Request the current epoch liveness state from the beacon node.
let current_epoch_responses = beacon_nodes let current_epoch_responses = beacon_nodes
.first_success(RequireSynced::Yes, |beacon_node| async move { .first_success(
RequireSynced::Yes,
OfflineOnFailure::Yes,
|beacon_node| async move {
beacon_node beacon_node
.post_lighthouse_liveness(validator_indices, current_epoch) .post_lighthouse_liveness(validator_indices, current_epoch)
.await .await
.map_err(|e| format!("Failed query for validator liveness: {:?}", e)) .map_err(|e| format!("Failed query for validator liveness: {:?}", e))
.map(|result| result.data) .map(|result| result.data)
}) },
)
.await .await
.unwrap_or_else(|e| { .unwrap_or_else(|e| {
crit!( crit!(

View File

@ -8,7 +8,7 @@
mod sync; mod sync;
use crate::beacon_node_fallback::{BeaconNodeFallback, RequireSynced}; use crate::beacon_node_fallback::{BeaconNodeFallback, OfflineOnFailure, RequireSynced};
use crate::{ use crate::{
block_service::BlockServiceNotification, block_service::BlockServiceNotification,
http_metrics::metrics, http_metrics::metrics,
@ -382,7 +382,10 @@ async fn poll_validator_indices<T: SlotClock + 'static, E: EthSpec>(
// Query the remote BN to resolve a pubkey to a validator index. // Query the remote BN to resolve a pubkey to a validator index.
let download_result = duties_service let download_result = duties_service
.beacon_nodes .beacon_nodes
.first_success(duties_service.require_synced, |beacon_node| async move { .first_success(
duties_service.require_synced,
OfflineOnFailure::Yes,
|beacon_node| async move {
let _timer = metrics::start_timer_vec( let _timer = metrics::start_timer_vec(
&metrics::DUTIES_SERVICE_TIMES, &metrics::DUTIES_SERVICE_TIMES,
&[metrics::VALIDATOR_ID_HTTP_GET], &[metrics::VALIDATOR_ID_HTTP_GET],
@ -393,7 +396,8 @@ async fn poll_validator_indices<T: SlotClock + 'static, E: EthSpec>(
&ValidatorId::PublicKey(pubkey), &ValidatorId::PublicKey(pubkey),
) )
.await .await
}) },
)
.await; .await;
match download_result { match download_result {
@ -559,7 +563,10 @@ async fn poll_beacon_attesters<T: SlotClock + 'static, E: EthSpec>(
let subscriptions_ref = &subscriptions; let subscriptions_ref = &subscriptions;
if let Err(e) = duties_service if let Err(e) = duties_service
.beacon_nodes .beacon_nodes
.first_success(duties_service.require_synced, |beacon_node| async move { .first_success(
duties_service.require_synced,
OfflineOnFailure::Yes,
|beacon_node| async move {
let _timer = metrics::start_timer_vec( let _timer = metrics::start_timer_vec(
&metrics::DUTIES_SERVICE_TIMES, &metrics::DUTIES_SERVICE_TIMES,
&[metrics::SUBSCRIPTIONS_HTTP_POST], &[metrics::SUBSCRIPTIONS_HTTP_POST],
@ -567,7 +574,8 @@ async fn poll_beacon_attesters<T: SlotClock + 'static, E: EthSpec>(
beacon_node beacon_node
.post_validator_beacon_committee_subscriptions(subscriptions_ref) .post_validator_beacon_committee_subscriptions(subscriptions_ref)
.await .await
}) },
)
.await .await
{ {
error!( error!(
@ -619,7 +627,10 @@ async fn poll_beacon_attesters_for_epoch<T: SlotClock + 'static, E: EthSpec>(
let response = duties_service let response = duties_service
.beacon_nodes .beacon_nodes
.first_success(duties_service.require_synced, |beacon_node| async move { .first_success(
duties_service.require_synced,
OfflineOnFailure::Yes,
|beacon_node| async move {
let _timer = metrics::start_timer_vec( let _timer = metrics::start_timer_vec(
&metrics::DUTIES_SERVICE_TIMES, &metrics::DUTIES_SERVICE_TIMES,
&[metrics::ATTESTER_DUTIES_HTTP_POST], &[metrics::ATTESTER_DUTIES_HTTP_POST],
@ -627,7 +638,8 @@ async fn poll_beacon_attesters_for_epoch<T: SlotClock + 'static, E: EthSpec>(
beacon_node beacon_node
.post_validator_duties_attester(epoch, local_indices) .post_validator_duties_attester(epoch, local_indices)
.await .await
}) },
)
.await .await
.map_err(|e| Error::FailedToDownloadAttesters(e.to_string()))?; .map_err(|e| Error::FailedToDownloadAttesters(e.to_string()))?;
@ -779,7 +791,10 @@ async fn poll_beacon_proposers<T: SlotClock + 'static, E: EthSpec>(
if !local_pubkeys.is_empty() { if !local_pubkeys.is_empty() {
let download_result = duties_service let download_result = duties_service
.beacon_nodes .beacon_nodes
.first_success(duties_service.require_synced, |beacon_node| async move { .first_success(
duties_service.require_synced,
OfflineOnFailure::Yes,
|beacon_node| async move {
let _timer = metrics::start_timer_vec( let _timer = metrics::start_timer_vec(
&metrics::DUTIES_SERVICE_TIMES, &metrics::DUTIES_SERVICE_TIMES,
&[metrics::PROPOSER_DUTIES_HTTP_GET], &[metrics::PROPOSER_DUTIES_HTTP_GET],
@ -787,7 +802,8 @@ async fn poll_beacon_proposers<T: SlotClock + 'static, E: EthSpec>(
beacon_node beacon_node
.get_validator_duties_proposer(current_epoch) .get_validator_duties_proposer(current_epoch)
.await .await
}) },
)
.await; .await;
match download_result { match download_result {

View File

@ -1,3 +1,4 @@
use crate::beacon_node_fallback::OfflineOnFailure;
use crate::{ use crate::{
doppelganger_service::DoppelgangerStatus, doppelganger_service::DoppelgangerStatus,
duties_service::{DutiesService, Error}, duties_service::{DutiesService, Error},
@ -420,11 +421,15 @@ pub async fn poll_sync_committee_duties_for_period<T: SlotClock + 'static, E: Et
let duties_response = duties_service let duties_response = duties_service
.beacon_nodes .beacon_nodes
.first_success(duties_service.require_synced, |beacon_node| async move { .first_success(
duties_service.require_synced,
OfflineOnFailure::Yes,
|beacon_node| async move {
beacon_node beacon_node
.post_validator_duties_sync(period_start_epoch, local_indices) .post_validator_duties_sync(period_start_epoch, local_indices)
.await .await
}) },
)
.await; .await;
let duties = match duties_response { let duties = match duties_response {

View File

@ -26,7 +26,8 @@ use monitoring_api::{MonitoringHttpClient, ProcessType};
pub use slashing_protection::{SlashingDatabase, SLASHING_PROTECTION_FILENAME}; pub use slashing_protection::{SlashingDatabase, SLASHING_PROTECTION_FILENAME};
use crate::beacon_node_fallback::{ use crate::beacon_node_fallback::{
start_fallback_updater_service, BeaconNodeFallback, CandidateBeaconNode, RequireSynced, start_fallback_updater_service, BeaconNodeFallback, CandidateBeaconNode, OfflineOnFailure,
RequireSynced,
}; };
use crate::doppelganger_service::DoppelgangerService; use crate::doppelganger_service::DoppelgangerService;
use account_utils::validator_definitions::ValidatorDefinitions; use account_utils::validator_definitions::ValidatorDefinitions;
@ -570,9 +571,11 @@ async fn init_from_beacon_node<E: EthSpec>(
let genesis = loop { let genesis = loop {
match beacon_nodes match beacon_nodes
.first_success(RequireSynced::No, |node| async move { .first_success(
node.get_beacon_genesis().await RequireSynced::No,
}) OfflineOnFailure::Yes,
|node| async move { node.get_beacon_genesis().await },
)
.await .await
{ {
Ok(genesis) => break genesis.data, Ok(genesis) => break genesis.data,
@ -659,9 +662,11 @@ async fn poll_whilst_waiting_for_genesis<E: EthSpec>(
) -> Result<(), String> { ) -> Result<(), String> {
loop { loop {
match beacon_nodes match beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
beacon_node.get_lighthouse_staking().await RequireSynced::No,
}) OfflineOnFailure::Yes,
|beacon_node| async move { beacon_node.get_lighthouse_staking().await },
)
.await .await
{ {
Ok(is_staking) => { Ok(is_staking) => {

View File

@ -1,9 +1,10 @@
use crate::beacon_node_fallback::{BeaconNodeFallback, RequireSynced}; use crate::beacon_node_fallback::{BeaconNodeFallback, RequireSynced};
use crate::validator_store::{DoppelgangerStatus, ValidatorStore}; use crate::validator_store::{DoppelgangerStatus, ValidatorStore};
use crate::OfflineOnFailure;
use bls::PublicKeyBytes; use bls::PublicKeyBytes;
use environment::RuntimeContext; use environment::RuntimeContext;
use parking_lot::RwLock; use parking_lot::RwLock;
use slog::{debug, error, info}; use slog::{debug, error, info, warn};
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::collections::HashMap; use std::collections::HashMap;
use std::hash::Hash; use std::hash::Hash;
@ -330,11 +331,15 @@ impl<T: SlotClock + 'static, E: EthSpec> PreparationService<T, E> {
let preparation_entries = preparation_data.as_slice(); let preparation_entries = preparation_data.as_slice();
match self match self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::Yes, |beacon_node| async move { .first_success(
RequireSynced::Yes,
OfflineOnFailure::Yes,
|beacon_node| async move {
beacon_node beacon_node
.post_validator_prepare_beacon_proposer(preparation_entries) .post_validator_prepare_beacon_proposer(preparation_entries)
.await .await
}) },
)
.await .await
{ {
Ok(()) => debug!( Ok(()) => debug!(
@ -445,9 +450,13 @@ impl<T: SlotClock + 'static, E: EthSpec> PreparationService<T, E> {
for batch in signed.chunks(VALIDATOR_REGISTRATION_BATCH_SIZE) { for batch in signed.chunks(VALIDATOR_REGISTRATION_BATCH_SIZE) {
match self match self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::Yes, |beacon_node| async move { .first_success(
RequireSynced::Yes,
OfflineOnFailure::No,
|beacon_node| async move {
beacon_node.post_validator_register_validator(batch).await beacon_node.post_validator_register_validator(batch).await
}) },
)
.await .await
{ {
Ok(()) => info!( Ok(()) => info!(
@ -455,7 +464,7 @@ impl<T: SlotClock + 'static, E: EthSpec> PreparationService<T, E> {
"Published validator registrations to the builder network"; "Published validator registrations to the builder network";
"count" => registration_data_len, "count" => registration_data_len,
), ),
Err(e) => error!( Err(e) => warn!(
log, log,
"Unable to publish validator registrations to the builder network"; "Unable to publish validator registrations to the builder network";
"error" => %e, "error" => %e,

View File

@ -1,5 +1,5 @@
use crate::beacon_node_fallback::{BeaconNodeFallback, RequireSynced}; use crate::beacon_node_fallback::{BeaconNodeFallback, RequireSynced};
use crate::{duties_service::DutiesService, validator_store::ValidatorStore}; use crate::{duties_service::DutiesService, validator_store::ValidatorStore, OfflineOnFailure};
use environment::RuntimeContext; use environment::RuntimeContext;
use eth2::types::BlockId; use eth2::types::BlockId;
use futures::future::join_all; use futures::future::join_all;
@ -177,7 +177,7 @@ impl<T: SlotClock + 'static, E: EthSpec> SyncCommitteeService<T, E> {
// Fetch `block_root` and `execution_optimistic` for `SyncCommitteeContribution`. // Fetch `block_root` and `execution_optimistic` for `SyncCommitteeContribution`.
let response = self let response = self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::Yes, |beacon_node| async move { .first_success(RequireSynced::Yes, OfflineOnFailure::Yes,|beacon_node| async move {
beacon_node.get_beacon_blocks_root(BlockId::Head).await beacon_node.get_beacon_blocks_root(BlockId::Head).await
}) })
.await .await
@ -284,11 +284,15 @@ impl<T: SlotClock + 'static, E: EthSpec> SyncCommitteeService<T, E> {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.beacon_nodes self.beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async move {
beacon_node beacon_node
.post_beacon_pool_sync_committee_signatures(committee_signatures) .post_beacon_pool_sync_committee_signatures(committee_signatures)
.await .await
}) },
)
.await .await
.map_err(|e| { .map_err(|e| {
error!( error!(
@ -351,7 +355,10 @@ impl<T: SlotClock + 'static, E: EthSpec> SyncCommitteeService<T, E> {
let contribution = &self let contribution = &self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async move {
let sync_contribution_data = SyncContributionData { let sync_contribution_data = SyncContributionData {
slot, slot,
beacon_block_root, beacon_block_root,
@ -361,7 +368,8 @@ impl<T: SlotClock + 'static, E: EthSpec> SyncCommitteeService<T, E> {
beacon_node beacon_node
.get_validator_sync_committee_contribution::<E>(&sync_contribution_data) .get_validator_sync_committee_contribution::<E>(&sync_contribution_data)
.await .await
}) },
)
.await .await
.map_err(|e| { .map_err(|e| {
crit!( crit!(
@ -418,11 +426,15 @@ impl<T: SlotClock + 'static, E: EthSpec> SyncCommitteeService<T, E> {
// Publish to the beacon node. // Publish to the beacon node.
self.beacon_nodes self.beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async move {
beacon_node beacon_node
.post_validator_contribution_and_proofs(signed_contributions) .post_validator_contribution_and_proofs(signed_contributions)
.await .await
}) },
)
.await .await
.map_err(|e| { .map_err(|e| {
error!( error!(
@ -556,11 +568,15 @@ impl<T: SlotClock + 'static, E: EthSpec> SyncCommitteeService<T, E> {
if let Err(e) = self if let Err(e) = self
.beacon_nodes .beacon_nodes
.first_success(RequireSynced::No, |beacon_node| async move { .first_success(
RequireSynced::No,
OfflineOnFailure::Yes,
|beacon_node| async move {
beacon_node beacon_node
.post_validator_sync_committee_subscriptions(subscriptions_slice) .post_validator_sync_committee_subscriptions(subscriptions_slice)
.await .await
}) },
)
.await .await
{ {
error!( error!(