mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-20 21:34:46 +00:00
Merge branch 'unstable' of https://github.com/sigp/lighthouse into gloas-block-and-bid-production
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
use criterion::{BatchSize, BenchmarkId, Criterion, black_box, criterion_group, criterion_main};
|
||||
use criterion::{BatchSize, BenchmarkId, Criterion, criterion_group, criterion_main};
|
||||
use fixed_bytes::FixedBytesExtended;
|
||||
use milhouse::List;
|
||||
use rayon::prelude::*;
|
||||
use ssz::Encode;
|
||||
use std::hint::black_box;
|
||||
use std::sync::Arc;
|
||||
use types::{
|
||||
BeaconState, Epoch, Eth1Data, EthSpec, Hash256, MainnetEthSpec, Validator,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{Address, Epoch};
|
||||
use crate::{Address, Epoch, ForkName};
|
||||
use bls::PublicKeyBytes;
|
||||
use context_deserialize::context_deserialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use test_random_derive::TestRandom;
|
||||
@@ -12,6 +13,7 @@ pub type BuilderIndex = u64;
|
||||
#[derive(
|
||||
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Encode, Decode, TestRandom, TreeHash,
|
||||
)]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct Builder {
|
||||
pub pubkey: PublicKeyBytes,
|
||||
#[serde(with = "serde_utils::quoted_u8")]
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
use crate::test_utils::TestRandom;
|
||||
use crate::{
|
||||
ChainSpec, Domain, Epoch, EthSpec, ExecutionBlockHash, ExecutionPayloadEnvelope, Fork, Hash256,
|
||||
SignedRoot, Slot,
|
||||
BeaconState, BeaconStateError, ChainSpec, Domain, Epoch, EthSpec, ExecutionBlockHash,
|
||||
ExecutionPayloadEnvelope, Fork, ForkName, Hash256, SignedRoot, Slot,
|
||||
consts::gloas::BUILDER_INDEX_SELF_BUILD,
|
||||
};
|
||||
use bls::{PublicKey, Signature};
|
||||
use context_deserialize::context_deserialize;
|
||||
use educe::Educe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use ssz_derive::{Decode, Encode};
|
||||
@@ -13,6 +15,7 @@ use tree_hash_derive::TreeHash;
|
||||
#[derive(Debug, Clone, Serialize, Encode, Decode, Deserialize, TestRandom, TreeHash, Educe)]
|
||||
#[educe(PartialEq, Hash(bound(E: EthSpec)))]
|
||||
#[serde(bound = "E: EthSpec")]
|
||||
#[context_deserialize(ForkName)]
|
||||
pub struct SignedExecutionPayloadEnvelope<E: EthSpec> {
|
||||
pub message: ExecutionPayloadEnvelope<E>,
|
||||
pub signature: Signature,
|
||||
@@ -56,6 +59,42 @@ impl<E: EthSpec> SignedExecutionPayloadEnvelope<E> {
|
||||
|
||||
self.signature.verify(pubkey, message)
|
||||
}
|
||||
|
||||
/// Verify `self.signature` using keys drawn from the beacon state.
|
||||
pub fn verify_signature_with_state(
|
||||
&self,
|
||||
state: &BeaconState<E>,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<bool, BeaconStateError> {
|
||||
let builder_index = self.message.builder_index;
|
||||
|
||||
let pubkey_bytes = if builder_index == BUILDER_INDEX_SELF_BUILD {
|
||||
let validator_index = state.latest_block_header().proposer_index;
|
||||
state.get_validator(validator_index as usize)?.pubkey
|
||||
} else {
|
||||
state.get_builder(builder_index)?.pubkey
|
||||
};
|
||||
|
||||
// TODO(gloas): Could use pubkey cache on state here, but it probably isn't worth
|
||||
// it because this function is rarely used. Almost always the envelope should be signature
|
||||
// verified prior to consensus code running.
|
||||
let pubkey = pubkey_bytes.decompress()?;
|
||||
|
||||
// Ensure the state's epoch matches the message's epoch before determining the Fork.
|
||||
if self.epoch() != state.current_epoch() {
|
||||
return Err(BeaconStateError::SignedEnvelopeIncorrectEpoch {
|
||||
state_epoch: state.current_epoch(),
|
||||
envelope_epoch: self.epoch(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(self.verify_signature(
|
||||
&pubkey,
|
||||
&state.fork(),
|
||||
state.genesis_validators_root(),
|
||||
spec,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -23,7 +23,7 @@ use tree_hash_derive::TreeHash;
|
||||
use typenum::Unsigned;
|
||||
|
||||
use crate::{
|
||||
ExecutionBlockHash, ExecutionPayloadBid, Withdrawal,
|
||||
Address, ExecutionBlockHash, ExecutionPayloadBid, Withdrawal,
|
||||
attestation::{
|
||||
AttestationData, AttestationDuty, BeaconCommittee, Checkpoint, CommitteeIndex, PTC,
|
||||
ParticipationFlags, PendingAttestation,
|
||||
@@ -174,8 +174,12 @@ pub enum BeaconStateError {
|
||||
MerkleTreeError(merkle_proof::MerkleTreeError),
|
||||
PartialWithdrawalCountInvalid(usize),
|
||||
NonExecutionAddressWithdrawalCredential,
|
||||
WithdrawalCredentialMissingVersion,
|
||||
WithdrawalCredentialMissingAddress,
|
||||
NoCommitteeFound(CommitteeIndex),
|
||||
InvalidCommitteeIndex(CommitteeIndex),
|
||||
/// `Attestation.data.index` field is invalid in overloaded data index scenario.
|
||||
BadOverloadedDataIndex(u64),
|
||||
InvalidSelectionProof {
|
||||
aggregator_index: u64,
|
||||
},
|
||||
@@ -197,7 +201,12 @@ pub enum BeaconStateError {
|
||||
ProposerLookaheadOutOfBounds {
|
||||
i: usize,
|
||||
},
|
||||
SignedEnvelopeIncorrectEpoch {
|
||||
state_epoch: Epoch,
|
||||
envelope_epoch: Epoch,
|
||||
},
|
||||
InvalidIndicesCount,
|
||||
InvalidExecutionPayloadAvailabilityIndex(usize),
|
||||
}
|
||||
|
||||
/// Control whether an epoch-indexed field can be indexed at the next epoch or not.
|
||||
@@ -1917,6 +1926,15 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
.ok_or(BeaconStateError::UnknownValidator(validator_index))
|
||||
}
|
||||
|
||||
/// Safe indexer for the `builders` list.
|
||||
///
|
||||
/// Will return an error pre-Gloas, or for out-of-bounds indices.
|
||||
pub fn get_builder(&self, builder_index: BuilderIndex) -> Result<&Builder, BeaconStateError> {
|
||||
self.builders()?
|
||||
.get(builder_index as usize)
|
||||
.ok_or(BeaconStateError::UnknownBuilder(builder_index))
|
||||
}
|
||||
|
||||
/// Add a validator to the registry and return the validator index that was allocated for it.
|
||||
pub fn add_validator_to_registry(
|
||||
&mut self,
|
||||
@@ -1963,6 +1981,64 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
Ok(index)
|
||||
}
|
||||
|
||||
/// Add a builder to the registry and return the builder index that was allocated for it.
|
||||
pub fn add_builder_to_registry(
|
||||
&mut self,
|
||||
pubkey: PublicKeyBytes,
|
||||
withdrawal_credentials: Hash256,
|
||||
amount: u64,
|
||||
slot: Slot,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<BuilderIndex, BeaconStateError> {
|
||||
// We are not yet using the spec's `set_or_append_list`, but could consider it if it crops
|
||||
// up elsewhere. It has been retconned into the spec to support index reuse but so far
|
||||
// index reuse is only relevant for builders.
|
||||
let builder_index = self.get_index_for_new_builder()?;
|
||||
let builders = self.builders_mut()?;
|
||||
|
||||
let version = *withdrawal_credentials
|
||||
.as_slice()
|
||||
.first()
|
||||
.ok_or(BeaconStateError::WithdrawalCredentialMissingVersion)?;
|
||||
let execution_address = withdrawal_credentials
|
||||
.as_slice()
|
||||
.get(12..)
|
||||
.and_then(|bytes| Address::try_from(bytes).ok())
|
||||
.ok_or(BeaconStateError::WithdrawalCredentialMissingAddress)?;
|
||||
|
||||
let builder = Builder {
|
||||
pubkey,
|
||||
version,
|
||||
execution_address,
|
||||
balance: amount,
|
||||
deposit_epoch: slot.epoch(E::slots_per_epoch()),
|
||||
withdrawable_epoch: spec.far_future_epoch,
|
||||
};
|
||||
|
||||
if builder_index == builders.len() as u64 {
|
||||
builders.push(builder)?;
|
||||
} else {
|
||||
*builders
|
||||
.get_mut(builder_index as usize)
|
||||
.ok_or(BeaconStateError::UnknownBuilder(builder_index))? = builder;
|
||||
}
|
||||
Ok(builder_index)
|
||||
}
|
||||
|
||||
// TODO(gloas): Optimize this function if we see a lot of registered builders on-chain.
|
||||
// A cache here could be quite fiddly because this calculation depends on withdrawable epoch
|
||||
// and balance - a cache for this would need to be updated whenever either of those fields
|
||||
// changes.
|
||||
pub fn get_index_for_new_builder(&self) -> Result<BuilderIndex, BeaconStateError> {
|
||||
let current_epoch = self.current_epoch();
|
||||
for (index, builder) in self.builders()?.iter().enumerate() {
|
||||
if builder.withdrawable_epoch <= current_epoch && builder.balance == 0 {
|
||||
return Ok(index as u64);
|
||||
}
|
||||
}
|
||||
Ok(self.builders()?.len() as u64)
|
||||
}
|
||||
|
||||
/// Safe copy-on-write accessor for the `validators` list.
|
||||
pub fn get_validator_cow(
|
||||
&mut self,
|
||||
|
||||
@@ -4,6 +4,8 @@ mod validator_registration_data;
|
||||
mod validator_subscription;
|
||||
|
||||
pub use proposer_preparation_data::ProposerPreparationData;
|
||||
pub use validator::{Validator, is_compounding_withdrawal_credential};
|
||||
pub use validator::{
|
||||
Validator, is_builder_withdrawal_credential, is_compounding_withdrawal_credential,
|
||||
};
|
||||
pub use validator_registration_data::{SignedValidatorRegistrationData, ValidatorRegistrationData};
|
||||
pub use validator_subscription::ValidatorSubscription;
|
||||
|
||||
@@ -319,6 +319,14 @@ pub fn is_compounding_withdrawal_credential(
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn is_builder_withdrawal_credential(withdrawal_credentials: Hash256, spec: &ChainSpec) -> bool {
|
||||
withdrawal_credentials
|
||||
.as_slice()
|
||||
.first()
|
||||
.map(|prefix_byte| *prefix_byte == spec.builder_withdrawal_prefix_byte)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
Reference in New Issue
Block a user