Added process_withdrawals

This commit is contained in:
Mark Mackey
2022-11-13 18:20:27 -06:00
parent 81319dfcae
commit 276e1845fd
3 changed files with 150 additions and 35 deletions

View File

@@ -42,6 +42,7 @@ mod verify_deposit;
mod verify_exit;
mod verify_proposer_slashing;
use crate::common::decrease_balance;
#[cfg(feature = "arbitrary-fuzz")]
use arbitrary::Arbitrary;
@@ -165,6 +166,8 @@ pub fn per_block_processing<T: EthSpec, Payload: AbstractExecPayload<T>>(
// previous block.
if is_execution_enabled(state, block.body()) {
let payload = block.body().execution_payload()?;
#[cfg(all(feature = "withdrawals", feature = "withdrawals-processing"))]
process_withdrawals::<T, Payload>(state, payload, spec)?;
process_execution_payload::<T, Payload>(state, payload, spec)?;
}
@@ -455,3 +458,88 @@ pub fn compute_timestamp_at_slot<T: EthSpec>(
.safe_mul(spec.seconds_per_slot)
.and_then(|since_genesis| state.genesis_time().safe_add(since_genesis))
}
/// FIXME: add link to this function once the spec is stable
#[cfg(all(feature = "withdrawals", feature = "withdrawals-processing"))]
pub fn get_expected_withdrawals<T: EthSpec>(
state: &BeaconState<T>,
spec: &ChainSpec,
) -> Result<Withdrawals<T>, BlockProcessingError> {
let epoch = state.current_epoch();
let mut withdrawal_index = *state.next_withdrawal_index()?;
let mut validator_index = *state.next_withdrawal_validator_index()?;
let mut withdrawals = vec![];
for _ in 0..state.validators().len() {
let validator = state.get_validator(validator_index as usize)?;
let balance = *state
.balances()
.get(validator_index as usize)
.ok_or_else(|| BeaconStateError::BalancesOutOfBounds(validator_index as usize))?;
if validator.is_fully_withdrawable_at(balance, epoch, spec) {
withdrawals.push(Withdrawal {
index: withdrawal_index,
validator_index,
address: Address::from_slice(&validator.withdrawal_credentials[12..]),
amount: balance,
});
withdrawal_index.safe_add_assign(1)?;
} else if validator.is_partially_withdrawable_validator(balance, spec) {
withdrawals.push(Withdrawal {
index: withdrawal_index,
validator_index,
address: Address::from_slice(&validator.withdrawal_credentials[12..]),
amount: balance.safe_sub(spec.max_effective_balance)?,
});
withdrawal_index.safe_add_assign(1)?;
}
if withdrawals.len() == T::max_withdrawals_per_payload() {
break;
}
validator_index = validator_index.safe_add(1)? % state.validators().len() as u64;
}
Ok(withdrawals.into())
}
/// FIXME: add link to this function once the spec is stable
#[cfg(all(feature = "withdrawals", feature = "withdrawals-processing"))]
pub fn process_withdrawals<'payload, T: EthSpec, Payload: AbstractExecPayload<T>>(
state: &mut BeaconState<T>,
payload: Payload::Ref<'payload>,
spec: &ChainSpec,
) -> Result<(), BlockProcessingError> {
match state {
BeaconState::Merge(_) => Ok(()),
BeaconState::Capella(_) | BeaconState::Eip4844(_) => {
let expected_withdrawals = get_expected_withdrawals(state, spec)?;
let withdrawals_root = payload.withdrawals_root()?;
if expected_withdrawals.tree_hash_root() != payload.withdrawals_root()? {
return Err(BlockProcessingError::WithdrawalsRootMismatch {
expected: expected_withdrawals.tree_hash_root(),
found: payload.withdrawals_root()?,
});
}
for withdrawal in expected_withdrawals.iter() {
decrease_balance(
state,
withdrawal.validator_index as usize,
withdrawal.amount,
)?;
}
if let Some(latest_withdrawal) = expected_withdrawals.last() {
*state.next_withdrawal_index_mut()? = latest_withdrawal.index + 1;
let next_validator_index =
(latest_withdrawal.validator_index + 1) % state.validators().len() as u64;
*state.next_withdrawal_validator_index_mut()? = next_validator_index;
}
Ok(())
}
// these shouldn't even be encountered but they're here for completeness
BeaconState::Base(_) | BeaconState::Altair(_) => Ok(()),
}
}

View File

@@ -78,6 +78,10 @@ pub enum BlockProcessingError {
},
ExecutionInvalid,
ConsensusContext(ContextError),
WithdrawalsRootMismatch {
expected: Hash256,
found: Hash256,
},
BlobVersionHashMismatch,
/// The number of commitments in blob transactions in the payload does not match the number
/// of commitments in the block.