diff --git a/beacon_node/store/src/hdiff.rs b/beacon_node/store/src/hdiff.rs index 5731ebcbe0e..0573ce05229 100644 --- a/beacon_node/store/src/hdiff.rs +++ b/beacon_node/store/src/hdiff.rs @@ -9,7 +9,7 @@ use std::cmp::Ordering; use std::io::{Read, Write}; use std::ops::RangeInclusive; use std::str::FromStr; -use std::sync::LazyLock; +use std::sync::{Arc, LazyLock}; use superstruct::superstruct; use types::historical_summary::HistoricalSummary; use types::{BeaconState, ChainSpec, Epoch, EthSpec, Hash256, List, Slot, Validator}; @@ -100,7 +100,7 @@ pub struct HDiffBuffer { state: Vec, balances: Vec, inactivity_scores: Vec, - validators: Vec, + validators: Vec>, historical_roots: Vec, historical_summaries: Vec, } @@ -183,7 +183,11 @@ impl HDiffBuffer { // is post altair, all its items will show up in the diff as is. vec![] }; - let validators = std::mem::take(beacon_state.validators_mut()).to_vec(); + let validators = std::mem::take(beacon_state.validators_mut()) + .iter() + .cloned() + .map(Arc::new) + .collect::>(); let historical_roots = std::mem::take(beacon_state.historical_roots_mut()).to_vec(); let historical_summaries = if let Ok(historical_summaries) = beacon_state.historical_summaries_mut() { @@ -221,8 +225,9 @@ impl HDiffBuffer { .map_err(|_| Error::InvalidBalancesLength)?; } - *state.validators_mut() = List::try_from_iter(self.validators.iter().cloned()) - .map_err(|_| Error::InvalidBalancesLength)?; + *state.validators_mut() = + List::try_from_iter(self.validators.iter().map(|arc| (**arc).clone())) + .map_err(|_| Error::InvalidBalancesLength)?; *state.historical_roots_mut() = List::try_from_iter(self.historical_roots.iter().copied()) .map_err(|_| Error::InvalidBalancesLength)?; @@ -284,6 +289,7 @@ impl HDiff { .apply(&mut source.inactivity_scores, config)?; self.validators_diff() .apply(&mut source.validators, config)?; + self.historical_roots().apply(&mut source.historical_roots); self.historical_summaries() .apply(&mut source.historical_summaries); @@ -446,8 +452,8 @@ fn uncompress_bytes(input: &[u8], config: &StoreConfig) -> Result, Error impl ValidatorsDiff { pub fn compute( - xs: &[Validator], - ys: &[Validator], + xs: &[Arc], + ys: &[Arc], config: &StoreConfig, ) -> Result { if xs.len() > ys.len() { @@ -457,8 +463,10 @@ impl ValidatorsDiff { let uncompressed_bytes = ys .iter() .enumerate() - .filter_map(|(i, y)| { - let validator_diff = if let Some(x) = xs.get(i) { + .filter_map(|(i, y_arc)| { + let y = &**y_arc; + let validator_diff = if let Some(x_arc) = xs.get(i) { + let x = &**x_arc; if y == x { return None; } else { @@ -538,7 +546,7 @@ impl ValidatorsDiff { }) } - pub fn apply(&self, xs: &mut Vec, config: &StoreConfig) -> Result<(), Error> { + pub fn apply(&self, xs: &mut Vec>, config: &StoreConfig) -> Result<(), Error> { let validator_diff_bytes = uncompress_bytes(&self.bytes, config)?; for diff_bytes in @@ -550,37 +558,39 @@ impl ValidatorsDiff { } = ValidatorDiffEntry::from_ssz_bytes(diff_bytes) .map_err(|_| Error::BalancesIncompleteChunk)?; - if let Some(x) = xs.get_mut(index as usize) { + if let Some(x_arc) = xs.get_mut(index as usize) { + let mut v = (**x_arc).clone(); // Note: a pubkey change implies index re-use. In that case over-write // withdrawal_credentials and slashed inconditionally as their default values // are valid values. let pubkey_changed = diff.pubkey != *EMPTY_PUBKEY; if pubkey_changed { - x.pubkey = diff.pubkey; + v.pubkey = diff.pubkey; } if pubkey_changed || diff.withdrawal_credentials != Hash256::ZERO { - x.withdrawal_credentials = diff.withdrawal_credentials; + v.withdrawal_credentials = diff.withdrawal_credentials; } if diff.effective_balance != 0 { - x.effective_balance = x.effective_balance.wrapping_add(diff.effective_balance); + v.effective_balance = v.effective_balance.wrapping_add(diff.effective_balance); } if pubkey_changed || diff.slashed { - x.slashed = diff.slashed; + v.slashed = diff.slashed; } if diff.activation_eligibility_epoch != Epoch::new(0) { - x.activation_eligibility_epoch = diff.activation_eligibility_epoch; + v.activation_eligibility_epoch = diff.activation_eligibility_epoch; } if diff.activation_epoch != Epoch::new(0) { - x.activation_epoch = diff.activation_epoch; + v.activation_epoch = diff.activation_epoch; } if diff.exit_epoch != Epoch::new(0) { - x.exit_epoch = diff.exit_epoch; + v.exit_epoch = diff.exit_epoch; } if diff.withdrawable_epoch != Epoch::new(0) { - x.withdrawable_epoch = diff.withdrawable_epoch; + v.withdrawable_epoch = diff.withdrawable_epoch; } + *x_arc = Arc::new(v); } else { - xs.push(diff) + xs.push(Arc::new(diff)) } } @@ -918,12 +928,12 @@ mod tests { let config = &StoreConfig::default(); let xs = (0..10) .map(|_| rand_validator(&mut rng)) + .map(Arc::new) .collect::>(); let mut ys = xs.clone(); - ys[5] = rand_validator(&mut rng); - ys.push(rand_validator(&mut rng)); + ys[5] = Arc::new(rand_validator(&mut rng)); + ys.push(Arc::new(rand_validator(&mut rng))); let diff = ValidatorsDiff::compute(&xs, &ys, config).unwrap(); - let mut xs_out = xs.clone(); diff.apply(&mut xs_out, config).unwrap(); assert_eq!(xs_out, ys); @@ -959,7 +969,10 @@ mod tests { let pre_inactivity_scores = vec![1, 1, 1]; let post_inactivity_scores = vec![0, 0, 0, 1]; - let pre_validators = (0..3).map(|_| rand_validator(&mut rng)).collect::>(); + let pre_validators = (0..3) + .map(|_| rand_validator(&mut rng)) + .map(Arc::new) + .collect::>(); let post_validators = pre_validators.clone(); let pre_historical_roots = vec![Hash256::repeat_byte(0xff)];