Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redb slasher backend impl #4529

Merged
merged 51 commits into from
Jul 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
01c3aea
initial redb impl
eserilev Jul 21, 2023
f1dd16b
redb impl
eserilev Jul 21, 2023
4c01e3e
remove phantom data
eserilev Jul 21, 2023
45a68b3
fixed table definition
eserilev Jul 21, 2023
a9b4702
fighting the borrow checker
eserilev Jul 22, 2023
2a14754
a rough draft that doesnt cause lifetime issues
eserilev Jul 22, 2023
69c07ed
refactoring
eserilev Jul 30, 2023
bb365a7
refactor
eserilev Jul 31, 2023
a660d9a
refactor
eserilev Jul 31, 2023
9af9677
passing unit tests
eserilev Jul 31, 2023
d9b087e
refactor
eserilev Aug 1, 2023
42a0b7f
refactor
eserilev Aug 2, 2023
b9e5ee1
refactor
eserilev Aug 2, 2023
489733b
commit
eserilev Aug 2, 2023
8d803b3
move everything to one database
eserilev Aug 2, 2023
e48ccce
remove panics, ready for a review
eserilev Aug 8, 2023
0cc2a52
merge
eserilev Aug 8, 2023
1301e85
a working redb impl
eserilev Sep 24, 2023
41fe56a
passing a ref of txn to cursor
eserilev Sep 24, 2023
3d4fc01
this tries to create a second write transaction when initializing cur…
eserilev Sep 24, 2023
d0f983c
Use 2 lifetimes and subtyping
michaelsproul Sep 25, 2023
90e6bf3
Move table into cursor
michaelsproul Sep 25, 2023
f115397
Merge remote-tracking branch 'origin/unstable' into redb-slasher-back…
michaelsproul Sep 25, 2023
adfe3b0
changes based on feedback
eserilev Sep 25, 2023
35a1cdc
update lmdb
eserilev Sep 25, 2023
e913f71
fix lifetime issues
eserilev Sep 26, 2023
e0b637d
moving everything from Cursor to Transaction
eserilev Sep 27, 2023
c65b637
update
eserilev Sep 27, 2023
5d5c93e
upgrade to redb 2.0
eserilev Mar 29, 2024
5cfaf70
Merge branch 'unstable' of https://github.com/sigp/lighthouse into re…
eserilev May 27, 2024
c681a1f
bring back cursor
eserilev May 28, 2024
7da06b6
Merge branch 'unstable' of https://github.com/sigp/lighthouse into re…
eserilev May 28, 2024
77332a3
fix delete while
eserilev May 28, 2024
3bcf4f8
linting
eserilev May 28, 2024
b20a0c9
linting
eserilev May 28, 2024
a2b9d15
switch to lmdb
eserilev May 28, 2024
a14847b
update redb to v2.1
eserilev May 29, 2024
ecd90f7
build fixes, remove unwrap or default
eserilev Jun 4, 2024
0165841
another build error
eserilev Jun 4, 2024
e9dea7f
hopefully this is the last build error
eserilev Jun 4, 2024
cb9fabd
fmt
eserilev Jun 4, 2024
d8c234d
cargo.toml
eserilev Jun 4, 2024
474a355
fix mdbx
eserilev Jun 4, 2024
21059de
Merge branch 'unstable' of https://github.com/sigp/lighthouse into re…
eserilev Jun 4, 2024
6b0a81f
Remove a collect
michaelsproul Jun 13, 2024
33c66e1
Merge remote-tracking branch 'origin/unstable' into redb-slasher-back…
michaelsproul Jun 13, 2024
e751933
Merge branch 'redb-slasher-backend-impl' of https://github.com/eseril…
eserilev Jun 24, 2024
df800b0
re-enable test
eserilev Jun 24, 2024
cebc3bf
fix failing slasher test
eserilev Jun 24, 2024
9186d18
Merge remote-tracking branch 'origin/unstable' into redb-slasher-back…
michaelsproul Jul 1, 2024
4c247c3
Rename DB file to `slasher.redb`
michaelsproul Jul 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ PINNED_NIGHTLY ?= nightly
CLIPPY_PINNED_NIGHTLY=nightly-2022-05-19

# List of features to use when cross-compiling. Can be overridden via the environment.
CROSS_FEATURES ?= gnosis,slasher-lmdb,slasher-mdbx,jemalloc
CROSS_FEATURES ?= gnosis,slasher-lmdb,slasher-mdbx,slasher-redb,jemalloc

# Cargo profile for Cross builds. Default is for local builds, CI uses an override.
CROSS_PROFILE ?= release
Expand Down
2 changes: 2 additions & 0 deletions lighthouse/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ gnosis = []
slasher-mdbx = ["slasher/mdbx"]
# Support slasher LMDB backend.
slasher-lmdb = ["slasher/lmdb"]
# Support slasher redb backend.
slasher-redb = ["slasher/redb"]
# Deprecated. This is now enabled by default on non windows targets.
jemalloc = []

Expand Down
2 changes: 2 additions & 0 deletions lighthouse/tests/beacon_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2242,6 +2242,8 @@ fn slasher_broadcast_flag_false() {
assert!(!slasher_config.broadcast);
});
}

