Realized unrealized experimentation (#3322)

## Issue Addressed

Add a flag that optionally enables unrealized vote tracking.  Would like to test out on testnets and benchmark differences in methods of vote tracking. This PR includes a DB schema upgrade to enable to new vote tracking style.


Co-authored-by: realbigsean <sean@sigmaprime.io>
Co-authored-by: Paul Hauner <paul@paulhauner.com>
Co-authored-by: sean <seananderson33@gmail.com>
Co-authored-by: Mac L <mjladson@pm.me>
This commit is contained in:
realbigsean
2022-07-25 23:53:26 +00:00
parent bb5a6d2cca
commit 20ebf1f3c1
47 changed files with 1254 additions and 338 deletions

View File

@@ -0,0 +1,97 @@
use crate::beacon_fork_choice_store::{PersistedForkChoiceStoreV10, PersistedForkChoiceStoreV8};
use crate::persisted_fork_choice::{PersistedForkChoiceV10, PersistedForkChoiceV8};
use crate::schema_change::{
types::{SszContainerV10, SszContainerV7},
StoreError,
};
use proto_array::core::SszContainer;
use ssz::{Decode, Encode};
pub fn update_fork_choice(
mut fork_choice: PersistedForkChoiceV8,
) -> Result<PersistedForkChoiceV10, StoreError> {
let ssz_container_v7 = SszContainerV7::from_ssz_bytes(
&fork_choice.fork_choice.proto_array_bytes,
)
.map_err(|e| {
StoreError::SchemaMigrationError(format!(
"Failed to decode ProtoArrayForkChoice during schema migration: {:?}",
e
))
})?;
// These transformations instantiate `node.unrealized_justified_checkpoint` and
// `node.unrealized_finalized_checkpoint` to `None`.
let ssz_container_v10: SszContainerV10 = ssz_container_v7.into();
let ssz_container: SszContainer = ssz_container_v10.into();
fork_choice.fork_choice.proto_array_bytes = ssz_container.as_ssz_bytes();
Ok(fork_choice.into())
}
pub fn downgrade_fork_choice(
mut fork_choice: PersistedForkChoiceV10,
) -> Result<PersistedForkChoiceV8, StoreError> {
let ssz_container_v10 = SszContainerV10::from_ssz_bytes(
&fork_choice.fork_choice.proto_array_bytes,
)
.map_err(|e| {
StoreError::SchemaMigrationError(format!(
"Failed to decode ProtoArrayForkChoice during schema migration: {:?}",
e
))
})?;
let ssz_container_v7: SszContainerV7 = ssz_container_v10.into();
fork_choice.fork_choice.proto_array_bytes = ssz_container_v7.as_ssz_bytes();
Ok(fork_choice.into())
}
impl From<PersistedForkChoiceStoreV8> for PersistedForkChoiceStoreV10 {
fn from(other: PersistedForkChoiceStoreV8) -> Self {
Self {
balances_cache: other.balances_cache,
time: other.time,
finalized_checkpoint: other.finalized_checkpoint,
justified_checkpoint: other.justified_checkpoint,
justified_balances: other.justified_balances,
best_justified_checkpoint: other.best_justified_checkpoint,
unrealized_justified_checkpoint: other.best_justified_checkpoint,
unrealized_finalized_checkpoint: other.finalized_checkpoint,
proposer_boost_root: other.proposer_boost_root,
}
}
}
impl From<PersistedForkChoiceV8> for PersistedForkChoiceV10 {
fn from(other: PersistedForkChoiceV8) -> Self {
Self {
fork_choice: other.fork_choice,
fork_choice_store: other.fork_choice_store.into(),
}
}
}
impl From<PersistedForkChoiceStoreV10> for PersistedForkChoiceStoreV8 {
fn from(other: PersistedForkChoiceStoreV10) -> Self {
Self {
balances_cache: other.balances_cache,
time: other.time,
finalized_checkpoint: other.finalized_checkpoint,
justified_checkpoint: other.justified_checkpoint,
justified_balances: other.justified_balances,
best_justified_checkpoint: other.best_justified_checkpoint,
proposer_boost_root: other.proposer_boost_root,
}
}
}
impl From<PersistedForkChoiceV10> for PersistedForkChoiceV8 {
fn from(other: PersistedForkChoiceV10) -> Self {
Self {
fork_choice: other.fork_choice,
fork_choice_store: other.fork_choice_store.into(),
}
}
}

View File

@@ -2,7 +2,7 @@
use crate::beacon_chain::BeaconChainTypes;
use crate::beacon_fork_choice_store::{PersistedForkChoiceStoreV1, PersistedForkChoiceStoreV7};
use crate::persisted_fork_choice::{PersistedForkChoiceV1, PersistedForkChoiceV7};
use crate::schema_change::types::{ProtoNodeV6, SszContainerV6, SszContainerV7};
use crate::schema_change::types::{ProtoNodeV6, SszContainerV10, SszContainerV6, SszContainerV7};
use crate::types::{ChainSpec, Checkpoint, Epoch, EthSpec, Hash256, Slot};
use crate::{BeaconForkChoiceStore, BeaconSnapshot};
use fork_choice::ForkChoice;
@@ -86,7 +86,8 @@ pub(crate) fn update_fork_choice<T: BeaconChainTypes>(
// to `None`.
let ssz_container_v7: SszContainerV7 =
ssz_container_v6.into_ssz_container_v7(justified_checkpoint, finalized_checkpoint);
let ssz_container: SszContainer = ssz_container_v7.into();
let ssz_container_v10: SszContainerV10 = ssz_container_v7.into();
let ssz_container: SszContainer = ssz_container_v10.into();
let mut fork_choice: ProtoArrayForkChoice = ssz_container.into();
update_checkpoints::<T>(finalized_checkpoint.root, &nodes_v6, &mut fork_choice, db)
@@ -97,6 +98,13 @@ pub(crate) fn update_fork_choice<T: BeaconChainTypes>(
update_store_justified_checkpoint(persisted_fork_choice, &mut fork_choice)
.map_err(StoreError::SchemaMigrationError)?;
// Need to downgrade the SSZ container to V7 so that all migrations can be applied in sequence.
let ssz_container = SszContainer::from(&fork_choice);
let ssz_container_v7 = SszContainerV7::from(ssz_container);
persisted_fork_choice.fork_choice.proto_array_bytes = ssz_container_v7.as_ssz_bytes();
persisted_fork_choice.fork_choice_store.justified_checkpoint = justified_checkpoint;
Ok(())
}
@@ -301,8 +309,6 @@ fn update_store_justified_checkpoint(
.ok_or("Proto node with current finalized checkpoint not found")?;
fork_choice.core_proto_array_mut().justified_checkpoint = justified_checkpoint;
persisted_fork_choice.fork_choice.proto_array_bytes = fork_choice.as_bytes();
persisted_fork_choice.fork_choice_store.justified_checkpoint = justified_checkpoint;
Ok(())
}

View File

@@ -12,7 +12,7 @@ four_byte_option_impl!(four_byte_option_usize, usize);
four_byte_option_impl!(four_byte_option_checkpoint, Checkpoint);
#[superstruct(
variants(V1, V6, V7),
variants(V1, V6, V7, V10),
variant_attributes(derive(Clone, PartialEq, Debug, Encode, Decode)),
no_enum
)]
@@ -30,18 +30,24 @@ pub struct ProtoNode {
#[superstruct(only(V1, V6))]
pub finalized_epoch: Epoch,
#[ssz(with = "four_byte_option_checkpoint")]
#[superstruct(only(V7))]
#[superstruct(only(V7, V10))]
pub justified_checkpoint: Option<Checkpoint>,
#[ssz(with = "four_byte_option_checkpoint")]
#[superstruct(only(V7))]
#[superstruct(only(V7, V10))]
pub finalized_checkpoint: Option<Checkpoint>,
pub weight: u64,
#[ssz(with = "four_byte_option_usize")]
pub best_child: Option<usize>,
#[ssz(with = "four_byte_option_usize")]
pub best_descendant: Option<usize>,
#[superstruct(only(V6, V7))]
#[superstruct(only(V6, V7, V10))]
pub execution_status: ExecutionStatus,
#[ssz(with = "four_byte_option_checkpoint")]
#[superstruct(only(V10))]
pub unrealized_justified_checkpoint: Option<Checkpoint>,
#[ssz(with = "four_byte_option_checkpoint")]
#[superstruct(only(V10))]
pub unrealized_finalized_checkpoint: Option<Checkpoint>,
}
impl Into<ProtoNodeV6> for ProtoNodeV1 {
@@ -88,9 +94,31 @@ impl Into<ProtoNodeV7> for ProtoNodeV6 {
}
}
impl Into<ProtoNode> for ProtoNodeV7 {
fn into(self) -> ProtoNode {
ProtoNode {
impl Into<ProtoNodeV10> for ProtoNodeV7 {
fn into(self) -> ProtoNodeV10 {
ProtoNodeV10 {
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,
finalized_checkpoint: self.finalized_checkpoint,
weight: self.weight,
best_child: self.best_child,
best_descendant: self.best_descendant,
execution_status: self.execution_status,
unrealized_justified_checkpoint: None,
unrealized_finalized_checkpoint: None,
}
}
}
impl Into<ProtoNodeV7> for ProtoNodeV10 {
fn into(self) -> ProtoNodeV7 {
ProtoNodeV7 {
slot: self.slot,
state_root: self.state_root,
target_root: self.target_root,
@@ -108,8 +136,50 @@ impl Into<ProtoNode> for ProtoNodeV7 {
}
}
impl Into<ProtoNode> for ProtoNodeV10 {
fn into(self) -> ProtoNode {
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,
finalized_checkpoint: 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,
}
}
}
impl From<ProtoNode> for ProtoNodeV7 {
fn from(container: ProtoNode) -> Self {
Self {
slot: container.slot,
state_root: container.state_root,
target_root: container.target_root,
current_epoch_shuffling_id: container.current_epoch_shuffling_id,
next_epoch_shuffling_id: container.next_epoch_shuffling_id,
root: container.root,
parent: container.parent,
justified_checkpoint: container.justified_checkpoint,
finalized_checkpoint: container.finalized_checkpoint,
weight: container.weight,
best_child: container.best_child,
best_descendant: container.best_descendant,
execution_status: container.execution_status,
}
}
}
#[superstruct(
variants(V1, V6, V7),
variants(V1, V6, V7, V10),
variant_attributes(derive(Encode, Decode)),
no_enum
)]
@@ -122,9 +192,9 @@ pub struct SszContainer {
pub justified_epoch: Epoch,
#[superstruct(only(V1, V6))]
pub finalized_epoch: Epoch,
#[superstruct(only(V7))]
#[superstruct(only(V7, V10))]
pub justified_checkpoint: Checkpoint,
#[superstruct(only(V7))]
#[superstruct(only(V7, V10))]
pub finalized_checkpoint: Checkpoint,
#[superstruct(only(V1))]
pub nodes: Vec<ProtoNodeV1>,
@@ -132,8 +202,10 @@ pub struct SszContainer {
pub nodes: Vec<ProtoNodeV6>,
#[superstruct(only(V7))]
pub nodes: Vec<ProtoNodeV7>,
#[superstruct(only(V10))]
pub nodes: Vec<ProtoNodeV10>,
pub indices: Vec<(Hash256, usize)>,
#[superstruct(only(V7))]
#[superstruct(only(V7, V10))]
pub previous_proposer_boost: ProposerBoost,
}
@@ -174,7 +246,41 @@ impl SszContainerV6 {
}
}
impl Into<SszContainer> for SszContainerV7 {
impl Into<SszContainerV10> for SszContainerV7 {
fn into(self) -> SszContainerV10 {
let nodes = self.nodes.into_iter().map(Into::into).collect();
SszContainerV10 {
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 Into<SszContainerV7> for SszContainerV10 {
fn into(self) -> SszContainerV7 {
let nodes = self.nodes.into_iter().map(Into::into).collect();
SszContainerV7 {
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 Into<SszContainer> for SszContainerV10 {
fn into(self) -> SszContainer {
let nodes = self.nodes.into_iter().map(Into::into).collect();
@@ -190,3 +296,20 @@ impl Into<SszContainer> for SszContainerV7 {
}
}
}
impl From<SszContainer> for SszContainerV7 {
fn from(container: SszContainer) -> Self {
let nodes = container.nodes.into_iter().map(Into::into).collect();
Self {
votes: container.votes,
balances: container.balances,
prune_threshold: container.prune_threshold,
justified_checkpoint: container.justified_checkpoint,
finalized_checkpoint: container.finalized_checkpoint,
nodes,
indices: container.indices,
previous_proposer_boost: container.previous_proposer_boost,
}
}
}