Skip to content

Commit 5a993a0

Browse files
afckclaude
andcommitted
Use exhaustive match in is_expected() and extract warn_if_unexpected()
Make NodeError::is_expected() use a match without catch-all so the compiler forces a decision when new variants are added. Extract the duplicated WARN logging into ValidatorUpdater::warn_if_unexpected(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 35a8bd6 commit 5a993a0

File tree

2 files changed

+52
-40
lines changed

2 files changed

+52
-40
lines changed

linera-core/src/node.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -348,17 +348,44 @@ impl NodeError {
348348
/// Unexpected errors indicate genuine network issues, validator misbehavior, or
349349
/// internal problems.
350350
pub fn is_expected(&self) -> bool {
351-
matches!(
352-
self,
351+
match self {
352+
// Expected: validators return these during normal operation and the client
353+
// handles them automatically by supplying missing data and retrying.
353354
NodeError::BlobsNotFound(_)
354-
| NodeError::EventsNotFound(_)
355-
| NodeError::MissingCrossChainUpdate { .. }
356-
| NodeError::WrongRound(_)
357-
| NodeError::UnexpectedBlockHeight { .. }
358-
| NodeError::InactiveChain(_)
359-
| NodeError::InvalidTimestamp { .. }
360-
| NodeError::MissingCertificateValue
361-
)
355+
| NodeError::EventsNotFound(_)
356+
| NodeError::MissingCrossChainUpdate { .. }
357+
| NodeError::WrongRound(_)
358+
| NodeError::UnexpectedBlockHeight { .. }
359+
| NodeError::InactiveChain(_)
360+
| NodeError::InvalidTimestamp { .. }
361+
| NodeError::MissingCertificateValue => true,
362+
363+
// Unexpected: network issues, validator misbehavior, or internal problems.
364+
NodeError::CryptoError { .. }
365+
| NodeError::ArithmeticError { .. }
366+
| NodeError::ViewError { .. }
367+
| NodeError::ChainError { .. }
368+
| NodeError::WorkerError { .. }
369+
| NodeError::MissingCertificates(_)
370+
| NodeError::MissingVoteInValidatorResponse(_)
371+
| NodeError::InvalidChainInfoResponse
372+
| NodeError::UnexpectedCertificateValue
373+
| NodeError::InvalidDecoding
374+
| NodeError::UnexpectedMessage
375+
| NodeError::GrpcError { .. }
376+
| NodeError::ClientIoError { .. }
377+
| NodeError::CannotResolveValidatorAddress { .. }
378+
| NodeError::SubscriptionError { .. }
379+
| NodeError::SubscriptionFailed { .. }
380+
| NodeError::InvalidCertificateForBlob(_)
381+
| NodeError::DuplicatesInBlobsNotFound
382+
| NodeError::UnexpectedEntriesInBlobsNotFound
383+
| NodeError::UnexpectedCertificates { .. }
384+
| NodeError::EmptyBlobsNotFound
385+
| NodeError::ResponseHandlingError { .. }
386+
| NodeError::MissingCertificatesByHeights { .. }
387+
| NodeError::TooManyCertificatesReturned { .. } => false,
388+
}
362389
}
363390
}
364391

linera-core/src/updater.rs

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,17 @@ impl<Env> ValidatorUpdater<Env>
236236
where
237237
Env: Environment + 'static,
238238
{
239+
/// Logs a warning if the error is not an expected part of the protocol flow.
240+
fn warn_if_unexpected(&self, err: &NodeError) {
241+
if !err.is_expected() {
242+
tracing::warn!(
243+
remote_node = self.remote_node.address(),
244+
%err,
245+
"unexpected error from validator",
246+
);
247+
}
248+
}
249+
239250
#[instrument(
240251
level = "trace", skip_all, err(level = Level::DEBUG),
241252
fields(chain_id = %certificate.block().header.chain_id)
@@ -282,13 +293,7 @@ where
282293
}
283294
result => {
284295
if let Err(err) = &result {
285-
if !err.is_expected() {
286-
tracing::warn!(
287-
remote_node = self.remote_node.address(),
288-
%err,
289-
"unexpected error from validator",
290-
);
291-
}
296+
self.warn_if_unexpected(err);
292297
}
293298
return Ok(result?);
294299
}
@@ -341,13 +346,7 @@ where
341346
.handle_validated_certificate(certificate)
342347
.await;
343348
if let Err(err) = &result {
344-
if !err.is_expected() {
345-
tracing::warn!(
346-
remote_node = self.remote_node.address(),
347-
%err,
348-
"unexpected error from validator",
349-
);
350-
}
349+
self.warn_if_unexpected(err);
351350
}
352351
Ok(result?)
353352
}
@@ -369,14 +368,7 @@ where
369368
.await;
370369
if let Err(err) = &result {
371370
self.sync_if_needed(chain_id, round, height, err).await?;
372-
if !err.is_expected() {
373-
tracing::warn!(
374-
remote_node = self.remote_node.address(),
375-
%chain_id,
376-
%err,
377-
"unexpected error from validator",
378-
);
379-
}
371+
self.warn_if_unexpected(err);
380372
}
381373
Ok(result?)
382374
}
@@ -636,14 +628,7 @@ where
636628
}
637629
// Fail immediately on other errors.
638630
Err(err) => {
639-
if !err.is_expected() {
640-
tracing::warn!(
641-
remote_node = self.remote_node.address(),
642-
%chain_id,
643-
%err,
644-
"unexpected error from validator",
645-
);
646-
}
631+
self.warn_if_unexpected(&err);
647632
return Err(err.into());
648633
}
649634
}

0 commit comments

Comments
 (0)