#[cfg(all(feature = "lmdb"))]
#[test]
fn slasher_backend_override_to_default() {
// Hard to test this flag because all but one backend is disabled by default and the backend
Expand Down
4 changes: 4 additions & 0 deletions slasher/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ edition = { workspace = true }
default = ["lmdb"]
mdbx = ["dep:mdbx"]
lmdb = ["lmdb-rkv", "lmdb-rkv-sys"]
redb = ["dep:redb"]
portable = ["types/portable"]

[dependencies]
bincode = { workspace = true }
byteorder = { workspace = true }
derivative = { workspace = true }
ethereum_ssz = { workspace = true }
ethereum_ssz_derive = { workspace = true }
flate2 = { version = "1.0.14", features = ["zlib"], default-features = false }
Expand All @@ -36,6 +38,8 @@ mdbx = { package = "libmdbx", git = "https://github.com/sigp/libmdbx-rs", tag =
lmdb-rkv = { git = "https://github.com/sigp/lmdb-rs", rev = "f33845c6469b94265319aac0ed5085597862c27e", optional = true }
lmdb-rkv-sys = { git = "https://github.com/sigp/lmdb-rs", rev = "f33845c6469b94265319aac0ed5085597862c27e", optional = true }

redb = { version = "2.1", optional = true }

[dev-dependencies]
maplit = { workspace = true }
rayon = { workspace = true }
Expand Down
9 changes: 7 additions & 2 deletions slasher/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,19 @@ pub const DEFAULT_MAX_DB_SIZE: usize = 512 * 1024; // 512 GiB
pub const DEFAULT_ATTESTATION_ROOT_CACHE_SIZE: NonZeroUsize = new_non_zero_usize(100_000);
pub const DEFAULT_BROADCAST: bool = false;

#[cfg(all(feature = "mdbx", not(feature = "lmdb")))]
#[cfg(all(feature = "mdbx", not(any(feature = "lmdb", feature = "redb"))))]
pub const DEFAULT_BACKEND: DatabaseBackend = DatabaseBackend::Mdbx;
#[cfg(feature = "lmdb")]
pub const DEFAULT_BACKEND: DatabaseBackend = DatabaseBackend::Lmdb;
#[cfg(not(any(feature = "mdbx", feature = "lmdb")))]
#[cfg(all(feature = "redb", not(any(feature = "mdbx", feature = "lmdb"))))]
pub const DEFAULT_BACKEND: DatabaseBackend = DatabaseBackend::Redb;
#[cfg(not(any(feature = "mdbx", feature = "lmdb", feature = "redb")))]
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";
pub const REDB_DATA_FILENAME: &str = "slasher.redb";

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
Expand Down Expand Up @@ -64,6 +67,8 @@ pub enum DatabaseBackend {
Mdbx,
#[cfg(feature = "lmdb")]
Lmdb,
#[cfg(feature = "redb")]
Redb,
Disabled,
}

Expand Down
59 changes: 22 additions & 37 deletions slasher/src/database.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod interface;
mod lmdb_impl;
mod mdbx_impl;
mod redb_impl;

use crate::{
metrics, AttesterRecord, AttesterSlashingStatus, CompactAttesterRecord, Config, Error,
Expand Down Expand Up @@ -489,8 +490,7 @@ impl<E: EthSpec> SlasherDB<E> {
}

// Store the new indexed attestation at the end of the current table.
let db = &self.databases.indexed_attestation_db;
let mut cursor = txn.cursor(db)?;
let mut cursor = txn.cursor(&self.databases.indexed_attestation_db)?;

let indexed_att_id = match cursor.last_key()? {
// First ID is 1 so that 0 can be used to represent `null` in `CompactAttesterRecord`.
Expand All @@ -504,7 +504,6 @@ impl<E: EthSpec> SlasherDB<E> {

cursor.put(attestation_key.as_ref(), &data)?;
drop(cursor);

// Update the (epoch, hash) to ID mapping.
self.put_indexed_attestation_id(txn, &id_key, attestation_key)?;

Expand Down Expand Up @@ -743,21 +742,17 @@ impl<E: EthSpec> SlasherDB<E> {
return Ok(());
}

loop {
let (key_bytes, _) = cursor.get_current()?.ok_or(Error::MissingProposerKey)?;

let (slot, _) = ProposerKey::parse(key_bytes)?;
let should_delete = |key: &[u8]| -> Result<bool, Error> {
let mut should_delete = false;
let (slot, _) = ProposerKey::parse(Cow::from(key))?;
if slot < min_slot {
cursor.delete_current()?;

// End the loop if there is no next entry.
if cursor.next_key()?.is_none() {
break;
}
} else {
break;
should_delete = true;
}
}

Ok(should_delete)
};

cursor.delete_while(should_delete)?;

Ok(())
}
Expand All @@ -771,37 +766,27 @@ impl<E: EthSpec> SlasherDB<E> {
.saturating_add(1u64)
.saturating_sub(self.config.history_length as u64);

// Collect indexed attestation IDs to delete.
let mut indexed_attestation_ids = vec![];

let mut cursor = txn.cursor(&self.databases.indexed_attestation_id_db)?;

// Position cursor at first key, bailing out if the database is empty.
if cursor.first_key()?.is_none() {
return Ok(());
}

loop {
let (key_bytes, value) = cursor
.get_current()?
.ok_or(Error::MissingIndexedAttestationIdKey)?;

let (target_epoch, _) = IndexedAttestationIdKey::parse(key_bytes)?;

let should_delete = |key: &[u8]| -> Result<bool, Error> {
let (target_epoch, _) = IndexedAttestationIdKey::parse(Cow::from(key))?;
if target_epoch < min_epoch {
indexed_attestation_ids.push(IndexedAttestationId::new(
IndexedAttestationId::parse(value)?,
));
return Ok(true);
}

cursor.delete_current()?;
Ok(false)
};

if cursor.next_key()?.is_none() {
break;
}
} else {
break;
}
}
let indexed_attestation_ids = cursor
.delete_while(should_delete)?
.into_iter()
.map(|id| IndexedAttestationId::parse(id).map(IndexedAttestationId::new))
.collect::<Result<Vec<IndexedAttestationId>, Error>>()?;
drop(cursor);

// Delete the indexed attestations.
Expand Down
Loading
Loading