Skip to content

Commit 7ef9501

Browse files
authored
Instrument attestation signing. (#8508)
We noticed attestation signing taking 2+ seconds on some of our hoodi nodes and the current traces doesn't provide enough details. This PR adds a few more spans to the `attestation_duty_cycle` code path in the VC. Before: <img width="842" height="154" alt="image" src="https://github.com/user-attachments/assets/cfc5c8c0-e6f2-4f56-a8e4-65001af4a005" /> After: <img width="496" height="217" alt="image" src="https://github.com/user-attachments/assets/c91cfa88-af1b-456e-8c64-625809eb6881" /> Co-Authored-By: Jimmy Chen <[email protected]>
1 parent 4fbe517 commit 7ef9501

File tree

6 files changed

+77
-66
lines changed

6 files changed

+77
-66
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

validator_client/lighthouse_validator_store/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use std::marker::PhantomData;
1515
use std::path::Path;
1616
use std::sync::Arc;
1717
use task_executor::TaskExecutor;
18-
use tracing::{error, info, warn};
18+
use tracing::{error, info, instrument, warn};
1919
use types::{
2020
AbstractExecPayload, Address, AggregateAndProof, Attestation, BeaconBlock, BlindedPayload,
2121
ChainSpec, ContributionAndProof, Domain, Epoch, EthSpec, Fork, Graffiti, Hash256,
@@ -242,6 +242,7 @@ impl<T: SlotClock + 'static, E: EthSpec> LighthouseValidatorStore<T, E> {
242242

243243
/// Returns a `SigningMethod` for `validator_pubkey` *only if* that validator is considered safe
244244
/// by doppelganger protection.
245+
#[instrument(skip_all, level = "debug")]
245246
fn doppelganger_checked_signing_method(
246247
&self,
247248
validator_pubkey: PublicKeyBytes,
@@ -745,6 +746,7 @@ impl<T: SlotClock + 'static, E: EthSpec> ValidatorStore for LighthouseValidatorS
745746
}
746747
}
747748

749+
#[instrument(skip_all)]
748750
async fn sign_attestation(
749751
&self,
750752
validator_pubkey: PublicKeyBytes,

validator_client/signing_method/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ parking_lot = { workspace = true }
1212
reqwest = { workspace = true }
1313
serde = { workspace = true }
1414
task_executor = { workspace = true }
15+
tracing = { workspace = true }
1516
types = { workspace = true }
1617
url = { workspace = true }
1718
validator_metrics = { workspace = true }

validator_client/signing_method/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use reqwest::{Client, header::ACCEPT};
1010
use std::path::PathBuf;
1111
use std::sync::Arc;
1212
use task_executor::TaskExecutor;
13+
use tracing::instrument;
1314
use types::*;
1415
use url::Url;
1516
use web3signer::{ForkInfo, MessageType, SigningRequest, SigningResponse};
@@ -131,6 +132,7 @@ impl SigningMethod {
131132
}
132133

133134
/// Return the signature of `signable_message`, with respect to the `signing_context`.
135+
#[instrument(skip_all, level = "debug")]
134136
pub async fn get_signature<E: EthSpec, Payload: AbstractExecPayload<E>>(
135137
&self,
136138
signable_message: SignableMessage<'_, E, Payload>,

validator_client/slashing_protection/src/slashing_database.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rusqlite::{OptionalExtension, Transaction, TransactionBehavior, params};
1111
use std::fs::File;
1212
use std::path::Path;
1313
use std::time::Duration;
14+
use tracing::instrument;
1415
use types::{AttestationData, BeaconBlockHeader, Epoch, Hash256, PublicKeyBytes, SignedRoot, Slot};
1516

1617
type Pool = r2d2::Pool<SqliteConnectionManager>;
@@ -639,6 +640,7 @@ impl SlashingDatabase {
639640
/// to prevent concurrent checks and inserts from resulting in slashable data being inserted.
640641
///
641642
/// This is the safe, externally-callable interface for checking attestations.
643+
#[instrument(skip_all, level = "debug")]
642644
pub fn check_and_insert_attestation(
643645
&self,
644646
validator_pubkey: &PublicKeyBytes,

validator_client/validator_services/src/attestation_service.rs

Lines changed: 68 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::ops::Deref;
88
use std::sync::Arc;
99
use task_executor::TaskExecutor;
1010
use tokio::time::{Duration, Instant, sleep, sleep_until};
11-
use tracing::{Instrument, debug, error, info, info_span, instrument, trace, warn};
11+
use tracing::{Instrument, Span, debug, error, info, info_span, instrument, trace, warn};
1212
use tree_hash::TreeHash;
1313
use types::{Attestation, AttestationData, ChainSpec, CommitteeIndex, EthSpec, Slot};
1414
use validator_store::{Error as ValidatorStoreError, ValidatorStore};
@@ -369,79 +369,82 @@ impl<S: ValidatorStore + 'static, T: SlotClock + 'static> AttestationService<S,
369369

370370
// Create futures to produce signed `Attestation` objects.
371371
let attestation_data_ref = &attestation_data;
372-
let signing_futures = validator_duties.iter().map(|duty_and_proof| async move {
373-
let duty = &duty_and_proof.duty;
374-
let attestation_data = attestation_data_ref;
375-
376-
// Ensure that the attestation matches the duties.
377-
if !duty.match_attestation_data::<S::E>(attestation_data, &self.chain_spec) {
378-
crit!(
379-
validator = ?duty.pubkey,
380-
duty_slot = %duty.slot,
381-
attestation_slot = %attestation_data.slot,
382-
duty_index = duty.committee_index,
383-
attestation_index = attestation_data.index,
384-
"Inconsistent validator duties during signing"
385-
);
386-
return None;
387-
}
372+
let signing_futures = validator_duties.iter().map(|duty_and_proof| {
373+
async move {
374+
let duty = &duty_and_proof.duty;
375+
let attestation_data = attestation_data_ref;
388376

389-
let mut attestation = match Attestation::empty_for_signing(
390-
duty.committee_index,
391-
duty.committee_length as usize,
392-
attestation_data.slot,
393-
attestation_data.beacon_block_root,
394-
attestation_data.source,
395-
attestation_data.target,
396-
&self.chain_spec,
397-
) {
398-
Ok(attestation) => attestation,
399-
Err(err) => {
377+
// Ensure that the attestation matches the duties.
378+
if !duty.match_attestation_data::<S::E>(attestation_data, &self.chain_spec) {
400379
crit!(
401380
validator = ?duty.pubkey,
402-
?duty,
403-
?err,
404-
"Invalid validator duties during signing"
381+
duty_slot = %duty.slot,
382+
attestation_slot = %attestation_data.slot,
383+
duty_index = duty.committee_index,
384+
attestation_index = attestation_data.index,
385+
"Inconsistent validator duties during signing"
405386
);
406387
return None;
407388
}
408-
};
409389

410-
match self
411-
.validator_store
412-
.sign_attestation(
413-
duty.pubkey,
414-
duty.validator_committee_index as usize,
415-
&mut attestation,
416-
current_epoch,
417-
)
418-
.await
419-
{
420-
Ok(()) => Some((attestation, duty.validator_index)),
421-
Err(ValidatorStoreError::UnknownPubkey(pubkey)) => {
422-
// A pubkey can be missing when a validator was recently
423-
// removed via the API.
424-
warn!(
425-
info = "a validator may have recently been removed from this VC",
426-
pubkey = ?pubkey,
427-
validator = ?duty.pubkey,
428-
committee_index = committee_index,
429-
slot = slot.as_u64(),
430-
"Missing pubkey for attestation"
431-
);
432-
None
433-
}
434-
Err(e) => {
435-
crit!(
436-
error = ?e,
437-
validator = ?duty.pubkey,
438-
committee_index,
439-
slot = slot.as_u64(),
440-
"Failed to sign attestation"
441-
);
442-
None
390+
let mut attestation = match Attestation::empty_for_signing(
391+
duty.committee_index,
392+
duty.committee_length as usize,
393+
attestation_data.slot,
394+
attestation_data.beacon_block_root,
395+
attestation_data.source,
396+
attestation_data.target,
397+
&self.chain_spec,
398+
) {
399+
Ok(attestation) => attestation,
400+
Err(err) => {
401+
crit!(
402+
validator = ?duty.pubkey,
403+
?duty,
404+
?err,
405+
"Invalid validator duties during signing"
406+
);
407+
return None;
408+
}
409+
};
410+
411+
match self
412+
.validator_store
413+
.sign_attestation(
414+
duty.pubkey,
415+
duty.validator_committee_index as usize,
416+
&mut attestation,
417+
current_epoch,
418+
)
419+
.await
420+
{
421+
Ok(()) => Some((attestation, duty.validator_index)),
422+
Err(ValidatorStoreError::UnknownPubkey(pubkey)) => {
423+
// A pubkey can be missing when a validator was recently
424+
// removed via the API.
425+
warn!(
426+
info = "a validator may have recently been removed from this VC",
427+
pubkey = ?pubkey,
428+
validator = ?duty.pubkey,
429+
committee_index = committee_index,
430+
slot = slot.as_u64(),
431+
"Missing pubkey for attestation"
432+
);
433+
None
434+
}
435+
Err(e) => {
436+
crit!(
437+
error = ?e,
438+
validator = ?duty.pubkey,
439+
committee_index,
440+
slot = slot.as_u64(),
441+
"Failed to sign attestation"
442+
);
443+
None
444+
}
443445
}
444446
}
447+
.instrument(Span::current())
445448
});
446449

447450
// Execute all the futures in parallel, collecting any successful results.

0 commit comments

Comments
 (0)