Skip to content

Conversation

@varun-doshi
Copy link
Contributor

Added BeaconState mutators and functions

/// Decrease the validator balance at index ``index`` by ``delta`` with underflow protection.
pub fn decrease_balance(mut self, index: u64, delta: u64) {
if let Some(balance) = self.balances.get_mut(index as usize) {
*balance -= delta;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
*balance -= delta;
balance.saturating_sub(delta)

the comment says underflow protection, I am assuming that would be a saturating sub?

}

/// Decrease the validator balance at index ``index`` by ``delta`` with underflow protection.
pub fn decrease_balance(mut self, index: u64, delta: u64) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub fn decrease_balance(mut self, index: u64, delta: u64) {
pub fn decrease_balance(&mut self, index: u64, delta: u64) {

Copy link
Contributor

@KolbyML KolbyML left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here is some more feedback

Comment on lines 338 to 342
let current_epoch = self.get_current_epoch();
let mut exit_queue_epoch = exit_epochs
.into_iter()
.max()
.unwrap_or_else(|| compute_activation_exit_epoch(current_epoch));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let current_epoch = self.get_current_epoch();
let mut exit_queue_epoch = exit_epochs
.into_iter()
.max()
.unwrap_or_else(|| compute_activation_exit_epoch(current_epoch));
let mut exit_queue_epoch = exit_epochs
.into_iter()
.max()
.unwrap_or_else(|| compute_activation_exit_epoch(self.get_current_epoch()));

this isn't reused it should be inlined

Comment on lines 338 to 342
let current_epoch = self.get_current_epoch();
let mut exit_queue_epoch = exit_epochs
.into_iter()
.max()
.unwrap_or_else(|| compute_activation_exit_epoch(current_epoch));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't follow the spec no?

Suggested change
let current_epoch = self.get_current_epoch();
let mut exit_queue_epoch = exit_epochs
.into_iter()
.max()
.unwrap_or_else(|| compute_activation_exit_epoch(current_epoch));
let current_epoch = self.get_current_epoch();
let mut exit_queue_epoch = max(exit_epochs, vec![compute_activation_exit_epoch(self.get_current_epoch())]);

I think this would match the spec better

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This however returns a Vec instead of just a u64

This feels a more suitable approach:

exit_epochs.push(compute_activation_exit_epoch(self.get_current_epoch()));
let mut exit_queue_epoch = *exit_epochs.iter().max().unwrap_or(&0);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sounds good

if index as usize >= self.validators.len() {
return;
}
let exit_epochs: Vec<u64> = self
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aren't you missing this check

    if validator.exit_epoch != FAR_FUTURE_EPOCH:
        return
        

Comment on lines 365 to 366
slashed_index: usize,
whistleblower_index: Option<usize>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
slashed_index: usize,
whistleblower_index: Option<usize>,
slashed_index: u64,
whistleblower_index: Option<u64>,

these should be u64's as that is how they are defined in the spec, also then there will be less type conversions in this function so it will be cleaner to read

}

/// Slash the validator with index ``slashed_index``
pub fn slash_validator(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is outdated, please update it to follow the latest version of the spec https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#modified-slash_validator

pub const SLOTS_PER_HISTORICAL_ROOT: u64 = 8192;
pub const MIN_SEED_LOOKAHEAD: u64 = 1;
pub const MAX_COMMITTEES_PER_SLOT: u64 = 64;
pub const WHISTLEBLOWER_REWARD_QUOTIENT: u64 = 512;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WHISTLEBLOWER_REWARD_QUOTIENT should go below TARGET_COMMITTEE_SIZE

let whistleblower_index = whistleblower_index.unwrap_or(proposer_index);

let whistleblower_reward = validator.effective_balance / WHISTLEBLOWER_REWARD_QUOTIENT;
let proposer_reward = (whistleblower_reward * PROPOSER_WEIGHT) / WEIGHT_DENOMINATOR;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let proposer_reward = (whistleblower_reward * PROPOSER_WEIGHT) / WEIGHT_DENOMINATOR;
let proposer_reward = whistleblower_reward * PROPOSER_WEIGHT / WEIGHT_DENOMINATOR;

these brackets aren't needed due to order of operations

Comment on lines 374 to 392
// Mutably borrow the slashed validator
let mut binding = self.clone();
let validator = binding
.validators
.get_mut(slashed_index as usize)
.ok_or_else(|| anyhow::anyhow!("Validator at index {} not found", slashed_index))?;

validator.slashed = true;
validator.withdrawable_epoch = std::cmp::max(
validator.withdrawable_epoch,
epoch + EPOCHS_PER_SLASHINGS_VECTOR,
);

// Add slashed effective balance to the slashings vector
self.slashings[(epoch % EPOCHS_PER_SLASHINGS_VECTOR) as usize] +=
validator.effective_balance;

// Decrease validator balance
self.clone().decrease_balance(
slashed_index,
validator.effective_balance / MIN_SLASHING_PENALTY_QUOTIENT,
);
Copy link
Contributor

@KolbyML KolbyML Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Mutably borrow the slashed validator
let mut binding = self.clone();
let validator = binding
.validators
.get_mut(slashed_index as usize)
.ok_or_else(|| anyhow::anyhow!("Validator at index {} not found", slashed_index))?;
validator.slashed = true;
validator.withdrawable_epoch = std::cmp::max(
validator.withdrawable_epoch,
epoch + EPOCHS_PER_SLASHINGS_VECTOR,
);
// Add slashed effective balance to the slashings vector
self.slashings[(epoch % EPOCHS_PER_SLASHINGS_VECTOR) as usize] +=
validator.effective_balance;
// Decrease validator balance
self.clone().decrease_balance(
slashed_index,
validator.effective_balance / MIN_SLASHING_PENALTY_QUOTIENT,
);
let validator_effective_balance = if let Some(validator) = self.validators
.get_mut(slashed_index as usize) {
validator.slashed = true;
validator.withdrawable_epoch = std::cmp::max(
validator.withdrawable_epoch,
epoch + EPOCHS_PER_SLASHINGS_VECTOR,
);
validator.effective_balance
} else {
bail!("Validator at index {slashed_index} not found")
};
// Add slashed effective balance to the slashings vector
self.slashings[(epoch % EPOCHS_PER_SLASHINGS_VECTOR) as usize] +=
validator_effective_balance;
// Decrease validator balance
self.decrease_balance(
slashed_index,
validator_effective_balance / MIN_SLASHING_PENALTY_QUOTIENT,
);

You shouldn't be doing clones like this, we aren't using pointers so this code wouldn't work, the cloned object would be different then self. You would be modifying the clone, not self.

Comment on lines 374 to 399
let validator_effective_balance =
if let Some(validator) = self.validators.get_mut(slashed_index as usize) {
validator.slashed = true;
validator.withdrawable_epoch = std::cmp::max(
validator.withdrawable_epoch,
epoch + EPOCHS_PER_SLASHINGS_VECTOR,
);
validator.effective_balance
} else {
bail!("Validator at index {slashed_index} not found")
};
// Add slashed effective balance to the slashings vector
self.slashings[(epoch % EPOCHS_PER_SLASHINGS_VECTOR) as usize] +=
validator_effective_balance;
// Decrease validator balance
self.decrease_balance(
slashed_index,
validator_effective_balance / MIN_SLASHING_PENALTY_QUOTIENT,
);

// Apply proposer and whistleblower rewards
let proposer_index = self.get_beacon_proposer_index()?;
let whistleblower_index = whistleblower_index.unwrap_or(proposer_index);

let whistleblower_reward =
if let Some(validator) = self.validators.get(slashed_index as usize) {
validator.effective_balance / WHISTLEBLOWER_REWARD_QUOTIENT
} else {
bail!("Validator at index {slashed_index} not found")
};
let proposer_reward = whistleblower_reward * PROPOSER_WEIGHT / WEIGHT_DENOMINATOR;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let validator_effective_balance =
if let Some(validator) = self.validators.get_mut(slashed_index as usize) {
validator.slashed = true;
validator.withdrawable_epoch = std::cmp::max(
validator.withdrawable_epoch,
epoch + EPOCHS_PER_SLASHINGS_VECTOR,
);
validator.effective_balance
} else {
bail!("Validator at index {slashed_index} not found")
};
// Add slashed effective balance to the slashings vector
self.slashings[(epoch % EPOCHS_PER_SLASHINGS_VECTOR) as usize] +=
validator_effective_balance;
// Decrease validator balance
self.decrease_balance(
slashed_index,
validator_effective_balance / MIN_SLASHING_PENALTY_QUOTIENT,
);
// Apply proposer and whistleblower rewards
let proposer_index = self.get_beacon_proposer_index()?;
let whistleblower_index = whistleblower_index.unwrap_or(proposer_index);
let whistleblower_reward =
if let Some(validator) = self.validators.get(slashed_index as usize) {
validator.effective_balance / WHISTLEBLOWER_REWARD_QUOTIENT
} else {
bail!("Validator at index {slashed_index} not found")
};
let proposer_reward = whistleblower_reward * PROPOSER_WEIGHT / WEIGHT_DENOMINATOR;
let validator_effective_balance =
if let Some(validator) = self.validators.get_mut(slashed_index as usize) {
validator.slashed = true;
validator.withdrawable_epoch = std::cmp::max(
validator.withdrawable_epoch,
epoch + EPOCHS_PER_SLASHINGS_VECTOR,
);
validator.effective_balance
} else {
bail!("Validator at index {slashed_index} not found")
};
// Add slashed effective balance to the slashings vector
self.slashings[(epoch % EPOCHS_PER_SLASHINGS_VECTOR) as usize] +=
validator_effective_balance;
// Decrease validator balance
self.decrease_balance(
slashed_index,
validator_effective_balance / MIN_SLASHING_PENALTY_QUOTIENT,
);
// Apply proposer and whistleblower rewards
let proposer_index = self.get_beacon_proposer_index()?;
let whistleblower_index = whistleblower_index.unwrap_or(proposer_index);
let whistleblower_reward = validator_effective_balance / WHISTLEBLOWER_REWARD_QUOTIENT;
let proposer_reward = whistleblower_reward * PROPOSER_WEIGHT / WEIGHT_DENOMINATOR;

the effective balance doesn't change in this function, so we don't need to call self.validators.get() again

Copy link
Contributor

@KolbyML KolbyML left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: looks good

@KolbyML KolbyML added this pull request to the merge queue Jan 16, 2025
Merged via the queue into ReamLabs:master with commit f095027 Jan 16, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants