2016-07-14 12:07:33 +02:00
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// 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 ;
2016-10-24 16:24:35 +02:00
use network ::{ NetworkProtocolHandler , NetworkService , NetworkContext , PeerId , ProtocolId ,
2016-10-24 18:25:27 +02:00
NetworkConfiguration as BasicNetworkConfiguration , NonReservedPeerMode , NetworkError ,
AllowIP as NetworkAllowIP } ;
2016-11-16 13:37:21 +01:00
use util ::{ U256 , H256 , H512 } ;
2016-08-05 10:32:04 +02:00
use io ::{ TimerToken } ;
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 ;
2016-07-14 12:07:33 +02:00
use chain ::{ ChainSync , SyncStatus } ;
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 } ;
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
/// 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 ,
/// Network ID
2016-11-03 22:22:25 +01:00
pub network_id : usize ,
2016-09-28 14:21:59 +02:00
/// Main "eth" subprotocol name.
pub 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-07-14 12:07:33 +02:00
}
impl Default for SyncConfig {
fn default ( ) -> SyncConfig {
SyncConfig {
max_download_ahead_blocks : 20000 ,
2016-11-03 22:22:25 +01:00
network_id : 1 ,
2016-09-28 14:21:59 +02:00
subprotocol_name : * b " eth " ,
2016-07-27 21:38:22 +02:00
fork_block : None ,
2016-10-29 13:07:06 +02:00
warp_sync : false ,
2016-07-14 12:07:33 +02:00
}
}
}
binary_fixed_size! ( SyncConfig ) ;
binary_fixed_size! ( SyncStatus ) ;
/// Current sync status
pub trait SyncProvider : Send + Sync {
/// Get sync status
fn status ( & self ) -> SyncStatus ;
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
#[ derive(Debug, Binary) ]
pub struct TransactionStats {
pub first_seen : u64 ,
pub propagated_to : BTreeMap < H512 , usize > ,
2016-10-12 20:18:59 +02:00
}
/// Peer connection information
#[ derive(Debug, Binary) ]
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 ,
/// Ethereum protocol version
pub eth_version : u32 ,
/// SHA3 of peer best block hash
pub eth_head : H256 ,
/// Peer total difficulty if known
pub eth_difficulty : Option < U256 > ,
2016-07-14 12:07:33 +02:00
}
/// Ethereum network protocol handler
pub struct EthSync {
/// Network service
network : NetworkService ,
/// Protocol handler
handler : Arc < SyncProtocolHandler > ,
2016-09-28 14:21:59 +02:00
/// The main subprotocol name
subprotocol_name : [ u8 ; 3 ] ,
2016-10-24 18:25:27 +02:00
/// Configuration
config : NetworkConfiguration ,
2016-07-14 12:07:33 +02:00
}
impl EthSync {
/// Creates and register protocol with the network service
2016-09-06 15:31:13 +02:00
pub fn new ( config : SyncConfig , chain : Arc < BlockChainClient > , snapshot_service : Arc < SnapshotService > , network_config : NetworkConfiguration ) -> Result < Arc < EthSync > , NetworkError > {
2016-08-10 16:29:40 +02:00
let chain_sync = ChainSync ::new ( config , & * chain ) ;
2016-10-24 18:25:27 +02:00
let service = try ! ( NetworkService ::new ( try ! ( network_config . clone ( ) . into_basic ( ) ) ) ) ;
2016-07-14 12:07:33 +02:00
let sync = Arc ::new ( EthSync {
network : service ,
2016-10-18 18:16:00 +02:00
handler : Arc ::new ( SyncProtocolHandler {
sync : RwLock ::new ( chain_sync ) ,
chain : chain ,
snapshot_service : snapshot_service ,
overlay : RwLock ::new ( HashMap ::new ( ) ) ,
} ) ,
2016-09-28 14:21:59 +02:00
subprotocol_name : config . subprotocol_name ,
2016-10-24 18:25:27 +02:00
config : network_config ,
2016-07-14 12:07:33 +02:00
} ) ;
Ok ( sync )
}
}
#[ ipc(client_ident= " SyncClient " ) ]
impl SyncProvider for EthSync {
/// Get sync status
fn status ( & self ) -> SyncStatus {
self . handler . sync . write ( ) . status ( )
}
2016-10-12 20:18:59 +02:00
/// Get sync peers
fn peers ( & self ) -> Vec < PeerInfo > {
self . network . with_context_eval ( self . subprotocol_name , | context | {
2016-10-18 18:16:00 +02:00
let sync_io = NetSyncIo ::new ( context , & * self . handler . chain , & * self . handler . snapshot_service , & self . handler . overlay ) ;
2016-10-12 20:18:59 +02:00
self . handler . sync . write ( ) . peers ( & sync_io )
} ) . unwrap_or ( Vec ::new ( ) )
}
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 > {
let sync = self . handler . sync . read ( ) ;
sync . transactions_stats ( )
. iter ( )
. map ( | ( hash , stats ) | ( * hash , stats . into ( ) ) )
. collect ( )
}
2016-07-14 12:07:33 +02:00
}
struct SyncProtocolHandler {
2016-09-06 15:31:13 +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 {
fn initialize ( & self , io : & NetworkContext ) {
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 > ,
_duration : u64 )
2016-07-14 12:07:33 +02:00
{
2016-09-28 14:21:59 +02:00
self . network . with_context ( self . subprotocol_name , | context | {
2016-10-18 18:16:00 +02:00
let mut sync_io = NetSyncIo ::new ( context , & * self . handler . chain , & * self . handler . snapshot_service , & self . handler . overlay ) ;
2016-07-14 12:07:33 +02:00
self . handler . sync . write ( ) . chain_new_blocks (
& mut sync_io ,
& imported ,
& invalid ,
& enacted ,
& retracted ,
& sealed ) ;
} ) ;
}
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-10-24 16:24:35 +02:00
self . network . register_protocol ( self . 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
self . network . register_protocol ( self . handler . clone ( ) , WARP_SYNC_PROTOCOL_ID , SNAPSHOT_SYNC_PACKET_COUNT , & [ 1 u8 ] )
. unwrap_or_else ( | e | warn! ( " Error registering snapshot sync protocol: {:?} " , e ) ) ;
2016-07-14 12:07:33 +02:00
}
fn stop ( & self ) {
2016-11-13 13:52:53 +01:00
self . 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-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 ;
}
#[ ipc(client_ident= " NetworkManagerClient " ) ]
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-10-18 18:16:00 +02:00
let mut sync_io = NetSyncIo ::new ( context , & * self . handler . chain , & * self . handler . snapshot_service , & self . handler . overlay ) ;
2016-07-14 12:07:33 +02:00
self . handler . sync . write ( ) . abort ( & mut sync_io ) ;
} ) ;
self . stop ( ) ;
}
fn network_config ( & self ) -> NetworkConfiguration {
NetworkConfiguration ::from ( self . network . config ( ) . clone ( ) )
}
}
2016-10-24 18:25:27 +02:00
/// IP fiter
#[ derive(Binary, Clone, Debug, PartialEq, Eq) ]
pub enum AllowIP {
/// Connect to any address
All ,
/// Connect to private network only
Private ,
/// Connect to public network only
Public ,
}
impl AllowIP {
/// Attempt to parse the peer mode from a string.
pub fn parse ( s : & str ) -> Option < Self > {
match s {
" all " = > Some ( AllowIP ::All ) ,
" private " = > Some ( AllowIP ::Private ) ,
" public " = > Some ( AllowIP ::Public ) ,
_ = > None ,
}
}
}
2016-08-05 10:32:04 +02:00
#[ derive(Binary, Debug, Clone, PartialEq, Eq) ]
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
2016-08-24 18:35:21 +02:00
pub use_secret : Option < H256 > ,
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
pub allow_ips : AllowIP ,
2016-07-14 12:07:33 +02:00
}
impl NetworkConfiguration {
2016-08-05 10:32:04 +02:00
pub fn new ( ) -> Self {
From ::from ( BasicNetworkConfiguration ::new ( ) )
}
pub fn new_local ( ) -> Self {
From ::from ( BasicNetworkConfiguration ::new_local ( ) )
}
fn validate ( & self ) -> Result < ( ) , AddrParseError > {
if let Some ( ref addr ) = self . listen_address {
try ! ( SocketAddr ::from_str ( & addr ) ) ;
}
if let Some ( ref addr ) = self . public_address {
try ! ( SocketAddr ::from_str ( & addr ) ) ;
}
Ok ( ( ) )
}
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-07-14 12:07:33 +02:00
listen_address : match self . listen_address { None = > None , Some ( addr ) = > Some ( try ! ( SocketAddr ::from_str ( & addr ) ) ) } ,
public_address : match self . public_address { None = > None , Some ( addr ) = > Some ( try ! ( SocketAddr ::from_str ( & addr ) ) ) } ,
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 ,
2016-10-24 18:25:27 +02:00
allow_ips : match self . allow_ips {
AllowIP ::All = > NetworkAllowIP ::All ,
AllowIP ::Private = > NetworkAllowIP ::Private ,
AllowIP ::Public = > NetworkAllowIP ::Public ,
} ,
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 ,
2016-10-24 18:25:27 +02:00
allow_ips : match other . allow_ips {
NetworkAllowIP ::All = > AllowIP ::All ,
NetworkAllowIP ::Private = > AllowIP ::Private ,
NetworkAllowIP ::Public = > AllowIP ::Public ,
} ,
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
#[ derive(Debug, Binary, Clone) ]
pub struct ServiceConfiguration {
pub sync : SyncConfig ,
pub net : NetworkConfiguration ,
2016-08-22 18:41:58 +02:00
pub io_path : String ,
2016-07-20 18:13:56 +02:00
}