Skip to content

Commit c297755

Browse files
bart-linerama2bd
andauthored
[Backport] Add a limit for the number of received_log entries in a chain info response (#4643)
## Motivation The huge amount of entries in the `received_log` seems to be making it impossible to sync the old GoL chain on Testnet Conway. ## Proposal Limit the number of returned entries in a single response. Client should request more entries with an increased offset until the number of returned entries is less than the limit (indicating that there are no more entries). ## Test Plan CI; Manual testing on the testnet will show whether this fixes the syncing issue ## Release Plan - These changes should be: - released in a new SDK, - released in a validator hotfix. ## Links - [reviewer checklist](https://github.com/linera-io/linera-protocol/blob/main/CONTRIBUTING.md#reviewer-checklist) --------- Co-authored-by: Mathieu Baudet <1105398+ma2bd@users.noreply.github.com>
1 parent e999a17 commit c297755

File tree

6 files changed

+78
-7
lines changed

6 files changed

+78
-7
lines changed

linera-core/src/chain_worker/config.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ use std::sync::Arc;
77

88
use linera_base::{crypto::ValidatorSecretKey, time::Duration};
99

10+
use crate::CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES;
11+
1012
/// Configuration parameters for the [`ChainWorkerState`][`super::state::ChainWorkerState`].
11-
#[derive(Clone, Default)]
13+
#[derive(Clone)]
1214
pub struct ChainWorkerConfig {
1315
/// The signature key pair of the validator. The key may be missing for replicas
1416
/// without voting rights (possibly with a partial view of chains).
@@ -27,6 +29,8 @@ pub struct ChainWorkerConfig {
2729
/// TTL for sender chains.
2830
// We don't want them to keep in memory forever since usually they're short-lived.
2931
pub sender_chain_ttl: Duration,
32+
/// The size to truncate receive log entries in chain info responses.
33+
pub chain_info_max_received_log_entries: usize,
3034
}
3135

3236
impl ChainWorkerConfig {
@@ -48,3 +52,18 @@ impl ChainWorkerConfig {
4852
self.key_pair.as_ref().map(Arc::as_ref)
4953
}
5054
}
55+
56+
impl Default for ChainWorkerConfig {
57+
fn default() -> Self {
58+
Self {
59+
key_pair: None,
60+
allow_inactive_chains: false,
61+
allow_messages_from_deprecated_epochs: false,
62+
long_lived_services: false,
63+
grace_period: Default::default(),
64+
ttl: Default::default(),
65+
sender_chain_ttl: Default::default(),
66+
chain_info_max_received_log_entries: CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES,
67+
}
68+
}
69+
}

linera-core/src/chain_worker/state.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1407,7 +1407,11 @@ where
14071407
info.requested_sent_certificate_hashes = hashes;
14081408
if let Some(start) = query.request_received_log_excluding_first_n {
14091409
let start = usize::try_from(start).map_err(|_| ArithmeticError::Overflow)?;
1410-
info.requested_received_log = chain.received_log.read(start..).await?;
1410+
let max_received_log_entries = self.config.chain_info_max_received_log_entries;
1411+
let end = start
1412+
.saturating_add(max_received_log_entries)
1413+
.min(chain.received_log.count());
1414+
info.requested_received_log = chain.received_log.read(start..end).await?;
14111415
}
14121416
if query.request_manager_values {
14131417
info.manager.add_values(&chain.manager);

linera-core/src/client/mod.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ use crate::{
7575
remote_node::RemoteNode,
7676
updater::{communicate_with_quorum, CommunicateAction, CommunicationError, ValidatorUpdater},
7777
worker::{Notification, ProcessableCertificate, Reason, WorkerError, WorkerState},
78+
CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES,
7879
};
7980

8081
mod chain_client_state;
@@ -760,9 +761,18 @@ impl<Env: Environment> Client<Env> {
760761
let (max_epoch, committees) = self.admin_committees().await?;
761762

762763
// Retrieve the list of newly received certificates from this validator.
763-
let query = ChainInfoQuery::new(chain_id).with_received_log_excluding_first_n(tracker);
764-
let info = remote_node.handle_chain_info_query(query).await?;
765-
let remote_log = info.requested_received_log;
764+
let mut remote_log = Vec::new();
765+
let mut offset = tracker;
766+
loop {
767+
let query = ChainInfoQuery::new(chain_id).with_received_log_excluding_first_n(offset);
768+
let info = remote_node.handle_chain_info_query(query).await?;
769+
let received_entries = info.requested_received_log.len();
770+
offset += received_entries as u64;
771+
remote_log.extend(info.requested_received_log);
772+
if received_entries < CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES {
773+
break;
774+
}
775+
}
766776
let remote_heights = Self::heights_per_chain(&remote_log);
767777

768778
// Obtain the next block height we need in the local node, for each chain.

linera-core/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ pub use crate::join_set_ext::{JoinSetExt, TaskHandle};
2929

3030
pub mod environment;
3131
pub use environment::Environment;
32+
33+
/// The maximum number of entries in a `received_log` included in a `ChainInfo` response.
34+
// TODO(#4638): Revisit the number.
35+
pub const CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES: usize = 20_000;

linera-core/src/worker.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use crate::{
4343
join_set_ext::{JoinSet, JoinSetExt},
4444
notifier::Notifier,
4545
value_cache::ValueCache,
46+
CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES,
4647
};
4748

4849
const BLOCK_CACHE_SIZE: usize = 5_000;
@@ -421,6 +422,26 @@ where
421422
self
422423
}
423424

425+
/// Returns an instance with the specified maximum size for received_log entries.
426+
///
427+
/// Sizes below `CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES` should be avoided.
428+
#[instrument(level = "trace", skip(self))]
429+
pub fn with_chain_info_max_received_log_entries(
430+
mut self,
431+
chain_info_max_received_log_entries: usize,
432+
) -> Self {
433+
if chain_info_max_received_log_entries < CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES {
434+
warn!(
435+
"The value set for the maximum size of received_log entries \
436+
may not be compatible with the latest clients: {} instead of {}",
437+
chain_info_max_received_log_entries, CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES
438+
);
439+
}
440+
self.chain_worker_config.chain_info_max_received_log_entries =
441+
chain_info_max_received_log_entries;
442+
self
443+
}
444+
424445
#[instrument(level = "trace", skip(self))]
425446
pub fn nickname(&self) -> &str {
426447
&self.nickname

linera-service/src/server.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use linera_base::{
3737
listen_for_shutdown_signals,
3838
};
3939
use linera_client::config::{CommitteeConfig, ValidatorConfig, ValidatorServerConfig};
40-
use linera_core::{worker::WorkerState, JoinSetExt as _};
40+
use linera_core::{worker::WorkerState, JoinSetExt as _, CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES};
4141
use linera_execution::{WasmRuntime, WithWasmDefault};
4242
#[cfg(with_metrics)]
4343
use linera_metrics::monitoring_server;
@@ -68,6 +68,7 @@ struct ServerContext {
6868
shard: Option<usize>,
6969
grace_period: Duration,
7070
chain_worker_ttl: Duration,
71+
chain_info_max_received_log_entries: usize,
7172
}
7273

7374
impl ServerContext {
@@ -94,7 +95,8 @@ impl ServerContext {
9495
.with_allow_inactive_chains(false)
9596
.with_allow_messages_from_deprecated_epochs(false)
9697
.with_grace_period(self.grace_period)
97-
.with_chain_worker_ttl(self.chain_worker_ttl);
98+
.with_chain_worker_ttl(self.chain_worker_ttl)
99+
.with_chain_info_max_received_log_entries(self.chain_info_max_received_log_entries);
98100
(state, shard_id, shard.clone())
99101
}
100102

@@ -380,6 +382,15 @@ enum ServerCommand {
380382
value_parser = util::parse_millis
381383
)]
382384
chain_worker_ttl: Duration,
385+
386+
/// Maximum size for received_log entries in chain info responses. This should
387+
/// generally only be increased from the default value.
388+
#[arg(
389+
long,
390+
default_value_t = CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES,
391+
env = "LINERA_SERVER_CHAIN_INFO_MAX_RECEIVED_LOG_ENTRIES",
392+
)]
393+
chain_info_max_received_log_entries: usize,
383394
},
384395

385396
/// Act as a trusted third-party and generate all server configurations
@@ -492,6 +503,7 @@ async fn run(options: ServerOptions) {
492503
grace_period,
493504
wasm_runtime,
494505
chain_worker_ttl,
506+
chain_info_max_received_log_entries,
495507
} => {
496508
linera_version::VERSION_INFO.log();
497509

@@ -505,6 +517,7 @@ async fn run(options: ServerOptions) {
505517
shard,
506518
grace_period,
507519
chain_worker_ttl,
520+
chain_info_max_received_log_entries,
508521
};
509522
let wasm_runtime = wasm_runtime.with_wasm_default();
510523
let store_config = storage_config

0 commit comments

Comments
 (0)