zakura_network/zakura/header_sync/
config.rs1use super::{error::*, validation::*, wire::*, *};
2use crate::zakura::ServicePeerLimits;
3
4#[derive(Copy, Clone, Debug, Eq, PartialEq)]
6pub struct HeaderSyncStatus {
7 pub tip_height: block::Height,
9 pub tip_hash: block::Hash,
11 pub anchor_height: block::Height,
13 pub max_headers_per_response: u32,
15 pub max_inflight_requests: u16,
17}
18
19impl HeaderSyncStatus {
20 pub(super) fn encode_to<W: Write>(&self, writer: &mut W) -> Result<(), HeaderSyncWireError> {
21 write_height(writer, self.tip_height)?;
22 self.tip_hash.zcash_serialize(&mut *writer)?;
23 write_height(writer, self.anchor_height)?;
24 writer.write_u32::<LittleEndian>(clamp_advertised_range(self.max_headers_per_response))?;
25 writer.write_u16::<LittleEndian>(self.max_inflight_requests)?;
26 Ok(())
27 }
28
29 pub(super) fn decode_from<R: Read>(reader: &mut R) -> Result<Self, HeaderSyncWireError> {
30 Ok(Self {
31 tip_height: read_height(reader)?,
32 tip_hash: block::Hash::zcash_deserialize(&mut *reader)?,
33 anchor_height: read_height(reader)?,
34 max_headers_per_response: clamp_advertised_range(reader.read_u32::<LittleEndian>()?),
35 max_inflight_requests: reader.read_u16::<LittleEndian>()?,
36 })
37 }
38}
39
40impl Default for HeaderSyncStatus {
41 fn default() -> Self {
42 Self {
43 tip_height: block::Height::MIN,
44 tip_hash: block::Hash([0; 32]),
45 anchor_height: block::Height::MIN,
46 max_headers_per_response: DEFAULT_HS_RANGE,
47 max_inflight_requests: DEFAULT_HS_MAX_INFLIGHT,
48 }
49 }
50}
51
52#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
54#[serde(deny_unknown_fields, default)]
55pub struct ZakuraHeaderSyncConfig {
56 pub max_headers_per_response: u32,
58 pub max_inflight_requests: u16,
64 #[serde(with = "humantime_serde")]
66 pub status_refresh_interval: Duration,
67 pub peer_limits: ServicePeerLimits,
69 pub accept_new_blocks: bool,
74 pub anchor_height: Option<block::Height>,
79 pub anchor_hash: Option<block::Hash>,
84}
85
86impl Default for ZakuraHeaderSyncConfig {
87 fn default() -> Self {
88 Self {
89 max_headers_per_response: DEFAULT_HS_RANGE,
90 max_inflight_requests: DEFAULT_HS_MAX_INFLIGHT,
91 status_refresh_interval: DEFAULT_HS_STATUS_REFRESH_INTERVAL,
92 peer_limits: ServicePeerLimits::default(),
93 accept_new_blocks: true,
94 anchor_height: None,
95 anchor_hash: None,
96 }
97 }
98}
99
100impl ZakuraHeaderSyncConfig {
101 pub fn advertised_max_headers_per_response(&self) -> u32 {
103 clamp_advertised_range(self.max_headers_per_response)
104 }
105
106 pub fn advertised_max_inflight_requests(&self) -> u16 {
108 self.max_inflight_requests
109 .clamp(1, LOCAL_MAX_HS_INFLIGHT_PER_PEER)
110 }
111
112 pub fn anchor(
114 &self,
115 network: &Network,
116 ) -> Result<(block::Height, block::Hash), HeaderSyncStartError> {
117 match (self.anchor_height, self.anchor_hash) {
118 (Some(height), Some(hash)) => Ok((height, hash)),
119 (None, None) => Ok((block::Height(0), network.genesis_hash())),
120 _ => Err(HeaderSyncStartError::IncompleteAnchor),
121 }
122 }
123}
124
125pub fn header_sync_header_bytes_for_network(network: &Network) -> usize {
127 if network
128 .parameters()
129 .is_some_and(|parameters| parameters.is_regtest())
130 {
131 REGTEST_HEADER_BYTES
132 } else {
133 COMMON_HEADER_BYTES
134 }
135}
136
137pub fn header_sync_count_by_byte_budget(
141 network: &Network,
142 max_frame_bytes: u32,
143 want_tree_aux_roots: bool,
144) -> u32 {
145 let frame_payload_cap = usize::try_from(max_frame_bytes)
146 .unwrap_or(usize::MAX)
147 .saturating_sub(FRAME_HEADER_BYTES);
148 let payload_cap = MAX_HS_MESSAGE_BYTES.min(frame_payload_cap);
149 let root_bytes = if want_tree_aux_roots {
150 HEADER_SYNC_BLOCK_COMMITMENT_ROOTS_BYTES
151 } else {
152 0
153 };
154 let header_bytes = header_sync_header_bytes_for_network(network)
155 .saturating_add(HEADER_SYNC_BODY_SIZE_BYTES)
156 .saturating_add(root_bytes);
157 let count = payload_cap.saturating_sub(
158 HEADER_SYNC_MESSAGE_TYPE_BYTES
159 + HEADER_SYNC_REQUEST_ID_BYTES
160 + HEADER_SYNC_COUNT_BYTES
161 + HEADER_SYNC_HAS_ROOTS_BYTES,
162 ) / header_bytes;
163
164 u32::try_from(count)
165 .unwrap_or(u32::MAX)
166 .clamp(1, MAX_HS_RANGE)
167}
168
169pub fn clamp_header_sync_request_count(
171 desired_count: u32,
172 peer_max_headers_per_response: u32,
173 network: &Network,
174 max_frame_bytes: u32,
175 want_tree_aux_roots: bool,
176) -> u32 {
177 desired_count
178 .min(clamp_advertised_range(peer_max_headers_per_response))
179 .min(MAX_HS_RANGE)
180 .min(header_sync_count_by_byte_budget(
181 network,
182 max_frame_bytes,
183 want_tree_aux_roots,
184 ))
185 .max(1)
186}
187
188pub fn inbound_get_headers_count_limit(
190 config: &ZakuraHeaderSyncConfig,
191 network: &Network,
192 max_frame_bytes: u32,
193 want_tree_aux_roots: bool,
194) -> u32 {
195 clamp_header_sync_request_count(
196 u32::MAX,
197 config.advertised_max_headers_per_response(),
198 network,
199 max_frame_bytes,
200 want_tree_aux_roots,
201 )
202}