Switch default slasher backend to LMDB (#4360)

## Issue Addressed

Closes #4354
Closes #3987

Replaces #4305, #4283

## Proposed Changes

This switches the default slasher backend _back_ to LMDB.

If an MDBX database exists and the MDBX backend is enabled then MDBX will continue to be used. Our release binaries and Docker images will continue to include MDBX for as long as it is practical, so users of these should not notice any difference.

The main benefit is to users compiling from source and devs running tests. These users no longer have to struggle to compile MDBX and deal with the compatibility issues that arises. Similarly, devs don't need to worry about toggling feature flags in tests or risk forgetting to run the slasher tests due to backend issues.
This commit is contained in:
Michael Sproul
2023-06-07 01:50:33 +00:00
parent b14d1493cc
commit 299cfe1fe6
15 changed files with 184 additions and 35 deletions

View File

@@ -5,7 +5,7 @@ authors = ["Michael Sproul <michael@sigmaprime.io>"]
edition = "2021"
[features]
default = ["mdbx"]
default = ["lmdb"]
mdbx = ["dep:mdbx"]
lmdb = ["lmdb-rkv", "lmdb-rkv-sys"]

View File

@@ -9,7 +9,7 @@ beacon_chain = { path = "../../beacon_node/beacon_chain" }
directory = { path = "../../common/directory" }
lighthouse_network = { path = "../../beacon_node/lighthouse_network" }
network = { path = "../../beacon_node/network" }
slasher = { path = "..", default-features = false }
slasher = { path = ".." }
slog = "2.5.2"
slot_clock = { path = "../../common/slot_clock" }
state_processing = { path = "../../consensus/state_processing" }

View File

@@ -13,15 +13,16 @@ pub const DEFAULT_MAX_DB_SIZE: usize = 256 * 1024; // 256 GiB
pub const DEFAULT_ATTESTATION_ROOT_CACHE_SIZE: usize = 100_000;
pub const DEFAULT_BROADCAST: bool = false;
#[cfg(feature = "mdbx")]
#[cfg(all(feature = "mdbx", not(feature = "lmdb")))]
pub const DEFAULT_BACKEND: DatabaseBackend = DatabaseBackend::Mdbx;
#[cfg(all(feature = "lmdb", not(feature = "mdbx")))]
#[cfg(feature = "lmdb")]
pub const DEFAULT_BACKEND: DatabaseBackend = DatabaseBackend::Lmdb;
#[cfg(not(any(feature = "mdbx", feature = "lmdb")))]
pub const DEFAULT_BACKEND: DatabaseBackend = DatabaseBackend::Disabled;
pub const MAX_HISTORY_LENGTH: usize = 1 << 16;
pub const MEGABYTE: usize = 1 << 20;
pub const MDBX_DATA_FILENAME: &str = "mdbx.dat";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
@@ -64,6 +65,13 @@ pub enum DatabaseBackend {
Disabled,
}
#[derive(Debug, PartialEq)]
pub enum DatabaseBackendOverride {
Success(DatabaseBackend),
Failure(PathBuf),
Noop,
}
impl Config {
pub fn new(database_path: PathBuf) -> Self {
Self {
@@ -161,4 +169,28 @@ impl Config {
.filter(move |v| self.validator_chunk_index(**v) == validator_chunk_index)
.copied()
}
pub fn override_backend(&mut self) -> DatabaseBackendOverride {
let mdbx_path = self.database_path.join(MDBX_DATA_FILENAME);
#[cfg(feature = "mdbx")]
let already_mdbx = self.backend == DatabaseBackend::Mdbx;
#[cfg(not(feature = "mdbx"))]
let already_mdbx = false;
if !already_mdbx && mdbx_path.exists() {
#[cfg(feature = "mdbx")]
{
let old_backend = self.backend;
self.backend = DatabaseBackend::Mdbx;
DatabaseBackendOverride::Success(old_backend)
}
#[cfg(not(feature = "mdbx"))]
{
DatabaseBackendOverride::Failure(mdbx_path)
}
} else {
DatabaseBackendOverride::Noop
}
}
}

View File

@@ -21,7 +21,7 @@ pub use crate::slasher::Slasher;
pub use attestation_queue::{AttestationBatch, AttestationQueue, SimpleBatch};
pub use attester_record::{AttesterRecord, CompactAttesterRecord, IndexedAttesterRecord};
pub use block_queue::BlockQueue;
pub use config::{Config, DatabaseBackend};
pub use config::{Config, DatabaseBackend, DatabaseBackendOverride};
pub use database::{
interface::{Database, Environment, RwTransaction},
IndexedAttestationId, SlasherDB,

57
slasher/tests/backend.rs Normal file
View File

@@ -0,0 +1,57 @@
#![cfg(all(feature = "lmdb"))]
use slasher::{config::MDBX_DATA_FILENAME, Config, DatabaseBackend, DatabaseBackendOverride};
use std::fs::File;
use tempfile::tempdir;
#[test]
#[cfg(all(feature = "mdbx", feature = "lmdb"))]
fn override_no_existing_db() {
let tempdir = tempdir().unwrap();
let mut config = Config::new(tempdir.path().into());
assert_eq!(config.override_backend(), DatabaseBackendOverride::Noop);
}
#[test]
#[cfg(all(feature = "mdbx", feature = "lmdb"))]
fn override_with_existing_mdbx_db() {
let tempdir = tempdir().unwrap();
let mut config = Config::new(tempdir.path().into());
File::create(config.database_path.join(MDBX_DATA_FILENAME)).unwrap();
assert_eq!(
config.override_backend(),
DatabaseBackendOverride::Success(DatabaseBackend::Lmdb)
);
assert_eq!(config.backend, DatabaseBackend::Mdbx);
}
#[test]
#[cfg(all(feature = "mdbx", feature = "lmdb"))]
fn no_override_with_existing_mdbx_db() {
let tempdir = tempdir().unwrap();
let mut config = Config::new(tempdir.path().into());
config.backend = DatabaseBackend::Mdbx;
File::create(config.database_path.join(MDBX_DATA_FILENAME)).unwrap();
assert_eq!(config.override_backend(), DatabaseBackendOverride::Noop);
assert_eq!(config.backend, DatabaseBackend::Mdbx);
}
#[test]
#[cfg(all(not(feature = "mdbx"), feature = "lmdb"))]
fn failed_override_with_existing_mdbx_db() {
let tempdir = tempdir().unwrap();
let mut config = Config::new(tempdir.path().into());
let filename = config.database_path.join(MDBX_DATA_FILENAME);
File::create(&filename).unwrap();
assert_eq!(
config.override_backend(),
DatabaseBackendOverride::Failure(filename)
);
assert_eq!(config.backend, DatabaseBackend::Lmdb);
}