Expose functions to do preliminary slashing checks (#7783)

Co-Authored-By: Daniel Knopik <daniel@dknopik.de>

Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
Daniel Knopik
2025-09-11 08:11:58 +02:00
committed by GitHub
parent a080bb5cee
commit 58156815f1
4 changed files with 85 additions and 1 deletions

1
.gitignore vendored
View File

@@ -9,7 +9,6 @@ perf.data*
*.tar.gz *.tar.gz
/bin /bin
genesis.ssz genesis.ssz
/clippy.toml
/.cargo /.cargo
# IntelliJ # IntelliJ

View File

@@ -249,6 +249,7 @@ lint:
-D clippy::fn_to_numeric_cast_any \ -D clippy::fn_to_numeric_cast_any \
-D clippy::manual_let_else \ -D clippy::manual_let_else \
-D clippy::large_stack_frames \ -D clippy::large_stack_frames \
-D clippy::disallowed_methods \
-D warnings \ -D warnings \
-A clippy::derive_partial_eq_without_eq \ -A clippy::derive_partial_eq_without_eq \
-A clippy::upper-case-acronyms \ -A clippy::upper-case-acronyms \

7
clippy.toml Normal file
View File

@@ -0,0 +1,7 @@
# Disallow preliminary slashing checks,
disallowed-methods = [
{ path = "slashing_protection::slashing_database::SlashingDatabase::preliminary_check_block_proposal", reason = "not safe for slashing checks", replacement = "slashing_protection::slashing_database::SlashingDatabase::check_and_insert_block_proposal" },
{ path = "slashing_protection::slashing_database::SlashingDatabase::preliminary_check_block_signing_root", reason = "not safe for slashing checks", replacement = "slashing_protection::slashing_database::SlashingDatabase::check_and_insert_block_signing_root" },
{ path = "slashing_protection::slashing_database::SlashingDatabase::preliminary_check_attestation", reason = "not safe for slashing checks", replacement = "slashing_protection::slashing_database::SlashingDatabase::check_and_insert_attestation" },
{ path = "slashing_protection::slashing_database::SlashingDatabase::preliminary_check_attestation_signing_root", reason = "not safe for slashing checks", replacement = "slashing_protection::slashing_database::SlashingDatabase::check_and_insert_attestation_signing_root" },
]

View File

@@ -599,6 +599,40 @@ impl SlashingDatabase {
Ok(safe) Ok(safe)
} }
/// Check whether a block would be safe to sign if we were to sign it now.
///
/// The database is not modified, and therefore multiple threads reading the database might get
/// the same result. Therefore:
///
/// DO NOT USE THIS FUNCTION TO DECIDE IF A BLOCK IS SAFE TO SIGN!
pub fn preliminary_check_block_proposal(
&self,
validator_pubkey: &PublicKeyBytes,
block_header: &BeaconBlockHeader,
domain: Hash256,
) -> Result<Safe, NotSafe> {
#[allow(clippy::disallowed_methods)]
self.preliminary_check_block_signing_root(
validator_pubkey,
block_header.slot,
block_header.signing_root(domain).into(),
)
}
/// As for `preliminary_check_block_proposal` but without requiring the whole `BeaconBlockHeader`.
///
/// DO NOT USE THIS FUNCTION TO DECIDE IF A BLOCK IS SAFE TO SIGN!
pub fn preliminary_check_block_signing_root(
&self,
validator_pubkey: &PublicKeyBytes,
slot: Slot,
signing_root: SigningRoot,
) -> Result<Safe, NotSafe> {
let mut conn = self.conn_pool.get()?;
let txn = conn.transaction_with_behavior(TransactionBehavior::Exclusive)?;
self.check_block_proposal(&txn, validator_pubkey, slot, signing_root)
}
/// Check an attestation for slash safety, and if it is safe, record it in the database. /// Check an attestation for slash safety, and if it is safe, record it in the database.
/// ///
/// The checking and inserting happen atomically and exclusively. We enforce exclusivity /// The checking and inserting happen atomically and exclusively. We enforce exclusivity
@@ -670,6 +704,49 @@ impl SlashingDatabase {
Ok(safe) Ok(safe)
} }
/// Check whether an attestation would be safe to sign if we were to sign it now.
///
/// The database is not modified, and therefore multiple threads reading the database might get
/// the same result. Therefore:
///
/// DO NOT USE THIS FUNCTION TO DECIDE IF AN ATTESTATION IS SAFE TO SIGN!
pub fn preliminary_check_attestation(
&self,
validator_pubkey: &PublicKeyBytes,
attestation: &AttestationData,
domain: Hash256,
) -> Result<Safe, NotSafe> {
let attestation_signing_root = attestation.signing_root(domain).into();
#[allow(clippy::disallowed_methods)]
self.preliminary_check_attestation_signing_root(
validator_pubkey,
attestation.source.epoch,
attestation.target.epoch,
attestation_signing_root,
)
}
/// As for `preliminary_check_attestation` but without requiring the whole `AttestationData`.
///
/// DO NOT USE THIS FUNCTION TO DECIDE IF AN ATTESTATION IS SAFE TO SIGN!
pub fn preliminary_check_attestation_signing_root(
&self,
validator_pubkey: &PublicKeyBytes,
att_source_epoch: Epoch,
att_target_epoch: Epoch,
att_signing_root: SigningRoot,
) -> Result<Safe, NotSafe> {
let mut conn = self.conn_pool.get()?;
let txn = conn.transaction_with_behavior(TransactionBehavior::Exclusive)?;
self.check_attestation(
&txn,
validator_pubkey,
att_source_epoch,
att_target_epoch,
att_signing_root,
)
}
/// Import slashing protection from another client in the interchange format. /// Import slashing protection from another client in the interchange format.
/// ///
/// This function will atomically import the entire interchange, failing if *any* /// This function will atomically import the entire interchange, failing if *any*