Docs
This commit is contained in:
parent
8cd3aa4b43
commit
10fe6b937f
@ -5,21 +5,20 @@ extern crate rustc_serialize;
|
|||||||
use std::io::*;
|
use std::io::*;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use rustc_serialize::hex::FromHex;
|
|
||||||
use util::hash::*;
|
use util::hash::*;
|
||||||
use util::network::{NetworkService};
|
use util::network::{NetworkService};
|
||||||
use ethcore::client::Client;
|
use ethcore::client::Client;
|
||||||
use ethcore::sync::EthSync;
|
use ethcore::sync::EthSync;
|
||||||
|
use ethcore::spec::Spec;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut service = NetworkService::start().unwrap();
|
let mut service = NetworkService::start().unwrap();
|
||||||
//TODO: replace with proper genesis and chain params.
|
//TODO: replace with proper genesis and chain params.
|
||||||
let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap();
|
let frontier = Spec::new_frontier();
|
||||||
let mut dir = env::temp_dir();
|
let mut dir = env::temp_dir();
|
||||||
dir.push(H32::random().hex());
|
dir.push(H32::random().hex());
|
||||||
let client = Arc::new(Client::new(&genesis, &dir));
|
let client = Arc::new(Client::new(&frontier.genesis_block(), &dir));
|
||||||
let sync = Box::new(EthSync::new(client));
|
EthSync::register(&mut service, client);
|
||||||
service.register_protocol(sync, "eth", &[62u8, 63u8]).expect("Error registering eth protocol handler");
|
|
||||||
loop {
|
loop {
|
||||||
let mut cmd = String::new();
|
let mut cmd = String::new();
|
||||||
stdin().read_line(&mut cmd).unwrap();
|
stdin().read_line(&mut cmd).unwrap();
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
///
|
||||||
|
/// BlockChain synchronization strategy.
|
||||||
|
/// Syncs to peers and keeps up to date.
|
||||||
|
/// This implementation uses ethereum protocol v63
|
||||||
|
///
|
||||||
|
/// Syncing strategy.
|
||||||
|
///
|
||||||
|
/// 1. A peer arrives with a total difficulty better than ours
|
||||||
|
/// 2. Find a common best block between our an peer chain.
|
||||||
|
/// Start with out best block and request headers from peer backwards until a common block is found
|
||||||
|
/// 3. Download headers and block bodies from peers in parallel.
|
||||||
|
/// As soon as a set of the blocks is fully downloaded at the head of the queue it is fed to the blockchain
|
||||||
|
/// 4. Maintain sync by handling NewBlocks/NewHashes messages
|
||||||
|
///
|
||||||
|
|
||||||
use std::collections::{HashSet, HashMap};
|
use std::collections::{HashSet, HashMap};
|
||||||
use std::cmp::{min, max};
|
use std::cmp::{min, max};
|
||||||
use std::mem::{replace};
|
use std::mem::{replace};
|
||||||
@ -13,7 +28,7 @@ use client::{BlockNumber, BlockChainClient, BlockStatus, QueueStatus, ImportResu
|
|||||||
use views::{HeaderView};
|
use views::{HeaderView};
|
||||||
use header::{Header as BlockHeader};
|
use header::{Header as BlockHeader};
|
||||||
use sync::range_collection::{RangeCollection, ToUsize, FromUsize};
|
use sync::range_collection::{RangeCollection, ToUsize, FromUsize};
|
||||||
use sync::{SyncIo};
|
use sync::io::SyncIo;
|
||||||
|
|
||||||
impl ToUsize for BlockNumber {
|
impl ToUsize for BlockNumber {
|
||||||
fn to_usize(&self) -> usize {
|
fn to_usize(&self) -> usize {
|
||||||
@ -52,7 +67,7 @@ const GET_RECEIPTS_PACKET: u8 = 0x0f;
|
|||||||
const RECEIPTS_PACKET: u8 = 0x10;
|
const RECEIPTS_PACKET: u8 = 0x10;
|
||||||
|
|
||||||
struct Header {
|
struct Header {
|
||||||
///Header data
|
/// Header data
|
||||||
data: Bytes,
|
data: Bytes,
|
||||||
/// Block hash
|
/// Block hash
|
||||||
hash: H256,
|
hash: H256,
|
||||||
@ -81,13 +96,21 @@ pub enum SyncState {
|
|||||||
NewBlocks,
|
NewBlocks,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Syncing status and statistics
|
||||||
pub struct SyncStatus {
|
pub struct SyncStatus {
|
||||||
|
/// State
|
||||||
pub state: SyncState,
|
pub state: SyncState,
|
||||||
|
/// Syncing protocol version. That's the maximum protocol version we connect to.
|
||||||
pub protocol_version: u8,
|
pub protocol_version: u8,
|
||||||
|
/// BlockChain height for the moment the sync started.
|
||||||
pub start_block_number: BlockNumber,
|
pub start_block_number: BlockNumber,
|
||||||
|
/// Last fully downloaded and imported block number.
|
||||||
pub last_imported_block_number: BlockNumber,
|
pub last_imported_block_number: BlockNumber,
|
||||||
|
/// Highest block number in the download queue.
|
||||||
pub highest_block_number: BlockNumber,
|
pub highest_block_number: BlockNumber,
|
||||||
|
/// Total number of blocks for the sync process.
|
||||||
pub blocks_total: usize,
|
pub blocks_total: usize,
|
||||||
|
/// Number of blocks downloaded so far.
|
||||||
pub blocks_received: usize,
|
pub blocks_received: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,11 +201,7 @@ impl ChainSync {
|
|||||||
self.peers.clear();
|
self.peers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns true is Sync is in progress
|
/// Rest sync. Clear all downloaded data but keep the queue
|
||||||
pub fn is_syncing(&self) -> bool {
|
|
||||||
self.state != SyncState::Idle
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
fn reset(&mut self) {
|
||||||
self.downloading_headers.clear();
|
self.downloading_headers.clear();
|
||||||
self.downloading_bodies.clear();
|
self.downloading_bodies.clear();
|
||||||
@ -389,6 +408,7 @@ impl ChainSync {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handles NewHashes packet. Initiates headers download for any unknown hashes.
|
||||||
fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: &PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
fn on_peer_new_hashes(&mut self, io: &mut SyncIo, peer_id: &PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
||||||
if self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer").asking != PeerAsking::Nothing {
|
if self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer").asking != PeerAsking::Nothing {
|
||||||
trace!(target: "sync", "Ignoring new hashes since we're already downloading.");
|
trace!(target: "sync", "Ignoring new hashes since we're already downloading.");
|
||||||
@ -432,6 +452,7 @@ impl ChainSync {
|
|||||||
self.continue_sync(io);
|
self.continue_sync(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called when a new peer is connected
|
||||||
pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: &PeerId) {
|
pub fn on_peer_connected(&mut self, io: &mut SyncIo, peer: &PeerId) {
|
||||||
trace!(target: "sync", "== Connected {}", peer);
|
trace!(target: "sync", "== Connected {}", peer);
|
||||||
self.send_status(io, peer);
|
self.send_status(io, peer);
|
||||||
@ -459,6 +480,7 @@ impl ChainSync {
|
|||||||
self.state = SyncState::Waiting;
|
self.state = SyncState::Waiting;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find something to do for a peer. Called for a new peer or when a peer is done with it's task.
|
||||||
fn sync_peer(&mut self, io: &mut SyncIo, peer_id: &PeerId, force: bool) {
|
fn sync_peer(&mut self, io: &mut SyncIo, peer_id: &PeerId, force: bool) {
|
||||||
let (peer_latest, peer_difficulty) = {
|
let (peer_latest, peer_difficulty) = {
|
||||||
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
|
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
|
||||||
@ -488,6 +510,7 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Find some headers or blocks to download for a peer.
|
||||||
fn request_blocks(&mut self, io: &mut SyncIo, peer_id: &PeerId) {
|
fn request_blocks(&mut self, io: &mut SyncIo, peer_id: &PeerId) {
|
||||||
self.clear_peer_download(peer_id);
|
self.clear_peer_download(peer_id);
|
||||||
|
|
||||||
@ -572,6 +595,7 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear all blocks/headers marked as being downloaded by a peer.
|
||||||
fn clear_peer_download(&mut self, peer_id: &PeerId) {
|
fn clear_peer_download(&mut self, peer_id: &PeerId) {
|
||||||
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
|
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
|
||||||
for b in &peer.asking_blocks {
|
for b in &peer.asking_blocks {
|
||||||
@ -581,6 +605,7 @@ impl ChainSync {
|
|||||||
peer.asking_blocks.clear();
|
peer.asking_blocks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if there are blocks fully downloaded that can be imported into the blockchain and does the import.
|
||||||
fn collect_blocks(&mut self, io: &mut SyncIo) {
|
fn collect_blocks(&mut self, io: &mut SyncIo) {
|
||||||
if !self.have_common_block || self.headers.is_empty() || self.bodies.is_empty() {
|
if !self.have_common_block || self.headers.is_empty() || self.bodies.is_empty() {
|
||||||
return;
|
return;
|
||||||
@ -647,6 +672,8 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Remove downloaded bocks/headers starting from specified number.
|
||||||
|
/// Used to recover from an error and re-download parts of the chain detected as bad.
|
||||||
fn remove_downloaded_blocks(&mut self, start: BlockNumber) {
|
fn remove_downloaded_blocks(&mut self, start: BlockNumber) {
|
||||||
for n in self.headers.get_tail(&start) {
|
for n in self.headers.get_tail(&start) {
|
||||||
match self.headers.find_item(&n) {
|
match self.headers.find_item(&n) {
|
||||||
@ -667,8 +694,9 @@ impl ChainSync {
|
|||||||
self.bodies.remove_tail(&start);
|
self.bodies.remove_tail(&start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request headers from a peer by block hash
|
||||||
fn request_headers_by_hash(&mut self, sync: &mut SyncIo, peer_id: &PeerId, h: &H256, count: usize, skip: usize, reverse: bool) {
|
fn request_headers_by_hash(&mut self, sync: &mut SyncIo, peer_id: &PeerId, h: &H256, count: usize, skip: usize, reverse: bool) {
|
||||||
trace!(target: "sync", "{}<- GetBlockHeaders: {} entries starting from {}", peer_id, count, h);
|
trace!(target: "sync", "{} <- GetBlockHeaders: {} entries starting from {}", peer_id, count, h);
|
||||||
let mut rlp = RlpStream::new_list(4);
|
let mut rlp = RlpStream::new_list(4);
|
||||||
rlp.append(h);
|
rlp.append(h);
|
||||||
rlp.append(&count);
|
rlp.append(&count);
|
||||||
@ -677,9 +705,10 @@ impl ChainSync {
|
|||||||
self.send_request(sync, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out());
|
self.send_request(sync, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request headers from a peer by block number
|
||||||
fn request_headers_by_number(&mut self, sync: &mut SyncIo, peer_id: &PeerId, n: BlockNumber, count: usize, skip: usize, reverse: bool) {
|
fn request_headers_by_number(&mut self, sync: &mut SyncIo, peer_id: &PeerId, n: BlockNumber, count: usize, skip: usize, reverse: bool) {
|
||||||
let mut rlp = RlpStream::new_list(4);
|
let mut rlp = RlpStream::new_list(4);
|
||||||
trace!(target: "sync", "{}<- GetBlockHeaders: {} entries starting from {}", peer_id, count, n);
|
trace!(target: "sync", "{} <- GetBlockHeaders: {} entries starting from {}", peer_id, count, n);
|
||||||
rlp.append(&n);
|
rlp.append(&n);
|
||||||
rlp.append(&count);
|
rlp.append(&count);
|
||||||
rlp.append(&skip);
|
rlp.append(&skip);
|
||||||
@ -687,15 +716,17 @@ impl ChainSync {
|
|||||||
self.send_request(sync, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out());
|
self.send_request(sync, peer_id, PeerAsking::BlockHeaders, GET_BLOCK_HEADERS_PACKET, rlp.out());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request block bodies from a peer
|
||||||
fn request_bodies(&mut self, sync: &mut SyncIo, peer_id: &PeerId, hashes: Vec<H256>) {
|
fn request_bodies(&mut self, sync: &mut SyncIo, peer_id: &PeerId, hashes: Vec<H256>) {
|
||||||
let mut rlp = RlpStream::new_list(hashes.len());
|
let mut rlp = RlpStream::new_list(hashes.len());
|
||||||
trace!(target: "sync", "{}<- GetBlockBodies: {} entries", peer_id, hashes.len());
|
trace!(target: "sync", "{} <- GetBlockBodies: {} entries", peer_id, hashes.len());
|
||||||
for h in hashes {
|
for h in hashes {
|
||||||
rlp.append(&h);
|
rlp.append(&h);
|
||||||
}
|
}
|
||||||
self.send_request(sync, peer_id, PeerAsking::BlockBodies, GET_BLOCK_BODIES_PACKET, rlp.out());
|
self.send_request(sync, peer_id, PeerAsking::BlockBodies, GET_BLOCK_BODIES_PACKET, rlp.out());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reset peer status after request is complete.
|
||||||
fn reset_peer_asking(&mut self, peer_id: &PeerId, asking: PeerAsking) {
|
fn reset_peer_asking(&mut self, peer_id: &PeerId, asking: PeerAsking) {
|
||||||
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
|
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
|
||||||
if peer.asking != asking {
|
if peer.asking != asking {
|
||||||
@ -706,6 +737,7 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generic request sender
|
||||||
fn send_request(&mut self, sync: &mut SyncIo, peer_id: &PeerId, asking: PeerAsking, packet_id: PacketId, packet: Bytes) {
|
fn send_request(&mut self, sync: &mut SyncIo, peer_id: &PeerId, asking: PeerAsking, packet_id: PacketId, packet: Bytes) {
|
||||||
{
|
{
|
||||||
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
|
let peer = self.peers.get_mut(&peer_id).expect("ChainSync: unknown peer");
|
||||||
@ -726,10 +758,12 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Called when peer sends us new transactions
|
||||||
fn on_peer_transactions(&mut self, _io: &mut SyncIo, _peer_id: &PeerId, _r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
fn on_peer_transactions(&mut self, _io: &mut SyncIo, _peer_id: &PeerId, _r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Send Status message
|
||||||
fn send_status(&mut self, io: &mut SyncIo, peer_id: &PeerId) {
|
fn send_status(&mut self, io: &mut SyncIo, peer_id: &PeerId) {
|
||||||
let mut packet = RlpStream::new_list(5);
|
let mut packet = RlpStream::new_list(5);
|
||||||
let chain = io.chain().chain_info();
|
let chain = io.chain().chain_info();
|
||||||
@ -748,6 +782,7 @@ impl ChainSync {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Respond to GetBlockHeaders request
|
||||||
fn return_block_headers(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
fn return_block_headers(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
||||||
// Packet layout:
|
// Packet layout:
|
||||||
// [ block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ]
|
// [ block: { P , B_32 }, maxHeaders: P, skip: P, reverse: P in { 0 , 1 } ]
|
||||||
@ -804,6 +839,7 @@ impl ChainSync {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Respond to GetBlockBodies request
|
||||||
fn return_block_bodies(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
fn return_block_bodies(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
||||||
let mut count = r.item_count();
|
let mut count = r.item_count();
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
@ -831,6 +867,7 @@ impl ChainSync {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Respond to GetNodeData request
|
||||||
fn return_node_data(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
fn return_node_data(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
||||||
let mut count = r.item_count();
|
let mut count = r.item_count();
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
@ -856,6 +893,7 @@ impl ChainSync {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Respond to GetReceipts request
|
||||||
fn return_receipts(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
fn return_receipts(&self, io: &mut SyncIo, r: &UntrustedRlp) -> Result<(), PacketDecodeError> {
|
||||||
let mut count = r.item_count();
|
let mut count = r.item_count();
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
@ -881,6 +919,7 @@ impl ChainSync {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Dispatch incoming requests and responses
|
||||||
pub fn on_packet(&mut self, io: &mut SyncIo, peer: &PeerId, packet_id: u8, data: &[u8]) {
|
pub fn on_packet(&mut self, io: &mut SyncIo, peer: &PeerId, packet_id: u8, data: &[u8]) {
|
||||||
let rlp = UntrustedRlp::new(data);
|
let rlp = UntrustedRlp::new(data);
|
||||||
let result = match packet_id {
|
let result = match packet_id {
|
||||||
@ -904,6 +943,7 @@ impl ChainSync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Maintain other peers. Send out any new blocks and transactions
|
||||||
pub fn maintain_sync(&mut self, _io: &mut SyncIo) {
|
pub fn maintain_sync(&mut self, _io: &mut SyncIo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,88 +1,73 @@
|
|||||||
|
/// Blockchain sync module
|
||||||
|
/// Implements ethereum protocol version 63 as specified here:
|
||||||
|
/// https://github.com/ethereum/wiki/wiki/Ethereum-Wire-Protocol
|
||||||
|
///
|
||||||
|
/// Usage example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// extern crate ethcore_util as util;
|
||||||
|
/// extern crate ethcore;
|
||||||
|
/// use std::env;
|
||||||
|
/// use std::sync::Arc;
|
||||||
|
/// use util::network::NetworkService;
|
||||||
|
/// use ethcore::client::Client;
|
||||||
|
/// use ethcore::sync::EthSync;
|
||||||
|
/// use ethcore::spec::Spec;
|
||||||
|
///
|
||||||
|
/// fn main() {
|
||||||
|
/// let mut service = NetworkService::start().unwrap();
|
||||||
|
/// let frontier = Spec::new_frontier();
|
||||||
|
/// let dir = env::temp_dir();
|
||||||
|
/// let client = Arc::new(Client::new(&frontier.genesis_block(), &dir));
|
||||||
|
/// EthSync::register(&mut service, client);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use client::BlockChainClient;
|
use client::BlockChainClient;
|
||||||
use util::network::{ProtocolHandler, NetworkService, HandlerIo, TimerToken, PeerId, PacketId, Message, Error as NetworkError};
|
use util::network::{ProtocolHandler, NetworkService, HandlerIo, TimerToken, PeerId, Message};
|
||||||
use sync::chain::ChainSync;
|
use sync::chain::ChainSync;
|
||||||
|
use sync::io::NetSyncIo;
|
||||||
|
|
||||||
mod chain;
|
mod chain;
|
||||||
|
mod io;
|
||||||
mod range_collection;
|
mod range_collection;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub fn new(_service: &mut NetworkService, eth_client: Arc<BlockChainClient + Send + Sized>) -> EthSync {
|
/// Ethereum network protocol handler
|
||||||
EthSync {
|
|
||||||
chain: eth_client,
|
|
||||||
sync: ChainSync::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait SyncIo {
|
|
||||||
fn disable_peer(&mut self, peer_id: &PeerId);
|
|
||||||
fn respond(&mut self, packet_id: PacketId, data: Vec<u8>) -> Result<(), NetworkError>;
|
|
||||||
fn send(&mut self, peer_id: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), NetworkError>;
|
|
||||||
fn chain<'s>(&'s mut self) -> &'s mut BlockChainClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NetSyncIo<'s, 'h> where 'h:'s {
|
|
||||||
network: &'s mut HandlerIo<'h>,
|
|
||||||
chain: &'s mut BlockChainClient
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'h> NetSyncIo<'s, 'h> {
|
|
||||||
pub fn new(network: &'s mut HandlerIo<'h>, chain: &'s mut BlockChainClient) -> NetSyncIo<'s,'h> {
|
|
||||||
NetSyncIo {
|
|
||||||
network: network,
|
|
||||||
chain: chain,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'s, 'h> SyncIo for NetSyncIo<'s, 'h> {
|
|
||||||
fn disable_peer(&mut self, peer_id: &PeerId) {
|
|
||||||
self.network.disable_peer(*peer_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn respond(&mut self, packet_id: PacketId, data: Vec<u8>) -> Result<(), NetworkError>{
|
|
||||||
self.network.respond(packet_id, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn send(&mut self, peer_id: PeerId, packet_id: PacketId, data: Vec<u8>) -> Result<(), NetworkError>{
|
|
||||||
self.network.send(peer_id, packet_id, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn chain<'a>(&'a mut self) -> &'a mut BlockChainClient {
|
|
||||||
self.chain
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct EthSync {
|
pub struct EthSync {
|
||||||
|
/// Shared blockchain client. TODO: this should evetually become an IPC endpoint
|
||||||
chain: Arc<BlockChainClient + Send + Sized>,
|
chain: Arc<BlockChainClient + Send + Sized>,
|
||||||
|
/// Sync strategy
|
||||||
sync: ChainSync
|
sync: ChainSync
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::chain::SyncStatus;
|
pub use self::chain::SyncStatus;
|
||||||
|
|
||||||
impl EthSync {
|
impl EthSync {
|
||||||
pub fn new(chain: Arc<BlockChainClient + Send + Sized>) -> EthSync {
|
/// Creates and register protocol with the network service
|
||||||
EthSync {
|
pub fn register(service: &mut NetworkService, chain: Arc<BlockChainClient + Send + Sized>) {
|
||||||
|
let sync = Box::new(EthSync {
|
||||||
chain: chain,
|
chain: chain,
|
||||||
sync: ChainSync::new(),
|
sync: ChainSync::new(),
|
||||||
}
|
});
|
||||||
}
|
service.register_protocol(sync, "eth", &[62u8, 63u8]).expect("Error registering eth protocol handler");
|
||||||
|
|
||||||
pub fn is_syncing(&self) -> bool {
|
|
||||||
self.sync.is_syncing()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get sync status
|
||||||
pub fn status(&self) -> SyncStatus {
|
pub fn status(&self) -> SyncStatus {
|
||||||
self.sync.status()
|
self.sync.status()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_network(&mut self, io: &mut HandlerIo) {
|
/// Stop sync
|
||||||
|
pub fn stop(&mut self, io: &mut HandlerIo) {
|
||||||
self.sync.abort(&mut NetSyncIo::new(io, Arc::get_mut(&mut self.chain).unwrap()));
|
self.sync.abort(&mut NetSyncIo::new(io, Arc::get_mut(&mut self.chain).unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start_network(&mut self, io: &mut HandlerIo) {
|
/// Restart sync
|
||||||
|
pub fn restart(&mut self, io: &mut HandlerIo) {
|
||||||
self.sync.restart(&mut NetSyncIo::new(io, Arc::get_mut(&mut self.chain).unwrap()));
|
self.sync.restart(&mut NetSyncIo::new(io, Arc::get_mut(&mut self.chain).unwrap()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
/// This module defines a trait for a collection of ranged values and an implementation
|
||||||
|
/// for this trait over sorted vector.
|
||||||
|
|
||||||
use std::ops::{Add, Sub, Range};
|
use std::ops::{Add, Sub, Range};
|
||||||
|
|
||||||
pub trait ToUsize {
|
pub trait ToUsize {
|
||||||
@ -8,16 +11,28 @@ pub trait FromUsize {
|
|||||||
fn from_usize(s: usize) -> Self;
|
fn from_usize(s: usize) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A key-value collection orderd by key with sequential key-value pairs grouped together.
|
||||||
|
/// Such group is called a range.
|
||||||
|
/// E.g. a set of collection of 5 pairs {1, a}, {2, b}, {10, x}, {11, y}, {12, z} will be grouped into two ranges: {1, [a,b]}, {10, [x,y,z]}
|
||||||
pub trait RangeCollection<K, V> {
|
pub trait RangeCollection<K, V> {
|
||||||
|
/// Check if the given key is present in the collection.
|
||||||
fn have_item(&self, key: &K) -> bool;
|
fn have_item(&self, key: &K) -> bool;
|
||||||
|
/// Get value by key.
|
||||||
fn find_item(&self, key: &K) -> Option<&V>;
|
fn find_item(&self, key: &K) -> Option<&V>;
|
||||||
|
/// Get a range of keys from `key` till the end of the range that has `key`
|
||||||
|
/// Returns an empty range is key does not exist.
|
||||||
fn get_tail(&mut self, key: &K) -> Range<K>;
|
fn get_tail(&mut self, key: &K) -> Range<K>;
|
||||||
|
/// Remove all elements < `start` in the range that contains `start` - 1
|
||||||
fn remove_head(&mut self, start: &K);
|
fn remove_head(&mut self, start: &K);
|
||||||
|
/// Remove all elements >= `start` in the range that contains `start`
|
||||||
fn remove_tail(&mut self, start: &K);
|
fn remove_tail(&mut self, start: &K);
|
||||||
|
/// Remove all elements >= `tail`
|
||||||
fn insert_item(&mut self, key: K, value: V);
|
fn insert_item(&mut self, key: K, value: V);
|
||||||
|
/// Get an iterator over ranges
|
||||||
fn range_iter<'c>(&'c self) -> RangeIterator<'c, K, V>;
|
fn range_iter<'c>(&'c self) -> RangeIterator<'c, K, V>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Range iterator. For each range yelds a key for the first element of the range and a vector of values.
|
||||||
pub struct RangeIterator<'c, K:'c, V:'c> {
|
pub struct RangeIterator<'c, K:'c, V:'c> {
|
||||||
range: usize,
|
range: usize,
|
||||||
collection: &'c Vec<(K, Vec<V>)>
|
collection: &'c Vec<(K, Vec<V>)>
|
||||||
@ -72,7 +87,6 @@ impl<K, V> RangeCollection<K, V> for Vec<(K, Vec<V>)> where K: Ord + PartialEq +
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a range of elements from start till the end of the range
|
|
||||||
fn get_tail(&mut self, key: &K) -> Range<K> {
|
fn get_tail(&mut self, key: &K) -> Range<K> {
|
||||||
let kv = *key;
|
let kv = *key;
|
||||||
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
|
match self.binary_search_by(|&(k, _)| k.cmp(key).reverse()) {
|
||||||
|
@ -7,8 +7,8 @@ use util::rlp::{self, Rlp, RlpStream, View, Stream};
|
|||||||
use util::network::{PeerId, PacketId, Error as NetworkError};
|
use util::network::{PeerId, PacketId, Error as NetworkError};
|
||||||
use client::{BlockChainClient, BlockStatus, BlockNumber, TreeRoute, BlockQueueStatus, BlockChainInfo, ImportResult, QueueStatus};
|
use client::{BlockChainClient, BlockStatus, BlockNumber, TreeRoute, BlockQueueStatus, BlockChainInfo, ImportResult, QueueStatus};
|
||||||
use header::Header as BlockHeader;
|
use header::Header as BlockHeader;
|
||||||
use sync::{SyncIo};
|
use sync::io::SyncIo;
|
||||||
use sync::chain::{ChainSync};
|
use sync::chain::ChainSync;
|
||||||
|
|
||||||
struct TestBlockChainClient {
|
struct TestBlockChainClient {
|
||||||
blocks: HashMap<H256, Bytes>,
|
blocks: HashMap<H256, Bytes>,
|
||||||
|
Loading…
Reference in New Issue
Block a user