mirror of
https://github.com/sigp/lighthouse.git
synced 2026-07-04 21:34:36 +00:00
Merge branch 'beacon-api-electra' of https://github.com/sigp/lighthouse into ef-tests-electra
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -7653,6 +7653,7 @@ dependencies = [
|
|||||||
"safe_arith",
|
"safe_arith",
|
||||||
"serde",
|
"serde",
|
||||||
"slog",
|
"slog",
|
||||||
|
"ssz_types",
|
||||||
"strum",
|
"strum",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tree_hash",
|
"tree_hash",
|
||||||
|
|||||||
@@ -61,10 +61,9 @@ use std::borrow::Cow;
|
|||||||
use strum::AsRefStr;
|
use strum::AsRefStr;
|
||||||
use tree_hash::TreeHash;
|
use tree_hash::TreeHash;
|
||||||
use types::{
|
use types::{
|
||||||
Attestation, AttestationRef, BeaconCommittee,
|
Attestation, AttestationRef, BeaconCommittee, BeaconStateError::NoCommitteeFound, ChainSpec,
|
||||||
BeaconStateError::{self, NoCommitteeFound},
|
CommitteeIndex, Epoch, EthSpec, Hash256, IndexedAttestation, SelectionProof,
|
||||||
ChainSpec, CommitteeIndex, Epoch, EthSpec, ForkName, Hash256, IndexedAttestation,
|
SignedAggregateAndProof, Slot, SubnetId,
|
||||||
SelectionProof, SignedAggregateAndProof, Slot, SubnetId,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use batch::{batch_verify_aggregated_attestations, batch_verify_unaggregated_attestations};
|
pub use batch::{batch_verify_aggregated_attestations, batch_verify_unaggregated_attestations};
|
||||||
@@ -266,30 +265,9 @@ pub enum Error {
|
|||||||
BeaconChainError(BeaconChainError),
|
BeaconChainError(BeaconChainError),
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(electra) the error conversion changes here are to get a test case to pass
|
|
||||||
// this could easily be cleaned up
|
|
||||||
impl From<BeaconChainError> for Error {
|
impl From<BeaconChainError> for Error {
|
||||||
fn from(e: BeaconChainError) -> Self {
|
fn from(e: BeaconChainError) -> Self {
|
||||||
match &e {
|
Self::BeaconChainError(e)
|
||||||
BeaconChainError::BeaconStateError(beacon_state_error) => {
|
|
||||||
if let BeaconStateError::AggregatorNotInCommittee { aggregator_index } =
|
|
||||||
beacon_state_error
|
|
||||||
{
|
|
||||||
Self::AggregatorNotInCommittee {
|
|
||||||
aggregator_index: *aggregator_index,
|
|
||||||
}
|
|
||||||
} else if let BeaconStateError::InvalidSelectionProof { aggregator_index } =
|
|
||||||
beacon_state_error
|
|
||||||
{
|
|
||||||
Self::InvalidSelectionProof {
|
|
||||||
aggregator_index: *aggregator_index,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Error::BeaconChainError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Error::BeaconChainError(e),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1169,7 +1147,7 @@ pub fn verify_propagation_slot_range<S: SlotClock, E: EthSpec>(
|
|||||||
|
|
||||||
let current_fork =
|
let current_fork =
|
||||||
spec.fork_name_at_slot::<E>(slot_clock.now().ok_or(BeaconChainError::UnableToReadSlot)?);
|
spec.fork_name_at_slot::<E>(slot_clock.now().ok_or(BeaconChainError::UnableToReadSlot)?);
|
||||||
let earliest_permissible_slot = if current_fork < ForkName::Deneb {
|
let earliest_permissible_slot = if !current_fork.deneb_enabled() {
|
||||||
one_epoch_prior
|
one_epoch_prior
|
||||||
// EIP-7045
|
// EIP-7045
|
||||||
} else {
|
} else {
|
||||||
@@ -1414,11 +1392,11 @@ pub fn obtain_indexed_attestation_and_committees_per_slot<T: BeaconChainTypes>(
|
|||||||
/// Runs the `map_fn` with the committee and committee count per slot for the given `attestation`.
|
/// Runs the `map_fn` with the committee and committee count per slot for the given `attestation`.
|
||||||
///
|
///
|
||||||
/// This function exists in this odd "map" pattern because efficiently obtaining the committees for
|
/// This function exists in this odd "map" pattern because efficiently obtaining the committees for
|
||||||
/// an attestations slot can be complex. It might involve reading straight from the
|
/// an attestation's slot can be complex. It might involve reading straight from the
|
||||||
/// `beacon_chain.shuffling_cache` or it might involve reading it from a state from the DB. Due to
|
/// `beacon_chain.shuffling_cache` or it might involve reading it from a state from the DB. Due to
|
||||||
/// the complexities of `RwLock`s on the shuffling cache, a simple `Cow` isn't suitable here.
|
/// the complexities of `RwLock`s on the shuffling cache, a simple `Cow` isn't suitable here.
|
||||||
///
|
///
|
||||||
/// If the committees for an `attestation`'s slot isn't found in the `shuffling_cache`, we will read a state
|
/// If the committees for an `attestation`'s slot aren't found in the `shuffling_cache`, we will read a state
|
||||||
/// from disk and then update the `shuffling_cache`.
|
/// from disk and then update the `shuffling_cache`.
|
||||||
///
|
///
|
||||||
/// Committees are sorted by ascending index order 0..committees_per_slot
|
/// Committees are sorted by ascending index order 0..committees_per_slot
|
||||||
|
|||||||
@@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
use beacon_chain::block_verification_types::{AsBlock, ExecutedBlock, RpcBlock};
|
use beacon_chain::block_verification_types::{AsBlock, ExecutedBlock, RpcBlock};
|
||||||
use beacon_chain::{
|
use beacon_chain::{
|
||||||
test_utils::{AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType},
|
test_utils::{
|
||||||
|
test_spec, AttestationStrategy, BeaconChainHarness, BlockStrategy, EphemeralHarnessType,
|
||||||
|
},
|
||||||
AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes, ExecutionPendingBlock,
|
AvailabilityProcessingStatus, BeaconChain, BeaconChainTypes, ExecutionPendingBlock,
|
||||||
};
|
};
|
||||||
use beacon_chain::{
|
use beacon_chain::{
|
||||||
@@ -1210,8 +1212,14 @@ async fn block_gossip_verification() {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn verify_block_for_gossip_slashing_detection() {
|
async fn verify_block_for_gossip_slashing_detection() {
|
||||||
let slasher_dir = tempdir().unwrap();
|
let slasher_dir = tempdir().unwrap();
|
||||||
|
let spec = Arc::new(test_spec::<E>());
|
||||||
let slasher = Arc::new(
|
let slasher = Arc::new(
|
||||||
Slasher::open(SlasherConfig::new(slasher_dir.path().into()), test_logger()).unwrap(),
|
Slasher::open(
|
||||||
|
SlasherConfig::new(slasher_dir.path().into()),
|
||||||
|
spec,
|
||||||
|
test_logger(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let inner_slasher = slasher.clone();
|
let inner_slasher = slasher.clone();
|
||||||
|
|||||||
@@ -184,8 +184,8 @@ pub fn earliest_attestation_validators<E: EthSpec>(
|
|||||||
// Bitfield of validators whose attestations are new/fresh.
|
// Bitfield of validators whose attestations are new/fresh.
|
||||||
let mut new_validators = match attestation.indexed {
|
let mut new_validators = match attestation.indexed {
|
||||||
CompactIndexedAttestation::Base(indexed_att) => indexed_att.aggregation_bits.clone(),
|
CompactIndexedAttestation::Base(indexed_att) => indexed_att.aggregation_bits.clone(),
|
||||||
// TODO(electra) per the comments above, this code path is obsolete post altair fork, so maybe we should just return an empty bitlist here?
|
// This code path is obsolete post altair fork, so we just return an empty bitlist here.
|
||||||
CompactIndexedAttestation::Electra(_) => todo!(),
|
CompactIndexedAttestation::Electra(_) => return BitList::with_capacity(0).unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let state_attestations = if attestation.checkpoint.target_epoch == state.current_epoch() {
|
let state_attestations = if attestation.checkpoint.target_epoch == state.current_epoch() {
|
||||||
|
|||||||
@@ -165,22 +165,22 @@ impl<E: EthSpec> CompactIndexedAttestation<E> {
|
|||||||
CompactIndexedAttestation::Electra(this),
|
CompactIndexedAttestation::Electra(this),
|
||||||
CompactIndexedAttestation::Electra(other),
|
CompactIndexedAttestation::Electra(other),
|
||||||
) => this.should_aggregate(other),
|
) => this.should_aggregate(other),
|
||||||
// TODO(electra) is a mix of electra and base compact indexed attestations an edge case we need to deal with?
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aggregate(&mut self, other: &Self) -> Option<()> {
|
/// Returns `true` if aggregated, otherwise `false`.
|
||||||
|
pub fn aggregate(&mut self, other: &Self) -> bool {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(CompactIndexedAttestation::Base(this), CompactIndexedAttestation::Base(other)) => {
|
(CompactIndexedAttestation::Base(this), CompactIndexedAttestation::Base(other)) => {
|
||||||
this.aggregate(other)
|
this.aggregate(other);
|
||||||
|
true
|
||||||
}
|
}
|
||||||
(
|
(
|
||||||
CompactIndexedAttestation::Electra(this),
|
CompactIndexedAttestation::Electra(this),
|
||||||
CompactIndexedAttestation::Electra(other),
|
CompactIndexedAttestation::Electra(other),
|
||||||
) => this.aggregate_same_committee(other),
|
) => this.aggregate_same_committee(other),
|
||||||
// TODO(electra) is a mix of electra and base compact indexed attestations an edge case we need to deal with?
|
_ => false,
|
||||||
_ => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ impl<E: EthSpec> CompactIndexedAttestationBase<E> {
|
|||||||
.is_zero()
|
.is_zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aggregate(&mut self, other: &Self) -> Option<()> {
|
pub fn aggregate(&mut self, other: &Self) {
|
||||||
self.attesting_indices = self
|
self.attesting_indices = self
|
||||||
.attesting_indices
|
.attesting_indices
|
||||||
.drain(..)
|
.drain(..)
|
||||||
@@ -201,8 +201,6 @@ impl<E: EthSpec> CompactIndexedAttestationBase<E> {
|
|||||||
.collect();
|
.collect();
|
||||||
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
||||||
self.signature.add_assign_aggregate(&other.signature);
|
self.signature.add_assign_aggregate(&other.signature);
|
||||||
|
|
||||||
Some(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,9 +214,10 @@ impl<E: EthSpec> CompactIndexedAttestationElectra<E> {
|
|||||||
.is_zero()
|
.is_zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aggregate_same_committee(&mut self, other: &Self) -> Option<()> {
|
/// Returns `true` if aggregated, otherwise `false`.
|
||||||
|
pub fn aggregate_same_committee(&mut self, other: &Self) -> bool {
|
||||||
if self.committee_bits != other.committee_bits {
|
if self.committee_bits != other.committee_bits {
|
||||||
return None;
|
return false;
|
||||||
}
|
}
|
||||||
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
||||||
self.attesting_indices = self
|
self.attesting_indices = self
|
||||||
@@ -228,7 +227,7 @@ impl<E: EthSpec> CompactIndexedAttestationElectra<E> {
|
|||||||
.dedup()
|
.dedup()
|
||||||
.collect();
|
.collect();
|
||||||
self.signature.add_assign_aggregate(&other.signature);
|
self.signature.add_assign_aggregate(&other.signature);
|
||||||
Some(())
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn aggregate_with_disjoint_committees(&mut self, other: &Self) -> Option<()> {
|
pub fn aggregate_with_disjoint_committees(&mut self, other: &Self) -> Option<()> {
|
||||||
@@ -318,8 +317,7 @@ impl<E: EthSpec> AttestationMap<E> {
|
|||||||
|
|
||||||
for existing_attestation in attestations.iter_mut() {
|
for existing_attestation in attestations.iter_mut() {
|
||||||
if existing_attestation.should_aggregate(&indexed) {
|
if existing_attestation.should_aggregate(&indexed) {
|
||||||
existing_attestation.aggregate(&indexed);
|
aggregated = existing_attestation.aggregate(&indexed);
|
||||||
aggregated = true;
|
|
||||||
} else if *existing_attestation == indexed {
|
} else if *existing_attestation == indexed {
|
||||||
aggregated = true;
|
aggregated = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ use std::ptr;
|
|||||||
use types::{
|
use types::{
|
||||||
sync_aggregate::Error as SyncAggregateError, typenum::Unsigned, AbstractExecPayload,
|
sync_aggregate::Error as SyncAggregateError, typenum::Unsigned, AbstractExecPayload,
|
||||||
Attestation, AttestationData, AttesterSlashing, BeaconState, BeaconStateError, ChainSpec,
|
Attestation, AttestationData, AttesterSlashing, BeaconState, BeaconStateError, ChainSpec,
|
||||||
Epoch, EthSpec, ForkName, ProposerSlashing, SignedBeaconBlock, SignedBlsToExecutionChange,
|
Epoch, EthSpec, ProposerSlashing, SignedBeaconBlock, SignedBlsToExecutionChange,
|
||||||
SignedVoluntaryExit, Slot, SyncAggregate, SyncCommitteeContribution, Validator,
|
SignedVoluntaryExit, Slot, SyncAggregate, SyncCommitteeContribution, Validator,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -316,10 +316,10 @@ impl<E: EthSpec> OperationPool<E> {
|
|||||||
)
|
)
|
||||||
.inspect(|_| num_curr_valid += 1);
|
.inspect(|_| num_curr_valid += 1);
|
||||||
|
|
||||||
let curr_epoch_limit = if fork_name < ForkName::Electra {
|
let curr_epoch_limit = if fork_name.electra_enabled() {
|
||||||
E::MaxAttestations::to_usize()
|
|
||||||
} else {
|
|
||||||
E::MaxAttestationsElectra::to_usize()
|
E::MaxAttestationsElectra::to_usize()
|
||||||
|
} else {
|
||||||
|
E::MaxAttestations::to_usize()
|
||||||
};
|
};
|
||||||
let prev_epoch_limit = if let BeaconState::Base(base_state) = state {
|
let prev_epoch_limit = if let BeaconState::Base(base_state) = state {
|
||||||
std::cmp::min(
|
std::cmp::min(
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ impl<E: EthSpec> ProductionBeaconNode<E> {
|
|||||||
|
|
||||||
let builder = ClientBuilder::new(context.eth_spec_instance.clone())
|
let builder = ClientBuilder::new(context.eth_spec_instance.clone())
|
||||||
.runtime_context(context)
|
.runtime_context(context)
|
||||||
.chain_spec(spec)
|
.chain_spec(spec.clone())
|
||||||
.beacon_processor(client_config.beacon_processor.clone())
|
.beacon_processor(client_config.beacon_processor.clone())
|
||||||
.http_api_config(client_config.http_api.clone())
|
.http_api_config(client_config.http_api.clone())
|
||||||
.disk_store(
|
.disk_store(
|
||||||
@@ -113,8 +113,12 @@ impl<E: EthSpec> ProductionBeaconNode<E> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
let slasher = Arc::new(
|
let slasher = Arc::new(
|
||||||
Slasher::open(slasher_config, log.new(slog::o!("service" => "slasher")))
|
Slasher::open(
|
||||||
.map_err(|e| format!("Slasher open error: {:?}", e))?,
|
slasher_config,
|
||||||
|
Arc::new(spec),
|
||||||
|
log.new(slog::o!("service" => "slasher")),
|
||||||
|
)
|
||||||
|
.map_err(|e| format!("Slasher open error: {:?}", e))?,
|
||||||
);
|
);
|
||||||
builder.slasher(slasher)
|
builder.slasher(slasher)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -146,8 +146,19 @@ For more information on historic state storage see the
|
|||||||
|
|
||||||
To manually specify a checkpoint use the following two flags:
|
To manually specify a checkpoint use the following two flags:
|
||||||
|
|
||||||
* `--checkpoint-state`: accepts an SSZ-encoded `BeaconState` blob
|
* `--checkpoint-state`: accepts an SSZ-encoded `BeaconState` file
|
||||||
* `--checkpoint-block`: accepts an SSZ-encoded `SignedBeaconBlock` blob
|
* `--checkpoint-block`: accepts an SSZ-encoded `SignedBeaconBlock` file
|
||||||
|
* `--checkpoint-blobs`: accepts an SSZ-encoded `Blobs` file
|
||||||
|
|
||||||
|
The command is as following:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -H "Accept: application/octet-stream" "http://localhost:5052/eth/v2/debug/beacon/states/$SLOT" > state.ssz
|
||||||
|
curl -H "Accept: application/octet-stream" "http://localhost:5052/eth/v2/beacon/blocks/$SLOT" > block.ssz
|
||||||
|
curl -H "Accept: application/octet-stream" "http://localhost:5052/eth/v1/beacon/blob_sidecars/$SLOT" > blobs.ssz
|
||||||
|
```
|
||||||
|
|
||||||
|
where `$SLOT` is the slot number. It can be specified as `head` or `finalized` as well.
|
||||||
|
|
||||||
_Both_ the state and block must be provided and the state **must** match the block. The
|
_Both_ the state and block must be provided and the state **must** match the block. The
|
||||||
state may be from the same slot as the block (unadvanced), or advanced to an epoch boundary,
|
state may be from the same slot as the block (unadvanced), or advanced to an epoch boundary,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ validator client or the slasher**.
|
|||||||
|
|
||||||
| Lighthouse version | Release date | Schema version | Downgrade available? |
|
| Lighthouse version | Release date | Schema version | Downgrade available? |
|
||||||
|--------------------|--------------|----------------|----------------------|
|
|--------------------|--------------|----------------|----------------------|
|
||||||
|
| v5.2.0 | Jun 2024 | v19 | yes before Deneb |
|
||||||
| v5.1.0 | Mar 2024 | v19 | yes before Deneb |
|
| v5.1.0 | Mar 2024 | v19 | yes before Deneb |
|
||||||
| v5.0.0 | Feb 2024 | v19 | yes before Deneb |
|
| v5.0.0 | Feb 2024 | v19 | yes before Deneb |
|
||||||
| v4.6.0 | Dec 2023 | v19 | yes before Deneb |
|
| v4.6.0 | Dec 2023 | v19 | yes before Deneb |
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
- [My beacon node logs `WARN Error signalling fork choice waiter`, what should I do?](#bn-fork-choice)
|
- [My beacon node logs `WARN Error signalling fork choice waiter`, what should I do?](#bn-fork-choice)
|
||||||
- [My beacon node logs `ERRO Aggregate attestation queue full`, what should I do?](#bn-queue-full)
|
- [My beacon node logs `ERRO Aggregate attestation queue full`, what should I do?](#bn-queue-full)
|
||||||
- [My beacon node logs `WARN Failed to finalize deposit cache`, what should I do?](#bn-deposit-cache)
|
- [My beacon node logs `WARN Failed to finalize deposit cache`, what should I do?](#bn-deposit-cache)
|
||||||
|
- [My beacon node logs `WARN Could not verify blob sidecar for gossip`, what does it mean?](#bn-blob)
|
||||||
|
|
||||||
## [Validator](#validator-1)
|
## [Validator](#validator-1)
|
||||||
|
|
||||||
@@ -214,6 +215,16 @@ This suggests that the computer resources are being overwhelmed. It could be due
|
|||||||
|
|
||||||
This is a known [bug](https://github.com/sigp/lighthouse/issues/3707) that will fix by itself.
|
This is a known [bug](https://github.com/sigp/lighthouse/issues/3707) that will fix by itself.
|
||||||
|
|
||||||
|
### <a name="bn-blob"></a> My beacon node logs `WARN Could not verify blob sidecar for gossip`, what does it mean?
|
||||||
|
|
||||||
|
An example of the full log is shown below:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Jun 07 23:05:12.170 WARN Could not verify blob sidecar for gossip. Ignoring the blob sidecar, commitment: 0xaa97…6f54, index: 1, root: 0x93b8…c47c, slot: 9248017, error: PastFinalizedSlot { blob_slot: Slot(9248017), finalized_slot: Slot(9248032) }, module: network::network_beacon_processor::gossip_methods:720
|
||||||
|
```
|
||||||
|
|
||||||
|
The `PastFinalizedSlot` indicates that the time at which the node received the blob has past the finalization period. This could be due to a peer sending an earlier blob. The log will be gone when Lighthouse eventually drops the peer.
|
||||||
|
|
||||||
## Validator
|
## Validator
|
||||||
|
|
||||||
### <a name="vc-activation"></a> Why does it take so long for a validator to be activated?
|
### <a name="vc-activation"></a> Why does it take so long for a validator to be activated?
|
||||||
@@ -327,13 +338,24 @@ The first thing is to ensure both consensus and execution clients are synced wit
|
|||||||
|
|
||||||
You can see more information on the [Ethstaker KB](https://ethstaker.gitbook.io/ethstaker-knowledge-base/help/missed-attestations).
|
You can see more information on the [Ethstaker KB](https://ethstaker.gitbook.io/ethstaker-knowledge-base/help/missed-attestations).
|
||||||
|
|
||||||
Another cause for missing attestations is delays during block processing. When this happens, the debug logs will show (debug logs can be found under `$datadir/beacon/logs`):
|
Another cause for missing attestations is the block arriving late, or there are delays during block processing.
|
||||||
|
|
||||||
|
An example of the log: (debug logs can be found under `$datadir/beacon/logs`):
|
||||||
|
|
||||||
```text
|
```text
|
||||||
DEBG Delayed head block set_as_head_delay: Some(93.579425ms), imported_delay: Some(1.460405278s), observed_delay: Some(2.540811921s), block_delay: 4.094796624s, slot: 6837344, proposer_index: 211108, block_root: 0x2c52231c0a5a117401f5231585de8aa5dd963bc7cbc00c544e681342eedd1700, service: beacon
|
Delayed head block, set_as_head_time_ms: 27, imported_time_ms: 168, attestable_delay_ms: 4209, available_delay_ms: 4186, execution_time_ms: 201, blob_delay_ms: 3815, observed_delay_ms: 3984, total_delay_ms: 4381, slot: 1886014, proposer_index: 733, block_root: 0xa7390baac88d50f1cbb5ad81691915f6402385a12521a670bbbd4cd5f8bf3934, service: beacon, module: beacon_chain::canonical_head:1441
|
||||||
```
|
```
|
||||||
|
|
||||||
The fields to look for are `imported_delay > 1s` and `observed_delay < 3s`. The `imported_delay` is how long the node took to process the block. The `imported_delay` of larger than 1 second suggests that there is slowness in processing the block. It could be due to high CPU usage, high I/O disk usage or the clients are doing some background maintenance processes. The `observed_delay` is determined mostly by the proposer and partly by your networking setup (e.g., how long it took for the node to receive the block). The `observed_delay` of less than 3 seconds means that the block is not arriving late from the block proposer. Combining the above, this implies that the validator should have been able to attest to the block, but failed due to slowness in the node processing the block.
|
The field to look for is `attestable_delay`, which defines the time when a block is ready for the validator to attest. If the `attestable_delay` is greater than 4s which has past the window of attestation, the attestation wil fail. In the above example, the delay is mostly caused by late block observed by the node, as shown in `observed_delay`. The `observed_delay` is determined mostly by the proposer and partly by your networking setup (e.g., how long it took for the node to receive the block). Ideally, `observed_delay` should be less than 3 seconds. In this example, the validator failed to attest the block due to the block arriving late.
|
||||||
|
|
||||||
|
Another example of log:
|
||||||
|
|
||||||
|
```
|
||||||
|
DEBG Delayed head block, set_as_head_time_ms: 22, imported_time_ms: 312, attestable_delay_ms: 7052, available_delay_ms: 6874, execution_time_ms: 4694, blob_delay_ms: 2159, observed_delay_ms: 2179, total_delay_ms: 7209, slot: 1885922, proposer_index: 606896, block_root: 0x9966df24d24e722d7133068186f0caa098428696e9f441ac416d0aca70cc0a23, service: beacon, module: beacon_chain::canonical_head:1441
|
||||||
|
/159.69.68.247/tcp/9000, service: libp2p, module: lighthouse_network::service:1811
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, we see that the `execution_time_ms` is 4694ms. The `execution_time_ms` is how long the node took to process the block. The `execution_time_ms` of larger than 1 second suggests that there is slowness in processing the block. If the `execution_time_ms` is high, it could be due to high CPU usage, high I/O disk usage or the clients are doing some background maintenance processes.
|
||||||
|
|
||||||
### <a name="vc-head-vote"></a> Sometimes I miss the attestation head vote, resulting in penalty. Is this normal?
|
### <a name="vc-head-vote"></a> Sometimes I miss the attestation head vote, resulting in penalty. Is this normal?
|
||||||
|
|
||||||
@@ -514,21 +536,23 @@ If you would still like to subscribe to all subnets, you can use the flag `subsc
|
|||||||
|
|
||||||
### <a name="net-quic"></a> How to know how many of my peers are connected via QUIC?
|
### <a name="net-quic"></a> How to know how many of my peers are connected via QUIC?
|
||||||
|
|
||||||
With `--metrics` enabled in the beacon node, you can find the number of peers connected via QUIC using:
|
With `--metrics` enabled in the beacon node, the [Grafana Network dashboard](https://github.com/sigp/lighthouse-metrics/blob/master/dashboards/Network.json) displays the connected by transport, which will show the number of peers connected via QUIC.
|
||||||
|
|
||||||
|
Alternatively, you can find the number of peers connected via QUIC manually using:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -s "http://localhost:5054/metrics" | grep libp2p_quic_peers
|
curl -s "http://localhost:5054/metrics" | grep 'transport="quic"'
|
||||||
```
|
```
|
||||||
|
|
||||||
A response example is:
|
A response example is:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
# HELP libp2p_quic_peers Count of libp2p peers currently connected via QUIC
|
libp2p_peers_multi{direction="inbound",transport="quic"} 27
|
||||||
# TYPE libp2p_quic_peers gauge
|
libp2p_peers_multi{direction="none",transport="quic"} 0
|
||||||
libp2p_quic_peers 4
|
libp2p_peers_multi{direction="outbound",transport="quic"} 9
|
||||||
```
|
```
|
||||||
|
|
||||||
which shows that there are 4 peers connected via QUIC.
|
which shows that there are a total of 36 peers connected via QUIC.
|
||||||
|
|
||||||
## Miscellaneous
|
## Miscellaneous
|
||||||
|
|
||||||
|
|||||||
@@ -114,13 +114,13 @@ changed after initialization.
|
|||||||
|
|
||||||
* Flag: `--slasher-max-db-size GIGABYTES`
|
* Flag: `--slasher-max-db-size GIGABYTES`
|
||||||
* Argument: maximum size of the database in gigabytes
|
* Argument: maximum size of the database in gigabytes
|
||||||
* Default: 256 GB
|
* Default: 512 GB
|
||||||
|
|
||||||
Both database backends LMDB and MDBX place a hard limit on the size of the database
|
Both database backends LMDB and MDBX place a hard limit on the size of the database
|
||||||
file. You can use the `--slasher-max-db-size` flag to set this limit. It can be adjusted after
|
file. You can use the `--slasher-max-db-size` flag to set this limit. It can be adjusted after
|
||||||
initialization if the limit is reached.
|
initialization if the limit is reached.
|
||||||
|
|
||||||
By default the limit is set to accommodate the default history length and around 600K validators (with about 30% headroom) but
|
By default the limit is set to accommodate the default history length and around 1 million validators but
|
||||||
you can set it lower if running with a reduced history length. The space required scales
|
you can set it lower if running with a reduced history length. The space required scales
|
||||||
approximately linearly in validator count and history length, i.e. if you halve either you can halve
|
approximately linearly in validator count and history length, i.e. if you halve either you can halve
|
||||||
the space required.
|
the space required.
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ Once you have the slashing protection database from your existing client, you ca
|
|||||||
using this command:
|
using this command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
lighthouse account validator slashing-protection import <my_interchange.json>
|
lighthouse account validator slashing-protection import filename.json
|
||||||
```
|
```
|
||||||
|
|
||||||
When importing an interchange file, you still need to import the validator keystores themselves
|
When importing an interchange file, you still need to import the validator keystores themselves
|
||||||
@@ -86,7 +86,7 @@ separately, using the instructions for [import validator keys](./mainnet-validat
|
|||||||
You can export Lighthouse's database for use with another client with this command:
|
You can export Lighthouse's database for use with another client with this command:
|
||||||
|
|
||||||
```
|
```
|
||||||
lighthouse account validator slashing-protection export <lighthouse_interchange.json>
|
lighthouse account validator slashing-protection export filename.json
|
||||||
```
|
```
|
||||||
|
|
||||||
The validator client needs to be stopped in order to export, to guarantee that the data exported is
|
The validator client needs to be stopped in order to export, to guarantee that the data exported is
|
||||||
|
|||||||
@@ -626,6 +626,7 @@ pub fn process_withdrawals<E: EthSpec, Payload: AbstractExecPayload<E>>(
|
|||||||
|
|
||||||
// Update pending partial withdrawals [New in Electra:EIP7251]
|
// Update pending partial withdrawals [New in Electra:EIP7251]
|
||||||
if let Some(partial_withdrawals_count) = partial_withdrawals_count {
|
if let Some(partial_withdrawals_count) = partial_withdrawals_count {
|
||||||
|
// TODO(electra): Use efficient pop_front after milhouse release https://github.com/sigp/milhouse/pull/38
|
||||||
let new_partial_withdrawals = state
|
let new_partial_withdrawals = state
|
||||||
.pending_partial_withdrawals()?
|
.pending_partial_withdrawals()?
|
||||||
.iter_from(partial_withdrawals_count)?
|
.iter_from(partial_withdrawals_count)?
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ pub trait TransformPersist {
|
|||||||
pub struct SigVerifiedOp<T: TransformPersist, E: EthSpec> {
|
pub struct SigVerifiedOp<T: TransformPersist, E: EthSpec> {
|
||||||
op: T,
|
op: T,
|
||||||
verified_against: VerifiedAgainst,
|
verified_against: VerifiedAgainst,
|
||||||
//#[ssz(skip_serializing, skip_deserializing)]
|
|
||||||
_phantom: PhantomData<E>,
|
_phantom: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,8 @@ use tree_hash_derive::TreeHash;
|
|||||||
derive(Debug, PartialEq, TreeHash, Serialize,),
|
derive(Debug, PartialEq, TreeHash, Serialize,),
|
||||||
serde(untagged, bound = "E: EthSpec"),
|
serde(untagged, bound = "E: EthSpec"),
|
||||||
tree_hash(enum_behaviour = "transparent")
|
tree_hash(enum_behaviour = "transparent")
|
||||||
)
|
),
|
||||||
|
map_ref_into(AttestationRef)
|
||||||
)]
|
)]
|
||||||
#[derive(
|
#[derive(
|
||||||
arbitrary::Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash,
|
arbitrary::Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash,
|
||||||
@@ -59,19 +60,17 @@ pub struct AggregateAndProof<E: EthSpec> {
|
|||||||
impl<'a, E: EthSpec> AggregateAndProofRef<'a, E> {
|
impl<'a, E: EthSpec> AggregateAndProofRef<'a, E> {
|
||||||
/// Returns `true` if `validator_pubkey` signed over `self.aggregate.data.slot`.
|
/// Returns `true` if `validator_pubkey` signed over `self.aggregate.data.slot`.
|
||||||
pub fn aggregate(self) -> AttestationRef<'a, E> {
|
pub fn aggregate(self) -> AttestationRef<'a, E> {
|
||||||
match self {
|
map_aggregate_and_proof_ref_into_attestation_ref!(&'a _, self, |inner, cons| {
|
||||||
AggregateAndProofRef::Base(a) => AttestationRef::Base(&a.aggregate),
|
cons(&inner.aggregate)
|
||||||
AggregateAndProofRef::Electra(a) => AttestationRef::Electra(&a.aggregate),
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<E: EthSpec> AggregateAndProof<E> {
|
impl<E: EthSpec> AggregateAndProof<E> {
|
||||||
/// Returns `true` if `validator_pubkey` signed over `self.aggregate.data.slot`.
|
/// Returns `true` if `validator_pubkey` signed over `self.aggregate.data.slot`.
|
||||||
pub fn aggregate(&self) -> AttestationRef<E> {
|
pub fn aggregate<'a>(&'a self) -> AttestationRef<'a, E> {
|
||||||
match self {
|
map_aggregate_and_proof_ref_into_attestation_ref!(&'a _, self.to_ref(), |inner, cons| {
|
||||||
AggregateAndProof::Base(a) => AttestationRef::Base(&a.aggregate),
|
cons(&inner.aggregate)
|
||||||
AggregateAndProof::Electra(a) => AttestationRef::Electra(&a.aggregate),
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::slot_data::SlotData;
|
use crate::slot_data::SlotData;
|
||||||
|
use crate::Checkpoint;
|
||||||
use crate::{test_utils::TestRandom, Hash256, Slot};
|
use crate::{test_utils::TestRandom, Hash256, Slot};
|
||||||
use crate::{Checkpoint, ForkName};
|
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use safe_arith::ArithError;
|
use safe_arith::ArithError;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -99,7 +99,7 @@ impl<E: EthSpec> Attestation<E> {
|
|||||||
target: Checkpoint,
|
target: Checkpoint,
|
||||||
spec: &ChainSpec,
|
spec: &ChainSpec,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
if spec.fork_name_at_slot::<E>(slot) >= ForkName::Electra {
|
if spec.fork_name_at_slot::<E>(slot).electra_enabled() {
|
||||||
let mut committee_bits: BitVector<E::MaxCommitteesPerSlot> = BitVector::default();
|
let mut committee_bits: BitVector<E::MaxCommitteesPerSlot> = BitVector::default();
|
||||||
committee_bits
|
committee_bits
|
||||||
.set(committee_index as usize, true)
|
.set(committee_index as usize, true)
|
||||||
@@ -277,16 +277,6 @@ impl<'a, E: EthSpec> AttestationRef<'a, E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> AttestationElectra<E> {
|
impl<E: EthSpec> AttestationElectra<E> {
|
||||||
/// Are the aggregation bitfields of these attestations disjoint?
|
|
||||||
// TODO(electra): check whether the definition from CompactIndexedAttestation::should_aggregate
|
|
||||||
// is useful where this is used, i.e. only consider attestations disjoint when their committees
|
|
||||||
// match AND their aggregation bits do not intersect.
|
|
||||||
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
|
|
||||||
self.aggregation_bits
|
|
||||||
.intersection(&other.aggregation_bits)
|
|
||||||
.is_zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn committee_index(&self) -> Option<u64> {
|
pub fn committee_index(&self) -> Option<u64> {
|
||||||
self.get_committee_indices().first().cloned()
|
self.get_committee_indices().first().cloned()
|
||||||
}
|
}
|
||||||
@@ -304,7 +294,6 @@ impl<E: EthSpec> AttestationElectra<E> {
|
|||||||
/// The aggregation bitfields must be disjoint, and the data must be the same.
|
/// The aggregation bitfields must be disjoint, and the data must be the same.
|
||||||
pub fn aggregate(&mut self, other: &Self) {
|
pub fn aggregate(&mut self, other: &Self) {
|
||||||
debug_assert_eq!(self.data, other.data);
|
debug_assert_eq!(self.data, other.data);
|
||||||
debug_assert!(self.signers_disjoint_from(other));
|
|
||||||
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
||||||
self.signature.add_assign_aggregate(&other.signature);
|
self.signature.add_assign_aggregate(&other.signature);
|
||||||
}
|
}
|
||||||
@@ -358,19 +347,11 @@ impl<E: EthSpec> AttestationElectra<E> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> AttestationBase<E> {
|
impl<E: EthSpec> AttestationBase<E> {
|
||||||
/// Are the aggregation bitfields of these attestations disjoint?
|
|
||||||
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
|
|
||||||
self.aggregation_bits
|
|
||||||
.intersection(&other.aggregation_bits)
|
|
||||||
.is_zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Aggregate another Attestation into this one.
|
/// Aggregate another Attestation into this one.
|
||||||
///
|
///
|
||||||
/// The aggregation bitfields must be disjoint, and the data must be the same.
|
/// The aggregation bitfields must be disjoint, and the data must be the same.
|
||||||
pub fn aggregate(&mut self, other: &Self) {
|
pub fn aggregate(&mut self, other: &Self) {
|
||||||
debug_assert_eq!(self.data, other.data);
|
debug_assert_eq!(self.data, other.data);
|
||||||
debug_assert!(self.signers_disjoint_from(other));
|
|
||||||
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
||||||
self.signature.add_assign_aggregate(&other.signature);
|
self.signature.add_assign_aggregate(&other.signature);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,12 +118,8 @@ impl<E: EthSpec> ExecutionPayloadHeader<E> {
|
|||||||
pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize {
|
pub fn ssz_max_var_len_for_fork(fork_name: ForkName) -> usize {
|
||||||
// Matching here in case variable fields are added in future forks.
|
// Matching here in case variable fields are added in future forks.
|
||||||
match fork_name {
|
match fork_name {
|
||||||
ForkName::Base
|
ForkName::Base | ForkName::Altair => 0,
|
||||||
| ForkName::Altair
|
ForkName::Bellatrix | ForkName::Capella | ForkName::Deneb | ForkName::Electra => {
|
||||||
| ForkName::Bellatrix
|
|
||||||
| ForkName::Capella
|
|
||||||
| ForkName::Deneb
|
|
||||||
| ForkName::Electra => {
|
|
||||||
// Max size of variable length `extra_data` field
|
// Max size of variable length `extra_data` field
|
||||||
E::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len()
|
E::max_extra_data_bytes() * <u8 as Encode>::ssz_fixed_len()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,10 @@ impl ForkName {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deneb_enabled(self) -> bool {
|
||||||
|
self >= ForkName::Deneb
|
||||||
|
}
|
||||||
|
|
||||||
pub fn electra_enabled(self) -> bool {
|
pub fn electra_enabled(self) -> bool {
|
||||||
self >= ForkName::Electra
|
self >= ForkName::Electra
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,38 +240,6 @@ mod quoted_variable_list_u64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
|
|
||||||
#[ssz(enum_behaviour = "union")]
|
|
||||||
pub enum IndexedAttestationOnDisk<E: EthSpec> {
|
|
||||||
Base(IndexedAttestationBase<E>),
|
|
||||||
Electra(IndexedAttestationElectra<E>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Encode, PartialEq)]
|
|
||||||
#[ssz(enum_behaviour = "union")]
|
|
||||||
pub enum IndexedAttestationRefOnDisk<'a, E: EthSpec> {
|
|
||||||
Base(&'a IndexedAttestationBase<E>),
|
|
||||||
Electra(&'a IndexedAttestationElectra<E>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, E: EthSpec> From<&'a IndexedAttestation<E>> for IndexedAttestationRefOnDisk<'a, E> {
|
|
||||||
fn from(attestation: &'a IndexedAttestation<E>) -> Self {
|
|
||||||
match attestation {
|
|
||||||
IndexedAttestation::Base(attestation) => Self::Base(attestation),
|
|
||||||
IndexedAttestation::Electra(attestation) => Self::Electra(attestation),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: EthSpec> From<IndexedAttestationOnDisk<E>> for IndexedAttestation<E> {
|
|
||||||
fn from(attestation: IndexedAttestationOnDisk<E>) -> Self {
|
|
||||||
match attestation {
|
|
||||||
IndexedAttestationOnDisk::Base(attestation) => Self::Base(attestation),
|
|
||||||
IndexedAttestationOnDisk::Electra(attestation) => Self::Electra(attestation),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|||||||
@@ -176,27 +176,28 @@ pub use crate::fork_versioned_response::{ForkVersionDeserialize, ForkVersionedRe
|
|||||||
pub use crate::graffiti::{Graffiti, GRAFFITI_BYTES_LEN};
|
pub use crate::graffiti::{Graffiti, GRAFFITI_BYTES_LEN};
|
||||||
pub use crate::historical_batch::HistoricalBatch;
|
pub use crate::historical_batch::HistoricalBatch;
|
||||||
pub use crate::indexed_attestation::{
|
pub use crate::indexed_attestation::{
|
||||||
IndexedAttestation, IndexedAttestationBase, IndexedAttestationElectra,
|
IndexedAttestation, IndexedAttestationBase, IndexedAttestationElectra, IndexedAttestationRef,
|
||||||
IndexedAttestationOnDisk, IndexedAttestationRef, IndexedAttestationRefOnDisk,
|
|
||||||
};
|
};
|
||||||
pub use crate::light_client_bootstrap::{
|
pub use crate::light_client_bootstrap::{
|
||||||
LightClientBootstrap, LightClientBootstrapAltair, LightClientBootstrapCapella,
|
LightClientBootstrap, LightClientBootstrapAltair, LightClientBootstrapCapella,
|
||||||
LightClientBootstrapDeneb,
|
LightClientBootstrapDeneb, LightClientBootstrapElectra,
|
||||||
};
|
};
|
||||||
pub use crate::light_client_finality_update::{
|
pub use crate::light_client_finality_update::{
|
||||||
LightClientFinalityUpdate, LightClientFinalityUpdateAltair, LightClientFinalityUpdateCapella,
|
LightClientFinalityUpdate, LightClientFinalityUpdateAltair, LightClientFinalityUpdateCapella,
|
||||||
LightClientFinalityUpdateDeneb,
|
LightClientFinalityUpdateDeneb, LightClientFinalityUpdateElectra,
|
||||||
};
|
};
|
||||||
pub use crate::light_client_header::{
|
pub use crate::light_client_header::{
|
||||||
LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb,
|
LightClientHeader, LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb,
|
||||||
|
LightClientHeaderElectra,
|
||||||
};
|
};
|
||||||
pub use crate::light_client_optimistic_update::{
|
pub use crate::light_client_optimistic_update::{
|
||||||
LightClientOptimisticUpdate, LightClientOptimisticUpdateAltair,
|
LightClientOptimisticUpdate, LightClientOptimisticUpdateAltair,
|
||||||
LightClientOptimisticUpdateCapella, LightClientOptimisticUpdateDeneb,
|
LightClientOptimisticUpdateCapella, LightClientOptimisticUpdateDeneb,
|
||||||
|
LightClientOptimisticUpdateElectra,
|
||||||
};
|
};
|
||||||
pub use crate::light_client_update::{
|
pub use crate::light_client_update::{
|
||||||
Error as LightClientError, LightClientUpdate, LightClientUpdateAltair,
|
Error as LightClientError, LightClientUpdate, LightClientUpdateAltair,
|
||||||
LightClientUpdateCapella, LightClientUpdateDeneb,
|
LightClientUpdateCapella, LightClientUpdateDeneb, LightClientUpdateElectra,
|
||||||
};
|
};
|
||||||
pub use crate::participation_flags::ParticipationFlags;
|
pub use crate::participation_flags::ParticipationFlags;
|
||||||
pub use crate::participation_list::ParticipationList;
|
pub use crate::participation_list::ParticipationList;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
light_client_update::*, test_utils::TestRandom, BeaconState, ChainSpec, EthSpec, FixedVector,
|
light_client_update::*, test_utils::TestRandom, BeaconState, ChainSpec, EthSpec, FixedVector,
|
||||||
ForkName, ForkVersionDeserialize, Hash256, LightClientHeader, LightClientHeaderAltair,
|
ForkName, ForkVersionDeserialize, Hash256, LightClientHeader, LightClientHeaderAltair,
|
||||||
LightClientHeaderCapella, LightClientHeaderDeneb, SignedBeaconBlock, Slot, SyncCommittee,
|
LightClientHeaderCapella, LightClientHeaderDeneb, LightClientHeaderElectra, SignedBeaconBlock,
|
||||||
|
Slot, SyncCommittee,
|
||||||
};
|
};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
@@ -16,7 +17,7 @@ use tree_hash_derive::TreeHash;
|
|||||||
/// A LightClientBootstrap is the initializer we send over to light_client nodes
|
/// A LightClientBootstrap is the initializer we send over to light_client nodes
|
||||||
/// that are trying to generate their basic storage when booting up.
|
/// that are trying to generate their basic storage when booting up.
|
||||||
#[superstruct(
|
#[superstruct(
|
||||||
variants(Altair, Capella, Deneb),
|
variants(Altair, Capella, Deneb, Electra),
|
||||||
variant_attributes(
|
variant_attributes(
|
||||||
derive(
|
derive(
|
||||||
Debug,
|
Debug,
|
||||||
@@ -51,6 +52,8 @@ pub struct LightClientBootstrap<E: EthSpec> {
|
|||||||
pub header: LightClientHeaderCapella<E>,
|
pub header: LightClientHeaderCapella<E>,
|
||||||
#[superstruct(only(Deneb), partial_getter(rename = "header_deneb"))]
|
#[superstruct(only(Deneb), partial_getter(rename = "header_deneb"))]
|
||||||
pub header: LightClientHeaderDeneb<E>,
|
pub header: LightClientHeaderDeneb<E>,
|
||||||
|
#[superstruct(only(Electra), partial_getter(rename = "header_electra"))]
|
||||||
|
pub header: LightClientHeaderElectra<E>,
|
||||||
/// The `SyncCommittee` used in the requested period.
|
/// The `SyncCommittee` used in the requested period.
|
||||||
pub current_sync_committee: Arc<SyncCommittee<E>>,
|
pub current_sync_committee: Arc<SyncCommittee<E>>,
|
||||||
/// Merkle proof for sync committee
|
/// Merkle proof for sync committee
|
||||||
@@ -66,6 +69,7 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
|||||||
Self::Altair(_) => func(ForkName::Altair),
|
Self::Altair(_) => func(ForkName::Altair),
|
||||||
Self::Capella(_) => func(ForkName::Capella),
|
Self::Capella(_) => func(ForkName::Capella),
|
||||||
Self::Deneb(_) => func(ForkName::Deneb),
|
Self::Deneb(_) => func(ForkName::Deneb),
|
||||||
|
Self::Electra(_) => func(ForkName::Electra),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,9 +86,8 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
|||||||
Self::Altair(LightClientBootstrapAltair::from_ssz_bytes(bytes)?)
|
Self::Altair(LightClientBootstrapAltair::from_ssz_bytes(bytes)?)
|
||||||
}
|
}
|
||||||
ForkName::Capella => Self::Capella(LightClientBootstrapCapella::from_ssz_bytes(bytes)?),
|
ForkName::Capella => Self::Capella(LightClientBootstrapCapella::from_ssz_bytes(bytes)?),
|
||||||
ForkName::Deneb | ForkName::Electra => {
|
ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb::from_ssz_bytes(bytes)?),
|
||||||
Self::Deneb(LightClientBootstrapDeneb::from_ssz_bytes(bytes)?)
|
ForkName::Electra => Self::Electra(LightClientBootstrapElectra::from_ssz_bytes(bytes)?),
|
||||||
}
|
|
||||||
ForkName::Base => {
|
ForkName::Base => {
|
||||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||||
"LightClientBootstrap decoding for {fork_name} not implemented"
|
"LightClientBootstrap decoding for {fork_name} not implemented"
|
||||||
@@ -97,18 +100,16 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
|||||||
|
|
||||||
#[allow(clippy::arithmetic_side_effects)]
|
#[allow(clippy::arithmetic_side_effects)]
|
||||||
pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize {
|
pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize {
|
||||||
// TODO(electra): review electra changes
|
let fixed_len = match fork_name {
|
||||||
match fork_name {
|
|
||||||
ForkName::Base => 0,
|
ForkName::Base => 0,
|
||||||
ForkName::Altair
|
ForkName::Altair | ForkName::Bellatrix => {
|
||||||
| ForkName::Bellatrix
|
|
||||||
| ForkName::Capella
|
|
||||||
| ForkName::Deneb
|
|
||||||
| ForkName::Electra => {
|
|
||||||
<LightClientBootstrapAltair<E> as Encode>::ssz_fixed_len()
|
<LightClientBootstrapAltair<E> as Encode>::ssz_fixed_len()
|
||||||
+ LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
|
|
||||||
}
|
}
|
||||||
}
|
ForkName::Capella => <LightClientBootstrapCapella<E> as Encode>::ssz_fixed_len(),
|
||||||
|
ForkName::Deneb => <LightClientBootstrapDeneb<E> as Encode>::ssz_fixed_len(),
|
||||||
|
ForkName::Electra => <LightClientBootstrapElectra<E> as Encode>::ssz_fixed_len(),
|
||||||
|
};
|
||||||
|
fixed_len + LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_beacon_state(
|
pub fn from_beacon_state(
|
||||||
@@ -138,11 +139,16 @@ impl<E: EthSpec> LightClientBootstrap<E> {
|
|||||||
current_sync_committee,
|
current_sync_committee,
|
||||||
current_sync_committee_branch,
|
current_sync_committee_branch,
|
||||||
}),
|
}),
|
||||||
ForkName::Deneb | ForkName::Electra => Self::Deneb(LightClientBootstrapDeneb {
|
ForkName::Deneb => Self::Deneb(LightClientBootstrapDeneb {
|
||||||
header: LightClientHeaderDeneb::block_to_light_client_header(block)?,
|
header: LightClientHeaderDeneb::block_to_light_client_header(block)?,
|
||||||
current_sync_committee,
|
current_sync_committee,
|
||||||
current_sync_committee_branch,
|
current_sync_committee_branch,
|
||||||
}),
|
}),
|
||||||
|
ForkName::Electra => Self::Electra(LightClientBootstrapElectra {
|
||||||
|
header: LightClientHeaderElectra::block_to_light_client_header(block)?,
|
||||||
|
current_sync_committee,
|
||||||
|
current_sync_committee_branch,
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(light_client_bootstrap)
|
Ok(light_client_bootstrap)
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ use super::{EthSpec, FixedVector, Hash256, LightClientHeader, Slot, SyncAggregat
|
|||||||
use crate::ChainSpec;
|
use crate::ChainSpec;
|
||||||
use crate::{
|
use crate::{
|
||||||
light_client_update::*, test_utils::TestRandom, ForkName, ForkVersionDeserialize,
|
light_client_update::*, test_utils::TestRandom, ForkName, ForkVersionDeserialize,
|
||||||
LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb, SignedBeaconBlock,
|
LightClientHeaderAltair, LightClientHeaderCapella, LightClientHeaderDeneb,
|
||||||
|
LightClientHeaderElectra, SignedBeaconBlock,
|
||||||
};
|
};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
@@ -15,7 +16,7 @@ use test_random_derive::TestRandom;
|
|||||||
use tree_hash_derive::TreeHash;
|
use tree_hash_derive::TreeHash;
|
||||||
|
|
||||||
#[superstruct(
|
#[superstruct(
|
||||||
variants(Altair, Capella, Deneb),
|
variants(Altair, Capella, Deneb, Electra),
|
||||||
variant_attributes(
|
variant_attributes(
|
||||||
derive(
|
derive(
|
||||||
Debug,
|
Debug,
|
||||||
@@ -50,6 +51,8 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {
|
|||||||
pub attested_header: LightClientHeaderCapella<E>,
|
pub attested_header: LightClientHeaderCapella<E>,
|
||||||
#[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))]
|
#[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))]
|
||||||
pub attested_header: LightClientHeaderDeneb<E>,
|
pub attested_header: LightClientHeaderDeneb<E>,
|
||||||
|
#[superstruct(only(Electra), partial_getter(rename = "attested_header_electra"))]
|
||||||
|
pub attested_header: LightClientHeaderElectra<E>,
|
||||||
/// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch).
|
/// The last `BeaconBlockHeader` from the last attested finalized block (end of epoch).
|
||||||
#[superstruct(only(Altair), partial_getter(rename = "finalized_header_altair"))]
|
#[superstruct(only(Altair), partial_getter(rename = "finalized_header_altair"))]
|
||||||
pub finalized_header: LightClientHeaderAltair<E>,
|
pub finalized_header: LightClientHeaderAltair<E>,
|
||||||
@@ -57,6 +60,8 @@ pub struct LightClientFinalityUpdate<E: EthSpec> {
|
|||||||
pub finalized_header: LightClientHeaderCapella<E>,
|
pub finalized_header: LightClientHeaderCapella<E>,
|
||||||
#[superstruct(only(Deneb), partial_getter(rename = "finalized_header_deneb"))]
|
#[superstruct(only(Deneb), partial_getter(rename = "finalized_header_deneb"))]
|
||||||
pub finalized_header: LightClientHeaderDeneb<E>,
|
pub finalized_header: LightClientHeaderDeneb<E>,
|
||||||
|
#[superstruct(only(Electra), partial_getter(rename = "finalized_header_electra"))]
|
||||||
|
pub finalized_header: LightClientHeaderElectra<E>,
|
||||||
/// Merkle proof attesting finalized header.
|
/// Merkle proof attesting finalized header.
|
||||||
#[test_random(default)]
|
#[test_random(default)]
|
||||||
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
|
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
|
||||||
@@ -80,7 +85,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
|||||||
.map_err(|_| Error::InconsistentFork)?
|
.map_err(|_| Error::InconsistentFork)?
|
||||||
{
|
{
|
||||||
ForkName::Altair | ForkName::Bellatrix => {
|
ForkName::Altair | ForkName::Bellatrix => {
|
||||||
let finality_update = LightClientFinalityUpdateAltair {
|
Self::Altair(LightClientFinalityUpdateAltair {
|
||||||
attested_header: LightClientHeaderAltair::block_to_light_client_header(
|
attested_header: LightClientHeaderAltair::block_to_light_client_header(
|
||||||
attested_block,
|
attested_block,
|
||||||
)?,
|
)?,
|
||||||
@@ -90,37 +95,42 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
|||||||
finality_branch,
|
finality_branch,
|
||||||
sync_aggregate,
|
sync_aggregate,
|
||||||
signature_slot,
|
signature_slot,
|
||||||
};
|
})
|
||||||
Self::Altair(finality_update)
|
|
||||||
}
|
|
||||||
ForkName::Capella => {
|
|
||||||
let finality_update = LightClientFinalityUpdateCapella {
|
|
||||||
attested_header: LightClientHeaderCapella::block_to_light_client_header(
|
|
||||||
attested_block,
|
|
||||||
)?,
|
|
||||||
finalized_header: LightClientHeaderCapella::block_to_light_client_header(
|
|
||||||
finalized_block,
|
|
||||||
)?,
|
|
||||||
finality_branch,
|
|
||||||
sync_aggregate,
|
|
||||||
signature_slot,
|
|
||||||
};
|
|
||||||
Self::Capella(finality_update)
|
|
||||||
}
|
|
||||||
ForkName::Deneb | ForkName::Electra => {
|
|
||||||
let finality_update = LightClientFinalityUpdateDeneb {
|
|
||||||
attested_header: LightClientHeaderDeneb::block_to_light_client_header(
|
|
||||||
attested_block,
|
|
||||||
)?,
|
|
||||||
finalized_header: LightClientHeaderDeneb::block_to_light_client_header(
|
|
||||||
finalized_block,
|
|
||||||
)?,
|
|
||||||
finality_branch,
|
|
||||||
sync_aggregate,
|
|
||||||
signature_slot,
|
|
||||||
};
|
|
||||||
Self::Deneb(finality_update)
|
|
||||||
}
|
}
|
||||||
|
ForkName::Capella => Self::Capella(LightClientFinalityUpdateCapella {
|
||||||
|
attested_header: LightClientHeaderCapella::block_to_light_client_header(
|
||||||
|
attested_block,
|
||||||
|
)?,
|
||||||
|
finalized_header: LightClientHeaderCapella::block_to_light_client_header(
|
||||||
|
finalized_block,
|
||||||
|
)?,
|
||||||
|
finality_branch,
|
||||||
|
sync_aggregate,
|
||||||
|
signature_slot,
|
||||||
|
}),
|
||||||
|
ForkName::Deneb => Self::Deneb(LightClientFinalityUpdateDeneb {
|
||||||
|
attested_header: LightClientHeaderDeneb::block_to_light_client_header(
|
||||||
|
attested_block,
|
||||||
|
)?,
|
||||||
|
finalized_header: LightClientHeaderDeneb::block_to_light_client_header(
|
||||||
|
finalized_block,
|
||||||
|
)?,
|
||||||
|
finality_branch,
|
||||||
|
sync_aggregate,
|
||||||
|
signature_slot,
|
||||||
|
}),
|
||||||
|
ForkName::Electra => Self::Electra(LightClientFinalityUpdateElectra {
|
||||||
|
attested_header: LightClientHeaderElectra::block_to_light_client_header(
|
||||||
|
attested_block,
|
||||||
|
)?,
|
||||||
|
finalized_header: LightClientHeaderElectra::block_to_light_client_header(
|
||||||
|
finalized_block,
|
||||||
|
)?,
|
||||||
|
finality_branch,
|
||||||
|
sync_aggregate,
|
||||||
|
signature_slot,
|
||||||
|
}),
|
||||||
|
|
||||||
ForkName::Base => return Err(Error::AltairForkNotActive),
|
ForkName::Base => return Err(Error::AltairForkNotActive),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -135,6 +145,7 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
|||||||
Self::Altair(_) => func(ForkName::Altair),
|
Self::Altair(_) => func(ForkName::Altair),
|
||||||
Self::Capella(_) => func(ForkName::Capella),
|
Self::Capella(_) => func(ForkName::Capella),
|
||||||
Self::Deneb(_) => func(ForkName::Deneb),
|
Self::Deneb(_) => func(ForkName::Deneb),
|
||||||
|
Self::Electra(_) => func(ForkName::Electra),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,8 +164,9 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
|||||||
ForkName::Capella => {
|
ForkName::Capella => {
|
||||||
Self::Capella(LightClientFinalityUpdateCapella::from_ssz_bytes(bytes)?)
|
Self::Capella(LightClientFinalityUpdateCapella::from_ssz_bytes(bytes)?)
|
||||||
}
|
}
|
||||||
ForkName::Deneb | ForkName::Electra => {
|
ForkName::Deneb => Self::Deneb(LightClientFinalityUpdateDeneb::from_ssz_bytes(bytes)?),
|
||||||
Self::Deneb(LightClientFinalityUpdateDeneb::from_ssz_bytes(bytes)?)
|
ForkName::Electra => {
|
||||||
|
Self::Electra(LightClientFinalityUpdateElectra::from_ssz_bytes(bytes)?)
|
||||||
}
|
}
|
||||||
ForkName::Base => {
|
ForkName::Base => {
|
||||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||||
@@ -168,18 +180,17 @@ impl<E: EthSpec> LightClientFinalityUpdate<E> {
|
|||||||
|
|
||||||
#[allow(clippy::arithmetic_side_effects)]
|
#[allow(clippy::arithmetic_side_effects)]
|
||||||
pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize {
|
pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize {
|
||||||
// TODO(electra): review electra changes
|
let fixed_size = match fork_name {
|
||||||
match fork_name {
|
|
||||||
ForkName::Base => 0,
|
ForkName::Base => 0,
|
||||||
ForkName::Altair
|
ForkName::Altair | ForkName::Bellatrix => {
|
||||||
| ForkName::Bellatrix
|
|
||||||
| ForkName::Capella
|
|
||||||
| ForkName::Deneb
|
|
||||||
| ForkName::Electra => {
|
|
||||||
<LightClientFinalityUpdateAltair<E> as Encode>::ssz_fixed_len()
|
<LightClientFinalityUpdateAltair<E> as Encode>::ssz_fixed_len()
|
||||||
+ 2 * LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
|
|
||||||
}
|
}
|
||||||
}
|
ForkName::Capella => <LightClientFinalityUpdateCapella<E> as Encode>::ssz_fixed_len(),
|
||||||
|
ForkName::Deneb => <LightClientFinalityUpdateDeneb<E> as Encode>::ssz_fixed_len(),
|
||||||
|
ForkName::Electra => <LightClientFinalityUpdateElectra<E> as Encode>::ssz_fixed_len(),
|
||||||
|
};
|
||||||
|
// `2 *` because there are two headers in the update
|
||||||
|
fixed_size + 2 * LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::ForkVersionDeserialize;
|
|||||||
use crate::{light_client_update::*, BeaconBlockBody};
|
use crate::{light_client_update::*, BeaconBlockBody};
|
||||||
use crate::{
|
use crate::{
|
||||||
test_utils::TestRandom, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb,
|
test_utils::TestRandom, EthSpec, ExecutionPayloadHeaderCapella, ExecutionPayloadHeaderDeneb,
|
||||||
FixedVector, Hash256, SignedBeaconBlock,
|
ExecutionPayloadHeaderElectra, FixedVector, Hash256, SignedBeaconBlock,
|
||||||
};
|
};
|
||||||
use crate::{BeaconBlockHeader, ExecutionPayloadHeader};
|
use crate::{BeaconBlockHeader, ExecutionPayloadHeader};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
@@ -17,7 +17,7 @@ use test_random_derive::TestRandom;
|
|||||||
use tree_hash_derive::TreeHash;
|
use tree_hash_derive::TreeHash;
|
||||||
|
|
||||||
#[superstruct(
|
#[superstruct(
|
||||||
variants(Altair, Capella, Deneb),
|
variants(Altair, Capella, Deneb, Electra),
|
||||||
variant_attributes(
|
variant_attributes(
|
||||||
derive(
|
derive(
|
||||||
Debug,
|
Debug,
|
||||||
@@ -54,8 +54,13 @@ pub struct LightClientHeader<E: EthSpec> {
|
|||||||
pub execution: ExecutionPayloadHeaderCapella<E>,
|
pub execution: ExecutionPayloadHeaderCapella<E>,
|
||||||
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_header_deneb"))]
|
#[superstruct(only(Deneb), partial_getter(rename = "execution_payload_header_deneb"))]
|
||||||
pub execution: ExecutionPayloadHeaderDeneb<E>,
|
pub execution: ExecutionPayloadHeaderDeneb<E>,
|
||||||
|
#[superstruct(
|
||||||
|
only(Electra),
|
||||||
|
partial_getter(rename = "execution_payload_header_electra")
|
||||||
|
)]
|
||||||
|
pub execution: ExecutionPayloadHeaderElectra<E>,
|
||||||
|
|
||||||
#[superstruct(only(Capella, Deneb))]
|
#[superstruct(only(Capella, Deneb, Electra))]
|
||||||
pub execution_branch: FixedVector<Hash256, ExecutionPayloadProofLen>,
|
pub execution_branch: FixedVector<Hash256, ExecutionPayloadProofLen>,
|
||||||
|
|
||||||
#[ssz(skip_serializing, skip_deserializing)]
|
#[ssz(skip_serializing, skip_deserializing)]
|
||||||
@@ -81,9 +86,12 @@ impl<E: EthSpec> LightClientHeader<E> {
|
|||||||
ForkName::Capella => LightClientHeader::Capella(
|
ForkName::Capella => LightClientHeader::Capella(
|
||||||
LightClientHeaderCapella::block_to_light_client_header(block)?,
|
LightClientHeaderCapella::block_to_light_client_header(block)?,
|
||||||
),
|
),
|
||||||
ForkName::Deneb | ForkName::Electra => LightClientHeader::Deneb(
|
ForkName::Deneb => LightClientHeader::Deneb(
|
||||||
LightClientHeaderDeneb::block_to_light_client_header(block)?,
|
LightClientHeaderDeneb::block_to_light_client_header(block)?,
|
||||||
),
|
),
|
||||||
|
ForkName::Electra => LightClientHeader::Electra(
|
||||||
|
LightClientHeaderElectra::block_to_light_client_header(block)?,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
Ok(header)
|
Ok(header)
|
||||||
}
|
}
|
||||||
@@ -96,9 +104,12 @@ impl<E: EthSpec> LightClientHeader<E> {
|
|||||||
ForkName::Capella => {
|
ForkName::Capella => {
|
||||||
LightClientHeader::Capella(LightClientHeaderCapella::from_ssz_bytes(bytes)?)
|
LightClientHeader::Capella(LightClientHeaderCapella::from_ssz_bytes(bytes)?)
|
||||||
}
|
}
|
||||||
ForkName::Deneb | ForkName::Electra => {
|
ForkName::Deneb => {
|
||||||
LightClientHeader::Deneb(LightClientHeaderDeneb::from_ssz_bytes(bytes)?)
|
LightClientHeader::Deneb(LightClientHeaderDeneb::from_ssz_bytes(bytes)?)
|
||||||
}
|
}
|
||||||
|
ForkName::Electra => {
|
||||||
|
LightClientHeader::Electra(LightClientHeaderElectra::from_ssz_bytes(bytes)?)
|
||||||
|
}
|
||||||
ForkName::Base => {
|
ForkName::Base => {
|
||||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||||
"LightClientHeader decoding for {fork_name} not implemented"
|
"LightClientHeader decoding for {fork_name} not implemented"
|
||||||
@@ -192,6 +203,34 @@ impl<E: EthSpec> LightClientHeaderDeneb<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: EthSpec> LightClientHeaderElectra<E> {
|
||||||
|
pub fn block_to_light_client_header(block: &SignedBeaconBlock<E>) -> Result<Self, Error> {
|
||||||
|
let payload = block
|
||||||
|
.message()
|
||||||
|
.execution_payload()?
|
||||||
|
.execution_payload_electra()?;
|
||||||
|
|
||||||
|
let header = ExecutionPayloadHeaderElectra::from(payload);
|
||||||
|
let beacon_block_body = BeaconBlockBody::from(
|
||||||
|
block
|
||||||
|
.message()
|
||||||
|
.body_electra()
|
||||||
|
.map_err(|_| Error::BeaconBlockBodyError)?
|
||||||
|
.to_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let execution_branch =
|
||||||
|
beacon_block_body.block_body_merkle_proof(EXECUTION_PAYLOAD_INDEX)?;
|
||||||
|
|
||||||
|
Ok(LightClientHeaderElectra {
|
||||||
|
beacon: block.message().block_header(),
|
||||||
|
execution: header,
|
||||||
|
execution_branch: FixedVector::new(execution_branch)?,
|
||||||
|
_phantom_data: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> ForkVersionDeserialize for LightClientHeader<E> {
|
impl<E: EthSpec> ForkVersionDeserialize for LightClientHeader<E> {
|
||||||
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
|
fn deserialize_by_fork<'de, D: serde::Deserializer<'de>>(
|
||||||
value: serde_json::value::Value,
|
value: serde_json::value::Value,
|
||||||
@@ -204,9 +243,12 @@ impl<E: EthSpec> ForkVersionDeserialize for LightClientHeader<E> {
|
|||||||
ForkName::Capella => serde_json::from_value(value)
|
ForkName::Capella => serde_json::from_value(value)
|
||||||
.map(|light_client_header| Self::Capella(light_client_header))
|
.map(|light_client_header| Self::Capella(light_client_header))
|
||||||
.map_err(serde::de::Error::custom),
|
.map_err(serde::de::Error::custom),
|
||||||
ForkName::Deneb | ForkName::Electra => serde_json::from_value(value)
|
ForkName::Deneb => serde_json::from_value(value)
|
||||||
.map(|light_client_header| Self::Deneb(light_client_header))
|
.map(|light_client_header| Self::Deneb(light_client_header))
|
||||||
.map_err(serde::de::Error::custom),
|
.map_err(serde::de::Error::custom),
|
||||||
|
ForkName::Electra => serde_json::from_value(value)
|
||||||
|
.map(|light_client_header| Self::Electra(light_client_header))
|
||||||
|
.map_err(serde::de::Error::custom),
|
||||||
ForkName::Base => Err(serde::de::Error::custom(format!(
|
ForkName::Base => Err(serde::de::Error::custom(format!(
|
||||||
"LightClientHeader deserialization for {fork_name} not implemented"
|
"LightClientHeader deserialization for {fork_name} not implemented"
|
||||||
))),
|
))),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use super::{EthSpec, ForkName, ForkVersionDeserialize, LightClientHeader, Slot,
|
|||||||
use crate::test_utils::TestRandom;
|
use crate::test_utils::TestRandom;
|
||||||
use crate::{
|
use crate::{
|
||||||
light_client_update::*, ChainSpec, LightClientHeaderAltair, LightClientHeaderCapella,
|
light_client_update::*, ChainSpec, LightClientHeaderAltair, LightClientHeaderCapella,
|
||||||
LightClientHeaderDeneb, SignedBeaconBlock,
|
LightClientHeaderDeneb, LightClientHeaderElectra, SignedBeaconBlock,
|
||||||
};
|
};
|
||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
@@ -18,7 +18,7 @@ use tree_hash_derive::TreeHash;
|
|||||||
/// A LightClientOptimisticUpdate is the update we send on each slot,
|
/// A LightClientOptimisticUpdate is the update we send on each slot,
|
||||||
/// it is based off the current unfinalized epoch is verified only against BLS signature.
|
/// it is based off the current unfinalized epoch is verified only against BLS signature.
|
||||||
#[superstruct(
|
#[superstruct(
|
||||||
variants(Altair, Capella, Deneb),
|
variants(Altair, Capella, Deneb, Electra),
|
||||||
variant_attributes(
|
variant_attributes(
|
||||||
derive(
|
derive(
|
||||||
Debug,
|
Debug,
|
||||||
@@ -53,6 +53,8 @@ pub struct LightClientOptimisticUpdate<E: EthSpec> {
|
|||||||
pub attested_header: LightClientHeaderCapella<E>,
|
pub attested_header: LightClientHeaderCapella<E>,
|
||||||
#[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))]
|
#[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))]
|
||||||
pub attested_header: LightClientHeaderDeneb<E>,
|
pub attested_header: LightClientHeaderDeneb<E>,
|
||||||
|
#[superstruct(only(Electra), partial_getter(rename = "attested_header_electra"))]
|
||||||
|
pub attested_header: LightClientHeaderElectra<E>,
|
||||||
/// current sync aggregate
|
/// current sync aggregate
|
||||||
pub sync_aggregate: SyncAggregate<E>,
|
pub sync_aggregate: SyncAggregate<E>,
|
||||||
/// Slot of the sync aggregated signature
|
/// Slot of the sync aggregated signature
|
||||||
@@ -86,13 +88,20 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
|
|||||||
sync_aggregate,
|
sync_aggregate,
|
||||||
signature_slot,
|
signature_slot,
|
||||||
}),
|
}),
|
||||||
ForkName::Deneb | ForkName::Electra => Self::Deneb(LightClientOptimisticUpdateDeneb {
|
ForkName::Deneb => Self::Deneb(LightClientOptimisticUpdateDeneb {
|
||||||
attested_header: LightClientHeaderDeneb::block_to_light_client_header(
|
attested_header: LightClientHeaderDeneb::block_to_light_client_header(
|
||||||
attested_block,
|
attested_block,
|
||||||
)?,
|
)?,
|
||||||
sync_aggregate,
|
sync_aggregate,
|
||||||
signature_slot,
|
signature_slot,
|
||||||
}),
|
}),
|
||||||
|
ForkName::Electra => Self::Electra(LightClientOptimisticUpdateElectra {
|
||||||
|
attested_header: LightClientHeaderElectra::block_to_light_client_header(
|
||||||
|
attested_block,
|
||||||
|
)?,
|
||||||
|
sync_aggregate,
|
||||||
|
signature_slot,
|
||||||
|
}),
|
||||||
ForkName::Base => return Err(Error::AltairForkNotActive),
|
ForkName::Base => return Err(Error::AltairForkNotActive),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -107,6 +116,7 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
|
|||||||
Self::Altair(_) => func(ForkName::Altair),
|
Self::Altair(_) => func(ForkName::Altair),
|
||||||
Self::Capella(_) => func(ForkName::Capella),
|
Self::Capella(_) => func(ForkName::Capella),
|
||||||
Self::Deneb(_) => func(ForkName::Deneb),
|
Self::Deneb(_) => func(ForkName::Deneb),
|
||||||
|
Self::Electra(_) => func(ForkName::Electra),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,9 +149,12 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
|
|||||||
ForkName::Capella => {
|
ForkName::Capella => {
|
||||||
Self::Capella(LightClientOptimisticUpdateCapella::from_ssz_bytes(bytes)?)
|
Self::Capella(LightClientOptimisticUpdateCapella::from_ssz_bytes(bytes)?)
|
||||||
}
|
}
|
||||||
ForkName::Deneb | ForkName::Electra => {
|
ForkName::Deneb => {
|
||||||
Self::Deneb(LightClientOptimisticUpdateDeneb::from_ssz_bytes(bytes)?)
|
Self::Deneb(LightClientOptimisticUpdateDeneb::from_ssz_bytes(bytes)?)
|
||||||
}
|
}
|
||||||
|
ForkName::Electra => {
|
||||||
|
Self::Electra(LightClientOptimisticUpdateElectra::from_ssz_bytes(bytes)?)
|
||||||
|
}
|
||||||
ForkName::Base => {
|
ForkName::Base => {
|
||||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||||
"LightClientOptimisticUpdate decoding for {fork_name} not implemented"
|
"LightClientOptimisticUpdate decoding for {fork_name} not implemented"
|
||||||
@@ -154,18 +167,16 @@ impl<E: EthSpec> LightClientOptimisticUpdate<E> {
|
|||||||
|
|
||||||
#[allow(clippy::arithmetic_side_effects)]
|
#[allow(clippy::arithmetic_side_effects)]
|
||||||
pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize {
|
pub fn ssz_max_len_for_fork(fork_name: ForkName) -> usize {
|
||||||
// TODO(electra): review electra changes
|
let fixed_len = match fork_name {
|
||||||
match fork_name {
|
|
||||||
ForkName::Base => 0,
|
ForkName::Base => 0,
|
||||||
ForkName::Altair
|
ForkName::Altair | ForkName::Bellatrix => {
|
||||||
| ForkName::Bellatrix
|
|
||||||
| ForkName::Capella
|
|
||||||
| ForkName::Deneb
|
|
||||||
| ForkName::Electra => {
|
|
||||||
<LightClientOptimisticUpdateAltair<E> as Encode>::ssz_fixed_len()
|
<LightClientOptimisticUpdateAltair<E> as Encode>::ssz_fixed_len()
|
||||||
+ LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
|
|
||||||
}
|
}
|
||||||
}
|
ForkName::Capella => <LightClientOptimisticUpdateCapella<E> as Encode>::ssz_fixed_len(),
|
||||||
|
ForkName::Deneb => <LightClientOptimisticUpdateDeneb<E> as Encode>::ssz_fixed_len(),
|
||||||
|
ForkName::Electra => <LightClientOptimisticUpdateElectra<E> as Encode>::ssz_fixed_len(),
|
||||||
|
};
|
||||||
|
fixed_len + LightClientHeader::<E>::ssz_max_var_len_for_fork(fork_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use super::{EthSpec, FixedVector, Hash256, Slot, SyncAggregate, SyncCommittee};
|
use super::{EthSpec, FixedVector, Hash256, Slot, SyncAggregate, SyncCommittee};
|
||||||
|
use crate::light_client_header::LightClientHeaderElectra;
|
||||||
use crate::{
|
use crate::{
|
||||||
beacon_state, test_utils::TestRandom, BeaconBlock, BeaconBlockHeader, BeaconState, ChainSpec,
|
beacon_state, test_utils::TestRandom, BeaconBlock, BeaconBlockHeader, BeaconState, ChainSpec,
|
||||||
ForkName, ForkVersionDeserialize, LightClientHeaderAltair, LightClientHeaderCapella,
|
ForkName, ForkVersionDeserialize, LightClientHeaderAltair, LightClientHeaderCapella,
|
||||||
@@ -76,7 +77,7 @@ impl From<milhouse::Error> for Error {
|
|||||||
/// or to sync up to the last committee period, we need to have one ready for each ALTAIR period
|
/// or to sync up to the last committee period, we need to have one ready for each ALTAIR period
|
||||||
/// we go over, note: there is no need to keep all of the updates from [ALTAIR_PERIOD, CURRENT_PERIOD].
|
/// we go over, note: there is no need to keep all of the updates from [ALTAIR_PERIOD, CURRENT_PERIOD].
|
||||||
#[superstruct(
|
#[superstruct(
|
||||||
variants(Altair, Capella, Deneb),
|
variants(Altair, Capella, Deneb, Electra),
|
||||||
variant_attributes(
|
variant_attributes(
|
||||||
derive(
|
derive(
|
||||||
Debug,
|
Debug,
|
||||||
@@ -111,6 +112,8 @@ pub struct LightClientUpdate<E: EthSpec> {
|
|||||||
pub attested_header: LightClientHeaderCapella<E>,
|
pub attested_header: LightClientHeaderCapella<E>,
|
||||||
#[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))]
|
#[superstruct(only(Deneb), partial_getter(rename = "attested_header_deneb"))]
|
||||||
pub attested_header: LightClientHeaderDeneb<E>,
|
pub attested_header: LightClientHeaderDeneb<E>,
|
||||||
|
#[superstruct(only(Electra), partial_getter(rename = "attested_header_electra"))]
|
||||||
|
pub attested_header: LightClientHeaderElectra<E>,
|
||||||
/// The `SyncCommittee` used in the next period.
|
/// The `SyncCommittee` used in the next period.
|
||||||
pub next_sync_committee: Arc<SyncCommittee<E>>,
|
pub next_sync_committee: Arc<SyncCommittee<E>>,
|
||||||
/// Merkle proof for next sync committee
|
/// Merkle proof for next sync committee
|
||||||
@@ -122,6 +125,8 @@ pub struct LightClientUpdate<E: EthSpec> {
|
|||||||
pub finalized_header: LightClientHeaderCapella<E>,
|
pub finalized_header: LightClientHeaderCapella<E>,
|
||||||
#[superstruct(only(Deneb), partial_getter(rename = "finalized_header_deneb"))]
|
#[superstruct(only(Deneb), partial_getter(rename = "finalized_header_deneb"))]
|
||||||
pub finalized_header: LightClientHeaderDeneb<E>,
|
pub finalized_header: LightClientHeaderDeneb<E>,
|
||||||
|
#[superstruct(only(Electra), partial_getter(rename = "finalized_header_electra"))]
|
||||||
|
pub finalized_header: LightClientHeaderElectra<E>,
|
||||||
/// Merkle proof attesting finalized header.
|
/// Merkle proof attesting finalized header.
|
||||||
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
|
pub finality_branch: FixedVector<Hash256, FinalizedRootProofLen>,
|
||||||
/// current sync aggreggate
|
/// current sync aggreggate
|
||||||
@@ -221,7 +226,7 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
|||||||
signature_slot: block.slot(),
|
signature_slot: block.slot(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ForkName::Deneb | ForkName::Electra => {
|
ForkName::Deneb => {
|
||||||
let attested_header =
|
let attested_header =
|
||||||
LightClientHeaderDeneb::block_to_light_client_header(attested_block)?;
|
LightClientHeaderDeneb::block_to_light_client_header(attested_block)?;
|
||||||
let finalized_header =
|
let finalized_header =
|
||||||
@@ -236,6 +241,23 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
|||||||
signature_slot: block.slot(),
|
signature_slot: block.slot(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ForkName::Electra => {
|
||||||
|
let attested_header =
|
||||||
|
LightClientHeaderElectra::block_to_light_client_header(attested_block)?;
|
||||||
|
let finalized_header =
|
||||||
|
LightClientHeaderElectra::block_to_light_client_header(finalized_block)?;
|
||||||
|
Self::Electra(LightClientUpdateElectra {
|
||||||
|
attested_header,
|
||||||
|
next_sync_committee: attested_state.next_sync_committee()?.clone(),
|
||||||
|
next_sync_committee_branch: FixedVector::new(next_sync_committee_branch)?,
|
||||||
|
finalized_header,
|
||||||
|
finality_branch: FixedVector::new(finality_branch)?,
|
||||||
|
sync_aggregate: sync_aggregate.clone(),
|
||||||
|
signature_slot: block.slot(),
|
||||||
|
})
|
||||||
|
} // To add a new fork, just append the new fork variant on the latest fork. Forks that
|
||||||
|
// have a distinct execution header will need a new LightClientUdpate variant only
|
||||||
|
// if you need to test or support lightclient usages
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(light_client_update)
|
Ok(light_client_update)
|
||||||
@@ -247,9 +269,8 @@ impl<E: EthSpec> LightClientUpdate<E> {
|
|||||||
Self::Altair(LightClientUpdateAltair::from_ssz_bytes(bytes)?)
|
Self::Altair(LightClientUpdateAltair::from_ssz_bytes(bytes)?)
|
||||||
}
|
}
|
||||||
ForkName::Capella => Self::Capella(LightClientUpdateCapella::from_ssz_bytes(bytes)?),
|
ForkName::Capella => Self::Capella(LightClientUpdateCapella::from_ssz_bytes(bytes)?),
|
||||||
ForkName::Deneb | ForkName::Electra => {
|
ForkName::Deneb => Self::Deneb(LightClientUpdateDeneb::from_ssz_bytes(bytes)?),
|
||||||
Self::Deneb(LightClientUpdateDeneb::from_ssz_bytes(bytes)?)
|
ForkName::Electra => Self::Electra(LightClientUpdateElectra::from_ssz_bytes(bytes)?),
|
||||||
}
|
|
||||||
ForkName::Base => {
|
ForkName::Base => {
|
||||||
return Err(ssz::DecodeError::BytesInvalid(format!(
|
return Err(ssz::DecodeError::BytesInvalid(format!(
|
||||||
"LightClientUpdate decoding for {fork_name} not implemented"
|
"LightClientUpdate decoding for {fork_name} not implemented"
|
||||||
|
|||||||
@@ -34,7 +34,9 @@ use tree_hash_derive::TreeHash;
|
|||||||
),
|
),
|
||||||
serde(bound = "E: EthSpec"),
|
serde(bound = "E: EthSpec"),
|
||||||
arbitrary(bound = "E: EthSpec"),
|
arbitrary(bound = "E: EthSpec"),
|
||||||
)
|
),
|
||||||
|
map_into(Attestation),
|
||||||
|
map_ref_into(AggregateAndProofRef)
|
||||||
)]
|
)]
|
||||||
#[derive(
|
#[derive(
|
||||||
arbitrary::Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash,
|
arbitrary::Arbitrary, Debug, Clone, PartialEq, Serialize, Deserialize, Encode, TreeHash,
|
||||||
@@ -102,19 +104,17 @@ impl<E: EthSpec> SignedAggregateAndProof<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn message(&self) -> AggregateAndProofRef<E> {
|
pub fn message<'a>(&'a self) -> AggregateAndProofRef<'a, E> {
|
||||||
match self {
|
map_signed_aggregate_and_proof_ref_into_aggregate_and_proof_ref!(
|
||||||
SignedAggregateAndProof::Base(message) => AggregateAndProofRef::Base(&message.message),
|
&'a _,
|
||||||
SignedAggregateAndProof::Electra(message) => {
|
self.to_ref(),
|
||||||
AggregateAndProofRef::Electra(&message.message)
|
|inner, cons| { cons(&inner.message) }
|
||||||
}
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_attestation(self) -> Attestation<E> {
|
pub fn into_attestation(self) -> Attestation<E> {
|
||||||
match self {
|
map_signed_aggregate_and_proof_into_attestation!(self, |inner, cons| {
|
||||||
Self::Base(att) => Attestation::Base(att.message.aggregate),
|
cons(inner.message.aggregate)
|
||||||
Self::Electra(att) => Attestation::Electra(att.message.aggregate),
|
})
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,13 +63,6 @@ impl<E: EthSpec> SyncCommitteeContribution<E> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Are the aggregation bitfields of these sync contribution disjoint?
|
|
||||||
pub fn signers_disjoint_from(&self, other: &Self) -> bool {
|
|
||||||
self.aggregation_bits
|
|
||||||
.intersection(&other.aggregation_bits)
|
|
||||||
.is_zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Aggregate another `SyncCommitteeContribution` into this one.
|
/// Aggregate another `SyncCommitteeContribution` into this one.
|
||||||
///
|
///
|
||||||
/// The aggregation bitfields must be disjoint, and the data must be the same.
|
/// The aggregation bitfields must be disjoint, and the data must be the same.
|
||||||
@@ -77,7 +70,6 @@ impl<E: EthSpec> SyncCommitteeContribution<E> {
|
|||||||
debug_assert_eq!(self.slot, other.slot);
|
debug_assert_eq!(self.slot, other.slot);
|
||||||
debug_assert_eq!(self.beacon_block_root, other.beacon_block_root);
|
debug_assert_eq!(self.beacon_block_root, other.beacon_block_root);
|
||||||
debug_assert_eq!(self.subcommittee_index, other.subcommittee_index);
|
debug_assert_eq!(self.subcommittee_index, other.subcommittee_index);
|
||||||
debug_assert!(self.signers_disjoint_from(other));
|
|
||||||
|
|
||||||
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
self.aggregation_bits = self.aggregation_bits.union(&other.aggregation_bits);
|
||||||
self.signature.add_assign_aggregate(&other.signature);
|
self.signature.add_assign_aggregate(&other.signature);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ tree_hash = { workspace = true }
|
|||||||
tree_hash_derive = { workspace = true }
|
tree_hash_derive = { workspace = true }
|
||||||
types = { workspace = true }
|
types = { workspace = true }
|
||||||
strum = { workspace = true }
|
strum = { workspace = true }
|
||||||
|
ssz_types = { workspace = true }
|
||||||
|
|
||||||
# MDBX is pinned at the last version with Windows and macOS support.
|
# MDBX is pinned at the last version with Windows and macOS support.
|
||||||
mdbx = { package = "libmdbx", git = "https://github.com/sigp/libmdbx-rs", tag = "v0.1.4", optional = true }
|
mdbx = { package = "libmdbx", git = "https://github.com/sigp/libmdbx-rs", tag = "v0.1.4", optional = true }
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ pub const DEFAULT_VALIDATOR_CHUNK_SIZE: usize = 256;
|
|||||||
pub const DEFAULT_HISTORY_LENGTH: usize = 4096;
|
pub const DEFAULT_HISTORY_LENGTH: usize = 4096;
|
||||||
pub const DEFAULT_UPDATE_PERIOD: u64 = 12;
|
pub const DEFAULT_UPDATE_PERIOD: u64 = 12;
|
||||||
pub const DEFAULT_SLOT_OFFSET: f64 = 10.5;
|
pub const DEFAULT_SLOT_OFFSET: f64 = 10.5;
|
||||||
pub const DEFAULT_MAX_DB_SIZE: usize = 256 * 1024; // 256 GiB
|
pub const DEFAULT_MAX_DB_SIZE: usize = 512 * 1024; // 512 GiB
|
||||||
pub const DEFAULT_ATTESTATION_ROOT_CACHE_SIZE: NonZeroUsize = new_non_zero_usize(100_000);
|
pub const DEFAULT_ATTESTATION_ROOT_CACHE_SIZE: NonZeroUsize = new_non_zero_usize(100_000);
|
||||||
pub const DEFAULT_BROADCAST: bool = false;
|
pub const DEFAULT_BROADCAST: bool = false;
|
||||||
|
|
||||||
|
|||||||
@@ -13,17 +13,19 @@ use parking_lot::Mutex;
|
|||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use slog::{info, Logger};
|
use slog::{info, Logger};
|
||||||
use ssz::{Decode, Encode};
|
use ssz::{Decode, Encode};
|
||||||
|
use ssz_derive::{Decode, Encode};
|
||||||
use std::borrow::{Borrow, Cow};
|
use std::borrow::{Borrow, Cow};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tree_hash::TreeHash;
|
use tree_hash::TreeHash;
|
||||||
use types::{
|
use types::{
|
||||||
Epoch, EthSpec, Hash256, IndexedAttestation, IndexedAttestationOnDisk,
|
AggregateSignature, AttestationData, ChainSpec, Epoch, EthSpec, Hash256, IndexedAttestation,
|
||||||
IndexedAttestationRefOnDisk, ProposerSlashing, SignedBeaconBlockHeader, Slot,
|
IndexedAttestationBase, IndexedAttestationElectra, ProposerSlashing, SignedBeaconBlockHeader,
|
||||||
|
Slot, VariableList,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Current database schema version, to check compatibility of on-disk DB with software.
|
/// Current database schema version, to check compatibility of on-disk DB with software.
|
||||||
pub const CURRENT_SCHEMA_VERSION: u64 = 4;
|
pub const CURRENT_SCHEMA_VERSION: u64 = 3;
|
||||||
|
|
||||||
/// Metadata about the slashing database itself.
|
/// Metadata about the slashing database itself.
|
||||||
const METADATA_DB: &str = "metadata";
|
const METADATA_DB: &str = "metadata";
|
||||||
@@ -70,6 +72,7 @@ pub struct SlasherDB<E: EthSpec> {
|
|||||||
/// LRU cache mapping indexed attestation IDs to their attestation data roots.
|
/// LRU cache mapping indexed attestation IDs to their attestation data roots.
|
||||||
attestation_root_cache: Mutex<LruCache<IndexedAttestationId, Hash256>>,
|
attestation_root_cache: Mutex<LruCache<IndexedAttestationId, Hash256>>,
|
||||||
pub(crate) config: Arc<Config>,
|
pub(crate) config: Arc<Config>,
|
||||||
|
pub(crate) spec: Arc<ChainSpec>,
|
||||||
_phantom: PhantomData<E>,
|
_phantom: PhantomData<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,6 +239,43 @@ impl AsRef<[u8]> for IndexedAttestationId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Indexed attestation that abstracts over Phase0 and Electra variants by using a plain `Vec` for
|
||||||
|
/// the attesting indices.
|
||||||
|
///
|
||||||
|
/// This allows us to avoid rewriting the entire indexed attestation database at Electra, which
|
||||||
|
/// saves a lot of execution time. The bytes that it encodes to are the same as the bytes that a
|
||||||
|
/// regular IndexedAttestation encodes to, because SSZ doesn't care about the length-bound.
|
||||||
|
#[derive(Debug, PartialEq, Decode, Encode)]
|
||||||
|
pub struct IndexedAttestationOnDisk {
|
||||||
|
attesting_indices: Vec<u64>,
|
||||||
|
data: AttestationData,
|
||||||
|
signature: AggregateSignature,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IndexedAttestationOnDisk {
|
||||||
|
fn into_indexed_attestation<E: EthSpec>(
|
||||||
|
self,
|
||||||
|
spec: &ChainSpec,
|
||||||
|
) -> Result<IndexedAttestation<E>, Error> {
|
||||||
|
let fork_at_target_epoch = spec.fork_name_at_epoch(self.data.target.epoch);
|
||||||
|
if fork_at_target_epoch.electra_enabled() {
|
||||||
|
let attesting_indices = VariableList::new(self.attesting_indices)?;
|
||||||
|
Ok(IndexedAttestation::Electra(IndexedAttestationElectra {
|
||||||
|
attesting_indices,
|
||||||
|
data: self.data,
|
||||||
|
signature: self.signature,
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
let attesting_indices = VariableList::new(self.attesting_indices)?;
|
||||||
|
Ok(IndexedAttestation::Base(IndexedAttestationBase {
|
||||||
|
attesting_indices,
|
||||||
|
data: self.data,
|
||||||
|
signature: self.signature,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Bincode deserialization specialised to `Cow<[u8]>`.
|
/// Bincode deserialization specialised to `Cow<[u8]>`.
|
||||||
fn bincode_deserialize<T: DeserializeOwned>(bytes: Cow<[u8]>) -> Result<T, Error> {
|
fn bincode_deserialize<T: DeserializeOwned>(bytes: Cow<[u8]>) -> Result<T, Error> {
|
||||||
Ok(bincode::deserialize(bytes.borrow())?)
|
Ok(bincode::deserialize(bytes.borrow())?)
|
||||||
@@ -246,7 +286,7 @@ fn ssz_decode<T: Decode>(bytes: Cow<[u8]>) -> Result<T, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> SlasherDB<E> {
|
impl<E: EthSpec> SlasherDB<E> {
|
||||||
pub fn open(config: Arc<Config>, log: Logger) -> Result<Self, Error> {
|
pub fn open(config: Arc<Config>, spec: Arc<ChainSpec>, log: Logger) -> Result<Self, Error> {
|
||||||
info!(log, "Opening slasher database"; "backend" => %config.backend);
|
info!(log, "Opening slasher database"; "backend" => %config.backend);
|
||||||
|
|
||||||
std::fs::create_dir_all(&config.database_path)?;
|
std::fs::create_dir_all(&config.database_path)?;
|
||||||
@@ -269,6 +309,7 @@ impl<E: EthSpec> SlasherDB<E> {
|
|||||||
databases,
|
databases,
|
||||||
attestation_root_cache,
|
attestation_root_cache,
|
||||||
config,
|
config,
|
||||||
|
spec,
|
||||||
_phantom: PhantomData,
|
_phantom: PhantomData,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -458,9 +499,8 @@ impl<E: EthSpec> SlasherDB<E> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let attestation_key = IndexedAttestationId::new(indexed_att_id);
|
let attestation_key = IndexedAttestationId::new(indexed_att_id);
|
||||||
let indexed_attestation_on_disk: IndexedAttestationRefOnDisk<E> =
|
// IndexedAttestationOnDisk and IndexedAttestation have compatible encodings.
|
||||||
indexed_attestation.into();
|
let data = indexed_attestation.as_ssz_bytes();
|
||||||
let data = indexed_attestation_on_disk.as_ssz_bytes();
|
|
||||||
|
|
||||||
cursor.put(attestation_key.as_ref(), &data)?;
|
cursor.put(attestation_key.as_ref(), &data)?;
|
||||||
drop(cursor);
|
drop(cursor);
|
||||||
@@ -484,8 +524,8 @@ impl<E: EthSpec> SlasherDB<E> {
|
|||||||
.ok_or(Error::MissingIndexedAttestation {
|
.ok_or(Error::MissingIndexedAttestation {
|
||||||
id: indexed_attestation_id.as_u64(),
|
id: indexed_attestation_id.as_u64(),
|
||||||
})?;
|
})?;
|
||||||
let indexed_attestation: IndexedAttestationOnDisk<E> = ssz_decode(bytes)?;
|
let indexed_attestation_on_disk: IndexedAttestationOnDisk = ssz_decode(bytes)?;
|
||||||
Ok(indexed_attestation.into())
|
indexed_attestation_on_disk.into_indexed_attestation(&self.spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_attestation_data_root(
|
fn get_attestation_data_root(
|
||||||
@@ -775,3 +815,93 @@ impl<E: EthSpec> SlasherDB<E> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use types::{Checkpoint, ForkName, MainnetEthSpec, Unsigned};
|
||||||
|
|
||||||
|
type E = MainnetEthSpec;
|
||||||
|
|
||||||
|
fn indexed_attestation_on_disk_roundtrip_test(
|
||||||
|
spec: &ChainSpec,
|
||||||
|
make_attestation: fn(
|
||||||
|
Vec<u64>,
|
||||||
|
AttestationData,
|
||||||
|
AggregateSignature,
|
||||||
|
) -> IndexedAttestation<E>,
|
||||||
|
committee_len: u64,
|
||||||
|
) {
|
||||||
|
let attestation_data = AttestationData {
|
||||||
|
slot: Slot::new(1000),
|
||||||
|
index: 0,
|
||||||
|
beacon_block_root: Hash256::repeat_byte(0xaa),
|
||||||
|
source: Checkpoint {
|
||||||
|
epoch: Epoch::new(0),
|
||||||
|
root: Hash256::repeat_byte(0xbb),
|
||||||
|
},
|
||||||
|
target: Checkpoint {
|
||||||
|
epoch: Epoch::new(31),
|
||||||
|
root: Hash256::repeat_byte(0xcc),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let attesting_indices = (0..committee_len).collect::<Vec<_>>();
|
||||||
|
let signature = AggregateSignature::infinity();
|
||||||
|
|
||||||
|
let fork_attestation = make_attestation(
|
||||||
|
attesting_indices.clone(),
|
||||||
|
attestation_data.clone(),
|
||||||
|
signature.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let on_disk = IndexedAttestationOnDisk {
|
||||||
|
attesting_indices,
|
||||||
|
data: attestation_data,
|
||||||
|
signature,
|
||||||
|
};
|
||||||
|
let encoded = on_disk.as_ssz_bytes();
|
||||||
|
assert_eq!(encoded, fork_attestation.as_ssz_bytes());
|
||||||
|
|
||||||
|
let decoded_on_disk = IndexedAttestationOnDisk::from_ssz_bytes(&encoded).unwrap();
|
||||||
|
assert_eq!(decoded_on_disk, on_disk);
|
||||||
|
|
||||||
|
let decoded = on_disk.into_indexed_attestation(spec).unwrap();
|
||||||
|
assert_eq!(decoded, fork_attestation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that `IndexedAttestationOnDisk` and `IndexedAttestation` have compatible encodings.
|
||||||
|
#[test]
|
||||||
|
fn indexed_attestation_on_disk_roundtrip_base() {
|
||||||
|
let spec = ForkName::Base.make_genesis_spec(E::default_spec());
|
||||||
|
let make_attestation = |attesting_indices, data, signature| {
|
||||||
|
IndexedAttestation::<E>::Base(IndexedAttestationBase {
|
||||||
|
attesting_indices: VariableList::new(attesting_indices).unwrap(),
|
||||||
|
data,
|
||||||
|
signature,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
indexed_attestation_on_disk_roundtrip_test(
|
||||||
|
&spec,
|
||||||
|
make_attestation,
|
||||||
|
<E as EthSpec>::MaxValidatorsPerCommittee::to_u64(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn indexed_attestation_on_disk_roundtrip_electra() {
|
||||||
|
let spec = ForkName::Electra.make_genesis_spec(E::default_spec());
|
||||||
|
let make_attestation = |attesting_indices, data, signature| {
|
||||||
|
IndexedAttestation::<E>::Electra(IndexedAttestationElectra {
|
||||||
|
attesting_indices: VariableList::new(attesting_indices).unwrap(),
|
||||||
|
data,
|
||||||
|
signature,
|
||||||
|
})
|
||||||
|
};
|
||||||
|
indexed_attestation_on_disk_roundtrip_test(
|
||||||
|
&spec,
|
||||||
|
make_attestation,
|
||||||
|
<E as EthSpec>::MaxValidatorsPerSlot::to_u64(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ pub enum Error {
|
|||||||
DatabaseIOError(io::Error),
|
DatabaseIOError(io::Error),
|
||||||
DatabasePermissionsError(filesystem::Error),
|
DatabasePermissionsError(filesystem::Error),
|
||||||
SszDecodeError(ssz::DecodeError),
|
SszDecodeError(ssz::DecodeError),
|
||||||
|
SszTypesError(ssz_types::Error),
|
||||||
BincodeError(bincode::Error),
|
BincodeError(bincode::Error),
|
||||||
ArithError(safe_arith::ArithError),
|
ArithError(safe_arith::ArithError),
|
||||||
ChunkIndexOutOfBounds(usize),
|
ChunkIndexOutOfBounds(usize),
|
||||||
@@ -100,6 +101,12 @@ impl From<ssz::DecodeError> for Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<ssz_types::Error> for Error {
|
||||||
|
fn from(e: ssz_types::Error) -> Self {
|
||||||
|
Error::SszTypesError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<bincode::Error> for Error {
|
impl From<bincode::Error> for Error {
|
||||||
fn from(e: bincode::Error) -> Self {
|
fn from(e: bincode::Error) -> Self {
|
||||||
Error::BincodeError(e)
|
Error::BincodeError(e)
|
||||||
|
|||||||
@@ -17,10 +17,6 @@ impl<E: EthSpec> SlasherDB<E> {
|
|||||||
software_schema_version: CURRENT_SCHEMA_VERSION,
|
software_schema_version: CURRENT_SCHEMA_VERSION,
|
||||||
}),
|
}),
|
||||||
(x, y) if x == y => Ok(self),
|
(x, y) if x == y => Ok(self),
|
||||||
(3, 4) => {
|
|
||||||
// TODO(electra): db migration due to `IndexedAttestationOnDisk`
|
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
(_, _) => Err(Error::IncompatibleSchemaVersion {
|
(_, _) => Err(Error::IncompatibleSchemaVersion {
|
||||||
database_schema_version: schema_version,
|
database_schema_version: schema_version,
|
||||||
software_schema_version: CURRENT_SCHEMA_VERSION,
|
software_schema_version: CURRENT_SCHEMA_VERSION,
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ use slog::{debug, error, info, Logger};
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::{
|
use types::{
|
||||||
AttesterSlashing, Epoch, EthSpec, IndexedAttestation, ProposerSlashing, SignedBeaconBlockHeader,
|
AttesterSlashing, ChainSpec, Epoch, EthSpec, IndexedAttestation, ProposerSlashing,
|
||||||
|
SignedBeaconBlockHeader,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -28,10 +29,10 @@ pub struct Slasher<E: EthSpec> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> Slasher<E> {
|
impl<E: EthSpec> Slasher<E> {
|
||||||
pub fn open(config: Config, log: Logger) -> Result<Self, Error> {
|
pub fn open(config: Config, spec: Arc<ChainSpec>, log: Logger) -> Result<Self, Error> {
|
||||||
config.validate()?;
|
config.validate()?;
|
||||||
let config = Arc::new(config);
|
let config = Arc::new(config);
|
||||||
let db = SlasherDB::open(config.clone(), log.clone())?;
|
let db = SlasherDB::open(config.clone(), spec, log.clone())?;
|
||||||
let attester_slashings = Mutex::new(HashSet::new());
|
let attester_slashings = Mutex::new(HashSet::new());
|
||||||
let proposer_slashings = Mutex::new(HashSet::new());
|
let proposer_slashings = Mutex::new(HashSet::new());
|
||||||
let attestation_queue = AttestationQueue::default();
|
let attestation_queue = AttestationQueue::default();
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::sync::Arc;
|
||||||
use types::{
|
use types::{
|
||||||
indexed_attestation::{IndexedAttestationBase, IndexedAttestationElectra},
|
indexed_attestation::{IndexedAttestationBase, IndexedAttestationElectra},
|
||||||
AggregateSignature, AttestationData, AttesterSlashing, AttesterSlashingBase,
|
AggregateSignature, AttestationData, AttesterSlashing, AttesterSlashingBase,
|
||||||
AttesterSlashingElectra, BeaconBlockHeader, Checkpoint, Epoch, Hash256, IndexedAttestation,
|
AttesterSlashingElectra, BeaconBlockHeader, ChainSpec, Checkpoint, Epoch, EthSpec, Hash256,
|
||||||
MainnetEthSpec, Signature, SignedBeaconBlockHeader, Slot,
|
IndexedAttestation, MainnetEthSpec, Signature, SignedBeaconBlockHeader, Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type E = MainnetEthSpec;
|
pub type E = MainnetEthSpec;
|
||||||
@@ -145,3 +146,7 @@ pub fn block(slot: u64, proposer_index: u64, block_root: u64) -> SignedBeaconBlo
|
|||||||
signature: Signature::empty(),
|
signature: Signature::empty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn chain_spec() -> Arc<ChainSpec> {
|
||||||
|
Arc::new(E::default_spec())
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ use rayon::prelude::*;
|
|||||||
use slasher::{
|
use slasher::{
|
||||||
config::DEFAULT_CHUNK_SIZE,
|
config::DEFAULT_CHUNK_SIZE,
|
||||||
test_utils::{
|
test_utils::{
|
||||||
att_slashing, indexed_att, indexed_att_electra, slashed_validators_from_slashings, E,
|
att_slashing, chain_spec, indexed_att, indexed_att_electra,
|
||||||
|
slashed_validators_from_slashings, E,
|
||||||
},
|
},
|
||||||
Config, Slasher,
|
Config, Slasher,
|
||||||
};
|
};
|
||||||
@@ -270,7 +271,8 @@ fn slasher_test(
|
|||||||
) {
|
) {
|
||||||
let tempdir = tempdir().unwrap();
|
let tempdir = tempdir().unwrap();
|
||||||
let config = Config::new(tempdir.path().into());
|
let config = Config::new(tempdir.path().into());
|
||||||
let slasher = Slasher::open(config, test_logger()).unwrap();
|
let spec = chain_spec();
|
||||||
|
let slasher = Slasher::open(config, spec, test_logger()).unwrap();
|
||||||
let current_epoch = Epoch::new(current_epoch);
|
let current_epoch = Epoch::new(current_epoch);
|
||||||
|
|
||||||
for (i, attestation) in attestations.iter().enumerate() {
|
for (i, attestation) in attestations.iter().enumerate() {
|
||||||
@@ -299,7 +301,8 @@ fn parallel_slasher_test(
|
|||||||
) {
|
) {
|
||||||
let tempdir = tempdir().unwrap();
|
let tempdir = tempdir().unwrap();
|
||||||
let config = Config::new(tempdir.path().into());
|
let config = Config::new(tempdir.path().into());
|
||||||
let slasher = Slasher::open(config, test_logger()).unwrap();
|
let spec = chain_spec();
|
||||||
|
let slasher = Slasher::open(config, spec, test_logger()).unwrap();
|
||||||
let current_epoch = Epoch::new(current_epoch);
|
let current_epoch = Epoch::new(current_epoch);
|
||||||
|
|
||||||
attestations
|
attestations
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use logging::test_logger;
|
use logging::test_logger;
|
||||||
use slasher::{
|
use slasher::{
|
||||||
test_utils::{block as test_block, E},
|
test_utils::{block as test_block, chain_spec, E},
|
||||||
Config, Slasher,
|
Config, Slasher,
|
||||||
};
|
};
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
@@ -12,7 +12,8 @@ use types::{Epoch, EthSpec};
|
|||||||
fn empty_pruning() {
|
fn empty_pruning() {
|
||||||
let tempdir = tempdir().unwrap();
|
let tempdir = tempdir().unwrap();
|
||||||
let config = Config::new(tempdir.path().into());
|
let config = Config::new(tempdir.path().into());
|
||||||
let slasher = Slasher::<E>::open(config, test_logger()).unwrap();
|
let spec = chain_spec();
|
||||||
|
let slasher = Slasher::<E>::open(config, spec, test_logger()).unwrap();
|
||||||
slasher.prune_database(Epoch::new(0)).unwrap();
|
slasher.prune_database(Epoch::new(0)).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,8 +25,9 @@ fn block_pruning() {
|
|||||||
let mut config = Config::new(tempdir.path().into());
|
let mut config = Config::new(tempdir.path().into());
|
||||||
config.chunk_size = 2;
|
config.chunk_size = 2;
|
||||||
config.history_length = 2;
|
config.history_length = 2;
|
||||||
|
let spec = chain_spec();
|
||||||
|
|
||||||
let slasher = Slasher::<E>::open(config.clone(), test_logger()).unwrap();
|
let slasher = Slasher::<E>::open(config.clone(), spec, test_logger()).unwrap();
|
||||||
let current_epoch = Epoch::from(2 * config.history_length);
|
let current_epoch = Epoch::from(2 * config.history_length);
|
||||||
|
|
||||||
// Pruning the empty database should be safe.
|
// Pruning the empty database should be safe.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use logging::test_logger;
|
|||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use slasher::{
|
use slasher::{
|
||||||
test_utils::{
|
test_utils::{
|
||||||
block, indexed_att, slashed_validators_from_attestations,
|
block, chain_spec, indexed_att, slashed_validators_from_attestations,
|
||||||
slashed_validators_from_slashings, E,
|
slashed_validators_from_slashings, E,
|
||||||
},
|
},
|
||||||
Config, Slasher,
|
Config, Slasher,
|
||||||
@@ -49,7 +49,9 @@ fn random_test(seed: u64, test_config: TestConfig) {
|
|||||||
config.chunk_size = 1 << chunk_size_exponent;
|
config.chunk_size = 1 << chunk_size_exponent;
|
||||||
config.history_length = 1 << rng.gen_range(chunk_size_exponent..chunk_size_exponent + 3);
|
config.history_length = 1 << rng.gen_range(chunk_size_exponent..chunk_size_exponent + 3);
|
||||||
|
|
||||||
let slasher = Slasher::<E>::open(config.clone(), test_logger()).unwrap();
|
let spec = chain_spec();
|
||||||
|
|
||||||
|
let slasher = Slasher::<E>::open(config.clone(), spec, test_logger()).unwrap();
|
||||||
|
|
||||||
let validators = (0..num_validators as u64).collect::<Vec<u64>>();
|
let validators = (0..num_validators as u64).collect::<Vec<u64>>();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
#![cfg(any(feature = "mdbx", feature = "lmdb"))]
|
#![cfg(any(feature = "mdbx", feature = "lmdb"))]
|
||||||
|
|
||||||
use logging::test_logger;
|
use logging::test_logger;
|
||||||
use slasher::{test_utils::indexed_att, Config, Slasher};
|
use slasher::{
|
||||||
|
test_utils::{chain_spec, indexed_att},
|
||||||
|
Config, Slasher,
|
||||||
|
};
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
use types::Epoch;
|
use types::Epoch;
|
||||||
|
|
||||||
@@ -9,11 +12,12 @@ use types::Epoch;
|
|||||||
fn attestation_pruning_empty_wrap_around() {
|
fn attestation_pruning_empty_wrap_around() {
|
||||||
let tempdir = tempdir().unwrap();
|
let tempdir = tempdir().unwrap();
|
||||||
let mut config = Config::new(tempdir.path().into());
|
let mut config = Config::new(tempdir.path().into());
|
||||||
|
let spec = chain_spec();
|
||||||
config.validator_chunk_size = 1;
|
config.validator_chunk_size = 1;
|
||||||
config.chunk_size = 16;
|
config.chunk_size = 16;
|
||||||
config.history_length = 16;
|
config.history_length = 16;
|
||||||
|
|
||||||
let slasher = Slasher::open(config.clone(), test_logger()).unwrap();
|
let slasher = Slasher::open(config.clone(), spec, test_logger()).unwrap();
|
||||||
|
|
||||||
let v = vec![0];
|
let v = vec![0];
|
||||||
let history_length = config.history_length as u64;
|
let history_length = config.history_length as u64;
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ excluded_paths = [
|
|||||||
"bls12-381-tests/hash_to_G2",
|
"bls12-381-tests/hash_to_G2",
|
||||||
"tests/.*/eip6110",
|
"tests/.*/eip6110",
|
||||||
"tests/.*/whisk",
|
"tests/.*/whisk",
|
||||||
"tests/.*/eip7594",
|
"tests/.*/eip7594"
|
||||||
"tests/.*/electra/ssz_static/LightClient*"
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ type_name_generic!(AggregateAndProof);
|
|||||||
type_name_generic!(AggregateAndProofBase, "AggregateAndProof");
|
type_name_generic!(AggregateAndProofBase, "AggregateAndProof");
|
||||||
type_name_generic!(AggregateAndProofElectra, "AggregateAndProof");
|
type_name_generic!(AggregateAndProofElectra, "AggregateAndProof");
|
||||||
type_name_generic!(Attestation);
|
type_name_generic!(Attestation);
|
||||||
|
type_name_generic!(AttestationBase, "Attestation");
|
||||||
|
type_name_generic!(AttestationElectra, "Attestation");
|
||||||
type_name!(AttestationData);
|
type_name!(AttestationData);
|
||||||
type_name_generic!(AttesterSlashing);
|
type_name_generic!(AttesterSlashing);
|
||||||
type_name_generic!(AttesterSlashingBase, "AttesterSlashing");
|
type_name_generic!(AttesterSlashingBase, "AttesterSlashing");
|
||||||
|
|||||||
Reference in New Issue
Block a user