Skip to content

Commit 7b8aeb1

Browse files
committed
Reduce notification size if too large
1 parent eca57b4 commit 7b8aeb1

File tree

2 files changed

+73
-6
lines changed

2 files changed

+73
-6
lines changed

substrate/client/network/statement/src/config.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub(crate) const PROPAGATE_TIMEOUT: time::Duration = time::Duration::from_millis
2727
pub(crate) const MAX_KNOWN_STATEMENTS: usize = 4 * 1024 * 1024;
2828

2929
/// Maximum allowed size for a statement notification.
30-
pub(crate) const MAX_STATEMENT_SIZE: u64 = 256 * 1024;
30+
pub(crate) const MAX_STATEMENT_NOTIFICATION_SIZE: u64 = 256 * 1024;
3131

3232
/// Maximum number of statement validation request we keep at any moment.
3333
pub(crate) const MAX_PENDING_STATEMENTS: usize = 2 * 1024 * 1024;

substrate/client/network/statement/src/lib.rs

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ use crate::config::*;
3030

3131
use codec::{Decode, Encode};
3232
use futures::{channel::oneshot, prelude::*, stream::FuturesUnordered, FutureExt};
33-
use prometheus_endpoint::{register, Counter, PrometheusError, Registry, U64};
33+
use prometheus_endpoint::{
34+
register, Counter, Histogram, HistogramOpts, PrometheusError, Registry, U64,
35+
};
3436
use sc_network::{
3537
config::{NonReservedPeerMode, SetConfig},
3638
error, multiaddr,
@@ -89,6 +91,8 @@ const LOG_TARGET: &str = "statement-gossip";
8991
struct Metrics {
9092
propagated_statements: Counter<U64>,
9193
known_statements_received: Counter<U64>,
94+
skipped_oversized_statements: Counter<U64>,
95+
propagated_statements_chunks: Histogram,
9296
}
9397

9498
impl Metrics {
@@ -108,6 +112,22 @@ impl Metrics {
108112
)?,
109113
r,
110114
)?,
115+
skipped_oversized_statements: register(
116+
Counter::new(
117+
"substrate_sync_skipped_oversized_statements",
118+
"Number of oversized statements that were skipped to be gossiped",
119+
)?,
120+
r,
121+
)?,
122+
propagated_statements_chunks: register(
123+
Histogram::with_opts(
124+
HistogramOpts::new(
125+
"substrate_sync_propagated_statements_chunks",
126+
"Distribution of chunk sizes when propagating statements",
127+
),
128+
)?,
129+
r,
130+
)?,
111131
})
112132
}
113133
}
@@ -139,7 +159,7 @@ impl StatementHandlerPrototype {
139159
let (config, notification_service) = Net::notification_config(
140160
protocol_name.clone().into(),
141161
Vec::new(),
142-
MAX_STATEMENT_SIZE,
162+
MAX_STATEMENT_NOTIFICATION_SIZE,
143163
None,
144164
SetConfig {
145165
in_peers: 0,
@@ -485,9 +505,56 @@ where
485505

486506
propagated_statements += to_send.len();
487507

488-
if !to_send.is_empty() {
489-
log::trace!(target: LOG_TARGET, "Sending {} statements to {}", to_send.len(), who);
490-
self.notification_service.send_sync_notification(who, to_send.encode());
508+
let mut offset = 0;
509+
while offset < to_send.len() {
510+
// Try to send as many statements as possible in one notification
511+
let chunk_size = to_send.len() - offset;
512+
let chunk_end = offset + chunk_size;
513+
let mut current_end = chunk_end;
514+
515+
loop {
516+
let chunk = &to_send[offset..current_end];
517+
let encoded = chunk.encode();
518+
519+
// If chunk fits, send it
520+
if encoded.len() <= MAX_STATEMENT_NOTIFICATION_SIZE as usize {
521+
log::trace!(
522+
target: LOG_TARGET,
523+
"Sending {} statements ({} KB) to {}",
524+
chunk.len(),
525+
encoded.len() / 1024,
526+
who
527+
);
528+
self.notification_service.send_sync_notification(who, encoded);
529+
offset = current_end;
530+
if let Some(ref metrics) = self.metrics {
531+
metrics.propagated_statements_chunks.observe(chunk.len() as f64);
532+
}
533+
break;
534+
}
535+
536+
// Size exceeded - split the chunk
537+
let split_factor =
538+
(encoded.len() / MAX_STATEMENT_NOTIFICATION_SIZE as usize) + 1;
539+
let new_chunk_size = (current_end - offset) / split_factor;
540+
541+
// Single statement is too large
542+
if new_chunk_size == 0 {
543+
log::warn!(
544+
target: LOG_TARGET,
545+
"Statement too large ({} KB), skipping",
546+
encoded.len() / 1024
547+
);
548+
if let Some(ref metrics) = self.metrics {
549+
metrics.skipped_oversized_statements.inc();
550+
}
551+
offset = current_end;
552+
break;
553+
}
554+
555+
// Reduce chunk size and try again
556+
current_end = offset + new_chunk_size;
557+
}
491558
}
492559
}
493560

0 commit comments

Comments
 (0)