implemented blocknotify option
This commit is contained in:
parent
d60820ca57
commit
07d4f00241
|
@ -694,12 +694,14 @@ dependencies = [
|
||||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"import 0.1.0",
|
"import 0.1.0",
|
||||||
"keys 0.1.0",
|
"keys 0.1.0",
|
||||||
|
"libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"logs 0.1.0",
|
"logs 0.1.0",
|
||||||
"message 0.1.0",
|
"message 0.1.0",
|
||||||
"miner 0.1.0",
|
"miner 0.1.0",
|
||||||
"network 0.1.0",
|
"network 0.1.0",
|
||||||
"p2p 0.1.0",
|
"p2p 0.1.0",
|
||||||
|
"primitives 0.1.0",
|
||||||
"rpc 0.1.0",
|
"rpc 0.1.0",
|
||||||
"script 0.1.0",
|
"script 0.1.0",
|
||||||
"sync 0.1.0",
|
"sync 0.1.0",
|
||||||
|
|
|
@ -9,6 +9,7 @@ description = "Parity bitcoin client."
|
||||||
log = "0.3"
|
log = "0.3"
|
||||||
env_logger = "0.3"
|
env_logger = "0.3"
|
||||||
app_dirs = "^1.1.1"
|
app_dirs = "^1.1.1"
|
||||||
|
libc = "0.2"
|
||||||
clap = { version = "2", features = ["yaml"] }
|
clap = { version = "2", features = ["yaml"] }
|
||||||
chain = { path = "chain" }
|
chain = { path = "chain" }
|
||||||
keys = { path = "keys" }
|
keys = { path = "keys" }
|
||||||
|
@ -24,6 +25,7 @@ import = { path = "import" }
|
||||||
bencher = { path = "bencher" }
|
bencher = { path = "bencher" }
|
||||||
logs = { path = "logs" }
|
logs = { path = "logs" }
|
||||||
rpc = { path = "rpc" }
|
rpc = { path = "rpc" }
|
||||||
|
primitives = { path = "primitives" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
path = "pbtc/main.rs"
|
path = "pbtc/main.rs"
|
||||||
|
|
|
@ -71,6 +71,11 @@ args:
|
||||||
help: List of allowed Host header values
|
help: List of allowed Host header values
|
||||||
takes_value: true
|
takes_value: true
|
||||||
value_name: HOSTS
|
value_name: HOSTS
|
||||||
|
- blocknotify:
|
||||||
|
long: blocknotify
|
||||||
|
help: Execute command when the best block changes (%s in cmd is replaced by block hash)
|
||||||
|
takes_value: true
|
||||||
|
value_name: command
|
||||||
subcommands:
|
subcommands:
|
||||||
- import:
|
- import:
|
||||||
about: Import blocks from bitcoin core database
|
about: Import blocks from bitcoin core database
|
||||||
|
|
|
@ -1,10 +1,87 @@
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use sync::{create_sync_peers, create_local_sync_node, create_sync_connection_factory};
|
use std::thread;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::mpsc::{channel, Sender, Receiver};
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
use sync::{create_sync_peers, create_local_sync_node, create_sync_connection_factory, SyncListener};
|
||||||
use message::Services;
|
use message::Services;
|
||||||
|
use primitives::hash::H256;
|
||||||
use util::{open_db, init_db, node_table_path};
|
use util::{open_db, init_db, node_table_path};
|
||||||
use {config, p2p, PROTOCOL_VERSION, PROTOCOL_MINIMUM};
|
use {config, p2p, PROTOCOL_VERSION, PROTOCOL_MINIMUM};
|
||||||
use super::super::rpc;
|
use super::super::rpc;
|
||||||
|
|
||||||
|
enum BlockNotifierTask {
|
||||||
|
NewBlock(H256),
|
||||||
|
Stop,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BlockNotifier {
|
||||||
|
tx: Sender<BlockNotifierTask>,
|
||||||
|
is_synchronizing: Arc<AtomicBool>,
|
||||||
|
worker_thread: Option<thread::JoinHandle<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockNotifier {
|
||||||
|
pub fn new(block_notify_command: String) -> Self {
|
||||||
|
let (tx, rx) = channel();
|
||||||
|
let is_synchronizing = Arc::new(AtomicBool::default());
|
||||||
|
BlockNotifier {
|
||||||
|
tx: tx,
|
||||||
|
is_synchronizing: is_synchronizing.clone(),
|
||||||
|
worker_thread: Some(thread::Builder::new()
|
||||||
|
.name("Block notification thread".to_owned())
|
||||||
|
.spawn(move || BlockNotifier::worker(rx, block_notify_command))
|
||||||
|
.expect("Error creating block notification thread"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn worker(rx: Receiver<BlockNotifierTask>, block_notify_command: String) {
|
||||||
|
for cmd in rx {
|
||||||
|
match cmd {
|
||||||
|
BlockNotifierTask::NewBlock(new_block_hash) => {
|
||||||
|
let new_block_hash = new_block_hash.to_reversed_str();
|
||||||
|
let command = block_notify_command.replace("%s", &new_block_hash);
|
||||||
|
let c_command = ::std::ffi::CString::new(command.clone()).unwrap();
|
||||||
|
unsafe {
|
||||||
|
use libc::system;
|
||||||
|
|
||||||
|
let err = system(c_command.as_ptr());
|
||||||
|
if err != 0 {
|
||||||
|
error!(target: "pbtc", "Block notification command {} exited with error code {}", command, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BlockNotifierTask::Stop => {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!(target: "pbtc", "Block notification thread stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SyncListener for BlockNotifier {
|
||||||
|
fn synchronization_state_switched(&self, is_synchronizing: bool) {
|
||||||
|
self.is_synchronizing.store(is_synchronizing, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn best_storage_block_inserted(&self, block_hash: &H256) {
|
||||||
|
if !self.is_synchronizing.load(Ordering::SeqCst) {
|
||||||
|
self.tx.send(BlockNotifierTask::NewBlock(block_hash.clone()))
|
||||||
|
.expect("Block notification thread have the same lifetime as `BlockNotifier`")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for BlockNotifier {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Some(join_handle) = self.worker_thread.take() {
|
||||||
|
let _ = self.tx.send(BlockNotifierTask::Stop);
|
||||||
|
join_handle.join().expect("Clean shutdown.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn start(cfg: config::Config) -> Result<(), String> {
|
pub fn start(cfg: config::Config) -> Result<(), String> {
|
||||||
let mut el = p2p::event_loop();
|
let mut el = p2p::event_loop();
|
||||||
|
|
||||||
|
@ -38,6 +115,10 @@ pub fn start(cfg: config::Config) -> Result<(), String> {
|
||||||
let local_sync_node = create_local_sync_node(&sync_handle, cfg.magic, db.clone(), sync_peers.clone());
|
let local_sync_node = create_local_sync_node(&sync_handle, cfg.magic, db.clone(), sync_peers.clone());
|
||||||
let sync_connection_factory = create_sync_connection_factory(sync_peers.clone(), local_sync_node.clone());
|
let sync_connection_factory = create_sync_connection_factory(sync_peers.clone(), local_sync_node.clone());
|
||||||
|
|
||||||
|
if let Some(block_notify_command) = cfg.block_notify_command {
|
||||||
|
local_sync_node.install_sync_listener(Box::new(BlockNotifier::new(block_notify_command)));
|
||||||
|
}
|
||||||
|
|
||||||
let p2p = try!(p2p::P2P::new(p2p_cfg, sync_connection_factory, el.handle()).map_err(|x| x.to_string()));
|
let p2p = try!(p2p::P2P::new(p2p_cfg, sync_connection_factory, el.handle()).map_err(|x| x.to_string()));
|
||||||
let rpc_deps = rpc::Dependencies {
|
let rpc_deps = rpc::Dependencies {
|
||||||
network: cfg.magic,
|
network: cfg.magic,
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub struct Config {
|
||||||
pub user_agent: String,
|
pub user_agent: String,
|
||||||
pub internet_protocol: InternetProtocol,
|
pub internet_protocol: InternetProtocol,
|
||||||
pub rpc_config: RpcHttpConfig,
|
pub rpc_config: RpcHttpConfig,
|
||||||
|
pub block_notify_command: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const DEFAULT_DB_CACHE: usize = 512;
|
pub const DEFAULT_DB_CACHE: usize = 512;
|
||||||
|
@ -91,6 +92,11 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
|
||||||
|
|
||||||
let rpc_config = try!(parse_rpc_config(magic, matches));
|
let rpc_config = try!(parse_rpc_config(magic, matches));
|
||||||
|
|
||||||
|
let block_notify_command = match matches.value_of("blocknotify") {
|
||||||
|
Some(s) => Some(try!(s.parse().map_err(|_| "Invalid blocknotify commmand".to_owned()))),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
let config = Config {
|
let config = Config {
|
||||||
print_to_console: print_to_console,
|
print_to_console: print_to_console,
|
||||||
magic: magic,
|
magic: magic,
|
||||||
|
@ -105,6 +111,7 @@ pub fn parse(matches: &clap::ArgMatches) -> Result<Config, String> {
|
||||||
user_agent: user_agent.to_string(),
|
user_agent: user_agent.to_string(),
|
||||||
internet_protocol: only_net,
|
internet_protocol: only_net,
|
||||||
rpc_config: rpc_config,
|
rpc_config: rpc_config,
|
||||||
|
block_notify_command: block_notify_command,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(config)
|
Ok(config)
|
||||||
|
|
|
@ -6,6 +6,7 @@ extern crate clap;
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate app_dirs;
|
extern crate app_dirs;
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
extern crate db;
|
extern crate db;
|
||||||
extern crate chain;
|
extern crate chain;
|
||||||
|
@ -18,6 +19,7 @@ extern crate p2p;
|
||||||
extern crate sync;
|
extern crate sync;
|
||||||
extern crate import;
|
extern crate import;
|
||||||
extern crate rpc as ethcore_rpc;
|
extern crate rpc as ethcore_rpc;
|
||||||
|
extern crate primitives;
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
mod config;
|
mod config;
|
||||||
|
|
|
@ -48,6 +48,7 @@ use std::sync::Arc;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use tokio_core::reactor::Handle;
|
use tokio_core::reactor::Handle;
|
||||||
use network::Magic;
|
use network::Magic;
|
||||||
|
use primitives::hash::H256;
|
||||||
use verification::BackwardsCompatibleChainVerifier as ChainVerifier;
|
use verification::BackwardsCompatibleChainVerifier as ChainVerifier;
|
||||||
|
|
||||||
/// Sync errors.
|
/// Sync errors.
|
||||||
|
@ -61,6 +62,14 @@ pub enum Error {
|
||||||
Verification(String),
|
Verification(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Synchronization events listener
|
||||||
|
pub trait SyncListener: Send + 'static {
|
||||||
|
/// Called when node switches to synchronization state
|
||||||
|
fn synchronization_state_switched(&self, is_synchronizing: bool);
|
||||||
|
/// Called when new best storage block is inserted
|
||||||
|
fn best_storage_block_inserted(&self, block_hash: &H256);
|
||||||
|
}
|
||||||
|
|
||||||
/// Create blocks writer.
|
/// Create blocks writer.
|
||||||
pub fn create_sync_blocks_writer(db: db::SharedStore, network: Magic, verification: bool) -> blocks_writer::BlocksWriter {
|
pub fn create_sync_blocks_writer(db: db::SharedStore, network: Magic, verification: bool) -> blocks_writer::BlocksWriter {
|
||||||
blocks_writer::BlocksWriter::new(db, network, verification)
|
blocks_writer::BlocksWriter::new(db, network, verification)
|
||||||
|
|
|
@ -14,7 +14,7 @@ use primitives::hash::H256;
|
||||||
use miner::BlockTemplate;
|
use miner::BlockTemplate;
|
||||||
use synchronization_peers::{TransactionAnnouncementType, BlockAnnouncementType};
|
use synchronization_peers::{TransactionAnnouncementType, BlockAnnouncementType};
|
||||||
use types::{PeerIndex, RequestId, StorageRef, MemoryPoolRef, PeersRef, ExecutorRef,
|
use types::{PeerIndex, RequestId, StorageRef, MemoryPoolRef, PeersRef, ExecutorRef,
|
||||||
ClientRef, ServerRef, SynchronizationStateRef};
|
ClientRef, ServerRef, SynchronizationStateRef, SyncListenerRef};
|
||||||
|
|
||||||
/// Local synchronization node
|
/// Local synchronization node
|
||||||
pub struct LocalNode<T: TaskExecutor, U: Server, V: Client> {
|
pub struct LocalNode<T: TaskExecutor, U: Server, V: Client> {
|
||||||
|
@ -261,6 +261,7 @@ impl<T, U, V> LocalNode<T, U, V> where T: TaskExecutor, U: Server, V: Client {
|
||||||
self.peers.misbehaving(peer_index, "Got unrequested 'blocktxn' message");
|
self.peers.misbehaving(peer_index, "Got unrequested 'blocktxn' message");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Verify and then schedule new transaction
|
||||||
pub fn accept_transaction(&self, transaction: Transaction) -> Result<H256, String> {
|
pub fn accept_transaction(&self, transaction: Transaction) -> Result<H256, String> {
|
||||||
let sink_data = Arc::new(TransactionAcceptSinkData::default());
|
let sink_data = Arc::new(TransactionAcceptSinkData::default());
|
||||||
let sink = TransactionAcceptSink::new(sink_data.clone()).boxed();
|
let sink = TransactionAcceptSink::new(sink_data.clone()).boxed();
|
||||||
|
@ -272,11 +273,17 @@ impl<T, U, V> LocalNode<T, U, V> where T: TaskExecutor, U: Server, V: Client {
|
||||||
sink_data.wait()
|
sink_data.wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get block template for mining
|
||||||
pub fn get_block_template(&self) -> BlockTemplate {
|
pub fn get_block_template(&self) -> BlockTemplate {
|
||||||
let block_assembler = BlockAssembler::default();
|
let block_assembler = BlockAssembler::default();
|
||||||
let memory_pool = &*self.memory_pool.read();
|
let memory_pool = &*self.memory_pool.read();
|
||||||
block_assembler.create_new_block(&self.storage, memory_pool, time::get_time().sec as u32, self.network)
|
block_assembler.create_new_block(&self.storage, memory_pool, time::get_time().sec as u32, self.network)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Install synchronization events listener
|
||||||
|
pub fn install_sync_listener(&self, listener: SyncListenerRef) {
|
||||||
|
self.client.install_sync_listener(listener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TransactionAcceptSink {
|
impl TransactionAcceptSink {
|
||||||
|
|
|
@ -5,7 +5,7 @@ use message::types;
|
||||||
use synchronization_executor::TaskExecutor;
|
use synchronization_executor::TaskExecutor;
|
||||||
use synchronization_verifier::{Verifier, TransactionVerificationSink};
|
use synchronization_verifier::{Verifier, TransactionVerificationSink};
|
||||||
use synchronization_client_core::{ClientCore, SynchronizationClientCore};
|
use synchronization_client_core::{ClientCore, SynchronizationClientCore};
|
||||||
use types::{PeerIndex, ClientCoreRef, SynchronizationStateRef, EmptyBoxFuture};
|
use types::{PeerIndex, ClientCoreRef, SynchronizationStateRef, EmptyBoxFuture, SyncListenerRef};
|
||||||
|
|
||||||
#[cfg_attr(feature="cargo-clippy", allow(doc_markdown))]
|
#[cfg_attr(feature="cargo-clippy", allow(doc_markdown))]
|
||||||
///! TODO: update with headers-first corrections
|
///! TODO: update with headers-first corrections
|
||||||
|
@ -130,6 +130,7 @@ pub trait Client : Send + Sync + 'static {
|
||||||
fn on_notfound(&self, peer_index: PeerIndex, message: types::NotFound);
|
fn on_notfound(&self, peer_index: PeerIndex, message: types::NotFound);
|
||||||
fn after_peer_nearly_blocks_verified(&self, peer_index: PeerIndex, future: EmptyBoxFuture);
|
fn after_peer_nearly_blocks_verified(&self, peer_index: PeerIndex, future: EmptyBoxFuture);
|
||||||
fn accept_transaction(&self, transaction: Transaction, sink: Box<TransactionVerificationSink>) -> Result<(), String>;
|
fn accept_transaction(&self, transaction: Transaction, sink: Box<TransactionVerificationSink>) -> Result<(), String>;
|
||||||
|
fn install_sync_listener(&self, listener: SyncListenerRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Synchronization client facade
|
/// Synchronization client facade
|
||||||
|
@ -222,6 +223,10 @@ impl<T, U> Client for SynchronizationClient<T, U> where T: TaskExecutor, U: Veri
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn install_sync_listener(&self, listener: SyncListenerRef) {
|
||||||
|
self.core.lock().install_sync_listener(listener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, U> SynchronizationClient<T, U> where T: TaskExecutor, U: Verifier {
|
impl<T, U> SynchronizationClient<T, U> where T: TaskExecutor, U: Verifier {
|
||||||
|
|
|
@ -24,7 +24,7 @@ use synchronization_manager::{manage_synchronization_peers_blocks, manage_synchr
|
||||||
ManagePeersConfig, ManageUnknownBlocksConfig, ManageOrphanTransactionsConfig};
|
ManagePeersConfig, ManageUnknownBlocksConfig, ManageOrphanTransactionsConfig};
|
||||||
use synchronization_peers_tasks::PeersTasks;
|
use synchronization_peers_tasks::PeersTasks;
|
||||||
use synchronization_verifier::{VerificationSink, BlockVerificationSink, TransactionVerificationSink, VerificationTask};
|
use synchronization_verifier::{VerificationSink, BlockVerificationSink, TransactionVerificationSink, VerificationTask};
|
||||||
use types::{BlockHeight, ClientCoreRef, PeersRef, PeerIndex, SynchronizationStateRef, EmptyBoxFuture};
|
use types::{BlockHeight, ClientCoreRef, PeersRef, PeerIndex, SynchronizationStateRef, EmptyBoxFuture, SyncListenerRef};
|
||||||
use utils::{AverageSpeedMeter, MessageBlockHeadersProvider, OrphanBlocksPool, OrphanTransactionsPool, HashPosition};
|
use utils::{AverageSpeedMeter, MessageBlockHeadersProvider, OrphanBlocksPool, OrphanTransactionsPool, HashPosition};
|
||||||
#[cfg(test)] use synchronization_peers::Peers;
|
#[cfg(test)] use synchronization_peers::Peers;
|
||||||
#[cfg(test)] use synchronization_peers_tasks::{Information as PeersTasksInformation};
|
#[cfg(test)] use synchronization_peers_tasks::{Information as PeersTasksInformation};
|
||||||
|
@ -76,6 +76,7 @@ pub trait ClientCore {
|
||||||
fn on_notfound(&mut self, peer_index: PeerIndex, message: types::NotFound);
|
fn on_notfound(&mut self, peer_index: PeerIndex, message: types::NotFound);
|
||||||
fn after_peer_nearly_blocks_verified(&mut self, peer_index: PeerIndex, future: EmptyBoxFuture);
|
fn after_peer_nearly_blocks_verified(&mut self, peer_index: PeerIndex, future: EmptyBoxFuture);
|
||||||
fn accept_transaction(&mut self, transaction: Transaction, sink: Box<TransactionVerificationSink>) -> Result<VecDeque<IndexedTransaction>, String>;
|
fn accept_transaction(&mut self, transaction: Transaction, sink: Box<TransactionVerificationSink>) -> Result<VecDeque<IndexedTransaction>, String>;
|
||||||
|
fn install_sync_listener(&mut self, listener: SyncListenerRef);
|
||||||
fn execute_synchronization_tasks(&mut self, forced_blocks_requests: Option<Vec<H256>>, final_blocks_requests: Option<Vec<H256>>);
|
fn execute_synchronization_tasks(&mut self, forced_blocks_requests: Option<Vec<H256>>, final_blocks_requests: Option<Vec<H256>>);
|
||||||
fn try_switch_to_saturated_state(&mut self) -> bool;
|
fn try_switch_to_saturated_state(&mut self) -> bool;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +132,8 @@ pub struct SynchronizationClientCore<T: TaskExecutor> {
|
||||||
sync_speed_meter: AverageSpeedMeter,
|
sync_speed_meter: AverageSpeedMeter,
|
||||||
/// Configuration
|
/// Configuration
|
||||||
config: Config,
|
config: Config,
|
||||||
|
/// Synchronization events listener
|
||||||
|
listener: Option<SyncListenerRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verification sink for synchronization client core
|
/// Verification sink for synchronization client core
|
||||||
|
@ -511,6 +514,12 @@ impl<T> ClientCore for SynchronizationClientCore<T> where T: TaskExecutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn install_sync_listener(&mut self, listener: SyncListenerRef) {
|
||||||
|
// currently single, single-setup listener is supported
|
||||||
|
assert!(self.listener.is_none());
|
||||||
|
self.listener = Some(listener);
|
||||||
|
}
|
||||||
|
|
||||||
/// Schedule new synchronization tasks, if any.
|
/// Schedule new synchronization tasks, if any.
|
||||||
fn execute_synchronization_tasks(&mut self, forced_blocks_requests: Option<Vec<H256>>, final_blocks_requests: Option<Vec<H256>>) {
|
fn execute_synchronization_tasks(&mut self, forced_blocks_requests: Option<Vec<H256>>, final_blocks_requests: Option<Vec<H256>>) {
|
||||||
let mut tasks: Vec<Task> = Vec::new();
|
let mut tasks: Vec<Task> = Vec::new();
|
||||||
|
@ -726,6 +735,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
||||||
block_speed_meter: AverageSpeedMeter::with_inspect_items(SYNC_SPEED_BLOCKS_TO_INSPECT),
|
block_speed_meter: AverageSpeedMeter::with_inspect_items(SYNC_SPEED_BLOCKS_TO_INSPECT),
|
||||||
sync_speed_meter: AverageSpeedMeter::with_inspect_items(BLOCKS_SPEED_BLOCKS_TO_INSPECT),
|
sync_speed_meter: AverageSpeedMeter::with_inspect_items(BLOCKS_SPEED_BLOCKS_TO_INSPECT),
|
||||||
config: config,
|
config: config,
|
||||||
|
listener: None,
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -939,6 +949,10 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref listener) = self.listener {
|
||||||
|
listener.synchronization_state_switched(true);
|
||||||
|
}
|
||||||
|
|
||||||
self.shared_state.update_synchronizing(true);
|
self.shared_state.update_synchronizing(true);
|
||||||
self.state = State::Synchronizing(time::precise_time_s(), self.chain.best_storage_block().number);
|
self.state = State::Synchronizing(time::precise_time_s(), self.chain.best_storage_block().number);
|
||||||
}
|
}
|
||||||
|
@ -949,6 +963,10 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref listener) = self.listener {
|
||||||
|
listener.synchronization_state_switched(false);
|
||||||
|
}
|
||||||
|
|
||||||
self.shared_state.update_synchronizing(false);
|
self.shared_state.update_synchronizing(false);
|
||||||
self.state = State::NearlySaturated;
|
self.state = State::NearlySaturated;
|
||||||
}
|
}
|
||||||
|
@ -959,6 +977,10 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref listener) = self.listener {
|
||||||
|
listener.synchronization_state_switched(false);
|
||||||
|
}
|
||||||
|
|
||||||
self.shared_state.update_synchronizing(false);
|
self.shared_state.update_synchronizing(false);
|
||||||
self.state = State::Saturated;
|
self.state = State::Saturated;
|
||||||
self.peers_tasks.reset();
|
self.peers_tasks.reset();
|
||||||
|
@ -1013,6 +1035,13 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
||||||
// update shared state
|
// update shared state
|
||||||
self.shared_state.update_best_storage_block_height(self.chain.best_storage_block().number);
|
self.shared_state.update_best_storage_block_height(self.chain.best_storage_block().number);
|
||||||
|
|
||||||
|
// notify listener
|
||||||
|
if let Some(best_block_hash) = insert_result.canonized_blocks_hashes.last() {
|
||||||
|
if let Some(ref listener) = self.listener {
|
||||||
|
listener.best_storage_block_inserted(best_block_hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// awake threads, waiting for this block insertion
|
// awake threads, waiting for this block insertion
|
||||||
self.awake_waiting_threads(block.hash());
|
self.awake_waiting_threads(block.hash());
|
||||||
|
|
||||||
|
@ -1175,7 +1204,7 @@ impl<T> SynchronizationClientCore<T> where T: TaskExecutor {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::{Mutex, RwLock};
|
||||||
use tokio_core::reactor::{Core, Handle};
|
use tokio_core::reactor::{Core, Handle};
|
||||||
use chain::{Block, Transaction};
|
use chain::{Block, Transaction};
|
||||||
use db;
|
use db;
|
||||||
|
@ -1198,6 +1227,35 @@ pub mod tests {
|
||||||
use utils::SynchronizationState;
|
use utils::SynchronizationState;
|
||||||
use types::{PeerIndex, StorageRef, SynchronizationStateRef, ClientCoreRef};
|
use types::{PeerIndex, StorageRef, SynchronizationStateRef, ClientCoreRef};
|
||||||
use super::{Config, SynchronizationClientCore, ClientCore, CoreVerificationSink};
|
use super::{Config, SynchronizationClientCore, ClientCore, CoreVerificationSink};
|
||||||
|
use super::super::SyncListener;
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct DummySyncListenerData {
|
||||||
|
pub is_synchronizing: bool,
|
||||||
|
pub best_blocks: Vec<H256>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DummySyncListener {
|
||||||
|
data: Arc<Mutex<DummySyncListenerData>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DummySyncListener {
|
||||||
|
pub fn new(data: Arc<Mutex<DummySyncListenerData>>) -> Self {
|
||||||
|
DummySyncListener {
|
||||||
|
data: data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SyncListener for DummySyncListener {
|
||||||
|
fn synchronization_state_switched(&self, is_synchronizing: bool) {
|
||||||
|
self.data.lock().is_synchronizing = is_synchronizing;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn best_storage_block_inserted(&self, block_hash: &H256) {
|
||||||
|
self.data.lock().best_blocks.push(block_hash.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn create_disk_storage() -> StorageRef {
|
fn create_disk_storage() -> StorageRef {
|
||||||
let path = RandomTempPath::create_dir();
|
let path = RandomTempPath::create_dir();
|
||||||
|
@ -2262,4 +2320,42 @@ pub mod tests {
|
||||||
assert!(mempool.write().remove_by_hash(&b1.transactions[2].hash()).is_some());
|
assert!(mempool.write().remove_by_hash(&b1.transactions[2].hash()).is_some());
|
||||||
assert!(mempool.write().remove_by_hash(&tx3.hash()).is_some());
|
assert!(mempool.write().remove_by_hash(&tx3.hash()).is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn sync_listener_calls() {
|
||||||
|
let (_, _, _, _, sync) = create_sync(None, None);
|
||||||
|
|
||||||
|
// install sync listener
|
||||||
|
let data = Arc::new(Mutex::new(DummySyncListenerData::default()));
|
||||||
|
sync.install_sync_listener(Box::new(DummySyncListener::new(data.clone())));
|
||||||
|
|
||||||
|
// at the beginning, is_synchronizing must be equal to false
|
||||||
|
assert_eq!(data.lock().is_synchronizing, false);
|
||||||
|
assert_eq!(data.lock().best_blocks.len(), 0);
|
||||||
|
|
||||||
|
// supply with new block header => is_synchronizing is still false
|
||||||
|
sync.on_headers(0, types::Headers::with_headers(vec![test_data::block_h1().block_header]));
|
||||||
|
assert_eq!(data.lock().is_synchronizing, false);
|
||||||
|
assert_eq!(data.lock().best_blocks.len(), 0);
|
||||||
|
|
||||||
|
// supply with 2 new blocks headers => is_synchronizing is true
|
||||||
|
sync.on_headers(0, types::Headers::with_headers(vec![test_data::block_h2().block_header, test_data::block_h3().block_header]));
|
||||||
|
assert_eq!(data.lock().is_synchronizing, true);
|
||||||
|
assert_eq!(data.lock().best_blocks.len(), 0);
|
||||||
|
|
||||||
|
// supply with block 3 => no new best block is informed
|
||||||
|
sync.on_block(0, test_data::block_h3().into());
|
||||||
|
assert_eq!(data.lock().is_synchronizing, true);
|
||||||
|
assert_eq!(data.lock().best_blocks.len(), 0);
|
||||||
|
|
||||||
|
// supply with block 1 => new best block is informed
|
||||||
|
sync.on_block(0, test_data::block_h1().into());
|
||||||
|
assert_eq!(data.lock().is_synchronizing, true);
|
||||||
|
assert_eq!(data.lock().best_blocks.len(), 1);
|
||||||
|
|
||||||
|
// supply with block 2 => 2 new best block is informed
|
||||||
|
sync.on_block(0, test_data::block_h2().into());
|
||||||
|
assert_eq!(data.lock().is_synchronizing, false);
|
||||||
|
assert_eq!(data.lock().best_blocks.len(), 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use parking_lot::{Mutex, RwLock};
|
||||||
use db;
|
use db;
|
||||||
use local_node::LocalNode;
|
use local_node::LocalNode;
|
||||||
use miner::MemoryPool;
|
use miner::MemoryPool;
|
||||||
|
use super::SyncListener;
|
||||||
use synchronization_client::SynchronizationClient;
|
use synchronization_client::SynchronizationClient;
|
||||||
use synchronization_executor::LocalSynchronizationTaskExecutor;
|
use synchronization_executor::LocalSynchronizationTaskExecutor;
|
||||||
use synchronization_peers::Peers;
|
use synchronization_peers::Peers;
|
||||||
|
@ -48,3 +49,6 @@ pub type ServerRef<T> = Arc<T>;
|
||||||
|
|
||||||
/// Reference to local node
|
/// Reference to local node
|
||||||
pub type LocalNodeRef = Arc<LocalNode<LocalSynchronizationTaskExecutor, ServerImpl, SynchronizationClient<LocalSynchronizationTaskExecutor, AsyncVerifier>>>;
|
pub type LocalNodeRef = Arc<LocalNode<LocalSynchronizationTaskExecutor, ServerImpl, SynchronizationClient<LocalSynchronizationTaskExecutor, AsyncVerifier>>>;
|
||||||
|
|
||||||
|
/// Synchronization events listener reference
|
||||||
|
pub type SyncListenerRef = Box<SyncListener>;
|
||||||
|
|
|
@ -32,6 +32,12 @@ pub fn block_h2() -> Block {
|
||||||
"010000004860eb18bf1b1620e37e9490fc8a427514416fd75159ab86688e9a8300000000d5fdcc541e25de1c7a5addedf24858b8bb665c9f36ef744ee42c316022c90f9bb0bc6649ffff001d08d2bd610101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d010bffffffff0100f2052a010000004341047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77ac00000000".into()
|
"010000004860eb18bf1b1620e37e9490fc8a427514416fd75159ab86688e9a8300000000d5fdcc541e25de1c7a5addedf24858b8bb665c9f36ef744ee42c316022c90f9bb0bc6649ffff001d08d2bd610101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d010bffffffff0100f2052a010000004341047211a824f55b505228e4c3d5194c1fcfaa15a456abdf37f9b9d97a4040afc073dee6c89064984f03385237d92167c13e236446b417ab79a0fcae412ae3316b77ac00000000".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://webbtc.com/block/0000000082b5015589a3fdf2d4baff403e6f0be035a5d9742c1cae6295464449.hex
|
||||||
|
// height 3
|
||||||
|
pub fn block_h3() -> Block {
|
||||||
|
"01000000bddd99ccfda39da1b108ce1a5d70038d0a967bacb68b6b63065f626a0000000044f672226090d85db9a9f2fbfe5f0f9609b387af7be5b7fbb7a1767c831c9e995dbe6649ffff001d05e0ed6d0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d010effffffff0100f2052a0100000043410494b9d3e76c5b1629ecf97fff95d7a4bbdac87cc26099ada28066c6ff1eb9191223cd897194a08d0c2726c5747f1db49e8cf90e75dc3e3550ae9b30086f3cd5aaac00000000".into()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn genesis() -> Block {
|
pub fn genesis() -> Block {
|
||||||
"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into()
|
"0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000".into()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue