1use bitcoin::BlockHash;
2use bitcoin::hashes::Hash;
3use serde::{Deserialize, Serialize};
4use urma_chain::observation::Chain;
5
6pub const API_VERSION: u32 = 1;
7pub const SCAN_RULES_VERSION: u32 = 1;
8
9#[derive(Clone, Debug, Serialize, Deserialize)]
12#[serde(deny_unknown_fields)]
13pub struct PinReceipt {
14 pub root: bitcoin::Txid,
15 pub pinned: bool,
16}
17
18#[derive(Clone, Debug, Serialize, Deserialize)]
21#[serde(deny_unknown_fields)]
22pub struct PruneReceipt {
23 pub records_removed: u64,
24}
25
26#[derive(Clone, Debug, Serialize, Deserialize)]
32#[serde(deny_unknown_fields)]
33pub struct RecordPackage {
34 pub version: u32,
35 pub chain_genesis: BlockHash,
36 pub block: ChainPoint,
37 pub reveal: urma_chain::inclusion::TransactionProof,
38 pub commit: Vec<u8>,
39}
40
41#[derive(Clone, Debug, Serialize, Deserialize)]
44pub struct RecordReceipt {
45 pub generation: u64,
46 pub block: ChainPoint,
47 pub position: u32,
48 pub txid: bitcoin::Txid,
49 pub wtxid: bitcoin::Wtxid,
50}
51
52#[derive(Clone, Debug, Serialize, Deserialize)]
53pub struct ArchivedRecord {
54 pub receipt: RecordReceipt,
55 pub package: RecordPackage,
56}
57
58#[derive(Clone, Debug, Serialize, Deserialize)]
62pub struct ObjectStatus {
63 pub root: bitcoin::Txid,
64 pub verified_generation: u64,
65 pub payload_bytes: u64,
66 pub members_total: u64,
67 pub members_local: u64,
68 pub members_selected: u64,
70 pub pinned: bool,
71}
72
73impl ObjectStatus {
74 pub fn locally_complete(&self) -> bool {
75 self.members_total > 0 && self.members_local == self.members_total
76 }
77
78 pub fn selected_complete(&self) -> bool {
79 self.locally_complete() && self.members_selected == self.members_total
80 }
81}
82
83#[derive(Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize)]
84pub struct ChainPoint {
85 pub height: u64,
86 pub hash: BlockHash,
87}
88
89#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
90#[serde(rename_all = "kebab-case")]
91pub enum Retention {
92 Pruned,
93 #[default]
94 Unpruned,
95}
96
97#[derive(Clone, Debug, Serialize, Deserialize)]
100#[serde(deny_unknown_fields)]
101pub struct ArchiveConfig {
102 pub chain: Chain,
103 pub application_start: ChainPoint,
104 pub retention: Retention,
105}
106
107#[derive(Clone, Debug, Serialize, Deserialize)]
110#[non_exhaustive]
111pub struct ArchiveStatus {
112 pub api_version: u32,
113 pub chain_genesis: BlockHash,
114 pub application_start: ChainPoint,
115 pub retention: Retention,
116 pub generation: u64,
117 pub selected_tip: Option<ChainPoint>,
118 pub indexed_through: Option<ChainPoint>,
121 pub scanned_blocks: u64,
122 pub unresolved_dependencies: u64,
123 pub stored_transactions: u64,
124 pub scan_rules_version: u32,
125 pub peer_synced_through: Option<ChainPoint>,
127 pub peer_omissions: u64,
129 pub unaudited_records: u64,
131}
132
133impl Default for ArchiveStatus {
134 fn default() -> Self {
135 let zero = BlockHash::all_zeros();
136 Self {
137 api_version: API_VERSION,
138 chain_genesis: zero,
139 application_start: ChainPoint {
140 height: 0,
141 hash: zero,
142 },
143 retention: Retention::default(),
144 generation: 0,
145 selected_tip: None,
146 indexed_through: None,
147 scanned_blocks: 0,
148 unresolved_dependencies: 0,
149 stored_transactions: 0,
150 scan_rules_version: SCAN_RULES_VERSION,
151 peer_synced_through: None,
152 peer_omissions: 0,
153 unaudited_records: 0,
154 }
155 }
156}
157
158#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
162#[non_exhaustive]
163pub struct CacheReceipt {
164 pub enabled: bool,
165 pub limit_bytes: u64,
166 pub before_bytes: u64,
167 pub remaining_bytes: u64,
168 pub removed_records: u64,
169 pub removed_transactions: u64,
170 pub over_budget: bool,
171}
172
173#[derive(Clone, Debug, Default, Serialize, Deserialize)]
176#[non_exhaustive]
177pub struct ServiceStatus {
178 pub archive: ArchiveStatus,
179 pub last_sync_error: Option<String>,
180 pub last_sync_error_at: Option<u64>,
181 pub last_retention_error: Option<String>,
182 pub last_retention_error_at: Option<u64>,
183 pub last_names_error: Option<String>,
184 pub last_names_error_at: Option<u64>,
185 pub last_dependency_error: Option<String>,
186 pub last_dependency_error_at: Option<u64>,
187 pub last_inventory_error: Option<String>,
188 pub last_inventory_error_at: Option<u64>,
189 pub last_discovery_error: Option<String>,
190 pub last_discovery_error_at: Option<u64>,
191 pub commit_sources: Vec<CommitSourceStatus>,
192 pub cache_limit_bytes: u64,
193 pub last_cache_error: Option<String>,
194 pub last_cache_error_at: Option<u64>,
195 pub last_cache_maintenance: Option<CacheReceipt>,
196 pub overlay: Option<OverlayStatus>,
197 #[serde(default)]
199 pub chain_peers: u64,
200 #[serde(default)]
204 pub chain_target: Option<u64>,
205 pub retention_configured: bool,
206 pub record_sources_configured: u64,
207 pub capabilities: Vec<String>,
208}
209
210#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
211#[non_exhaustive]
212pub struct CommitSourceStatus {
213 pub label: String,
214 pub last_error: Option<String>,
215 pub last_error_at: Option<u64>,
216}
217
218#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
220#[non_exhaustive]
221pub struct OverlayStatus {
222 pub peer_id: String,
223 #[serde(default)]
224 pub listen: Vec<String>,
225 #[serde(default)]
226 pub announce: Vec<String>,
227 pub peer_book: u64,
228 pub connected: u64,
229 pub admitted: u64,
230 pub rejected: u64,
231 pub peers: Vec<OverlayPeerStatus>,
232 pub discovery: Option<DiscoveryStatus>,
233}
234
235#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
239#[non_exhaustive]
240pub struct DiscoveryStatus {
241 pub seeds: u64,
242 pub book: u64,
243 pub reached: u64,
244 pub reached_ever: u64,
245 pub gossip: u64,
246 pub last_seed_round_error: Option<String>,
247 pub last_seed_round_error_at: Option<u64>,
248 pub last_gossip_error: Option<String>,
249 pub last_gossip_error_at: Option<u64>,
250}
251
252#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
254pub struct Omission {
255 pub peer: String,
256 pub block: ChainPoint,
257 pub position: u32,
258 pub txid: bitcoin::Txid,
259 pub generation: u64,
260}
261
262#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
265#[serde(rename_all = "snake_case")]
266pub enum BookOrigin {
267 Gossip,
268 Seed,
269 Manual,
270}
271
272#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
276pub struct BookEntry {
277 pub peer_id: Option<String>,
278 pub addrs: Vec<String>,
279 pub origin: BookOrigin,
280 pub last_success: Option<u64>,
281 pub failures: u32,
282 pub banned_until: Option<u64>,
283}
284
285#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
286#[non_exhaustive]
287pub struct OverlayPeerStatus {
288 pub label: String,
289 pub cursor: u64,
290 pub synced_through: Option<u64>,
291 pub last_error: Option<String>,
292 pub last_error_at: Option<u64>,
293 pub backoff_until: Option<u64>,
295 pub last_progress_at: Option<u64>,
297}
298
299#[cfg(test)]
300#[path = "model_tests.rs"]
301mod model_tests;