Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit fb7494e

Browse files
authored
Merge pull request #132 from WithAutonomi/fix/audit-failure-log-add-first-failed-key
fix(replication): add first_failed_key to audit-failure log
2 parents 30ed8c7 + 90a3c85 commit fb7494e

1 file changed

Lines changed: 57 additions & 2 deletions

File tree

src/replication/mod.rs

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,6 +2538,24 @@ async fn execute_single_fetch(
25382538
// Audit result handler
25392539
// ---------------------------------------------------------------------------
25402540

2541+
/// Format the first confirmed-failed key as a 16-hex-char label.
2542+
///
2543+
/// Pairs with `challenged_peer` to form a stable cross-host correlation
2544+
/// handle in the audit-failure log line, e.g.
2545+
///
2546+
/// ```text
2547+
/// Audit failure for <peer>: …, `first_failed_key=0x18878f1d2d9e0612`
2548+
/// ```
2549+
///
2550+
/// Falls back to `"0x"` when the list is empty so the log line never
2551+
/// contains a misleading default.
2552+
fn first_failed_key_label(confirmed_failed_keys: &[XorName]) -> String {
2553+
confirmed_failed_keys.first().map_or_else(
2554+
|| "0x".to_string(),
2555+
|k| format!("0x{}", hex::encode(&k[..8])),
2556+
)
2557+
}
2558+
25412559
/// Handle audit result: log findings and emit trust events.
25422560
async fn handle_audit_result(
25432561
result: &AuditTickResult,
@@ -2573,8 +2591,9 @@ async fn handle_audit_result(
25732591
..
25742592
} = evidence
25752593
{
2594+
let first_failed_key = first_failed_key_label(confirmed_failed_keys);
25762595
error!(
2577-
"Audit failure for {challenged_peer}: reason={reason:?}, confirmed_failed_keys={}, challenged_keys={}, absent_keys={}, digest_mismatch_keys={}",
2596+
"Audit failure for {challenged_peer}: reason={reason:?}, confirmed_failed_keys={}, challenged_keys={}, absent_keys={}, digest_mismatch_keys={}, first_failed_key={first_failed_key}",
25782597
confirmed_failed_keys.len(),
25792598
summary.challenged_keys,
25802599
summary.absent_keys,
@@ -2650,7 +2669,7 @@ fn audit_failure_clears_bootstrap_claim(reason: &AuditFailureReason) -> bool {
26502669
#[cfg(test)]
26512670
#[allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
26522671
mod tests {
2653-
use super::audit_failure_clears_bootstrap_claim;
2672+
use super::{audit_failure_clears_bootstrap_claim, first_failed_key_label};
26542673
use crate::replication::types::AuditFailureReason;
26552674

26562675
#[test]
@@ -2674,4 +2693,40 @@ mod tests {
26742693
);
26752694
}
26762695
}
2696+
2697+
#[test]
2698+
fn first_failed_key_label_truncates_to_16_hex_chars() {
2699+
// The high-order 8 bytes of the XorName determine the label so an
2700+
// operator can group audit-failures on the same chunk prefix.
2701+
let mut key = [0u8; 32];
2702+
key[0] = 0x18;
2703+
key[7] = 0xff;
2704+
// Low-order bytes (positions 8..32) are deliberately set to 0xAA
2705+
// to verify they are NOT included in the label.
2706+
for byte in &mut key[8..] {
2707+
*byte = 0xAA;
2708+
}
2709+
let label = first_failed_key_label(&[key]);
2710+
// Only the first 8 bytes are encoded, low-order bytes are dropped.
2711+
assert_eq!(label, "0x18000000000000ff");
2712+
assert_eq!(label.len(), "0x".len() + 16);
2713+
}
2714+
2715+
#[test]
2716+
fn first_failed_key_label_falls_back_when_empty() {
2717+
// Should never happen in production (handle_audit_failure rejects
2718+
// empty sets), but the formatter must still produce a valid label
2719+
// so the log line doesn't contain a misleading default.
2720+
assert_eq!(first_failed_key_label(&[]), "0x");
2721+
}
2722+
2723+
#[test]
2724+
fn first_failed_key_label_uses_first_key_only() {
2725+
let first = [0x11u8; 32];
2726+
let second = [0x22u8; 32];
2727+
assert_eq!(
2728+
first_failed_key_label(&[first, second]),
2729+
format!("0x{}", hex::encode(&first[..8]))
2730+
);
2731+
}
26772732
}

0 commit comments

Comments
 (0)