|
| 1 | +use crate::beacon_chain::BeaconChainTypes; |
| 2 | +use crate::persisted_fork_choice::PersistedForkChoice; |
| 3 | +use crate::schema_change::StoreError; |
| 4 | +use crate::test_utils::{PersistedBeaconChain, BEACON_CHAIN_DB_KEY, FORK_CHOICE_DB_KEY}; |
| 5 | +use crate::BeaconForkChoiceStore; |
| 6 | +use fork_choice::{ForkChoice, ResetPayloadStatuses}; |
| 7 | +use slog::Logger; |
| 8 | +use ssz::{Decode, Encode}; |
| 9 | +use ssz_derive::{Decode, Encode}; |
| 10 | +use std::sync::Arc; |
| 11 | +use store::{DBColumn, Error, HotColdDB, KeyValueStoreOp, StoreItem}; |
| 12 | +use types::{Hash256, Slot}; |
| 13 | + |
| 14 | +/// Dummy value to use for the canonical head block root, see below. |
| 15 | +pub const DUMMY_CANONICAL_HEAD_BLOCK_ROOT: Hash256 = Hash256::repeat_byte(0xff); |
| 16 | + |
| 17 | +pub fn upgrade_to_v23<T: BeaconChainTypes>( |
| 18 | + db: Arc<HotColdDB<T::EthSpec, T::HotStore, T::ColdStore>>, |
| 19 | + _log: Logger, |
| 20 | +) -> Result<Vec<KeyValueStoreOp>, Error> { |
| 21 | + // Set the head-tracker to empty |
| 22 | + |
| 23 | + let Some(persisted_beacon_chain_v22) = |
| 24 | + db.get_item::<PersistedBeaconChainV22>(&BEACON_CHAIN_DB_KEY)? |
| 25 | + else { |
| 26 | + // If there is no persisted beacon chain, ignore the upgrade |
| 27 | + return Ok(vec![]); |
| 28 | + }; |
| 29 | + |
| 30 | + let persisted_beacon_chain = PersistedBeaconChain { |
| 31 | + genesis_block_root: persisted_beacon_chain_v22.genesis_block_root, |
| 32 | + }; |
| 33 | + |
| 34 | + db.put_item::<PersistedBeaconChain>(&BEACON_CHAIN_DB_KEY, &persisted_beacon_chain)?; |
| 35 | + |
| 36 | + todo!(); |
| 37 | +} |
| 38 | + |
| 39 | +pub fn downgrade_from_v23<T: BeaconChainTypes>( |
| 40 | + db: Arc<HotColdDB<T::EthSpec, T::HotStore, T::ColdStore>>, |
| 41 | + log: Logger, |
| 42 | +) -> Result<Vec<KeyValueStoreOp>, Error> { |
| 43 | + // recreate head-tracker from the fork-choice |
| 44 | + |
| 45 | + let Some(persisted_fork_choice) = db.get_item::<PersistedForkChoice>(&FORK_CHOICE_DB_KEY)? |
| 46 | + else { |
| 47 | + // Is it possible for the fork-choice to not exist on a downgrade? |
| 48 | + return Ok(vec![]); |
| 49 | + }; |
| 50 | + |
| 51 | + let Some(persisted_beacon_chain) = db.get_item::<PersistedBeaconChain>(&BEACON_CHAIN_DB_KEY)? |
| 52 | + else { |
| 53 | + // TODO: Is it possible for persisted beacon chain to be missing if the fork choice exists? |
| 54 | + return Ok(vec![]); |
| 55 | + }; |
| 56 | + |
| 57 | + let fc_store = |
| 58 | + BeaconForkChoiceStore::from_persisted(persisted_fork_choice.fork_choice_store, db.clone()) |
| 59 | + .map_err(|e| { |
| 60 | + Error::MigrationError(format!( |
| 61 | + "Error loading fork choise store from persisted: {e:?}" |
| 62 | + )) |
| 63 | + })?; |
| 64 | + |
| 65 | + // TODO: what value to choose here? |
| 66 | + let reset_payload_statuses = ResetPayloadStatuses::OnlyWithInvalidPayload; |
| 67 | + let mut fork_choice = ForkChoice::from_persisted( |
| 68 | + persisted_fork_choice.fork_choice, |
| 69 | + reset_payload_statuses, |
| 70 | + fc_store, |
| 71 | + &db.spec, |
| 72 | + &log, |
| 73 | + ) |
| 74 | + .map_err(|e| { |
| 75 | + Error::MigrationError(format!("Error loading fork choice from persisted: {e:?}")) |
| 76 | + })?; |
| 77 | + |
| 78 | + // TODO: initialize clock |
| 79 | + let current_slot = Slot::new(0); |
| 80 | + let head_block_root = fork_choice |
| 81 | + .get_head(current_slot, &db.spec) |
| 82 | + .map_err(|e| Error::MigrationError(format!("Error computing get_head: {e:?}")))?; |
| 83 | + |
| 84 | + let head_proto_block = fork_choice |
| 85 | + .get_block(&head_block_root) |
| 86 | + .ok_or(Error::MigrationError(format!( |
| 87 | + "HeadBlockMissingFromForkChoice({head_block_root:?})" |
| 88 | + )))?; |
| 89 | + |
| 90 | + let heads = fork_choice |
| 91 | + .proto_array() |
| 92 | + .viable_heads::<T::EthSpec>(head_proto_block.slot); |
| 93 | + |
| 94 | + let head_roots = heads.iter().map(|node| node.root).collect(); |
| 95 | + let head_slots = heads.iter().map(|node| node.slot).collect(); |
| 96 | + |
| 97 | + let persisted_beacon_chain_v22 = PersistedBeaconChainV22 { |
| 98 | + _canonical_head_block_root: DUMMY_CANONICAL_HEAD_BLOCK_ROOT, |
| 99 | + genesis_block_root: persisted_beacon_chain.genesis_block_root, |
| 100 | + ssz_head_tracker: SszHeadTracker { |
| 101 | + roots: head_roots, |
| 102 | + slots: head_slots, |
| 103 | + }, |
| 104 | + }; |
| 105 | + |
| 106 | + db.put_item::<PersistedBeaconChainV22>(&BEACON_CHAIN_DB_KEY, &persisted_beacon_chain_v22)?; |
| 107 | + |
| 108 | + todo!(); |
| 109 | +} |
| 110 | + |
| 111 | +/// Helper struct that is used to encode/decode the state of the `HeadTracker` as SSZ bytes. |
| 112 | +/// |
| 113 | +/// This is used when persisting the state of the `BeaconChain` to disk. |
| 114 | +#[derive(Encode, Decode, Clone)] |
| 115 | +pub struct SszHeadTracker { |
| 116 | + roots: Vec<Hash256>, |
| 117 | + slots: Vec<Slot>, |
| 118 | +} |
| 119 | + |
| 120 | +#[derive(Clone, Encode, Decode)] |
| 121 | +pub struct PersistedBeaconChainV22 { |
| 122 | + /// This value is ignored to resolve the issue described here: |
| 123 | + /// |
| 124 | + /// https://github.com/sigp/lighthouse/pull/1639 |
| 125 | + /// |
| 126 | + /// Its removal is tracked here: |
| 127 | + /// |
| 128 | + /// https://github.com/sigp/lighthouse/issues/1784 |
| 129 | + pub _canonical_head_block_root: Hash256, |
| 130 | + pub genesis_block_root: Hash256, |
| 131 | + /// DEPRECATED |
| 132 | + pub ssz_head_tracker: SszHeadTracker, |
| 133 | +} |
| 134 | + |
| 135 | +impl StoreItem for PersistedBeaconChainV22 { |
| 136 | + fn db_column() -> DBColumn { |
| 137 | + DBColumn::BeaconChain |
| 138 | + } |
| 139 | + |
| 140 | + fn as_store_bytes(&self) -> Vec<u8> { |
| 141 | + self.as_ssz_bytes() |
| 142 | + } |
| 143 | + |
| 144 | + fn from_store_bytes(bytes: &[u8]) -> Result<Self, StoreError> { |
| 145 | + Self::from_ssz_bytes(bytes).map_err(Into::into) |
| 146 | + } |
| 147 | +} |
0 commit comments