Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions lib/node/net_task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ fn disconnect_tip_(
Ok(())
}

// peer-caused state errors must not be fatal
fn is_fatal_reorg_error(err: &Error) -> bool {
!matches!(err, Error::State(_))
}

/// Re-org to the specified tip, if it is better than the current tip.
/// The new tip block and all ancestor blocks must exist in the node's archive.
/// A result of `Ok(true)` indicates a successful re-org.
Expand Down Expand Up @@ -1022,8 +1027,8 @@ impl NetTask {
}
}
}
MailboxItem::NewTipReady(new_tip, _addr, resp_tx) => {
let reorg_applied = task::block_in_place(|| {
MailboxItem::NewTipReady(new_tip, addr, resp_tx) => {
let reorg_result = task::block_in_place(|| {
reorg_to_tip(
&self.ctxt.env,
&self.ctxt.archive,
Expand All @@ -1033,7 +1038,26 @@ impl NetTask {
&self.ctxt.zmq_pub_handler,
new_tip,
)
})?;
});
let reorg_applied = match reorg_result {
Ok(applied) => applied,
Err(err) if is_fatal_reorg_error(&err) => {
return Err(err);
}
// invalid block: drop the peer, keep running
Err(err) => {
tracing::warn!(
?new_tip,
?addr,
err = format!("{err:#}"),
"rejecting invalid tip from peer"
);
if let Some(addr) = addr {
self.ctxt.net.remove_active_peer(addr);
}
false
}
};
if let Some(resp_tx) = resp_tx {
let () = resp_tx
.send(reorg_applied)
Expand Down Expand Up @@ -1259,3 +1283,20 @@ impl Drop for NetTaskHandle {
}
}
}

#[cfg(test)]
mod tests {
use super::{Error, is_fatal_reorg_error};
use crate::state;

#[test]
fn invalid_peer_block_is_not_fatal() {
let err = Error::State(Box::new(state::Error::NotEnoughValueIn));
assert!(!is_fatal_reorg_error(&err));
}

#[test]
fn infrastructure_error_is_fatal() {
assert!(is_fatal_reorg_error(&Error::PeerInfoRxClosed));
}
}
Loading