mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-16 03:12:41 +00:00
Directory Restructure (#1163)
* Move tests -> testing * Directory restructure * Update Cargo.toml during restructure * Update Makefile during restructure * Fix arbitrary path
This commit is contained in:
53
consensus/state_processing/src/common/deposit_data_tree.rs
Normal file
53
consensus/state_processing/src/common/deposit_data_tree.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use eth2_hashing::hash;
|
||||
use int_to_bytes::int_to_bytes32;
|
||||
use merkle_proof::{MerkleTree, MerkleTreeError};
|
||||
use safe_arith::SafeArith;
|
||||
use types::Hash256;
|
||||
|
||||
/// Emulates the eth1 deposit contract merkle tree.
|
||||
pub struct DepositDataTree {
|
||||
tree: MerkleTree,
|
||||
mix_in_length: usize,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl DepositDataTree {
|
||||
/// Create a new Merkle tree from a list of leaves (`DepositData::tree_hash_root`) and a fixed depth.
|
||||
pub fn create(leaves: &[Hash256], mix_in_length: usize, depth: usize) -> Self {
|
||||
Self {
|
||||
tree: MerkleTree::create(leaves, depth),
|
||||
mix_in_length,
|
||||
depth,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns 32 bytes representing the "mix in length" for the merkle root of this tree.
|
||||
fn length_bytes(&self) -> Vec<u8> {
|
||||
int_to_bytes32(self.mix_in_length as u64)
|
||||
}
|
||||
|
||||
/// Retrieve the root hash of this Merkle tree with the length mixed in.
|
||||
pub fn root(&self) -> Hash256 {
|
||||
let mut preimage = [0; 64];
|
||||
preimage[0..32].copy_from_slice(&self.tree.hash()[..]);
|
||||
preimage[32..64].copy_from_slice(&self.length_bytes());
|
||||
Hash256::from_slice(&hash(&preimage))
|
||||
}
|
||||
|
||||
/// Return the leaf at `index` and a Merkle proof of its inclusion.
|
||||
///
|
||||
/// The Merkle proof is in "bottom-up" order, starting with a leaf node
|
||||
/// and moving up the tree. Its length will be exactly equal to `depth + 1`.
|
||||
pub fn generate_proof(&self, index: usize) -> (Hash256, Vec<Hash256>) {
|
||||
let (root, mut proof) = self.tree.generate_proof(index, self.depth);
|
||||
proof.push(Hash256::from_slice(&self.length_bytes()));
|
||||
(root, proof)
|
||||
}
|
||||
|
||||
/// Add a deposit to the merkle tree.
|
||||
pub fn push_leaf(&mut self, leaf: Hash256) -> Result<(), MerkleTreeError> {
|
||||
self.tree.push_leaf(leaf, self.depth)?;
|
||||
self.mix_in_length.increment()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
use types::*;
|
||||
|
||||
/// Returns validator indices which participated in the attestation, sorted by increasing index.
|
||||
///
|
||||
/// Spec v0.11.1
|
||||
pub fn get_attesting_indices<T: EthSpec>(
|
||||
committee: &[usize],
|
||||
bitlist: &BitList<T::MaxValidatorsPerCommittee>,
|
||||
) -> Result<Vec<usize>, BeaconStateError> {
|
||||
if bitlist.len() != committee.len() {
|
||||
return Err(BeaconStateError::InvalidBitfield);
|
||||
}
|
||||
|
||||
let mut indices = Vec::with_capacity(bitlist.num_set_bits());
|
||||
|
||||
for (i, validator_index) in committee.iter().enumerate() {
|
||||
if let Ok(true) = bitlist.get(i) {
|
||||
indices.push(*validator_index)
|
||||
}
|
||||
}
|
||||
|
||||
indices.sort_unstable();
|
||||
|
||||
Ok(indices)
|
||||
}
|
||||
24
consensus/state_processing/src/common/get_base_reward.rs
Normal file
24
consensus/state_processing/src/common/get_base_reward.rs
Normal file
@@ -0,0 +1,24 @@
|
||||
use integer_sqrt::IntegerSquareRoot;
|
||||
use safe_arith::SafeArith;
|
||||
use types::*;
|
||||
|
||||
/// Returns the base reward for some validator.
|
||||
///
|
||||
/// Spec v0.11.1
|
||||
pub fn get_base_reward<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
index: usize,
|
||||
// Should be == get_total_active_balance(state, spec)
|
||||
total_active_balance: u64,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<u64, BeaconStateError> {
|
||||
if total_active_balance == 0 {
|
||||
Ok(0)
|
||||
} else {
|
||||
Ok(state
|
||||
.get_effective_balance(index, spec)?
|
||||
.safe_mul(spec.base_reward_factor)?
|
||||
.safe_div(total_active_balance.integer_sqrt())?
|
||||
.safe_div(spec.base_rewards_per_epoch)?)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
use super::get_attesting_indices;
|
||||
use crate::per_block_processing::errors::{AttestationInvalid as Invalid, BlockOperationError};
|
||||
use types::*;
|
||||
|
||||
type Result<T> = std::result::Result<T, BlockOperationError<Invalid>>;
|
||||
|
||||
/// Convert `attestation` to (almost) indexed-verifiable form.
|
||||
///
|
||||
/// Spec v0.11.1
|
||||
pub fn get_indexed_attestation<T: EthSpec>(
|
||||
committee: &[usize],
|
||||
attestation: &Attestation<T>,
|
||||
) -> Result<IndexedAttestation<T>> {
|
||||
let attesting_indices = get_attesting_indices::<T>(committee, &attestation.aggregation_bits)?;
|
||||
|
||||
Ok(IndexedAttestation {
|
||||
attesting_indices: VariableList::new(
|
||||
attesting_indices.into_iter().map(|x| x as u64).collect(),
|
||||
)?,
|
||||
data: attestation.data.clone(),
|
||||
signature: attestation.signature.clone(),
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
use std::cmp::max;
|
||||
use types::{BeaconStateError as Error, *};
|
||||
|
||||
/// Initiate the exit of the validator of the given `index`.
|
||||
///
|
||||
/// Spec v0.11.1
|
||||
pub fn initiate_validator_exit<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
index: usize,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
if index >= state.validators.len() {
|
||||
return Err(Error::UnknownValidator(index as u64));
|
||||
}
|
||||
|
||||
// Return if the validator already initiated exit
|
||||
if state.validators[index].exit_epoch != spec.far_future_epoch {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Ensure the exit cache is built.
|
||||
state.exit_cache.build(&state.validators, spec)?;
|
||||
|
||||
// Compute exit queue epoch
|
||||
let delayed_epoch = state.compute_activation_exit_epoch(state.current_epoch(), spec);
|
||||
let mut exit_queue_epoch = state
|
||||
.exit_cache
|
||||
.max_epoch()?
|
||||
.map_or(delayed_epoch, |epoch| max(epoch, delayed_epoch));
|
||||
let exit_queue_churn = state.exit_cache.get_churn_at(exit_queue_epoch)?;
|
||||
|
||||
if exit_queue_churn >= state.get_churn_limit(spec)? {
|
||||
exit_queue_epoch += 1;
|
||||
}
|
||||
|
||||
state.exit_cache.record_validator_exit(exit_queue_epoch)?;
|
||||
state.validators[index].exit_epoch = exit_queue_epoch;
|
||||
state.validators[index].withdrawable_epoch =
|
||||
exit_queue_epoch + spec.min_validator_withdrawability_delay;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
34
consensus/state_processing/src/common/mod.rs
Normal file
34
consensus/state_processing/src/common/mod.rs
Normal file
@@ -0,0 +1,34 @@
|
||||
mod deposit_data_tree;
|
||||
mod get_attesting_indices;
|
||||
mod get_base_reward;
|
||||
mod get_indexed_attestation;
|
||||
mod initiate_validator_exit;
|
||||
mod slash_validator;
|
||||
|
||||
pub use deposit_data_tree::DepositDataTree;
|
||||
pub use get_attesting_indices::get_attesting_indices;
|
||||
pub use get_base_reward::get_base_reward;
|
||||
pub use get_indexed_attestation::get_indexed_attestation;
|
||||
pub use initiate_validator_exit::initiate_validator_exit;
|
||||
pub use slash_validator::slash_validator;
|
||||
|
||||
use safe_arith::{ArithError, SafeArith};
|
||||
use types::{BeaconState, EthSpec};
|
||||
|
||||
/// Increase the balance of a validator, erroring upon overflow, as per the spec.
|
||||
///
|
||||
/// Spec v0.11.2
|
||||
pub fn increase_balance<E: EthSpec>(
|
||||
state: &mut BeaconState<E>,
|
||||
index: usize,
|
||||
delta: u64,
|
||||
) -> Result<(), ArithError> {
|
||||
state.balances[index].safe_add_assign(delta)
|
||||
}
|
||||
|
||||
/// Decrease the balance of a validator, saturating upon overflow, as per the spec.
|
||||
///
|
||||
/// Spec v0.11.2
|
||||
pub fn decrease_balance<E: EthSpec>(state: &mut BeaconState<E>, index: usize, delta: u64) {
|
||||
state.balances[index] = state.balances[index].saturating_sub(delta);
|
||||
}
|
||||
56
consensus/state_processing/src/common/slash_validator.rs
Normal file
56
consensus/state_processing/src/common/slash_validator.rs
Normal file
@@ -0,0 +1,56 @@
|
||||
use crate::common::{decrease_balance, increase_balance, initiate_validator_exit};
|
||||
use safe_arith::SafeArith;
|
||||
use std::cmp;
|
||||
use types::{BeaconStateError as Error, *};
|
||||
|
||||
/// Slash the validator with index ``index``.
|
||||
///
|
||||
/// Spec v0.11.1
|
||||
pub fn slash_validator<T: EthSpec>(
|
||||
state: &mut BeaconState<T>,
|
||||
slashed_index: usize,
|
||||
opt_whistleblower_index: Option<usize>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
if slashed_index >= state.validators.len() || slashed_index >= state.balances.len() {
|
||||
return Err(BeaconStateError::UnknownValidator(slashed_index as u64));
|
||||
}
|
||||
|
||||
let epoch = state.current_epoch();
|
||||
|
||||
initiate_validator_exit(state, slashed_index, spec)?;
|
||||
|
||||
state.validators[slashed_index].slashed = true;
|
||||
state.validators[slashed_index].withdrawable_epoch = cmp::max(
|
||||
state.validators[slashed_index].withdrawable_epoch,
|
||||
epoch + Epoch::from(T::EpochsPerSlashingsVector::to_u64()),
|
||||
);
|
||||
let validator_effective_balance = state.get_effective_balance(slashed_index, spec)?;
|
||||
state.set_slashings(
|
||||
epoch,
|
||||
state
|
||||
.get_slashings(epoch)?
|
||||
.safe_add(validator_effective_balance)?,
|
||||
)?;
|
||||
decrease_balance(
|
||||
state,
|
||||
slashed_index,
|
||||
validator_effective_balance.safe_div(spec.min_slashing_penalty_quotient)?,
|
||||
);
|
||||
|
||||
// Apply proposer and whistleblower rewards
|
||||
let proposer_index = state.get_beacon_proposer_index(state.slot, spec)?;
|
||||
let whistleblower_index = opt_whistleblower_index.unwrap_or(proposer_index);
|
||||
let whistleblower_reward =
|
||||
validator_effective_balance.safe_div(spec.whistleblower_reward_quotient)?;
|
||||
let proposer_reward = whistleblower_reward.safe_div(spec.proposer_reward_quotient)?;
|
||||
|
||||
increase_balance(state, proposer_index, proposer_reward)?;
|
||||
increase_balance(
|
||||
state,
|
||||
whistleblower_index,
|
||||
whistleblower_reward.safe_sub(proposer_reward)?,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user