DB migration for fork choice cleanup (#4265)
## Issue Addressed #4233 ## Proposed Changes Remove the `best_justified_checkpoint` from the `PersistedForkChoiceStore` type as it is now unused. Additionally, remove the `Option`'s wrapping the `justified_checkpoint` and `finalized_checkpoint` fields on `ProtoNode` which were only present to facilitate a previous migration. Include the necessary code to facilitate the migration to a new DB schema.
This commit is contained in:
parent
40abaefffb
commit
3c029d48bf
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -6196,6 +6196,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
|
"superstruct 0.5.0",
|
||||||
"types",
|
"types",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -218,7 +218,6 @@ where
|
|||||||
finalized_checkpoint: self.finalized_checkpoint,
|
finalized_checkpoint: self.finalized_checkpoint,
|
||||||
justified_checkpoint: self.justified_checkpoint,
|
justified_checkpoint: self.justified_checkpoint,
|
||||||
justified_balances: self.justified_balances.effective_balances.clone(),
|
justified_balances: self.justified_balances.effective_balances.clone(),
|
||||||
best_justified_checkpoint: JUNK_BEST_JUSTIFIED_CHECKPOINT,
|
|
||||||
unrealized_justified_checkpoint: self.unrealized_justified_checkpoint,
|
unrealized_justified_checkpoint: self.unrealized_justified_checkpoint,
|
||||||
unrealized_finalized_checkpoint: self.unrealized_finalized_checkpoint,
|
unrealized_finalized_checkpoint: self.unrealized_finalized_checkpoint,
|
||||||
proposer_boost_root: self.proposer_boost_root,
|
proposer_boost_root: self.proposer_boost_root,
|
||||||
@ -355,24 +354,62 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type PersistedForkChoiceStore = PersistedForkChoiceStoreV17;
|
||||||
|
|
||||||
/// A container which allows persisting the `BeaconForkChoiceStore` to the on-disk database.
|
/// A container which allows persisting the `BeaconForkChoiceStore` to the on-disk database.
|
||||||
#[superstruct(variants(V11), variant_attributes(derive(Encode, Decode)), no_enum)]
|
#[superstruct(
|
||||||
|
variants(V11, V17),
|
||||||
|
variant_attributes(derive(Encode, Decode)),
|
||||||
|
no_enum
|
||||||
|
)]
|
||||||
pub struct PersistedForkChoiceStore {
|
pub struct PersistedForkChoiceStore {
|
||||||
#[superstruct(only(V11))]
|
#[superstruct(only(V11, V17))]
|
||||||
pub balances_cache: BalancesCacheV8,
|
pub balances_cache: BalancesCacheV8,
|
||||||
pub time: Slot,
|
pub time: Slot,
|
||||||
pub finalized_checkpoint: Checkpoint,
|
pub finalized_checkpoint: Checkpoint,
|
||||||
pub justified_checkpoint: Checkpoint,
|
pub justified_checkpoint: Checkpoint,
|
||||||
pub justified_balances: Vec<u64>,
|
pub justified_balances: Vec<u64>,
|
||||||
|
#[superstruct(only(V11))]
|
||||||
pub best_justified_checkpoint: Checkpoint,
|
pub best_justified_checkpoint: Checkpoint,
|
||||||
#[superstruct(only(V11))]
|
#[superstruct(only(V11, V17))]
|
||||||
pub unrealized_justified_checkpoint: Checkpoint,
|
pub unrealized_justified_checkpoint: Checkpoint,
|
||||||
#[superstruct(only(V11))]
|
#[superstruct(only(V11, V17))]
|
||||||
pub unrealized_finalized_checkpoint: Checkpoint,
|
pub unrealized_finalized_checkpoint: Checkpoint,
|
||||||
#[superstruct(only(V11))]
|
#[superstruct(only(V11, V17))]
|
||||||
pub proposer_boost_root: Hash256,
|
pub proposer_boost_root: Hash256,
|
||||||
#[superstruct(only(V11))]
|
#[superstruct(only(V11, V17))]
|
||||||
pub equivocating_indices: BTreeSet<u64>,
|
pub equivocating_indices: BTreeSet<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type PersistedForkChoiceStore = PersistedForkChoiceStoreV11;
|
impl Into<PersistedForkChoiceStore> for PersistedForkChoiceStoreV11 {
|
||||||
|
fn into(self) -> PersistedForkChoiceStore {
|
||||||
|
PersistedForkChoiceStore {
|
||||||
|
balances_cache: self.balances_cache,
|
||||||
|
time: self.time,
|
||||||
|
finalized_checkpoint: self.finalized_checkpoint,
|
||||||
|
justified_checkpoint: self.justified_checkpoint,
|
||||||
|
justified_balances: self.justified_balances,
|
||||||
|
unrealized_justified_checkpoint: self.unrealized_justified_checkpoint,
|
||||||
|
unrealized_finalized_checkpoint: self.unrealized_finalized_checkpoint,
|
||||||
|
proposer_boost_root: self.proposer_boost_root,
|
||||||
|
equivocating_indices: self.equivocating_indices,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<PersistedForkChoiceStoreV11> for PersistedForkChoiceStore {
|
||||||
|
fn into(self) -> PersistedForkChoiceStoreV11 {
|
||||||
|
PersistedForkChoiceStoreV11 {
|
||||||
|
balances_cache: self.balances_cache,
|
||||||
|
time: self.time,
|
||||||
|
finalized_checkpoint: self.finalized_checkpoint,
|
||||||
|
justified_checkpoint: self.justified_checkpoint,
|
||||||
|
justified_balances: self.justified_balances,
|
||||||
|
best_justified_checkpoint: JUNK_BEST_JUSTIFIED_CHECKPOINT,
|
||||||
|
unrealized_justified_checkpoint: self.unrealized_justified_checkpoint,
|
||||||
|
unrealized_finalized_checkpoint: self.unrealized_finalized_checkpoint,
|
||||||
|
proposer_boost_root: self.proposer_boost_root,
|
||||||
|
equivocating_indices: self.equivocating_indices,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,17 +1,41 @@
|
|||||||
use crate::beacon_fork_choice_store::PersistedForkChoiceStoreV11;
|
use crate::beacon_fork_choice_store::{PersistedForkChoiceStoreV11, PersistedForkChoiceStoreV17};
|
||||||
use ssz::{Decode, Encode};
|
use ssz::{Decode, Encode};
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use store::{DBColumn, Error, StoreItem};
|
use store::{DBColumn, Error, StoreItem};
|
||||||
use superstruct::superstruct;
|
use superstruct::superstruct;
|
||||||
|
|
||||||
// If adding a new version you should update this type alias and fix the breakages.
|
// If adding a new version you should update this type alias and fix the breakages.
|
||||||
pub type PersistedForkChoice = PersistedForkChoiceV11;
|
pub type PersistedForkChoice = PersistedForkChoiceV17;
|
||||||
|
|
||||||
#[superstruct(variants(V11), variant_attributes(derive(Encode, Decode)), no_enum)]
|
#[superstruct(
|
||||||
|
variants(V11, V17),
|
||||||
|
variant_attributes(derive(Encode, Decode)),
|
||||||
|
no_enum
|
||||||
|
)]
|
||||||
pub struct PersistedForkChoice {
|
pub struct PersistedForkChoice {
|
||||||
pub fork_choice: fork_choice::PersistedForkChoice,
|
pub fork_choice: fork_choice::PersistedForkChoice,
|
||||||
#[superstruct(only(V11))]
|
#[superstruct(only(V11))]
|
||||||
pub fork_choice_store: PersistedForkChoiceStoreV11,
|
pub fork_choice_store: PersistedForkChoiceStoreV11,
|
||||||
|
#[superstruct(only(V17))]
|
||||||
|
pub fork_choice_store: PersistedForkChoiceStoreV17,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<PersistedForkChoice> for PersistedForkChoiceV11 {
|
||||||
|
fn into(self) -> PersistedForkChoice {
|
||||||
|
PersistedForkChoice {
|
||||||
|
fork_choice: self.fork_choice,
|
||||||
|
fork_choice_store: self.fork_choice_store.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<PersistedForkChoiceV11> for PersistedForkChoice {
|
||||||
|
fn into(self) -> PersistedForkChoiceV11 {
|
||||||
|
PersistedForkChoiceV11 {
|
||||||
|
fork_choice: self.fork_choice,
|
||||||
|
fork_choice_store: self.fork_choice_store.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_store_item {
|
macro_rules! impl_store_item {
|
||||||
@ -33,3 +57,4 @@ macro_rules! impl_store_item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl_store_item!(PersistedForkChoiceV11);
|
impl_store_item!(PersistedForkChoiceV11);
|
||||||
|
impl_store_item!(PersistedForkChoiceV17);
|
||||||
|
@ -4,6 +4,7 @@ mod migration_schema_v13;
|
|||||||
mod migration_schema_v14;
|
mod migration_schema_v14;
|
||||||
mod migration_schema_v15;
|
mod migration_schema_v15;
|
||||||
mod migration_schema_v16;
|
mod migration_schema_v16;
|
||||||
|
mod migration_schema_v17;
|
||||||
|
|
||||||
use crate::beacon_chain::{BeaconChainTypes, ETH1_CACHE_DB_KEY};
|
use crate::beacon_chain::{BeaconChainTypes, ETH1_CACHE_DB_KEY};
|
||||||
use crate::eth1_chain::SszEth1;
|
use crate::eth1_chain::SszEth1;
|
||||||
@ -141,6 +142,14 @@ pub fn migrate_schema<T: BeaconChainTypes>(
|
|||||||
let ops = migration_schema_v16::downgrade_from_v16::<T>(db.clone(), log)?;
|
let ops = migration_schema_v16::downgrade_from_v16::<T>(db.clone(), log)?;
|
||||||
db.store_schema_version_atomically(to, ops)
|
db.store_schema_version_atomically(to, ops)
|
||||||
}
|
}
|
||||||
|
(SchemaVersion(16), SchemaVersion(17)) => {
|
||||||
|
let ops = migration_schema_v17::upgrade_to_v17::<T>(db.clone(), log)?;
|
||||||
|
db.store_schema_version_atomically(to, ops)
|
||||||
|
}
|
||||||
|
(SchemaVersion(17), SchemaVersion(16)) => {
|
||||||
|
let ops = migration_schema_v17::downgrade_from_v17::<T>(db.clone(), log)?;
|
||||||
|
db.store_schema_version_atomically(to, ops)
|
||||||
|
}
|
||||||
// Anything else is an error.
|
// Anything else is an error.
|
||||||
(_, _) => Err(HotColdDBError::UnsupportedSchemaVersion {
|
(_, _) => Err(HotColdDBError::UnsupportedSchemaVersion {
|
||||||
target_version: to,
|
target_version: to,
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
use crate::beacon_chain::{BeaconChainTypes, FORK_CHOICE_DB_KEY};
|
||||||
|
use crate::persisted_fork_choice::{PersistedForkChoiceV11, PersistedForkChoiceV17};
|
||||||
|
use proto_array::core::{SszContainerV16, SszContainerV17};
|
||||||
|
use slog::{debug, Logger};
|
||||||
|
use ssz::{Decode, Encode};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use store::{Error, HotColdDB, KeyValueStoreOp, StoreItem};
|
||||||
|
|
||||||
|
pub fn upgrade_fork_choice(
|
||||||
|
mut fork_choice: PersistedForkChoiceV11,
|
||||||
|
) -> Result<PersistedForkChoiceV17, Error> {
|
||||||
|
let ssz_container_v16 = SszContainerV16::from_ssz_bytes(
|
||||||
|
&fork_choice.fork_choice.proto_array_bytes,
|
||||||
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
Error::SchemaMigrationError(format!(
|
||||||
|
"Failed to decode ProtoArrayForkChoice during schema migration: {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let ssz_container_v17: SszContainerV17 = ssz_container_v16.try_into().map_err(|e| {
|
||||||
|
Error::SchemaMigrationError(format!(
|
||||||
|
"Missing checkpoint during schema migration: {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
fork_choice.fork_choice.proto_array_bytes = ssz_container_v17.as_ssz_bytes();
|
||||||
|
|
||||||
|
Ok(fork_choice.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downgrade_fork_choice(
|
||||||
|
mut fork_choice: PersistedForkChoiceV17,
|
||||||
|
) -> Result<PersistedForkChoiceV11, Error> {
|
||||||
|
let ssz_container_v17 = SszContainerV17::from_ssz_bytes(
|
||||||
|
&fork_choice.fork_choice.proto_array_bytes,
|
||||||
|
)
|
||||||
|
.map_err(|e| {
|
||||||
|
Error::SchemaMigrationError(format!(
|
||||||
|
"Failed to decode ProtoArrayForkChoice during schema migration: {:?}",
|
||||||
|
e
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let ssz_container_v16: SszContainerV16 = ssz_container_v17.into();
|
||||||
|
fork_choice.fork_choice.proto_array_bytes = ssz_container_v16.as_ssz_bytes();
|
||||||
|
|
||||||
|
Ok(fork_choice.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn upgrade_to_v17<T: BeaconChainTypes>(
|
||||||
|
db: Arc<HotColdDB<T::EthSpec, T::HotStore, T::ColdStore>>,
|
||||||
|
log: Logger,
|
||||||
|
) -> Result<Vec<KeyValueStoreOp>, Error> {
|
||||||
|
// Get persisted_fork_choice.
|
||||||
|
let v11 = db
|
||||||
|
.get_item::<PersistedForkChoiceV11>(&FORK_CHOICE_DB_KEY)?
|
||||||
|
.ok_or_else(|| Error::SchemaMigrationError("fork choice missing from database".into()))?;
|
||||||
|
|
||||||
|
let v17 = upgrade_fork_choice(v11)?;
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
log,
|
||||||
|
"Removing unused best_justified_checkpoint from fork choice store."
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(vec![v17.as_kv_store_op(FORK_CHOICE_DB_KEY)])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn downgrade_from_v17<T: BeaconChainTypes>(
|
||||||
|
db: Arc<HotColdDB<T::EthSpec, T::HotStore, T::ColdStore>>,
|
||||||
|
log: Logger,
|
||||||
|
) -> Result<Vec<KeyValueStoreOp>, Error> {
|
||||||
|
// Get persisted_fork_choice.
|
||||||
|
let v17 = db
|
||||||
|
.get_item::<PersistedForkChoiceV17>(&FORK_CHOICE_DB_KEY)?
|
||||||
|
.ok_or_else(|| Error::SchemaMigrationError("fork choice missing from database".into()))?;
|
||||||
|
|
||||||
|
let v11 = downgrade_fork_choice(v17)?;
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
log,
|
||||||
|
"Adding junk best_justified_checkpoint to fork choice store."
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(vec![v11.as_kv_store_op(FORK_CHOICE_DB_KEY)])
|
||||||
|
}
|
@ -2202,12 +2202,8 @@ pub fn serve<T: BeaconChainTypes>(
|
|||||||
.parent
|
.parent
|
||||||
.and_then(|index| proto_array.nodes.get(index))
|
.and_then(|index| proto_array.nodes.get(index))
|
||||||
.map(|parent| parent.root),
|
.map(|parent| parent.root),
|
||||||
justified_epoch: node
|
justified_epoch: node.justified_checkpoint.epoch,
|
||||||
.justified_checkpoint
|
finalized_epoch: node.finalized_checkpoint.epoch,
|
||||||
.map(|checkpoint| checkpoint.epoch),
|
|
||||||
finalized_epoch: node
|
|
||||||
.finalized_checkpoint
|
|
||||||
.map(|checkpoint| checkpoint.epoch),
|
|
||||||
weight: node.weight,
|
weight: node.weight,
|
||||||
validity: execution_status,
|
validity: execution_status,
|
||||||
execution_block_hash: node
|
execution_block_hash: node
|
||||||
|
@ -1956,8 +1956,8 @@ impl ApiTester {
|
|||||||
.parent
|
.parent
|
||||||
.and_then(|index| expected_proto_array.nodes.get(index))
|
.and_then(|index| expected_proto_array.nodes.get(index))
|
||||||
.map(|parent| parent.root),
|
.map(|parent| parent.root),
|
||||||
justified_epoch: node.justified_checkpoint.map(|checkpoint| checkpoint.epoch),
|
justified_epoch: node.justified_checkpoint.epoch,
|
||||||
finalized_epoch: node.finalized_checkpoint.map(|checkpoint| checkpoint.epoch),
|
finalized_epoch: node.finalized_checkpoint.epoch,
|
||||||
weight: node.weight,
|
weight: node.weight,
|
||||||
validity: execution_status,
|
validity: execution_status,
|
||||||
execution_block_hash: node
|
execution_block_hash: node
|
||||||
|
@ -4,7 +4,7 @@ use ssz::{Decode, Encode};
|
|||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use types::{Checkpoint, Hash256, Slot};
|
use types::{Checkpoint, Hash256, Slot};
|
||||||
|
|
||||||
pub const CURRENT_SCHEMA_VERSION: SchemaVersion = SchemaVersion(16);
|
pub const CURRENT_SCHEMA_VERSION: SchemaVersion = SchemaVersion(17);
|
||||||
|
|
||||||
// All the keys that get stored under the `BeaconMeta` column.
|
// All the keys that get stored under the `BeaconMeta` column.
|
||||||
//
|
//
|
||||||
|
@ -1229,8 +1229,8 @@ pub struct ForkChoiceNode {
|
|||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
pub block_root: Hash256,
|
pub block_root: Hash256,
|
||||||
pub parent_root: Option<Hash256>,
|
pub parent_root: Option<Hash256>,
|
||||||
pub justified_epoch: Option<Epoch>,
|
pub justified_epoch: Epoch,
|
||||||
pub finalized_epoch: Option<Epoch>,
|
pub finalized_epoch: Epoch,
|
||||||
#[serde(with = "serde_utils::quoted_u64")]
|
#[serde(with = "serde_utils::quoted_u64")]
|
||||||
pub weight: u64,
|
pub weight: u64,
|
||||||
pub validity: Option<String>,
|
pub validity: Option<String>,
|
||||||
|
@ -16,3 +16,4 @@ serde = "1.0.116"
|
|||||||
serde_derive = "1.0.116"
|
serde_derive = "1.0.116"
|
||||||
serde_yaml = "0.8.13"
|
serde_yaml = "0.8.13"
|
||||||
safe_arith = { path = "../safe_arith" }
|
safe_arith = { path = "../safe_arith" }
|
||||||
|
superstruct = "0.5.0"
|
@ -14,6 +14,8 @@ pub enum Error {
|
|||||||
InvalidBestDescendant(usize),
|
InvalidBestDescendant(usize),
|
||||||
InvalidParentDelta(usize),
|
InvalidParentDelta(usize),
|
||||||
InvalidNodeDelta(usize),
|
InvalidNodeDelta(usize),
|
||||||
|
MissingJustifiedCheckpoint,
|
||||||
|
MissingFinalizedCheckpoint,
|
||||||
DeltaOverflow(usize),
|
DeltaOverflow(usize),
|
||||||
ProposerBoostOverflow(usize),
|
ProposerBoostOverflow(usize),
|
||||||
ReOrgThresholdOverflow,
|
ReOrgThresholdOverflow,
|
||||||
@ -67,6 +69,6 @@ pub struct InvalidBestNodeInfo {
|
|||||||
pub justified_checkpoint: Checkpoint,
|
pub justified_checkpoint: Checkpoint,
|
||||||
pub finalized_checkpoint: Checkpoint,
|
pub finalized_checkpoint: Checkpoint,
|
||||||
pub head_root: Hash256,
|
pub head_root: Hash256,
|
||||||
pub head_justified_checkpoint: Option<Checkpoint>,
|
pub head_justified_checkpoint: Checkpoint,
|
||||||
pub head_finalized_checkpoint: Option<Checkpoint>,
|
pub head_finalized_checkpoint: Checkpoint,
|
||||||
}
|
}
|
||||||
|
@ -16,5 +16,5 @@ pub use error::Error;
|
|||||||
pub mod core {
|
pub mod core {
|
||||||
pub use super::proto_array::{ProposerBoost, ProtoArray, ProtoNode};
|
pub use super::proto_array::{ProposerBoost, ProtoArray, ProtoNode};
|
||||||
pub use super::proto_array_fork_choice::VoteTracker;
|
pub use super::proto_array_fork_choice::VoteTracker;
|
||||||
pub use super::ssz_container::SszContainer;
|
pub use super::ssz_container::{SszContainer, SszContainerV16, SszContainerV17};
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ use ssz::four_byte_option_impl;
|
|||||||
use ssz::Encode;
|
use ssz::Encode;
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
use superstruct::superstruct;
|
||||||
use types::{
|
use types::{
|
||||||
AttestationShufflingId, ChainSpec, Checkpoint, Epoch, EthSpec, ExecutionBlockHash, Hash256,
|
AttestationShufflingId, ChainSpec, Checkpoint, Epoch, EthSpec, ExecutionBlockHash, Hash256,
|
||||||
Slot,
|
Slot,
|
||||||
@ -66,7 +67,13 @@ impl InvalidationOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug, Encode, Decode, Serialize, Deserialize)]
|
pub type ProtoNode = ProtoNodeV17;
|
||||||
|
|
||||||
|
#[superstruct(
|
||||||
|
variants(V16, V17),
|
||||||
|
variant_attributes(derive(Clone, PartialEq, Debug, Encode, Decode, Serialize, Deserialize)),
|
||||||
|
no_enum
|
||||||
|
)]
|
||||||
pub struct ProtoNode {
|
pub struct ProtoNode {
|
||||||
/// The `slot` is not necessary for `ProtoArray`, it just exists so external components can
|
/// The `slot` is not necessary for `ProtoArray`, it just exists so external components can
|
||||||
/// easily query the block slot. This is useful for upstream fork choice logic.
|
/// easily query the block slot. This is useful for upstream fork choice logic.
|
||||||
@ -85,10 +92,16 @@ pub struct ProtoNode {
|
|||||||
pub root: Hash256,
|
pub root: Hash256,
|
||||||
#[ssz(with = "four_byte_option_usize")]
|
#[ssz(with = "four_byte_option_usize")]
|
||||||
pub parent: Option<usize>,
|
pub parent: Option<usize>,
|
||||||
|
#[superstruct(only(V16))]
|
||||||
#[ssz(with = "four_byte_option_checkpoint")]
|
#[ssz(with = "four_byte_option_checkpoint")]
|
||||||
pub justified_checkpoint: Option<Checkpoint>,
|
pub justified_checkpoint: Option<Checkpoint>,
|
||||||
|
#[superstruct(only(V16))]
|
||||||
#[ssz(with = "four_byte_option_checkpoint")]
|
#[ssz(with = "four_byte_option_checkpoint")]
|
||||||
pub finalized_checkpoint: Option<Checkpoint>,
|
pub finalized_checkpoint: Option<Checkpoint>,
|
||||||
|
#[superstruct(only(V17))]
|
||||||
|
pub justified_checkpoint: Checkpoint,
|
||||||
|
#[superstruct(only(V17))]
|
||||||
|
pub finalized_checkpoint: Checkpoint,
|
||||||
pub weight: u64,
|
pub weight: u64,
|
||||||
#[ssz(with = "four_byte_option_usize")]
|
#[ssz(with = "four_byte_option_usize")]
|
||||||
pub best_child: Option<usize>,
|
pub best_child: Option<usize>,
|
||||||
@ -103,6 +116,57 @@ pub struct ProtoNode {
|
|||||||
pub unrealized_finalized_checkpoint: Option<Checkpoint>,
|
pub unrealized_finalized_checkpoint: Option<Checkpoint>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryInto<ProtoNode> for ProtoNodeV16 {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<ProtoNode, Error> {
|
||||||
|
let result = ProtoNode {
|
||||||
|
slot: self.slot,
|
||||||
|
state_root: self.state_root,
|
||||||
|
target_root: self.target_root,
|
||||||
|
current_epoch_shuffling_id: self.current_epoch_shuffling_id,
|
||||||
|
next_epoch_shuffling_id: self.next_epoch_shuffling_id,
|
||||||
|
root: self.root,
|
||||||
|
parent: self.parent,
|
||||||
|
justified_checkpoint: self
|
||||||
|
.justified_checkpoint
|
||||||
|
.ok_or(Error::MissingJustifiedCheckpoint)?,
|
||||||
|
finalized_checkpoint: self
|
||||||
|
.finalized_checkpoint
|
||||||
|
.ok_or(Error::MissingFinalizedCheckpoint)?,
|
||||||
|
weight: self.weight,
|
||||||
|
best_child: self.best_child,
|
||||||
|
best_descendant: self.best_descendant,
|
||||||
|
execution_status: self.execution_status,
|
||||||
|
unrealized_justified_checkpoint: self.unrealized_justified_checkpoint,
|
||||||
|
unrealized_finalized_checkpoint: self.unrealized_finalized_checkpoint,
|
||||||
|
};
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<ProtoNodeV16> for ProtoNode {
|
||||||
|
fn into(self) -> ProtoNodeV16 {
|
||||||
|
ProtoNodeV16 {
|
||||||
|
slot: self.slot,
|
||||||
|
state_root: self.state_root,
|
||||||
|
target_root: self.target_root,
|
||||||
|
current_epoch_shuffling_id: self.current_epoch_shuffling_id,
|
||||||
|
next_epoch_shuffling_id: self.next_epoch_shuffling_id,
|
||||||
|
root: self.root,
|
||||||
|
parent: self.parent,
|
||||||
|
justified_checkpoint: Some(self.justified_checkpoint),
|
||||||
|
finalized_checkpoint: Some(self.finalized_checkpoint),
|
||||||
|
weight: self.weight,
|
||||||
|
best_child: self.best_child,
|
||||||
|
best_descendant: self.best_descendant,
|
||||||
|
execution_status: self.execution_status,
|
||||||
|
unrealized_justified_checkpoint: self.unrealized_justified_checkpoint,
|
||||||
|
unrealized_finalized_checkpoint: self.unrealized_finalized_checkpoint,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Encode, Decode, Serialize, Deserialize, Copy, Clone)]
|
#[derive(PartialEq, Debug, Encode, Decode, Serialize, Deserialize, Copy, Clone)]
|
||||||
pub struct ProposerBoost {
|
pub struct ProposerBoost {
|
||||||
pub root: Hash256,
|
pub root: Hash256,
|
||||||
@ -320,8 +384,8 @@ impl ProtoArray {
|
|||||||
parent: block
|
parent: block
|
||||||
.parent_root
|
.parent_root
|
||||||
.and_then(|parent| self.indices.get(&parent).copied()),
|
.and_then(|parent| self.indices.get(&parent).copied()),
|
||||||
justified_checkpoint: Some(block.justified_checkpoint),
|
justified_checkpoint: block.justified_checkpoint,
|
||||||
finalized_checkpoint: Some(block.finalized_checkpoint),
|
finalized_checkpoint: block.finalized_checkpoint,
|
||||||
weight: 0,
|
weight: 0,
|
||||||
best_child: None,
|
best_child: None,
|
||||||
best_descendant: None,
|
best_descendant: None,
|
||||||
@ -883,14 +947,7 @@ impl ProtoArray {
|
|||||||
let genesis_epoch = Epoch::new(0);
|
let genesis_epoch = Epoch::new(0);
|
||||||
let current_epoch = current_slot.epoch(E::slots_per_epoch());
|
let current_epoch = current_slot.epoch(E::slots_per_epoch());
|
||||||
let node_epoch = node.slot.epoch(E::slots_per_epoch());
|
let node_epoch = node.slot.epoch(E::slots_per_epoch());
|
||||||
let node_justified_checkpoint =
|
let node_justified_checkpoint = node.justified_checkpoint;
|
||||||
if let Some(justified_checkpoint) = node.justified_checkpoint {
|
|
||||||
justified_checkpoint
|
|
||||||
} else {
|
|
||||||
// The node does not have any information about the justified
|
|
||||||
// checkpoint. This indicates an inconsistent proto-array.
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
let voting_source = if current_epoch > node_epoch {
|
let voting_source = if current_epoch > node_epoch {
|
||||||
// The block is from a prior epoch, the voting source will be pulled-up.
|
// The block is from a prior epoch, the voting source will be pulled-up.
|
||||||
@ -998,9 +1055,13 @@ impl ProtoArray {
|
|||||||
// Run this check once, outside of the loop rather than inside the loop.
|
// Run this check once, outside of the loop rather than inside the loop.
|
||||||
// If the conditions don't match for this node then they're unlikely to
|
// If the conditions don't match for this node then they're unlikely to
|
||||||
// start matching for its ancestors.
|
// start matching for its ancestors.
|
||||||
|
for checkpoint in &[node.finalized_checkpoint, node.justified_checkpoint] {
|
||||||
|
if checkpoint == &self.finalized_checkpoint {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for checkpoint in &[
|
for checkpoint in &[
|
||||||
node.finalized_checkpoint,
|
|
||||||
node.justified_checkpoint,
|
|
||||||
node.unrealized_finalized_checkpoint,
|
node.unrealized_finalized_checkpoint,
|
||||||
node.unrealized_justified_checkpoint,
|
node.unrealized_justified_checkpoint,
|
||||||
] {
|
] {
|
||||||
|
@ -754,29 +754,20 @@ impl ProtoArrayForkChoice {
|
|||||||
.and_then(|i| self.proto_array.nodes.get(i))
|
.and_then(|i| self.proto_array.nodes.get(i))
|
||||||
.map(|parent| parent.root);
|
.map(|parent| parent.root);
|
||||||
|
|
||||||
// If a node does not have a `finalized_checkpoint` or `justified_checkpoint` populated,
|
Some(Block {
|
||||||
// it means it is not a descendant of the finalized checkpoint, so it is valid to return
|
slot: block.slot,
|
||||||
// `None` here.
|
root: block.root,
|
||||||
if let (Some(justified_checkpoint), Some(finalized_checkpoint)) =
|
parent_root,
|
||||||
(block.justified_checkpoint, block.finalized_checkpoint)
|
state_root: block.state_root,
|
||||||
{
|
target_root: block.target_root,
|
||||||
Some(Block {
|
current_epoch_shuffling_id: block.current_epoch_shuffling_id.clone(),
|
||||||
slot: block.slot,
|
next_epoch_shuffling_id: block.next_epoch_shuffling_id.clone(),
|
||||||
root: block.root,
|
justified_checkpoint: block.justified_checkpoint,
|
||||||
parent_root,
|
finalized_checkpoint: block.finalized_checkpoint,
|
||||||
state_root: block.state_root,
|
execution_status: block.execution_status,
|
||||||
target_root: block.target_root,
|
unrealized_justified_checkpoint: block.unrealized_justified_checkpoint,
|
||||||
current_epoch_shuffling_id: block.current_epoch_shuffling_id.clone(),
|
unrealized_finalized_checkpoint: block.unrealized_finalized_checkpoint,
|
||||||
next_epoch_shuffling_id: block.next_epoch_shuffling_id.clone(),
|
})
|
||||||
justified_checkpoint,
|
|
||||||
finalized_checkpoint,
|
|
||||||
execution_status: block.execution_status,
|
|
||||||
unrealized_justified_checkpoint: block.unrealized_justified_checkpoint,
|
|
||||||
unrealized_finalized_checkpoint: block.unrealized_finalized_checkpoint,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `block.execution_status` field, if the block is present.
|
/// Returns the `block.execution_status` field, if the block is present.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::proto_array::ProposerBoost;
|
use crate::proto_array::ProposerBoost;
|
||||||
use crate::{
|
use crate::{
|
||||||
proto_array::{ProtoArray, ProtoNode},
|
proto_array::{ProtoArray, ProtoNodeV16, ProtoNodeV17},
|
||||||
proto_array_fork_choice::{ElasticList, ProtoArrayForkChoice, VoteTracker},
|
proto_array_fork_choice::{ElasticList, ProtoArrayForkChoice, VoteTracker},
|
||||||
Error, JustifiedBalances,
|
Error, JustifiedBalances,
|
||||||
};
|
};
|
||||||
@ -8,24 +8,71 @@ use ssz::{four_byte_option_impl, Encode};
|
|||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use superstruct::superstruct;
|
||||||
use types::{Checkpoint, Hash256};
|
use types::{Checkpoint, Hash256};
|
||||||
|
|
||||||
// Define a "legacy" implementation of `Option<usize>` which uses four bytes for encoding the union
|
// Define a "legacy" implementation of `Option<usize>` which uses four bytes for encoding the union
|
||||||
// selector.
|
// selector.
|
||||||
four_byte_option_impl!(four_byte_option_checkpoint, Checkpoint);
|
four_byte_option_impl!(four_byte_option_checkpoint, Checkpoint);
|
||||||
|
|
||||||
#[derive(Encode, Decode)]
|
pub type SszContainer = SszContainerV17;
|
||||||
|
|
||||||
|
#[superstruct(
|
||||||
|
variants(V16, V17),
|
||||||
|
variant_attributes(derive(Encode, Decode)),
|
||||||
|
no_enum
|
||||||
|
)]
|
||||||
pub struct SszContainer {
|
pub struct SszContainer {
|
||||||
pub votes: Vec<VoteTracker>,
|
pub votes: Vec<VoteTracker>,
|
||||||
pub balances: Vec<u64>,
|
pub balances: Vec<u64>,
|
||||||
pub prune_threshold: usize,
|
pub prune_threshold: usize,
|
||||||
pub justified_checkpoint: Checkpoint,
|
pub justified_checkpoint: Checkpoint,
|
||||||
pub finalized_checkpoint: Checkpoint,
|
pub finalized_checkpoint: Checkpoint,
|
||||||
pub nodes: Vec<ProtoNode>,
|
#[superstruct(only(V16))]
|
||||||
|
pub nodes: Vec<ProtoNodeV16>,
|
||||||
|
#[superstruct(only(V17))]
|
||||||
|
pub nodes: Vec<ProtoNodeV17>,
|
||||||
pub indices: Vec<(Hash256, usize)>,
|
pub indices: Vec<(Hash256, usize)>,
|
||||||
pub previous_proposer_boost: ProposerBoost,
|
pub previous_proposer_boost: ProposerBoost,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl TryInto<SszContainer> for SszContainerV16 {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_into(self) -> Result<SszContainer, Error> {
|
||||||
|
let nodes: Result<Vec<ProtoNodeV17>, Error> =
|
||||||
|
self.nodes.into_iter().map(TryInto::try_into).collect();
|
||||||
|
|
||||||
|
Ok(SszContainer {
|
||||||
|
votes: self.votes,
|
||||||
|
balances: self.balances,
|
||||||
|
prune_threshold: self.prune_threshold,
|
||||||
|
justified_checkpoint: self.justified_checkpoint,
|
||||||
|
finalized_checkpoint: self.finalized_checkpoint,
|
||||||
|
nodes: nodes?,
|
||||||
|
indices: self.indices,
|
||||||
|
previous_proposer_boost: self.previous_proposer_boost,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<SszContainerV16> for SszContainer {
|
||||||
|
fn into(self) -> SszContainerV16 {
|
||||||
|
let nodes = self.nodes.into_iter().map(Into::into).collect();
|
||||||
|
|
||||||
|
SszContainerV16 {
|
||||||
|
votes: self.votes,
|
||||||
|
balances: self.balances,
|
||||||
|
prune_threshold: self.prune_threshold,
|
||||||
|
justified_checkpoint: self.justified_checkpoint,
|
||||||
|
finalized_checkpoint: self.finalized_checkpoint,
|
||||||
|
nodes,
|
||||||
|
indices: self.indices,
|
||||||
|
previous_proposer_boost: self.previous_proposer_boost,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&ProtoArrayForkChoice> for SszContainer {
|
impl From<&ProtoArrayForkChoice> for SszContainer {
|
||||||
fn from(from: &ProtoArrayForkChoice) -> Self {
|
fn from(from: &ProtoArrayForkChoice) -> Self {
|
||||||
let proto_array = &from.proto_array;
|
let proto_array = &from.proto_array;
|
||||||
|
Loading…
Reference in New Issue
Block a user