From 9a1e4846952de3e9ede16aee69a55e39d19b0b89 Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Mon, 18 Sep 2023 21:53:56 +0000 Subject: [PATCH 01/16] feat: implements process bls to execution change --- .../src/capella/block_processing.rs | 60 ++++++++++++++----- .../src/capella/bls_to_execution_change.rs | 4 +- 2 files changed, 47 insertions(+), 17 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 31d7a0b87..132957492 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -1,13 +1,16 @@ use crate::{ capella::{ - compute_timestamp_at_slot, decrease_balance, get_current_epoch, get_randao_mix, - is_fully_withdrawable_validator, is_partially_withdrawable_validator, process_attestation, - process_attester_slashing, process_block_header, process_deposit, process_eth1_data, - process_proposer_slashing, process_randao, process_sync_aggregate, process_voluntary_exit, - BeaconBlock, BeaconBlockBody, BeaconState, ExecutionAddress, ExecutionEngine, + compute_domain, compute_signing_root, compute_timestamp_at_slot, decrease_balance, + get_current_epoch, get_randao_mix, is_fully_withdrawable_validator, + is_partially_withdrawable_validator, process_attestation, process_attester_slashing, + process_block_header, process_deposit, process_eth1_data, process_proposer_slashing, + process_randao, process_sync_aggregate, process_voluntary_exit, BeaconBlock, + BeaconBlockBody, BeaconState, BlsPublicKey, DomainType, ExecutionAddress, ExecutionEngine, ExecutionPayload, ExecutionPayloadHeader, NewPayloadRequest, SignedBlsToExecutionChange, Withdrawal, }, + crypto::{hash, verify_signature}, + primitives::{BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX}, ssz::prelude::*, state_transition::{ invalid_operation_error, Context, InvalidDeposit, InvalidExecutionPayload, @@ -27,7 +30,7 @@ pub fn process_bls_to_execution_change< const BYTES_PER_LOGS_BLOOM: usize, const MAX_EXTRA_DATA_BYTES: usize, >( - _state: &mut BeaconState< + state: &mut BeaconState< SLOTS_PER_HISTORICAL_ROOT, HISTORICAL_ROOTS_LIMIT, ETH1_DATA_VOTES_BOUND, @@ -39,10 +42,37 @@ pub fn process_bls_to_execution_change< BYTES_PER_LOGS_BLOOM, MAX_EXTRA_DATA_BYTES, >, - _signed_address_change: &mut SignedBlsToExecutionChange, - _context: &Context, + signed_address_change: &mut SignedBlsToExecutionChange, + context: &Context, ) -> Result<()> { - unimplemented!() + let address_change = signed_address_change; + + assert!(address_change.message.validator_index < state.validators.len()); + + let validator = &mut state.validators[address_change.message.validator_index]; + + assert!(validator.withdrawal_credentials.starts_with(&[BLS_WITHDRAWAL_PREFIX])); + assert!( + validator.withdrawal_credentials[1..] + == hash(address_change.message.from_bls_public_key.as_ref())[1..] + ); + + let domain = compute_domain( + DomainType::BlsToExecutionChange, + None, + Some(state.genesis_validators_root), + context, + )?; + let signing_root = compute_signing_root(address_change, domain)?; + let pk: &BlsPublicKey = &address_change.message.from_bls_public_key; + assert!(verify_signature(&pk, signing_root.as_ref(), &address_change.signature,).is_ok()); + let withdrawal_credentials = vec![ETH1_ADDRESS_WITHDRAWAL_PREFIX]; + + let withdrawal_credentials_array: [u8; 32] = + withdrawal_credentials.try_into().expect("Wrong size"); + validator.withdrawal_credentials = ByteVector::try_from(withdrawal_credentials_array.as_ref()) + .expect("Failed to convert array to ByteVector"); + Ok(()) } pub fn process_operations< @@ -105,7 +135,7 @@ pub fn process_operations< expected: expected_deposit_count, count: body.deposits.len(), }, - ))) + ))); } body.proposer_slashings .iter_mut() @@ -177,7 +207,7 @@ pub fn process_execution_payload< expected: state.latest_execution_payload_header.block_hash.clone(), } .into(), - )) + )); } let current_epoch = get_current_epoch(state, context); @@ -189,7 +219,7 @@ pub fn process_execution_payload< expected: randao_mix.clone(), } .into(), - )) + )); } let timestamp = compute_timestamp_at_slot(state, state.slot, context)?; @@ -200,7 +230,7 @@ pub fn process_execution_payload< expected: timestamp, } .into(), - )) + )); } let new_payload_request = NewPayloadRequest(payload); @@ -271,7 +301,7 @@ pub fn process_withdrawals< provided: execution_payload.withdrawals.to_vec(), expected: expected_withdrawals, }, - ))) + ))); } for withdrawal in &expected_withdrawals { @@ -356,7 +386,7 @@ pub fn get_expected_withdrawals< withdrawal_index += 1; } if withdrawals.len() == context.max_withdrawals_per_payload { - break + break; } validator_index = (validator_index + 1) % state.validators.len(); } diff --git a/ethereum-consensus/src/capella/bls_to_execution_change.rs b/ethereum-consensus/src/capella/bls_to_execution_change.rs index 273543676..4533f1dc4 100644 --- a/ethereum-consensus/src/capella/bls_to_execution_change.rs +++ b/ethereum-consensus/src/capella/bls_to_execution_change.rs @@ -16,6 +16,6 @@ pub struct BlsToExecutionChange { #[derive(Default, Debug, Clone, SimpleSerialize, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SignedBlsToExecutionChange { - message: BlsToExecutionChange, - signature: BlsSignature, + pub message: BlsToExecutionChange, + pub signature: BlsSignature, } From 156ee94a15fd0cbe718d375f04a72deb57ada65e Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Tue, 19 Sep 2023 00:33:57 +0000 Subject: [PATCH 02/16] chore: lint --- ethereum-consensus/src/capella/block_processing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 132957492..032139a5f 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -65,7 +65,7 @@ pub fn process_bls_to_execution_change< )?; let signing_root = compute_signing_root(address_change, domain)?; let pk: &BlsPublicKey = &address_change.message.from_bls_public_key; - assert!(verify_signature(&pk, signing_root.as_ref(), &address_change.signature,).is_ok()); + assert!(verify_signature(pk, signing_root.as_ref(), &address_change.signature,).is_ok()); let withdrawal_credentials = vec![ETH1_ADDRESS_WITHDRAWAL_PREFIX]; let withdrawal_credentials_array: [u8; 32] = From f596fda69ba65c8124dfccac25534aeb7a8a1d2c Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Wed, 20 Sep 2023 05:39:23 +0000 Subject: [PATCH 03/16] chore: PR comments --- .../src/capella/block_processing.rs | 55 ++++++++++++------- .../src/state_transition/error.rs | 10 +++- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 032139a5f..647f5590f 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -45,17 +45,23 @@ pub fn process_bls_to_execution_change< signed_address_change: &mut SignedBlsToExecutionChange, context: &Context, ) -> Result<()> { - let address_change = signed_address_change; + let address_change = &signed_address_change.message; + let signature = &signed_address_change.signature; - assert!(address_change.message.validator_index < state.validators.len()); + if address_change.validator_index >= state.validators.len() { + return Err(invalid_operation_error(InvalidOperation::ValidatorIndex( + address_change.validator_index, + ))) + } - let validator = &mut state.validators[address_change.message.validator_index]; + let withdrawal_credentials_prefix = + state.validators[address_change.validator_index].withdrawal_credentials[0]; - assert!(validator.withdrawal_credentials.starts_with(&[BLS_WITHDRAWAL_PREFIX])); - assert!( - validator.withdrawal_credentials[1..] - == hash(address_change.message.from_bls_public_key.as_ref())[1..] - ); + if withdrawal_credentials_prefix != BLS_WITHDRAWAL_PREFIX { + return Err(invalid_operation_error(InvalidOperation::WithdrawalCredentialsPrefix( + state.validators[address_change.validator_index].withdrawal_credentials[0], + ))) + } let domain = compute_domain( DomainType::BlsToExecutionChange, @@ -63,15 +69,24 @@ pub fn process_bls_to_execution_change< Some(state.genesis_validators_root), context, )?; - let signing_root = compute_signing_root(address_change, domain)?; - let pk: &BlsPublicKey = &address_change.message.from_bls_public_key; - assert!(verify_signature(pk, signing_root.as_ref(), &address_change.signature,).is_ok()); - let withdrawal_credentials = vec![ETH1_ADDRESS_WITHDRAWAL_PREFIX]; + let signed_data = + verify_signed_data(&mut address_change.clone(), signature, public_key, domain); + if signed_data.is_err() { + return Err(invalid_operation_error(InvalidOperation::ExecutionChange( + signed_address_change.signature.clone(), + ))) + } + + let validator = &mut state.validators[address_change.validator_index]; + + validator.withdrawal_credentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX; + let mut withdrawal_credentials: Vec = validator.withdrawal_credentials.as_ref().to_vec(); + withdrawal_credentials[12..].copy_from_slice(address_change.to_execution_address.as_ref()); + let withdrawal_credentials: &[u8] = &withdrawal_credentials; + let withdrawal_credentials = + ByteVector::<32>::try_from(withdrawal_credentials).expect("Wrong size"); + validator.withdrawal_credentials = withdrawal_credentials; - let withdrawal_credentials_array: [u8; 32] = - withdrawal_credentials.try_into().expect("Wrong size"); - validator.withdrawal_credentials = ByteVector::try_from(withdrawal_credentials_array.as_ref()) - .expect("Failed to convert array to ByteVector"); Ok(()) } @@ -135,7 +150,7 @@ pub fn process_operations< expected: expected_deposit_count, count: body.deposits.len(), }, - ))); + ))) } body.proposer_slashings .iter_mut() @@ -207,7 +222,7 @@ pub fn process_execution_payload< expected: state.latest_execution_payload_header.block_hash.clone(), } .into(), - )); + )) } let current_epoch = get_current_epoch(state, context); @@ -219,7 +234,7 @@ pub fn process_execution_payload< expected: randao_mix.clone(), } .into(), - )); + )) } let timestamp = compute_timestamp_at_slot(state, state.slot, context)?; @@ -230,7 +245,7 @@ pub fn process_execution_payload< expected: timestamp, } .into(), - )); + )) } let new_payload_request = NewPayloadRequest(payload); diff --git a/ethereum-consensus/src/state_transition/error.rs b/ethereum-consensus/src/state_transition/error.rs index bacdb6759..f61ebe081 100644 --- a/ethereum-consensus/src/state_transition/error.rs +++ b/ethereum-consensus/src/state_transition/error.rs @@ -85,8 +85,14 @@ pub enum InvalidOperation { SyncAggregate(#[from] InvalidSyncAggregate), #[error("invalid execution payload: {0}")] ExecutionPayload(#[from] InvalidExecutionPayload), - #[error("invalid withdrawals: {0}")] - Withdrawal(#[from] InvalidWithdrawals), + #[error("invalid bls signature for execution chang {0:?}")] + ExecutionChange(BlsSignature), + #[error("validator index is out of bounds {0}")] + ValidatorIndex(usize), + #[error("invalid withdrawal credentials prefix{0}")] + WithdrawalCredentialsPrefix(u8), + #[error("invalid withdrawal credentials public key{0:?}")] + WithdrawalCredentialsPublicKey(&'static [u8]), } #[derive(Debug, Error)] From 2c9d9f7810cba4c3118f59e9ace9cecdb29e47cb Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Wed, 20 Sep 2023 05:42:52 +0000 Subject: [PATCH 04/16] chore: lint --- ethereum-consensus/src/capella/block_processing.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 647f5590f..d8b5d1208 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -1,15 +1,14 @@ use crate::{ capella::{ - compute_domain, compute_signing_root, compute_timestamp_at_slot, decrease_balance, + compute_domain, compute_timestamp_at_slot, decrease_balance, get_current_epoch, get_randao_mix, is_fully_withdrawable_validator, is_partially_withdrawable_validator, process_attestation, process_attester_slashing, process_block_header, process_deposit, process_eth1_data, process_proposer_slashing, process_randao, process_sync_aggregate, process_voluntary_exit, BeaconBlock, - BeaconBlockBody, BeaconState, BlsPublicKey, DomainType, ExecutionAddress, ExecutionEngine, + BeaconBlockBody, BeaconState, DomainType, ExecutionAddress, ExecutionEngine, ExecutionPayload, ExecutionPayloadHeader, NewPayloadRequest, SignedBlsToExecutionChange, Withdrawal, }, - crypto::{hash, verify_signature}, primitives::{BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX}, ssz::prelude::*, state_transition::{ @@ -18,6 +17,8 @@ use crate::{ }, }; +use super::verify_signed_data; + pub fn process_bls_to_execution_change< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -42,7 +43,7 @@ pub fn process_bls_to_execution_change< BYTES_PER_LOGS_BLOOM, MAX_EXTRA_DATA_BYTES, >, - signed_address_change: &mut SignedBlsToExecutionChange, + signed_address_change: &SignedBlsToExecutionChange, context: &Context, ) -> Result<()> { let address_change = &signed_address_change.message; @@ -69,6 +70,7 @@ pub fn process_bls_to_execution_change< Some(state.genesis_validators_root), context, )?; + let public_key = &address_change.from_bls_public_key; let signed_data = verify_signed_data(&mut address_change.clone(), signature, public_key, domain); if signed_data.is_err() { From c689eeb1d9b76730ddfd9317b9de2b29edb281cb Mon Sep 17 00:00:00 2001 From: samtvlabs <112424909+samtvlabs@users.noreply.github.com> Date: Wed, 20 Sep 2023 20:11:21 +0000 Subject: [PATCH 05/16] Update ethereum-consensus/src/capella/block_processing.rs Co-authored-by: Alex Stokes --- .../src/capella/block_processing.rs | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index d8b5d1208..6faea7332 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -1,15 +1,15 @@ use crate::{ capella::{ - compute_domain, compute_timestamp_at_slot, decrease_balance, - get_current_epoch, get_randao_mix, is_fully_withdrawable_validator, - is_partially_withdrawable_validator, process_attestation, process_attester_slashing, - process_block_header, process_deposit, process_eth1_data, process_proposer_slashing, - process_randao, process_sync_aggregate, process_voluntary_exit, BeaconBlock, - BeaconBlockBody, BeaconState, DomainType, ExecutionAddress, ExecutionEngine, - ExecutionPayload, ExecutionPayloadHeader, NewPayloadRequest, SignedBlsToExecutionChange, - Withdrawal, + compute_domain, compute_timestamp_at_slot, decrease_balance, get_current_epoch, + get_randao_mix, is_fully_withdrawable_validator, is_partially_withdrawable_validator, + process_attestation, process_attester_slashing, process_block_header, process_deposit, + process_eth1_data, process_proposer_slashing, process_randao, process_sync_aggregate, + process_voluntary_exit, BeaconBlock, BeaconBlockBody, BeaconState, BlsPublicKey, + DomainType, ExecutionAddress, ExecutionEngine, ExecutionPayload, ExecutionPayloadHeader, + NewPayloadRequest, SignedBlsToExecutionChange, Withdrawal, }, primitives::{BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX}, + signing::verify_signed_data, ssz::prelude::*, state_transition::{ invalid_operation_error, Context, InvalidDeposit, InvalidExecutionPayload, @@ -17,8 +17,6 @@ use crate::{ }, }; -use super::verify_signed_data; - pub fn process_bls_to_execution_change< const SLOTS_PER_HISTORICAL_ROOT: usize, const HISTORICAL_ROOTS_LIMIT: usize, @@ -52,7 +50,7 @@ pub fn process_bls_to_execution_change< if address_change.validator_index >= state.validators.len() { return Err(invalid_operation_error(InvalidOperation::ValidatorIndex( address_change.validator_index, - ))) + ))); } let withdrawal_credentials_prefix = @@ -61,7 +59,7 @@ pub fn process_bls_to_execution_change< if withdrawal_credentials_prefix != BLS_WITHDRAWAL_PREFIX { return Err(invalid_operation_error(InvalidOperation::WithdrawalCredentialsPrefix( state.validators[address_change.validator_index].withdrawal_credentials[0], - ))) + ))); } let domain = compute_domain( @@ -76,7 +74,7 @@ pub fn process_bls_to_execution_change< if signed_data.is_err() { return Err(invalid_operation_error(InvalidOperation::ExecutionChange( signed_address_change.signature.clone(), - ))) + ))); } let validator = &mut state.validators[address_change.validator_index]; @@ -152,7 +150,7 @@ pub fn process_operations< expected: expected_deposit_count, count: body.deposits.len(), }, - ))) + ))); } body.proposer_slashings .iter_mut() @@ -224,7 +222,7 @@ pub fn process_execution_payload< expected: state.latest_execution_payload_header.block_hash.clone(), } .into(), - )) + )); } let current_epoch = get_current_epoch(state, context); @@ -236,7 +234,7 @@ pub fn process_execution_payload< expected: randao_mix.clone(), } .into(), - )) + )); } let timestamp = compute_timestamp_at_slot(state, state.slot, context)?; @@ -247,7 +245,7 @@ pub fn process_execution_payload< expected: timestamp, } .into(), - )) + )); } let new_payload_request = NewPayloadRequest(payload); From 9567d591d0efe4bd0357bbcb1c1ae1c3ce0781aa Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Mon, 25 Sep 2023 05:27:39 +0000 Subject: [PATCH 06/16] fix: PR comments --- .../src/capella/block_processing.rs | 66 ++++++++++--------- .../src/state_transition/error.rs | 26 +++++--- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 6faea7332..4cba059b3 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -4,16 +4,17 @@ use crate::{ get_randao_mix, is_fully_withdrawable_validator, is_partially_withdrawable_validator, process_attestation, process_attester_slashing, process_block_header, process_deposit, process_eth1_data, process_proposer_slashing, process_randao, process_sync_aggregate, - process_voluntary_exit, BeaconBlock, BeaconBlockBody, BeaconState, BlsPublicKey, - DomainType, ExecutionAddress, ExecutionEngine, ExecutionPayload, ExecutionPayloadHeader, + process_voluntary_exit, BeaconBlock, BeaconBlockBody, BeaconState, DomainType, + ExecutionAddress, ExecutionEngine, ExecutionPayload, ExecutionPayloadHeader, NewPayloadRequest, SignedBlsToExecutionChange, Withdrawal, }, + crypto::hash, primitives::{BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX}, signing::verify_signed_data, ssz::prelude::*, state_transition::{ - invalid_operation_error, Context, InvalidDeposit, InvalidExecutionPayload, - InvalidOperation, InvalidWithdrawals, Result, + invalid_operation_error, Context, InvalidBlsToExecutionChange, InvalidDeposit, + InvalidExecutionPayload, InvalidOperation, InvalidWithdrawals, Result, }, }; @@ -44,22 +45,34 @@ pub fn process_bls_to_execution_change< signed_address_change: &SignedBlsToExecutionChange, context: &Context, ) -> Result<()> { - let address_change = &signed_address_change.message; + let mut address_change = signed_address_change.message.clone(); let signature = &signed_address_change.signature; if address_change.validator_index >= state.validators.len() { - return Err(invalid_operation_error(InvalidOperation::ValidatorIndex( - address_change.validator_index, - ))); + return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( + InvalidBlsToExecutionChange::BadValidatorIndex(address_change.validator_index), + ))) } let withdrawal_credentials_prefix = state.validators[address_change.validator_index].withdrawal_credentials[0]; if withdrawal_credentials_prefix != BLS_WITHDRAWAL_PREFIX { - return Err(invalid_operation_error(InvalidOperation::WithdrawalCredentialsPrefix( - state.validators[address_change.validator_index].withdrawal_credentials[0], - ))); + return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( + InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix( + state.validators[address_change.validator_index].withdrawal_credentials[0], + ), + ))) + } + + let public_key = address_change.from_bls_public_key.clone(); + + if state.validators[address_change.validator_index].withdrawal_credentials[1..] != + hash(public_key.as_slice())[1..] + { + return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( + InvalidBlsToExecutionChange::WithdrawalCredentialsPublicKey(public_key), + ))) } let domain = compute_domain( @@ -68,24 +81,15 @@ pub fn process_bls_to_execution_change< Some(state.genesis_validators_root), context, )?; - let public_key = &address_change.from_bls_public_key; - let signed_data = - verify_signed_data(&mut address_change.clone(), signature, public_key, domain); - if signed_data.is_err() { - return Err(invalid_operation_error(InvalidOperation::ExecutionChange( - signed_address_change.signature.clone(), - ))); - } + + verify_signed_data(&mut address_change, signature, &public_key, domain)?; let validator = &mut state.validators[address_change.validator_index]; validator.withdrawal_credentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX; - let mut withdrawal_credentials: Vec = validator.withdrawal_credentials.as_ref().to_vec(); - withdrawal_credentials[12..].copy_from_slice(address_change.to_execution_address.as_ref()); - let withdrawal_credentials: &[u8] = &withdrawal_credentials; - let withdrawal_credentials = - ByteVector::<32>::try_from(withdrawal_credentials).expect("Wrong size"); - validator.withdrawal_credentials = withdrawal_credentials; + validator.withdrawal_credentials[1..12].fill(0); + validator.withdrawal_credentials[12..] + .copy_from_slice(address_change.to_execution_address.as_ref()); Ok(()) } @@ -150,7 +154,7 @@ pub fn process_operations< expected: expected_deposit_count, count: body.deposits.len(), }, - ))); + ))) } body.proposer_slashings .iter_mut() @@ -222,7 +226,7 @@ pub fn process_execution_payload< expected: state.latest_execution_payload_header.block_hash.clone(), } .into(), - )); + )) } let current_epoch = get_current_epoch(state, context); @@ -234,7 +238,7 @@ pub fn process_execution_payload< expected: randao_mix.clone(), } .into(), - )); + )) } let timestamp = compute_timestamp_at_slot(state, state.slot, context)?; @@ -245,7 +249,7 @@ pub fn process_execution_payload< expected: timestamp, } .into(), - )); + )) } let new_payload_request = NewPayloadRequest(payload); @@ -316,7 +320,7 @@ pub fn process_withdrawals< provided: execution_payload.withdrawals.to_vec(), expected: expected_withdrawals, }, - ))); + ))) } for withdrawal in &expected_withdrawals { @@ -401,7 +405,7 @@ pub fn get_expected_withdrawals< withdrawal_index += 1; } if withdrawals.len() == context.max_withdrawals_per_payload { - break; + break } validator_index = (validator_index + 1) % state.validators.len(); } diff --git a/ethereum-consensus/src/state_transition/error.rs b/ethereum-consensus/src/state_transition/error.rs index f61ebe081..9b60cf0e9 100644 --- a/ethereum-consensus/src/state_transition/error.rs +++ b/ethereum-consensus/src/state_transition/error.rs @@ -1,5 +1,5 @@ use crate::{ - capella::Withdrawal, + capella::{BlsPublicKey, Withdrawal}, crypto::Error as CryptoError, phase0::{AttestationData, BeaconBlockHeader, Checkpoint}, primitives::{BlsSignature, Bytes32, Epoch, Hash32, Root, Slot, ValidatorIndex}, @@ -85,14 +85,10 @@ pub enum InvalidOperation { SyncAggregate(#[from] InvalidSyncAggregate), #[error("invalid execution payload: {0}")] ExecutionPayload(#[from] InvalidExecutionPayload), - #[error("invalid bls signature for execution chang {0:?}")] - ExecutionChange(BlsSignature), - #[error("validator index is out of bounds {0}")] - ValidatorIndex(usize), - #[error("invalid withdrawal credentials prefix{0}")] - WithdrawalCredentialsPrefix(u8), - #[error("invalid withdrawal credentials public key{0:?}")] - WithdrawalCredentialsPublicKey(&'static [u8]), + #[error("invalid withdrawals: {0}")] + Withdrawal(#[from] InvalidWithdrawals), + #[error("invalid bls signature to execution change: {0}")] + BlsToExecutionChange(#[from] InvalidBlsToExecutionChange), } #[derive(Debug, Error)] @@ -195,6 +191,18 @@ pub enum InvalidWithdrawals { IncorrectWithdrawals { provided: Vec, expected: Vec }, } +#[derive(Debug, Error)] +pub enum InvalidBlsToExecutionChange { + #[error("invalid bls signature for execution change {0:?}")] + ExecutionChange(BlsSignature), + #[error("validator index is out of bounds {0}")] + BadValidatorIndex(usize), + #[error("invalid withdrawal credentials prefix{0}")] + WithdrawalCredentialsPrefix(u8), + #[error("invalid withdrawal credentials public key{0:?}")] + WithdrawalCredentialsPublicKey(BlsPublicKey), +} + #[derive(Debug, Error)] pub enum InvalidSyncAggregate { #[error("invalid sync committee aggregate signature {signature} signing over previous slot block root {root}")] From 2e38cba1bb9f11f54b4fa93fe1a8445ee5428c62 Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Tue, 26 Sep 2023 04:31:30 +0000 Subject: [PATCH 07/16] fix: pr comments - errors --- ethereum-consensus/src/state_transition/error.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ethereum-consensus/src/state_transition/error.rs b/ethereum-consensus/src/state_transition/error.rs index 9b60cf0e9..8833dfa8f 100644 --- a/ethereum-consensus/src/state_transition/error.rs +++ b/ethereum-consensus/src/state_transition/error.rs @@ -194,13 +194,13 @@ pub enum InvalidWithdrawals { #[derive(Debug, Error)] pub enum InvalidBlsToExecutionChange { #[error("invalid bls signature for execution change {0:?}")] - ExecutionChange(BlsSignature), + InvalidSignature(BlsSignature), #[error("validator index is out of bounds {0}")] - BadValidatorIndex(usize), - #[error("invalid withdrawal credentials prefix{0}")] + ValidatorIndexOutOfBounds(usize), + #[error("invalid withdrawal credentials prefix: {0}")] WithdrawalCredentialsPrefix(u8), - #[error("invalid withdrawal credentials public key{0:?}")] - WithdrawalCredentialsPublicKey(BlsPublicKey), + #[error("operation's public key did not match the registered key: {0:?}")] + PublicKeyMismatch(BlsPublicKey), } #[derive(Debug, Error)] From 77d2224bfa950e69453d73027dcc91413e7b34e6 Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Tue, 26 Sep 2023 04:50:33 +0000 Subject: [PATCH 08/16] fix: PR comments - block processing --- .../src/capella/block_processing.rs | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 4cba059b3..21bb3110d 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -1,16 +1,16 @@ use crate::{ capella::{ - compute_domain, compute_timestamp_at_slot, decrease_balance, get_current_epoch, - get_randao_mix, is_fully_withdrawable_validator, is_partially_withdrawable_validator, - process_attestation, process_attester_slashing, process_block_header, process_deposit, - process_eth1_data, process_proposer_slashing, process_randao, process_sync_aggregate, - process_voluntary_exit, BeaconBlock, BeaconBlockBody, BeaconState, DomainType, - ExecutionAddress, ExecutionEngine, ExecutionPayload, ExecutionPayloadHeader, - NewPayloadRequest, SignedBlsToExecutionChange, Withdrawal, + compute_domain, compute_signing_root, compute_timestamp_at_slot, decrease_balance, + get_current_epoch, get_randao_mix, is_fully_withdrawable_validator, + is_partially_withdrawable_validator, process_attestation, process_attester_slashing, + process_block_header, process_deposit, process_eth1_data, process_proposer_slashing, + process_randao, process_sync_aggregate, process_voluntary_exit, BeaconBlock, + BeaconBlockBody, BeaconState, DomainType, ExecutionAddress, ExecutionEngine, + ExecutionPayload, ExecutionPayloadHeader, NewPayloadRequest, SignedBlsToExecutionChange, + Withdrawal, }, - crypto::hash, + crypto::{hash, verify_signature}, primitives::{BLS_WITHDRAWAL_PREFIX, ETH1_ADDRESS_WITHDRAWAL_PREFIX}, - signing::verify_signed_data, ssz::prelude::*, state_transition::{ invalid_operation_error, Context, InvalidBlsToExecutionChange, InvalidDeposit, @@ -42,22 +42,20 @@ pub fn process_bls_to_execution_change< BYTES_PER_LOGS_BLOOM, MAX_EXTRA_DATA_BYTES, >, - signed_address_change: &SignedBlsToExecutionChange, + signed_address_change: &mut SignedBlsToExecutionChange, context: &Context, ) -> Result<()> { - let mut address_change = signed_address_change.message.clone(); + let address_change = &mut signed_address_change.message; let signature = &signed_address_change.signature; + let validator = &mut state.validators[address_change.validator_index].clone(); + let withdrawal_credentials = &mut validator.withdrawal_credentials; if address_change.validator_index >= state.validators.len() { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( - InvalidBlsToExecutionChange::BadValidatorIndex(address_change.validator_index), + InvalidBlsToExecutionChange::ValidatorIndexOutOfBounds(address_change.validator_index), ))) } - - let withdrawal_credentials_prefix = - state.validators[address_change.validator_index].withdrawal_credentials[0]; - - if withdrawal_credentials_prefix != BLS_WITHDRAWAL_PREFIX { + if withdrawal_credentials[0] != BLS_WITHDRAWAL_PREFIX { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix( state.validators[address_change.validator_index].withdrawal_credentials[0], @@ -65,13 +63,11 @@ pub fn process_bls_to_execution_change< ))) } - let public_key = address_change.from_bls_public_key.clone(); + let public_key = &address_change.from_bls_public_key; - if state.validators[address_change.validator_index].withdrawal_credentials[1..] != - hash(public_key.as_slice())[1..] - { + if withdrawal_credentials[1..] != hash(public_key.as_slice())[1..] { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( - InvalidBlsToExecutionChange::WithdrawalCredentialsPublicKey(public_key), + InvalidBlsToExecutionChange::PublicKeyMismatch(public_key.clone()), ))) } @@ -82,9 +78,13 @@ pub fn process_bls_to_execution_change< context, )?; - verify_signed_data(&mut address_change, signature, &public_key, domain)?; - - let validator = &mut state.validators[address_change.validator_index]; + let signing_root = compute_signing_root(address_change, domain)?; + verify_signature(&address_change.from_bls_public_key, signing_root.as_ref(), signature) + .map_err(|_| { + invalid_operation_error(InvalidOperation::BlsToExecutionChange( + InvalidBlsToExecutionChange::InvalidSignature(signature.clone()), + )) + })?; validator.withdrawal_credentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX; validator.withdrawal_credentials[1..12].fill(0); From 358ba32ae26782ce92cf25d1047458052c7619fa Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Tue, 26 Sep 2023 04:58:16 +0000 Subject: [PATCH 09/16] chore: remove clone from validator --- ethereum-consensus/src/capella/block_processing.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 21bb3110d..0be580bfe 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -47,14 +47,15 @@ pub fn process_bls_to_execution_change< ) -> Result<()> { let address_change = &mut signed_address_change.message; let signature = &signed_address_change.signature; - let validator = &mut state.validators[address_change.validator_index].clone(); - let withdrawal_credentials = &mut validator.withdrawal_credentials; if address_change.validator_index >= state.validators.len() { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( InvalidBlsToExecutionChange::ValidatorIndexOutOfBounds(address_change.validator_index), ))) } + + let validator = &mut state.validators[address_change.validator_index]; + let withdrawal_credentials = &mut validator.withdrawal_credentials; if withdrawal_credentials[0] != BLS_WITHDRAWAL_PREFIX { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix( From 14930ea62a227b5cd69c882f63dc0a18f90c59d8 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 26 Sep 2023 08:53:11 -0600 Subject: [PATCH 10/16] Apply suggestions from code review --- .../src/capella/block_processing.rs | 18 ++++++------------ .../src/state_transition/error.rs | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 0be580bfe..5c6f19286 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -59,14 +59,13 @@ pub fn process_bls_to_execution_change< if withdrawal_credentials[0] != BLS_WITHDRAWAL_PREFIX { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix( - state.validators[address_change.validator_index].withdrawal_credentials[0], + withdrawal_credentials[0], ), ))) } let public_key = &address_change.from_bls_public_key; - - if withdrawal_credentials[1..] != hash(public_key.as_slice())[1..] { + if withdrawal_credentials[1..] != hash(public_key.as_ref())[1..] { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( InvalidBlsToExecutionChange::PublicKeyMismatch(public_key.clone()), ))) @@ -80,16 +79,11 @@ pub fn process_bls_to_execution_change< )?; let signing_root = compute_signing_root(address_change, domain)?; - verify_signature(&address_change.from_bls_public_key, signing_root.as_ref(), signature) - .map_err(|_| { - invalid_operation_error(InvalidOperation::BlsToExecutionChange( - InvalidBlsToExecutionChange::InvalidSignature(signature.clone()), - )) - })?; + verify_signature(public_key, signing_root.as_ref(), signature)?; - validator.withdrawal_credentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX; - validator.withdrawal_credentials[1..12].fill(0); - validator.withdrawal_credentials[12..] + withdrawal_credentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX; + withdrawal_credentials[1..12].fill(0); + withdrawal_credentials[12..] .copy_from_slice(address_change.to_execution_address.as_ref()); Ok(()) diff --git a/ethereum-consensus/src/state_transition/error.rs b/ethereum-consensus/src/state_transition/error.rs index 8833dfa8f..82c9242e2 100644 --- a/ethereum-consensus/src/state_transition/error.rs +++ b/ethereum-consensus/src/state_transition/error.rs @@ -195,7 +195,7 @@ pub enum InvalidWithdrawals { pub enum InvalidBlsToExecutionChange { #[error("invalid bls signature for execution change {0:?}")] InvalidSignature(BlsSignature), - #[error("validator index is out of bounds {0}")] + #[error("validator index {0} is out of bounds")] ValidatorIndexOutOfBounds(usize), #[error("invalid withdrawal credentials prefix: {0}")] WithdrawalCredentialsPrefix(u8), From 11c39782275d10b62297cd721e7993c6cb15c5ad Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Tue, 26 Sep 2023 09:08:20 -0600 Subject: [PATCH 11/16] Update ethereum-consensus/src/capella/block_processing.rs --- .../src/capella/block_processing.rs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 5c6f19286..ce4887e21 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -58,27 +58,26 @@ pub fn process_bls_to_execution_change< let withdrawal_credentials = &mut validator.withdrawal_credentials; if withdrawal_credentials[0] != BLS_WITHDRAWAL_PREFIX { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( - InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix( - withdrawal_credentials[0], - ), + InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix(withdrawal_credentials[0]), ))) } - - let public_key = &address_change.from_bls_public_key; - if withdrawal_credentials[1..] != hash(public_key.as_ref())[1..] { - return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( - InvalidBlsToExecutionChange::PublicKeyMismatch(public_key.clone()), - ))) - } - + + // NOTE: compute `signing_root` ahead of the public key check to satisfy borrow check let domain = compute_domain( DomainType::BlsToExecutionChange, None, Some(state.genesis_validators_root), context, )?; - + let signing_root = compute_signing_root(address_change, domain)?; + let public_key = &address_change.from_bls_public_key; + if withdrawal_credentials[1..] != hash(public_key.as_ref())[1..] { + return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( + InvalidBlsToExecutionChange::PublicKeyMismatch(public_key.clone()), + ))) + } + verify_signature(public_key, signing_root.as_ref(), signature)?; withdrawal_credentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX; From dd5445997365c27e369abce19e86759796df7af2 Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Tue, 26 Sep 2023 15:12:32 +0000 Subject: [PATCH 12/16] chore: lint --- ethereum-consensus/src/capella/block_processing.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index ce4887e21..fbdcd563f 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -61,7 +61,7 @@ pub fn process_bls_to_execution_change< InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix(withdrawal_credentials[0]), ))) } - + // NOTE: compute `signing_root` ahead of the public key check to satisfy borrow check let domain = compute_domain( DomainType::BlsToExecutionChange, @@ -69,7 +69,7 @@ pub fn process_bls_to_execution_change< Some(state.genesis_validators_root), context, )?; - + let signing_root = compute_signing_root(address_change, domain)?; let public_key = &address_change.from_bls_public_key; if withdrawal_credentials[1..] != hash(public_key.as_ref())[1..] { @@ -77,13 +77,12 @@ pub fn process_bls_to_execution_change< InvalidBlsToExecutionChange::PublicKeyMismatch(public_key.clone()), ))) } - + verify_signature(public_key, signing_root.as_ref(), signature)?; withdrawal_credentials[0] = ETH1_ADDRESS_WITHDRAWAL_PREFIX; withdrawal_credentials[1..12].fill(0); - withdrawal_credentials[12..] - .copy_from_slice(address_change.to_execution_address.as_ref()); + withdrawal_credentials[12..].copy_from_slice(address_change.to_execution_address.as_ref()); Ok(()) } From 169bef9ac325dd7cd582d414ddc7ce81bf317a8a Mon Sep 17 00:00:00 2001 From: samtvlabs Date: Tue, 26 Sep 2023 18:29:19 +0000 Subject: [PATCH 13/16] fix: pr comments --- ethereum-consensus/src/state_transition/error.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ethereum-consensus/src/state_transition/error.rs b/ethereum-consensus/src/state_transition/error.rs index 82c9242e2..3f05322ec 100644 --- a/ethereum-consensus/src/state_transition/error.rs +++ b/ethereum-consensus/src/state_transition/error.rs @@ -1,8 +1,8 @@ use crate::{ - capella::{BlsPublicKey, Withdrawal}, + capella::Withdrawal, crypto::Error as CryptoError, phase0::{AttestationData, BeaconBlockHeader, Checkpoint}, - primitives::{BlsSignature, Bytes32, Epoch, Hash32, Root, Slot, ValidatorIndex}, + primitives::{BlsPublicKey, BlsSignature, Bytes32, Epoch, Hash32, Root, Slot, ValidatorIndex}, ssz::prelude::*, state_transition::Forks, }; @@ -193,8 +193,6 @@ pub enum InvalidWithdrawals { #[derive(Debug, Error)] pub enum InvalidBlsToExecutionChange { - #[error("invalid bls signature for execution change {0:?}")] - InvalidSignature(BlsSignature), #[error("validator index {0} is out of bounds")] ValidatorIndexOutOfBounds(usize), #[error("invalid withdrawal credentials prefix: {0}")] From f8e0eee02979d4545e42413cbad06597947fd3a6 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 28 Sep 2023 15:57:02 -0600 Subject: [PATCH 14/16] Apply suggestions from code review --- ethereum-consensus/src/capella/block_processing.rs | 5 ++--- ethereum-consensus/src/state_transition/error.rs | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index fbdcd563f..6500c41ce 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -54,8 +54,7 @@ pub fn process_bls_to_execution_change< ))) } - let validator = &mut state.validators[address_change.validator_index]; - let withdrawal_credentials = &mut validator.withdrawal_credentials; + let withdrawal_credentials = &mut state.validators[address_change.validator_index].withdrawal_credentials; if withdrawal_credentials[0] != BLS_WITHDRAWAL_PREFIX { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix(withdrawal_credentials[0]), @@ -69,8 +68,8 @@ pub fn process_bls_to_execution_change< Some(state.genesis_validators_root), context, )?; - let signing_root = compute_signing_root(address_change, domain)?; + let public_key = &address_change.from_bls_public_key; if withdrawal_credentials[1..] != hash(public_key.as_ref())[1..] { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( diff --git a/ethereum-consensus/src/state_transition/error.rs b/ethereum-consensus/src/state_transition/error.rs index 3f05322ec..99dda66b4 100644 --- a/ethereum-consensus/src/state_transition/error.rs +++ b/ethereum-consensus/src/state_transition/error.rs @@ -87,7 +87,7 @@ pub enum InvalidOperation { ExecutionPayload(#[from] InvalidExecutionPayload), #[error("invalid withdrawals: {0}")] Withdrawal(#[from] InvalidWithdrawals), - #[error("invalid bls signature to execution change: {0}")] + #[error("invalid BLS signature to execution change: {0}")] BlsToExecutionChange(#[from] InvalidBlsToExecutionChange), } From 6f6ca8999f4cf601485d423a96754dd5b40dd28b Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 28 Sep 2023 16:01:24 -0600 Subject: [PATCH 15/16] Update ethereum-consensus/src/capella/block_processing.rs --- ethereum-consensus/src/capella/block_processing.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 6500c41ce..36bb1c21f 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -54,7 +54,8 @@ pub fn process_bls_to_execution_change< ))) } - let withdrawal_credentials = &mut state.validators[address_change.validator_index].withdrawal_credentials; + let withdrawal_credentials = + &mut state.validators[address_change.validator_index].withdrawal_credentials; if withdrawal_credentials[0] != BLS_WITHDRAWAL_PREFIX { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix(withdrawal_credentials[0]), From 1cf7cf8411ff06d5ab5844dfd7d4cf97d0b97d18 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 28 Sep 2023 16:04:58 -0600 Subject: [PATCH 16/16] Update ethereum-consensus/src/capella/block_processing.rs --- ethereum-consensus/src/capella/block_processing.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum-consensus/src/capella/block_processing.rs b/ethereum-consensus/src/capella/block_processing.rs index 36bb1c21f..8beb345ae 100644 --- a/ethereum-consensus/src/capella/block_processing.rs +++ b/ethereum-consensus/src/capella/block_processing.rs @@ -55,7 +55,7 @@ pub fn process_bls_to_execution_change< } let withdrawal_credentials = - &mut state.validators[address_change.validator_index].withdrawal_credentials; + &mut state.validators[address_change.validator_index].withdrawal_credentials; if withdrawal_credentials[0] != BLS_WITHDRAWAL_PREFIX { return Err(invalid_operation_error(InvalidOperation::BlsToExecutionChange( InvalidBlsToExecutionChange::WithdrawalCredentialsPrefix(withdrawal_credentials[0]),