2019-05-22 01:41:15 +00:00
|
|
|
use crate::common::{initiate_validator_exit, slash_validator};
|
2019-03-06 06:14:54 +00:00
|
|
|
use errors::{BlockInvalid as Invalid, BlockProcessingError as Error, IntoWithIndex};
|
2019-03-09 21:33:17 +00:00
|
|
|
use rayon::prelude::*;
|
2019-04-16 04:25:43 +00:00
|
|
|
use tree_hash::{SignedRoot, TreeHash};
|
2019-03-06 04:22:45 +00:00
|
|
|
use types::*;
|
|
|
|
|
2019-05-21 06:40:48 +00:00
|
|
|
pub use self::verify_attester_slashing::{get_slashable_indices, verify_attester_slashing};
|
2019-03-06 03:46:12 +00:00
|
|
|
pub use self::verify_proposer_slashing::verify_proposer_slashing;
|
2019-03-20 05:52:58 +00:00
|
|
|
pub use validate_attestation::{
|
|
|
|
validate_attestation, validate_attestation_time_independent_only,
|
|
|
|
validate_attestation_without_signature,
|
|
|
|
};
|
2019-05-22 08:54:26 +00:00
|
|
|
pub use verify_deposit::{
|
|
|
|
get_existing_validator_index, verify_deposit_index, verify_deposit_merkle_proof,
|
|
|
|
verify_deposit_signature,
|
|
|
|
};
|
2019-03-20 04:57:41 +00:00
|
|
|
pub use verify_exit::{verify_exit, verify_exit_time_independent_only};
|
2019-05-21 06:38:16 +00:00
|
|
|
pub use verify_indexed_attestation::{
|
|
|
|
verify_indexed_attestation, verify_indexed_attestation_without_signature,
|
|
|
|
};
|
2019-03-20 05:13:06 +00:00
|
|
|
pub use verify_transfer::{
|
|
|
|
execute_transfer, verify_transfer, verify_transfer_time_independent_only,
|
|
|
|
};
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-06 06:14:54 +00:00
|
|
|
pub mod errors;
|
2019-03-06 04:22:45 +00:00
|
|
|
mod validate_attestation;
|
|
|
|
mod verify_attester_slashing;
|
|
|
|
mod verify_deposit;
|
|
|
|
mod verify_exit;
|
2019-05-13 07:28:04 +00:00
|
|
|
mod verify_indexed_attestation;
|
2019-03-06 04:22:45 +00:00
|
|
|
mod verify_proposer_slashing;
|
|
|
|
mod verify_transfer;
|
|
|
|
|
2019-03-06 05:24:56 +00:00
|
|
|
/// Updates the state for a new block, whilst validating that the block is valid.
|
|
|
|
///
|
|
|
|
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
|
|
|
|
/// returns an error describing why the block was invalid or how the function failed to execute.
|
|
|
|
///
|
2019-05-22 02:17:40 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn per_block_processing<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-06 04:22:45 +00:00
|
|
|
block: &BeaconBlock,
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
per_block_processing_signature_optional(state, block, true, spec)
|
|
|
|
}
|
|
|
|
|
2019-03-06 05:24:56 +00:00
|
|
|
/// Updates the state for a new block, whilst validating that the block is valid, without actually
|
|
|
|
/// checking the block proposer signature.
|
|
|
|
///
|
|
|
|
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
|
|
|
|
/// returns an error describing why the block was invalid or how the function failed to execute.
|
|
|
|
///
|
2019-05-22 02:17:40 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn per_block_processing_without_verifying_block_signature<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-06 04:22:45 +00:00
|
|
|
block: &BeaconBlock,
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
per_block_processing_signature_optional(state, block, false, spec)
|
|
|
|
}
|
|
|
|
|
2019-03-06 05:24:56 +00:00
|
|
|
/// Updates the state for a new block, whilst validating that the block is valid, optionally
|
|
|
|
/// checking the block proposer signature.
|
|
|
|
///
|
|
|
|
/// Returns `Ok(())` if the block is valid and the state was successfully updated. Otherwise
|
|
|
|
/// returns an error describing why the block was invalid or how the function failed to execute.
|
|
|
|
///
|
2019-05-22 02:17:40 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
fn per_block_processing_signature_optional<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
mut state: &mut BeaconState<T>,
|
2019-03-06 04:22:45 +00:00
|
|
|
block: &BeaconBlock,
|
|
|
|
should_verify_block_signature: bool,
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
2019-03-17 01:25:37 +00:00
|
|
|
process_block_header(state, block, spec)?;
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-05-22 02:17:40 +00:00
|
|
|
// Ensure the current and previous epoch caches are built.
|
2019-05-20 04:36:54 +00:00
|
|
|
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
|
|
|
|
state.build_committee_cache(RelativeEpoch::Current, spec)?;
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
if should_verify_block_signature {
|
|
|
|
verify_block_signature(&state, &block, &spec)?;
|
|
|
|
}
|
|
|
|
process_randao(&mut state, &block, &spec)?;
|
2019-05-20 02:42:02 +00:00
|
|
|
process_eth1_data(&mut state, &block.body.eth1_data, spec)?;
|
2019-03-09 03:11:49 +00:00
|
|
|
process_proposer_slashings(&mut state, &block.body.proposer_slashings, spec)?;
|
|
|
|
process_attester_slashings(&mut state, &block.body.attester_slashings, spec)?;
|
|
|
|
process_attestations(&mut state, &block.body.attestations, spec)?;
|
|
|
|
process_deposits(&mut state, &block.body.deposits, spec)?;
|
|
|
|
process_exits(&mut state, &block.body.voluntary_exits, spec)?;
|
|
|
|
process_transfers(&mut state, &block.body.transfers, spec)?;
|
2019-03-06 06:03:18 +00:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-03-17 01:25:37 +00:00
|
|
|
/// Processes the block header.
|
|
|
|
///
|
2019-05-20 02:42:02 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn process_block_header<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-17 01:25:37 +00:00
|
|
|
block: &BeaconBlock,
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
verify!(block.slot == state.slot, Invalid::StateSlotMismatch);
|
|
|
|
|
2019-04-17 03:59:40 +00:00
|
|
|
let expected_previous_block_root =
|
|
|
|
Hash256::from_slice(&state.latest_block_header.signed_root());
|
2019-03-17 01:25:37 +00:00
|
|
|
verify!(
|
2019-04-17 03:59:40 +00:00
|
|
|
block.previous_block_root == expected_previous_block_root,
|
|
|
|
Invalid::ParentBlockRootMismatch {
|
|
|
|
state: expected_previous_block_root,
|
|
|
|
block: block.previous_block_root,
|
|
|
|
}
|
2019-03-17 01:25:37 +00:00
|
|
|
);
|
|
|
|
|
2019-03-19 23:51:53 +00:00
|
|
|
state.latest_block_header = block.temporary_block_header(spec);
|
2019-03-17 01:25:37 +00:00
|
|
|
|
2019-05-20 02:42:02 +00:00
|
|
|
// Verify proposer is not slashed
|
|
|
|
let proposer_idx = state.get_beacon_proposer_index(block.slot, RelativeEpoch::Current, spec)?;
|
|
|
|
let proposer = &state.validator_registry[proposer_idx];
|
|
|
|
verify!(!proposer.slashed, Invalid::ProposerSlashed(proposer_idx));
|
|
|
|
|
2019-03-17 01:25:37 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
/// Verifies the signature of a block.
|
|
|
|
///
|
2019-05-20 02:42:02 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn verify_block_signature<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &BeaconState<T>,
|
2019-03-06 06:03:18 +00:00
|
|
|
block: &BeaconBlock,
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
2019-03-17 01:25:37 +00:00
|
|
|
let block_proposer = &state.validator_registry
|
|
|
|
[state.get_beacon_proposer_index(block.slot, RelativeEpoch::Current, spec)?];
|
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
let domain = spec.get_domain(
|
|
|
|
block.slot.epoch(spec.slots_per_epoch),
|
2019-05-20 02:42:02 +00:00
|
|
|
Domain::BeaconProposer,
|
2019-03-06 06:03:18 +00:00
|
|
|
&state.fork,
|
|
|
|
);
|
|
|
|
|
|
|
|
verify!(
|
2019-03-17 01:25:37 +00:00
|
|
|
block
|
2019-03-06 06:03:18 +00:00
|
|
|
.signature
|
2019-03-17 01:25:37 +00:00
|
|
|
.verify(&block.signed_root()[..], domain, &block_proposer.pubkey),
|
2019-03-06 06:03:18 +00:00
|
|
|
Invalid::BadSignature
|
|
|
|
);
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Verifies the `randao_reveal` against the block's proposer pubkey and updates
|
|
|
|
/// `state.latest_randao_mixes`.
|
|
|
|
///
|
2019-05-20 02:42:02 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn process_randao<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-06 06:03:18 +00:00
|
|
|
block: &BeaconBlock,
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
2019-03-17 01:25:37 +00:00
|
|
|
let block_proposer = &state.validator_registry
|
|
|
|
[state.get_beacon_proposer_index(block.slot, RelativeEpoch::Current, spec)?];
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-17 01:25:37 +00:00
|
|
|
// Verify the RANDAO is a valid signature of the proposer.
|
2019-03-06 04:22:45 +00:00
|
|
|
verify!(
|
2019-03-17 01:25:37 +00:00
|
|
|
block.body.randao_reveal.verify(
|
2019-05-19 05:56:24 +00:00
|
|
|
&state.current_epoch().tree_hash_root()[..],
|
2019-03-06 06:03:18 +00:00
|
|
|
spec.get_domain(
|
|
|
|
block.slot.epoch(spec.slots_per_epoch),
|
|
|
|
Domain::Randao,
|
|
|
|
&state.fork
|
|
|
|
),
|
2019-03-06 04:22:45 +00:00
|
|
|
&block_proposer.pubkey
|
|
|
|
),
|
|
|
|
Invalid::BadRandaoSignature
|
|
|
|
);
|
|
|
|
|
2019-03-17 01:25:37 +00:00
|
|
|
// Update the current epoch RANDAO mix.
|
2019-05-20 02:42:02 +00:00
|
|
|
state.update_randao_mix(state.current_epoch(), &block.body.randao_reveal)?;
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
/// Update the `state.eth1_data_votes` based upon the `eth1_data` provided.
|
|
|
|
///
|
2019-05-20 02:42:02 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn process_eth1_data<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
|
|
|
eth1_data: &Eth1Data,
|
2019-05-20 02:42:02 +00:00
|
|
|
spec: &ChainSpec,
|
2019-05-08 05:36:02 +00:00
|
|
|
) -> Result<(), Error> {
|
2019-05-20 02:42:02 +00:00
|
|
|
state.eth1_data_votes.push(eth1_data.clone());
|
|
|
|
|
|
|
|
let num_votes = state
|
2019-03-06 04:22:45 +00:00
|
|
|
.eth1_data_votes
|
|
|
|
.iter()
|
2019-05-20 02:42:02 +00:00
|
|
|
.filter(|vote| *vote == eth1_data)
|
|
|
|
.count() as u64;
|
|
|
|
|
|
|
|
if num_votes * 2 > spec.slots_per_eth1_voting_period {
|
|
|
|
state.latest_eth1_data = eth1_data.clone();
|
2019-03-06 04:22:45 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Validates each `ProposerSlashing` and updates the state, short-circuiting on an invalid object.
|
|
|
|
///
|
|
|
|
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
|
|
|
/// an `Err` describing the invalid object or cause of failure.
|
|
|
|
///
|
2019-05-20 05:08:20 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn process_proposer_slashings<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-06 06:03:18 +00:00
|
|
|
proposer_slashings: &[ProposerSlashing],
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
2019-03-06 04:22:45 +00:00
|
|
|
verify!(
|
2019-03-06 06:03:18 +00:00
|
|
|
proposer_slashings.len() as u64 <= spec.max_proposer_slashings,
|
2019-03-06 04:22:45 +00:00
|
|
|
Invalid::MaxProposerSlashingsExceeded
|
|
|
|
);
|
2019-03-09 21:33:17 +00:00
|
|
|
|
|
|
|
// Verify proposer slashings in parallel.
|
|
|
|
proposer_slashings
|
|
|
|
.par_iter()
|
|
|
|
.enumerate()
|
|
|
|
.try_for_each(|(i, proposer_slashing)| {
|
|
|
|
verify_proposer_slashing(proposer_slashing, &state, spec)
|
|
|
|
.map_err(|e| e.into_with_index(i))
|
|
|
|
})?;
|
|
|
|
|
2019-03-17 01:25:37 +00:00
|
|
|
// Update the state.
|
2019-03-09 21:33:17 +00:00
|
|
|
for proposer_slashing in proposer_slashings {
|
2019-05-20 05:08:20 +00:00
|
|
|
slash_validator(state, proposer_slashing.proposer_index as usize, None, spec)?;
|
2019-03-06 04:22:45 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-05-20 05:08:20 +00:00
|
|
|
/// Validates each `AttesterSlashing` and updates the state, short-circuiting on an invalid object.
|
2019-03-06 06:03:18 +00:00
|
|
|
///
|
|
|
|
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
|
|
|
/// an `Err` describing the invalid object or cause of failure.
|
|
|
|
///
|
2019-05-20 05:08:20 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn process_attester_slashings<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-06 06:03:18 +00:00
|
|
|
attester_slashings: &[AttesterSlashing],
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
2019-03-06 04:22:45 +00:00
|
|
|
verify!(
|
2019-03-06 06:03:18 +00:00
|
|
|
attester_slashings.len() as u64 <= spec.max_attester_slashings,
|
2019-03-06 04:22:45 +00:00
|
|
|
Invalid::MaxAttesterSlashingsExceed
|
|
|
|
);
|
2019-03-09 21:33:17 +00:00
|
|
|
|
2019-05-13 07:28:04 +00:00
|
|
|
// Verify the `IndexedAttestation`s in parallel (these are the resource-consuming objects, not
|
2019-03-09 21:55:45 +00:00
|
|
|
// the `AttesterSlashing`s themselves).
|
2019-05-13 07:28:04 +00:00
|
|
|
let mut indexed_attestations: Vec<&IndexedAttestation> =
|
2019-03-09 21:55:45 +00:00
|
|
|
Vec::with_capacity(attester_slashings.len() * 2);
|
|
|
|
for attester_slashing in attester_slashings {
|
2019-05-13 07:28:04 +00:00
|
|
|
indexed_attestations.push(&attester_slashing.attestation_1);
|
|
|
|
indexed_attestations.push(&attester_slashing.attestation_2);
|
2019-03-09 21:55:45 +00:00
|
|
|
}
|
|
|
|
|
2019-05-13 07:28:04 +00:00
|
|
|
// Verify indexed attestations in parallel.
|
|
|
|
indexed_attestations
|
2019-03-09 21:33:17 +00:00
|
|
|
.par_iter()
|
|
|
|
.enumerate()
|
2019-05-13 07:28:04 +00:00
|
|
|
.try_for_each(|(i, indexed_attestation)| {
|
|
|
|
verify_indexed_attestation(&state, indexed_attestation, spec)
|
2019-03-09 21:33:17 +00:00
|
|
|
.map_err(|e| e.into_with_index(i))
|
|
|
|
})?;
|
2019-05-13 07:28:04 +00:00
|
|
|
let all_indexed_attestations_have_been_checked = true;
|
2019-03-09 21:33:17 +00:00
|
|
|
|
2019-05-13 07:28:04 +00:00
|
|
|
// Gather the indexed indices and preform the final verification and update the state in series.
|
2019-03-06 06:03:18 +00:00
|
|
|
for (i, attester_slashing) in attester_slashings.iter().enumerate() {
|
2019-05-13 07:28:04 +00:00
|
|
|
let should_verify_indexed_attestations = !all_indexed_attestations_have_been_checked;
|
2019-03-09 21:55:45 +00:00
|
|
|
|
|
|
|
verify_attester_slashing(
|
|
|
|
&state,
|
|
|
|
&attester_slashing,
|
2019-05-13 07:28:04 +00:00
|
|
|
should_verify_indexed_attestations,
|
2019-03-09 21:55:45 +00:00
|
|
|
spec,
|
|
|
|
)
|
|
|
|
.map_err(|e| e.into_with_index(i))?;
|
|
|
|
|
2019-05-20 05:08:20 +00:00
|
|
|
let slashable_indices = get_slashable_indices(&state, &attester_slashing, spec)
|
2019-03-06 04:22:45 +00:00
|
|
|
.map_err(|e| e.into_with_index(i))?;
|
2019-03-09 21:55:45 +00:00
|
|
|
|
2019-05-21 06:40:48 +00:00
|
|
|
for i in slashable_indices {
|
2019-05-20 05:08:20 +00:00
|
|
|
slash_validator(state, i as usize, None, spec)?;
|
2019-03-06 04:22:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
/// Validates each `Attestation` and updates the state, short-circuiting on an invalid object.
|
|
|
|
///
|
|
|
|
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
|
|
|
/// an `Err` describing the invalid object or cause of failure.
|
|
|
|
///
|
2019-05-21 06:38:16 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn process_attestations<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-06 06:03:18 +00:00
|
|
|
attestations: &[Attestation],
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
2019-03-06 04:22:45 +00:00
|
|
|
verify!(
|
2019-03-06 06:03:18 +00:00
|
|
|
attestations.len() as u64 <= spec.max_attestations,
|
2019-03-06 04:22:45 +00:00
|
|
|
Invalid::MaxAttestationsExceeded
|
|
|
|
);
|
|
|
|
|
2019-03-09 21:33:17 +00:00
|
|
|
// Ensure the previous epoch cache exists.
|
2019-05-20 04:36:54 +00:00
|
|
|
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
|
2019-03-09 21:33:17 +00:00
|
|
|
|
|
|
|
// Verify attestations in parallel.
|
|
|
|
attestations
|
|
|
|
.par_iter()
|
|
|
|
.enumerate()
|
|
|
|
.try_for_each(|(i, attestation)| {
|
|
|
|
validate_attestation(state, attestation, spec).map_err(|e| e.into_with_index(i))
|
|
|
|
})?;
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-09 21:33:17 +00:00
|
|
|
// Update the state in series.
|
2019-05-21 06:38:16 +00:00
|
|
|
let proposer_index =
|
|
|
|
state.get_beacon_proposer_index(state.slot, RelativeEpoch::Current, spec)? as u64;
|
2019-03-09 21:33:17 +00:00
|
|
|
for attestation in attestations {
|
2019-05-21 06:38:16 +00:00
|
|
|
let attestation_slot = state.get_attestation_slot(&attestation.data)?;
|
|
|
|
let pending_attestation = PendingAttestation {
|
|
|
|
aggregation_bitfield: attestation.aggregation_bitfield.clone(),
|
|
|
|
data: attestation.data.clone(),
|
|
|
|
inclusion_delay: (state.slot - attestation_slot).as_u64(),
|
|
|
|
proposer_index,
|
|
|
|
};
|
|
|
|
|
|
|
|
if attestation.data.target_epoch == state.current_epoch() {
|
2019-03-17 01:25:37 +00:00
|
|
|
state.current_epoch_attestations.push(pending_attestation)
|
2019-05-21 06:38:16 +00:00
|
|
|
} else {
|
2019-03-17 01:25:37 +00:00
|
|
|
state.previous_epoch_attestations.push(pending_attestation)
|
|
|
|
}
|
2019-03-06 04:22:45 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
/// Validates each `Deposit` and updates the state, short-circuiting on an invalid object.
|
|
|
|
///
|
|
|
|
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
|
|
|
/// an `Err` describing the invalid object or cause of failure.
|
|
|
|
///
|
2019-05-21 08:02:31 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn process_deposits<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-06 06:03:18 +00:00
|
|
|
deposits: &[Deposit],
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
2019-03-06 04:22:45 +00:00
|
|
|
verify!(
|
2019-05-21 08:02:31 +00:00
|
|
|
deposits.len() as u64
|
|
|
|
== std::cmp::min(
|
|
|
|
spec.max_deposits,
|
|
|
|
state.latest_eth1_data.deposit_count - state.deposit_index
|
|
|
|
),
|
|
|
|
Invalid::DepositCountInvalid
|
2019-03-06 04:22:45 +00:00
|
|
|
);
|
|
|
|
|
2019-03-09 21:33:17 +00:00
|
|
|
// Verify deposits in parallel.
|
|
|
|
deposits
|
|
|
|
.par_iter()
|
|
|
|
.enumerate()
|
|
|
|
.try_for_each(|(i, deposit)| {
|
2019-05-22 08:54:26 +00:00
|
|
|
verify_deposit_merkle_proof(state, deposit, spec).map_err(|e| e.into_with_index(i))
|
2019-03-09 21:33:17 +00:00
|
|
|
})?;
|
|
|
|
|
|
|
|
// Check `state.deposit_index` and update the state in series.
|
|
|
|
for (i, deposit) in deposits.iter().enumerate() {
|
|
|
|
verify_deposit_index(state, deposit).map_err(|e| e.into_with_index(i))?;
|
|
|
|
|
2019-05-22 08:54:26 +00:00
|
|
|
state.deposit_index += 1;
|
|
|
|
|
2019-03-13 05:40:28 +00:00
|
|
|
// Ensure the state's pubkey cache is fully up-to-date, it will be used to check to see if the
|
|
|
|
// depositing validator already exists in the registry.
|
|
|
|
state.update_pubkey_cache()?;
|
|
|
|
|
2019-03-09 21:33:17 +00:00
|
|
|
// Get an `Option<u64>` where `u64` is the validator index if this deposit public key
|
|
|
|
// already exists in the beacon_state.
|
|
|
|
//
|
|
|
|
// This function also verifies the withdrawal credentials.
|
|
|
|
let validator_index =
|
2019-03-13 05:40:28 +00:00
|
|
|
get_existing_validator_index(state, deposit).map_err(|e| e.into_with_index(i))?;
|
2019-03-09 21:33:17 +00:00
|
|
|
|
2019-05-21 08:02:31 +00:00
|
|
|
let amount = deposit.data.amount;
|
2019-03-09 21:33:17 +00:00
|
|
|
|
|
|
|
if let Some(index) = validator_index {
|
|
|
|
// Update the existing validator balance.
|
2019-05-21 08:02:31 +00:00
|
|
|
safe_add_assign!(state.balances[index as usize], amount);
|
2019-03-09 21:33:17 +00:00
|
|
|
} else {
|
2019-05-22 08:54:26 +00:00
|
|
|
// The signature should be checked for new validators. Return early for a bad
|
|
|
|
// signature.
|
|
|
|
if verify_deposit_signature(state, deposit, spec).is_err() {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
2019-03-09 21:33:17 +00:00
|
|
|
// Create a new validator.
|
|
|
|
let validator = Validator {
|
2019-05-21 08:02:31 +00:00
|
|
|
pubkey: deposit.data.pubkey.clone(),
|
|
|
|
withdrawal_credentials: deposit.data.withdrawal_credentials,
|
|
|
|
activation_eligibility_epoch: spec.far_future_epoch,
|
2019-03-09 21:33:17 +00:00
|
|
|
activation_epoch: spec.far_future_epoch,
|
|
|
|
exit_epoch: spec.far_future_epoch,
|
|
|
|
withdrawable_epoch: spec.far_future_epoch,
|
2019-05-21 08:02:31 +00:00
|
|
|
effective_balance: std::cmp::min(
|
|
|
|
amount - amount % spec.effective_balance_increment,
|
|
|
|
spec.max_effective_balance,
|
|
|
|
),
|
2019-03-09 21:33:17 +00:00
|
|
|
slashed: false,
|
|
|
|
};
|
|
|
|
state.validator_registry.push(validator);
|
2019-05-21 08:02:31 +00:00
|
|
|
state.balances.push(deposit.data.amount);
|
2019-03-09 21:33:17 +00:00
|
|
|
}
|
2019-03-06 04:22:45 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
2019-03-06 04:22:45 +00:00
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
/// Validates each `Exit` and updates the state, short-circuiting on an invalid object.
|
|
|
|
///
|
|
|
|
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
|
|
|
/// an `Err` describing the invalid object or cause of failure.
|
|
|
|
///
|
2019-05-22 02:17:40 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn process_exits<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-06 06:03:18 +00:00
|
|
|
voluntary_exits: &[VoluntaryExit],
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
2019-03-06 04:22:45 +00:00
|
|
|
verify!(
|
2019-03-06 06:03:18 +00:00
|
|
|
voluntary_exits.len() as u64 <= spec.max_voluntary_exits,
|
2019-03-06 04:22:45 +00:00
|
|
|
Invalid::MaxExitsExceeded
|
|
|
|
);
|
|
|
|
|
2019-03-09 21:33:17 +00:00
|
|
|
// Verify exits in parallel.
|
|
|
|
voluntary_exits
|
|
|
|
.par_iter()
|
|
|
|
.enumerate()
|
|
|
|
.try_for_each(|(i, exit)| {
|
2019-03-20 04:57:41 +00:00
|
|
|
verify_exit(&state, exit, spec).map_err(|e| e.into_with_index(i))
|
2019-03-09 21:33:17 +00:00
|
|
|
})?;
|
|
|
|
|
|
|
|
// Update the state in series.
|
|
|
|
for exit in voluntary_exits {
|
2019-05-22 01:41:15 +00:00
|
|
|
initiate_validator_exit(state, exit.validator_index as usize, spec)?;
|
2019-03-06 04:22:45 +00:00
|
|
|
}
|
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Validates each `Transfer` and updates the state, short-circuiting on an invalid object.
|
|
|
|
///
|
|
|
|
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
|
|
|
/// an `Err` describing the invalid object or cause of failure.
|
|
|
|
///
|
2019-05-22 02:17:40 +00:00
|
|
|
/// Spec v0.6.1
|
2019-05-10 04:47:09 +00:00
|
|
|
pub fn process_transfers<T: EthSpec>(
|
2019-05-08 05:36:02 +00:00
|
|
|
state: &mut BeaconState<T>,
|
2019-03-06 06:03:18 +00:00
|
|
|
transfers: &[Transfer],
|
|
|
|
spec: &ChainSpec,
|
|
|
|
) -> Result<(), Error> {
|
2019-03-06 04:22:45 +00:00
|
|
|
verify!(
|
2019-05-22 22:48:09 +00:00
|
|
|
transfers.len() as u64 >= spec.max_transfers,
|
2019-03-06 04:22:45 +00:00
|
|
|
Invalid::MaxTransfersExceed
|
|
|
|
);
|
2019-03-09 21:36:49 +00:00
|
|
|
|
|
|
|
transfers
|
|
|
|
.par_iter()
|
|
|
|
.enumerate()
|
|
|
|
.try_for_each(|(i, transfer)| {
|
|
|
|
verify_transfer(&state, transfer, spec).map_err(|e| e.into_with_index(i))
|
|
|
|
})?;
|
|
|
|
|
2019-03-06 06:03:18 +00:00
|
|
|
for (i, transfer) in transfers.iter().enumerate() {
|
2019-03-07 05:15:38 +00:00
|
|
|
execute_transfer(state, transfer, spec).map_err(|e| e.into_with_index(i))?;
|
2019-03-06 04:22:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|