spec v0.6.1: deposit processing (WIP)
This commit is contained in:
parent
468dc2ceb0
commit
545fb10005
@ -89,11 +89,9 @@ fn per_block_processing_signature_optional<T: EthSpec>(
|
|||||||
process_proposer_slashings(&mut state, &block.body.proposer_slashings, spec)?;
|
process_proposer_slashings(&mut state, &block.body.proposer_slashings, spec)?;
|
||||||
process_attester_slashings(&mut state, &block.body.attester_slashings, spec)?;
|
process_attester_slashings(&mut state, &block.body.attester_slashings, spec)?;
|
||||||
process_attestations(&mut state, &block.body.attestations, spec)?;
|
process_attestations(&mut state, &block.body.attestations, spec)?;
|
||||||
/*
|
|
||||||
process_deposits(&mut state, &block.body.deposits, spec)?;
|
process_deposits(&mut state, &block.body.deposits, spec)?;
|
||||||
process_exits(&mut state, &block.body.voluntary_exits, spec)?;
|
process_exits(&mut state, &block.body.voluntary_exits, spec)?;
|
||||||
process_transfers(&mut state, &block.body.transfers, spec)?;
|
process_transfers(&mut state, &block.body.transfers, spec)?;
|
||||||
*/
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -350,21 +348,24 @@ pub fn process_attestations<T: EthSpec>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
/// Validates each `Deposit` and updates the state, short-circuiting on an invalid object.
|
/// 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
|
/// Returns `Ok(())` if the validation and state updates completed successfully, otherwise returns
|
||||||
/// an `Err` describing the invalid object or cause of failure.
|
/// an `Err` describing the invalid object or cause of failure.
|
||||||
///
|
///
|
||||||
/// Spec v0.5.1
|
/// Spec v0.6.1
|
||||||
pub fn process_deposits<T: EthSpec>(
|
pub fn process_deposits<T: EthSpec>(
|
||||||
state: &mut BeaconState<T>,
|
state: &mut BeaconState<T>,
|
||||||
deposits: &[Deposit],
|
deposits: &[Deposit],
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
verify!(
|
verify!(
|
||||||
deposits.len() as u64 <= spec.max_deposits,
|
deposits.len() as u64
|
||||||
Invalid::MaxDepositsExceeded
|
== std::cmp::min(
|
||||||
|
spec.max_deposits,
|
||||||
|
state.latest_eth1_data.deposit_count - state.deposit_index
|
||||||
|
),
|
||||||
|
Invalid::DepositCountInvalid
|
||||||
);
|
);
|
||||||
|
|
||||||
// Verify deposits in parallel.
|
// Verify deposits in parallel.
|
||||||
@ -391,28 +392,28 @@ pub fn process_deposits<T: EthSpec>(
|
|||||||
let validator_index =
|
let validator_index =
|
||||||
get_existing_validator_index(state, deposit).map_err(|e| e.into_with_index(i))?;
|
get_existing_validator_index(state, deposit).map_err(|e| e.into_with_index(i))?;
|
||||||
|
|
||||||
let deposit_data = &deposit.deposit_data;
|
let amount = deposit.data.amount;
|
||||||
let deposit_input = &deposit.deposit_data.deposit_input;
|
|
||||||
|
|
||||||
if let Some(index) = validator_index {
|
if let Some(index) = validator_index {
|
||||||
// Update the existing validator balance.
|
// Update the existing validator balance.
|
||||||
safe_add_assign!(
|
safe_add_assign!(state.balances[index as usize], amount);
|
||||||
state.validator_balances[index as usize],
|
|
||||||
deposit_data.amount
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Create a new validator.
|
// Create a new validator.
|
||||||
let validator = Validator {
|
let validator = Validator {
|
||||||
pubkey: deposit_input.pubkey.clone(),
|
pubkey: deposit.data.pubkey.clone(),
|
||||||
withdrawal_credentials: deposit_input.withdrawal_credentials,
|
withdrawal_credentials: deposit.data.withdrawal_credentials,
|
||||||
|
activation_eligibility_epoch: spec.far_future_epoch,
|
||||||
activation_epoch: spec.far_future_epoch,
|
activation_epoch: spec.far_future_epoch,
|
||||||
exit_epoch: spec.far_future_epoch,
|
exit_epoch: spec.far_future_epoch,
|
||||||
withdrawable_epoch: spec.far_future_epoch,
|
withdrawable_epoch: spec.far_future_epoch,
|
||||||
initiated_exit: false,
|
effective_balance: std::cmp::min(
|
||||||
|
amount - amount % spec.effective_balance_increment,
|
||||||
|
spec.max_effective_balance,
|
||||||
|
),
|
||||||
slashed: false,
|
slashed: false,
|
||||||
};
|
};
|
||||||
state.validator_registry.push(validator);
|
state.validator_registry.push(validator);
|
||||||
state.validator_balances.push(deposit_data.amount);
|
state.balances.push(deposit.data.amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
state.deposit_index += 1;
|
state.deposit_index += 1;
|
||||||
@ -482,4 +483,3 @@ pub fn process_transfers<T: EthSpec>(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
@ -77,7 +77,7 @@ pub enum BlockInvalid {
|
|||||||
MaxAttestationsExceeded,
|
MaxAttestationsExceeded,
|
||||||
MaxAttesterSlashingsExceed,
|
MaxAttesterSlashingsExceed,
|
||||||
MaxProposerSlashingsExceeded,
|
MaxProposerSlashingsExceeded,
|
||||||
MaxDepositsExceeded,
|
DepositCountInvalid,
|
||||||
MaxExitsExceeded,
|
MaxExitsExceeded,
|
||||||
MaxTransfersExceed,
|
MaxTransfersExceed,
|
||||||
AttestationInvalid(usize, AttestationInvalid),
|
AttestationInvalid(usize, AttestationInvalid),
|
||||||
|
@ -3,6 +3,7 @@ use hashing::hash;
|
|||||||
use merkle_proof::verify_merkle_proof;
|
use merkle_proof::verify_merkle_proof;
|
||||||
use ssz::ssz_encode;
|
use ssz::ssz_encode;
|
||||||
use ssz_derive::Encode;
|
use ssz_derive::Encode;
|
||||||
|
use tree_hash::{SignedRoot, TreeHash};
|
||||||
use types::*;
|
use types::*;
|
||||||
|
|
||||||
/// Indicates if a `Deposit` is valid to be included in a block in the current epoch of the given
|
/// Indicates if a `Deposit` is valid to be included in a block in the current epoch of the given
|
||||||
@ -15,25 +16,13 @@ use types::*;
|
|||||||
///
|
///
|
||||||
/// Note: this function is incomplete.
|
/// Note: this function is incomplete.
|
||||||
///
|
///
|
||||||
/// Spec v0.5.1
|
/// Spec v0.6.1
|
||||||
pub fn verify_deposit<T: EthSpec>(
|
pub fn verify_deposit<T: EthSpec>(
|
||||||
state: &BeaconState<T>,
|
state: &BeaconState<T>,
|
||||||
deposit: &Deposit,
|
deposit: &Deposit,
|
||||||
verify_merkle_branch: bool,
|
verify_merkle_branch: bool,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<(), Error> {
|
) -> 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 {
|
if verify_merkle_branch {
|
||||||
verify!(
|
verify!(
|
||||||
verify_deposit_merkle_proof(state, deposit, spec),
|
verify_deposit_merkle_proof(state, deposit, spec),
|
||||||
@ -41,12 +30,23 @@ pub fn verify_deposit<T: EthSpec>(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: proof of possession should only be verified when the validator
|
||||||
|
// is not already part of the registry
|
||||||
|
verify!(
|
||||||
|
deposit.data.signature.verify(
|
||||||
|
&deposit.data.signed_root(),
|
||||||
|
spec.get_domain(state.current_epoch(), Domain::Deposit, &state.fork),
|
||||||
|
&deposit.data.pubkey,
|
||||||
|
),
|
||||||
|
Invalid::BadProofOfPossession
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify that the `Deposit` index is correct.
|
/// Verify that the `Deposit` index is correct.
|
||||||
///
|
///
|
||||||
/// Spec v0.5.1
|
/// Spec v0.6.1
|
||||||
pub fn verify_deposit_index<T: EthSpec>(
|
pub fn verify_deposit_index<T: EthSpec>(
|
||||||
state: &BeaconState<T>,
|
state: &BeaconState<T>,
|
||||||
deposit: &Deposit,
|
deposit: &Deposit,
|
||||||
@ -72,16 +72,15 @@ pub fn get_existing_validator_index<T: EthSpec>(
|
|||||||
state: &BeaconState<T>,
|
state: &BeaconState<T>,
|
||||||
deposit: &Deposit,
|
deposit: &Deposit,
|
||||||
) -> Result<Option<u64>, Error> {
|
) -> Result<Option<u64>, Error> {
|
||||||
let deposit_input = &deposit.deposit_data.deposit_input;
|
let validator_index = state.get_validator_index(&deposit.data.pubkey)?;
|
||||||
|
|
||||||
let validator_index = state.get_validator_index(&deposit_input.pubkey)?;
|
|
||||||
|
|
||||||
|
// NOTE: it seems that v0.6.1 doesn't require the withdrawal credentials to be checked
|
||||||
match validator_index {
|
match validator_index {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(index) => {
|
Some(index) => {
|
||||||
verify!(
|
verify!(
|
||||||
deposit_input.withdrawal_credentials
|
deposit.data.withdrawal_credentials
|
||||||
== state.validator_registry[index as usize].withdrawal_credentials,
|
== state.validator_registry[index].withdrawal_credentials,
|
||||||
Invalid::BadWithdrawalCredentials
|
Invalid::BadWithdrawalCredentials
|
||||||
);
|
);
|
||||||
Ok(Some(index as u64))
|
Ok(Some(index as u64))
|
||||||
@ -91,7 +90,7 @@ pub fn get_existing_validator_index<T: EthSpec>(
|
|||||||
|
|
||||||
/// Verify that a deposit is included in the state's eth1 deposit root.
|
/// Verify that a deposit is included in the state's eth1 deposit root.
|
||||||
///
|
///
|
||||||
/// Spec v0.6.0
|
/// Spec v0.6.1
|
||||||
fn verify_deposit_merkle_proof<T: EthSpec>(
|
fn verify_deposit_merkle_proof<T: EthSpec>(
|
||||||
state: &BeaconState<T>,
|
state: &BeaconState<T>,
|
||||||
deposit: &Deposit,
|
deposit: &Deposit,
|
||||||
|
@ -1,92 +0,0 @@
|
|||||||
use crate::test_utils::TestRandom;
|
|
||||||
use crate::*;
|
|
||||||
use bls::{PublicKey, Signature};
|
|
||||||
|
|
||||||
use serde_derive::{Deserialize, Serialize};
|
|
||||||
use ssz_derive::{Decode, Encode};
|
|
||||||
use test_random_derive::TestRandom;
|
|
||||||
use tree_hash::{SignedRoot, TreeHash};
|
|
||||||
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
|
|
||||||
|
|
||||||
/// The data supplied by the user to the deposit contract.
|
|
||||||
///
|
|
||||||
/// Spec v0.5.1
|
|
||||||
#[derive(
|
|
||||||
Debug,
|
|
||||||
PartialEq,
|
|
||||||
Clone,
|
|
||||||
Serialize,
|
|
||||||
Deserialize,
|
|
||||||
Encode,
|
|
||||||
Decode,
|
|
||||||
SignedRoot,
|
|
||||||
TreeHash,
|
|
||||||
CachedTreeHash,
|
|
||||||
TestRandom,
|
|
||||||
)]
|
|
||||||
pub struct DepositInput {
|
|
||||||
pub pubkey: PublicKey,
|
|
||||||
pub withdrawal_credentials: Hash256,
|
|
||||||
#[signed_root(skip_hashing)]
|
|
||||||
pub proof_of_possession: Signature,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DepositInput {
|
|
||||||
/// Generate the 'proof_of_posession' signature for a given DepositInput details.
|
|
||||||
///
|
|
||||||
/// Spec v0.5.1
|
|
||||||
pub fn create_proof_of_possession(
|
|
||||||
&self,
|
|
||||||
secret_key: &SecretKey,
|
|
||||||
epoch: Epoch,
|
|
||||||
fork: &Fork,
|
|
||||||
spec: &ChainSpec,
|
|
||||||
) -> Signature {
|
|
||||||
let msg = self.signed_root();
|
|
||||||
let domain = spec.get_domain(epoch, Domain::Deposit, fork);
|
|
||||||
|
|
||||||
Signature::new(msg.as_slice(), domain, secret_key)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Verify that proof-of-possession is valid.
|
|
||||||
///
|
|
||||||
/// Spec v0.5.1
|
|
||||||
pub fn validate_proof_of_possession(
|
|
||||||
&self,
|
|
||||||
epoch: Epoch,
|
|
||||||
fork: &Fork,
|
|
||||||
spec: &ChainSpec,
|
|
||||||
) -> bool {
|
|
||||||
let msg = self.signed_root();
|
|
||||||
let domain = spec.get_domain(epoch, Domain::Deposit, fork);
|
|
||||||
|
|
||||||
self.proof_of_possession.verify(&msg, domain, &self.pubkey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
ssz_tests!(DepositInput);
|
|
||||||
cached_tree_hash_tests!(DepositInput);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn can_create_and_validate() {
|
|
||||||
let spec = ChainSpec::foundation();
|
|
||||||
let fork = Fork::genesis(&spec);
|
|
||||||
let keypair = Keypair::random();
|
|
||||||
let epoch = Epoch::new(0);
|
|
||||||
|
|
||||||
let mut deposit_input = DepositInput {
|
|
||||||
pubkey: keypair.pk.clone(),
|
|
||||||
withdrawal_credentials: Hash256::zero(),
|
|
||||||
proof_of_possession: Signature::empty_signature(),
|
|
||||||
};
|
|
||||||
|
|
||||||
deposit_input.proof_of_possession =
|
|
||||||
deposit_input.create_proof_of_possession(&keypair.sk, epoch, &fork, &spec);
|
|
||||||
|
|
||||||
assert!(deposit_input.validate_proof_of_possession(epoch, &fork, &spec));
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user