use super::errors::{DepositInvalid as Invalid, DepositValidationError as Error}; use hashing::hash; use merkle_proof::verify_merkle_proof; use ssz::ssz_encode; use ssz_derive::Encode; use std::collections::HashMap; use types::*; pub type PublicKeyValidatorIndexHashmap = HashMap; /// Indicates if a `Deposit` is valid to be included in a block in the current epoch of the given /// state. /// /// Returns `Ok(())` if the `Deposit` is valid, otherwise indicates the reason for invalidity. /// /// This function _does not_ check `state.deposit_index` so this function may be run in parallel. /// See the `verify_deposit_index` function for this. /// /// Note: this function is incomplete. /// /// Spec v0.4.0 pub fn verify_deposit( state: &BeaconState, deposit: &Deposit, verify_merkle_branch: bool, spec: &ChainSpec, ) -> Result<(), Error> { verify!( deposit .deposit_data .deposit_input .validate_proof_of_possession( state.slot.epoch(spec.slots_per_epoch), &state.fork, spec ), Invalid::BadProofOfPossession ); if verify_merkle_branch { verify!( verify_deposit_merkle_proof(state, deposit, spec), Invalid::BadMerkleProof ); } Ok(()) } /// Verify that the `Deposit` index is correct. /// /// Spec v0.4.0 pub fn verify_deposit_index(state: &BeaconState, deposit: &Deposit) -> Result<(), Error> { verify!( deposit.index == state.deposit_index, Invalid::BadIndex(state.deposit_index, deposit.index) ); Ok(()) } pub fn build_public_key_hashmap(state: &BeaconState) -> PublicKeyValidatorIndexHashmap { let mut hashmap = HashMap::with_capacity(state.validator_registry.len()); for (i, validator) in state.validator_registry.iter().enumerate() { hashmap.insert(validator.pubkey.clone(), i as u64); } hashmap } pub fn get_existing_validator_index( state: &BeaconState, deposit: &Deposit, ) -> Result, Error> { let deposit_input = &deposit.deposit_data.deposit_input; let validator_index = state .get_validator_index(&deposit_input.pubkey)? .and_then(|i| Some(i)); match validator_index { None => Ok(None), Some(index) => { verify!( deposit_input.withdrawal_credentials == state.validator_registry[index as usize].withdrawal_credentials, Invalid::BadWithdrawalCredentials ); Ok(Some(index as u64)) } } } /// Verify that a deposit is included in the state's eth1 deposit root. /// /// Spec v0.4.0 fn verify_deposit_merkle_proof(state: &BeaconState, deposit: &Deposit, spec: &ChainSpec) -> bool { let leaf = hash(&get_serialized_deposit_data(deposit)); verify_merkle_proof( Hash256::from_slice(&leaf), &deposit.branch, spec.deposit_contract_tree_depth as usize, deposit.index as usize, state.latest_eth1_data.deposit_root, ) } /// Helper struct for easily getting the serialized data generated by the deposit contract. /// /// Spec v0.4.0 #[derive(Encode)] struct SerializedDepositData { amount: u64, timestamp: u64, input: DepositInput, } /// Return the serialized data generated by the deposit contract that is used to generate the /// merkle proof. /// /// Spec v0.4.0 fn get_serialized_deposit_data(deposit: &Deposit) -> Vec { let serialized_deposit_data = SerializedDepositData { amount: deposit.deposit_data.amount, timestamp: deposit.deposit_data.timestamp, input: deposit.deposit_data.deposit_input.clone(), }; ssz_encode(&serialized_deposit_data) }