Skip to content
Open
Show file tree
Hide file tree
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
17 changes: 17 additions & 0 deletions zebra-network/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- The address book updater is now a `Buffer`-wrapped tower service that owns the address book
write path. Candidate selection and cache reads use its single ordered request queue instead
of locking the shared mutex, making pick-and-mark-`AttemptPending` atomic. Hot reads and
`init()` are unchanged, and there is no network-visible behavior change
([#1976](https://github.com/ZcashFoundation/zebra/issues/1976)).
- The manual `min_next_handshake`/`min_next_crawl` rate-limit timers in the candidate set are
replaced by small tower middlewares: outbound connection pacing is only charged when a
candidate is actually yielded, and crawls are still skipped while rate-limited. The intervals
and the existing rate-limit test assertions are unchanged
([#1976](https://github.com/ZcashFoundation/zebra/issues/1976)).
- The internal `CandidateSet` struct is dissolved into the peer crawler: candidate selection and
crawling are now plain cloneable service handles with shared rate limits, removing the async
mutex that used to serialize them
([#1976](https://github.com/ZcashFoundation/zebra/issues/1976)).

## [12.0.0] - 2026-08-10

### Breaking Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
# everyone who runs the test benefits from these saved cases.
cc e27ea62986a1ace4e16dde4b99d8ae8557a6b1e92e3f9a7c6aba0d7b179eb817 # shrinks to peers = [MetaAddr { addr: 0.0.0.0:0, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623572152, calendar: 2021-06-13T08:15:52Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 0.0.0.0:0, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623572152, calendar: 2021-06-13T08:15:52Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 0.0.0.0:1151, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623572152, calendar: 2021-06-13T08:15:52Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 129.65.108.101:9019, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623572152, calendar: 2021-06-13T08:15:52Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 95.68.199.21:46887, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623572152, calendar: 2021-06-13T08:15:52Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 167.206.253.131:43927, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623572152, calendar: 2021-06-13T08:15:52Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 160.138.155.239:63430, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623572152, calendar: 2021-06-13T08:15:52Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: [6a4e:a543:8c93:e074:8a2a:5cc4:96f8:ce95]:51071, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623572152, calendar: 2021-06-13T08:15:52Z }, last_connection_state: NeverAttemptedAlternate }], initial_candidates = 0, extra_candidates = 2
cc 788fe2c47a4af559e9a921764d1ce8fcfd0743361c19e6e7a06adc093bc19078 # shrinks to peers = [MetaAddr { addr: [::e9:8050:dbf7:5665]:27188, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623573029, calendar: 2021-06-13T08:30:29Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 106.27.232.177:51742, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623573029, calendar: 2021-06-13T08:30:29Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 127.0.0.1:30827, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623573029, calendar: 2021-06-13T08:30:29Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 0.0.0.0:21948, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623573029, calendar: 2021-06-13T08:30:29Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 0.0.0.0:38186, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623573029, calendar: 2021-06-13T08:30:29Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: [4db2:96e6:38c5:fd62:e964:9338:4ce8:bfa0]:32686, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623573029, calendar: 2021-06-13T08:30:29Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 0.0.0.0:22952, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623573029, calendar: 2021-06-13T08:30:29Z }, last_connection_state: NeverAttemptedAlternate }, MetaAddr { addr: 114.164.73.233:10203, services: NODE_NETWORK, last_seen: DateTime32 { timestamp: 1623573029, calendar: 2021-06-13T08:30:29Z }, last_connection_state: NeverAttemptedAlternate }], initial_candidates = 3, extra_candidates = 3
cc b0ede440aa0549b3de2694c7e4c66cc61b2035ec4a4a707db9acc34a5482be99 # shrinks to peers = {127.0.0.1: 12457, ::ffff:127.0.0.1: 36973, 16.62.55.176: 2464, ::ffff:43.208.158.66: 38413, 18.125.234.138: 31209, f007:edbb:3024:14e5:d305:5a0e:c970:b82c: 2775, 83.130.58.195: 2456, 117.237.203.222: 55214}, initial_candidates = 3, extra_candidates = 3
30 changes: 25 additions & 5 deletions zebra-network/src/address_book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,25 @@ impl AddressBook {
/// As an exception, this function can ignore all changes for specific
/// [`PeerSocketAddr`]s. Ignored addresses will never be used to connect to
/// peers.
#[allow(clippy::unwrap_in_result)]
pub fn update(&mut self, change: MetaAddrChange) -> Option<MetaAddr> {
let updated = self.update_without_metrics(change);

if updated.is_some() {
self.update_metrics(Instant::now(), Utc::now());
}

updated
}

/// Applies `change`, without refreshing the address metrics.
///
/// # Correctness
///
/// Callers must call [`AddressBook::update_metrics`] once they have finished applying
/// changes, and only once: a refresh walks the address book several times, under the
/// mutex, so refreshing per change makes a batch quadratic.
#[allow(clippy::unwrap_in_result)]
fn update_without_metrics(&mut self, change: MetaAddrChange) -> Option<MetaAddr> {
if self.bans_by_ip.contains_key(&change.addr().ip()) {
// Remote peers control how often this fires, so keep it below `warn` (#11134).
tracing::debug!(
Expand Down Expand Up @@ -554,9 +571,6 @@ impl AddressBook {
}

assert!(self.len() <= self.addr_limit);

std::mem::drop(_guard);
self.update_metrics(instant_now, chrono_now);
}

updated
Expand Down Expand Up @@ -858,8 +872,14 @@ impl Extend<MetaAddrChange> for AddressBook {
where
T: IntoIterator<Item = MetaAddrChange>,
{
let mut any_updated = false;

for change in iter.into_iter() {
self.update(change);
any_updated |= self.update_without_metrics(change).is_some();
}

if any_updated {
self.update_metrics(Instant::now(), Utc::now());
}
}
}
Expand Down
Loading
Loading