Prevent fd leak in random slasher tests (#6254)

* Prevent fd leak in random slasher tests

* Clippy
This commit is contained in:
Michael Sproul
2024-08-19 19:21:07 +10:00
committed by GitHub
parent 042915859d
commit 6faa9c678e
3 changed files with 121 additions and 18 deletions

View File

@@ -4,8 +4,8 @@ mod mdbx_impl;
mod redb_impl;
use crate::{
metrics, AttesterRecord, AttesterSlashingStatus, CompactAttesterRecord, Config, Error,
ProposerSlashingStatus,
metrics, AttesterRecord, AttesterSlashingStatus, CompactAttesterRecord, Config, Database,
Error, ProposerSlashingStatus,
};
use byteorder::{BigEndian, ByteOrder};
use interface::{Environment, OpenDatabases, RwTransaction};
@@ -350,6 +350,18 @@ impl<E: EthSpec> SlasherDB<E> {
Ok(())
}
pub fn get_config(&self) -> &Config {
&self.config
}
/// TESTING ONLY.
///
/// Replace the config for this database. This is only a sane thing to do if the database
/// is empty (has been `reset`).
pub fn update_config(&mut self, config: Arc<Config>) {
self.config = config;
}
/// Load a config from disk.
///
/// This is generic in order to allow loading of configs for different schema versions.
@@ -799,6 +811,50 @@ impl<E: EthSpec> SlasherDB<E> {
Ok(())
}
/// Delete all data from the database, essentially re-initialising it.
///
/// We use this reset pattern in tests instead of leaking tonnes of file descriptors and
/// exhausting our allocation by creating (and leaking) databases.
///
/// THIS FUNCTION SHOULD ONLY BE USED IN TESTS.
pub fn reset(&self) -> Result<(), Error> {
// Clear the cache(s) first.
self.attestation_root_cache.lock().clear();
// Pattern match to avoid missing any database.
let OpenDatabases {
indexed_attestation_db,
indexed_attestation_id_db,
attesters_db,
attesters_max_targets_db,
min_targets_db,
max_targets_db,
current_epochs_db,
proposers_db,
metadata_db,
} = &self.databases;
let mut txn = self.begin_rw_txn()?;
self.reset_db(&mut txn, indexed_attestation_db)?;
self.reset_db(&mut txn, indexed_attestation_id_db)?;
self.reset_db(&mut txn, attesters_db)?;
self.reset_db(&mut txn, attesters_max_targets_db)?;
self.reset_db(&mut txn, min_targets_db)?;
self.reset_db(&mut txn, max_targets_db)?;
self.reset_db(&mut txn, current_epochs_db)?;
self.reset_db(&mut txn, proposers_db)?;
self.reset_db(&mut txn, metadata_db)?;
txn.commit()
}
fn reset_db(&self, txn: &mut RwTransaction<'_>, db: &Database<'static>) -> Result<(), Error> {
let mut cursor = txn.cursor(db)?;
if cursor.first_key()?.is_none() {
return Ok(());
}
cursor.delete_while(|_| Ok(true))?;
Ok(())
}
}
#[cfg(test)]

View File

@@ -33,6 +33,19 @@ impl<E: EthSpec> Slasher<E> {
config.validate()?;
let config = Arc::new(config);
let db = SlasherDB::open(config.clone(), spec, log.clone())?;
Self::from_config_and_db(config, db, log)
}
/// TESTING ONLY.
///
/// Initialise a slasher database from an existing `db`. The caller must ensure that the
/// database's config matches the one provided.
pub fn from_config_and_db(
config: Arc<Config>,
db: SlasherDB<E>,
log: Logger,
) -> Result<Self, Error> {
config.validate()?;
let attester_slashings = Mutex::new(HashSet::new());
let proposer_slashings = Mutex::new(HashSet::new());
let attestation_queue = AttestationQueue::default();
@@ -48,6 +61,11 @@ impl<E: EthSpec> Slasher<E> {
})
}
pub fn into_reset_db(self) -> Result<SlasherDB<E>, Error> {
self.db.reset()?;
Ok(self.db)
}
/// Harvest all attester slashings found, removing them from the slasher.
pub fn get_attester_slashings(&self) -> HashSet<AttesterSlashing<E>> {
std::mem::take(&mut self.attester_slashings.lock())