Merge branch 'master' into unitdiff
This commit is contained in:
@@ -17,9 +17,10 @@
|
||||
|
||||
use std::fs::File;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::{Arc, RwLock, Weak};
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::thread;
|
||||
use std::time::Instant;
|
||||
use util::RwLock;
|
||||
|
||||
use chain::{self, ChainAdapter, Options};
|
||||
use chrono::prelude::{DateTime, Utc};
|
||||
@@ -34,7 +35,7 @@ use p2p;
|
||||
use pool;
|
||||
use rand::prelude::*;
|
||||
use store;
|
||||
use util::{OneTime, LOGGER};
|
||||
use util::OneTime;
|
||||
|
||||
/// Implementation of the NetAdapter for the . Gets notified when new
|
||||
/// blocks and transactions are received and forwards to the chain and pool
|
||||
@@ -73,7 +74,6 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
let header = self.chain().head_header().unwrap();
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Received tx {}, inputs: {}, outputs: {}, kernels: {}, going to process.",
|
||||
tx_hash,
|
||||
tx.inputs().len(),
|
||||
@@ -82,18 +82,17 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
);
|
||||
|
||||
let res = {
|
||||
let mut tx_pool = self.tx_pool.write().unwrap();
|
||||
let mut tx_pool = self.tx_pool.write();
|
||||
tx_pool.add_to_pool(source, tx, stem, &header)
|
||||
};
|
||||
|
||||
if let Err(e) = res {
|
||||
debug!(LOGGER, "Transaction {} rejected: {:?}", tx_hash, e);
|
||||
debug!("Transaction {} rejected: {:?}", tx_hash, e);
|
||||
}
|
||||
}
|
||||
|
||||
fn block_received(&self, b: core::Block, addr: SocketAddr) -> bool {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Received block {} at {} from {}, inputs: {}, outputs: {}, kernels: {}, going to process.",
|
||||
b.hash(),
|
||||
b.header.height,
|
||||
@@ -108,7 +107,6 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
fn compact_block_received(&self, cb: core::CompactBlock, addr: SocketAddr) -> bool {
|
||||
let bhash = cb.hash();
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Received compact_block {} at {} from {}, outputs: {}, kernels: {}, kern_ids: {}, going to process.",
|
||||
bhash,
|
||||
cb.header.height,
|
||||
@@ -124,7 +122,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
match core::Block::hydrate_from(cb, vec![]) {
|
||||
Ok(block) => self.process_block(block, addr),
|
||||
Err(e) => {
|
||||
debug!(LOGGER, "Invalid hydrated block {}: {}", cb_hash, e);
|
||||
debug!("Invalid hydrated block {}: {}", cb_hash, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -134,17 +132,16 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
.chain()
|
||||
.process_block_header(&cb.header, self.chain_opts())
|
||||
{
|
||||
debug!(LOGGER, "Invalid compact block header {}: {}", cb_hash, e);
|
||||
debug!("Invalid compact block header {}: {}", cb_hash, e);
|
||||
return !e.is_bad_data();
|
||||
}
|
||||
|
||||
let (txs, missing_short_ids) = {
|
||||
let tx_pool = self.tx_pool.read().unwrap();
|
||||
let tx_pool = self.tx_pool.read();
|
||||
tx_pool.retrieve_transactions(cb.hash(), cb.nonce, cb.kern_ids())
|
||||
};
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"adapter: txs from tx pool - {}, (unknown kern_ids: {})",
|
||||
txs.len(),
|
||||
missing_short_ids.len(),
|
||||
@@ -158,7 +155,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
let block = match core::Block::hydrate_from(cb.clone(), txs) {
|
||||
Ok(block) => block,
|
||||
Err(e) => {
|
||||
debug!(LOGGER, "Invalid hydrated block {}: {}", cb.hash(), e);
|
||||
debug!("Invalid hydrated block {}: {}", cb.hash(), e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -168,29 +165,22 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
.validate(&prev.total_kernel_offset, self.verifier_cache.clone())
|
||||
.is_ok()
|
||||
{
|
||||
debug!(LOGGER, "adapter: successfully hydrated block from tx pool!");
|
||||
debug!("adapter: successfully hydrated block from tx pool!");
|
||||
self.process_block(block, addr)
|
||||
} else {
|
||||
if self.sync_state.status() == SyncStatus::NoSync {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"adapter: block invalid after hydration, requesting full block"
|
||||
);
|
||||
debug!("adapter: block invalid after hydration, requesting full block");
|
||||
self.request_block(&cb.header, &addr);
|
||||
true
|
||||
} else {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"adapter: block invalid after hydration, ignoring it, cause still syncing"
|
||||
);
|
||||
true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"adapter: failed to retrieve previous block header (still syncing?)"
|
||||
);
|
||||
debug!("adapter: failed to retrieve previous block header (still syncing?)");
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -199,8 +189,8 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
fn header_received(&self, bh: core::BlockHeader, addr: SocketAddr) -> bool {
|
||||
let bhash = bh.hash();
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Received block header {} at {} from {}, going to process.", bhash, bh.height, addr,
|
||||
"Received block header {} at {} from {}, going to process.",
|
||||
bhash, bh.height, addr,
|
||||
);
|
||||
|
||||
// pushing the new block header through the header chain pipeline
|
||||
@@ -208,16 +198,11 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
let res = self.chain().process_block_header(&bh, self.chain_opts());
|
||||
|
||||
if let &Err(ref e) = &res {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Block header {} refused by chain: {:?}",
|
||||
bhash,
|
||||
e.kind()
|
||||
);
|
||||
debug!("Block header {} refused by chain: {:?}", bhash, e.kind());
|
||||
if e.is_bad_data() {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"header_received: {} is a bad header, resetting header head", bhash
|
||||
"header_received: {} is a bad header, resetting header head",
|
||||
bhash
|
||||
);
|
||||
let _ = self.chain().reset_head();
|
||||
return false;
|
||||
@@ -238,7 +223,6 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
|
||||
fn headers_received(&self, bhs: Vec<core::BlockHeader>, addr: SocketAddr) -> bool {
|
||||
info!(
|
||||
LOGGER,
|
||||
"Received block headers {:?} from {}",
|
||||
bhs.iter().map(|x| x.hash()).collect::<Vec<_>>(),
|
||||
addr,
|
||||
@@ -251,7 +235,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
// try to add headers to our header chain
|
||||
let res = self.chain().sync_block_headers(&bhs, self.chain_opts());
|
||||
if let &Err(ref e) = &res {
|
||||
debug!(LOGGER, "Block headers refused by chain: {:?}", e);
|
||||
debug!("Block headers refused by chain: {:?}", e);
|
||||
|
||||
if e.is_bad_data() {
|
||||
return false;
|
||||
@@ -261,14 +245,14 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
}
|
||||
|
||||
fn locate_headers(&self, locator: Vec<Hash>) -> Vec<core::BlockHeader> {
|
||||
debug!(LOGGER, "locate_headers: {:?}", locator,);
|
||||
debug!("locate_headers: {:?}", locator,);
|
||||
|
||||
let header = match self.find_common_header(locator) {
|
||||
Some(header) => header,
|
||||
None => return vec![],
|
||||
};
|
||||
|
||||
debug!(LOGGER, "locate_headers: common header: {:?}", header.hash(),);
|
||||
debug!("locate_headers: common header: {:?}", header.hash(),);
|
||||
|
||||
// looks like we know one, getting as many following headers as allowed
|
||||
let hh = header.height;
|
||||
@@ -280,18 +264,14 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
Err(e) => match e.kind() {
|
||||
chain::ErrorKind::StoreErr(store::Error::NotFoundErr(_), _) => break,
|
||||
_ => {
|
||||
error!(LOGGER, "Could not build header locator: {:?}", e);
|
||||
error!("Could not build header locator: {:?}", e);
|
||||
return vec![];
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"locate_headers: returning headers: {}",
|
||||
headers.len(),
|
||||
);
|
||||
debug!("locate_headers: returning headers: {}", headers.len(),);
|
||||
|
||||
headers
|
||||
}
|
||||
@@ -316,10 +296,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
reader: read,
|
||||
}),
|
||||
Err(e) => {
|
||||
warn!(
|
||||
LOGGER,
|
||||
"Couldn't produce txhashset data for block {}: {:?}", h, e
|
||||
);
|
||||
warn!("Couldn't produce txhashset data for block {}: {:?}", h, e);
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -366,12 +343,12 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||
.chain()
|
||||
.txhashset_write(h, txhashset_data, self.sync_state.as_ref())
|
||||
{
|
||||
error!(LOGGER, "Failed to save txhashset archive: {}", e);
|
||||
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));
|
||||
is_good_data
|
||||
} else {
|
||||
info!(LOGGER, "Received valid txhashset data for {}.", h);
|
||||
info!("Received valid txhashset data for {}.", h);
|
||||
true
|
||||
}
|
||||
}
|
||||
@@ -446,7 +423,7 @@ impl NetToChainAdapter {
|
||||
self.find_common_header(locator[1..].to_vec())
|
||||
}
|
||||
_ => {
|
||||
error!(LOGGER, "Could not build header locator: {:?}", e);
|
||||
error!("Could not build header locator: {:?}", e);
|
||||
None
|
||||
}
|
||||
},
|
||||
@@ -456,14 +433,11 @@ impl NetToChainAdapter {
|
||||
// pushing the new block through the chain pipeline
|
||||
// remembering to reset the head if we have a bad block
|
||||
fn process_block(&self, b: core::Block, addr: SocketAddr) -> bool {
|
||||
if !self.archive_mode {
|
||||
// We cannot process blocks earlier than the horizon so check for this here.
|
||||
{
|
||||
let head = self.chain().head().unwrap();
|
||||
// we have a fast sync'd node and are sent a block older than our horizon,
|
||||
// only sync can do something with that
|
||||
if b.header.height < head
|
||||
.height
|
||||
.saturating_sub(global::cut_through_horizon() as u64)
|
||||
{
|
||||
let horizon = head.height.saturating_sub(global::cut_through_horizon() as u64);
|
||||
if b.header.height < horizon {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -478,8 +452,8 @@ impl NetToChainAdapter {
|
||||
}
|
||||
Err(ref e) if e.is_bad_data() => {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"adapter: process_block: {} is a bad block, resetting head", bhash
|
||||
"adapter: process_block: {} is a bad block, resetting head",
|
||||
bhash
|
||||
);
|
||||
let _ = self.chain().reset_head();
|
||||
|
||||
@@ -494,14 +468,13 @@ impl NetToChainAdapter {
|
||||
chain::ErrorKind::Orphan => {
|
||||
// make sure we did not miss the parent block
|
||||
if !self.chain().is_orphan(&prev_hash) && !self.sync_state.is_syncing() {
|
||||
debug!(LOGGER, "adapter: process_block: received an orphan block, checking the parent: {:}", prev_hash);
|
||||
debug!("adapter: process_block: received an orphan block, checking the parent: {:}", prev_hash);
|
||||
self.request_block_by_hash(prev_hash, &addr)
|
||||
}
|
||||
true
|
||||
}
|
||||
_ => {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"adapter: process_block: block {} refused by chain: {}",
|
||||
bhash,
|
||||
e.kind()
|
||||
@@ -526,8 +499,8 @@ impl NetToChainAdapter {
|
||||
let now = Instant::now();
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"adapter: process_block: ***** validating full chain state at {}", bhash,
|
||||
"adapter: process_block: ***** validating full chain state at {}",
|
||||
bhash,
|
||||
);
|
||||
|
||||
self.chain()
|
||||
@@ -535,7 +508,6 @@ impl NetToChainAdapter {
|
||||
.expect("chain validation failed, hard stop");
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"adapter: process_block: ***** done validating full chain state, took {}s",
|
||||
now.elapsed().as_secs(),
|
||||
);
|
||||
@@ -557,7 +529,7 @@ impl NetToChainAdapter {
|
||||
.name("compactor".to_string())
|
||||
.spawn(move || {
|
||||
if let Err(e) = chain.compact() {
|
||||
error!(LOGGER, "Could not compact chain: {:?}", e);
|
||||
error!("Could not compact chain: {:?}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -591,23 +563,19 @@ impl NetToChainAdapter {
|
||||
match self.chain().block_exists(h) {
|
||||
Ok(false) => match self.peers().get_connected_peer(addr) {
|
||||
None => debug!(
|
||||
LOGGER,
|
||||
"send_block_request_to_peer: can't send request to peer {:?}, not connected",
|
||||
addr
|
||||
),
|
||||
Some(peer) => {
|
||||
if let Err(e) = f(&peer, h) {
|
||||
error!(LOGGER, "send_block_request_to_peer: failed: {:?}", e)
|
||||
error!("send_block_request_to_peer: failed: {:?}", e)
|
||||
}
|
||||
}
|
||||
},
|
||||
Ok(true) => debug!(
|
||||
LOGGER,
|
||||
"send_block_request_to_peer: block {} already known", h
|
||||
),
|
||||
Ok(true) => debug!("send_block_request_to_peer: block {} already known", h),
|
||||
Err(e) => error!(
|
||||
LOGGER,
|
||||
"send_block_request_to_peer: failed to check block exists: {:?}", e
|
||||
"send_block_request_to_peer: failed to check block exists: {:?}",
|
||||
e
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -638,11 +606,10 @@ impl ChainAdapter for ChainToPoolAndNetAdapter {
|
||||
return;
|
||||
}
|
||||
|
||||
debug!(LOGGER, "adapter: block_accepted: {:?}", b.hash());
|
||||
debug!("adapter: block_accepted: {:?}", b.hash());
|
||||
|
||||
if let Err(e) = self.tx_pool.write().unwrap().reconcile_block(b) {
|
||||
if let Err(e) = self.tx_pool.write().reconcile_block(b) {
|
||||
error!(
|
||||
LOGGER,
|
||||
"Pool could not update itself at block {}: {:?}",
|
||||
b.hash(),
|
||||
e,
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
//! Server stat collection types, to be used by tests, logging or GUI/TUI
|
||||
//! to collect information about server status
|
||||
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use std::time::SystemTime;
|
||||
use util::RwLock;
|
||||
|
||||
use core::pow::Difficulty;
|
||||
use core::consensus::graph_weight;
|
||||
|
||||
use chrono::prelude::*;
|
||||
|
||||
@@ -31,8 +31,6 @@ use p2p;
|
||||
/// and populated when required
|
||||
#[derive(Clone)]
|
||||
pub struct ServerStateInfo {
|
||||
/// whether we're in a state of waiting for peers at startup
|
||||
pub awaiting_peers: Arc<AtomicBool>,
|
||||
/// Stratum stats
|
||||
pub stratum_stats: Arc<RwLock<StratumStats>>,
|
||||
}
|
||||
@@ -40,7 +38,6 @@ pub struct ServerStateInfo {
|
||||
impl Default for ServerStateInfo {
|
||||
fn default() -> ServerStateInfo {
|
||||
ServerStateInfo {
|
||||
awaiting_peers: Arc::new(AtomicBool::new(false)),
|
||||
stratum_stats: Arc::new(RwLock::new(StratumStats::default())),
|
||||
}
|
||||
}
|
||||
@@ -57,8 +54,6 @@ pub struct ServerStats {
|
||||
pub header_head: chain::Tip,
|
||||
/// Whether we're currently syncing
|
||||
pub sync_status: SyncStatus,
|
||||
/// Whether we're awaiting peers
|
||||
pub awaiting_peers: bool,
|
||||
/// Handle to current stratum server stats
|
||||
pub stratum_stats: StratumStats,
|
||||
/// Peer stats
|
||||
@@ -163,8 +158,7 @@ pub struct PeerStats {
|
||||
impl StratumStats {
|
||||
/// Calculate network hashrate
|
||||
pub fn network_hashrate(&self) -> f64 {
|
||||
42.0 * (self.network_difficulty as f64 / Difficulty::scale(self.edge_bits as u8) as f64)
|
||||
/ 60.0
|
||||
42.0 * (self.network_difficulty as f64 / graph_weight(self.edge_bits as u8) as f64) / 60.0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+21
-35
@@ -14,7 +14,8 @@
|
||||
|
||||
//! Server types
|
||||
use std::convert::From;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use util::RwLock;
|
||||
|
||||
use api;
|
||||
use chain;
|
||||
@@ -24,7 +25,6 @@ use core::{core, pow};
|
||||
use p2p;
|
||||
use pool;
|
||||
use store;
|
||||
use util::LOGGER;
|
||||
use wallet;
|
||||
|
||||
/// Error type wrapping underlying module errors.
|
||||
@@ -44,6 +44,8 @@ pub enum Error {
|
||||
Wallet(wallet::Error),
|
||||
/// Error originating from the cuckoo miner
|
||||
Cuckoo(pow::Error),
|
||||
/// Error originating from the transaction pool.
|
||||
Pool(pool::PoolError),
|
||||
}
|
||||
|
||||
impl From<core::block::Error> for Error {
|
||||
@@ -87,6 +89,12 @@ impl From<wallet::Error> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<pool::PoolError> for Error {
|
||||
fn from(e: pool::PoolError) -> Error {
|
||||
Error::Pool(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// Type of seeding the server will use to find other peers on the network.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum ChainValidationMode {
|
||||
@@ -160,28 +168,6 @@ pub struct ServerConfig {
|
||||
pub stratum_mining_config: Option<StratumServerConfig>,
|
||||
}
|
||||
|
||||
impl ServerConfig {
|
||||
/// Configuration items validation check
|
||||
pub fn validation_check(&mut self) {
|
||||
// check [server.p2p_config.capabilities] with 'archive_mode' in [server]
|
||||
if let Some(archive) = self.archive_mode {
|
||||
// note: slog not available before config loaded, only print here.
|
||||
if archive != self
|
||||
.p2p_config
|
||||
.capabilities
|
||||
.contains(p2p::Capabilities::FULL_HIST)
|
||||
{
|
||||
// if conflict, 'archive_mode' win
|
||||
self.p2p_config
|
||||
.capabilities
|
||||
.toggle(p2p::Capabilities::FULL_HIST);
|
||||
}
|
||||
}
|
||||
|
||||
// todo: other checks if needed
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ServerConfig {
|
||||
fn default() -> ServerConfig {
|
||||
ServerConfig {
|
||||
@@ -250,6 +236,9 @@ pub enum SyncStatus {
|
||||
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,
|
||||
@@ -297,12 +286,12 @@ impl SyncState {
|
||||
/// Whether the current state matches any active syncing operation.
|
||||
/// Note: This includes our "initial" state.
|
||||
pub fn is_syncing(&self) -> bool {
|
||||
*self.current.read().unwrap() != SyncStatus::NoSync
|
||||
*self.current.read() != SyncStatus::NoSync
|
||||
}
|
||||
|
||||
/// Current syncing status
|
||||
pub fn status(&self) -> SyncStatus {
|
||||
*self.current.read().unwrap()
|
||||
*self.current.read()
|
||||
}
|
||||
|
||||
/// Update the syncing status
|
||||
@@ -311,12 +300,9 @@ impl SyncState {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut status = self.current.write().unwrap();
|
||||
let mut status = self.current.write();
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"sync_state: sync_status: {:?} -> {:?}", *status, new_status,
|
||||
);
|
||||
debug!("sync_state: sync_status: {:?} -> {:?}", *status, new_status,);
|
||||
|
||||
*status = new_status;
|
||||
}
|
||||
@@ -324,7 +310,7 @@ impl SyncState {
|
||||
/// 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().unwrap();
|
||||
let mut status = self.current.write();
|
||||
*status = new_status;
|
||||
true
|
||||
} else {
|
||||
@@ -334,7 +320,7 @@ impl SyncState {
|
||||
|
||||
/// Communicate sync error
|
||||
pub fn set_sync_error(&self, error: Error) {
|
||||
*self.sync_error.write().unwrap() = Some(error);
|
||||
*self.sync_error.write() = Some(error);
|
||||
}
|
||||
|
||||
/// Get sync error
|
||||
@@ -344,7 +330,7 @@ impl SyncState {
|
||||
|
||||
/// Clear sync error
|
||||
pub fn clear_sync_error(&self) {
|
||||
*self.sync_error.write().unwrap() = None;
|
||||
*self.sync_error.write() = None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,7 +340,7 @@ impl chain::TxHashsetWriteStatus for SyncState {
|
||||
}
|
||||
|
||||
fn on_validation(&self, vkernels: u64, vkernel_total: u64, vrproofs: u64, vrproof_total: u64) {
|
||||
let mut status = self.current.write().unwrap();
|
||||
let mut status = self.current.write();
|
||||
match *status {
|
||||
SyncStatus::TxHashsetValidation {
|
||||
kernels,
|
||||
|
||||
@@ -15,15 +15,15 @@
|
||||
use chrono::prelude::Utc;
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use util::RwLock;
|
||||
|
||||
use core::core::hash::Hashed;
|
||||
use core::core::transaction;
|
||||
use core::core::verifier_cache::VerifierCache;
|
||||
use pool::{DandelionConfig, PoolEntryState, PoolError, TransactionPool, TxSource};
|
||||
use util::LOGGER;
|
||||
|
||||
/// A process to monitor transactions in the stempool.
|
||||
/// With Dandelion, transaction can be broadcasted in stem or fluff phase.
|
||||
@@ -39,7 +39,7 @@ pub fn monitor_transactions(
|
||||
verifier_cache: Arc<RwLock<VerifierCache>>,
|
||||
stop: Arc<AtomicBool>,
|
||||
) {
|
||||
debug!(LOGGER, "Started Dandelion transaction monitor.");
|
||||
debug!("Started Dandelion transaction monitor.");
|
||||
|
||||
let _ = thread::Builder::new()
|
||||
.name("dandelion".to_string())
|
||||
@@ -57,26 +57,26 @@ pub fn monitor_transactions(
|
||||
// Aggregate them up to give a single (valid) aggregated tx and propagate it
|
||||
// to the next Dandelion relay along the stem.
|
||||
if process_stem_phase(tx_pool.clone(), verifier_cache.clone()).is_err() {
|
||||
error!(LOGGER, "dand_mon: Problem with stem phase.");
|
||||
error!("dand_mon: Problem with stem phase.");
|
||||
}
|
||||
|
||||
// Step 2: find all "ToFluff" entries in stempool from last run.
|
||||
// Aggregate them up to give a single (valid) aggregated tx and (re)add it
|
||||
// to our pool with stem=false (which will then broadcast it).
|
||||
if process_fluff_phase(tx_pool.clone(), verifier_cache.clone()).is_err() {
|
||||
error!(LOGGER, "dand_mon: Problem with fluff phase.");
|
||||
error!("dand_mon: Problem with fluff phase.");
|
||||
}
|
||||
|
||||
// Step 3: now find all "Fresh" entries in stempool since last run.
|
||||
// Coin flip for each (90/10) and label them as either "ToStem" or "ToFluff".
|
||||
// We will process these in the next run (waiting patience secs).
|
||||
if process_fresh_entries(dandelion_config.clone(), tx_pool.clone()).is_err() {
|
||||
error!(LOGGER, "dand_mon: Problem processing fresh pool entries.");
|
||||
error!("dand_mon: Problem processing fresh pool entries.");
|
||||
}
|
||||
|
||||
// Step 4: now find all expired entries based on embargo timer.
|
||||
if process_expired_entries(dandelion_config.clone(), tx_pool.clone()).is_err() {
|
||||
error!(LOGGER, "dand_mon: Problem processing fresh pool entries.");
|
||||
error!("dand_mon: Problem processing fresh pool entries.");
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -86,14 +86,20 @@ fn process_stem_phase(
|
||||
tx_pool: Arc<RwLock<TransactionPool>>,
|
||||
verifier_cache: Arc<RwLock<VerifierCache>>,
|
||||
) -> Result<(), PoolError> {
|
||||
let mut tx_pool = tx_pool.write().unwrap();
|
||||
let mut tx_pool = tx_pool.write();
|
||||
|
||||
let header = tx_pool.chain_head()?;
|
||||
|
||||
let txpool_tx = tx_pool.txpool.aggregate_transaction()?;
|
||||
let stem_txs = tx_pool
|
||||
.stempool
|
||||
.get_transactions_in_state(PoolEntryState::ToStem);
|
||||
|
||||
if stem_txs.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let txpool_tx = tx_pool.txpool.aggregate_transaction()?;
|
||||
|
||||
let stem_txs = tx_pool
|
||||
.stempool
|
||||
.select_valid_transactions(stem_txs, txpool_tx, &header)?;
|
||||
@@ -102,21 +108,14 @@ fn process_stem_phase(
|
||||
.transition_to_state(&stem_txs, PoolEntryState::Stemmed);
|
||||
|
||||
if stem_txs.len() > 0 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Found {} txs for stemming.",
|
||||
stem_txs.len()
|
||||
);
|
||||
debug!("dand_mon: Found {} txs for stemming.", stem_txs.len());
|
||||
|
||||
let agg_tx = transaction::aggregate(stem_txs)?;
|
||||
agg_tx.validate(verifier_cache.clone())?;
|
||||
|
||||
let res = tx_pool.adapter.stem_tx_accepted(&agg_tx);
|
||||
if res.is_err() {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Unable to propagate stem tx. No relay, fluffing instead."
|
||||
);
|
||||
debug!("dand_mon: Unable to propagate stem tx. No relay, fluffing instead.");
|
||||
|
||||
let src = TxSource {
|
||||
debug_name: "no_relay".to_string(),
|
||||
@@ -133,14 +132,20 @@ fn process_fluff_phase(
|
||||
tx_pool: Arc<RwLock<TransactionPool>>,
|
||||
verifier_cache: Arc<RwLock<VerifierCache>>,
|
||||
) -> Result<(), PoolError> {
|
||||
let mut tx_pool = tx_pool.write().unwrap();
|
||||
let mut tx_pool = tx_pool.write();
|
||||
|
||||
let header = tx_pool.chain_head()?;
|
||||
|
||||
let txpool_tx = tx_pool.txpool.aggregate_transaction()?;
|
||||
let stem_txs = tx_pool
|
||||
.stempool
|
||||
.get_transactions_in_state(PoolEntryState::ToFluff);
|
||||
|
||||
if stem_txs.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let txpool_tx = tx_pool.txpool.aggregate_transaction()?;
|
||||
|
||||
let stem_txs = tx_pool
|
||||
.stempool
|
||||
.select_valid_transactions(stem_txs, txpool_tx, &header)?;
|
||||
@@ -149,11 +154,7 @@ fn process_fluff_phase(
|
||||
.transition_to_state(&stem_txs, PoolEntryState::Fluffed);
|
||||
|
||||
if stem_txs.len() > 0 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Found {} txs for fluffing.",
|
||||
stem_txs.len()
|
||||
);
|
||||
debug!("dand_mon: Found {} txs for fluffing.", stem_txs.len());
|
||||
|
||||
let agg_tx = transaction::aggregate(stem_txs)?;
|
||||
agg_tx.validate(verifier_cache.clone())?;
|
||||
@@ -172,7 +173,7 @@ fn process_fresh_entries(
|
||||
dandelion_config: DandelionConfig,
|
||||
tx_pool: Arc<RwLock<TransactionPool>>,
|
||||
) -> Result<(), PoolError> {
|
||||
let mut tx_pool = tx_pool.write().unwrap();
|
||||
let mut tx_pool = tx_pool.write();
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
@@ -185,7 +186,6 @@ fn process_fresh_entries(
|
||||
|
||||
if fresh_entries.len() > 0 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Found {} fresh entries in stempool.",
|
||||
fresh_entries.len()
|
||||
);
|
||||
@@ -212,31 +212,23 @@ fn process_expired_entries(
|
||||
|
||||
let mut expired_entries = vec![];
|
||||
{
|
||||
let tx_pool = tx_pool.read().unwrap();
|
||||
let tx_pool = tx_pool.read();
|
||||
for entry in tx_pool
|
||||
.stempool
|
||||
.entries
|
||||
.iter()
|
||||
.filter(|x| x.tx_at.timestamp() < cutoff)
|
||||
{
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Embargo timer expired for {:?}",
|
||||
entry.tx.hash()
|
||||
);
|
||||
debug!("dand_mon: Embargo timer expired for {:?}", entry.tx.hash());
|
||||
expired_entries.push(entry.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if expired_entries.len() > 0 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"dand_mon: Found {} expired txs.",
|
||||
expired_entries.len()
|
||||
);
|
||||
debug!("dand_mon: Found {} expired txs.", expired_entries.len());
|
||||
|
||||
{
|
||||
let mut tx_pool = tx_pool.write().unwrap();
|
||||
let mut tx_pool = tx_pool.write();
|
||||
let header = tx_pool.chain_head()?;
|
||||
|
||||
for entry in expired_entries {
|
||||
@@ -245,11 +237,8 @@ fn process_expired_entries(
|
||||
identifier: "?.?.?.?".to_string(),
|
||||
};
|
||||
match tx_pool.add_to_pool(src, entry.tx, false, &header) {
|
||||
Ok(_) => debug!(
|
||||
LOGGER,
|
||||
"dand_mon: embargo expired, fluffed tx successfully."
|
||||
),
|
||||
Err(e) => debug!(LOGGER, "dand_mon: Failed to fluff expired tx - {:?}", e),
|
||||
Ok(_) => debug!("dand_mon: embargo expired, fluffed tx successfully."),
|
||||
Err(e) => debug!("dand_mon: Failed to fluff expired tx - {:?}", e),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+28
-23
@@ -12,9 +12,10 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Mining plugin manager, using the cuckoo-miner crate to provide
|
||||
//! a mining worker implementation
|
||||
//!
|
||||
//! Seeds a server with initial peers on first start and keep monitoring
|
||||
//! peer counts to connect to more if neeed. Seedin strategy is
|
||||
//! configurable with either no peers, a user-defined list or a preset
|
||||
//! list of DNS records (the default).
|
||||
|
||||
use chrono::prelude::Utc;
|
||||
use chrono::{Duration, MIN_DATE};
|
||||
@@ -27,7 +28,6 @@ use std::{cmp, io, str, thread, time};
|
||||
use p2p;
|
||||
use p2p::ChainAdapter;
|
||||
use pool::DandelionConfig;
|
||||
use util::LOGGER;
|
||||
|
||||
// DNS Seeds with contact email associated
|
||||
const DNS_SEEDS: &'static [&'static str] = &[
|
||||
@@ -60,10 +60,18 @@ pub fn connect_and_monitor(
|
||||
);
|
||||
|
||||
let mut prev = MIN_DATE.and_hms(0, 0, 0);
|
||||
let mut prev_expire_check = MIN_DATE.and_hms(0, 0, 0);
|
||||
let mut prev_ping = Utc::now();
|
||||
let mut start_attempt = 0;
|
||||
|
||||
while !stop.load(Ordering::Relaxed) {
|
||||
// Check for and remove expired peers from the storage
|
||||
if Utc::now() - prev_expire_check > Duration::hours(1) {
|
||||
peers.remove_expired();
|
||||
|
||||
prev_expire_check = Utc::now();
|
||||
}
|
||||
|
||||
// make several attempts to get peers as quick as possible
|
||||
// with exponential backoff
|
||||
if Utc::now() - prev > Duration::seconds(cmp::min(20, 1 << start_attempt)) {
|
||||
@@ -111,6 +119,7 @@ fn monitor_peers(
|
||||
let mut healthy_count = 0;
|
||||
let mut banned_count = 0;
|
||||
let mut defuncts = vec![];
|
||||
|
||||
for x in peers.all_peers() {
|
||||
match x.flags {
|
||||
p2p::State::Banned => {
|
||||
@@ -119,8 +128,8 @@ fn monitor_peers(
|
||||
if interval >= config.ban_window() {
|
||||
peers.unban_peer(&x.addr);
|
||||
debug!(
|
||||
LOGGER,
|
||||
"monitor_peers: unbanned {} after {} seconds", x.addr, interval
|
||||
"monitor_peers: unbanned {} after {} seconds",
|
||||
x.addr, interval
|
||||
);
|
||||
} else {
|
||||
banned_count += 1;
|
||||
@@ -132,7 +141,6 @@ fn monitor_peers(
|
||||
}
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"monitor_peers: on {}:{}, {} connected ({} most_work). \
|
||||
all {} = {} healthy + {} banned + {} defunct",
|
||||
config.host,
|
||||
@@ -158,8 +166,8 @@ fn monitor_peers(
|
||||
let mut connected_peers: Vec<SocketAddr> = vec![];
|
||||
for p in peers.connected_peers() {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"monitor_peers: {}:{} ask {} for more peers", config.host, config.port, p.info.addr,
|
||||
"monitor_peers: {}:{} ask {} for more peers",
|
||||
config.host, config.port, p.info.addr,
|
||||
);
|
||||
let _ = p.send_peer_request(capabilities);
|
||||
connected_peers.push(p.info.addr)
|
||||
@@ -178,7 +186,7 @@ fn monitor_peers(
|
||||
}
|
||||
}
|
||||
}
|
||||
None => debug!(LOGGER, "monitor_peers: no preferred peers"),
|
||||
None => debug!("monitor_peers: no preferred peers"),
|
||||
}
|
||||
|
||||
// take a random defunct peer and mark it healthy: over a long period any
|
||||
@@ -197,8 +205,8 @@ fn monitor_peers(
|
||||
);
|
||||
for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"monitor_peers: on {}:{}, queue to soon try {}", config.host, config.port, p.addr,
|
||||
"monitor_peers: on {}:{}, queue to soon try {}",
|
||||
config.host, config.port, p.addr,
|
||||
);
|
||||
tx.send(p.addr).unwrap();
|
||||
}
|
||||
@@ -208,13 +216,13 @@ fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionCon
|
||||
// Dandelion Relay Updater
|
||||
let dandelion_relay = peers.get_dandelion_relay();
|
||||
if dandelion_relay.is_empty() {
|
||||
debug!(LOGGER, "monitor_peers: no dandelion relay updating");
|
||||
debug!("monitor_peers: no dandelion relay updating");
|
||||
peers.update_dandelion_relay();
|
||||
} else {
|
||||
for last_added in dandelion_relay.keys() {
|
||||
let dandelion_interval = Utc::now().timestamp() - last_added;
|
||||
if dandelion_interval >= dandelion_config.relay_secs.unwrap() as i64 {
|
||||
debug!(LOGGER, "monitor_peers: updating expired dandelion relay");
|
||||
debug!("monitor_peers: updating expired dandelion relay");
|
||||
peers.update_dandelion_relay();
|
||||
}
|
||||
}
|
||||
@@ -230,7 +238,7 @@ fn connect_to_seeds_and_preferred_peers(
|
||||
peers_preferred_list: Option<Vec<SocketAddr>>,
|
||||
) {
|
||||
// check if we have some peers in db
|
||||
let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::FULL_HIST, 100);
|
||||
let peers = peers.find_peers(p2p::State::Healthy, p2p::Capabilities::FULL_NODE, 100);
|
||||
|
||||
// if so, get their addresses, otherwise use our seeds
|
||||
let mut peer_addrs = if peers.len() > 3 {
|
||||
@@ -242,11 +250,11 @@ fn connect_to_seeds_and_preferred_peers(
|
||||
// If we have preferred peers add them to the connection
|
||||
match peers_preferred_list {
|
||||
Some(mut peers_preferred) => peer_addrs.append(&mut peers_preferred),
|
||||
None => debug!(LOGGER, "No preferred peers"),
|
||||
None => debug!("No preferred peers"),
|
||||
};
|
||||
|
||||
if peer_addrs.len() == 0 {
|
||||
warn!(LOGGER, "No seeds were retrieved.");
|
||||
warn!("No seeds were retrieved.");
|
||||
}
|
||||
|
||||
// connect to this first set of addresses
|
||||
@@ -311,7 +319,7 @@ pub fn dns_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
|
||||
let mut addresses: Vec<SocketAddr> = vec![];
|
||||
for dns_seed in DNS_SEEDS {
|
||||
let temp_addresses = addresses.clone();
|
||||
debug!(LOGGER, "Retrieving seed nodes from dns {}", dns_seed);
|
||||
debug!("Retrieving seed nodes from dns {}", dns_seed);
|
||||
match (dns_seed.to_owned(), 0).to_socket_addrs() {
|
||||
Ok(addrs) => addresses.append(
|
||||
&mut (addrs
|
||||
@@ -321,13 +329,10 @@ pub fn dns_seeds() -> Box<Fn() -> Vec<SocketAddr> + Send> {
|
||||
}).filter(|addr| !temp_addresses.contains(addr))
|
||||
.collect()),
|
||||
),
|
||||
Err(e) => debug!(
|
||||
LOGGER,
|
||||
"Failed to resolve seed {:?} got error {:?}", dns_seed, e
|
||||
),
|
||||
Err(e) => debug!("Failed to resolve seed {:?} got error {:?}", dns_seed, e),
|
||||
}
|
||||
}
|
||||
debug!(LOGGER, "Retrieved seed addresses: {:?}", addresses);
|
||||
debug!("Retrieved seed addresses: {:?}", addresses);
|
||||
addresses
|
||||
})
|
||||
}
|
||||
|
||||
+15
-52
@@ -18,8 +18,9 @@
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use std::{thread, time};
|
||||
use util::RwLock;
|
||||
|
||||
use api;
|
||||
use chain;
|
||||
@@ -27,8 +28,7 @@ use common::adapters::{
|
||||
ChainToPoolAndNetAdapter, NetToChainAdapter, PoolToChainAdapter, PoolToNetAdapter,
|
||||
};
|
||||
use common::stats::{DiffBlock, DiffStats, PeerStats, ServerStateInfo, ServerStats};
|
||||
use common::types::{Error, ServerConfig, StratumServerConfig, SyncState};
|
||||
use core::core::hash::Hashed;
|
||||
use common::types::{Error, ServerConfig, StratumServerConfig, SyncState, SyncStatus};
|
||||
use core::core::verifier_cache::{LruVerifierCache, VerifierCache};
|
||||
use core::{consensus, genesis, global, pow};
|
||||
use grin::{dandelion_monitor, seed, sync};
|
||||
@@ -38,7 +38,6 @@ use p2p;
|
||||
use pool;
|
||||
use store;
|
||||
use util::file::get_first_line;
|
||||
use util::LOGGER;
|
||||
|
||||
/// Grin server holding internal structures.
|
||||
pub struct Server {
|
||||
@@ -79,7 +78,7 @@ impl Server {
|
||||
if let Some(s) = enable_stratum_server {
|
||||
if s {
|
||||
{
|
||||
let mut stratum_stats = serv.state_info.stratum_stats.write().unwrap();
|
||||
let mut stratum_stats = serv.state_info.stratum_stats.write();
|
||||
stratum_stats.is_enabled = true;
|
||||
}
|
||||
serv.start_stratum_server(c.clone());
|
||||
@@ -111,18 +110,6 @@ impl Server {
|
||||
Some(b) => b,
|
||||
};
|
||||
|
||||
// If archive mode is enabled then the flags should contains the FULL_HIST flag
|
||||
if archive_mode && !config
|
||||
.p2p_config
|
||||
.capabilities
|
||||
.contains(p2p::Capabilities::FULL_HIST)
|
||||
{
|
||||
config
|
||||
.p2p_config
|
||||
.capabilities
|
||||
.insert(p2p::Capabilities::FULL_HIST);
|
||||
}
|
||||
|
||||
let stop = Arc::new(AtomicBool::new(false));
|
||||
|
||||
// Shared cache for verification results.
|
||||
@@ -155,7 +142,7 @@ impl Server {
|
||||
global::ChainTypes::Mainnet => genesis::genesis_testnet2(), //TODO: Fix, obviously
|
||||
};
|
||||
|
||||
info!(LOGGER, "Starting server, genesis block: {}", genesis.hash());
|
||||
info!("Starting server, genesis block: {}", genesis.hash());
|
||||
|
||||
let db_env = Arc::new(store::new_env(config.db_root.clone()));
|
||||
let shared_chain = Arc::new(chain::Chain::init(
|
||||
@@ -170,8 +157,6 @@ impl Server {
|
||||
|
||||
pool_adapter.set_chain(shared_chain.clone());
|
||||
|
||||
let awaiting_peers = Arc::new(AtomicBool::new(false));
|
||||
|
||||
let net_adapter = Arc::new(NetToChainAdapter::new(
|
||||
sync_state.clone(),
|
||||
archive_mode,
|
||||
@@ -181,11 +166,6 @@ impl Server {
|
||||
config.clone(),
|
||||
));
|
||||
|
||||
let block_1_hash = match shared_chain.get_header_by_height(1) {
|
||||
Ok(header) => Some(header.hash()),
|
||||
Err(_) => None,
|
||||
};
|
||||
|
||||
let peer_db_env = Arc::new(store::new_named_env(config.db_root.clone(), "peer".into()));
|
||||
let p2p_server = Arc::new(p2p::Server::new(
|
||||
peer_db_env,
|
||||
@@ -194,8 +174,6 @@ impl Server {
|
||||
net_adapter.clone(),
|
||||
genesis.hash(),
|
||||
stop.clone(),
|
||||
archive_mode,
|
||||
block_1_hash,
|
||||
)?);
|
||||
chain_adapter.init(p2p_server.peers.clone());
|
||||
pool_net_adapter.init(p2p_server.peers.clone());
|
||||
@@ -204,10 +182,7 @@ impl Server {
|
||||
if config.p2p_config.seeding_type.clone() != p2p::Seeding::Programmatic {
|
||||
let seeder = match config.p2p_config.seeding_type.clone() {
|
||||
p2p::Seeding::None => {
|
||||
warn!(
|
||||
LOGGER,
|
||||
"No seed configured, will stay solo until connected to"
|
||||
);
|
||||
warn!("No seed configured, will stay solo until connected to");
|
||||
seed::predefined_seeds(vec![])
|
||||
}
|
||||
p2p::Seeding::List => {
|
||||
@@ -234,18 +209,13 @@ impl Server {
|
||||
|
||||
// Defaults to None (optional) in config file.
|
||||
// This translates to false here so we do not skip by default.
|
||||
let skip_sync_wait = match config.skip_sync_wait {
|
||||
None => false,
|
||||
Some(b) => b,
|
||||
};
|
||||
let skip_sync_wait = config.skip_sync_wait.unwrap_or(false);
|
||||
sync_state.update(SyncStatus::AwaitingPeers(!skip_sync_wait));
|
||||
|
||||
sync::run_sync(
|
||||
sync_state.clone(),
|
||||
awaiting_peers.clone(),
|
||||
p2p_server.peers.clone(),
|
||||
shared_chain.clone(),
|
||||
skip_sync_wait,
|
||||
archive_mode,
|
||||
stop.clone(),
|
||||
);
|
||||
|
||||
@@ -254,7 +224,7 @@ impl Server {
|
||||
.name("p2p-server".to_string())
|
||||
.spawn(move || p2p_inner.listen());
|
||||
|
||||
info!(LOGGER, "Starting rest apis at: {}", &config.api_http_addr);
|
||||
info!("Starting rest apis at: {}", &config.api_http_addr);
|
||||
let api_secret = get_first_line(config.api_secret_path.clone());
|
||||
api::start_rest_apis(
|
||||
config.api_http_addr.clone(),
|
||||
@@ -265,10 +235,7 @@ impl Server {
|
||||
None,
|
||||
);
|
||||
|
||||
info!(
|
||||
LOGGER,
|
||||
"Starting dandelion monitor: {}", &config.api_http_addr
|
||||
);
|
||||
info!("Starting dandelion monitor: {}", &config.api_http_addr);
|
||||
dandelion_monitor::monitor_transactions(
|
||||
config.dandelion_config.clone(),
|
||||
tx_pool.clone(),
|
||||
@@ -276,7 +243,7 @@ impl Server {
|
||||
stop.clone(),
|
||||
);
|
||||
|
||||
warn!(LOGGER, "Grin server started.");
|
||||
warn!("Grin server started.");
|
||||
Ok(Server {
|
||||
config,
|
||||
p2p: p2p_server,
|
||||
@@ -285,7 +252,6 @@ impl Server {
|
||||
verifier_cache,
|
||||
sync_state,
|
||||
state_info: ServerStateInfo {
|
||||
awaiting_peers: awaiting_peers,
|
||||
..Default::default()
|
||||
},
|
||||
stop,
|
||||
@@ -335,7 +301,7 @@ impl Server {
|
||||
/// internal miner, and should only be used for automated testing. Burns
|
||||
/// reward if wallet_listener_url is 'None'
|
||||
pub fn start_test_miner(&self, wallet_listener_url: Option<String>, stop: Arc<AtomicBool>) {
|
||||
info!(LOGGER, "start_test_miner - start",);
|
||||
info!("start_test_miner - start",);
|
||||
let sync_state = self.sync_state.clone();
|
||||
let config_wallet_url = match wallet_listener_url.clone() {
|
||||
Some(u) => u,
|
||||
@@ -388,8 +354,7 @@ impl Server {
|
||||
/// other
|
||||
/// consumers
|
||||
pub fn get_server_stats(&self) -> Result<ServerStats, Error> {
|
||||
let stratum_stats = self.state_info.stratum_stats.read().unwrap().clone();
|
||||
let awaiting_peers = self.state_info.awaiting_peers.load(Ordering::Relaxed);
|
||||
let stratum_stats = self.state_info.stratum_stats.read().clone();
|
||||
|
||||
// Fill out stats on our current difficulty calculation
|
||||
// TODO: check the overhead of calculating this again isn't too much
|
||||
@@ -406,7 +371,6 @@ impl Server {
|
||||
let mut last_time = last_blocks[0].timestamp;
|
||||
let tip_height = self.chain.head().unwrap().height as i64;
|
||||
let earliest_block_height = tip_height as i64 - last_blocks.len() as i64;
|
||||
|
||||
let mut i = 1;
|
||||
|
||||
let diff_entries: Vec<DiffBlock> = last_blocks
|
||||
@@ -414,7 +378,7 @@ impl Server {
|
||||
.skip(1)
|
||||
.map(|n| {
|
||||
let dur = n.timestamp - last_time;
|
||||
let height = earliest_block_height + i + 1;
|
||||
let height = earliest_block_height + i;
|
||||
i += 1;
|
||||
last_time = n.timestamp;
|
||||
DiffBlock {
|
||||
@@ -450,7 +414,6 @@ impl Server {
|
||||
head: self.head(),
|
||||
header_head: self.header_head(),
|
||||
sync_status: self.sync_state.status(),
|
||||
awaiting_peers: awaiting_peers,
|
||||
stratum_stats: stratum_stats,
|
||||
peer_stats: peer_stats,
|
||||
diff_stats: diff_stats,
|
||||
@@ -466,6 +429,6 @@ impl Server {
|
||||
/// Stops the test miner without stopping the p2p layer
|
||||
pub fn stop_test_miner(&self, stop: Arc<AtomicBool>) {
|
||||
stop.store(true, Ordering::Relaxed);
|
||||
info!(LOGGER, "stop_test_miner - stop",);
|
||||
info!("stop_test_miner - stop",);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ use common::types::{SyncState, SyncStatus};
|
||||
use core::core::hash::{Hash, Hashed, ZERO_HASH};
|
||||
use core::global;
|
||||
use p2p;
|
||||
use util::LOGGER;
|
||||
|
||||
pub struct BodySync {
|
||||
chain: Arc<chain::Chain>,
|
||||
@@ -87,14 +86,13 @@ impl BodySync {
|
||||
|
||||
fn body_sync(&mut self) {
|
||||
let horizon = global::cut_through_horizon() as u64;
|
||||
let body_head: chain::Tip = self.chain.head().unwrap();
|
||||
let header_head: chain::Tip = self.chain.header_head().unwrap();
|
||||
let sync_head: chain::Tip = self.chain.get_sync_head().unwrap();
|
||||
let body_head = self.chain.head().unwrap();
|
||||
let header_head = self.chain.header_head().unwrap();
|
||||
let sync_head = self.chain.get_sync_head().unwrap();
|
||||
|
||||
self.reset();
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"body_sync: body_head - {}, {}, header_head - {}, {}, sync_head - {}, {}",
|
||||
body_head.last_block_h,
|
||||
body_head.height,
|
||||
@@ -123,15 +121,16 @@ impl BodySync {
|
||||
}
|
||||
hashes.reverse();
|
||||
|
||||
if oldest_height < header_head.height.saturating_sub(horizon) {
|
||||
debug!("body_sync: cannot sync full blocks earlier than horizon.");
|
||||
return;
|
||||
}
|
||||
|
||||
let peers = self.peers.more_work_peers();
|
||||
|
||||
// if we have 5 peers to sync from then ask for 50 blocks total (peer_count *
|
||||
// 10) max will be 80 if all 8 peers are advertising more work
|
||||
// also if the chain is already saturated with orphans, throttle
|
||||
let peers = if oldest_height < header_head.height.saturating_sub(horizon) {
|
||||
self.peers.more_work_archival_peers()
|
||||
} else {
|
||||
self.peers.more_work_peers()
|
||||
};
|
||||
|
||||
let block_count = cmp::min(
|
||||
cmp::min(100, peers.len() * p2p::SEND_CHANNEL_CAP),
|
||||
chain::MAX_ORPHAN_SIZE.saturating_sub(self.chain.orphans_len()) + 1,
|
||||
@@ -148,7 +147,6 @@ impl BodySync {
|
||||
|
||||
if hashes_to_get.len() > 0 {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"block_sync: {}/{} requesting blocks {:?} from {} peers",
|
||||
body_head.height,
|
||||
header_head.height,
|
||||
@@ -161,7 +159,7 @@ impl BodySync {
|
||||
for hash in hashes_to_get.clone() {
|
||||
if let Some(peer) = peers_iter.next() {
|
||||
if let Err(e) = peer.send_block_request(*hash) {
|
||||
debug!(LOGGER, "Skipped request to {}: {:?}", peer.info.addr, e);
|
||||
debug!("Skipped request to {}: {:?}", peer.info.addr, e);
|
||||
} else {
|
||||
self.body_sync_hashes.push(hash.clone());
|
||||
}
|
||||
@@ -199,7 +197,6 @@ impl BodySync {
|
||||
.filter(|x| !self.chain.get_block(*x).is_ok() && !self.chain.is_orphan(*x))
|
||||
.collect::<Vec<_>>();
|
||||
debug!(
|
||||
LOGGER,
|
||||
"body_sync: {}/{} blocks received, and no more in 200ms",
|
||||
self.body_sync_hashes.len() - hashes_not_get.len(),
|
||||
self.body_sync_hashes.len(),
|
||||
@@ -210,7 +207,6 @@ impl BodySync {
|
||||
None => {
|
||||
if Utc::now() - self.sync_start_ts > Duration::seconds(5) {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"body_sync: 0/{} blocks received in 5s",
|
||||
self.body_sync_hashes.len(),
|
||||
);
|
||||
|
||||
@@ -20,7 +20,6 @@ use chain;
|
||||
use common::types::{Error, SyncState, SyncStatus};
|
||||
use core::core::hash::{Hash, Hashed};
|
||||
use p2p::{self, Peer};
|
||||
use util::LOGGER;
|
||||
|
||||
pub struct HeaderSync {
|
||||
sync_state: Arc<SyncState>,
|
||||
@@ -55,12 +54,11 @@ impl HeaderSync {
|
||||
|
||||
let enable_header_sync = match status {
|
||||
SyncStatus::BodySync { .. } | SyncStatus::HeaderSync { .. } => true,
|
||||
SyncStatus::NoSync | SyncStatus::Initial => {
|
||||
SyncStatus::NoSync | SyncStatus::Initial | SyncStatus::AwaitingPeers(_) => {
|
||||
// Reset sync_head to header_head on transition to HeaderSync,
|
||||
// but ONLY on initial transition to HeaderSync state.
|
||||
let sync_head = self.chain.get_sync_head().unwrap();
|
||||
debug!(
|
||||
LOGGER,
|
||||
"sync: initial transition to HeaderSync. sync_head: {} at {}, reset to: {} at {}",
|
||||
sync_head.hash(),
|
||||
sync_head.height,
|
||||
@@ -104,7 +102,7 @@ impl HeaderSync {
|
||||
|
||||
// always enable header sync on initial state transition from NoSync / Initial
|
||||
let force_sync = match self.sync_state.status() {
|
||||
SyncStatus::NoSync | SyncStatus::Initial => true,
|
||||
SyncStatus::NoSync | SyncStatus::Initial | SyncStatus::AwaitingPeers(_) => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
@@ -141,8 +139,8 @@ impl HeaderSync {
|
||||
fn request_headers(&mut self, peer: &Peer) {
|
||||
if let Ok(locator) = self.get_locator() {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"sync: request_headers: asking {} for headers, {:?}", peer.info.addr, locator,
|
||||
"sync: request_headers: asking {} for headers, {:?}",
|
||||
peer.info.addr, locator,
|
||||
);
|
||||
|
||||
let _ = peer.send_header_request(locator);
|
||||
@@ -165,7 +163,7 @@ impl HeaderSync {
|
||||
self.history_locators.clear();
|
||||
}
|
||||
|
||||
debug!(LOGGER, "sync: locator heights : {:?}", heights);
|
||||
debug!("sync: locator heights : {:?}", heights);
|
||||
|
||||
let mut locator: Vec<Hash> = vec![];
|
||||
let mut current = self.chain.get_block_header(&tip.last_block_h);
|
||||
@@ -237,7 +235,7 @@ impl HeaderSync {
|
||||
}
|
||||
}
|
||||
|
||||
debug!(LOGGER, "sync: locator heights': {:?}", new_heights);
|
||||
debug!("sync: locator heights': {:?}", new_heights);
|
||||
|
||||
// shrink history_locators properly
|
||||
if heights.len() > 1 {
|
||||
@@ -258,14 +256,13 @@ impl HeaderSync {
|
||||
}
|
||||
}
|
||||
debug!(
|
||||
LOGGER,
|
||||
"sync: history locators: len={}, shrunk={}",
|
||||
self.history_locators.len(),
|
||||
shrunk_size
|
||||
);
|
||||
}
|
||||
|
||||
debug!(LOGGER, "sync: locator: {:?}", locator);
|
||||
debug!("sync: locator: {:?}", locator);
|
||||
|
||||
Ok(locator)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ use common::types::{Error, SyncState, SyncStatus};
|
||||
use core::core::hash::Hashed;
|
||||
use core::global;
|
||||
use p2p::{self, Peer};
|
||||
use util::LOGGER;
|
||||
|
||||
/// Fast sync has 3 "states":
|
||||
/// * syncing headers
|
||||
@@ -33,7 +32,6 @@ pub struct StateSync {
|
||||
sync_state: Arc<SyncState>,
|
||||
peers: Arc<p2p::Peers>,
|
||||
chain: Arc<chain::Chain>,
|
||||
archive_mode: bool,
|
||||
|
||||
prev_fast_sync: Option<DateTime<Utc>>,
|
||||
fast_sync_peer: Option<Arc<Peer>>,
|
||||
@@ -44,13 +42,11 @@ impl StateSync {
|
||||
sync_state: Arc<SyncState>,
|
||||
peers: Arc<p2p::Peers>,
|
||||
chain: Arc<chain::Chain>,
|
||||
archive_mode: bool,
|
||||
) -> StateSync {
|
||||
StateSync {
|
||||
sync_state,
|
||||
peers,
|
||||
chain,
|
||||
archive_mode,
|
||||
prev_fast_sync: None,
|
||||
fast_sync_peer: None,
|
||||
}
|
||||
@@ -65,8 +61,8 @@ impl StateSync {
|
||||
head: &chain::Tip,
|
||||
highest_height: u64,
|
||||
) -> bool {
|
||||
let need_state_sync = !self.archive_mode
|
||||
&& highest_height.saturating_sub(head.height) > global::cut_through_horizon() as u64;
|
||||
let need_state_sync =
|
||||
highest_height.saturating_sub(head.height) > global::cut_through_horizon() as u64;
|
||||
if !need_state_sync {
|
||||
return false;
|
||||
}
|
||||
@@ -76,11 +72,8 @@ impl StateSync {
|
||||
// check sync error
|
||||
{
|
||||
let clone = self.sync_state.sync_error();
|
||||
if let Some(ref sync_error) = *clone.read().unwrap() {
|
||||
error!(
|
||||
LOGGER,
|
||||
"fast_sync: error = {:?}. restart fast sync", sync_error
|
||||
);
|
||||
if let Some(ref sync_error) = *clone.read() {
|
||||
error!("fast_sync: error = {:?}. restart fast sync", sync_error);
|
||||
sync_need_restart = true;
|
||||
}
|
||||
drop(clone);
|
||||
@@ -92,8 +85,8 @@ impl StateSync {
|
||||
if !peer.is_connected() {
|
||||
sync_need_restart = true;
|
||||
info!(
|
||||
LOGGER,
|
||||
"fast_sync: peer connection lost: {:?}. restart", peer.info.addr,
|
||||
"fast_sync: peer connection lost: {:?}. restart",
|
||||
peer.info.addr,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -110,10 +103,7 @@ impl StateSync {
|
||||
|
||||
if let SyncStatus::TxHashsetDownload { .. } = self.sync_state.status() {
|
||||
if download_timeout {
|
||||
error!(
|
||||
LOGGER,
|
||||
"fast_sync: TxHashsetDownload status timeout in 10 minutes!"
|
||||
);
|
||||
error!("fast_sync: TxHashsetDownload status timeout in 10 minutes!");
|
||||
self.sync_state
|
||||
.set_sync_error(Error::P2P(p2p::Error::Timeout));
|
||||
}
|
||||
@@ -168,7 +158,6 @@ impl StateSync {
|
||||
}
|
||||
let bhash = txhashset_head.hash();
|
||||
debug!(
|
||||
LOGGER,
|
||||
"fast_sync: before txhashset request, header head: {} / {}, txhashset_head: {} / {}",
|
||||
header_head.height,
|
||||
header_head.last_block_h,
|
||||
@@ -176,7 +165,7 @@ impl StateSync {
|
||||
bhash
|
||||
);
|
||||
if let Err(e) = peer.send_txhashset_request(txhashset_head.height, bhash) {
|
||||
error!(LOGGER, "fast_sync: send_txhashset_request err! {:?}", e);
|
||||
error!("fast_sync: send_txhashset_request err! {:?}", e);
|
||||
return Err(e);
|
||||
}
|
||||
return Ok(peer.clone());
|
||||
|
||||
+156
-152
@@ -23,184 +23,188 @@ use core::pow::Difficulty;
|
||||
use grin::sync::body_sync::BodySync;
|
||||
use grin::sync::header_sync::HeaderSync;
|
||||
use grin::sync::state_sync::StateSync;
|
||||
use p2p::{self, Peers};
|
||||
use util::LOGGER;
|
||||
use p2p;
|
||||
|
||||
pub fn run_sync(
|
||||
sync_state: Arc<SyncState>,
|
||||
awaiting_peers: Arc<AtomicBool>,
|
||||
peers: Arc<p2p::Peers>,
|
||||
chain: Arc<chain::Chain>,
|
||||
skip_sync_wait: bool,
|
||||
archive_mode: bool,
|
||||
stop: Arc<AtomicBool>,
|
||||
) {
|
||||
let _ = thread::Builder::new()
|
||||
.name("sync".to_string())
|
||||
.spawn(move || {
|
||||
sync_loop(
|
||||
sync_state,
|
||||
awaiting_peers,
|
||||
peers,
|
||||
chain,
|
||||
skip_sync_wait,
|
||||
archive_mode,
|
||||
stop,
|
||||
)
|
||||
let runner = SyncRunner::new(sync_state, peers, chain, stop);
|
||||
runner.sync_loop();
|
||||
});
|
||||
}
|
||||
|
||||
fn wait_for_min_peers(
|
||||
awaiting_peers: Arc<AtomicBool>,
|
||||
peers: Arc<p2p::Peers>,
|
||||
chain: Arc<chain::Chain>,
|
||||
skip_sync_wait: bool,
|
||||
) {
|
||||
// Initial sleep to give us time to peer with some nodes.
|
||||
// Note: Even if we have "skip_sync_wait" we need to wait a
|
||||
// short period of time for tests to do the right thing.
|
||||
let wait_secs = if skip_sync_wait { 3 } else { 30 };
|
||||
|
||||
let head = chain.head().unwrap();
|
||||
|
||||
awaiting_peers.store(true, Ordering::Relaxed);
|
||||
let mut n = 0;
|
||||
const MIN_PEERS: usize = 3;
|
||||
loop {
|
||||
let wp = peers.more_work_peers();
|
||||
// exit loop when:
|
||||
// * we have more than MIN_PEERS more_work peers
|
||||
// * we are synced already, e.g. grin was quickly restarted
|
||||
// * timeout
|
||||
if wp.len() > MIN_PEERS
|
||||
|| (wp.len() == 0 && peers.enough_peers() && head.total_difficulty > Difficulty::zero())
|
||||
|| n > wait_secs
|
||||
{
|
||||
break;
|
||||
}
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
n += 1;
|
||||
}
|
||||
awaiting_peers.store(false, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Starts the syncing loop, just spawns two threads that loop forever
|
||||
fn sync_loop(
|
||||
pub struct SyncRunner {
|
||||
sync_state: Arc<SyncState>,
|
||||
awaiting_peers: Arc<AtomicBool>,
|
||||
peers: Arc<p2p::Peers>,
|
||||
chain: Arc<chain::Chain>,
|
||||
skip_sync_wait: bool,
|
||||
archive_mode: bool,
|
||||
stop: Arc<AtomicBool>,
|
||||
) {
|
||||
// Wait for connections reach at least MIN_PEERS
|
||||
wait_for_min_peers(awaiting_peers, peers.clone(), chain.clone(), skip_sync_wait);
|
||||
|
||||
// Our 3 main sync stages
|
||||
let mut header_sync = HeaderSync::new(sync_state.clone(), peers.clone(), chain.clone());
|
||||
let mut body_sync = BodySync::new(sync_state.clone(), peers.clone(), chain.clone());
|
||||
let mut state_sync = StateSync::new(
|
||||
sync_state.clone(),
|
||||
peers.clone(),
|
||||
chain.clone(),
|
||||
archive_mode,
|
||||
);
|
||||
|
||||
// Highest height seen on the network, generally useful for a fast test on
|
||||
// whether some sync is needed
|
||||
let mut highest_height = 0;
|
||||
|
||||
// Main syncing loop
|
||||
while !stop.load(Ordering::Relaxed) {
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
|
||||
// check whether syncing is generally needed, when we compare our state with others
|
||||
let (syncing, most_work_height) =
|
||||
needs_syncing(sync_state.as_ref(), peers.clone(), chain.clone());
|
||||
|
||||
if most_work_height > 0 {
|
||||
// we can occasionally get a most work height of 0 if read locks fail
|
||||
highest_height = most_work_height;
|
||||
}
|
||||
|
||||
// quick short-circuit (and a decent sleep) if no syncing is needed
|
||||
if !syncing {
|
||||
sync_state.update(SyncStatus::NoSync);
|
||||
thread::sleep(time::Duration::from_secs(10));
|
||||
continue;
|
||||
}
|
||||
|
||||
// if syncing is needed
|
||||
let head = chain.head().unwrap();
|
||||
let header_head = chain.header_head().unwrap();
|
||||
|
||||
// run each sync stage, each of them deciding whether they're needed
|
||||
// except for body sync that only runs if state sync is off or done
|
||||
header_sync.check_run(&header_head, highest_height);
|
||||
if !state_sync.check_run(&header_head, &head, highest_height) {
|
||||
body_sync.check_run(&head, highest_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether we're currently syncing the chain or we're fully caught up and
|
||||
/// just receiving blocks through gossip.
|
||||
fn needs_syncing(
|
||||
sync_state: &SyncState,
|
||||
peers: Arc<Peers>,
|
||||
chain: Arc<chain::Chain>,
|
||||
) -> (bool, u64) {
|
||||
let local_diff = chain.head().unwrap().total_difficulty;
|
||||
let peer = peers.most_work_peer();
|
||||
let is_syncing = sync_state.is_syncing();
|
||||
let mut most_work_height = 0;
|
||||
impl SyncRunner {
|
||||
fn new(
|
||||
sync_state: Arc<SyncState>,
|
||||
peers: Arc<p2p::Peers>,
|
||||
chain: Arc<chain::Chain>,
|
||||
stop: Arc<AtomicBool>,
|
||||
) -> SyncRunner {
|
||||
SyncRunner {
|
||||
sync_state,
|
||||
peers,
|
||||
chain,
|
||||
stop,
|
||||
}
|
||||
}
|
||||
|
||||
// if we're already syncing, we're caught up if no peer has a higher
|
||||
// difficulty than us
|
||||
if is_syncing {
|
||||
if let Some(peer) = peer {
|
||||
most_work_height = peer.info.height();
|
||||
if peer.info.total_difficulty() <= local_diff {
|
||||
let ch = chain.head().unwrap();
|
||||
info!(
|
||||
LOGGER,
|
||||
"synchronized at {} @ {} [{}]",
|
||||
local_diff.to_num(),
|
||||
ch.height,
|
||||
ch.last_block_h
|
||||
);
|
||||
fn wait_for_min_peers(&self) {
|
||||
// Initial sleep to give us time to peer with some nodes.
|
||||
// Note: Even if we have skip peer wait we need to wait a
|
||||
// short period of time for tests to do the right thing.
|
||||
let wait_secs = if let SyncStatus::AwaitingPeers(true) = self.sync_state.status() {
|
||||
30
|
||||
} else {
|
||||
3
|
||||
};
|
||||
|
||||
let _ = chain.reset_head();
|
||||
return (false, most_work_height);
|
||||
let head = self.chain.head().unwrap();
|
||||
|
||||
let mut n = 0;
|
||||
const MIN_PEERS: usize = 3;
|
||||
loop {
|
||||
let wp = self.peers.more_work_peers();
|
||||
// exit loop when:
|
||||
// * we have more than MIN_PEERS more_work peers
|
||||
// * we are synced already, e.g. grin was quickly restarted
|
||||
// * timeout
|
||||
if wp.len() > MIN_PEERS
|
||||
|| (wp.len() == 0
|
||||
&& self.peers.enough_peers()
|
||||
&& head.total_difficulty > Difficulty::zero())
|
||||
|| n > wait_secs
|
||||
{
|
||||
break;
|
||||
}
|
||||
thread::sleep(time::Duration::from_secs(1));
|
||||
n += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts the syncing loop, just spawns two threads that loop forever
|
||||
fn sync_loop(&self) {
|
||||
// Wait for connections reach at least MIN_PEERS
|
||||
self.wait_for_min_peers();
|
||||
|
||||
// Our 3 main sync stages
|
||||
let mut header_sync = HeaderSync::new(
|
||||
self.sync_state.clone(),
|
||||
self.peers.clone(),
|
||||
self.chain.clone(),
|
||||
);
|
||||
let mut body_sync = BodySync::new(
|
||||
self.sync_state.clone(),
|
||||
self.peers.clone(),
|
||||
self.chain.clone(),
|
||||
);
|
||||
let mut state_sync = StateSync::new(
|
||||
self.sync_state.clone(),
|
||||
self.peers.clone(),
|
||||
self.chain.clone(),
|
||||
);
|
||||
|
||||
// Highest height seen on the network, generally useful for a fast test on
|
||||
// whether some sync is needed
|
||||
let mut highest_height = 0;
|
||||
|
||||
// Main syncing loop
|
||||
while !self.stop.load(Ordering::Relaxed) {
|
||||
thread::sleep(time::Duration::from_millis(10));
|
||||
|
||||
// check whether syncing is generally needed, when we compare our state with others
|
||||
let (syncing, most_work_height) = self.needs_syncing();
|
||||
|
||||
if most_work_height > 0 {
|
||||
// we can occasionally get a most work height of 0 if read locks fail
|
||||
highest_height = most_work_height;
|
||||
}
|
||||
|
||||
// quick short-circuit (and a decent sleep) if no syncing is needed
|
||||
if !syncing {
|
||||
self.sync_state.update(SyncStatus::NoSync);
|
||||
thread::sleep(time::Duration::from_secs(10));
|
||||
continue;
|
||||
}
|
||||
|
||||
// if syncing is needed
|
||||
let head = self.chain.head().unwrap();
|
||||
let header_head = self.chain.header_head().unwrap();
|
||||
|
||||
// run each sync stage, each of them deciding whether they're needed
|
||||
// except for body sync that only runs if state sync is off or done
|
||||
header_sync.check_run(&header_head, highest_height);
|
||||
if !state_sync.check_run(&header_head, &head, highest_height) {
|
||||
body_sync.check_run(&head, highest_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether we're currently syncing the chain or we're fully caught up and
|
||||
/// just receiving blocks through gossip.
|
||||
fn needs_syncing(&self) -> (bool, u64) {
|
||||
let local_diff = self.chain.head().unwrap().total_difficulty;
|
||||
let peer = self.peers.most_work_peer();
|
||||
let is_syncing = self.sync_state.is_syncing();
|
||||
let mut most_work_height = 0;
|
||||
|
||||
// if we're already syncing, we're caught up if no peer has a higher
|
||||
// difficulty than us
|
||||
if is_syncing {
|
||||
if let Some(peer) = peer {
|
||||
most_work_height = peer.info.height();
|
||||
if peer.info.total_difficulty() <= local_diff {
|
||||
let ch = self.chain.head().unwrap();
|
||||
info!(
|
||||
"synchronized at {} @ {} [{}]",
|
||||
local_diff.to_num(),
|
||||
ch.height,
|
||||
ch.last_block_h
|
||||
);
|
||||
|
||||
let _ = self.chain.reset_head();
|
||||
return (false, most_work_height);
|
||||
}
|
||||
} else {
|
||||
warn!("sync: no peers available, disabling sync");
|
||||
return (false, 0);
|
||||
}
|
||||
} else {
|
||||
warn!(LOGGER, "sync: no peers available, disabling sync");
|
||||
return (false, 0);
|
||||
}
|
||||
} else {
|
||||
if let Some(peer) = peer {
|
||||
most_work_height = peer.info.height();
|
||||
if let Some(peer) = peer {
|
||||
most_work_height = peer.info.height();
|
||||
|
||||
// sum the last 5 difficulties to give us the threshold
|
||||
let threshold = chain
|
||||
.difficulty_iter()
|
||||
.map(|x| x.difficulty)
|
||||
.take(5)
|
||||
.fold(Difficulty::zero(), |sum, val| sum + val);
|
||||
// sum the last 5 difficulties to give us the threshold
|
||||
let threshold = self
|
||||
.chain
|
||||
.difficulty_iter()
|
||||
.map(|x| x.difficulty)
|
||||
.take(5)
|
||||
.fold(Difficulty::zero(), |sum, val| sum + val);
|
||||
|
||||
let peer_diff = peer.info.total_difficulty();
|
||||
if peer_diff > local_diff.clone() + threshold.clone() {
|
||||
info!(
|
||||
LOGGER,
|
||||
"sync: total_difficulty {}, peer_difficulty {}, threshold {} (last 5 blocks), enabling sync",
|
||||
local_diff,
|
||||
peer_diff,
|
||||
threshold,
|
||||
);
|
||||
return (true, most_work_height);
|
||||
let peer_diff = peer.info.total_difficulty();
|
||||
if peer_diff > local_diff.clone() + threshold.clone() {
|
||||
info!(
|
||||
"sync: total_difficulty {}, peer_difficulty {}, threshold {} (last 5 blocks), enabling sync",
|
||||
local_diff,
|
||||
peer_diff,
|
||||
threshold,
|
||||
);
|
||||
return (true, most_work_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
(is_syncing, most_work_height)
|
||||
}
|
||||
(is_syncing, most_work_height)
|
||||
}
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ extern crate serde;
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
#[macro_use]
|
||||
extern crate slog;
|
||||
extern crate log;
|
||||
extern crate chrono;
|
||||
|
||||
extern crate grin_api as api;
|
||||
|
||||
@@ -17,9 +17,10 @@
|
||||
|
||||
use chrono::prelude::{DateTime, NaiveDateTime, Utc};
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use util::RwLock;
|
||||
|
||||
use chain;
|
||||
use common::types::Error;
|
||||
@@ -27,7 +28,7 @@ use core::core::verifier_cache::VerifierCache;
|
||||
use core::{consensus, core, ser};
|
||||
use keychain::{ExtKeychain, Identifier, Keychain};
|
||||
use pool;
|
||||
use util::{self, LOGGER};
|
||||
use util;
|
||||
use wallet::{self, BlockFees};
|
||||
|
||||
// Ensure a block suitable for mining is built and returned
|
||||
@@ -54,24 +55,22 @@ pub fn get_block(
|
||||
self::Error::Chain(c) => match c.kind() {
|
||||
chain::ErrorKind::DuplicateCommitment(_) => {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Duplicate commit for potential coinbase detected. Trying next derivation."
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
error!(LOGGER, "Chain Error: {}", c);
|
||||
error!("Chain Error: {}", c);
|
||||
}
|
||||
},
|
||||
self::Error::Wallet(_) => {
|
||||
error!(
|
||||
LOGGER,
|
||||
"Error building new block: Can't connect to wallet listener at {:?}; will retry",
|
||||
wallet_listener_url.as_ref().unwrap()
|
||||
);
|
||||
thread::sleep(Duration::from_secs(wallet_retry_interval));
|
||||
}
|
||||
ae => {
|
||||
warn!(LOGGER, "Error building new block: {:?}. Retrying.", ae);
|
||||
warn!("Error building new block: {:?}. Retrying.", ae);
|
||||
}
|
||||
}
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
@@ -106,15 +105,10 @@ fn build_block(
|
||||
|
||||
// Determine the difficulty our block should be at.
|
||||
// Note: do not keep the difficulty_iter in scope (it has an active batch).
|
||||
let difficulty = consensus::next_difficulty(1, chain.difficulty_iter());
|
||||
let difficulty = consensus::next_difficulty(head.height + 1, chain.difficulty_iter());
|
||||
|
||||
// extract current transaction from the pool
|
||||
// TODO - we have a lot of unwrap() going on in this fn...
|
||||
let txs = tx_pool
|
||||
.read()
|
||||
.unwrap()
|
||||
.prepare_mineable_transactions()
|
||||
.unwrap();
|
||||
let txs = tx_pool.read().prepare_mineable_transactions()?;
|
||||
|
||||
// build the coinbase and the block itself
|
||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||
@@ -137,7 +131,6 @@ fn build_block(
|
||||
|
||||
let b_difficulty = (b.header.total_difficulty() - head.total_difficulty()).to_num();
|
||||
debug!(
|
||||
LOGGER,
|
||||
"Built new block with {} inputs and {} outputs, network difficulty: {}, cumulative difficulty {}",
|
||||
b.inputs().len(),
|
||||
b.outputs().len(),
|
||||
@@ -162,10 +155,7 @@ fn build_block(
|
||||
|
||||
//Some other issue, possibly duplicate kernel
|
||||
_ => {
|
||||
error!(
|
||||
LOGGER,
|
||||
"Error setting txhashset root to build a block: {:?}", e
|
||||
);
|
||||
error!("Error setting txhashset root to build a block: {:?}", e);
|
||||
Err(Error::Chain(
|
||||
chain::ErrorKind::Other(format!("{:?}", e)).into(),
|
||||
))
|
||||
@@ -179,7 +169,7 @@ fn build_block(
|
||||
/// Probably only want to do this when testing.
|
||||
///
|
||||
fn burn_reward(block_fees: BlockFees) -> Result<(core::Output, core::TxKernel, BlockFees), Error> {
|
||||
warn!(LOGGER, "Burning block fees: {:?}", block_fees);
|
||||
warn!("Burning block fees: {:?}", block_fees);
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||
let (out, kernel) =
|
||||
@@ -212,7 +202,7 @@ fn get_coinbase(
|
||||
..block_fees
|
||||
};
|
||||
|
||||
debug!(LOGGER, "get_coinbase: {:?}", block_fees);
|
||||
debug!("get_coinbase: {:?}", block_fees);
|
||||
return Ok((output, kernel, block_fees));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,10 @@ use serde_json::Value;
|
||||
use std::error::Error;
|
||||
use std::io::{BufRead, ErrorKind, Write};
|
||||
use std::net::{TcpListener, TcpStream};
|
||||
use std::sync::{Arc, Mutex, RwLock};
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{cmp, thread};
|
||||
use util::{Mutex, RwLock};
|
||||
|
||||
use chain;
|
||||
use common::stats::{StratumStats, WorkerStats};
|
||||
@@ -34,7 +35,7 @@ use core::{pow, ser};
|
||||
use keychain;
|
||||
use mining::mine_block;
|
||||
use pool;
|
||||
use util::{self, LOGGER};
|
||||
use util;
|
||||
|
||||
// ----------------------------------------
|
||||
// http://www.jsonrpc.org/specification
|
||||
@@ -113,7 +114,6 @@ fn accept_workers(
|
||||
match stream {
|
||||
Ok(stream) => {
|
||||
warn!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) New connection: {}",
|
||||
id,
|
||||
stream.peer_addr().unwrap()
|
||||
@@ -122,22 +122,19 @@ fn accept_workers(
|
||||
.set_nonblocking(true)
|
||||
.expect("set_nonblocking call failed");
|
||||
let mut worker = Worker::new(worker_id.to_string(), BufStream::new(stream));
|
||||
workers.lock().unwrap().push(worker);
|
||||
workers.lock().push(worker);
|
||||
// stats for this worker (worker stat objects are added and updated but never
|
||||
// removed)
|
||||
let mut worker_stats = WorkerStats::default();
|
||||
worker_stats.is_connected = true;
|
||||
worker_stats.id = worker_id.to_string();
|
||||
worker_stats.pow_difficulty = 1; // XXX TODO
|
||||
let mut stratum_stats = stratum_stats.write().unwrap();
|
||||
let mut stratum_stats = stratum_stats.write();
|
||||
stratum_stats.worker_stats.push(worker_stats);
|
||||
worker_id = worker_id + 1;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Error accepting connection: {:?}", id, e
|
||||
);
|
||||
warn!("(Server ID: {}) Error accepting connection: {:?}", id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -184,8 +181,8 @@ impl Worker {
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Error in connection with stratum client: {}", self.id, e
|
||||
"(Server ID: {}) Error in connection with stratum client: {}",
|
||||
self.id, e
|
||||
);
|
||||
self.error = true;
|
||||
return None;
|
||||
@@ -205,16 +202,16 @@ impl Worker {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Error in connection with stratum client: {}", self.id, e
|
||||
"(Server ID: {}) Error in connection with stratum client: {}",
|
||||
self.id, e
|
||||
);
|
||||
self.error = true;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
warn!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Error in connection with stratum client: {}", self.id, e
|
||||
"(Server ID: {}) Error in connection with stratum client: {}",
|
||||
self.id, e
|
||||
);
|
||||
self.error = true;
|
||||
return;
|
||||
@@ -285,7 +282,7 @@ impl StratumServer {
|
||||
|
||||
// Handle an RPC request message from the worker(s)
|
||||
fn handle_rpc_requests(&mut self, stratum_stats: &mut Arc<RwLock<StratumStats>>) {
|
||||
let mut workers_l = self.workers.lock().unwrap();
|
||||
let mut workers_l = self.workers.lock();
|
||||
for num in 0..workers_l.len() {
|
||||
match workers_l[num].read_message() {
|
||||
Some(the_message) => {
|
||||
@@ -295,7 +292,6 @@ impl StratumServer {
|
||||
Err(e) => {
|
||||
// not a valid JSON RpcRequest - disconnect the worker
|
||||
warn!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Failed to parse JSONRpc: {} - {:?}",
|
||||
self.id,
|
||||
e.description(),
|
||||
@@ -306,7 +302,7 @@ impl StratumServer {
|
||||
}
|
||||
};
|
||||
|
||||
let mut stratum_stats = stratum_stats.write().unwrap();
|
||||
let mut stratum_stats = stratum_stats.write();
|
||||
let worker_stats_id = stratum_stats
|
||||
.worker_stats
|
||||
.iter()
|
||||
@@ -408,11 +404,8 @@ impl StratumServer {
|
||||
let job_template = self.build_block_template();
|
||||
let response = serde_json::to_value(&job_template).unwrap();
|
||||
debug!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) sending block {} with id {} to single worker",
|
||||
self.id,
|
||||
job_template.height,
|
||||
job_template.job_id,
|
||||
self.id, job_template.height, job_template.job_id,
|
||||
);
|
||||
return Ok(response);
|
||||
}
|
||||
@@ -451,8 +444,8 @@ impl StratumServer {
|
||||
if params.height != self.current_block_versions.last().unwrap().header.height {
|
||||
// Return error status
|
||||
error!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Share at height {} submitted too late", self.id, params.height,
|
||||
"(Server ID: {}) Share at height {} submitted too late",
|
||||
self.id, params.height,
|
||||
);
|
||||
worker_stats.num_stale += 1;
|
||||
let e = RpcError {
|
||||
@@ -466,11 +459,8 @@ impl StratumServer {
|
||||
if b.is_none() {
|
||||
// Return error status
|
||||
error!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Failed to validate solution at height {}: invalid job_id {}",
|
||||
self.id,
|
||||
params.height,
|
||||
params.job_id,
|
||||
self.id, params.height, params.job_id,
|
||||
);
|
||||
worker_stats.num_rejected += 1;
|
||||
let e = RpcError {
|
||||
@@ -490,11 +480,8 @@ impl StratumServer {
|
||||
if share_difficulty < self.minimum_share_difficulty {
|
||||
// Return error status
|
||||
error!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Share rejected due to low difficulty: {}/{}",
|
||||
self.id,
|
||||
share_difficulty,
|
||||
self.minimum_share_difficulty,
|
||||
self.id, share_difficulty, self.minimum_share_difficulty,
|
||||
);
|
||||
worker_stats.num_rejected += 1;
|
||||
let e = RpcError {
|
||||
@@ -510,7 +497,6 @@ impl StratumServer {
|
||||
if let Err(e) = res {
|
||||
// Return error status
|
||||
error!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Failed to validate solution at height {}: {}: {}",
|
||||
self.id,
|
||||
params.height,
|
||||
@@ -527,15 +513,14 @@ impl StratumServer {
|
||||
share_is_block = true;
|
||||
// Log message to make it obvious we found a block
|
||||
warn!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Solution Found for block {} - Yay!!!", self.id, params.height
|
||||
"(Server ID: {}) Solution Found for block {} - Yay!!!",
|
||||
self.id, params.height
|
||||
);
|
||||
} else {
|
||||
// Do some validation but dont submit
|
||||
if !pow::verify_size(&b.header, b.header.pow.proof.edge_bits).is_ok() {
|
||||
// Return error status
|
||||
error!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Failed to validate share at height {} with nonce {} using job_id {}",
|
||||
self.id,
|
||||
params.height,
|
||||
@@ -556,7 +541,6 @@ impl StratumServer {
|
||||
Some(login) => login.clone(),
|
||||
};
|
||||
info!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Got share for block: hash {}, height {}, nonce {}, difficulty {}/{}, submitted by {}",
|
||||
self.id,
|
||||
b.hash(),
|
||||
@@ -582,18 +566,16 @@ impl StratumServer {
|
||||
// Purge dead/sick workers - remove all workers marked in error state
|
||||
fn clean_workers(&mut self, stratum_stats: &mut Arc<RwLock<StratumStats>>) -> usize {
|
||||
let mut start = 0;
|
||||
let mut workers_l = self.workers.lock().unwrap();
|
||||
let mut workers_l = self.workers.lock();
|
||||
loop {
|
||||
for num in start..workers_l.len() {
|
||||
if workers_l[num].error == true {
|
||||
warn!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Dropping worker: {}",
|
||||
self.id,
|
||||
workers_l[num].id;
|
||||
);
|
||||
"(Server ID: {}) Dropping worker: {}",
|
||||
self.id, workers_l[num].id
|
||||
);
|
||||
// Update worker stats
|
||||
let mut stratum_stats = stratum_stats.write().unwrap();
|
||||
let mut stratum_stats = stratum_stats.write();
|
||||
let worker_stats_id = stratum_stats
|
||||
.worker_stats
|
||||
.iter()
|
||||
@@ -607,7 +589,7 @@ impl StratumServer {
|
||||
start = num + 1;
|
||||
}
|
||||
if start >= workers_l.len() {
|
||||
let mut stratum_stats = stratum_stats.write().unwrap();
|
||||
let mut stratum_stats = stratum_stats.write();
|
||||
stratum_stats.num_workers = workers_l.len();
|
||||
return stratum_stats.num_workers;
|
||||
}
|
||||
@@ -630,16 +612,13 @@ impl StratumServer {
|
||||
};
|
||||
let job_request_json = serde_json::to_string(&job_request).unwrap();
|
||||
debug!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) sending block {} with id {} to stratum clients",
|
||||
self.id,
|
||||
job_template.height,
|
||||
job_template.job_id,
|
||||
self.id, job_template.height, job_template.job_id,
|
||||
);
|
||||
// Push the new block to all connected clients
|
||||
// NOTE: We do not give a unique nonce (should we?) so miners need
|
||||
// to choose one for themselves
|
||||
let mut workers_l = self.workers.lock().unwrap();
|
||||
let mut workers_l = self.workers.lock();
|
||||
for num in 0..workers_l.len() {
|
||||
workers_l[num].write_message(job_request_json.clone());
|
||||
}
|
||||
@@ -658,11 +637,8 @@ impl StratumServer {
|
||||
sync_state: Arc<SyncState>,
|
||||
) {
|
||||
info!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Starting stratum server with edge_bits = {}, proof_size = {}",
|
||||
self.id,
|
||||
edge_bits,
|
||||
proof_size
|
||||
self.id, edge_bits, proof_size
|
||||
);
|
||||
|
||||
self.sync_state = sync_state;
|
||||
@@ -691,13 +667,12 @@ impl StratumServer {
|
||||
|
||||
// We have started
|
||||
{
|
||||
let mut stratum_stats = stratum_stats.write().unwrap();
|
||||
let mut stratum_stats = stratum_stats.write();
|
||||
stratum_stats.is_running = true;
|
||||
stratum_stats.edge_bits = edge_bits as u16;
|
||||
}
|
||||
|
||||
warn!(
|
||||
LOGGER,
|
||||
"Stratum server started on {}",
|
||||
self.config.stratum_server_addr.clone().unwrap()
|
||||
);
|
||||
@@ -753,7 +728,7 @@ impl StratumServer {
|
||||
deadline = Utc::now().timestamp() + attempt_time_per_block as i64;
|
||||
|
||||
{
|
||||
let mut stratum_stats = stratum_stats.write().unwrap();
|
||||
let mut stratum_stats = stratum_stats.write();
|
||||
stratum_stats.block_height = new_block.header.height;
|
||||
stratum_stats.network_difficulty = self.current_difficulty;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
|
||||
use chrono::prelude::Utc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::sync::Arc;
|
||||
use util::RwLock;
|
||||
|
||||
use chain;
|
||||
use common::types::StratumServerConfig;
|
||||
@@ -30,7 +31,6 @@ use core::global;
|
||||
use core::pow::PoWContext;
|
||||
use mining::mine_block;
|
||||
use pool;
|
||||
use util::LOGGER;
|
||||
|
||||
pub struct Miner {
|
||||
config: StratumServerConfig,
|
||||
@@ -84,7 +84,6 @@ impl Miner {
|
||||
let deadline = Utc::now().timestamp() + attempt_time_per_block as i64;
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Mining Cuckoo{} for max {}s on {} @ {} [{}].",
|
||||
self.debug_output_id,
|
||||
global::min_edge_bits(),
|
||||
@@ -115,10 +114,8 @@ impl Miner {
|
||||
}
|
||||
|
||||
debug!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) No solution found after {} iterations, continuing...",
|
||||
self.debug_output_id,
|
||||
iter_count
|
||||
self.debug_output_id, iter_count
|
||||
);
|
||||
false
|
||||
}
|
||||
@@ -127,8 +124,8 @@ impl Miner {
|
||||
/// chain anytime required and looking for PoW solution.
|
||||
pub fn run_loop(&self, wallet_listener_url: Option<String>) {
|
||||
info!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Starting test miner loop.", self.debug_output_id
|
||||
"(Server ID: {}) Starting test miner loop.",
|
||||
self.debug_output_id
|
||||
);
|
||||
|
||||
// iteration, we keep the returned derivation to provide it back when
|
||||
@@ -136,7 +133,7 @@ impl Miner {
|
||||
let mut key_id = None;
|
||||
|
||||
while !self.stop.load(Ordering::Relaxed) {
|
||||
trace!(LOGGER, "in miner loop. key_id: {:?}", key_id);
|
||||
trace!("in miner loop. key_id: {:?}", key_id);
|
||||
|
||||
// get the latest chain state and build a block on top of it
|
||||
let head = self.chain.head_header().unwrap();
|
||||
@@ -160,7 +157,6 @@ impl Miner {
|
||||
// we found a solution, push our block through the chain processing pipeline
|
||||
if sol {
|
||||
info!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Found valid proof of work, adding block {}.",
|
||||
self.debug_output_id,
|
||||
b.hash()
|
||||
@@ -168,26 +164,21 @@ impl Miner {
|
||||
let res = self.chain.process_block(b, chain::Options::MINE);
|
||||
if let Err(e) = res {
|
||||
error!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) Error validating mined block: {:?}",
|
||||
self.debug_output_id,
|
||||
e
|
||||
self.debug_output_id, e
|
||||
);
|
||||
}
|
||||
trace!(LOGGER, "resetting key_id in miner to None");
|
||||
trace!("resetting key_id in miner to None");
|
||||
key_id = None;
|
||||
} else {
|
||||
debug!(
|
||||
LOGGER,
|
||||
"setting pubkey in miner to pubkey from block_fees - {:?}", block_fees
|
||||
"setting pubkey in miner to pubkey from block_fees - {:?}",
|
||||
block_fees
|
||||
);
|
||||
key_id = block_fees.key_id();
|
||||
}
|
||||
}
|
||||
|
||||
info!(
|
||||
LOGGER,
|
||||
"(Server ID: {}) test miner exit.", self.debug_output_id
|
||||
);
|
||||
info!("(Server ID: {}) test miner exit.", self.debug_output_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,8 +25,6 @@ use std::env;
|
||||
use std::io::Error;
|
||||
use std::thread;
|
||||
|
||||
use util::LOGGER;
|
||||
|
||||
/// Future returned from `MainService`.
|
||||
enum MainFuture {
|
||||
Root,
|
||||
@@ -94,10 +92,7 @@ pub fn start_webwallet_server() {
|
||||
let server = Server::bind(&addr)
|
||||
.serve(|| future::ok::<_, Error>(MainService::new()))
|
||||
.map_err(|e| eprintln!("server error: {}", e));
|
||||
warn!(
|
||||
LOGGER,
|
||||
"Grin Web-Wallet Application is running at http://{}/", addr
|
||||
);
|
||||
warn!("Grin Web-Wallet Application is running at http://{}/", addr);
|
||||
rt::run(server);
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user