use std::time::Duration;
use serde::{Deserialize, Serialize};
use zakura_chain::{block, parameters::Network};
use super::{wire::*, HeaderSyncStartError};
use crate::zakura::ServicePeerLimits;
const COMMON_HEADER_BYTES: usize = 1_487;
const REGTEST_HEADER_BYTES: usize = 177;
const LOCAL_MAX_HS_INFLIGHT_PER_PEER: u16 = 1;
const DEFAULT_HS_STATUS_REFRESH_INTERVAL: Duration = Duration::from_secs(30);
const DEFAULT_HS_MAX_UNPRODUCTIVE_REQUESTS: u32 = 3;
const DEFAULT_HS_UNPRODUCTIVE_PEER_COOLDOWN: Duration = Duration::from_secs(60);
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct ZakuraHeaderSyncConfig {
pub max_headers_per_response: u32,
#[serde(with = "humantime_serde")]
pub status_refresh_interval: Duration,
pub peer_limits: ServicePeerLimits,
pub max_unproductive_header_requests: u32,
#[serde(with = "humantime_serde")]
pub unproductive_peer_cooldown: Duration,
pub anchor_height: Option<block::Height>,
pub anchor_hash: Option<block::Hash>,
}
impl Default for ZakuraHeaderSyncConfig {
fn default() -> Self {
Self {
max_headers_per_response: DEFAULT_HS_RANGE,
status_refresh_interval: DEFAULT_HS_STATUS_REFRESH_INTERVAL,
peer_limits: ServicePeerLimits::default(),
max_unproductive_header_requests: DEFAULT_HS_MAX_UNPRODUCTIVE_REQUESTS,
unproductive_peer_cooldown: DEFAULT_HS_UNPRODUCTIVE_PEER_COOLDOWN,
anchor_height: None,
anchor_hash: None,
}
}
}
impl ZakuraHeaderSyncConfig {
pub fn advertised_max_headers_per_response(&self) -> u32 {
self.max_headers_per_response.clamp(1, MAX_HS_RANGE)
}
pub fn advertised_max_inflight_requests(&self) -> u16 {
LOCAL_MAX_HS_INFLIGHT_PER_PEER
}
pub fn effective_status_refresh_interval(&self) -> Duration {
self.status_refresh_interval.max(Duration::from_secs(1))
}
pub fn anchor(
&self,
network: &Network,
) -> Result<(block::Height, block::Hash), HeaderSyncStartError> {
match (self.anchor_height, self.anchor_hash) {
(Some(height), Some(hash)) if network.checkpoint_list().hash(height) == Some(hash) => {
Ok((height, hash))
}
(Some(height), Some(hash)) => Err(HeaderSyncStartError::InvalidAnchor {
anchor: (height, hash),
}),
(None, None) => Ok((block::Height(0), network.genesis_hash())),
_ => Err(HeaderSyncStartError::IncompleteAnchor),
}
}
}
pub fn header_sync_header_bytes_for_network(network: &Network) -> usize {
if network
.parameters()
.is_some_and(|parameters| parameters.is_regtest())
{
REGTEST_HEADER_BYTES
} else {
COMMON_HEADER_BYTES
}
}