From deb3836effd62f100a94fb193d08ff857e45cd37 Mon Sep 17 00:00:00 2001 From: Wei Tang Date: Thu, 2 May 2019 18:34:08 +0200 Subject: [PATCH] update v0.6: high/low balance separation (https://github.com/ethereum/eth2.0-specs/pull/728) --- beacon/src/config.rs | 12 ++++++------ beacon/src/executive/mod.rs | 31 +++++++++++++++++++++++++++++-- beacon/src/executive/per_block.rs | 22 +++++++++++++--------- beacon/src/executive/per_epoch.rs | 10 ++++++---- beacon/src/state.rs | 4 ++-- beacon/src/validator.rs | 2 ++ 6 files changed, 58 insertions(+), 23 deletions(-) diff --git a/beacon/src/config.rs b/beacon/src/config.rs index 99c32611..07bfe163 100644 --- a/beacon/src/config.rs +++ b/beacon/src/config.rs @@ -35,7 +35,7 @@ pub trait Config { /// Maximum deposit amount. fn max_deposit_amount(&self) -> Gwei; /// Fork choice balance increment. - fn fork_choice_balance_increment(&self) -> Gwei; + fn high_balance_increment(&self) -> Gwei; /// Ejection balance. fn ejection_balance(&self) -> Gwei; /// Genesis fork version. @@ -241,8 +241,8 @@ pub struct NoVerificationConfig { pub min_deposit_amount: Gwei, /// Maximum deposit amount. pub max_deposit_amount: Gwei, - /// Fork choice balance increment. - pub fork_choice_balance_increment: Gwei, + /// High balance increment. + pub high_balance_increment: Gwei, /// Ejection balance. pub ejection_balance: Gwei, /// Genesis fork version. @@ -327,7 +327,7 @@ impl Config for NoVerificationConfig { fn deposit_contract_tree_depth(&self) -> usize { self.deposit_contract_tree_depth } fn min_deposit_amount(&self) -> Gwei { self.min_deposit_amount } fn max_deposit_amount(&self) -> Gwei { self.max_deposit_amount } - fn fork_choice_balance_increment(&self) -> Gwei { self.fork_choice_balance_increment } + fn high_balance_increment(&self) -> Gwei { self.high_balance_increment } fn ejection_balance(&self) -> Gwei { self.ejection_balance } fn genesis_fork_version(&self) -> Version { Version::from(self.genesis_fork_version) } fn genesis_slot(&self) -> Slot { self.genesis_slot } @@ -401,7 +401,7 @@ impl NoVerificationConfig { deposit_contract_tree_depth: 32, min_deposit_amount: 1_000_000_000, max_deposit_amount: 32_000_000_000, - fork_choice_balance_increment: 1_000_000_000, + high_balance_increment: 1_000_000_000, ejection_balance: 16_000_000_000, genesis_fork_version: [0, 0, 0, 0], genesis_slot: 4294967296, @@ -452,7 +452,7 @@ impl NoVerificationConfig { deposit_contract_tree_depth: 32, min_deposit_amount: 1_000_000_000, max_deposit_amount: 32_000_000_000, - fork_choice_balance_increment: 1_000_000_000, + high_balance_increment: 1_000_000_000, ejection_balance: 16_000_000_000, genesis_fork_version: [0, 0, 0, 0], genesis_slot: 4294967296, diff --git a/beacon/src/executive/mod.rs b/beacon/src/executive/mod.rs index 65af64b2..e6885437 100644 --- a/beacon/src/executive/mod.rs +++ b/beacon/src/executive/mod.rs @@ -155,8 +155,35 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { Ok(self.earliest_attestation(index)?.inclusion_slot) } + fn balance(&self, index: ValidatorIndex) -> Gwei { + self.state.balances[index as usize] + } + + fn set_balance(&mut self, index: ValidatorIndex, balance: Gwei) { + let half_increment = self.config.high_balance_increment() / 2; + + let validator = &mut self.state.validator_registry[index as usize]; + if validator.high_balance > balance || validator.high_balance + 3 * half_increment < balance { + validator.high_balance = balance - balance % self.config.high_balance_increment(); + } + self.state.balances[index as usize] = balance; + } + + fn increase_balance(&mut self, index: ValidatorIndex, delta: Gwei) { + self.set_balance(index, self.balance(index) + delta); + } + + fn decrease_balance(&mut self, index: ValidatorIndex, delta: Gwei) { + let cur_balance = self.balance(index); + self.set_balance(index, if cur_balance >= delta { + cur_balance - delta + } else { + 0 + }); + } + fn effective_balance(&self, index: ValidatorIndex) -> Gwei { - core::cmp::min(self.state.validator_balances[index as usize], self.config.max_deposit_amount()) + core::cmp::min(self.balance(index), self.config.max_deposit_amount()) } fn total_balance(&self, indices: &[ValidatorIndex]) -> Gwei { @@ -309,7 +336,7 @@ pub fn genesis_state(deposits: Vec, genesis_time: Timestamp, }, validator_registry: Vec::new(), - validator_balances: Vec::new(), + balances: Vec::new(), validator_registry_update_epoch: config.genesis_epoch(), latest_randao_mixes: { diff --git a/beacon/src/executive/per_block.rs b/beacon/src/executive/per_block.rs index f04f38f5..fd3fe140 100644 --- a/beacon/src/executive/per_block.rs +++ b/beacon/src/executive/per_block.rs @@ -20,8 +20,8 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { let whistleblower_index = self.beacon_proposer_index(self.state.slot, false)?; let whistleblower_reward = self.effective_balance(index) / self.config.whistleblower_reward_quotient(); - self.state.validator_balances[whistleblower_index as usize] += whistleblower_reward; - self.state.validator_balances[index as usize] -= whistleblower_reward; + self.increase_balance(whistleblower_index, whistleblower_reward); + self.decrease_balance(index, whistleblower_reward); self.state.validator_registry[index as usize].slashed = true; self.state.validator_registry[index as usize].withdrawable_epoch = self.current_epoch() + self.config.latest_slashed_exit_length() as u64; @@ -324,7 +324,7 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { match self.state.validator_index_by_id(&deposit.deposit_data.deposit_input.pubkey) { Some(index) => { - self.state.validator_balances[index as usize] += deposit.deposit_data.amount; + self.increase_balance(index, deposit.deposit_data.amount); }, None => { if !deposit.is_proof_valid( @@ -342,10 +342,14 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { withdrawable_epoch: self.config.far_future_epoch(), initiated_exit: false, slashed: false, + high_balance: 0, }; + let validator_index = self.state.validator_registry.len() as u64; self.state.validator_registry.push(validator); - self.state.validator_balances.push(deposit.deposit_data.amount); + self.state.balances.push(0); + + self.set_balance(validator_index, deposit.deposit_data.amount); }, } @@ -389,11 +393,11 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { /// Push a new `Transfer` to the state. pub fn push_transfer(&mut self, transfer: Transfer) -> Result<(), Error> { - if self.state.validator_balances[transfer.sender as usize] < core::cmp::max(transfer.amount, transfer.fee) { + if self.balance(transfer.sender) < core::cmp::max(transfer.amount, transfer.fee) { return Err(Error::TransferNoFund) } - if !(self.state.validator_balances[transfer.sender as usize] == transfer.amount + transfer.fee || self.state.validator_balances[transfer.sender as usize] >= transfer.amount + transfer.fee + self.config.min_deposit_amount()) { + if !(self.balance(transfer.sender) == transfer.amount + transfer.fee || self.balance(transfer.sender) >= transfer.amount + transfer.fee + self.config.min_deposit_amount()) { return Err(Error::TransferNoFund) } @@ -418,10 +422,10 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { return Err(Error::TransferInvalidSignature) } - self.state.validator_balances[transfer.sender as usize] -= transfer.amount + transfer.fee; - self.state.validator_balances[transfer.recipient as usize] += transfer.amount; + self.decrease_balance(transfer.sender, transfer.amount + transfer.fee); + self.increase_balance(transfer.recipient, transfer.amount); let proposer_index = self.beacon_proposer_index(self.state.slot, false)?; - self.state.validator_balances[proposer_index as usize] += transfer.fee; + self.increase_balance(proposer_index, transfer.fee); Ok(()) } diff --git a/beacon/src/executive/per_epoch.rs b/beacon/src/executive/per_epoch.rs index 2842637d..b377928d 100644 --- a/beacon/src/executive/per_epoch.rs +++ b/beacon/src/executive/per_epoch.rs @@ -290,7 +290,9 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { let delta1 = self.justification_and_finalization_deltas()?; let delta2 = self.crosslink_deltas()?; for i in 0..self.state.validator_registry.len() { - self.state.validator_balances[i] = (self.state.validator_balances[i] + delta1.0[i] + delta2.0[i]).saturating_sub(delta1.1[i] + delta2.1[i]); + let new_balance = (self.balance(i as u64) + delta1.0[i] + delta2.0[i]) + .saturating_sub(delta1.1[i] + delta2.1[i]); + self.set_balance(i as u64, new_balance); } Ok(()) @@ -299,7 +301,7 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { /// Update validator ejections. pub fn update_ejections(&mut self) { for index in self.state.active_validator_indices(self.current_epoch()) { - if self.state.validator_balances[index as usize] < self.config.ejection_balance() { + if self.balance(index) < self.config.ejection_balance() { self.initiate_validator_exit(index); } } @@ -333,7 +335,7 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { let mut balance_churn = 0; for (i, validator) in self.state.validator_registry.clone().into_iter().enumerate() { let index = i as u64; - if validator.activation_epoch == self.config.far_future_epoch() && self.state.validator_balances[i] >= self.config.max_deposit_amount() { + if validator.activation_epoch == self.config.far_future_epoch() && self.balance(index) >= self.config.max_deposit_amount() { balance_churn += self.effective_balance(index); if balance_churn > max_balance_churn { break @@ -407,7 +409,7 @@ impl<'state, 'config, C: Config> Executive<'state, 'config, C> { self.effective_balance(index) * core::cmp::min(total_penalties * 3, total_balance) / total_balance, self.effective_balance(index) / self.config.min_penalty_quotient() ); - self.state.validator_balances[i] -= penalty; + self.decrease_balance(index, penalty); } } } diff --git a/beacon/src/state.rs b/beacon/src/state.rs index e62e4680..fc4825d7 100644 --- a/beacon/src/state.rs +++ b/beacon/src/state.rs @@ -47,8 +47,8 @@ pub struct BeaconState { /// Validator registry. pub validator_registry: Vec, - /// Validator balances. - pub validator_balances: Vec, + /// Balances. + pub balances: Vec, /// Last validator registry update epoch. pub validator_registry_update_epoch: Epoch, diff --git a/beacon/src/validator.rs b/beacon/src/validator.rs index a4325bd6..b365ce42 100644 --- a/beacon/src/validator.rs +++ b/beacon/src/validator.rs @@ -44,6 +44,8 @@ pub struct Validator { pub initiated_exit: bool, /// Was the validator slashed pub slashed: bool, + /// High balance + pub high_balance: u64, } impl Validator {