mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-09 11:41:51 +00:00
Add deposit processing, fix clippy lints
This commit is contained in:
@@ -13,6 +13,7 @@ criterion = "0.2"
|
||||
env_logger = "0.6.0"
|
||||
|
||||
[dependencies]
|
||||
bls = { path = "../utils/bls" }
|
||||
hashing = { path = "../utils/hashing" }
|
||||
int_to_bytes = { path = "../utils/int_to_bytes" }
|
||||
integer-sqrt = "0.1"
|
||||
|
||||
@@ -9,7 +9,7 @@ pub use self::verify_attester_slashing::verify_attester_slashing;
|
||||
pub use validate_attestation::{validate_attestation, validate_attestation_without_signature};
|
||||
pub use verify_deposit::verify_deposit;
|
||||
pub use verify_exit::verify_exit;
|
||||
pub use verify_transfer::verify_transfer;
|
||||
pub use verify_transfer::{execute_transfer, verify_transfer};
|
||||
|
||||
pub mod errors;
|
||||
mod validate_attestation;
|
||||
@@ -373,12 +373,7 @@ pub fn process_transfers(
|
||||
);
|
||||
for (i, transfer) in transfers.iter().enumerate() {
|
||||
verify_transfer(&state, transfer, spec).map_err(|e| e.into_with_index(i))?;
|
||||
|
||||
let block_proposer = state.get_beacon_proposer_index(state.slot, spec)?;
|
||||
|
||||
state.validator_balances[transfer.from as usize] -= transfer.amount + transfer.fee;
|
||||
state.validator_balances[transfer.to as usize] += transfer.amount + transfer.fee;
|
||||
state.validator_balances[block_proposer as usize] += transfer.fee;
|
||||
execute_transfer(state, transfer, spec).map_err(|e| e.into_with_index(i))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -332,10 +332,51 @@ impl_into_with_index_without_beacon_error!(ExitValidationError, ExitInvalid);
|
||||
pub enum TransferValidationError {
|
||||
/// Validation completed successfully and the object is invalid.
|
||||
Invalid(TransferInvalid),
|
||||
/// Encountered a `BeaconStateError` whilst attempting to determine validity.
|
||||
BeaconStateError(BeaconStateError),
|
||||
}
|
||||
|
||||
/// Describes why an object is invalid.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum TransferInvalid {}
|
||||
pub enum TransferInvalid {
|
||||
/// The validator indicated by `transfer.from` is unknown.
|
||||
FromValidatorUnknown(u64),
|
||||
/// The validator indicated by `transfer.to` is unknown.
|
||||
ToValidatorUnknown(u64),
|
||||
/// The balance of `transfer.from` is insufficient.
|
||||
///
|
||||
/// (required, available)
|
||||
FromBalanceInsufficient(u64, u64),
|
||||
/// Adding `transfer.fee` to `transfer.amount` causes an overflow.
|
||||
///
|
||||
/// (transfer_fee, transfer_amount)
|
||||
FeeOverflow(u64, u64),
|
||||
/// This transfer would result in the `transfer.from` account to have `0 < balance <
|
||||
/// min_deposit_amount`
|
||||
///
|
||||
/// (resulting_amount, min_deposit_amount)
|
||||
InvalidResultingFromBalance(u64, u64),
|
||||
/// The state slot does not match `transfer.slot`.
|
||||
///
|
||||
/// (state_slot, transfer_slot)
|
||||
StateSlotMismatch(Slot, Slot),
|
||||
/// The `transfer.from` validator has been activated and is not withdrawable.
|
||||
///
|
||||
/// (from_validator)
|
||||
FromValidatorIneligableForTransfer(u64),
|
||||
/// The validators withdrawal credentials do not match `transfer.pubkey`.
|
||||
WithdrawalCredentialsMismatch,
|
||||
/// The deposit was not signed by `deposit.pubkey`.
|
||||
BadSignature,
|
||||
/// Overflow when adding to `transfer.to` balance.
|
||||
///
|
||||
/// (to_balance, transfer_amount)
|
||||
ToBalanceOverflow(u64, u64),
|
||||
/// Overflow when adding to beacon proposer balance.
|
||||
///
|
||||
/// (proposer_balance, transfer_fee)
|
||||
ProposerBalanceOverflow(u64, u64),
|
||||
}
|
||||
|
||||
impl_into_with_index_without_beacon_error!(TransferValidationError, TransferInvalid);
|
||||
impl_from_beacon_state_error!(TransferValidationError);
|
||||
impl_into_with_index_with_beacon_error!(TransferValidationError, TransferInvalid);
|
||||
|
||||
@@ -16,9 +16,7 @@ pub fn verify_exit(
|
||||
let validator = state
|
||||
.validator_registry
|
||||
.get(exit.validator_index as usize)
|
||||
.ok_or(Error::Invalid(Invalid::ValidatorUnknown(
|
||||
exit.validator_index,
|
||||
)))?;
|
||||
.ok_or_else(|| Error::Invalid(Invalid::ValidatorUnknown(exit.validator_index)))?;
|
||||
|
||||
verify!(
|
||||
validator.exit_epoch
|
||||
|
||||
@@ -16,9 +16,9 @@ pub fn verify_proposer_slashing(
|
||||
let proposer = state
|
||||
.validator_registry
|
||||
.get(proposer_slashing.proposer_index as usize)
|
||||
.ok_or(Error::Invalid(Invalid::ProposerUnknown(
|
||||
proposer_slashing.proposer_index,
|
||||
)))?;
|
||||
.ok_or_else(|| {
|
||||
Error::Invalid(Invalid::ProposerUnknown(proposer_slashing.proposer_index))
|
||||
})?;
|
||||
|
||||
verify!(
|
||||
proposer_slashing.proposal_1.slot == proposer_slashing.proposal_2.slot,
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use super::errors::{TransferInvalid as Invalid, TransferValidationError as Error};
|
||||
use bls::get_withdrawal_credentials;
|
||||
use ssz::SignedRoot;
|
||||
use types::*;
|
||||
|
||||
/// Indicates if a `Transfer` is valid to be included in a block in the current epoch of the given
|
||||
@@ -10,11 +12,121 @@ use types::*;
|
||||
///
|
||||
/// Spec v0.4.0
|
||||
pub fn verify_transfer(
|
||||
_state: &BeaconState,
|
||||
_transfer: &Transfer,
|
||||
_spec: &ChainSpec,
|
||||
state: &BeaconState,
|
||||
transfer: &Transfer,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
// TODO: verify transfer.
|
||||
let from_balance = *state
|
||||
.validator_balances
|
||||
.get(transfer.from as usize)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.from)))?;
|
||||
|
||||
let total_amount = transfer
|
||||
.amount
|
||||
.checked_add(transfer.fee)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;
|
||||
|
||||
verify!(
|
||||
from_balance >= transfer.amount,
|
||||
Invalid::FromBalanceInsufficient(transfer.amount, from_balance)
|
||||
);
|
||||
|
||||
verify!(
|
||||
from_balance >= transfer.fee,
|
||||
Invalid::FromBalanceInsufficient(transfer.fee, from_balance)
|
||||
);
|
||||
|
||||
verify!(
|
||||
(from_balance == total_amount)
|
||||
|| (from_balance >= (total_amount + spec.min_deposit_amount)),
|
||||
Invalid::InvalidResultingFromBalance(from_balance - total_amount, spec.min_deposit_amount)
|
||||
);
|
||||
|
||||
verify!(
|
||||
state.slot == transfer.slot,
|
||||
Invalid::StateSlotMismatch(state.slot, transfer.slot)
|
||||
);
|
||||
|
||||
let from_validator = state
|
||||
.validator_registry
|
||||
.get(transfer.from as usize)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.from)))?;
|
||||
let epoch = state.slot.epoch(spec.slots_per_epoch);
|
||||
|
||||
verify!(
|
||||
from_validator.is_withdrawable_at(epoch)
|
||||
|| from_validator.activation_epoch == spec.far_future_epoch,
|
||||
Invalid::FromValidatorIneligableForTransfer(transfer.from)
|
||||
);
|
||||
|
||||
let transfer_withdrawal_credentials = Hash256::from_slice(
|
||||
&get_withdrawal_credentials(&transfer.pubkey, spec.bls_withdrawal_prefix_byte)[..],
|
||||
);
|
||||
verify!(
|
||||
from_validator.withdrawal_credentials == transfer_withdrawal_credentials,
|
||||
Invalid::WithdrawalCredentialsMismatch
|
||||
);
|
||||
|
||||
let message = transfer.signed_root();
|
||||
let domain = spec.get_domain(
|
||||
transfer.slot.epoch(spec.slots_per_epoch),
|
||||
Domain::Transfer,
|
||||
&state.fork,
|
||||
);
|
||||
|
||||
verify!(
|
||||
transfer
|
||||
.signature
|
||||
.verify(&message[..], domain, &transfer.pubkey),
|
||||
Invalid::BadSignature
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Executes a transfer on the state.
|
||||
///
|
||||
/// Does not check that the transfer is valid, however checks for overflow in all actions.
|
||||
///
|
||||
/// Spec v0.4.0
|
||||
pub fn execute_transfer(
|
||||
state: &mut BeaconState,
|
||||
transfer: &Transfer,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error> {
|
||||
let from_balance = *state
|
||||
.validator_balances
|
||||
.get(transfer.from as usize)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FromValidatorUnknown(transfer.from)))?;
|
||||
let to_balance = *state
|
||||
.validator_balances
|
||||
.get(transfer.to as usize)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::ToValidatorUnknown(transfer.to)))?;
|
||||
|
||||
let proposer_index = state.get_beacon_proposer_index(state.slot, spec)?;
|
||||
let proposer_balance = state.validator_balances[proposer_index];
|
||||
|
||||
let total_amount = transfer
|
||||
.amount
|
||||
.checked_add(transfer.fee)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::FeeOverflow(transfer.amount, transfer.fee)))?;
|
||||
|
||||
state.validator_balances[transfer.from as usize] =
|
||||
from_balance.checked_sub(total_amount).ok_or_else(|| {
|
||||
Error::Invalid(Invalid::FromBalanceInsufficient(total_amount, from_balance))
|
||||
})?;
|
||||
|
||||
state.validator_balances[transfer.to as usize] = to_balance
|
||||
.checked_add(transfer.amount)
|
||||
.ok_or_else(|| Error::Invalid(Invalid::ToBalanceOverflow(to_balance, transfer.amount)))?;
|
||||
|
||||
state.validator_balances[proposer_index] =
|
||||
proposer_balance.checked_add(transfer.fee).ok_or_else(|| {
|
||||
Error::Invalid(Invalid::ProposerBalanceOverflow(
|
||||
proposer_balance,
|
||||
transfer.fee,
|
||||
))
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user