Skip to main content

bsv_overlay_engine/
sync_load.rs

1//! Per-invocation selection and load accounting for GASP.
2
3use serde::{Deserialize, Serialize};
4
5/// An absent list selects everything; an empty list selects nothing.
6#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(deny_unknown_fields)]
8pub struct SyncFilter {
9    pub topics: Option<Vec<String>>,
10    pub peers: Option<Vec<String>>,
11}
12
13impl SyncFilter {
14    pub fn parse(body: &str) -> Result<Self, serde_json::Error> {
15        if body.trim().is_empty() {
16            Ok(Self::default())
17        } else {
18            serde_json::from_str(body)
19        }
20    }
21
22    pub fn explicit(&self) -> bool {
23        self.topics.is_some() || self.peers.is_some()
24    }
25}
26
27/// Three empty answers tolerate short propagation gaps. Thereafter probe at
28/// 60, 120, 240, 480, 960, 1,920 and 3,600 seconds, independent of tick rate.
29pub const QUIET_SYNCS_BEFORE_BACKOFF: u32 = 3;
30pub const QUIET_RETRY_BASE_SECS: u64 = 60;
31pub const QUIET_RETRY_MAX_SECS: u64 = 3_600;
32
33pub fn quiet_retry_secs(syncs: u32) -> u64 {
34    if syncs < QUIET_SYNCS_BEFORE_BACKOFF {
35        0
36    } else {
37        (QUIET_RETRY_BASE_SECS << (syncs - QUIET_SYNCS_BEFORE_BACKOFF).min(6))
38            .min(QUIET_RETRY_MAX_SECS)
39    }
40}
41
42/// Storage owns the clock; retry_after_secs is relative both on read and write.
43#[derive(Debug, Clone, Default, PartialEq, Eq)]
44pub struct PeerCadence {
45    pub quiet_syncs: u32,
46    pub retry_after_secs: u64,
47    pub advertisement: String,
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct SkippedPeer {
52    pub peer: String,
53    pub reason: String,
54    pub retry_after_secs: u64,
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
58pub struct RootBound {
59    pub peer: String,
60    pub outpoint: String,
61    pub reason: String,
62}