diff --git a/Cargo.toml b/Cargo.toml index 48ad3018f4..30d6e7fc3b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,6 +34,7 @@ failure_derive = "0.1" grin_api = { path = "./api", version = "2.0.1-beta.1" } grin_config = { path = "./config", version = "2.0.1-beta.1" } +grin_chain = { path = "./chain", version = "2.0.1-beta.1" } grin_core = { path = "./core", version = "2.0.1-beta.1" } grin_keychain = { path = "./keychain", version = "2.0.1-beta.1" } grin_p2p = { path = "./p2p", version = "2.0.1-beta.1" } diff --git a/chain/src/error.rs b/chain/src/error.rs index 8bf7d47404..502163ffa8 100644 --- a/chain/src/error.rs +++ b/chain/src/error.rs @@ -140,6 +140,9 @@ pub enum ErrorKind { /// Internal Roaring Bitmap error #[fail(display = "Roaring Bitmap error")] Bitmap, + /// Error during chain sync + #[fail(display = "Sync error")] + SyncError(String), } impl Display for Error { diff --git a/chain/src/lib.rs b/chain/src/lib.rs index cf8f8d0778..d38f922fc0 100644 --- a/chain/src/lib.rs +++ b/chain/src/lib.rs @@ -45,4 +45,6 @@ pub mod types; pub use crate::chain::{Chain, MAX_ORPHAN_SIZE}; pub use crate::error::{Error, ErrorKind}; pub use crate::store::ChainStore; -pub use crate::types::{BlockStatus, ChainAdapter, Options, Tip, TxHashsetWriteStatus}; +pub use crate::types::{ + BlockStatus, ChainAdapter, Options, SyncState, SyncStatus, Tip, TxHashsetWriteStatus, +}; diff --git a/chain/src/types.rs b/chain/src/types.rs index b3f7b782bb..6ab6e6dac8 100644 --- a/chain/src/types.rs +++ b/chain/src/types.rs @@ -14,10 +14,15 @@ //! Base types that the block chain pipeline requires. +use chrono::prelude::{DateTime, Utc}; +use std::sync::Arc; + use crate::core::core::hash::{Hash, Hashed, ZERO_HASH}; use crate::core::core::{Block, BlockHeader}; use crate::core::pow::Difficulty; use crate::core::ser; +use crate::error::Error; +use crate::util::RwLock; bitflags! { /// Options for block validation @@ -33,6 +38,171 @@ bitflags! { } } +/// Various status sync can be in, whether it's fast sync or archival. +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[allow(missing_docs)] +pub enum SyncStatus { + /// Initial State (we do not yet know if we are/should be syncing) + Initial, + /// Not syncing + NoSync, + /// Not enough peers to do anything yet, boolean indicates whether + /// we should wait at all or ignore and start ASAP + AwaitingPeers(bool), + /// Downloading block headers + HeaderSync { + current_height: u64, + highest_height: u64, + }, + /// Downloading the various txhashsets + TxHashsetDownload { + start_time: DateTime, + prev_update_time: DateTime, + update_time: DateTime, + prev_downloaded_size: u64, + downloaded_size: u64, + total_size: u64, + }, + /// Setting up before validation + TxHashsetSetup, + /// Validating the full state + TxHashsetValidation { + kernels: u64, + kernel_total: u64, + rproofs: u64, + rproof_total: u64, + }, + /// Finalizing the new state + TxHashsetSave, + /// State sync finalized + TxHashsetDone, + /// Downloading blocks + BodySync { + current_height: u64, + highest_height: u64, + }, + Shutdown, +} + +/// Current sync state. Encapsulates the current SyncStatus. +pub struct SyncState { + current: RwLock, + sync_error: Arc>>, +} + +impl SyncState { + /// Return a new SyncState initialize to NoSync + pub fn new() -> SyncState { + SyncState { + current: RwLock::new(SyncStatus::Initial), + sync_error: Arc::new(RwLock::new(None)), + } + } + + /// Whether the current state matches any active syncing operation. + /// Note: This includes our "initial" state. + pub fn is_syncing(&self) -> bool { + *self.current.read() != SyncStatus::NoSync + } + + /// Current syncing status + pub fn status(&self) -> SyncStatus { + *self.current.read() + } + + /// Update the syncing status + pub fn update(&self, new_status: SyncStatus) { + if self.status() == new_status { + return; + } + + let mut status = self.current.write(); + + debug!("sync_state: sync_status: {:?} -> {:?}", *status, new_status,); + + *status = new_status; + } + + /// Update txhashset downloading progress + pub fn update_txhashset_download(&self, new_status: SyncStatus) -> bool { + if let SyncStatus::TxHashsetDownload { .. } = new_status { + let mut status = self.current.write(); + *status = new_status; + true + } else { + false + } + } + + /// Communicate sync error + pub fn set_sync_error(&self, error: Error) { + *self.sync_error.write() = Some(error); + } + + /// Get sync error + pub fn sync_error(&self) -> Arc>> { + Arc::clone(&self.sync_error) + } + + /// Clear sync error + pub fn clear_sync_error(&self) { + *self.sync_error.write() = None; + } +} + +impl TxHashsetWriteStatus for SyncState { + fn on_setup(&self) { + self.update(SyncStatus::TxHashsetSetup); + } + + fn on_validation(&self, vkernels: u64, vkernel_total: u64, vrproofs: u64, vrproof_total: u64) { + let mut status = self.current.write(); + match *status { + SyncStatus::TxHashsetValidation { + kernels, + kernel_total, + rproofs, + rproof_total, + } => { + let ks = if vkernels > 0 { vkernels } else { kernels }; + let kt = if vkernel_total > 0 { + vkernel_total + } else { + kernel_total + }; + let rps = if vrproofs > 0 { vrproofs } else { rproofs }; + let rpt = if vrproof_total > 0 { + vrproof_total + } else { + rproof_total + }; + *status = SyncStatus::TxHashsetValidation { + kernels: ks, + kernel_total: kt, + rproofs: rps, + rproof_total: rpt, + }; + } + _ => { + *status = SyncStatus::TxHashsetValidation { + kernels: 0, + kernel_total: 0, + rproofs: 0, + rproof_total: 0, + } + } + } + } + + fn on_save(&self) { + self.update(SyncStatus::TxHashsetSave); + } + + fn on_done(&self) { + self.update(SyncStatus::TxHashsetDone); + } +} + /// A helper to hold the roots of the txhashset in order to keep them /// readable. #[derive(Debug)] diff --git a/servers/src/common/adapters.rs b/servers/src/common/adapters.rs index fa9f4f5ffd..3a2c9502f9 100644 --- a/servers/src/common/adapters.rs +++ b/servers/src/common/adapters.rs @@ -23,11 +23,9 @@ use std::sync::{Arc, Weak}; use std::thread; use std::time::Instant; -use crate::chain::{self, BlockStatus, ChainAdapter, Options}; +use crate::chain::{self, BlockStatus, ChainAdapter, Options, SyncState, SyncStatus}; use crate::common::hooks::{ChainEvents, NetEvents}; -use crate::common::types::{ - self, ChainValidationMode, DandelionEpoch, ServerConfig, SyncState, SyncStatus, -}; +use crate::common::types::{ChainValidationMode, DandelionEpoch, ServerConfig}; use crate::core::core::hash::{Hash, Hashed}; use crate::core::core::transaction::Transaction; use crate::core::core::verifier_cache::VerifierCache; @@ -251,7 +249,11 @@ impl p2p::ChainAdapter for NetToChainAdapter { .process_block_header(&bh, self.chain_opts(false)); if let Err(e) = res { - debug!("Block header {} refused by chain: {:?}", bh.hash(), e.kind()); + debug!( + "Block header {} refused by chain: {:?}", + bh.hash(), + e.kind() + ); if e.is_bad_data() { return Ok(false); } else { @@ -428,7 +430,7 @@ impl p2p::ChainAdapter for NetToChainAdapter { error!("Failed to save txhashset archive: {}", e); let is_good_data = !e.is_bad_data(); - self.sync_state.set_sync_error(types::Error::Chain(e)); + self.sync_state.set_sync_error(e); Ok(is_good_data) } else { info!("Received valid txhashset data for {}.", h); diff --git a/servers/src/common/stats.rs b/servers/src/common/stats.rs index 9fd6d62e09..047a8483ed 100644 --- a/servers/src/common/stats.rs +++ b/servers/src/common/stats.rs @@ -26,7 +26,7 @@ use crate::core::ser::ProtocolVersion; use chrono::prelude::*; use crate::chain; -use crate::common::types::SyncStatus; +use crate::chain::SyncStatus; use crate::p2p; /// Server state info collection struct, to be passed around into internals diff --git a/servers/src/common/types.rs b/servers/src/common/types.rs index 3a688ee159..fab6fae339 100644 --- a/servers/src/common/types.rs +++ b/servers/src/common/types.rs @@ -16,7 +16,7 @@ use std::convert::From; use std::sync::Arc; -use chrono::prelude::{DateTime, Utc}; +use chrono::prelude::Utc; use rand::prelude::*; use crate::api; @@ -28,7 +28,6 @@ use crate::p2p; use crate::pool; use crate::pool::types::DandelionConfig; use crate::store; -use crate::util::RwLock; /// Error type wrapping underlying module errors. #[derive(Debug)] @@ -301,171 +300,6 @@ impl Default for WebHooksConfig { } } -/// Various status sync can be in, whether it's fast sync or archival. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -#[allow(missing_docs)] -pub enum SyncStatus { - /// Initial State (we do not yet know if we are/should be syncing) - Initial, - /// Not syncing - NoSync, - /// Not enough peers to do anything yet, boolean indicates whether - /// we should wait at all or ignore and start ASAP - AwaitingPeers(bool), - /// Downloading block headers - HeaderSync { - current_height: u64, - highest_height: u64, - }, - /// Downloading the various txhashsets - TxHashsetDownload { - start_time: DateTime, - prev_update_time: DateTime, - update_time: DateTime, - prev_downloaded_size: u64, - downloaded_size: u64, - total_size: u64, - }, - /// Setting up before validation - TxHashsetSetup, - /// Validating the full state - TxHashsetValidation { - kernels: u64, - kernel_total: u64, - rproofs: u64, - rproof_total: u64, - }, - /// Finalizing the new state - TxHashsetSave, - /// State sync finalized - TxHashsetDone, - /// Downloading blocks - BodySync { - current_height: u64, - highest_height: u64, - }, - Shutdown, -} - -/// Current sync state. Encapsulates the current SyncStatus. -pub struct SyncState { - current: RwLock, - sync_error: Arc>>, -} - -impl SyncState { - /// Return a new SyncState initialize to NoSync - pub fn new() -> SyncState { - SyncState { - current: RwLock::new(SyncStatus::Initial), - sync_error: Arc::new(RwLock::new(None)), - } - } - - /// Whether the current state matches any active syncing operation. - /// Note: This includes our "initial" state. - pub fn is_syncing(&self) -> bool { - *self.current.read() != SyncStatus::NoSync - } - - /// Current syncing status - pub fn status(&self) -> SyncStatus { - *self.current.read() - } - - /// Update the syncing status - pub fn update(&self, new_status: SyncStatus) { - if self.status() == new_status { - return; - } - - let mut status = self.current.write(); - - debug!("sync_state: sync_status: {:?} -> {:?}", *status, new_status,); - - *status = new_status; - } - - /// Update txhashset downloading progress - pub fn update_txhashset_download(&self, new_status: SyncStatus) -> bool { - if let SyncStatus::TxHashsetDownload { .. } = new_status { - let mut status = self.current.write(); - *status = new_status; - true - } else { - false - } - } - - /// Communicate sync error - pub fn set_sync_error(&self, error: Error) { - *self.sync_error.write() = Some(error); - } - - /// Get sync error - pub fn sync_error(&self) -> Arc>> { - Arc::clone(&self.sync_error) - } - - /// Clear sync error - pub fn clear_sync_error(&self) { - *self.sync_error.write() = None; - } -} - -impl chain::TxHashsetWriteStatus for SyncState { - fn on_setup(&self) { - self.update(SyncStatus::TxHashsetSetup); - } - - fn on_validation(&self, vkernels: u64, vkernel_total: u64, vrproofs: u64, vrproof_total: u64) { - let mut status = self.current.write(); - match *status { - SyncStatus::TxHashsetValidation { - kernels, - kernel_total, - rproofs, - rproof_total, - } => { - let ks = if vkernels > 0 { vkernels } else { kernels }; - let kt = if vkernel_total > 0 { - vkernel_total - } else { - kernel_total - }; - let rps = if vrproofs > 0 { vrproofs } else { rproofs }; - let rpt = if vrproof_total > 0 { - vrproof_total - } else { - rproof_total - }; - *status = SyncStatus::TxHashsetValidation { - kernels: ks, - kernel_total: kt, - rproofs: rps, - rproof_total: rpt, - }; - } - _ => { - *status = SyncStatus::TxHashsetValidation { - kernels: 0, - kernel_total: 0, - rproofs: 0, - rproof_total: 0, - } - } - } - } - - fn on_save(&self) { - self.update(SyncStatus::TxHashsetSave); - } - - fn on_done(&self) { - self.update(SyncStatus::TxHashsetDone); - } -} - /// A node is either "stem" of "fluff" for the duration of a single epoch. /// A node also maintains an outbound relay peer for the epoch. #[derive(Debug)] diff --git a/servers/src/grin/server.rs b/servers/src/grin/server.rs index 9eecad746a..ee8cbc54e8 100644 --- a/servers/src/grin/server.rs +++ b/servers/src/grin/server.rs @@ -30,13 +30,13 @@ use fs2::FileExt; use crate::api; use crate::api::TLSConfig; -use crate::chain; +use crate::chain::{self, SyncState, SyncStatus}; use crate::common::adapters::{ ChainToPoolAndNetAdapter, NetToChainAdapter, PoolToChainAdapter, PoolToNetAdapter, }; use crate::common::hooks::{init_chain_hooks, init_net_hooks}; use crate::common::stats::{DiffBlock, DiffStats, PeerStats, ServerStateInfo, ServerStats}; -use crate::common::types::{Error, ServerConfig, StratumServerConfig, SyncState, SyncStatus}; +use crate::common::types::{Error, ServerConfig, StratumServerConfig}; use crate::core::core::hash::{Hashed, ZERO_HASH}; use crate::core::core::verifier_cache::{LruVerifierCache, VerifierCache}; use crate::core::ser::ProtocolVersion; diff --git a/servers/src/grin/sync/body_sync.rs b/servers/src/grin/sync/body_sync.rs index 687258642a..b5d88decac 100644 --- a/servers/src/grin/sync/body_sync.rs +++ b/servers/src/grin/sync/body_sync.rs @@ -17,8 +17,7 @@ use chrono::Duration; use std::cmp; use std::sync::Arc; -use crate::chain; -use crate::common::types::{SyncState, SyncStatus}; +use crate::chain::{self, SyncState, SyncStatus}; use crate::core::core::hash::Hash; use crate::p2p; diff --git a/servers/src/grin/sync/header_sync.rs b/servers/src/grin/sync/header_sync.rs index 040ef4b169..81d0277695 100644 --- a/servers/src/grin/sync/header_sync.rs +++ b/servers/src/grin/sync/header_sync.rs @@ -16,8 +16,8 @@ use chrono::prelude::{DateTime, Utc}; use chrono::Duration; use std::sync::Arc; -use crate::chain; -use crate::common::types::{Error, SyncState, SyncStatus}; +use crate::chain::{self, SyncState, SyncStatus}; +use crate::common::types::Error; use crate::core::core::hash::{Hash, Hashed}; use crate::p2p::{self, types::ReasonForBan, Peer}; diff --git a/servers/src/grin/sync/state_sync.rs b/servers/src/grin/sync/state_sync.rs index 0c06254baf..452a87b515 100644 --- a/servers/src/grin/sync/state_sync.rs +++ b/servers/src/grin/sync/state_sync.rs @@ -16,8 +16,7 @@ use chrono::prelude::{DateTime, Utc}; use chrono::Duration; use std::sync::Arc; -use crate::chain; -use crate::common::types::{Error, SyncState, SyncStatus}; +use crate::chain::{self, SyncState, SyncStatus}; use crate::core::core::hash::Hashed; use crate::core::global; use crate::p2p::{self, Peer}; @@ -119,8 +118,9 @@ impl StateSync { if let SyncStatus::TxHashsetDownload { .. } = self.sync_state.status() { if download_timeout { error!("state_sync: TxHashsetDownload status timeout in 10 minutes!"); - self.sync_state - .set_sync_error(Error::P2P(p2p::Error::Timeout)); + self.sync_state.set_sync_error( + chain::ErrorKind::SyncError(format!("{:?}", p2p::Error::Timeout)).into(), + ); } } @@ -130,7 +130,9 @@ impl StateSync { Ok(peer) => { self.state_sync_peer = Some(peer); } - Err(e) => self.sync_state.set_sync_error(Error::P2P(e)), + Err(e) => self + .sync_state + .set_sync_error(chain::ErrorKind::SyncError(format!("{:?}", e)).into()), } // to avoid the confusing log, diff --git a/servers/src/grin/sync/syncer.rs b/servers/src/grin/sync/syncer.rs index 3ef061b7e5..1564b4e8a1 100644 --- a/servers/src/grin/sync/syncer.rs +++ b/servers/src/grin/sync/syncer.rs @@ -16,8 +16,7 @@ use std::sync::Arc; use std::thread; use std::time; -use crate::chain; -use crate::common::types::{SyncState, SyncStatus}; +use crate::chain::{self, SyncState, SyncStatus}; use crate::core::global; use crate::core::pow::Difficulty; use crate::grin::sync::body_sync::BodySync; diff --git a/servers/src/mining/stratumserver.rs b/servers/src/mining/stratumserver.rs index fd5658ace0..bc5c7f1d30 100644 --- a/servers/src/mining/stratumserver.rs +++ b/servers/src/mining/stratumserver.rs @@ -32,9 +32,9 @@ use std::sync::Arc; use std::time::{Duration, SystemTime}; use std::{cmp, thread}; -use crate::chain; +use crate::chain::{self, SyncState}; use crate::common::stats::{StratumStats, WorkerStats}; -use crate::common::types::{StratumServerConfig, SyncState}; +use crate::common::types::StratumServerConfig; use crate::core::core::hash::Hashed; use crate::core::core::verifier_cache::VerifierCache; use crate::core::core::Block; diff --git a/src/bin/grin.rs b/src/bin/grin.rs index 0ba1205d9a..94e4fe8bc8 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -24,6 +24,7 @@ use crate::core::global; use crate::util::init_logger; use clap::App; use grin_api as api; +use grin_chain as chain; use grin_config as config; use grin_core as core; use grin_p2p as p2p; diff --git a/src/bin/tui/status.rs b/src/bin/tui/status.rs index d5bb776576..7069ab8b95 100644 --- a/src/bin/tui/status.rs +++ b/src/bin/tui/status.rs @@ -24,7 +24,7 @@ use cursive::Cursive; use crate::tui::constants::VIEW_BASIC_STATUS; use crate::tui::types::TUIStatusListener; -use crate::servers::common::types::SyncStatus; +use crate::chain::SyncStatus; use crate::servers::ServerStats; const NANO_TO_MILLIS: f64 = 1.0 / 1_000_000.0;