2017-01-25 18:51:41 +01:00
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
2016-07-14 12:07:33 +02:00
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std ::sync ::Arc ;
2016-11-16 13:37:21 +01:00
use std ::collections ::{ HashMap , BTreeMap } ;
2016-10-25 15:55:53 +02:00
use std ::io ;
2016-10-18 18:16:00 +02:00
use util ::Bytes ;
2017-07-14 20:40:28 +02:00
use network ::{ NetworkProtocolHandler , NetworkService , NetworkContext , HostInfo , PeerId , ProtocolId ,
2017-08-29 14:38:01 +02:00
NetworkConfiguration as BasicNetworkConfiguration , NonReservedPeerMode , NetworkError , ConnectionFilter } ;
2017-09-04 16:36:49 +02:00
use bigint ::prelude ::U256 ;
use bigint ::hash ::{ H256 , H512 } ;
2016-08-05 10:32:04 +02:00
use io ::{ TimerToken } ;
2017-01-11 12:16:47 +01:00
use ethcore ::ethstore ::ethkey ::Secret ;
2016-07-16 19:09:14 +02:00
use ethcore ::client ::{ BlockChainClient , ChainNotify } ;
2016-09-06 15:31:13 +02:00
use ethcore ::snapshot ::SnapshotService ;
2016-07-27 21:38:22 +02:00
use ethcore ::header ::BlockNumber ;
2016-08-05 10:32:04 +02:00
use sync_io ::NetSyncIo ;
2017-02-17 21:38:43 +01:00
use chain ::{ ChainSync , SyncStatus as EthSyncStatus } ;
2016-07-14 12:07:33 +02:00
use std ::net ::{ SocketAddr , AddrParseError } ;
use ipc ::{ BinaryConvertable , BinaryConvertError , IpcConfig } ;
2016-08-05 10:32:04 +02:00
use std ::str ::FromStr ;
2016-07-14 12:07:33 +02:00
use parking_lot ::RwLock ;
2016-10-24 16:24:35 +02:00
use chain ::{ ETH_PACKET_COUNT , SNAPSHOT_SYNC_PACKET_COUNT } ;
2017-02-09 18:42:18 +01:00
use light ::client ::AsLightClient ;
2016-12-16 17:38:16 +01:00
use light ::Provider ;
2017-01-20 12:41:49 +01:00
use light ::net ::{ self as light_net , LightProtocol , Params as LightParams , Capabilities , Handler as LightHandler , EventContext } ;
2017-07-28 19:06:39 +02:00
use network ::IpFilter ;
2016-10-24 16:24:35 +02:00
2016-11-29 16:54:30 +01:00
/// Parity sync protocol
2016-10-27 13:49:44 +02:00
pub const WARP_SYNC_PROTOCOL_ID : ProtocolId = * b " par " ;
2016-07-14 12:07:33 +02:00
/// Ethereum sync protocol
2016-11-29 16:54:30 +01:00
pub const ETH_PROTOCOL : ProtocolId = * b " eth " ;
2016-12-10 11:01:23 +01:00
/// Ethereum light protocol
2017-03-22 18:32:04 +01:00
pub const LIGHT_PROTOCOL : ProtocolId = * b " pip " ;
2016-07-14 12:07:33 +02:00
/// Sync configuration
2016-09-01 12:23:31 +02:00
#[ derive(Debug, Clone, Copy) ]
2016-07-14 12:07:33 +02:00
pub struct SyncConfig {
/// Max blocks to download ahead
pub max_download_ahead_blocks : usize ,
2016-11-22 18:03:35 +01:00
/// Enable ancient block download.
pub download_old_blocks : bool ,
2016-07-14 12:07:33 +02:00
/// Network ID
2016-12-05 15:54:31 +01:00
pub network_id : u64 ,
2016-09-28 14:21:59 +02:00
/// Main "eth" subprotocol name.
pub subprotocol_name : [ u8 ; 3 ] ,
2017-02-02 15:22:38 +01:00
/// Light subprotocol name.
2016-12-08 23:21:47 +01:00
pub light_subprotocol_name : [ u8 ; 3 ] ,
2016-07-27 21:38:22 +02:00
/// Fork block to check
pub fork_block : Option < ( BlockNumber , H256 ) > ,
2016-10-18 18:16:00 +02:00
/// Enable snapshot sync
pub warp_sync : bool ,
2016-12-08 23:21:47 +01:00
/// Enable light client server.
pub serve_light : bool ,
2016-07-14 12:07:33 +02:00
}
impl Default for SyncConfig {
fn default ( ) -> SyncConfig {
SyncConfig {
max_download_ahead_blocks : 20000 ,
2016-11-22 18:03:35 +01:00
download_old_blocks : true ,
2016-11-03 22:22:25 +01:00
network_id : 1 ,
2016-09-30 13:44:52 +02:00
subprotocol_name : ETH_PROTOCOL ,
2017-02-02 15:22:38 +01:00
light_subprotocol_name : LIGHT_PROTOCOL ,
2016-07-27 21:38:22 +02:00
fork_block : None ,
2016-10-29 13:07:06 +02:00
warp_sync : false ,
2016-12-08 23:21:47 +01:00
serve_light : false ,
2016-07-14 12:07:33 +02:00
}
}
}
binary_fixed_size! ( SyncConfig ) ;
2017-02-17 21:38:43 +01:00
binary_fixed_size! ( EthSyncStatus ) ;
2016-07-14 12:07:33 +02:00
/// Current sync status
pub trait SyncProvider : Send + Sync {
/// Get sync status
2017-02-17 21:38:43 +01:00
fn status ( & self ) -> EthSyncStatus ;
2016-10-12 20:18:59 +02:00
/// Get peers information
fn peers ( & self ) -> Vec < PeerInfo > ;
2016-11-13 13:52:53 +01:00
2016-11-02 19:43:21 +01:00
/// Get the enode if available.
fn enode ( & self ) -> Option < String > ;
2016-11-16 13:37:21 +01:00
/// Returns propagation count for pending transactions.
fn transactions_stats ( & self ) -> BTreeMap < H256 , TransactionStats > ;
}
/// Transaction stats
2016-12-08 19:52:48 +01:00
#[ derive(Debug) ]
#[ cfg_attr(feature = " ipc " , derive(Binary)) ]
2016-11-16 13:37:21 +01:00
pub struct TransactionStats {
2016-12-08 19:52:48 +01:00
/// Block number where this TX was first seen.
2016-11-16 13:37:21 +01:00
pub first_seen : u64 ,
2016-12-08 19:52:48 +01:00
/// Peers it was propagated to.
2016-11-16 13:37:21 +01:00
pub propagated_to : BTreeMap < H512 , usize > ,
2016-10-12 20:18:59 +02:00
}
/// Peer connection information
2016-12-08 19:52:48 +01:00
#[ derive(Debug) ]
#[ cfg_attr(feature = " ipc " , derive(Binary)) ]
2016-10-12 20:18:59 +02:00
pub struct PeerInfo {
/// Public node id
pub id : Option < String > ,
/// Node client ID
pub client_version : String ,
/// Capabilities
2016-10-24 16:24:35 +02:00
pub capabilities : Vec < String > ,
2016-10-12 20:18:59 +02:00
/// Remote endpoint address
pub remote_address : String ,
/// Local endpoint address
pub local_address : String ,
2017-01-20 12:41:49 +01:00
/// Eth protocol info.
pub eth_info : Option < EthProtocolInfo > ,
/// Light protocol info.
2017-03-22 16:45:50 +01:00
pub pip_info : Option < PipProtocolInfo > ,
2017-01-20 12:41:49 +01:00
}
/// Ethereum protocol info.
#[ derive(Debug) ]
#[ cfg_attr(feature = " ipc " , derive(Binary)) ]
pub struct EthProtocolInfo {
/// Protocol version
pub version : u32 ,
2016-10-12 20:18:59 +02:00
/// SHA3 of peer best block hash
2017-01-20 12:41:49 +01:00
pub head : H256 ,
2016-10-12 20:18:59 +02:00
/// Peer total difficulty if known
2017-01-20 12:41:49 +01:00
pub difficulty : Option < U256 > ,
}
2017-03-22 16:45:50 +01:00
/// PIP protocol info.
2017-01-20 12:41:49 +01:00
#[ derive(Debug) ]
#[ cfg_attr(feature = " ipc " , derive(Binary)) ]
2017-03-22 16:45:50 +01:00
pub struct PipProtocolInfo {
2017-01-20 12:41:49 +01:00
/// Protocol version
pub version : u32 ,
/// SHA3 of peer best block hash
pub head : H256 ,
/// Peer total difficulty if known
pub difficulty : U256 ,
}
2017-03-22 16:45:50 +01:00
impl From < light_net ::Status > for PipProtocolInfo {
2017-01-20 12:41:49 +01:00
fn from ( status : light_net ::Status ) -> Self {
2017-03-22 16:45:50 +01:00
PipProtocolInfo {
2017-01-20 12:41:49 +01:00
version : status . protocol_version ,
head : status . head_hash ,
difficulty : status . head_td ,
}
}
2016-07-14 12:07:33 +02:00
}
2017-07-14 20:40:28 +02:00
/// Configuration to attach alternate protocol handlers.
/// Only works when IPC is disabled.
#[ cfg(not(feature = " ipc " )) ]
pub struct AttachedProtocol {
/// The protocol handler in question.
pub handler : Arc < NetworkProtocolHandler + Send + Sync > ,
/// 3-character ID for the protocol.
pub protocol_id : ProtocolId ,
/// Packet count.
pub packet_count : u8 ,
/// Supported versions.
pub versions : & 'static [ u8 ] ,
}
/// Attached protocol: disabled in IPC mode.
#[ cfg(feature = " ipc " ) ]
#[ cfg_attr(feature = " ipc " , derive(Binary)) ]
pub struct AttachedProtocol ;
impl AttachedProtocol {
#[ cfg(feature = " ipc " ) ]
fn register ( & self , network : & NetworkService ) {
let res = network . register_protocol (
self . handler . clone ( ) ,
self . protocol_id ,
self . packet_count ,
self . versions
) ;
if let Err ( e ) = res {
warn! ( target : " sync " , " Error attaching protocol {:?} " , protocol_id ) ;
}
}
#[ cfg(not(feature = " ipc " )) ]
fn register ( & self , _network : & NetworkService ) { }
}
2016-12-08 23:21:47 +01:00
/// EthSync initialization parameters.
#[ cfg_attr(feature = " ipc " , derive(Binary)) ]
pub struct Params {
/// Configuration.
pub config : SyncConfig ,
/// Blockchain client.
pub chain : Arc < BlockChainClient > ,
/// Snapshot service.
pub snapshot_service : Arc < SnapshotService > ,
/// Light data provider.
pub provider : Arc < ::light ::Provider > ,
/// Network layer configuration.
pub network_config : NetworkConfiguration ,
2017-07-14 20:40:28 +02:00
/// Other protocols to attach.
pub attached_protos : Vec < AttachedProtocol > ,
2016-12-08 23:21:47 +01:00
}
2016-07-14 12:07:33 +02:00
/// Ethereum network protocol handler
pub struct EthSync {
/// Network service
network : NetworkService ,
2016-12-08 23:21:47 +01:00
/// Main (eth/par) protocol handler
2016-08-15 14:25:57 +02:00
eth_handler : Arc < SyncProtocolHandler > ,
2017-03-22 16:45:50 +01:00
/// Light (pip) protocol handler
2016-12-08 23:21:47 +01:00
light_proto : Option < Arc < LightProtocol > > ,
2017-07-14 20:40:28 +02:00
/// Other protocols to attach.
attached_protos : Vec < AttachedProtocol > ,
2016-09-28 14:21:59 +02:00
/// The main subprotocol name
subprotocol_name : [ u8 ; 3 ] ,
2016-12-08 23:21:47 +01:00
/// Light subprotocol name.
light_subprotocol_name : [ u8 ; 3 ] ,
2016-07-14 12:07:33 +02:00
}
impl EthSync {
/// Creates and register protocol with the network service
2017-08-29 14:38:01 +02:00
pub fn new ( params : Params , connection_filter : Option < Arc < ConnectionFilter > > ) -> Result < Arc < EthSync > , NetworkError > {
2017-05-23 12:31:09 +02:00
const MAX_LIGHTSERV_LOAD : f64 = 0.5 ;
2016-12-10 14:56:41 +01:00
let pruning_info = params . chain . pruning_info ( ) ;
2016-12-08 23:21:47 +01:00
let light_proto = match params . config . serve_light {
false = > None ,
true = > Some ( {
2017-05-23 12:31:09 +02:00
let sample_store = params . network_config . net_config_path
. clone ( )
. map ( ::std ::path ::PathBuf ::from )
. map ( | mut p | { p . push ( " request_timings " ) ; light_net ::FileStore ( p ) } )
. map ( | store | Box ::new ( store ) as Box < _ > ) ;
let mut light_params = LightParams {
2016-12-08 23:21:47 +01:00
network_id : params . config . network_id ,
2017-05-23 12:31:09 +02:00
config : Default ::default ( ) ,
2016-12-08 23:21:47 +01:00
capabilities : Capabilities {
serve_headers : true ,
serve_chain_since : Some ( pruning_info . earliest_chain ) ,
serve_state_since : Some ( pruning_info . earliest_state ) ,
tx_relay : true ,
} ,
2017-05-23 12:31:09 +02:00
sample_store : sample_store ,
2016-12-08 23:21:47 +01:00
} ;
2017-05-23 12:31:09 +02:00
let max_peers = ::std ::cmp ::min ( params . network_config . max_peers , 1 ) ;
light_params . config . load_share = MAX_LIGHTSERV_LOAD / max_peers as f64 ;
2016-12-08 23:21:47 +01:00
let mut light_proto = LightProtocol ::new ( params . provider , light_params ) ;
2017-01-11 14:39:03 +01:00
light_proto . add_handler ( Arc ::new ( TxRelay ( params . chain . clone ( ) ) ) ) ;
2016-12-08 23:21:47 +01:00
Arc ::new ( light_proto )
} )
} ;
let chain_sync = ChainSync ::new ( params . config , & * params . chain ) ;
2017-08-29 14:38:01 +02:00
let service = NetworkService ::new ( params . network_config . clone ( ) . into_basic ( ) ? , connection_filter ) ? ;
2016-12-08 23:21:47 +01:00
let sync = Arc ::new ( EthSync {
2016-07-14 12:07:33 +02:00
network : service ,
2016-11-07 12:34:45 +01:00
eth_handler : Arc ::new ( SyncProtocolHandler {
2016-10-18 18:16:00 +02:00
sync : RwLock ::new ( chain_sync ) ,
2016-12-08 23:21:47 +01:00
chain : params . chain ,
snapshot_service : params . snapshot_service ,
2016-11-07 12:34:45 +01:00
overlay : RwLock ::new ( HashMap ::new ( ) ) ,
} ) ,
2016-12-08 23:21:47 +01:00
light_proto : light_proto ,
subprotocol_name : params . config . subprotocol_name ,
light_subprotocol_name : params . config . light_subprotocol_name ,
2017-07-14 20:40:28 +02:00
attached_protos : params . attached_protos ,
2016-07-14 12:07:33 +02:00
} ) ;
Ok ( sync )
}
}
2016-12-08 19:52:48 +01:00
#[ cfg_attr(feature = " ipc " , ipc(client_ident= " SyncClient " )) ]
2016-07-14 12:07:33 +02:00
impl SyncProvider for EthSync {
/// Get sync status
2017-02-17 21:38:43 +01:00
fn status ( & self ) -> EthSyncStatus {
2016-08-15 14:25:57 +02:00
self . eth_handler . sync . write ( ) . status ( )
2016-07-14 12:07:33 +02:00
}
2016-10-12 20:18:59 +02:00
/// Get sync peers
fn peers ( & self ) -> Vec < PeerInfo > {
2017-01-20 12:41:49 +01:00
self . network . with_context_eval ( self . subprotocol_name , | ctx | {
let peer_ids = self . network . connected_peers ( ) ;
let eth_sync = self . eth_handler . sync . read ( ) ;
let light_proto = self . light_proto . as_ref ( ) ;
peer_ids . into_iter ( ) . filter_map ( | peer_id | {
let session_info = match ctx . session_info ( peer_id ) {
None = > return None ,
Some ( info ) = > info ,
} ;
Some ( PeerInfo {
id : session_info . id . map ( | id | id . hex ( ) ) ,
client_version : session_info . client_version ,
capabilities : session_info . peer_capabilities . into_iter ( ) . map ( | c | c . to_string ( ) ) . collect ( ) ,
remote_address : session_info . remote_address ,
local_address : session_info . local_address ,
eth_info : eth_sync . peer_info ( & peer_id ) ,
2017-03-22 16:45:50 +01:00
pip_info : light_proto . as_ref ( ) . and_then ( | lp | lp . peer_status ( & peer_id ) ) . map ( Into ::into ) ,
2017-01-20 12:41:49 +01:00
} )
} ) . collect ( )
} ) . unwrap_or_else ( Vec ::new )
2016-10-12 20:18:59 +02:00
}
2016-11-02 19:43:21 +01:00
fn enode ( & self ) -> Option < String > {
self . network . external_url ( )
}
2016-11-16 13:37:21 +01:00
fn transactions_stats ( & self ) -> BTreeMap < H256 , TransactionStats > {
2016-11-25 12:36:25 +01:00
let sync = self . eth_handler . sync . read ( ) ;
2016-11-16 13:37:21 +01:00
sync . transactions_stats ( )
. iter ( )
. map ( | ( hash , stats ) | ( * hash , stats . into ( ) ) )
. collect ( )
}
2016-07-14 12:07:33 +02:00
}
struct SyncProtocolHandler {
2016-08-15 14:25:57 +02:00
/// Shared blockchain client.
2016-07-15 15:32:29 +02:00
chain : Arc < BlockChainClient > ,
2016-09-06 15:31:13 +02:00
/// Shared snapshot service.
snapshot_service : Arc < SnapshotService > ,
2016-07-14 12:07:33 +02:00
/// Sync strategy
sync : RwLock < ChainSync > ,
2016-10-18 18:16:00 +02:00
/// Chain overlay used to cache data such as fork block.
overlay : RwLock < HashMap < BlockNumber , Bytes > > ,
2016-07-14 12:07:33 +02:00
}
impl NetworkProtocolHandler for SyncProtocolHandler {
2017-07-14 20:40:28 +02:00
fn initialize ( & self , io : & NetworkContext , _host_info : & HostInfo ) {
2016-10-24 16:24:35 +02:00
if io . subprotocol_name ( ) ! = WARP_SYNC_PROTOCOL_ID {
io . register_timer ( 0 , 1000 ) . expect ( " Error registering sync timer " ) ;
}
2016-07-14 12:07:33 +02:00
}
fn read ( & self , io : & NetworkContext , peer : & PeerId , packet_id : u8 , data : & [ u8 ] ) {
2016-10-18 18:16:00 +02:00
ChainSync ::dispatch_packet ( & self . sync , & mut NetSyncIo ::new ( io , & * self . chain , & * self . snapshot_service , & self . overlay ) , * peer , packet_id , data ) ;
2016-07-14 12:07:33 +02:00
}
fn connected ( & self , io : & NetworkContext , peer : & PeerId ) {
2016-10-24 16:24:35 +02:00
// If warp protocol is supported only allow warp handshake
let warp_protocol = io . protocol_version ( WARP_SYNC_PROTOCOL_ID , * peer ) . unwrap_or ( 0 ) ! = 0 ;
let warp_context = io . subprotocol_name ( ) = = WARP_SYNC_PROTOCOL_ID ;
if warp_protocol = = warp_context {
self . sync . write ( ) . on_peer_connected ( & mut NetSyncIo ::new ( io , & * self . chain , & * self . snapshot_service , & self . overlay ) , * peer ) ;
}
2016-07-14 12:07:33 +02:00
}
fn disconnected ( & self , io : & NetworkContext , peer : & PeerId ) {
2016-10-24 16:24:35 +02:00
if io . subprotocol_name ( ) ! = WARP_SYNC_PROTOCOL_ID {
self . sync . write ( ) . on_peer_aborting ( & mut NetSyncIo ::new ( io , & * self . chain , & * self . snapshot_service , & self . overlay ) , * peer ) ;
}
2016-07-14 12:07:33 +02:00
}
fn timeout ( & self , io : & NetworkContext , _timer : TimerToken ) {
2016-10-18 18:16:00 +02:00
self . sync . write ( ) . maintain_peers ( & mut NetSyncIo ::new ( io , & * self . chain , & * self . snapshot_service , & self . overlay ) ) ;
self . sync . write ( ) . maintain_sync ( & mut NetSyncIo ::new ( io , & * self . chain , & * self . snapshot_service , & self . overlay ) ) ;
self . sync . write ( ) . propagate_new_transactions ( & mut NetSyncIo ::new ( io , & * self . chain , & * self . snapshot_service , & self . overlay ) ) ;
2016-07-14 12:07:33 +02:00
}
}
impl ChainNotify for EthSync {
fn new_blocks ( & self ,
imported : Vec < H256 > ,
invalid : Vec < H256 > ,
enacted : Vec < H256 > ,
retracted : Vec < H256 > ,
2016-07-20 12:36:20 +02:00
sealed : Vec < H256 > ,
2016-12-08 12:03:34 +01:00
proposed : Vec < Bytes > ,
2016-07-20 12:36:20 +02:00
_duration : u64 )
2016-07-14 12:07:33 +02:00
{
2016-12-08 23:57:09 +01:00
use light ::net ::Announcement ;
2016-09-28 14:21:59 +02:00
self . network . with_context ( self . subprotocol_name , | context | {
2016-11-07 12:34:45 +01:00
let mut sync_io = NetSyncIo ::new ( context , & * self . eth_handler . chain , & * self . eth_handler . snapshot_service , & self . eth_handler . overlay ) ;
2016-08-15 14:25:57 +02:00
self . eth_handler . sync . write ( ) . chain_new_blocks (
2016-07-14 12:07:33 +02:00
& mut sync_io ,
& imported ,
& invalid ,
& enacted ,
& retracted ,
2016-12-08 12:03:34 +01:00
& sealed ,
& proposed ) ;
2016-07-14 12:07:33 +02:00
} ) ;
2016-12-08 23:57:09 +01:00
self . network . with_context ( self . light_subprotocol_name , | context | {
let light_proto = match self . light_proto . as_ref ( ) {
Some ( lp ) = > lp ,
None = > return ,
} ;
2016-12-16 17:38:16 +01:00
2016-12-10 11:01:23 +01:00
let chain_info = self . eth_handler . chain . chain_info ( ) ;
2016-12-08 23:57:09 +01:00
light_proto . make_announcement ( context , Announcement {
head_hash : chain_info . best_block_hash ,
head_num : chain_info . best_block_number ,
head_td : chain_info . total_difficulty ,
reorg_depth : 0 , // recalculated on a per-peer basis.
serve_headers : false , // these fields consist of _changes_ in capability.
serve_state_since : None ,
serve_chain_since : None ,
tx_relay : false ,
} )
} )
2016-07-14 12:07:33 +02:00
}
fn start ( & self ) {
2016-10-25 15:55:53 +02:00
match self . network . start ( ) {
Err ( NetworkError ::StdIo ( ref e ) ) if e . kind ( ) = = io ::ErrorKind ::AddrInUse = > warn! ( " Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option. " , self . network . config ( ) . listen_address . expect ( " Listen address is not set. " ) ) ,
Err ( err ) = > warn! ( " Error starting network: {} " , err ) ,
_ = > { } ,
}
2016-11-07 12:34:45 +01:00
self . network . register_protocol ( self . eth_handler . clone ( ) , self . subprotocol_name , ETH_PACKET_COUNT , & [ 62 u8 , 63 u8 ] )
2016-07-14 12:07:33 +02:00
. unwrap_or_else ( | e | warn! ( " Error registering ethereum protocol: {:?} " , e ) ) ;
2016-10-24 16:24:35 +02:00
// register the warp sync subprotocol
2016-11-30 16:47:20 +01:00
self . network . register_protocol ( self . eth_handler . clone ( ) , WARP_SYNC_PROTOCOL_ID , SNAPSHOT_SYNC_PACKET_COUNT , & [ 1 u8 , 2 u8 ] )
2016-10-24 16:24:35 +02:00
. unwrap_or_else ( | e | warn! ( " Error registering snapshot sync protocol: {:?} " , e ) ) ;
2016-12-10 14:56:41 +01:00
2016-12-08 23:21:47 +01:00
// register the light protocol.
if let Some ( light_proto ) = self . light_proto . as_ref ( ) . map ( | x | x . clone ( ) ) {
self . network . register_protocol ( light_proto , self . light_subprotocol_name , ::light ::net ::PACKET_COUNT , ::light ::net ::PROTOCOL_VERSIONS )
. unwrap_or_else ( | e | warn! ( " Error registering light client protocol: {:?} " , e ) ) ;
}
2017-07-14 20:40:28 +02:00
// register any attached protocols.
for proto in & self . attached_protos { proto . register ( & self . network ) }
2016-07-14 12:07:33 +02:00
}
fn stop ( & self ) {
2016-11-16 14:13:21 +01:00
self . eth_handler . snapshot_service . abort_restore ( ) ;
2016-07-14 12:07:33 +02:00
self . network . stop ( ) . unwrap_or_else ( | e | warn! ( " Error stopping network: {:?} " , e ) ) ;
}
2016-08-15 14:25:57 +02:00
2016-08-26 13:16:56 +02:00
fn broadcast ( & self , message : Vec < u8 > ) {
2016-12-01 15:48:56 +01:00
self . network . with_context ( WARP_SYNC_PROTOCOL_ID , | context | {
2016-11-07 12:34:45 +01:00
let mut sync_io = NetSyncIo ::new ( context , & * self . eth_handler . chain , & * self . eth_handler . snapshot_service , & self . eth_handler . overlay ) ;
2016-11-29 16:54:30 +01:00
self . eth_handler . sync . write ( ) . propagate_consensus_packet ( & mut sync_io , message . clone ( ) ) ;
2016-08-15 14:25:57 +02:00
} ) ;
}
2016-12-12 21:28:46 +01:00
2016-12-10 21:22:19 +01:00
fn transactions_received ( & self , hashes : Vec < H256 > , peer_id : PeerId ) {
2016-12-12 21:28:46 +01:00
let mut sync = self . eth_handler . sync . write ( ) ;
2016-12-10 21:22:19 +01:00
sync . transactions_received ( hashes , peer_id ) ;
2016-12-10 14:56:41 +01:00
}
2016-07-14 12:07:33 +02:00
}
2017-03-22 16:45:50 +01:00
/// PIP event handler.
2016-12-08 23:21:47 +01:00
/// Simply queues transactions from light client peers.
struct TxRelay ( Arc < BlockChainClient > ) ;
impl LightHandler for TxRelay {
2017-01-13 09:51:36 +01:00
fn on_transactions ( & self , ctx : & EventContext , relay : & [ ::ethcore ::transaction ::UnverifiedTransaction ] ) {
2017-03-23 20:02:46 +01:00
trace! ( target : " pip " , " Relaying {} transactions from peer {} " , relay . len ( ) , ctx . peer ( ) ) ;
2017-06-28 14:16:53 +02:00
self . 0. queue_transactions ( relay . iter ( ) . map ( | tx | ::rlp ::encode ( tx ) . into_vec ( ) ) . collect ( ) , ctx . peer ( ) )
2016-12-08 23:21:47 +01:00
}
}
2016-07-16 19:24:45 +02:00
impl IpcConfig for ManageNetwork { }
impl IpcConfig for SyncProvider { }
2016-07-14 12:07:33 +02:00
/// Trait for managing network
pub trait ManageNetwork : Send + Sync {
/// Set to allow unreserved peers to connect
fn accept_unreserved_peers ( & self ) ;
/// Set to deny unreserved peers to connect
fn deny_unreserved_peers ( & self ) ;
/// Remove reservation for the peer
fn remove_reserved_peer ( & self , peer : String ) -> Result < ( ) , String > ;
/// Add reserved peer
fn add_reserved_peer ( & self , peer : String ) -> Result < ( ) , String > ;
/// Start network
fn start_network ( & self ) ;
/// Stop network
fn stop_network ( & self ) ;
/// Query the current configuration of the network
fn network_config ( & self ) -> NetworkConfiguration ;
}
2016-12-08 19:52:48 +01:00
#[ cfg_attr(feature = " ipc " , ipc(client_ident= " NetworkManagerClient " )) ]
2016-07-14 12:07:33 +02:00
impl ManageNetwork for EthSync {
fn accept_unreserved_peers ( & self ) {
self . network . set_non_reserved_mode ( NonReservedPeerMode ::Accept ) ;
}
fn deny_unreserved_peers ( & self ) {
self . network . set_non_reserved_mode ( NonReservedPeerMode ::Deny ) ;
}
fn remove_reserved_peer ( & self , peer : String ) -> Result < ( ) , String > {
self . network . remove_reserved_peer ( & peer ) . map_err ( | e | format! ( " {:?} " , e ) )
}
fn add_reserved_peer ( & self , peer : String ) -> Result < ( ) , String > {
self . network . add_reserved_peer ( & peer ) . map_err ( | e | format! ( " {:?} " , e ) )
}
fn start_network ( & self ) {
self . start ( ) ;
}
fn stop_network ( & self ) {
2016-09-28 14:21:59 +02:00
self . network . with_context ( self . subprotocol_name , | context | {
2016-11-07 12:34:45 +01:00
let mut sync_io = NetSyncIo ::new ( context , & * self . eth_handler . chain , & * self . eth_handler . snapshot_service , & self . eth_handler . overlay ) ;
2016-08-15 14:25:57 +02:00
self . eth_handler . sync . write ( ) . abort ( & mut sync_io ) ;
2016-07-14 12:07:33 +02:00
} ) ;
2016-12-08 23:21:47 +01:00
if let Some ( light_proto ) = self . light_proto . as_ref ( ) {
light_proto . abort ( ) ;
}
2016-07-14 12:07:33 +02:00
self . stop ( ) ;
}
fn network_config ( & self ) -> NetworkConfiguration {
NetworkConfiguration ::from ( self . network . config ( ) . clone ( ) )
}
}
2016-12-08 19:52:48 +01:00
#[ derive(Debug, Clone, PartialEq, Eq) ]
2016-12-21 15:09:35 +01:00
#[ cfg_attr(feature = " ipc " , binary) ]
2016-07-14 12:07:33 +02:00
/// Network service configuration
pub struct NetworkConfiguration {
2016-08-21 11:23:47 +02:00
/// Directory path to store general network configuration. None means nothing will be saved
2016-07-14 12:07:33 +02:00
pub config_path : Option < String > ,
2016-08-21 11:23:47 +02:00
/// Directory path to store network-specific configuration. None means nothing will be saved
pub net_config_path : Option < String > ,
2016-07-14 12:07:33 +02:00
/// IP address to listen for incoming connections. Listen to all connections by default
pub listen_address : Option < String > ,
/// IP address to advertise. Detected automatically if none.
pub public_address : Option < String > ,
/// Port for UDP connections, same as TCP by default
pub udp_port : Option < u16 > ,
/// Enable NAT configuration
pub nat_enabled : bool ,
/// Enable discovery
pub discovery_enabled : bool ,
/// List of initial node addresses
pub boot_nodes : Vec < String > ,
/// Use provided node key instead of default
2017-01-11 12:16:47 +01:00
pub use_secret : Option < Secret > ,
2016-07-29 17:30:02 +02:00
/// Max number of connected peers to maintain
pub max_peers : u32 ,
/// Min number of connected peers to maintain
pub min_peers : u32 ,
2016-10-24 18:25:27 +02:00
/// Max pending peers.
pub max_pending_peers : u32 ,
/// Reserved snapshot sync peers.
pub snapshot_peers : u32 ,
2016-07-14 12:07:33 +02:00
/// List of reserved node addresses.
pub reserved_nodes : Vec < String > ,
/// The non-reserved peer mode.
pub allow_non_reserved : bool ,
2016-10-24 18:25:27 +02:00
/// IP Filtering
2017-07-28 19:06:39 +02:00
pub ip_filter : IpFilter ,
2016-07-14 12:07:33 +02:00
}
impl NetworkConfiguration {
2016-12-08 19:52:48 +01:00
/// Create a new default config.
2016-08-05 10:32:04 +02:00
pub fn new ( ) -> Self {
From ::from ( BasicNetworkConfiguration ::new ( ) )
}
2016-12-08 19:52:48 +01:00
/// Create a new local config.
2016-08-05 10:32:04 +02:00
pub fn new_local ( ) -> Self {
From ::from ( BasicNetworkConfiguration ::new_local ( ) )
}
2016-12-08 19:52:48 +01:00
/// Attempt to convert this config into a BasicNetworkConfiguration.
2016-07-14 12:07:33 +02:00
pub fn into_basic ( self ) -> Result < BasicNetworkConfiguration , AddrParseError > {
Ok ( BasicNetworkConfiguration {
config_path : self . config_path ,
2016-08-21 11:23:47 +02:00
net_config_path : self . net_config_path ,
2016-12-27 12:53:56 +01:00
listen_address : match self . listen_address { None = > None , Some ( addr ) = > Some ( SocketAddr ::from_str ( & addr ) ? ) } ,
public_address : match self . public_address { None = > None , Some ( addr ) = > Some ( SocketAddr ::from_str ( & addr ) ? ) } ,
2016-07-14 12:07:33 +02:00
udp_port : self . udp_port ,
nat_enabled : self . nat_enabled ,
discovery_enabled : self . discovery_enabled ,
boot_nodes : self . boot_nodes ,
use_secret : self . use_secret ,
2016-07-29 17:30:02 +02:00
max_peers : self . max_peers ,
min_peers : self . min_peers ,
2016-10-24 18:25:27 +02:00
max_handshakes : self . max_pending_peers ,
reserved_protocols : hash_map ! [ WARP_SYNC_PROTOCOL_ID = > self . snapshot_peers ] ,
2016-07-14 12:07:33 +02:00
reserved_nodes : self . reserved_nodes ,
2017-07-28 19:06:39 +02:00
ip_filter : self . ip_filter ,
2016-07-14 12:07:33 +02:00
non_reserved_mode : if self . allow_non_reserved { NonReservedPeerMode ::Accept } else { NonReservedPeerMode ::Deny } ,
} )
}
}
impl From < BasicNetworkConfiguration > for NetworkConfiguration {
fn from ( other : BasicNetworkConfiguration ) -> Self {
NetworkConfiguration {
config_path : other . config_path ,
2016-08-21 11:23:47 +02:00
net_config_path : other . net_config_path ,
2016-07-14 12:07:33 +02:00
listen_address : other . listen_address . and_then ( | addr | Some ( format! ( " {} " , addr ) ) ) ,
public_address : other . public_address . and_then ( | addr | Some ( format! ( " {} " , addr ) ) ) ,
udp_port : other . udp_port ,
nat_enabled : other . nat_enabled ,
discovery_enabled : other . discovery_enabled ,
boot_nodes : other . boot_nodes ,
use_secret : other . use_secret ,
2016-07-29 17:30:02 +02:00
max_peers : other . max_peers ,
min_peers : other . min_peers ,
2016-10-24 18:25:27 +02:00
max_pending_peers : other . max_handshakes ,
snapshot_peers : * other . reserved_protocols . get ( & WARP_SYNC_PROTOCOL_ID ) . unwrap_or ( & 0 ) ,
2016-07-14 12:07:33 +02:00
reserved_nodes : other . reserved_nodes ,
2017-07-28 19:06:39 +02:00
ip_filter : other . ip_filter ,
2016-07-14 12:07:33 +02:00
allow_non_reserved : match other . non_reserved_mode { NonReservedPeerMode ::Accept = > true , _ = > false } ,
}
}
}
2016-07-20 18:13:56 +02:00
2016-12-08 19:52:48 +01:00
/// Configuration for IPC service.
#[ derive(Debug, Clone) ]
2016-12-21 15:09:35 +01:00
#[ cfg_attr(feature = " ipc " , binary) ]
2016-07-20 18:13:56 +02:00
pub struct ServiceConfiguration {
2016-12-08 19:52:48 +01:00
/// Sync config.
2016-07-20 18:13:56 +02:00
pub sync : SyncConfig ,
2016-12-08 19:52:48 +01:00
/// Network configuration.
2016-07-20 18:13:56 +02:00
pub net : NetworkConfiguration ,
2016-12-08 19:52:48 +01:00
/// IPC path.
2016-08-22 18:41:58 +02:00
pub io_path : String ,
2016-07-20 18:13:56 +02:00
}
2016-12-16 17:38:16 +01:00
2017-02-17 21:38:43 +01:00
/// Numbers of peers (max, min, active).
#[ derive(Debug, Clone) ]
#[ cfg_attr(feature = " ipc " , binary) ]
pub struct PeerNumbers {
/// Number of connected peers.
pub connected : usize ,
/// Number of active peers.
pub active : usize ,
/// Max peers.
pub max : usize ,
/// Min peers.
pub min : usize ,
}
/// Light synchronization.
pub trait LightSyncProvider {
/// Get peer numbers.
fn peer_numbers ( & self ) -> PeerNumbers ;
/// Get peers information
fn peers ( & self ) -> Vec < PeerInfo > ;
2017-03-22 21:09:43 +01:00
/// Get network id.
fn network_id ( & self ) -> u64 ;
2017-02-17 21:38:43 +01:00
/// Get the enode if available.
fn enode ( & self ) -> Option < String > ;
/// Returns propagation count for pending transactions.
fn transactions_stats ( & self ) -> BTreeMap < H256 , TransactionStats > ;
}
2016-12-16 17:38:16 +01:00
/// Configuration for the light sync.
pub struct LightSyncParams < L > {
/// Network configuration.
pub network_config : BasicNetworkConfiguration ,
/// Light client to sync to.
pub client : Arc < L > ,
/// Network ID.
pub network_id : u64 ,
/// Subprotocol name.
pub subprotocol_name : [ u8 ; 3 ] ,
2017-03-22 22:00:52 +01:00
/// Other handlers to attach.
pub handlers : Vec < Arc < LightHandler > > ,
2017-07-14 20:40:28 +02:00
/// Other subprotocols to run.
pub attached_protos : Vec < AttachedProtocol > ,
2016-12-16 17:38:16 +01:00
}
/// Service for light synchronization.
pub struct LightSync {
proto : Arc < LightProtocol > ,
2017-03-23 03:23:53 +01:00
sync : Arc < ::light_sync ::SyncInfo + Sync + Send > ,
2017-07-14 20:40:28 +02:00
attached_protos : Vec < AttachedProtocol > ,
2016-12-16 17:38:16 +01:00
network : NetworkService ,
subprotocol_name : [ u8 ; 3 ] ,
2017-03-22 21:09:43 +01:00
network_id : u64 ,
2016-12-16 17:38:16 +01:00
}
impl LightSync {
/// Create a new light sync service.
pub fn new < L > ( params : LightSyncParams < L > ) -> Result < Self , NetworkError >
2017-02-09 18:42:18 +01:00
where L : AsLightClient + Provider + Sync + Send + 'static
2016-12-16 17:38:16 +01:00
{
use light_sync ::LightSync as SyncHandler ;
// initialize light protocol handler and attach sync module.
2017-03-23 03:23:53 +01:00
let ( sync , light_proto ) = {
2016-12-16 17:38:16 +01:00
let light_params = LightParams {
network_id : params . network_id ,
2017-05-23 12:31:09 +02:00
config : Default ::default ( ) ,
2016-12-16 17:38:16 +01:00
capabilities : Capabilities {
serve_headers : false ,
serve_chain_since : None ,
serve_state_since : None ,
tx_relay : false ,
} ,
2017-05-23 12:31:09 +02:00
sample_store : None ,
2016-12-16 17:38:16 +01:00
} ;
let mut light_proto = LightProtocol ::new ( params . client . clone ( ) , light_params ) ;
2017-06-18 16:15:44 +02:00
let sync_handler = Arc ::new ( SyncHandler ::new ( params . client . clone ( ) ) ? ) ;
2017-03-23 03:23:53 +01:00
light_proto . add_handler ( sync_handler . clone ( ) ) ;
2016-12-16 17:38:16 +01:00
2017-03-22 22:00:52 +01:00
for handler in params . handlers {
light_proto . add_handler ( handler ) ;
}
2017-03-23 03:23:53 +01:00
( sync_handler , Arc ::new ( light_proto ) )
2016-12-16 17:38:16 +01:00
} ;
2017-08-29 14:38:01 +02:00
let service = NetworkService ::new ( params . network_config , None ) ? ;
2016-12-16 17:38:16 +01:00
Ok ( LightSync {
proto : light_proto ,
2017-03-23 03:23:53 +01:00
sync : sync ,
2017-07-14 20:40:28 +02:00
attached_protos : params . attached_protos ,
2016-12-16 17:38:16 +01:00
network : service ,
subprotocol_name : params . subprotocol_name ,
2017-03-22 21:09:43 +01:00
network_id : params . network_id ,
2016-12-16 17:38:16 +01:00
} )
}
2017-02-02 17:02:46 +01:00
/// Execute a closure with a protocol context.
pub fn with_context < F , T > ( & self , f : F ) -> Option < T >
where F : FnOnce ( & ::light ::net ::BasicContext ) -> T
{
self . network . with_context_eval (
self . subprotocol_name ,
move | ctx | self . proto . with_context ( ctx , f ) ,
)
}
2016-12-16 17:38:16 +01:00
}
2017-03-23 03:23:53 +01:00
impl ::std ::ops ::Deref for LightSync {
type Target = ::light_sync ::SyncInfo ;
fn deref ( & self ) -> & Self ::Target { & * self . sync }
}
2016-12-16 17:38:16 +01:00
impl ManageNetwork for LightSync {
fn accept_unreserved_peers ( & self ) {
self . network . set_non_reserved_mode ( NonReservedPeerMode ::Accept ) ;
}
fn deny_unreserved_peers ( & self ) {
self . network . set_non_reserved_mode ( NonReservedPeerMode ::Deny ) ;
}
fn remove_reserved_peer ( & self , peer : String ) -> Result < ( ) , String > {
self . network . remove_reserved_peer ( & peer ) . map_err ( | e | format! ( " {:?} " , e ) )
}
fn add_reserved_peer ( & self , peer : String ) -> Result < ( ) , String > {
self . network . add_reserved_peer ( & peer ) . map_err ( | e | format! ( " {:?} " , e ) )
}
fn start_network ( & self ) {
match self . network . start ( ) {
Err ( NetworkError ::StdIo ( ref e ) ) if e . kind ( ) = = io ::ErrorKind ::AddrInUse = > warn! ( " Network port {:?} is already in use, make sure that another instance of an Ethereum client is not running or change the port using the --port option. " , self . network . config ( ) . listen_address . expect ( " Listen address is not set. " ) ) ,
Err ( err ) = > warn! ( " Error starting network: {} " , err ) ,
_ = > { } ,
}
let light_proto = self . proto . clone ( ) ;
self . network . register_protocol ( light_proto , self . subprotocol_name , ::light ::net ::PACKET_COUNT , ::light ::net ::PROTOCOL_VERSIONS )
. unwrap_or_else ( | e | warn! ( " Error registering light client protocol: {:?} " , e ) ) ;
2017-07-14 20:40:28 +02:00
for proto in & self . attached_protos { proto . register ( & self . network ) }
2016-12-16 17:38:16 +01:00
}
fn stop_network ( & self ) {
self . proto . abort ( ) ;
if let Err ( e ) = self . network . stop ( ) {
warn! ( " Error stopping network: {} " , e ) ;
}
}
fn network_config ( & self ) -> NetworkConfiguration {
NetworkConfiguration ::from ( self . network . config ( ) . clone ( ) )
}
}
2017-01-11 12:16:47 +01:00
2017-02-17 21:38:43 +01:00
impl LightSyncProvider for LightSync {
fn peer_numbers ( & self ) -> PeerNumbers {
let ( connected , active ) = self . proto . peer_count ( ) ;
let config = self . network_config ( ) ;
PeerNumbers {
connected : connected ,
active : active ,
max : config . max_peers as usize ,
min : config . min_peers as usize ,
}
}
fn peers ( & self ) -> Vec < PeerInfo > {
self . network . with_context_eval ( self . subprotocol_name , | ctx | {
let peer_ids = self . network . connected_peers ( ) ;
peer_ids . into_iter ( ) . filter_map ( | peer_id | {
let session_info = match ctx . session_info ( peer_id ) {
None = > return None ,
Some ( info ) = > info ,
} ;
Some ( PeerInfo {
id : session_info . id . map ( | id | id . hex ( ) ) ,
client_version : session_info . client_version ,
capabilities : session_info . peer_capabilities . into_iter ( ) . map ( | c | c . to_string ( ) ) . collect ( ) ,
remote_address : session_info . remote_address ,
local_address : session_info . local_address ,
eth_info : None ,
2017-03-22 16:45:50 +01:00
pip_info : self . proto . peer_status ( & peer_id ) . map ( Into ::into ) ,
2017-02-17 21:38:43 +01:00
} )
} ) . collect ( )
} ) . unwrap_or_else ( Vec ::new )
}
fn enode ( & self ) -> Option < String > {
self . network . external_url ( )
}
2017-03-22 21:09:43 +01:00
fn network_id ( & self ) -> u64 {
self . network_id
}
2017-02-17 21:38:43 +01:00
fn transactions_stats ( & self ) -> BTreeMap < H256 , TransactionStats > {
Default ::default ( ) // TODO
}
}