From d56cec83fc1b2eb90f8e37d3aa7dc1f698c6dc65 Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Tue, 20 Jun 2023 11:47:52 +1000 Subject: [PATCH] Address clippy lints in `tree-states` (#4414) * Address some clippy lints * Box errors to fix error size lint * Add Default impl for Validator * Address more clippy lints * Re-implement `check_state_diff` * Fix misc test compile errors --- beacon_node/beacon_chain/src/migrate.rs | 2 +- .../src/sync_committee_rewards.rs | 2 +- beacon_node/beacon_chain/tests/store_tests.rs | 2 -- beacon_node/execution_layer/src/lib.rs | 8 ++--- beacon_node/genesis/src/interop.rs | 3 +- beacon_node/operation_pool/src/lib.rs | 2 +- beacon_node/store/src/forwards_iter.rs | 2 +- beacon_node/store/src/hdiff.rs | 2 +- beacon_node/store/src/hot_cold_store.rs | 2 +- beacon_node/store/src/leveldb_store.rs | 2 +- consensus/fork_choice/tests/tests.rs | 4 +-- .../src/per_block_processing/errors.rs | 6 ++-- .../src/per_block_processing/tests.rs | 4 +-- .../verify_attestation.rs | 8 ++--- consensus/types/src/beacon_state/tests.rs | 12 ++++---- consensus/types/src/validator.rs | 11 +++++-- lcli/src/new_testnet.rs | 29 ++++++++++--------- lcli/src/state_diff.rs | 8 ++--- lcli/src/transition_blocks.rs | 2 +- testing/ef_tests/src/case_result.rs | 28 +++++++++++++----- .../ef_tests/src/cases/epoch_processing.rs | 2 +- testing/ef_tests/src/cases/operations.rs | 4 +-- testing/ef_tests/src/cases/sanity_blocks.rs | 2 +- testing/ef_tests/src/cases/sanity_slots.rs | 2 +- testing/state_transition_vectors/src/exit.rs | 8 ++--- watch/src/updater/mod.rs | 10 +++---- 26 files changed, 94 insertions(+), 73 deletions(-) diff --git a/beacon_node/beacon_chain/src/migrate.rs b/beacon_node/beacon_chain/src/migrate.rs index 527e0c51de2..88c3c1c222d 100644 --- a/beacon_node/beacon_chain/src/migrate.rs +++ b/beacon_node/beacon_chain/src/migrate.rs @@ -400,7 +400,7 @@ impl, Cold: ItemStore> BackgroundMigrator BeaconChain { .zip(sync_aggregate.sync_committee_bits.iter()) { let participant_balance = balances - .get_mut(&validator_index) + .get_mut(validator_index) .ok_or(BeaconChainError::SyncCommitteeRewardsSyncError)?; if participant_bit { diff --git a/beacon_node/beacon_chain/tests/store_tests.rs b/beacon_node/beacon_chain/tests/store_tests.rs index 08e6d9d6ec2..9c611aeff33 100644 --- a/beacon_node/beacon_chain/tests/store_tests.rs +++ b/beacon_node/beacon_chain/tests/store_tests.rs @@ -28,8 +28,6 @@ use store::{ HotColdDB, LevelDB, StoreConfig, }; use tempfile::{tempdir, TempDir}; -use tokio::time::sleep; -use tree_hash::TreeHash; use types::test_utils::{SeedableRng, XorShiftRng}; use types::*; diff --git a/beacon_node/execution_layer/src/lib.rs b/beacon_node/execution_layer/src/lib.rs index 0e9df7a50d3..2720569c8d8 100644 --- a/beacon_node/execution_layer/src/lib.rs +++ b/beacon_node/execution_layer/src/lib.rs @@ -38,11 +38,11 @@ use tokio::{ }; use tokio_stream::wrappers::WatchStream; use tree_hash::TreeHash; -use types::{AbstractExecPayload, BeaconStateError, ExecPayload, Withdrawals}; +use types::{AbstractExecPayload, BeaconStateError, ExecPayload}; use types::{ - BlindedPayload, BlockType, ChainSpec, Epoch, ExecutionBlockHash, ExecutionPayload, - ExecutionPayloadCapella, ExecutionPayloadMerge, ForkName, ForkVersionedResponse, - ProposerPreparationData, PublicKeyBytes, Signature, SignedBeaconBlock, Slot, Uint256, + BlindedPayload, BlockType, ChainSpec, Epoch, ExecutionPayloadCapella, ExecutionPayloadMerge, + ForkVersionedResponse, ProposerPreparationData, PublicKeyBytes, Signature, SignedBeaconBlock, + Slot, }; mod block_hash; diff --git a/beacon_node/genesis/src/interop.rs b/beacon_node/genesis/src/interop.rs index eb21ad76c73..1dc61e2f72c 100644 --- a/beacon_node/genesis/src/interop.rs +++ b/beacon_node/genesis/src/interop.rs @@ -241,7 +241,8 @@ mod test { } for (index, v) in state.validators().iter().enumerate() { - let creds = v.withdrawal_credentials.as_bytes(); + let withdrawal_credientials = v.withdrawal_credentials(); + let creds = withdrawal_credientials.as_bytes(); if index % 2 == 0 { assert_eq!( creds[0], spec.bls_withdrawal_prefix_byte, diff --git a/beacon_node/operation_pool/src/lib.rs b/beacon_node/operation_pool/src/lib.rs index cded6b081d8..70f29d73676 100644 --- a/beacon_node/operation_pool/src/lib.rs +++ b/beacon_node/operation_pool/src/lib.rs @@ -1249,7 +1249,7 @@ mod release_tests { // Each validator will have a multiple of 1_000_000_000 wei. // Safe from overflow unless there are about 18B validators (2^64 / 1_000_000_000). for i in 0..state.validators().len() { - state.validators_mut()[i].effective_balance = 1_000_000_000 * i as u64; + state.validators_mut().get_mut(i).unwrap().effective_balance = 1_000_000_000 * i as u64; } let num_validators = num_committees diff --git a/beacon_node/store/src/forwards_iter.rs b/beacon_node/store/src/forwards_iter.rs index fb1bb3a3f93..2391739fde4 100644 --- a/beacon_node/store/src/forwards_iter.rs +++ b/beacon_node/store/src/forwards_iter.rs @@ -234,7 +234,7 @@ impl<'a, E: EthSpec, Hot: ItemStore, Cold: ItemStore> // of the pre iterator. None => { let continuation_data = continuation_data.take(); - let start_slot = Slot::from(iter.limit); + let start_slot = iter.limit; *self = PostFinalizationLazy { continuation_data, diff --git a/beacon_node/store/src/hdiff.rs b/beacon_node/store/src/hdiff.rs index 0c8d7ceccae..a1421ee3bb9 100644 --- a/beacon_node/store/src/hdiff.rs +++ b/beacon_node/store/src/hdiff.rs @@ -331,7 +331,7 @@ mod tests { let xor_diff = XorDiff::compute(&x_values, &y_values).unwrap(); - let mut y_from_xor = x_values.clone(); + let mut y_from_xor = x_values; xor_diff.apply(&mut y_from_xor).unwrap(); assert_eq!(y_values, y_from_xor); diff --git a/beacon_node/store/src/hot_cold_store.rs b/beacon_node/store/src/hot_cold_store.rs index 46101316709..6704b2dac76 100644 --- a/beacon_node/store/src/hot_cold_store.rs +++ b/beacon_node/store/src/hot_cold_store.rs @@ -1573,7 +1573,7 @@ impl, Cold: ItemStore> HotColdDB (start_slot.as_u64()..=end_slot.as_u64()) .map(Slot::new) .map(|slot| self.get_cold_blinded_block_by_slot(slot)), - |iter| iter.filter_map(|x| x).collect(), + |iter| iter.flatten().collect(), ) } diff --git a/beacon_node/store/src/leveldb_store.rs b/beacon_node/store/src/leveldb_store.rs index 47e26aca317..76cc37362f7 100644 --- a/beacon_node/store/src/leveldb_store.rs +++ b/beacon_node/store/src/leveldb_store.rs @@ -183,7 +183,7 @@ impl KeyValueStore for LevelDB { } fn iter_column_from(&self, column: DBColumn, from: &[u8]) -> ColumnIter { - let start_key = BytesKey::from_vec(get_key_for_col(column.into(), &from)); + let start_key = BytesKey::from_vec(get_key_for_col(column.into(), from)); let iter = self.db.iter(self.read_options()); iter.seek(&start_key); diff --git a/consensus/fork_choice/tests/tests.rs b/consensus/fork_choice/tests/tests.rs index ef262b58c00..aff5d0e02e2 100644 --- a/consensus/fork_choice/tests/tests.rs +++ b/consensus/fork_choice/tests/tests.rs @@ -345,7 +345,7 @@ impl ForkChoiceTest { let state_root = harness .chain .store - .get_blinded_block(&fc.fc_store().justified_checkpoint().root) + .get_blinded_block(&fc.fc_store().justified_checkpoint().root, None) .unwrap() .unwrap() .message() @@ -361,7 +361,7 @@ impl ForkChoiceTest { .into_iter() .map(|v| { if v.is_active_at(state.current_epoch()) { - v.effective_balance + v.effective_balance() } else { 0 } diff --git a/consensus/state_processing/src/per_block_processing/errors.rs b/consensus/state_processing/src/per_block_processing/errors.rs index 5907faa68e1..220290579d3 100644 --- a/consensus/state_processing/src/per_block_processing/errors.rs +++ b/consensus/state_processing/src/per_block_processing/errors.rs @@ -329,9 +329,11 @@ pub enum AttestationInvalid { /// /// `is_current` is `true` if the attestation was compared to the /// `state.current_justified_checkpoint`, `false` if compared to `state.previous_justified_checkpoint`. + /// + /// Checkpoints have been boxed to keep the error size down and prevent clippy failures. WrongJustifiedCheckpoint { - state: Checkpoint, - attestation: Checkpoint, + state: Box, + attestation: Box, is_current: bool, }, /// The aggregation bitfield length is not the smallest possible size to represent the committee. diff --git a/consensus/state_processing/src/per_block_processing/tests.rs b/consensus/state_processing/src/per_block_processing/tests.rs index ddb9ca6ad54..2992a49ab01 100644 --- a/consensus/state_processing/src/per_block_processing/tests.rs +++ b/consensus/state_processing/src/per_block_processing/tests.rs @@ -451,8 +451,8 @@ async fn invalid_attestation_wrong_justified_checkpoint() { Err(BlockProcessingError::AttestationInvalid { index: 0, reason: AttestationInvalid::WrongJustifiedCheckpoint { - state: old_justified_checkpoint, - attestation: new_justified_checkpoint, + state: Box::new(old_justified_checkpoint), + attestation: Box::new(new_justified_checkpoint), is_current: true, } }) diff --git a/consensus/state_processing/src/per_block_processing/verify_attestation.rs b/consensus/state_processing/src/per_block_processing/verify_attestation.rs index 303a6e3913a..8a1140035fa 100644 --- a/consensus/state_processing/src/per_block_processing/verify_attestation.rs +++ b/consensus/state_processing/src/per_block_processing/verify_attestation.rs @@ -93,8 +93,8 @@ fn verify_casper_ffg_vote( verify!( data.source == state.current_justified_checkpoint(), Invalid::WrongJustifiedCheckpoint { - state: state.current_justified_checkpoint(), - attestation: data.source, + state: Box::new(state.current_justified_checkpoint()), + attestation: Box::new(data.source), is_current: true, } ); @@ -103,8 +103,8 @@ fn verify_casper_ffg_vote( verify!( data.source == state.previous_justified_checkpoint(), Invalid::WrongJustifiedCheckpoint { - state: state.previous_justified_checkpoint(), - attestation: data.source, + state: Box::new(state.previous_justified_checkpoint()), + attestation: Box::new(data.source), is_current: false, } ); diff --git a/consensus/types/src/beacon_state/tests.rs b/consensus/types/src/beacon_state/tests.rs index 0504bc028b8..9c1ed5e3066 100644 --- a/consensus/types/src/beacon_state/tests.rs +++ b/consensus/types/src/beacon_state/tests.rs @@ -1,13 +1,10 @@ #![cfg(test)] use crate::{test_utils::*, ForkName}; -use beacon_chain::test_utils::{ - interop_genesis_state_with_eth1, test_spec, BeaconChainHarness, EphemeralHarnessType, - DEFAULT_ETH1_BLOCK_HASH, -}; +use beacon_chain::test_utils::{BeaconChainHarness, EphemeralHarnessType}; use beacon_chain::types::{ - test_utils::TestRandom, BeaconState, BeaconStateAltair, BeaconStateBase, BeaconStateError, - BeaconStateMerge, ChainSpec, Domain, Epoch, EthSpec, FixedVector, Hash256, Keypair, - MainnetEthSpec, MinimalEthSpec, RelativeEpoch, Slot, + test_utils::TestRandom, BeaconState, BeaconStateAltair, BeaconStateBase, BeaconStateCapella, + BeaconStateError, BeaconStateMerge, ChainSpec, Domain, Epoch, EthSpec, FixedVector, Hash256, + Keypair, MainnetEthSpec, MinimalEthSpec, RelativeEpoch, Slot, }; use ssz::Encode; use std::ops::Mul; @@ -418,6 +415,7 @@ fn check_num_fields_pow2() { ForkName::Base => BeaconStateBase::::NUM_FIELDS, ForkName::Altair => BeaconStateAltair::::NUM_FIELDS, ForkName::Merge => BeaconStateMerge::::NUM_FIELDS, + ForkName::Capella => BeaconStateCapella::::NUM_FIELDS, }; assert_eq!( num_fields.next_power_of_two(), diff --git a/consensus/types/src/validator.rs b/consensus/types/src/validator.rs index 7be8143f6fb..c9dbb8fda2d 100644 --- a/consensus/types/src/validator.rs +++ b/consensus/types/src/validator.rs @@ -230,7 +230,15 @@ impl Validator { } } -/* +impl Default for Validator { + fn default() -> Self { + Validator { + pubkey: Arc::new(PublicKeyBytes::empty()), + mutable: <_>::default(), + } + } +} + impl Default for ValidatorMutable { fn default() -> Self { ValidatorMutable { @@ -244,7 +252,6 @@ impl Default for ValidatorMutable { } } } -*/ impl TreeHash for Validator { fn tree_hash_type() -> tree_hash::TreeHashType { diff --git a/lcli/src/new_testnet.rs b/lcli/src/new_testnet.rs index aa5f52eef8c..69cd1fd0fe2 100644 --- a/lcli/src/new_testnet.rs +++ b/lcli/src/new_testnet.rs @@ -14,13 +14,14 @@ use std::fs::File; use std::io::Read; use std::path::PathBuf; use std::str::FromStr; +use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; use types::ExecutionBlockHash; use types::{ test_utils::generate_deterministic_keypairs, Address, BeaconState, ChainSpec, Config, Epoch, Eth1Data, EthSpec, ExecutionPayloadHeader, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderMerge, ExecutionPayloadHeaderRefMut, ForkName, Hash256, Keypair, - PublicKey, Validator, + PublicKey, Validator, ValidatorMutable, }; pub fn run(testnet_dir_path: PathBuf, matches: &ArgMatches) -> Result<(), String> { @@ -233,7 +234,7 @@ fn initialize_state_with_validators( let mut state = BeaconState::new(genesis_time, eth1_data, spec); // Seed RANDAO with Eth1 entropy - state.fill_randao_mixes_with(eth1_block_hash); + state.fill_randao_mixes_with(eth1_block_hash).unwrap(); for keypair in keypairs.iter() { let withdrawal_credentials = |pubkey: &PublicKey| { @@ -244,17 +245,19 @@ fn initialize_state_with_validators( let amount = spec.max_effective_balance; // Create a new validator. let validator = Validator { - pubkey: keypair.0.pk.clone().into(), - withdrawal_credentials: withdrawal_credentials(&keypair.1.pk), - activation_eligibility_epoch: spec.far_future_epoch, - activation_epoch: spec.far_future_epoch, - exit_epoch: spec.far_future_epoch, - withdrawable_epoch: spec.far_future_epoch, - effective_balance: std::cmp::min( - amount - amount % (spec.effective_balance_increment), - spec.max_effective_balance, - ), - slashed: false, + pubkey: Arc::new(keypair.0.pk.clone().into()), + mutable: ValidatorMutable { + withdrawal_credentials: withdrawal_credentials(&keypair.1.pk), + activation_eligibility_epoch: spec.far_future_epoch, + activation_epoch: spec.far_future_epoch, + exit_epoch: spec.far_future_epoch, + withdrawable_epoch: spec.far_future_epoch, + effective_balance: std::cmp::min( + amount - amount % (spec.effective_balance_increment), + spec.max_effective_balance, + ), + slashed: false, + }, }; state.validators_mut().push(validator).unwrap(); state.balances_mut().push(amount).unwrap(); diff --git a/lcli/src/state_diff.rs b/lcli/src/state_diff.rs index 5087fad35be..278b5bf0ee4 100644 --- a/lcli/src/state_diff.rs +++ b/lcli/src/state_diff.rs @@ -1,14 +1,12 @@ use crate::transition_blocks::load_from_ssz_with; use clap::ArgMatches; -use clap_utils::{parse_optional, parse_required}; +use clap_utils::parse_required; use environment::Environment; -use eth2::{types::BlockId, BeaconNodeHttpClient, SensitiveUrl, Timeouts}; use std::path::PathBuf; -use std::time::{Duration, Instant}; use store::hdiff::{HDiff, HDiffBuffer}; -use types::{BeaconState, EthSpec, FullPayload, SignedBeaconBlock}; +use types::{BeaconState, EthSpec}; -pub fn run(env: Environment, matches: &ArgMatches) -> Result<(), String> { +pub fn run(_env: Environment, matches: &ArgMatches) -> Result<(), String> { let state1_path: PathBuf = parse_required(matches, "state1")?; let state2_path: PathBuf = parse_required(matches, "state2")?; let spec = &T::default_spec(); diff --git a/lcli/src/transition_blocks.rs b/lcli/src/transition_blocks.rs index b33f4b75a5c..39af712271c 100644 --- a/lcli/src/transition_blocks.rs +++ b/lcli/src/transition_blocks.rs @@ -74,7 +74,7 @@ use eth2::{ use ssz::Encode; use state_processing::{ block_signature_verifier::BlockSignatureVerifier, per_block_processing, per_slot_processing, - BlockSignatureStrategy, ConsensusContext, StateProcessingStrategy, VerifyBlockRoot, + BlockSignatureStrategy, ConsensusContext, EpochCache, StateProcessingStrategy, VerifyBlockRoot, }; use std::borrow::Cow; use std::fs::File; diff --git a/testing/ef_tests/src/case_result.rs b/testing/ef_tests/src/case_result.rs index e0ab308418f..d04ce287fc6 100644 --- a/testing/ef_tests/src/case_result.rs +++ b/testing/ef_tests/src/case_result.rs @@ -2,7 +2,8 @@ use super::*; use compare_fields::{CompareFields, Comparison, FieldComparison}; use std::fmt::Debug; use std::path::{Path, PathBuf}; -use types::{beacon_state::BeaconStateDiff, milhouse::diff::Diff, BeaconState}; +use store::hdiff::{HDiff, HDiffBuffer}; +use types::BeaconState; pub const MAX_VALUE_STRING_LEN: usize = 500; @@ -121,15 +122,28 @@ where pub fn check_state_diff( pre_state: &BeaconState, opt_post_state: &Option>, + spec: &ChainSpec, ) -> Result<(), Error> { if let Some(post_state) = opt_post_state { - let diff = BeaconStateDiff::compute_diff(pre_state, post_state) - .expect("BeaconStateDiff should compute"); - let mut diffed_state = pre_state.clone(); - diff.apply_diff(&mut diffed_state) - .expect("BeaconStateDiff should apply"); + // Produce a diff between the pre- and post-states. + let pre_state_buf = HDiffBuffer::from_state(pre_state.clone()); + let post_state_buf = HDiffBuffer::from_state(post_state.clone()); + let diff = HDiff::compute(&pre_state_buf, &post_state_buf).expect("HDiff should compute"); - compare_result_detailed::<_, ()>(&Ok(diffed_state), opt_post_state) + // Apply the diff to the pre-state, ensuring the same post-state is + // regenerated. + let mut reconstructed_buf = HDiffBuffer::from_state(pre_state.clone()); + diff.apply(&mut reconstructed_buf) + .expect("HDiff should apply"); + let diffed_state = reconstructed_buf + .into_state(spec) + .expect("HDiffDiffer should convert to state"); + + // Drop the caches on the post-state to assist with equality checking. + let mut post_state_without_caches = post_state.clone(); + post_state_without_caches.drop_all_caches().unwrap(); + + compare_result_detailed::<_, ()>(&Ok(diffed_state), &Some(post_state_without_caches)) } else { Ok(()) } diff --git a/testing/ef_tests/src/cases/epoch_processing.rs b/testing/ef_tests/src/cases/epoch_processing.rs index ce68c1865a5..62ccb792c6e 100644 --- a/testing/ef_tests/src/cases/epoch_processing.rs +++ b/testing/ef_tests/src/cases/epoch_processing.rs @@ -328,7 +328,7 @@ impl> Case for EpochProcessing { let mut result = T::run(&mut state, spec).map(|_| state); - check_state_diff(&pre_state, &expected)?; + check_state_diff(&pre_state, &expected, spec)?; compare_beacon_state_results_without_caches(&mut result, &mut expected) } } diff --git a/testing/ef_tests/src/cases/operations.rs b/testing/ef_tests/src/cases/operations.rs index aabbed69a5e..f59d6b84370 100644 --- a/testing/ef_tests/src/cases/operations.rs +++ b/testing/ef_tests/src/cases/operations.rs @@ -458,7 +458,7 @@ impl> Case for Operations { // NOTE: some of the withdrawals tests have 0 active validators, do not try // to build the commitee cache in this case. if O::handler_name() != "withdrawals" { - state.build_all_committee_caches(spec).unwrap(); + pre_state.build_all_committee_caches(spec).unwrap(); } let mut state = pre_state.clone(); @@ -475,7 +475,7 @@ impl> Case for Operations { .apply_to(&mut state, spec, self) .map(|()| state); - check_state_diff(&pre_state, &expected)?; + check_state_diff(&pre_state, &expected, spec)?; compare_beacon_state_results_without_caches(&mut result, &mut expected) } } diff --git a/testing/ef_tests/src/cases/sanity_blocks.rs b/testing/ef_tests/src/cases/sanity_blocks.rs index e233b0b0bb0..105140156db 100644 --- a/testing/ef_tests/src/cases/sanity_blocks.rs +++ b/testing/ef_tests/src/cases/sanity_blocks.rs @@ -137,7 +137,7 @@ impl Case for SanityBlocks { post.build_all_committee_caches(spec).unwrap(); post }); - check_state_diff(&pre, &post)?; + check_state_diff(&pre, &post, spec)?; Ok(()) } } diff --git a/testing/ef_tests/src/cases/sanity_slots.rs b/testing/ef_tests/src/cases/sanity_slots.rs index bc4fe8d0b14..f71a6317e30 100644 --- a/testing/ef_tests/src/cases/sanity_slots.rs +++ b/testing/ef_tests/src/cases/sanity_slots.rs @@ -76,6 +76,6 @@ impl Case for SanitySlots { post.build_all_committee_caches(spec).unwrap(); post }); - check_state_diff(&pre, &post) + check_state_diff(&pre, &post, spec) } } diff --git a/testing/state_transition_vectors/src/exit.rs b/testing/state_transition_vectors/src/exit.rs index 2e33f8a7a2b..99ef1c2a008 100644 --- a/testing/state_transition_vectors/src/exit.rs +++ b/testing/state_transition_vectors/src/exit.rs @@ -336,17 +336,17 @@ mod custom_tests { fn assert_exited(state: &BeaconState, validator_index: usize) { let spec = E::default_spec(); - let validator = &state.validators()[validator_index]; + let validator = &state.validators().get(validator_index).unwrap(); assert_eq!( - validator.exit_epoch, + validator.exit_epoch(), // This is correct until we exceed the churn limit. If that happens, we // need to introduce more complex logic. state.current_epoch() + 1 + spec.max_seed_lookahead, "exit epoch" ); assert_eq!( - validator.withdrawable_epoch, - validator.exit_epoch + E::default_spec().min_validator_withdrawability_delay, + validator.withdrawable_epoch(), + validator.exit_epoch() + E::default_spec().min_validator_withdrawability_delay, "withdrawable epoch" ); } diff --git a/watch/src/updater/mod.rs b/watch/src/updater/mod.rs index 1fbb0107aef..376eb6d2fdd 100644 --- a/watch/src/updater/mod.rs +++ b/watch/src/updater/mod.rs @@ -211,20 +211,20 @@ pub async fn get_validators(bn: &BeaconNodeHttpClient) -> Result