Implement deposit merkle root verification.

It is currently disabled, but it's there for later.
This commit is contained in:
Paul Hauner 2019-03-08 09:26:03 +11:00
parent 60098a051d
commit f479beb87e
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
4 changed files with 62 additions and 5 deletions

View File

@ -18,6 +18,8 @@ hashing = { path = "../utils/hashing" }
int_to_bytes = { path = "../utils/int_to_bytes" }
integer-sqrt = "0.1"
log = "0.4"
merkle_proof = { path = "../utils/merkle_proof" }
ssz = { path = "../utils/ssz" }
ssz_derive = { path = "../utils/ssz_derive" }
types = { path = "../types" }
rayon = "1.0"

View File

@ -20,6 +20,11 @@ mod verify_proposer_slashing;
mod verify_slashable_attestation;
mod verify_transfer;
// Set to `true` to check the merkle proof that a deposit is in the eth1 deposit root.
//
// Presently disabled to make testing easier.
const VERIFY_DEPOSIT_MERKLE_PROOFS: bool = false;
/// 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
@ -309,7 +314,8 @@ pub fn process_deposits(
Invalid::MaxDepositsExceeded
);
for (i, deposit) in deposits.iter().enumerate() {
verify_deposit(state, deposit, spec).map_err(|e| e.into_with_index(i))?;
verify_deposit(state, deposit, VERIFY_DEPOSIT_MERKLE_PROOFS, spec)
.map_err(|e| e.into_with_index(i))?;
state
.process_deposit(

View File

@ -292,6 +292,9 @@ pub enum DepositInvalid {
///
/// (state_index, deposit_index)
BadIndex(u64, u64),
/// The specified `branch` and `index` did not form a valid proof that the deposit is included
/// in the eth1 deposit root.
BadMerkleProof,
}
impl_into_with_index_without_beacon_error!(DepositValidationError, DepositInvalid);

View File

@ -1,4 +1,8 @@
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 types::*;
/// Indicates if a `Deposit` is valid to be included in a block in the current epoch of the given
@ -12,16 +16,58 @@ use types::*;
pub fn verify_deposit(
state: &BeaconState,
deposit: &Deposit,
_spec: &ChainSpec,
verify_merkle_branch: bool,
spec: &ChainSpec,
) -> Result<(), Error> {
// TODO: verify serialized deposit data.
verify!(
deposit.index == state.deposit_index,
Invalid::BadIndex(state.deposit_index, deposit.index)
);
// TODO: verify merkle branch.
if verify_merkle_branch {
verify!(
verify_deposit_merkle_proof(state, deposit, spec),
Invalid::BadMerkleProof
);
}
Ok(())
}
/// 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<u8> {
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)
}