From 0d659c4fc5aa4a853d14cac33952fe5585404841 Mon Sep 17 00:00:00 2001 From: PoulavBhowmick03 Date: Mon, 30 Jun 2025 13:38:55 +0530 Subject: [PATCH 1/3] Optimise HDiffBuffer by using Arc instead of Vec --- beacon_node/store/src/hdiff.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/beacon_node/store/src/hdiff.rs b/beacon_node/store/src/hdiff.rs index 5731ebcbe0e..681e3f653fb 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: Arc<[Validator]>, historical_roots: Vec, historical_summaries: Vec, } @@ -184,6 +184,7 @@ impl HDiffBuffer { vec![] }; let validators = std::mem::take(beacon_state.validators_mut()).to_vec(); + let validators = Arc::from(validators); 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() { @@ -282,8 +283,11 @@ impl HDiff { self.balances_diff().apply(&mut source.balances, config)?; self.inactivity_scores_diff() .apply(&mut source.inactivity_scores, config)?; - self.validators_diff() - .apply(&mut source.validators, config)?; + + let mut validators_vec = source.validators.to_vec(); + self.validators_diff().apply(&mut validators_vec, config)?; + source.validators = Arc::from(validators_vec); + self.historical_roots().apply(&mut source.historical_roots); self.historical_summaries() .apply(&mut source.historical_summaries); @@ -972,7 +976,7 @@ mod tests { state: vec![0, 1, 2, 3, 3, 2, 1, 0], balances: pre_balances, inactivity_scores: pre_inactivity_scores, - validators: pre_validators, + validators: Arc::from(pre_validators), historical_roots: pre_historical_roots, historical_summaries: pre_historical_summaries, }; @@ -980,7 +984,7 @@ mod tests { state: vec![0, 1, 3, 2, 2, 3, 1, 1], balances: post_balances, inactivity_scores: post_inactivity_scores, - validators: post_validators, + validators: Arc::from(post_validators), historical_roots: post_historical_roots, historical_summaries: post_historical_summaries, }; From f04a93243345fc73648d28577db4ad791b5dd2d1 Mon Sep 17 00:00:00 2001 From: PoulavBhowmick03 Date: Mon, 30 Jun 2025 17:08:41 +0530 Subject: [PATCH 2/3] changed Arc[Validator] to Vec> and modified the compute and apply functions, alongside tests --- beacon_node/store/src/hdiff.rs | 51 ++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/beacon_node/store/src/hdiff.rs b/beacon_node/store/src/hdiff.rs index 681e3f653fb..f74c3049763 100644 --- a/beacon_node/store/src/hdiff.rs +++ b/beacon_node/store/src/hdiff.rs @@ -100,7 +100,7 @@ pub struct HDiffBuffer { state: Vec, balances: Vec, inactivity_scores: Vec, - validators: Arc<[Validator]>, + validators: Vec>, historical_roots: Vec, historical_summaries: Vec, } @@ -183,8 +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 = Arc::from(validators); + 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() { @@ -222,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)?; @@ -283,10 +287,8 @@ impl HDiff { self.balances_diff().apply(&mut source.balances, config)?; self.inactivity_scores_diff() .apply(&mut source.inactivity_scores, config)?; - - let mut validators_vec = source.validators.to_vec(); - self.validators_diff().apply(&mut validators_vec, config)?; - source.validators = Arc::from(validators_vec); + self.validators_diff() + .apply(&mut source.validators, config)?; self.historical_roots().apply(&mut source.historical_roots); self.historical_summaries() @@ -450,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() { @@ -461,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 { @@ -542,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 @@ -554,7 +558,8 @@ 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 x = (**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. @@ -584,7 +589,7 @@ impl ValidatorsDiff { x.withdrawable_epoch = diff.withdrawable_epoch; } } else { - xs.push(diff) + xs.push(Arc::new(diff)) } } @@ -922,10 +927,11 @@ 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(); @@ -963,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)]; @@ -976,7 +985,7 @@ mod tests { state: vec![0, 1, 2, 3, 3, 2, 1, 0], balances: pre_balances, inactivity_scores: pre_inactivity_scores, - validators: Arc::from(pre_validators), + validators: pre_validators, historical_roots: pre_historical_roots, historical_summaries: pre_historical_summaries, }; @@ -984,7 +993,7 @@ mod tests { state: vec![0, 1, 3, 2, 2, 3, 1, 1], balances: post_balances, inactivity_scores: post_inactivity_scores, - validators: Arc::from(post_validators), + validators: post_validators, historical_roots: post_historical_roots, historical_summaries: post_historical_summaries, }; From 1a1bb09640c5b887e7ef275a4c7e0c26a7fd6c74 Mon Sep 17 00:00:00 2001 From: PoulavBhowmick03 Date: Mon, 7 Jul 2025 00:01:37 +0530 Subject: [PATCH 3/3] fix: test-compressed_validators_diff --- beacon_node/store/src/hdiff.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/beacon_node/store/src/hdiff.rs b/beacon_node/store/src/hdiff.rs index f74c3049763..0573ce05229 100644 --- a/beacon_node/store/src/hdiff.rs +++ b/beacon_node/store/src/hdiff.rs @@ -559,35 +559,36 @@ impl ValidatorsDiff { .map_err(|_| Error::BalancesIncompleteChunk)?; if let Some(x_arc) = xs.get_mut(index as usize) { - let mut x = (**x_arc).clone(); + 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(Arc::new(diff)) } @@ -933,7 +934,6 @@ mod tests { 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);