lighthouse/beacon_node/store/src/errors.rs
Michael Sproul c574f8136e Fix block backfill with genesis skip slots (#4820)
## Issue Addressed

Closes #4817.

## Proposed Changes

- Fill in the linear block roots array between 0 and the slot of the first block (e.g. slots 0 and 1 on Holesky).
- Backport the `--freezer`, `--skip` and `--limit` options for `lighthouse db inspect` from tree-states. This allows us to easily view the database corruption of 4817 using `lighthouse db inspect --network holesky --freezer --column bbr --output values --limit 2`.
- Backport the `iter_column_from` change and `MemoryStore` overhaul from tree-states. These are required to enable `lighthouse db inspect`.
- Rework `freezer_upper_limit` to allow state lookups for slots below the `state_lower_limit`. Currently state lookups will fail until state reconstruction completes entirely.

There is a new regression test for the main bug, but no test for the `freezer_upper_limit` fix because we don't currently support running state reconstruction partially (see #3026). This will be fixed once we merge `tree-states`! In lieu of an automated test, I've tested manually on a Holesky node while it was reconstructing.

## Additional Info

Users who backfilled Holesky to slot 0 (e.g. using `--reconstruct-historic-states`) need to either:

- Re-sync from genesis.
- Re-sync using checkpoint sync and the changes from this PR.

Due to the recency of the Holesky genesis, writing a custom pass to fix up broken databases (which would require its own thorough testing) was deemed unnecessary. This is the primary reason for this PR being marked `backwards-incompat`.

This will create few conflicts with Deneb, which I've already resolved on `tree-states-deneb` and will be happy to backport to Deneb once this PR is merged to unstable.
2023-10-27 05:08:49 +00:00

126 lines
3.2 KiB
Rust

use crate::chunked_vector::ChunkError;
use crate::config::StoreConfigError;
use crate::hot_cold_store::HotColdDBError;
use ssz::DecodeError;
use state_processing::BlockReplayError;
use types::{BeaconStateError, Hash256, InconsistentFork, Slot};
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub enum Error {
SszDecodeError(DecodeError),
VectorChunkError(ChunkError),
BeaconStateError(BeaconStateError),
PartialBeaconStateError,
HotColdDBError(HotColdDBError),
DBError {
message: String,
},
RlpError(String),
BlockNotFound(Hash256),
NoContinuationData,
SplitPointModified(Slot, Slot),
ConfigError(StoreConfigError),
SchemaMigrationError(String),
/// The store's `anchor_info` was mutated concurrently, the latest modification wasn't applied.
AnchorInfoConcurrentMutation,
/// The store's `blob_info` was mutated concurrently, the latest modification wasn't applied.
BlobInfoConcurrentMutation,
/// The block or state is unavailable due to weak subjectivity sync.
HistoryUnavailable,
/// State reconstruction cannot commence because not all historic blocks are known.
MissingHistoricBlocks {
oldest_block_slot: Slot,
},
/// State reconstruction failed because it didn't reach the upper limit slot.
///
/// This should never happen (it's a logic error).
StateReconstructionDidNotComplete,
StateReconstructionRootMismatch {
slot: Slot,
expected: Hash256,
computed: Hash256,
},
BlockReplayError(BlockReplayError),
AddPayloadLogicError,
SlotClockUnavailableForMigration,
InvalidKey,
InvalidBytes,
UnableToDowngrade,
InconsistentFork(InconsistentFork),
}
pub trait HandleUnavailable<T> {
fn handle_unavailable(self) -> std::result::Result<Option<T>, Error>;
}
impl<T> HandleUnavailable<T> for Result<T> {
fn handle_unavailable(self) -> std::result::Result<Option<T>, Error> {
match self {
Ok(x) => Ok(Some(x)),
Err(Error::HistoryUnavailable) => Ok(None),
Err(e) => Err(e),
}
}
}
impl From<DecodeError> for Error {
fn from(e: DecodeError) -> Error {
Error::SszDecodeError(e)
}
}
impl From<ChunkError> for Error {
fn from(e: ChunkError) -> Error {
Error::VectorChunkError(e)
}
}
impl From<HotColdDBError> for Error {
fn from(e: HotColdDBError) -> Error {
Error::HotColdDBError(e)
}
}
impl From<BeaconStateError> for Error {
fn from(e: BeaconStateError) -> Error {
Error::BeaconStateError(e)
}
}
impl From<DBError> for Error {
fn from(e: DBError) -> Error {
Error::DBError { message: e.message }
}
}
impl From<StoreConfigError> for Error {
fn from(e: StoreConfigError) -> Error {
Error::ConfigError(e)
}
}
impl From<BlockReplayError> for Error {
fn from(e: BlockReplayError) -> Error {
Error::BlockReplayError(e)
}
}
impl From<InconsistentFork> for Error {
fn from(e: InconsistentFork) -> Error {
Error::InconsistentFork(e)
}
}
#[derive(Debug)]
pub struct DBError {
pub message: String,
}
impl DBError {
pub fn new(message: String) -> Self {
Self { message }
}
}