1use chrono::prelude::{DateTime, Utc};
18
19use crate::core::core::hash::{Hash, Hashed, ZERO_HASH};
20use crate::core::core::{Block, BlockHeader, HeaderVersion};
21use crate::core::pow::Difficulty;
22use crate::core::ser::{self, PMMRIndexHashable, Readable, Reader, Writeable, Writer};
23use crate::error::{Error, ErrorKind};
24use crate::util::{RwLock, RwLockWriteGuard};
25
26bitflags! {
27pub struct Options: u32 {
29 const NONE = 0b0000_0000;
31 const SKIP_POW = 0b0000_0001;
33 const SYNC = 0b0000_0010;
35 const MINE = 0b0000_0100;
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)]
42pub enum SyncStatus {
43 Initial,
45 NoSync,
47 AwaitingPeers(bool),
50 HeaderSync {
52 sync_head: Tip,
54 highest_height: u64,
56 highest_diff: Difficulty,
58 },
59 TxHashsetDownload(TxHashsetDownloadStats),
61 TxHashsetSetup,
63 TxHashsetKernelsValidation {
65 kernels: u64,
67 kernels_total: u64,
69 },
70 TxHashsetRangeProofsValidation {
72 rproofs: u64,
74 rproofs_total: u64,
76 },
77 TxHashsetSave,
79 TxHashsetDone,
81 BodySync {
83 current_height: u64,
85 highest_height: u64,
87 },
88 Shutdown,
90}
91
92#[derive(Debug, Clone, Copy, Eq, PartialEq, Deserialize, Serialize)]
94pub struct TxHashsetDownloadStats {
95 pub start_time: DateTime<Utc>,
97 pub prev_update_time: DateTime<Utc>,
99 pub update_time: DateTime<Utc>,
101 pub prev_downloaded_size: u64,
103 pub downloaded_size: u64,
105 pub total_size: u64,
107}
108
109impl Default for TxHashsetDownloadStats {
110 fn default() -> Self {
111 TxHashsetDownloadStats {
112 start_time: Utc::now(),
113 update_time: Utc::now(),
114 prev_update_time: Utc::now(),
115 prev_downloaded_size: 0,
116 downloaded_size: 0,
117 total_size: 0,
118 }
119 }
120}
121
122pub struct SyncState {
124 current: RwLock<SyncStatus>,
125 sync_error: RwLock<Option<Error>>,
126}
127
128impl SyncState {
129 pub fn new() -> SyncState {
131 SyncState {
132 current: RwLock::new(SyncStatus::Initial),
133 sync_error: RwLock::new(None),
134 }
135 }
136
137 pub fn reset(&self) {
139 self.clear_sync_error();
140 self.update(SyncStatus::NoSync);
141 }
142
143 pub fn is_syncing(&self) -> bool {
146 *self.current.read() != SyncStatus::NoSync
147 }
148
149 pub fn status(&self) -> SyncStatus {
151 *self.current.read()
152 }
153
154 pub fn update(&self, new_status: SyncStatus) -> bool {
156 let status = self.current.write();
157 self.update_with_guard(new_status, status)
158 }
159
160 fn update_with_guard(
161 &self,
162 new_status: SyncStatus,
163 mut status: RwLockWriteGuard<SyncStatus>,
164 ) -> bool {
165 if *status == new_status {
166 return false;
167 }
168
169 debug!("sync_state: sync_status: {:?} -> {:?}", *status, new_status,);
170 *status = new_status;
171 true
172 }
173
174 pub fn update_if<F>(&self, new_status: SyncStatus, f: F) -> bool
176 where
177 F: Fn(SyncStatus) -> bool,
178 {
179 let status = self.current.write();
180 if f(*status) {
181 self.update_with_guard(new_status, status)
182 } else {
183 false
184 }
185 }
186
187 pub fn update_header_sync(&self, new_sync_head: Tip) {
189 let status: &mut SyncStatus = &mut self.current.write();
190 match status {
191 SyncStatus::HeaderSync { sync_head, .. } => {
192 *sync_head = new_sync_head;
193 }
194 _ => (),
195 }
196 }
197
198 pub fn update_txhashset_download(&self, stats: TxHashsetDownloadStats) {
200 *self.current.write() = SyncStatus::TxHashsetDownload(stats);
201 }
202
203 pub fn set_sync_error(&self, error: Error) {
205 *self.sync_error.write() = Some(error);
206 }
207
208 pub fn sync_error(&self) -> Option<String> {
210 self.sync_error.read().as_ref().map(|e| e.to_string())
211 }
212
213 pub fn clear_sync_error(&self) {
215 *self.sync_error.write() = None;
216 }
217}
218
219impl TxHashsetWriteStatus for SyncState {
220 fn on_setup(&self) {
221 self.update(SyncStatus::TxHashsetSetup);
222 }
223
224 fn on_validation_kernels(&self, kernels: u64, kernels_total: u64) {
225 self.update(SyncStatus::TxHashsetKernelsValidation {
226 kernels,
227 kernels_total,
228 });
229 }
230
231 fn on_validation_rproofs(&self, rproofs: u64, rproofs_total: u64) {
232 self.update(SyncStatus::TxHashsetRangeProofsValidation {
233 rproofs,
234 rproofs_total,
235 });
236 }
237
238 fn on_save(&self) {
239 self.update(SyncStatus::TxHashsetSave);
240 }
241
242 fn on_done(&self) {
243 self.update(SyncStatus::TxHashsetDone);
244 }
245}
246
247#[derive(Debug)]
249pub struct TxHashSetRoots {
250 pub output_roots: OutputRoots,
252 pub rproof_root: Hash,
254 pub kernel_root: Hash,
256}
257
258impl TxHashSetRoots {
259 pub fn output_root(&self, header: &BlockHeader) -> Hash {
263 self.output_roots.root(header)
264 }
265
266 pub fn validate(&self, header: &BlockHeader) -> Result<(), Error> {
268 debug!(
269 "validate roots: {} at {}, {} vs. {} (original: {}, merged: {})",
270 header.hash(),
271 header.height,
272 header.output_root,
273 self.output_root(header),
274 self.output_roots.pmmr_root,
275 self.output_roots.merged_root(header),
276 );
277
278 if header.output_root != self.output_root(header)
279 || header.range_proof_root != self.rproof_root
280 || header.kernel_root != self.kernel_root
281 {
282 Err(ErrorKind::InvalidRoot.into())
283 } else {
284 Ok(())
285 }
286 }
287}
288
289#[derive(Debug)]
291pub struct OutputRoots {
292 pub pmmr_root: Hash,
294 pub bitmap_root: Hash,
296}
297
298impl OutputRoots {
299 pub fn root(&self, header: &BlockHeader) -> Hash {
304 if header.version < HeaderVersion(3) {
305 self.output_root()
306 } else {
307 self.merged_root(header)
308 }
309 }
310
311 fn output_root(&self) -> Hash {
313 self.pmmr_root
314 }
315
316 fn merged_root(&self, header: &BlockHeader) -> Hash {
320 (self.pmmr_root, self.bitmap_root).hash_with_index(header.output_mmr_size)
321 }
322}
323
324#[derive(Clone, Copy, Debug, PartialEq)]
326pub struct CommitPos {
327 pub pos: u64,
329 pub height: u64,
331}
332
333impl Readable for CommitPos {
334 fn read<R: Reader>(reader: &mut R) -> Result<CommitPos, ser::Error> {
335 let pos = reader.read_u64()?;
336 let height = reader.read_u64()?;
337 Ok(CommitPos { pos, height })
338 }
339}
340
341impl Writeable for CommitPos {
342 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
343 writer.write_u64(self.pos)?;
344 writer.write_u64(self.height)?;
345 Ok(())
346 }
347}
348
349#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
354pub struct Tip {
355 pub height: u64,
357 pub last_block_h: Hash,
359 pub prev_block_h: Hash,
361 pub total_difficulty: Difficulty,
363}
364
365impl Tip {
366 pub fn from_header(header: &BlockHeader) -> Tip {
368 header.into()
369 }
370}
371
372impl From<BlockHeader> for Tip {
373 fn from(header: BlockHeader) -> Self {
374 Self::from(&header)
375 }
376}
377
378impl From<&BlockHeader> for Tip {
379 fn from(header: &BlockHeader) -> Self {
380 Tip {
381 height: header.height,
382 last_block_h: header.hash(),
383 prev_block_h: header.prev_hash,
384 total_difficulty: header.total_difficulty(),
385 }
386 }
387}
388
389impl Hashed for Tip {
390 fn hash(&self) -> Hash {
392 self.last_block_h
393 }
394}
395
396impl Default for Tip {
397 fn default() -> Self {
398 Tip {
399 height: 0,
400 last_block_h: ZERO_HASH,
401 prev_block_h: ZERO_HASH,
402 total_difficulty: Difficulty::min_dma(),
403 }
404 }
405}
406
407impl ser::Writeable for Tip {
409 fn write<W: ser::Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
410 writer.write_u64(self.height)?;
411 writer.write_fixed_bytes(&self.last_block_h)?;
412 writer.write_fixed_bytes(&self.prev_block_h)?;
413 self.total_difficulty.write(writer)
414 }
415}
416
417impl ser::Readable for Tip {
418 fn read<R: ser::Reader>(reader: &mut R) -> Result<Tip, ser::Error> {
419 let height = reader.read_u64()?;
420 let last = Hash::read(reader)?;
421 let prev = Hash::read(reader)?;
422 let diff = Difficulty::read(reader)?;
423 Ok(Tip {
424 height: height,
425 last_block_h: last,
426 prev_block_h: prev,
427 total_difficulty: diff,
428 })
429 }
430}
431
432pub trait ChainAdapter {
436 fn block_accepted(&self, block: &Block, status: BlockStatus, opts: Options);
439}
440
441pub trait TxHashsetWriteStatus {
447 fn on_setup(&self);
449 fn on_validation_kernels(&self, kernels: u64, kernel_total: u64);
451 fn on_validation_rproofs(&self, rproofs: u64, rproof_total: u64);
453 fn on_save(&self);
455 fn on_done(&self);
457}
458
459pub struct NoStatus;
461
462impl TxHashsetWriteStatus for NoStatus {
463 fn on_setup(&self) {}
464 fn on_validation_kernels(&self, _ks: u64, _kts: u64) {}
465 fn on_validation_rproofs(&self, _rs: u64, _rt: u64) {}
466 fn on_save(&self) {}
467 fn on_done(&self) {}
468}
469
470pub struct NoopAdapter {}
472
473impl ChainAdapter for NoopAdapter {
474 fn block_accepted(&self, _b: &Block, _status: BlockStatus, _opts: Options) {}
475}
476
477#[derive(Debug, Clone, Copy, PartialEq)]
479pub enum BlockStatus {
480 Next {
482 prev: Tip,
484 },
485 Fork {
487 prev: Tip,
489 head: Tip,
491 fork_point: Tip,
493 },
494 Reorg {
497 prev: Tip,
499 prev_head: Tip,
501 fork_point: Tip,
503 },
504}
505
506impl BlockStatus {
507 pub fn is_next(&self) -> bool {
509 match *self {
510 BlockStatus::Next { .. } => true,
511 _ => false,
512 }
513 }
514
515 pub fn is_reorg(&self) -> bool {
517 match *self {
518 BlockStatus::Reorg { .. } => true,
519 _ => false,
520 }
521 }
522}