mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
Map peers by ip only (ignoring port unless on loopback ip) (#2540)
* wip * big refactor, regretting doing this now * PeerAddr everywhere * cleanup * fixup server tests * peers api working for GET, POST is still WIP * we can now ban/unban peers by ip only (port optional)
This commit is contained in:
parent
dc6542d82b
commit
23cb9e2514
19 changed files with 373 additions and 422 deletions
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
use super::utils::w;
|
use super::utils::w;
|
||||||
use crate::p2p;
|
use crate::p2p;
|
||||||
use crate::p2p::types::{PeerInfoDisplay, ReasonForBan};
|
use crate::p2p::types::{PeerAddr, PeerInfoDisplay, ReasonForBan};
|
||||||
use crate::router::{Handler, ResponseFuture};
|
use crate::router::{Handler, ResponseFuture};
|
||||||
use crate::web::*;
|
use crate::web::*;
|
||||||
use hyper::{Body, Request, StatusCode};
|
use hyper::{Body, Request, StatusCode};
|
||||||
|
@ -57,16 +57,25 @@ pub struct PeerHandler {
|
||||||
impl Handler for PeerHandler {
|
impl Handler for PeerHandler {
|
||||||
fn get(&self, req: Request<Body>) -> ResponseFuture {
|
fn get(&self, req: Request<Body>) -> ResponseFuture {
|
||||||
let command = right_path_element!(req);
|
let command = right_path_element!(req);
|
||||||
if let Ok(addr) = command.parse() {
|
|
||||||
match w(&self.peers).get_peer(addr) {
|
// We support both "ip" and "ip:port" here for peer_addr.
|
||||||
Ok(peer) => json_response(&peer),
|
// "ip:port" is only really useful for local usernet testing on loopback address.
|
||||||
Err(_) => response(StatusCode::NOT_FOUND, "peer not found"),
|
// Normally we map peers to ip and only allow a single peer per ip address.
|
||||||
}
|
let peer_addr;
|
||||||
|
if let Ok(ip_addr) = command.parse() {
|
||||||
|
peer_addr = PeerAddr::from_ip(ip_addr);
|
||||||
|
} else if let Ok(addr) = command.parse() {
|
||||||
|
peer_addr = PeerAddr(addr);
|
||||||
} else {
|
} else {
|
||||||
response(
|
return response(
|
||||||
StatusCode::BAD_REQUEST,
|
StatusCode::BAD_REQUEST,
|
||||||
format!("peer address unrecognized: {}", req.uri().path()),
|
format!("peer address unrecognized: {}", req.uri().path()),
|
||||||
)
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
match w(&self.peers).get_peer(peer_addr) {
|
||||||
|
Ok(peer) => json_response(&peer),
|
||||||
|
Err(_) => response(StatusCode::NOT_FOUND, "peer not found"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn post(&self, req: Request<Body>) -> ResponseFuture {
|
fn post(&self, req: Request<Body>) -> ResponseFuture {
|
||||||
|
@ -77,20 +86,23 @@ impl Handler for PeerHandler {
|
||||||
};
|
};
|
||||||
let addr = match path_elems.next() {
|
let addr = match path_elems.next() {
|
||||||
None => return response(StatusCode::BAD_REQUEST, "invalid url"),
|
None => return response(StatusCode::BAD_REQUEST, "invalid url"),
|
||||||
Some(a) => match a.parse() {
|
Some(a) => {
|
||||||
Err(e) => {
|
if let Ok(ip_addr) = a.parse() {
|
||||||
|
PeerAddr::from_ip(ip_addr)
|
||||||
|
} else if let Ok(addr) = a.parse() {
|
||||||
|
PeerAddr(addr)
|
||||||
|
} else {
|
||||||
return response(
|
return response(
|
||||||
StatusCode::BAD_REQUEST,
|
StatusCode::BAD_REQUEST,
|
||||||
format!("invalid peer address: {}", e),
|
format!("invalid peer address: {}", req.uri().path()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Ok(addr) => addr,
|
}
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
match command {
|
match command {
|
||||||
"ban" => w(&self.peers).ban_peer(&addr, ReasonForBan::ManualBan),
|
"ban" => w(&self.peers).ban_peer(addr, ReasonForBan::ManualBan),
|
||||||
"unban" => w(&self.peers).unban_peer(&addr),
|
"unban" => w(&self.peers).unban_peer(addr),
|
||||||
_ => return response(StatusCode::BAD_REQUEST, "invalid command"),
|
_ => return response(StatusCode::BAD_REQUEST, "invalid command"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ extern crate grin_core;
|
||||||
extern crate grin_p2p;
|
extern crate grin_p2p;
|
||||||
|
|
||||||
use grin_core::ser;
|
use grin_core::ser;
|
||||||
use grin_p2p::msg::SockAddr;
|
use grin_p2p::types::PeerAddr;
|
||||||
|
|
||||||
fuzz_target!(|data: &[u8]| {
|
fuzz_target!(|data: &[u8]| {
|
||||||
let mut d = data.clone();
|
let mut d = data.clone();
|
||||||
let _t: Result<SockAddr, ser::Error> = ser::deserialize(&mut d);
|
let _t: Result<PeerAddr, ser::Error> = ser::deserialize(&mut d);
|
||||||
});
|
});
|
|
@ -22,11 +22,9 @@ use rand::{thread_rng, Rng};
|
||||||
|
|
||||||
use crate::core::core::hash::Hash;
|
use crate::core::core::hash::Hash;
|
||||||
use crate::core::pow::Difficulty;
|
use crate::core::pow::Difficulty;
|
||||||
use crate::msg::{
|
use crate::msg::{read_message, write_message, Hand, Shake, Type, PROTOCOL_VERSION, USER_AGENT};
|
||||||
read_message, write_message, Hand, Shake, SockAddr, Type, PROTOCOL_VERSION, USER_AGENT,
|
|
||||||
};
|
|
||||||
use crate::peer::Peer;
|
use crate::peer::Peer;
|
||||||
use crate::types::{Capabilities, Direction, Error, P2PConfig, PeerInfo, PeerLiveInfo};
|
use crate::types::{Capabilities, Direction, Error, P2PConfig, PeerAddr, PeerInfo, PeerLiveInfo};
|
||||||
|
|
||||||
/// Local generated nonce for peer connecting.
|
/// Local generated nonce for peer connecting.
|
||||||
/// Used for self-connecting detection (on receiver side),
|
/// Used for self-connecting detection (on receiver side),
|
||||||
|
@ -44,7 +42,7 @@ pub struct Handshake {
|
||||||
/// a node id.
|
/// a node id.
|
||||||
nonces: Arc<RwLock<VecDeque<u64>>>,
|
nonces: Arc<RwLock<VecDeque<u64>>>,
|
||||||
/// Ring buffer of self addr(s) collected from PeerWithSelf detection (by nonce).
|
/// Ring buffer of self addr(s) collected from PeerWithSelf detection (by nonce).
|
||||||
pub addrs: Arc<RwLock<VecDeque<SocketAddr>>>,
|
pub addrs: Arc<RwLock<VecDeque<PeerAddr>>>,
|
||||||
/// The genesis block header of the chain seen by this node.
|
/// The genesis block header of the chain seen by this node.
|
||||||
/// We only want to connect to other nodes seeing the same chain (forks are
|
/// We only want to connect to other nodes seeing the same chain (forks are
|
||||||
/// ok).
|
/// ok).
|
||||||
|
@ -67,13 +65,13 @@ impl Handshake {
|
||||||
&self,
|
&self,
|
||||||
capab: Capabilities,
|
capab: Capabilities,
|
||||||
total_difficulty: Difficulty,
|
total_difficulty: Difficulty,
|
||||||
self_addr: SocketAddr,
|
self_addr: PeerAddr,
|
||||||
conn: &mut TcpStream,
|
conn: &mut TcpStream,
|
||||||
) -> Result<PeerInfo, Error> {
|
) -> Result<PeerInfo, Error> {
|
||||||
// prepare the first part of the handshake
|
// prepare the first part of the handshake
|
||||||
let nonce = self.next_nonce();
|
let nonce = self.next_nonce();
|
||||||
let peer_addr = match conn.peer_addr() {
|
let peer_addr = match conn.peer_addr() {
|
||||||
Ok(pa) => pa,
|
Ok(pa) => PeerAddr(pa),
|
||||||
Err(e) => return Err(Error::Connection(e)),
|
Err(e) => return Err(Error::Connection(e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,8 +81,8 @@ impl Handshake {
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
genesis: self.genesis,
|
genesis: self.genesis,
|
||||||
total_difficulty: total_difficulty,
|
total_difficulty: total_difficulty,
|
||||||
sender_addr: SockAddr(self_addr),
|
sender_addr: self_addr,
|
||||||
receiver_addr: SockAddr(peer_addr),
|
receiver_addr: peer_addr,
|
||||||
user_agent: USER_AGENT.to_string(),
|
user_agent: USER_AGENT.to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -118,7 +116,7 @@ impl Handshake {
|
||||||
|
|
||||||
// If denied then we want to close the connection
|
// If denied then we want to close the connection
|
||||||
// (without providing our peer with any details why).
|
// (without providing our peer with any details why).
|
||||||
if Peer::is_denied(&self.config, &peer_info.addr) {
|
if Peer::is_denied(&self.config, peer_info.addr) {
|
||||||
return Err(Error::ConnectionClose);
|
return Err(Error::ConnectionClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +153,7 @@ impl Handshake {
|
||||||
} else {
|
} else {
|
||||||
// check the nonce to see if we are trying to connect to ourselves
|
// check the nonce to see if we are trying to connect to ourselves
|
||||||
let nonces = self.nonces.read();
|
let nonces = self.nonces.read();
|
||||||
let addr = extract_ip(&hand.sender_addr.0, &conn);
|
let addr = resolve_peer_addr(hand.sender_addr, &conn);
|
||||||
if nonces.contains(&hand.nonce) {
|
if nonces.contains(&hand.nonce) {
|
||||||
// save ip addresses of ourselves
|
// save ip addresses of ourselves
|
||||||
let mut addrs = self.addrs.write();
|
let mut addrs = self.addrs.write();
|
||||||
|
@ -171,7 +169,7 @@ impl Handshake {
|
||||||
let peer_info = PeerInfo {
|
let peer_info = PeerInfo {
|
||||||
capabilities: hand.capabilities,
|
capabilities: hand.capabilities,
|
||||||
user_agent: hand.user_agent,
|
user_agent: hand.user_agent,
|
||||||
addr: extract_ip(&hand.sender_addr.0, &conn),
|
addr: resolve_peer_addr(hand.sender_addr, &conn),
|
||||||
version: hand.version,
|
version: hand.version,
|
||||||
live_info: Arc::new(RwLock::new(PeerLiveInfo {
|
live_info: Arc::new(RwLock::new(PeerLiveInfo {
|
||||||
total_difficulty: hand.total_difficulty,
|
total_difficulty: hand.total_difficulty,
|
||||||
|
@ -186,7 +184,7 @@ impl Handshake {
|
||||||
// so check if we are configured to explicitly allow or deny it.
|
// so check if we are configured to explicitly allow or deny it.
|
||||||
// If denied then we want to close the connection
|
// If denied then we want to close the connection
|
||||||
// (without providing our peer with any details why).
|
// (without providing our peer with any details why).
|
||||||
if Peer::is_denied(&self.config, &peer_info.addr) {
|
if Peer::is_denied(&self.config, peer_info.addr) {
|
||||||
return Err(Error::ConnectionClose);
|
return Err(Error::ConnectionClose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,28 +217,12 @@ impl Handshake {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempts to make a best guess at the correct remote IP by checking if the
|
/// Resolve the correct peer_addr based on the connection and the advertised port.
|
||||||
// advertised address is the loopback and our TCP connection. Note that the
|
fn resolve_peer_addr(advertised: PeerAddr, conn: &TcpStream) -> PeerAddr {
|
||||||
// port reported by the connection is always incorrect for receiving
|
let port = advertised.0.port();
|
||||||
// connections as it's dynamically allocated by the server.
|
|
||||||
fn extract_ip(advertised: &SocketAddr, conn: &TcpStream) -> SocketAddr {
|
|
||||||
match advertised {
|
|
||||||
&SocketAddr::V4(v4sock) => {
|
|
||||||
let ip = v4sock.ip();
|
|
||||||
if ip.is_loopback() || ip.is_unspecified() {
|
|
||||||
if let Ok(addr) = conn.peer_addr() {
|
if let Ok(addr) = conn.peer_addr() {
|
||||||
return SocketAddr::new(addr.ip(), advertised.port());
|
PeerAddr(SocketAddr::new(addr.ip(), port))
|
||||||
|
} else {
|
||||||
|
advertised
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
&SocketAddr::V6(v6sock) => {
|
|
||||||
let ip = v6sock.ip();
|
|
||||||
if ip.is_loopback() || ip.is_unspecified() {
|
|
||||||
if let Ok(addr) = conn.peer_addr() {
|
|
||||||
return SocketAddr::new(addr.ip(), advertised.port());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
advertised.clone()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,6 @@ pub use crate::peers::Peers;
|
||||||
pub use crate::serv::{DummyAdapter, Server};
|
pub use crate::serv::{DummyAdapter, Server};
|
||||||
pub use crate::store::{PeerData, State};
|
pub use crate::store::{PeerData, State};
|
||||||
pub use crate::types::{
|
pub use crate::types::{
|
||||||
Capabilities, ChainAdapter, Direction, Error, P2PConfig, PeerInfo, ReasonForBan, Seeding,
|
Capabilities, ChainAdapter, Direction, Error, P2PConfig, PeerAddr, PeerInfo, ReasonForBan,
|
||||||
TxHashSetRead, MAX_BLOCK_HEADERS, MAX_LOCATORS, MAX_PEER_ADDRS,
|
Seeding, TxHashSetRead, MAX_BLOCK_HEADERS, MAX_LOCATORS, MAX_PEER_ADDRS,
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
use num::FromPrimitive;
|
use num::FromPrimitive;
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
use crate::core::core::hash::Hash;
|
use crate::core::core::hash::Hash;
|
||||||
|
@ -25,7 +24,7 @@ use crate::core::pow::Difficulty;
|
||||||
use crate::core::ser::{self, FixedLength, Readable, Reader, StreamingReader, Writeable, Writer};
|
use crate::core::ser::{self, FixedLength, Readable, Reader, StreamingReader, Writeable, Writer};
|
||||||
use crate::core::{consensus, global};
|
use crate::core::{consensus, global};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
Capabilities, Error, ReasonForBan, MAX_BLOCK_HEADERS, MAX_LOCATORS, MAX_PEER_ADDRS,
|
Capabilities, Error, PeerAddr, ReasonForBan, MAX_BLOCK_HEADERS, MAX_LOCATORS, MAX_PEER_ADDRS,
|
||||||
};
|
};
|
||||||
use crate::util::read_write::read_exact;
|
use crate::util::read_write::read_exact;
|
||||||
|
|
||||||
|
@ -254,9 +253,9 @@ pub struct Hand {
|
||||||
/// may be needed
|
/// may be needed
|
||||||
pub total_difficulty: Difficulty,
|
pub total_difficulty: Difficulty,
|
||||||
/// network address of the sender
|
/// network address of the sender
|
||||||
pub sender_addr: SockAddr,
|
pub sender_addr: PeerAddr,
|
||||||
/// network address of the receiver
|
/// network address of the receiver
|
||||||
pub receiver_addr: SockAddr,
|
pub receiver_addr: PeerAddr,
|
||||||
/// name of version of the software
|
/// name of version of the software
|
||||||
pub user_agent: String,
|
pub user_agent: String,
|
||||||
}
|
}
|
||||||
|
@ -283,8 +282,8 @@ impl Readable for Hand {
|
||||||
let (version, capab, nonce) = ser_multiread!(reader, read_u32, read_u32, read_u64);
|
let (version, capab, nonce) = ser_multiread!(reader, read_u32, read_u32, read_u64);
|
||||||
let capabilities = Capabilities::from_bits_truncate(capab);
|
let capabilities = Capabilities::from_bits_truncate(capab);
|
||||||
let total_diff = Difficulty::read(reader)?;
|
let total_diff = Difficulty::read(reader)?;
|
||||||
let sender_addr = SockAddr::read(reader)?;
|
let sender_addr = PeerAddr::read(reader)?;
|
||||||
let receiver_addr = SockAddr::read(reader)?;
|
let receiver_addr = PeerAddr::read(reader)?;
|
||||||
let ua = reader.read_bytes_len_prefix()?;
|
let ua = reader.read_bytes_len_prefix()?;
|
||||||
let user_agent = String::from_utf8(ua).map_err(|_| ser::Error::CorruptedData)?;
|
let user_agent = String::from_utf8(ua).map_err(|_| ser::Error::CorruptedData)?;
|
||||||
let genesis = Hash::read(reader)?;
|
let genesis = Hash::read(reader)?;
|
||||||
|
@ -373,7 +372,7 @@ impl Readable for GetPeerAddrs {
|
||||||
/// GetPeerAddrs.
|
/// GetPeerAddrs.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct PeerAddrs {
|
pub struct PeerAddrs {
|
||||||
pub peers: Vec<SockAddr>,
|
pub peers: Vec<PeerAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Writeable for PeerAddrs {
|
impl Writeable for PeerAddrs {
|
||||||
|
@ -394,10 +393,9 @@ impl Readable for PeerAddrs {
|
||||||
} else if peer_count == 0 {
|
} else if peer_count == 0 {
|
||||||
return Ok(PeerAddrs { peers: vec![] });
|
return Ok(PeerAddrs { peers: vec![] });
|
||||||
}
|
}
|
||||||
// let peers = try_map_vec!([0..peer_count], |_| SockAddr::read(reader));
|
|
||||||
let mut peers = Vec::with_capacity(peer_count as usize);
|
let mut peers = Vec::with_capacity(peer_count as usize);
|
||||||
for _ in 0..peer_count {
|
for _ in 0..peer_count {
|
||||||
peers.push(SockAddr::read(reader)?);
|
peers.push(PeerAddr::read(reader)?);
|
||||||
}
|
}
|
||||||
Ok(PeerAddrs { peers: peers })
|
Ok(PeerAddrs { peers: peers })
|
||||||
}
|
}
|
||||||
|
@ -431,58 +429,6 @@ impl Readable for PeerError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only necessary so we can implement Readable and Writeable. Rust disallows
|
|
||||||
/// implementing traits when both types are outside of this crate (which is the
|
|
||||||
/// case for SocketAddr and Readable/Writeable).
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SockAddr(pub SocketAddr);
|
|
||||||
|
|
||||||
impl Writeable for SockAddr {
|
|
||||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
|
||||||
match self.0 {
|
|
||||||
SocketAddr::V4(sav4) => {
|
|
||||||
ser_multiwrite!(
|
|
||||||
writer,
|
|
||||||
[write_u8, 0],
|
|
||||||
[write_fixed_bytes, &sav4.ip().octets().to_vec()],
|
|
||||||
[write_u16, sav4.port()]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
SocketAddr::V6(sav6) => {
|
|
||||||
writer.write_u8(1)?;
|
|
||||||
for seg in &sav6.ip().segments() {
|
|
||||||
writer.write_u16(*seg)?;
|
|
||||||
}
|
|
||||||
writer.write_u16(sav6.port())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Readable for SockAddr {
|
|
||||||
fn read(reader: &mut dyn Reader) -> Result<SockAddr, ser::Error> {
|
|
||||||
let v4_or_v6 = reader.read_u8()?;
|
|
||||||
if v4_or_v6 == 0 {
|
|
||||||
let ip = reader.read_fixed_bytes(4)?;
|
|
||||||
let port = reader.read_u16()?;
|
|
||||||
Ok(SockAddr(SocketAddr::V4(SocketAddrV4::new(
|
|
||||||
Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]),
|
|
||||||
port,
|
|
||||||
))))
|
|
||||||
} else {
|
|
||||||
let ip = try_iter_map_vec!(0..8, |_| reader.read_u16());
|
|
||||||
let port = reader.read_u16()?;
|
|
||||||
Ok(SockAddr(SocketAddr::V6(SocketAddrV6::new(
|
|
||||||
Ipv6Addr::new(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]),
|
|
||||||
port,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serializable wrapper for the block locator.
|
/// Serializable wrapper for the block locator.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Locator {
|
pub struct Locator {
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
use crate::util::{Mutex, RwLock};
|
use crate::util::{Mutex, RwLock};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::net::{Shutdown, SocketAddr, TcpStream};
|
use std::net::{Shutdown, TcpStream};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::conn;
|
use crate::conn;
|
||||||
|
@ -25,7 +25,8 @@ use crate::handshake::Handshake;
|
||||||
use crate::msg::{self, BanReason, GetPeerAddrs, Locator, Ping, TxHashSetRequest};
|
use crate::msg::{self, BanReason, GetPeerAddrs, Locator, Ping, TxHashSetRequest};
|
||||||
use crate::protocol::Protocol;
|
use crate::protocol::Protocol;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerInfo, ReasonForBan, TxHashSetRead,
|
Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, PeerInfo, ReasonForBan,
|
||||||
|
TxHashSetRead,
|
||||||
};
|
};
|
||||||
use chrono::prelude::{DateTime, Utc};
|
use chrono::prelude::{DateTime, Utc};
|
||||||
|
|
||||||
|
@ -93,7 +94,7 @@ impl Peer {
|
||||||
conn: &mut TcpStream,
|
conn: &mut TcpStream,
|
||||||
capab: Capabilities,
|
capab: Capabilities,
|
||||||
total_difficulty: Difficulty,
|
total_difficulty: Difficulty,
|
||||||
self_addr: SocketAddr,
|
self_addr: PeerAddr,
|
||||||
hs: &Handshake,
|
hs: &Handshake,
|
||||||
na: Arc<dyn NetAdapter>,
|
na: Arc<dyn NetAdapter>,
|
||||||
) -> Result<Peer, Error> {
|
) -> Result<Peer, Error> {
|
||||||
|
@ -124,10 +125,9 @@ impl Peer {
|
||||||
self.connection = Some(Mutex::new(conn::listen(conn, handler)));
|
self.connection = Some(Mutex::new(conn::listen(conn, handler)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_denied(config: &P2PConfig, peer_addr: &SocketAddr) -> bool {
|
pub fn is_denied(config: &P2PConfig, peer_addr: PeerAddr) -> bool {
|
||||||
let peer = format!("{}:{}", peer_addr.ip(), peer_addr.port());
|
|
||||||
if let Some(ref denied) = config.peers_deny {
|
if let Some(ref denied) = config.peers_deny {
|
||||||
if denied.contains(&peer) {
|
if denied.contains(&peer_addr) {
|
||||||
debug!(
|
debug!(
|
||||||
"checking peer allowed/denied: {:?} explicitly denied",
|
"checking peer allowed/denied: {:?} explicitly denied",
|
||||||
peer_addr
|
peer_addr
|
||||||
|
@ -136,7 +136,7 @@ impl Peer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(ref allowed) = config.peers_allow {
|
if let Some(ref allowed) = config.peers_allow {
|
||||||
if allowed.contains(&peer) {
|
if allowed.contains(&peer_addr) {
|
||||||
debug!(
|
debug!(
|
||||||
"checking peer allowed/denied: {:?} explicitly allowed",
|
"checking peer allowed/denied: {:?} explicitly allowed",
|
||||||
peer_addr
|
peer_addr
|
||||||
|
@ -566,7 +566,7 @@ impl ChainAdapter for TrackingAdapter {
|
||||||
self.adapter.get_transaction(kernel_hash)
|
self.adapter.get_transaction(kernel_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tx_kernel_received(&self, kernel_hash: Hash, addr: SocketAddr) {
|
fn tx_kernel_received(&self, kernel_hash: Hash, addr: PeerAddr) {
|
||||||
self.push_recv(kernel_hash);
|
self.push_recv(kernel_hash);
|
||||||
self.adapter.tx_kernel_received(kernel_hash, addr)
|
self.adapter.tx_kernel_received(kernel_hash, addr)
|
||||||
}
|
}
|
||||||
|
@ -582,23 +582,23 @@ impl ChainAdapter for TrackingAdapter {
|
||||||
self.adapter.transaction_received(tx, stem)
|
self.adapter.transaction_received(tx, stem)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_received(&self, b: core::Block, addr: SocketAddr, _was_requested: bool) -> bool {
|
fn block_received(&self, b: core::Block, addr: PeerAddr, _was_requested: bool) -> bool {
|
||||||
let bh = b.hash();
|
let bh = b.hash();
|
||||||
self.push_recv(bh);
|
self.push_recv(bh);
|
||||||
self.adapter.block_received(b, addr, self.has_req(bh))
|
self.adapter.block_received(b, addr, self.has_req(bh))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compact_block_received(&self, cb: core::CompactBlock, addr: SocketAddr) -> bool {
|
fn compact_block_received(&self, cb: core::CompactBlock, addr: PeerAddr) -> bool {
|
||||||
self.push_recv(cb.hash());
|
self.push_recv(cb.hash());
|
||||||
self.adapter.compact_block_received(cb, addr)
|
self.adapter.compact_block_received(cb, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_received(&self, bh: core::BlockHeader, addr: SocketAddr) -> bool {
|
fn header_received(&self, bh: core::BlockHeader, addr: PeerAddr) -> bool {
|
||||||
self.push_recv(bh.hash());
|
self.push_recv(bh.hash());
|
||||||
self.adapter.header_received(bh, addr)
|
self.adapter.header_received(bh, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn headers_received(&self, bh: &[core::BlockHeader], addr: SocketAddr) -> bool {
|
fn headers_received(&self, bh: &[core::BlockHeader], addr: PeerAddr) -> bool {
|
||||||
self.adapter.headers_received(bh, addr)
|
self.adapter.headers_received(bh, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,7 +618,7 @@ impl ChainAdapter for TrackingAdapter {
|
||||||
self.adapter.txhashset_receive_ready()
|
self.adapter.txhashset_receive_ready()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn txhashset_write(&self, h: Hash, txhashset_data: File, peer_addr: SocketAddr) -> bool {
|
fn txhashset_write(&self, h: Hash, txhashset_data: File, peer_addr: PeerAddr) -> bool {
|
||||||
self.adapter.txhashset_write(h, txhashset_data, peer_addr)
|
self.adapter.txhashset_write(h, txhashset_data, peer_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,19 +634,19 @@ impl ChainAdapter for TrackingAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetAdapter for TrackingAdapter {
|
impl NetAdapter for TrackingAdapter {
|
||||||
fn find_peer_addrs(&self, capab: Capabilities) -> Vec<SocketAddr> {
|
fn find_peer_addrs(&self, capab: Capabilities) -> Vec<PeerAddr> {
|
||||||
self.adapter.find_peer_addrs(capab)
|
self.adapter.find_peer_addrs(capab)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peer_addrs_received(&self, addrs: Vec<SocketAddr>) {
|
fn peer_addrs_received(&self, addrs: Vec<PeerAddr>) {
|
||||||
self.adapter.peer_addrs_received(addrs)
|
self.adapter.peer_addrs_received(addrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peer_difficulty(&self, addr: SocketAddr, diff: Difficulty, height: u64) {
|
fn peer_difficulty(&self, addr: PeerAddr, diff: Difficulty, height: u64) {
|
||||||
self.adapter.peer_difficulty(addr, diff, height)
|
self.adapter.peer_difficulty(addr, diff, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_banned(&self, addr: SocketAddr) -> bool {
|
fn is_banned(&self, addr: PeerAddr) -> bool {
|
||||||
self.adapter.is_banned(addr)
|
self.adapter.is_banned(addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
116
p2p/src/peers.rs
116
p2p/src/peers.rs
|
@ -15,7 +15,6 @@
|
||||||
use crate::util::RwLock;
|
use crate::util::RwLock;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
|
@ -30,14 +29,14 @@ use chrono::Duration;
|
||||||
use crate::peer::Peer;
|
use crate::peer::Peer;
|
||||||
use crate::store::{PeerData, PeerStore, State};
|
use crate::store::{PeerData, PeerStore, State};
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
Capabilities, ChainAdapter, Direction, Error, NetAdapter, P2PConfig, ReasonForBan,
|
Capabilities, ChainAdapter, Direction, Error, NetAdapter, P2PConfig, PeerAddr, ReasonForBan,
|
||||||
TxHashSetRead, MAX_PEER_ADDRS,
|
TxHashSetRead, MAX_PEER_ADDRS,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Peers {
|
pub struct Peers {
|
||||||
pub adapter: Arc<dyn ChainAdapter>,
|
pub adapter: Arc<dyn ChainAdapter>,
|
||||||
store: PeerStore,
|
store: PeerStore,
|
||||||
peers: RwLock<HashMap<SocketAddr, Arc<Peer>>>,
|
peers: RwLock<HashMap<PeerAddr, Arc<Peer>>>,
|
||||||
dandelion_relay: RwLock<Option<(i64, Arc<Peer>)>>,
|
dandelion_relay: RwLock<Option<(i64, Arc<Peer>)>>,
|
||||||
config: P2PConfig,
|
config: P2PConfig,
|
||||||
}
|
}
|
||||||
|
@ -56,10 +55,7 @@ impl Peers {
|
||||||
/// Adds the peer to our internal peer mapping. Note that the peer is still
|
/// Adds the peer to our internal peer mapping. Note that the peer is still
|
||||||
/// returned so the server can run it.
|
/// returned so the server can run it.
|
||||||
pub fn add_connected(&self, peer: Arc<Peer>) -> Result<(), Error> {
|
pub fn add_connected(&self, peer: Arc<Peer>) -> Result<(), Error> {
|
||||||
let peer_data: PeerData;
|
let peer_data = PeerData {
|
||||||
let addr: SocketAddr;
|
|
||||||
{
|
|
||||||
peer_data = PeerData {
|
|
||||||
addr: peer.info.addr,
|
addr: peer.info.addr,
|
||||||
capabilities: peer.info.capabilities,
|
capabilities: peer.info.capabilities,
|
||||||
user_agent: peer.info.user_agent.clone(),
|
user_agent: peer.info.user_agent.clone(),
|
||||||
|
@ -68,21 +64,16 @@ impl Peers {
|
||||||
ban_reason: ReasonForBan::None,
|
ban_reason: ReasonForBan::None,
|
||||||
last_connected: Utc::now().timestamp(),
|
last_connected: Utc::now().timestamp(),
|
||||||
};
|
};
|
||||||
addr = peer.info.addr.clone();
|
debug!("Saving newly connected peer {}.", peer_data.addr);
|
||||||
}
|
|
||||||
debug!("Saving newly connected peer {}.", addr);
|
|
||||||
self.save_peer(&peer_data)?;
|
self.save_peer(&peer_data)?;
|
||||||
|
self.peers.write().insert(peer_data.addr, peer.clone());
|
||||||
|
|
||||||
{
|
|
||||||
let mut peers = self.peers.write();
|
|
||||||
peers.insert(addr, peer.clone());
|
|
||||||
}
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a peer as banned to block future connections, usually due to failed
|
/// Add a peer as banned to block future connections, usually due to failed
|
||||||
/// handshake
|
/// handshake
|
||||||
pub fn add_banned(&self, addr: SocketAddr, ban_reason: ReasonForBan) -> Result<(), Error> {
|
pub fn add_banned(&self, addr: PeerAddr, ban_reason: ReasonForBan) -> Result<(), Error> {
|
||||||
let peer_data = PeerData {
|
let peer_data = PeerData {
|
||||||
addr,
|
addr,
|
||||||
capabilities: Capabilities::UNKNOWN,
|
capabilities: Capabilities::UNKNOWN,
|
||||||
|
@ -129,18 +120,8 @@ impl Peers {
|
||||||
self.dandelion_relay.read().clone()
|
self.dandelion_relay.read().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_known(&self, addr: &SocketAddr) -> bool {
|
pub fn is_known(&self, addr: PeerAddr) -> bool {
|
||||||
self.peers.read().contains_key(addr)
|
self.peers.read().contains_key(&addr)
|
||||||
}
|
|
||||||
|
|
||||||
/// Check whether an ip address is in the active peers list, ignore the port
|
|
||||||
pub fn is_known_ip(&self, addr: &SocketAddr) -> bool {
|
|
||||||
for socket in self.peers.read().keys() {
|
|
||||||
if addr.ip() == socket.ip() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get vec of peers we are currently connected to.
|
/// Get vec of peers we are currently connected to.
|
||||||
|
@ -166,8 +147,8 @@ impl Peers {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a peer we're connected to by address.
|
/// Get a peer we're connected to by address.
|
||||||
pub fn get_connected_peer(&self, addr: &SocketAddr) -> Option<Arc<Peer>> {
|
pub fn get_connected_peer(&self, addr: PeerAddr) -> Option<Arc<Peer>> {
|
||||||
self.peers.read().get(addr).map(|p| p.clone())
|
self.peers.read().get(&addr).map(|p| p.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Number of peers currently connected to.
|
/// Number of peers currently connected to.
|
||||||
|
@ -257,31 +238,18 @@ impl Peers {
|
||||||
self.most_work_peers().pop()
|
self.most_work_peers().pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_banned(&self, peer_addr: SocketAddr) -> bool {
|
pub fn is_banned(&self, peer_addr: PeerAddr) -> bool {
|
||||||
if global::is_production_mode() {
|
if let Ok(peer) = self.store.get_peer(peer_addr) {
|
||||||
// Ban only cares about ip address, no mather what port.
|
if peer.flags == State::Banned {
|
||||||
// so, we query all saved peers with one same ip address, and ignore port
|
|
||||||
let peers_data = self.store.find_peers_by_ip(peer_addr);
|
|
||||||
for peer_data in peers_data {
|
|
||||||
if peer_data.flags == State::Banned {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// For travis-ci test, we need run multiple nodes in one server, with same ip address.
|
|
||||||
// so, just query the ip address and the port
|
|
||||||
if let Ok(peer_data) = self.store.get_peer(peer_addr) {
|
|
||||||
if peer_data.flags == State::Banned {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ban a peer, disconnecting it if we're currently connected
|
/// Ban a peer, disconnecting it if we're currently connected
|
||||||
pub fn ban_peer(&self, peer_addr: &SocketAddr, ban_reason: ReasonForBan) {
|
pub fn ban_peer(&self, peer_addr: PeerAddr, ban_reason: ReasonForBan) {
|
||||||
if let Err(e) = self.update_state(*peer_addr, State::Banned) {
|
if let Err(e) = self.update_state(peer_addr, State::Banned) {
|
||||||
error!("Couldn't ban {}: {:?}", peer_addr, e);
|
error!("Couldn't ban {}: {:?}", peer_addr, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,12 +263,12 @@ impl Peers {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unban a peer, checks if it exists and banned then unban
|
/// Unban a peer, checks if it exists and banned then unban
|
||||||
pub fn unban_peer(&self, peer_addr: &SocketAddr) {
|
pub fn unban_peer(&self, peer_addr: PeerAddr) {
|
||||||
debug!("unban_peer: peer {}", peer_addr);
|
debug!("unban_peer: peer {}", peer_addr);
|
||||||
match self.get_peer(*peer_addr) {
|
match self.get_peer(peer_addr) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
if self.is_banned(*peer_addr) {
|
if self.is_banned(peer_addr) {
|
||||||
if let Err(e) = self.update_state(*peer_addr, State::Healthy) {
|
if let Err(e) = self.update_state(peer_addr, State::Healthy) {
|
||||||
error!("Couldn't unban {}: {:?}", peer_addr, e);
|
error!("Couldn't unban {}: {:?}", peer_addr, e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -424,12 +392,12 @@ impl Peers {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get peer in store by address
|
/// Get peer in store by address
|
||||||
pub fn get_peer(&self, peer_addr: SocketAddr) -> Result<PeerData, Error> {
|
pub fn get_peer(&self, peer_addr: PeerAddr) -> Result<PeerData, Error> {
|
||||||
self.store.get_peer(peer_addr).map_err(From::from)
|
self.store.get_peer(peer_addr).map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether we've already seen a peer with the provided address
|
/// Whether we've already seen a peer with the provided address
|
||||||
pub fn exists_peer(&self, peer_addr: SocketAddr) -> Result<bool, Error> {
|
pub fn exists_peer(&self, peer_addr: PeerAddr) -> Result<bool, Error> {
|
||||||
self.store.exists_peer(peer_addr).map_err(From::from)
|
self.store.exists_peer(peer_addr).map_err(From::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,7 +407,7 @@ impl Peers {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the state of a peer in store
|
/// Updates the state of a peer in store
|
||||||
pub fn update_state(&self, peer_addr: SocketAddr, new_state: State) -> Result<(), Error> {
|
pub fn update_state(&self, peer_addr: PeerAddr, new_state: State) -> Result<(), Error> {
|
||||||
self.store
|
self.store
|
||||||
.update_state(peer_addr, new_state)
|
.update_state(peer_addr, new_state)
|
||||||
.map_err(From::from)
|
.map_err(From::from)
|
||||||
|
@ -495,9 +463,9 @@ impl Peers {
|
||||||
// now clean up peer map based on the list to remove
|
// now clean up peer map based on the list to remove
|
||||||
{
|
{
|
||||||
let mut peers = self.peers.write();
|
let mut peers = self.peers.write();
|
||||||
for p in rm {
|
for addr in rm {
|
||||||
let _ = peers.get(&p).map(|p| p.stop());
|
let _ = peers.get(&addr).map(|peer| peer.stop());
|
||||||
peers.remove(&p);
|
peers.remove(&addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -558,7 +526,7 @@ impl ChainAdapter for Peers {
|
||||||
self.adapter.get_transaction(kernel_hash)
|
self.adapter.get_transaction(kernel_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tx_kernel_received(&self, kernel_hash: Hash, addr: SocketAddr) {
|
fn tx_kernel_received(&self, kernel_hash: Hash, addr: PeerAddr) {
|
||||||
self.adapter.tx_kernel_received(kernel_hash, addr)
|
self.adapter.tx_kernel_received(kernel_hash, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,7 +534,7 @@ impl ChainAdapter for Peers {
|
||||||
self.adapter.transaction_received(tx, stem)
|
self.adapter.transaction_received(tx, stem)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_received(&self, b: core::Block, peer_addr: SocketAddr, was_requested: bool) -> bool {
|
fn block_received(&self, b: core::Block, peer_addr: PeerAddr, was_requested: bool) -> bool {
|
||||||
let hash = b.hash();
|
let hash = b.hash();
|
||||||
if !self.adapter.block_received(b, peer_addr, was_requested) {
|
if !self.adapter.block_received(b, peer_addr, was_requested) {
|
||||||
// if the peer sent us a block that's intrinsically bad
|
// if the peer sent us a block that's intrinsically bad
|
||||||
|
@ -575,45 +543,45 @@ impl ChainAdapter for Peers {
|
||||||
"Received a bad block {} from {}, the peer will be banned",
|
"Received a bad block {} from {}, the peer will be banned",
|
||||||
hash, peer_addr
|
hash, peer_addr
|
||||||
);
|
);
|
||||||
self.ban_peer(&peer_addr, ReasonForBan::BadBlock);
|
self.ban_peer(peer_addr, ReasonForBan::BadBlock);
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compact_block_received(&self, cb: core::CompactBlock, peer_addr: SocketAddr) -> bool {
|
fn compact_block_received(&self, cb: core::CompactBlock, peer_addr: PeerAddr) -> bool {
|
||||||
let hash = cb.hash();
|
let hash = cb.hash();
|
||||||
if !self.adapter.compact_block_received(cb, peer_addr) {
|
if !self.adapter.compact_block_received(cb, peer_addr) {
|
||||||
// if the peer sent us a block that's intrinsically bad
|
// if the peer sent us a block that's intrinsically bad
|
||||||
// they are either mistaken or malevolent, both of which require a ban
|
// they are either mistaken or malevolent, both of which require a ban
|
||||||
debug!(
|
debug!(
|
||||||
"Received a bad compact block {} from {}, the peer will be banned",
|
"Received a bad compact block {} from {}, the peer will be banned",
|
||||||
hash, &peer_addr
|
hash, peer_addr
|
||||||
);
|
);
|
||||||
self.ban_peer(&peer_addr, ReasonForBan::BadCompactBlock);
|
self.ban_peer(peer_addr, ReasonForBan::BadCompactBlock);
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_received(&self, bh: core::BlockHeader, peer_addr: SocketAddr) -> bool {
|
fn header_received(&self, bh: core::BlockHeader, peer_addr: PeerAddr) -> bool {
|
||||||
if !self.adapter.header_received(bh, peer_addr) {
|
if !self.adapter.header_received(bh, peer_addr) {
|
||||||
// if the peer sent us a block header that's intrinsically bad
|
// if the peer sent us a block header that's intrinsically bad
|
||||||
// they are either mistaken or malevolent, both of which require a ban
|
// they are either mistaken or malevolent, both of which require a ban
|
||||||
self.ban_peer(&peer_addr, ReasonForBan::BadBlockHeader);
|
self.ban_peer(peer_addr, ReasonForBan::BadBlockHeader);
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn headers_received(&self, headers: &[core::BlockHeader], peer_addr: SocketAddr) -> bool {
|
fn headers_received(&self, headers: &[core::BlockHeader], peer_addr: PeerAddr) -> bool {
|
||||||
if !self.adapter.headers_received(headers, peer_addr) {
|
if !self.adapter.headers_received(headers, peer_addr) {
|
||||||
// if the peer sent us a block header that's intrinsically bad
|
// if the peer sent us a block header that's intrinsically bad
|
||||||
// they are either mistaken or malevolent, both of which require a ban
|
// they are either mistaken or malevolent, both of which require a ban
|
||||||
self.ban_peer(&peer_addr, ReasonForBan::BadBlockHeader);
|
self.ban_peer(peer_addr, ReasonForBan::BadBlockHeader);
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
|
@ -636,13 +604,13 @@ impl ChainAdapter for Peers {
|
||||||
self.adapter.txhashset_receive_ready()
|
self.adapter.txhashset_receive_ready()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn txhashset_write(&self, h: Hash, txhashset_data: File, peer_addr: SocketAddr) -> bool {
|
fn txhashset_write(&self, h: Hash, txhashset_data: File, peer_addr: PeerAddr) -> bool {
|
||||||
if !self.adapter.txhashset_write(h, txhashset_data, peer_addr) {
|
if !self.adapter.txhashset_write(h, txhashset_data, peer_addr) {
|
||||||
debug!(
|
debug!(
|
||||||
"Received a bad txhashset data from {}, the peer will be banned",
|
"Received a bad txhashset data from {}, the peer will be banned",
|
||||||
&peer_addr
|
&peer_addr
|
||||||
);
|
);
|
||||||
self.ban_peer(&peer_addr, ReasonForBan::BadTxHashSet);
|
self.ban_peer(peer_addr, ReasonForBan::BadTxHashSet);
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
|
@ -663,14 +631,14 @@ impl ChainAdapter for Peers {
|
||||||
impl NetAdapter for Peers {
|
impl NetAdapter for Peers {
|
||||||
/// Find good peers we know with the provided capability and return their
|
/// Find good peers we know with the provided capability and return their
|
||||||
/// addresses.
|
/// addresses.
|
||||||
fn find_peer_addrs(&self, capab: Capabilities) -> Vec<SocketAddr> {
|
fn find_peer_addrs(&self, capab: Capabilities) -> Vec<PeerAddr> {
|
||||||
let peers = self.find_peers(State::Healthy, capab, MAX_PEER_ADDRS as usize);
|
let peers = self.find_peers(State::Healthy, capab, MAX_PEER_ADDRS as usize);
|
||||||
trace!("find_peer_addrs: {} healthy peers picked", peers.len());
|
trace!("find_peer_addrs: {} healthy peers picked", peers.len());
|
||||||
map_vec!(peers, |p| p.addr)
|
map_vec!(peers, |p| p.addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A list of peers has been received from one of our peers.
|
/// A list of peers has been received from one of our peers.
|
||||||
fn peer_addrs_received(&self, peer_addrs: Vec<SocketAddr>) {
|
fn peer_addrs_received(&self, peer_addrs: Vec<PeerAddr>) {
|
||||||
trace!("Received {} peer addrs, saving.", peer_addrs.len());
|
trace!("Received {} peer addrs, saving.", peer_addrs.len());
|
||||||
for pa in peer_addrs {
|
for pa in peer_addrs {
|
||||||
if let Ok(e) = self.exists_peer(pa) {
|
if let Ok(e) = self.exists_peer(pa) {
|
||||||
|
@ -693,13 +661,13 @@ impl NetAdapter for Peers {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peer_difficulty(&self, addr: SocketAddr, diff: Difficulty, height: u64) {
|
fn peer_difficulty(&self, addr: PeerAddr, diff: Difficulty, height: u64) {
|
||||||
if let Some(peer) = self.get_connected_peer(&addr) {
|
if let Some(peer) = self.get_connected_peer(addr) {
|
||||||
peer.info.update(height, diff);
|
peer.info.update(height, diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_banned(&self, addr: SocketAddr) -> bool {
|
fn is_banned(&self, addr: PeerAddr) -> bool {
|
||||||
if let Ok(peer) = self.get_peer(addr) {
|
if let Ok(peer) = self.get_peer(addr) {
|
||||||
peer.flags == State::Banned
|
peer.flags == State::Banned
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -16,7 +16,6 @@ use std::cmp;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufWriter, Write};
|
use std::io::{BufWriter, Write};
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::conn::{Message, MessageHandler, Response};
|
use crate::conn::{Message, MessageHandler, Response};
|
||||||
|
@ -25,18 +24,18 @@ use crate::util::{RateCounter, RwLock};
|
||||||
use chrono::prelude::Utc;
|
use chrono::prelude::Utc;
|
||||||
|
|
||||||
use crate::msg::{
|
use crate::msg::{
|
||||||
BanReason, GetPeerAddrs, Headers, Locator, PeerAddrs, Ping, Pong, SockAddr, TxHashSetArchive,
|
BanReason, GetPeerAddrs, Headers, Locator, PeerAddrs, Ping, Pong, TxHashSetArchive,
|
||||||
TxHashSetRequest, Type,
|
TxHashSetRequest, Type,
|
||||||
};
|
};
|
||||||
use crate::types::{Error, NetAdapter};
|
use crate::types::{Error, NetAdapter, PeerAddr};
|
||||||
|
|
||||||
pub struct Protocol {
|
pub struct Protocol {
|
||||||
adapter: Arc<dyn NetAdapter>,
|
adapter: Arc<dyn NetAdapter>,
|
||||||
addr: SocketAddr,
|
addr: PeerAddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Protocol {
|
impl Protocol {
|
||||||
pub fn new(adapter: Arc<dyn NetAdapter>, addr: SocketAddr) -> Protocol {
|
pub fn new(adapter: Arc<dyn NetAdapter>, addr: PeerAddr) -> Protocol {
|
||||||
Protocol { adapter, addr }
|
Protocol { adapter, addr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -231,19 +230,17 @@ impl MessageHandler for Protocol {
|
||||||
|
|
||||||
Type::GetPeerAddrs => {
|
Type::GetPeerAddrs => {
|
||||||
let get_peers: GetPeerAddrs = msg.body()?;
|
let get_peers: GetPeerAddrs = msg.body()?;
|
||||||
let peer_addrs = adapter.find_peer_addrs(get_peers.capabilities);
|
let peers = adapter.find_peer_addrs(get_peers.capabilities);
|
||||||
Ok(Some(Response::new(
|
Ok(Some(Response::new(
|
||||||
Type::PeerAddrs,
|
Type::PeerAddrs,
|
||||||
PeerAddrs {
|
PeerAddrs { peers },
|
||||||
peers: peer_addrs.iter().map(|sa| SockAddr(*sa)).collect(),
|
|
||||||
},
|
|
||||||
writer,
|
writer,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::PeerAddrs => {
|
Type::PeerAddrs => {
|
||||||
let peer_addrs: PeerAddrs = msg.body()?;
|
let peer_addrs: PeerAddrs = msg.body()?;
|
||||||
adapter.peer_addrs_received(peer_addrs.peers.iter().map(|pa| pa.0).collect());
|
adapter.peer_addrs_received(peer_addrs.peers);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ use crate::peer::Peer;
|
||||||
use crate::peers::Peers;
|
use crate::peers::Peers;
|
||||||
use crate::store::PeerStore;
|
use crate::store::PeerStore;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, ReasonForBan, Seeding, TxHashSetRead,
|
Capabilities, ChainAdapter, Error, NetAdapter, P2PConfig, PeerAddr, ReasonForBan, TxHashSetRead,
|
||||||
};
|
};
|
||||||
use crate::util::{Mutex, StopState};
|
use crate::util::{Mutex, StopState};
|
||||||
use chrono::prelude::{DateTime, Utc};
|
use chrono::prelude::{DateTime, Utc};
|
||||||
|
@ -82,6 +82,8 @@ impl Server {
|
||||||
|
|
||||||
match listener.accept() {
|
match listener.accept() {
|
||||||
Ok((stream, peer_addr)) => {
|
Ok((stream, peer_addr)) => {
|
||||||
|
let peer_addr = PeerAddr(peer_addr);
|
||||||
|
|
||||||
if self.check_undesirable(&stream) {
|
if self.check_undesirable(&stream) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -107,8 +109,8 @@ impl Server {
|
||||||
|
|
||||||
/// Asks the server to connect to a new peer. Directly returns the peer if
|
/// Asks the server to connect to a new peer. Directly returns the peer if
|
||||||
/// we're already connected to the provided address.
|
/// we're already connected to the provided address.
|
||||||
pub fn connect(&self, addr: &SocketAddr) -> Result<Arc<Peer>, Error> {
|
pub fn connect(&self, addr: PeerAddr) -> Result<Arc<Peer>, Error> {
|
||||||
if Peer::is_denied(&self.config, &addr) {
|
if Peer::is_denied(&self.config, addr) {
|
||||||
debug!("connect_peer: peer {} denied, not connecting.", addr);
|
debug!("connect_peer: peer {} denied, not connecting.", addr);
|
||||||
return Err(Error::ConnectionClose);
|
return Err(Error::ConnectionClose);
|
||||||
}
|
}
|
||||||
|
@ -134,7 +136,7 @@ impl Server {
|
||||||
self.config.port,
|
self.config.port,
|
||||||
addr
|
addr
|
||||||
);
|
);
|
||||||
match TcpStream::connect_timeout(addr, Duration::from_secs(10)) {
|
match TcpStream::connect_timeout(&addr.0, Duration::from_secs(10)) {
|
||||||
Ok(mut stream) => {
|
Ok(mut stream) => {
|
||||||
let addr = SocketAddr::new(self.config.host, self.config.port);
|
let addr = SocketAddr::new(self.config.host, self.config.port);
|
||||||
let total_diff = self.peers.total_difficulty();
|
let total_diff = self.peers.total_difficulty();
|
||||||
|
@ -143,7 +145,7 @@ impl Server {
|
||||||
&mut stream,
|
&mut stream,
|
||||||
self.capabilities,
|
self.capabilities,
|
||||||
total_diff,
|
total_diff,
|
||||||
addr,
|
PeerAddr(addr),
|
||||||
&self.handshake,
|
&self.handshake,
|
||||||
self.peers.clone(),
|
self.peers.clone(),
|
||||||
)?;
|
)?;
|
||||||
|
@ -191,13 +193,17 @@ impl Server {
|
||||||
/// different sets of peers themselves. In addition, it prevent potential
|
/// different sets of peers themselves. In addition, it prevent potential
|
||||||
/// duplicate connections, malicious or not.
|
/// duplicate connections, malicious or not.
|
||||||
fn check_undesirable(&self, stream: &TcpStream) -> bool {
|
fn check_undesirable(&self, stream: &TcpStream) -> bool {
|
||||||
// peer has been banned, go away!
|
|
||||||
if let Ok(peer_addr) = stream.peer_addr() {
|
if let Ok(peer_addr) = stream.peer_addr() {
|
||||||
let banned = self.peers.is_banned(peer_addr);
|
let peer_addr = PeerAddr(peer_addr);
|
||||||
let known_ip =
|
if self.peers.is_banned(peer_addr) {
|
||||||
self.peers.is_known_ip(&peer_addr) && self.config.seeding_type == Seeding::DNSSeed;
|
debug!("Peer {} banned, refusing connection.", peer_addr);
|
||||||
if banned || known_ip {
|
if let Err(e) = stream.shutdown(Shutdown::Both) {
|
||||||
debug!("Peer {} banned or known, refusing connection.", peer_addr);
|
debug!("Error shutting down conn: {:?}", e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if self.peers.is_known(peer_addr) {
|
||||||
|
debug!("Peer {} already known, refusing connection.", peer_addr);
|
||||||
if let Err(e) = stream.shutdown(Shutdown::Both) {
|
if let Err(e) = stream.shutdown(Shutdown::Both) {
|
||||||
debug!("Error shutting down conn: {:?}", e);
|
debug!("Error shutting down conn: {:?}", e);
|
||||||
}
|
}
|
||||||
|
@ -234,18 +240,18 @@ impl ChainAdapter for DummyAdapter {
|
||||||
fn get_transaction(&self, _h: Hash) -> Option<core::Transaction> {
|
fn get_transaction(&self, _h: Hash) -> Option<core::Transaction> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn tx_kernel_received(&self, _h: Hash, _addr: SocketAddr) {}
|
fn tx_kernel_received(&self, _h: Hash, _addr: PeerAddr) {}
|
||||||
fn transaction_received(&self, _: core::Transaction, _stem: bool) {}
|
fn transaction_received(&self, _: core::Transaction, _stem: bool) {}
|
||||||
fn compact_block_received(&self, _cb: core::CompactBlock, _addr: SocketAddr) -> bool {
|
fn compact_block_received(&self, _cb: core::CompactBlock, _addr: PeerAddr) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn header_received(&self, _bh: core::BlockHeader, _addr: SocketAddr) -> bool {
|
fn header_received(&self, _bh: core::BlockHeader, _addr: PeerAddr) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn block_received(&self, _: core::Block, _: SocketAddr, _: bool) -> bool {
|
fn block_received(&self, _: core::Block, _: PeerAddr, _: bool) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn headers_received(&self, _: &[core::BlockHeader], _: SocketAddr) -> bool {
|
fn headers_received(&self, _: &[core::BlockHeader], _: PeerAddr) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
fn locate_headers(&self, _: &[Hash]) -> Vec<core::BlockHeader> {
|
fn locate_headers(&self, _: &[Hash]) -> Vec<core::BlockHeader> {
|
||||||
|
@ -262,7 +268,7 @@ impl ChainAdapter for DummyAdapter {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn txhashset_write(&self, _h: Hash, _txhashset_data: File, _peer_addr: SocketAddr) -> bool {
|
fn txhashset_write(&self, _h: Hash, _txhashset_data: File, _peer_addr: PeerAddr) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,12 +283,12 @@ impl ChainAdapter for DummyAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetAdapter for DummyAdapter {
|
impl NetAdapter for DummyAdapter {
|
||||||
fn find_peer_addrs(&self, _: Capabilities) -> Vec<SocketAddr> {
|
fn find_peer_addrs(&self, _: Capabilities) -> Vec<PeerAddr> {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
fn peer_addrs_received(&self, _: Vec<SocketAddr>) {}
|
fn peer_addrs_received(&self, _: Vec<PeerAddr>) {}
|
||||||
fn peer_difficulty(&self, _: SocketAddr, _: Difficulty, _: u64) {}
|
fn peer_difficulty(&self, _: PeerAddr, _: Difficulty, _: u64) {}
|
||||||
fn is_banned(&self, _: SocketAddr) -> bool {
|
fn is_banned(&self, _: PeerAddr) -> bool {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,19 +17,17 @@
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use num::FromPrimitive;
|
use num::FromPrimitive;
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::lmdb;
|
use crate::lmdb;
|
||||||
|
|
||||||
use crate::core::ser::{self, Readable, Reader, Writeable, Writer};
|
use crate::core::ser::{self, Readable, Reader, Writeable, Writer};
|
||||||
use crate::msg::SockAddr;
|
use crate::types::{Capabilities, PeerAddr, ReasonForBan};
|
||||||
use crate::types::{Capabilities, ReasonForBan};
|
|
||||||
use grin_store::{self, option_to_not_found, to_key, Error};
|
use grin_store::{self, option_to_not_found, to_key, Error};
|
||||||
|
|
||||||
const STORE_SUBPATH: &'static str = "peers";
|
const STORE_SUBPATH: &'static str = "peers";
|
||||||
|
|
||||||
const PEER_PREFIX: u8 = 'p' as u8;
|
const PEER_PREFIX: u8 = 'P' as u8;
|
||||||
|
|
||||||
/// Types of messages
|
/// Types of messages
|
||||||
enum_from_primitive! {
|
enum_from_primitive! {
|
||||||
|
@ -45,7 +43,7 @@ enum_from_primitive! {
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PeerData {
|
pub struct PeerData {
|
||||||
/// Network address of the peer.
|
/// Network address of the peer.
|
||||||
pub addr: SocketAddr,
|
pub addr: PeerAddr,
|
||||||
/// What capabilities the peer advertises. Unknown until a successful
|
/// What capabilities the peer advertises. Unknown until a successful
|
||||||
/// connection.
|
/// connection.
|
||||||
pub capabilities: Capabilities,
|
pub capabilities: Capabilities,
|
||||||
|
@ -63,7 +61,7 @@ pub struct PeerData {
|
||||||
|
|
||||||
impl Writeable for PeerData {
|
impl Writeable for PeerData {
|
||||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||||
SockAddr(self.addr).write(writer)?;
|
self.addr.write(writer)?;
|
||||||
ser_multiwrite!(
|
ser_multiwrite!(
|
||||||
writer,
|
writer,
|
||||||
[write_u32, self.capabilities.bits()],
|
[write_u32, self.capabilities.bits()],
|
||||||
|
@ -79,7 +77,7 @@ impl Writeable for PeerData {
|
||||||
|
|
||||||
impl Readable for PeerData {
|
impl Readable for PeerData {
|
||||||
fn read(reader: &mut dyn Reader) -> Result<PeerData, ser::Error> {
|
fn read(reader: &mut dyn Reader) -> Result<PeerData, ser::Error> {
|
||||||
let addr = SockAddr::read(reader)?;
|
let addr = PeerAddr::read(reader)?;
|
||||||
let capab = reader.read_u32()?;
|
let capab = reader.read_u32()?;
|
||||||
let ua = reader.read_bytes_len_prefix()?;
|
let ua = reader.read_bytes_len_prefix()?;
|
||||||
let (fl, lb, br) = ser_multiread!(reader, read_u8, read_i64, read_i32);
|
let (fl, lb, br) = ser_multiread!(reader, read_u8, read_i64, read_i32);
|
||||||
|
@ -99,7 +97,7 @@ impl Readable for PeerData {
|
||||||
|
|
||||||
match State::from_u8(fl) {
|
match State::from_u8(fl) {
|
||||||
Some(flags) => Ok(PeerData {
|
Some(flags) => Ok(PeerData {
|
||||||
addr: addr.0,
|
addr,
|
||||||
capabilities,
|
capabilities,
|
||||||
user_agent,
|
user_agent,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
|
@ -132,20 +130,20 @@ impl PeerStore {
|
||||||
batch.commit()
|
batch.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_peer(&self, peer_addr: SocketAddr) -> Result<PeerData, Error> {
|
pub fn get_peer(&self, peer_addr: PeerAddr) -> Result<PeerData, Error> {
|
||||||
option_to_not_found(
|
option_to_not_found(
|
||||||
self.db.get_ser(&peer_key(peer_addr)[..]),
|
self.db.get_ser(&peer_key(peer_addr)[..]),
|
||||||
&format!("Peer at address: {}", peer_addr),
|
&format!("Peer at address: {}", peer_addr),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exists_peer(&self, peer_addr: SocketAddr) -> Result<bool, Error> {
|
pub fn exists_peer(&self, peer_addr: PeerAddr) -> Result<bool, Error> {
|
||||||
self.db.exists(&peer_key(peer_addr)[..])
|
self.db.exists(&peer_key(peer_addr)[..])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO - allow below added to avoid github issue reports
|
/// TODO - allow below added to avoid github issue reports
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn delete_peer(&self, peer_addr: SocketAddr) -> Result<(), Error> {
|
pub fn delete_peer(&self, peer_addr: PeerAddr) -> Result<(), Error> {
|
||||||
let batch = self.db.batch()?;
|
let batch = self.db.batch()?;
|
||||||
batch.delete(&peer_key(peer_addr)[..])?;
|
batch.delete(&peer_key(peer_addr)[..])?;
|
||||||
batch.commit()
|
batch.commit()
|
||||||
|
@ -162,17 +160,6 @@ impl PeerStore {
|
||||||
peers.iter().take(count).cloned().collect()
|
peers.iter().take(count).cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query all peers with same IP address, and ignore the port
|
|
||||||
pub fn find_peers_by_ip(&self, peer_addr: SocketAddr) -> Vec<PeerData> {
|
|
||||||
self.db
|
|
||||||
.iter::<PeerData>(&to_key(
|
|
||||||
PEER_PREFIX,
|
|
||||||
&mut format!("{}", peer_addr.ip()).into_bytes(),
|
|
||||||
))
|
|
||||||
.unwrap()
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List all known peers
|
/// List all known peers
|
||||||
/// Used for /v1/peers/all api endpoint
|
/// Used for /v1/peers/all api endpoint
|
||||||
pub fn all_peers(&self) -> Vec<PeerData> {
|
pub fn all_peers(&self) -> Vec<PeerData> {
|
||||||
|
@ -182,7 +169,7 @@ impl PeerStore {
|
||||||
|
|
||||||
/// Convenience method to load a peer data, update its status and save it
|
/// Convenience method to load a peer data, update its status and save it
|
||||||
/// back. If new state is Banned its last banned time will be updated too.
|
/// back. If new state is Banned its last banned time will be updated too.
|
||||||
pub fn update_state(&self, peer_addr: SocketAddr, new_state: State) -> Result<(), Error> {
|
pub fn update_state(&self, peer_addr: PeerAddr, new_state: State) -> Result<(), Error> {
|
||||||
let batch = self.db.batch()?;
|
let batch = self.db.batch()?;
|
||||||
|
|
||||||
let mut peer = option_to_not_found(
|
let mut peer = option_to_not_found(
|
||||||
|
@ -194,7 +181,7 @@ impl PeerStore {
|
||||||
peer.last_banned = Utc::now().timestamp();
|
peer.last_banned = Utc::now().timestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
batch.put_ser(&peer_key(peer.addr)[..], &peer)?;
|
batch.put_ser(&peer_key(peer_addr)[..], &peer)?;
|
||||||
batch.commit()
|
batch.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,9 +213,7 @@ impl PeerStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peer_key(peer_addr: SocketAddr) -> Vec<u8> {
|
// Ignore the port unless ip is loopback address.
|
||||||
to_key(
|
fn peer_key(peer_addr: PeerAddr) -> Vec<u8> {
|
||||||
PEER_PREFIX,
|
to_key(PEER_PREFIX, &mut peer_addr.as_key().into_bytes())
|
||||||
&mut format!("{}:{}", peer_addr.ip(), peer_addr.port()).into_bytes(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
143
p2p/src/types.rs
143
p2p/src/types.rs
|
@ -16,15 +16,18 @@ use crate::util::RwLock;
|
||||||
use std::convert::From;
|
use std::convert::From;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{IpAddr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
|
||||||
|
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
|
|
||||||
|
use crate::core::core;
|
||||||
use crate::core::core::hash::Hash;
|
use crate::core::core::hash::Hash;
|
||||||
|
use crate::core::global;
|
||||||
use crate::core::pow::Difficulty;
|
use crate::core::pow::Difficulty;
|
||||||
use crate::core::{core, ser};
|
use crate::core::ser::{self, Readable, Reader, Writeable, Writer};
|
||||||
use grin_store;
|
use grin_store;
|
||||||
|
|
||||||
/// Maximum number of block headers a peer should ever send
|
/// Maximum number of block headers a peer should ever send
|
||||||
|
@ -95,6 +98,106 @@ impl<T> From<mpsc::TrySendError<T>> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
|
pub struct PeerAddr(pub SocketAddr);
|
||||||
|
|
||||||
|
impl Writeable for PeerAddr {
|
||||||
|
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||||
|
match self.0 {
|
||||||
|
SocketAddr::V4(sav4) => {
|
||||||
|
ser_multiwrite!(
|
||||||
|
writer,
|
||||||
|
[write_u8, 0],
|
||||||
|
[write_fixed_bytes, &sav4.ip().octets().to_vec()],
|
||||||
|
[write_u16, sav4.port()]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
SocketAddr::V6(sav6) => {
|
||||||
|
writer.write_u8(1)?;
|
||||||
|
for seg in &sav6.ip().segments() {
|
||||||
|
writer.write_u16(*seg)?;
|
||||||
|
}
|
||||||
|
writer.write_u16(sav6.port())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Readable for PeerAddr {
|
||||||
|
fn read(reader: &mut dyn Reader) -> Result<PeerAddr, ser::Error> {
|
||||||
|
let v4_or_v6 = reader.read_u8()?;
|
||||||
|
if v4_or_v6 == 0 {
|
||||||
|
let ip = reader.read_fixed_bytes(4)?;
|
||||||
|
let port = reader.read_u16()?;
|
||||||
|
Ok(PeerAddr(SocketAddr::V4(SocketAddrV4::new(
|
||||||
|
Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]),
|
||||||
|
port,
|
||||||
|
))))
|
||||||
|
} else {
|
||||||
|
let ip = try_iter_map_vec!(0..8, |_| reader.read_u16());
|
||||||
|
let port = reader.read_u16()?;
|
||||||
|
Ok(PeerAddr(SocketAddr::V6(SocketAddrV6::new(
|
||||||
|
Ipv6Addr::new(ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7]),
|
||||||
|
port,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::hash::Hash for PeerAddr {
|
||||||
|
/// If loopback address then we care about ip and port.
|
||||||
|
/// If regular address then we only care about the ip and ignore the port.
|
||||||
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
|
if self.0.ip().is_loopback() {
|
||||||
|
self.0.hash(state);
|
||||||
|
} else {
|
||||||
|
self.0.ip().hash(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for PeerAddr {
|
||||||
|
/// If loopback address then we care about ip and port.
|
||||||
|
/// If regular address then we only care about the ip and ignore the port.
|
||||||
|
fn eq(&self, other: &PeerAddr) -> bool {
|
||||||
|
if self.0.ip().is_loopback() {
|
||||||
|
self.0 == other.0
|
||||||
|
} else {
|
||||||
|
self.0.ip() == other.0.ip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for PeerAddr {}
|
||||||
|
|
||||||
|
impl std::fmt::Display for PeerAddr {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PeerAddr {
|
||||||
|
/// Convenient way of constructing a new peer_addr from an ip_addr
|
||||||
|
/// defaults to port 3414 on mainnet and 13414 on floonet.
|
||||||
|
pub fn from_ip(addr: IpAddr) -> PeerAddr {
|
||||||
|
let port = if global::is_floonet() { 13414 } else { 3414 };
|
||||||
|
PeerAddr(SocketAddr::new(addr, port))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the ip is loopback then our key is "ip:port" (mainly for local usernet testing).
|
||||||
|
/// Otherwise we only care about the ip (we disallow multiple peers on the same ip address).
|
||||||
|
pub fn as_key(&self) -> String {
|
||||||
|
if self.0.ip().is_loopback() {
|
||||||
|
format!("{}:{}", self.0.ip(), self.0.port())
|
||||||
|
} else {
|
||||||
|
format!("{}", self.0.ip())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration for the peer-to-peer server.
|
/// Configuration for the peer-to-peer server.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct P2PConfig {
|
pub struct P2PConfig {
|
||||||
|
@ -106,18 +209,18 @@ pub struct P2PConfig {
|
||||||
pub seeding_type: Seeding,
|
pub seeding_type: Seeding,
|
||||||
|
|
||||||
/// The list of seed nodes, if using Seeding as a seed type
|
/// The list of seed nodes, if using Seeding as a seed type
|
||||||
pub seeds: Option<Vec<String>>,
|
pub seeds: Option<Vec<PeerAddr>>,
|
||||||
|
|
||||||
/// Capabilities expose by this node, also conditions which other peers this
|
/// Capabilities expose by this node, also conditions which other peers this
|
||||||
/// node will have an affinity toward when connection.
|
/// node will have an affinity toward when connection.
|
||||||
pub capabilities: Capabilities,
|
pub capabilities: Capabilities,
|
||||||
|
|
||||||
pub peers_allow: Option<Vec<String>>,
|
pub peers_allow: Option<Vec<PeerAddr>>,
|
||||||
|
|
||||||
pub peers_deny: Option<Vec<String>>,
|
pub peers_deny: Option<Vec<PeerAddr>>,
|
||||||
|
|
||||||
/// The list of preferred peers that we will try to connect to
|
/// The list of preferred peers that we will try to connect to
|
||||||
pub peers_preferred: Option<Vec<String>>,
|
pub peers_preferred: Option<Vec<PeerAddr>>,
|
||||||
|
|
||||||
pub ban_window: Option<i64>,
|
pub ban_window: Option<i64>,
|
||||||
|
|
||||||
|
@ -125,7 +228,7 @@ pub struct P2PConfig {
|
||||||
|
|
||||||
pub peer_min_preferred_count: Option<u32>,
|
pub peer_min_preferred_count: Option<u32>,
|
||||||
|
|
||||||
pub dandelion_peer: Option<SocketAddr>,
|
pub dandelion_peer: Option<PeerAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Default address for peer-to-peer connections.
|
/// Default address for peer-to-peer connections.
|
||||||
|
@ -178,7 +281,7 @@ impl P2PConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type of seeding the server will use to find other peers on the network.
|
/// Type of seeding the server will use to find other peers on the network.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
|
||||||
pub enum Seeding {
|
pub enum Seeding {
|
||||||
/// No seeding, mostly for tests that programmatically connect
|
/// No seeding, mostly for tests that programmatically connect
|
||||||
None,
|
None,
|
||||||
|
@ -262,7 +365,7 @@ pub struct PeerInfo {
|
||||||
pub capabilities: Capabilities,
|
pub capabilities: Capabilities,
|
||||||
pub user_agent: String,
|
pub user_agent: String,
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub addr: SocketAddr,
|
pub addr: PeerAddr,
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
pub live_info: Arc<RwLock<PeerLiveInfo>>,
|
pub live_info: Arc<RwLock<PeerLiveInfo>>,
|
||||||
}
|
}
|
||||||
|
@ -307,7 +410,7 @@ pub struct PeerInfoDisplay {
|
||||||
pub capabilities: Capabilities,
|
pub capabilities: Capabilities,
|
||||||
pub user_agent: String,
|
pub user_agent: String,
|
||||||
pub version: u32,
|
pub version: u32,
|
||||||
pub addr: SocketAddr,
|
pub addr: PeerAddr,
|
||||||
pub direction: Direction,
|
pub direction: Direction,
|
||||||
pub total_difficulty: Difficulty,
|
pub total_difficulty: Difficulty,
|
||||||
pub height: u64,
|
pub height: u64,
|
||||||
|
@ -353,22 +456,22 @@ pub trait ChainAdapter: Sync + Send {
|
||||||
|
|
||||||
fn get_transaction(&self, kernel_hash: Hash) -> Option<core::Transaction>;
|
fn get_transaction(&self, kernel_hash: Hash) -> Option<core::Transaction>;
|
||||||
|
|
||||||
fn tx_kernel_received(&self, kernel_hash: Hash, addr: SocketAddr);
|
fn tx_kernel_received(&self, kernel_hash: Hash, addr: PeerAddr);
|
||||||
|
|
||||||
/// A block has been received from one of our peers. Returns true if the
|
/// A block has been received from one of our peers. Returns true if the
|
||||||
/// block could be handled properly and is not deemed defective by the
|
/// block could be handled properly and is not deemed defective by the
|
||||||
/// chain. Returning false means the block will never be valid and
|
/// chain. Returning false means the block will never be valid and
|
||||||
/// may result in the peer being banned.
|
/// may result in the peer being banned.
|
||||||
fn block_received(&self, b: core::Block, addr: SocketAddr, was_requested: bool) -> bool;
|
fn block_received(&self, b: core::Block, addr: PeerAddr, was_requested: bool) -> bool;
|
||||||
|
|
||||||
fn compact_block_received(&self, cb: core::CompactBlock, addr: SocketAddr) -> bool;
|
fn compact_block_received(&self, cb: core::CompactBlock, addr: PeerAddr) -> bool;
|
||||||
|
|
||||||
fn header_received(&self, bh: core::BlockHeader, addr: SocketAddr) -> bool;
|
fn header_received(&self, bh: core::BlockHeader, addr: PeerAddr) -> bool;
|
||||||
|
|
||||||
/// A set of block header has been received, typically in response to a
|
/// A set of block header has been received, typically in response to a
|
||||||
/// block
|
/// block
|
||||||
/// header request.
|
/// header request.
|
||||||
fn headers_received(&self, bh: &[core::BlockHeader], addr: SocketAddr) -> bool;
|
fn headers_received(&self, bh: &[core::BlockHeader], addr: PeerAddr) -> bool;
|
||||||
|
|
||||||
/// Finds a list of block headers based on the provided locator. Tries to
|
/// Finds a list of block headers based on the provided locator. Tries to
|
||||||
/// identify the common chain and gets the headers that follow it
|
/// identify the common chain and gets the headers that follow it
|
||||||
|
@ -401,7 +504,7 @@ pub trait ChainAdapter: Sync + Send {
|
||||||
/// If we're willing to accept that new state, the data stream will be
|
/// If we're willing to accept that new state, the data stream will be
|
||||||
/// read as a zip file, unzipped and the resulting state files should be
|
/// read as a zip file, unzipped and the resulting state files should be
|
||||||
/// rewound to the provided indexes.
|
/// rewound to the provided indexes.
|
||||||
fn txhashset_write(&self, h: Hash, txhashset_data: File, peer_addr: SocketAddr) -> bool;
|
fn txhashset_write(&self, h: Hash, txhashset_data: File, peer_addr: PeerAddr) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional methods required by the protocol that don't need to be
|
/// Additional methods required by the protocol that don't need to be
|
||||||
|
@ -409,14 +512,14 @@ pub trait ChainAdapter: Sync + Send {
|
||||||
pub trait NetAdapter: ChainAdapter {
|
pub trait NetAdapter: ChainAdapter {
|
||||||
/// Find good peers we know with the provided capability and return their
|
/// Find good peers we know with the provided capability and return their
|
||||||
/// addresses.
|
/// addresses.
|
||||||
fn find_peer_addrs(&self, capab: Capabilities) -> Vec<SocketAddr>;
|
fn find_peer_addrs(&self, capab: Capabilities) -> Vec<PeerAddr>;
|
||||||
|
|
||||||
/// A list of peers has been received from one of our peers.
|
/// A list of peers has been received from one of our peers.
|
||||||
fn peer_addrs_received(&self, _: Vec<SocketAddr>);
|
fn peer_addrs_received(&self, _: Vec<PeerAddr>);
|
||||||
|
|
||||||
/// Heard total_difficulty from a connected peer (via ping/pong).
|
/// Heard total_difficulty from a connected peer (via ping/pong).
|
||||||
fn peer_difficulty(&self, _: SocketAddr, _: Difficulty, _: u64);
|
fn peer_difficulty(&self, _: PeerAddr, _: Difficulty, _: u64);
|
||||||
|
|
||||||
/// Is this peer currently banned?
|
/// Is this peer currently banned?
|
||||||
fn is_banned(&self, addr: SocketAddr) -> bool;
|
fn is_banned(&self, addr: PeerAddr) -> bool;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ use std::{thread, time};
|
||||||
|
|
||||||
use crate::core::core::hash::Hash;
|
use crate::core::core::hash::Hash;
|
||||||
use crate::core::pow::Difficulty;
|
use crate::core::pow::Difficulty;
|
||||||
|
use crate::p2p::types::PeerAddr;
|
||||||
use crate::p2p::Peer;
|
use crate::p2p::Peer;
|
||||||
|
|
||||||
fn open_port() -> u16 {
|
fn open_port() -> u16 {
|
||||||
|
@ -70,7 +71,7 @@ fn peer_handshake() {
|
||||||
let addr = SocketAddr::new(p2p_config.host, p2p_config.port);
|
let addr = SocketAddr::new(p2p_config.host, p2p_config.port);
|
||||||
let mut socket = TcpStream::connect_timeout(&addr, time::Duration::from_secs(10)).unwrap();
|
let mut socket = TcpStream::connect_timeout(&addr, time::Duration::from_secs(10)).unwrap();
|
||||||
|
|
||||||
let my_addr = "127.0.0.1:5000".parse().unwrap();
|
let my_addr = PeerAddr("127.0.0.1:5000".parse().unwrap());
|
||||||
let mut peer = Peer::connect(
|
let mut peer = Peer::connect(
|
||||||
&mut socket,
|
&mut socket,
|
||||||
p2p::Capabilities::UNKNOWN,
|
p2p::Capabilities::UNKNOWN,
|
||||||
|
@ -89,7 +90,7 @@ fn peer_handshake() {
|
||||||
peer.send_ping(Difficulty::min(), 0).unwrap();
|
peer.send_ping(Difficulty::min(), 0).unwrap();
|
||||||
thread::sleep(time::Duration::from_secs(1));
|
thread::sleep(time::Duration::from_secs(1));
|
||||||
|
|
||||||
let server_peer = server.peers.get_connected_peer(&my_addr).unwrap();
|
let server_peer = server.peers.get_connected_peer(my_addr).unwrap();
|
||||||
assert_eq!(server_peer.info.total_difficulty(), Difficulty::min());
|
assert_eq!(server_peer.info.total_difficulty(), Difficulty::min());
|
||||||
assert!(server.peers.peer_count() > 0);
|
assert!(server.peers.peer_count() > 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
use crate::util::RwLock;
|
use crate::util::RwLock;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
@ -31,6 +30,7 @@ use crate::core::core::{BlockHeader, BlockSums, CompactBlock};
|
||||||
use crate::core::pow::Difficulty;
|
use crate::core::pow::Difficulty;
|
||||||
use crate::core::{core, global};
|
use crate::core::{core, global};
|
||||||
use crate::p2p;
|
use crate::p2p;
|
||||||
|
use crate::p2p::types::PeerAddr;
|
||||||
use crate::pool;
|
use crate::pool;
|
||||||
use crate::util::OneTime;
|
use crate::util::OneTime;
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
|
@ -62,7 +62,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||||
self.tx_pool.read().retrieve_tx_by_kernel_hash(kernel_hash)
|
self.tx_pool.read().retrieve_tx_by_kernel_hash(kernel_hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tx_kernel_received(&self, kernel_hash: Hash, addr: SocketAddr) {
|
fn tx_kernel_received(&self, kernel_hash: Hash, addr: PeerAddr) {
|
||||||
// nothing much we can do with a new transaction while syncing
|
// nothing much we can do with a new transaction while syncing
|
||||||
if self.sync_state.is_syncing() {
|
if self.sync_state.is_syncing() {
|
||||||
return;
|
return;
|
||||||
|
@ -71,7 +71,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||||
let tx = self.tx_pool.read().retrieve_tx_by_kernel_hash(kernel_hash);
|
let tx = self.tx_pool.read().retrieve_tx_by_kernel_hash(kernel_hash);
|
||||||
|
|
||||||
if tx.is_none() {
|
if tx.is_none() {
|
||||||
self.request_transaction(kernel_hash, &addr);
|
self.request_transaction(kernel_hash, addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_received(&self, b: core::Block, addr: SocketAddr, was_requested: bool) -> bool {
|
fn block_received(&self, b: core::Block, addr: PeerAddr, was_requested: bool) -> bool {
|
||||||
debug!(
|
debug!(
|
||||||
"Received block {} at {} from {} [in/out/kern: {}/{}/{}] going to process.",
|
"Received block {} at {} from {} [in/out/kern: {}/{}/{}] going to process.",
|
||||||
b.hash(),
|
b.hash(),
|
||||||
|
@ -120,7 +120,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||||
self.process_block(b, addr, was_requested)
|
self.process_block(b, addr, was_requested)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compact_block_received(&self, cb: core::CompactBlock, addr: SocketAddr) -> bool {
|
fn compact_block_received(&self, cb: core::CompactBlock, addr: PeerAddr) -> bool {
|
||||||
let bhash = cb.hash();
|
let bhash = cb.hash();
|
||||||
debug!(
|
debug!(
|
||||||
"Received compact_block {} at {} from {} [out/kern/kern_ids: {}/{}/{}] going to process.",
|
"Received compact_block {} at {} from {} [out/kern/kern_ids: {}/{}/{}] going to process.",
|
||||||
|
@ -187,7 +187,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||||
} else {
|
} else {
|
||||||
if self.sync_state.status() == SyncStatus::NoSync {
|
if self.sync_state.status() == SyncStatus::NoSync {
|
||||||
debug!("adapter: block invalid after hydration, requesting full block");
|
debug!("adapter: block invalid after hydration, requesting full block");
|
||||||
self.request_block(&cb.header, &addr);
|
self.request_block(&cb.header, addr);
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
debug!("block invalid after hydration, ignoring it, cause still syncing");
|
debug!("block invalid after hydration, ignoring it, cause still syncing");
|
||||||
|
@ -201,7 +201,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_received(&self, bh: core::BlockHeader, addr: SocketAddr) -> bool {
|
fn header_received(&self, bh: core::BlockHeader, addr: PeerAddr) -> bool {
|
||||||
let bhash = bh.hash();
|
let bhash = bh.hash();
|
||||||
debug!(
|
debug!(
|
||||||
"Received block header {} at {} from {}, going to process.",
|
"Received block header {} at {} from {}, going to process.",
|
||||||
|
@ -227,13 +227,13 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||||
|
|
||||||
// we have successfully processed a block header
|
// we have successfully processed a block header
|
||||||
// so we can go request the block itself
|
// so we can go request the block itself
|
||||||
self.request_compact_block(&bh, &addr);
|
self.request_compact_block(&bh, addr);
|
||||||
|
|
||||||
// done receiving the header
|
// done receiving the header
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn headers_received(&self, bhs: &[core::BlockHeader], addr: SocketAddr) -> bool {
|
fn headers_received(&self, bhs: &[core::BlockHeader], addr: PeerAddr) -> bool {
|
||||||
info!("Received {} block headers from {}", bhs.len(), addr,);
|
info!("Received {} block headers from {}", bhs.len(), addr,);
|
||||||
|
|
||||||
if bhs.len() == 0 {
|
if bhs.len() == 0 {
|
||||||
|
@ -342,7 +342,7 @@ impl p2p::ChainAdapter for NetToChainAdapter {
|
||||||
/// If we're willing to accept that new state, the data stream will be
|
/// If we're willing to accept that new state, the data stream will be
|
||||||
/// read as a zip file, unzipped and the resulting state files should be
|
/// read as a zip file, unzipped and the resulting state files should be
|
||||||
/// rewound to the provided indexes.
|
/// rewound to the provided indexes.
|
||||||
fn txhashset_write(&self, h: Hash, txhashset_data: File, _peer_addr: SocketAddr) -> bool {
|
fn txhashset_write(&self, h: Hash, txhashset_data: File, _peer_addr: PeerAddr) -> bool {
|
||||||
// check status again after download, in case 2 txhashsets made it somehow
|
// check status again after download, in case 2 txhashsets made it somehow
|
||||||
if let SyncStatus::TxHashsetDownload { .. } = self.sync_state.status() {
|
if let SyncStatus::TxHashsetDownload { .. } = self.sync_state.status() {
|
||||||
} else {
|
} else {
|
||||||
|
@ -421,7 +421,7 @@ impl NetToChainAdapter {
|
||||||
|
|
||||||
// pushing the new block through the chain pipeline
|
// pushing the new block through the chain pipeline
|
||||||
// remembering to reset the head if we have a bad block
|
// remembering to reset the head if we have a bad block
|
||||||
fn process_block(&self, b: core::Block, addr: SocketAddr, was_requested: bool) -> bool {
|
fn process_block(&self, b: core::Block, addr: PeerAddr, was_requested: bool) -> bool {
|
||||||
// We cannot process blocks earlier than the horizon so check for this here.
|
// We cannot process blocks earlier than the horizon so check for this here.
|
||||||
{
|
{
|
||||||
let head = self.chain().head().unwrap();
|
let head = self.chain().head().unwrap();
|
||||||
|
@ -458,7 +458,7 @@ impl NetToChainAdapter {
|
||||||
&& !self.sync_state.is_syncing()
|
&& !self.sync_state.is_syncing()
|
||||||
{
|
{
|
||||||
debug!("process_block: received an orphan block, checking the parent: {:}", previous.hash());
|
debug!("process_block: received an orphan block, checking the parent: {:}", previous.hash());
|
||||||
self.request_block_by_hash(previous.hash(), &addr)
|
self.request_block_by_hash(previous.hash(), addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
|
@ -525,7 +525,7 @@ impl NetToChainAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_transaction(&self, h: Hash, addr: &SocketAddr) {
|
fn request_transaction(&self, h: Hash, addr: PeerAddr) {
|
||||||
self.send_tx_request_to_peer(h, addr, |peer, h| peer.send_tx_request(h))
|
self.send_tx_request_to_peer(h, addr, |peer, h| peer.send_tx_request(h))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,24 +533,24 @@ impl NetToChainAdapter {
|
||||||
// it into a full block then fallback to requesting the full block
|
// it into a full block then fallback to requesting the full block
|
||||||
// from the same peer that gave us the compact block
|
// from the same peer that gave us the compact block
|
||||||
// consider additional peers for redundancy?
|
// consider additional peers for redundancy?
|
||||||
fn request_block(&self, bh: &BlockHeader, addr: &SocketAddr) {
|
fn request_block(&self, bh: &BlockHeader, addr: PeerAddr) {
|
||||||
self.request_block_by_hash(bh.hash(), addr)
|
self.request_block_by_hash(bh.hash(), addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_block_by_hash(&self, h: Hash, addr: &SocketAddr) {
|
fn request_block_by_hash(&self, h: Hash, addr: PeerAddr) {
|
||||||
self.send_block_request_to_peer(h, addr, |peer, h| peer.send_block_request(h))
|
self.send_block_request_to_peer(h, addr, |peer, h| peer.send_block_request(h))
|
||||||
}
|
}
|
||||||
|
|
||||||
// After we have received a block header in "header first" propagation
|
// After we have received a block header in "header first" propagation
|
||||||
// we need to go request the block (compact representation) from the
|
// we need to go request the block (compact representation) from the
|
||||||
// same peer that gave us the header (unless we have already accepted the block)
|
// same peer that gave us the header (unless we have already accepted the block)
|
||||||
fn request_compact_block(&self, bh: &BlockHeader, addr: &SocketAddr) {
|
fn request_compact_block(&self, bh: &BlockHeader, addr: PeerAddr) {
|
||||||
self.send_block_request_to_peer(bh.hash(), addr, |peer, h| {
|
self.send_block_request_to_peer(bh.hash(), addr, |peer, h| {
|
||||||
peer.send_compact_block_request(h)
|
peer.send_compact_block_request(h)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_tx_request_to_peer<F>(&self, h: Hash, addr: &SocketAddr, f: F)
|
fn send_tx_request_to_peer<F>(&self, h: Hash, addr: PeerAddr, f: F)
|
||||||
where
|
where
|
||||||
F: Fn(&p2p::Peer, Hash) -> Result<(), p2p::Error>,
|
F: Fn(&p2p::Peer, Hash) -> Result<(), p2p::Error>,
|
||||||
{
|
{
|
||||||
|
@ -567,7 +567,7 @@ impl NetToChainAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_block_request_to_peer<F>(&self, h: Hash, addr: &SocketAddr, f: F)
|
fn send_block_request_to_peer<F>(&self, h: Hash, addr: PeerAddr, f: F)
|
||||||
where
|
where
|
||||||
F: Fn(&p2p::Peer, Hash) -> Result<(), p2p::Error>,
|
F: Fn(&p2p::Peer, Hash) -> Result<(), p2p::Error>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,12 +21,13 @@ use chrono::prelude::{DateTime, Utc};
|
||||||
use chrono::{Duration, MIN_DATE};
|
use chrono::{Duration, MIN_DATE};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::net::{SocketAddr, ToSocketAddrs};
|
use std::net::ToSocketAddrs;
|
||||||
use std::sync::{mpsc, Arc};
|
use std::sync::{mpsc, Arc};
|
||||||
use std::{cmp, str, thread, time};
|
use std::{cmp, str, thread, time};
|
||||||
|
|
||||||
use crate::core::global;
|
use crate::core::global;
|
||||||
use crate::p2p;
|
use crate::p2p;
|
||||||
|
use crate::p2p::types::PeerAddr;
|
||||||
use crate::p2p::ChainAdapter;
|
use crate::p2p::ChainAdapter;
|
||||||
use crate::pool::DandelionConfig;
|
use crate::pool::DandelionConfig;
|
||||||
use crate::util::{Mutex, StopState};
|
use crate::util::{Mutex, StopState};
|
||||||
|
@ -52,8 +53,8 @@ pub fn connect_and_monitor(
|
||||||
p2p_server: Arc<p2p::Server>,
|
p2p_server: Arc<p2p::Server>,
|
||||||
capabilities: p2p::Capabilities,
|
capabilities: p2p::Capabilities,
|
||||||
dandelion_config: DandelionConfig,
|
dandelion_config: DandelionConfig,
|
||||||
seed_list: Box<dyn Fn() -> Vec<SocketAddr> + Send>,
|
seed_list: Box<dyn Fn() -> Vec<PeerAddr> + Send>,
|
||||||
preferred_peers: Option<Vec<SocketAddr>>,
|
preferred_peers: Option<Vec<PeerAddr>>,
|
||||||
stop_state: Arc<Mutex<StopState>>,
|
stop_state: Arc<Mutex<StopState>>,
|
||||||
) {
|
) {
|
||||||
let _ = thread::Builder::new()
|
let _ = thread::Builder::new()
|
||||||
|
@ -78,7 +79,7 @@ pub fn connect_and_monitor(
|
||||||
let mut prev_ping = Utc::now();
|
let mut prev_ping = Utc::now();
|
||||||
let mut start_attempt = 0;
|
let mut start_attempt = 0;
|
||||||
|
|
||||||
let mut connecting_history: HashMap<SocketAddr, DateTime<Utc>> = HashMap::new();
|
let mut connecting_history: HashMap<PeerAddr, DateTime<Utc>> = HashMap::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if stop_state.lock().is_stopped() {
|
if stop_state.lock().is_stopped() {
|
||||||
|
@ -140,8 +141,8 @@ pub fn connect_and_monitor(
|
||||||
fn monitor_peers(
|
fn monitor_peers(
|
||||||
peers: Arc<p2p::Peers>,
|
peers: Arc<p2p::Peers>,
|
||||||
config: p2p::P2PConfig,
|
config: p2p::P2PConfig,
|
||||||
tx: mpsc::Sender<SocketAddr>,
|
tx: mpsc::Sender<PeerAddr>,
|
||||||
preferred_peers_list: Option<Vec<SocketAddr>>,
|
preferred_peers_list: Option<Vec<PeerAddr>>,
|
||||||
) {
|
) {
|
||||||
// regularly check if we need to acquire more peers and if so, gets
|
// regularly check if we need to acquire more peers and if so, gets
|
||||||
// them from db
|
// them from db
|
||||||
|
@ -156,7 +157,7 @@ fn monitor_peers(
|
||||||
let interval = Utc::now().timestamp() - x.last_banned;
|
let interval = Utc::now().timestamp() - x.last_banned;
|
||||||
// Unban peer
|
// Unban peer
|
||||||
if interval >= config.ban_window() {
|
if interval >= config.ban_window() {
|
||||||
peers.unban_peer(&x.addr);
|
peers.unban_peer(x.addr);
|
||||||
debug!(
|
debug!(
|
||||||
"monitor_peers: unbanned {} after {} seconds",
|
"monitor_peers: unbanned {} after {} seconds",
|
||||||
x.addr, interval
|
x.addr, interval
|
||||||
|
@ -192,7 +193,7 @@ fn monitor_peers(
|
||||||
|
|
||||||
// loop over connected peers
|
// loop over connected peers
|
||||||
// ask them for their list of peers
|
// ask them for their list of peers
|
||||||
let mut connected_peers: Vec<SocketAddr> = vec![];
|
let mut connected_peers: Vec<PeerAddr> = vec![];
|
||||||
for p in peers.connected_peers() {
|
for p in peers.connected_peers() {
|
||||||
trace!(
|
trace!(
|
||||||
"monitor_peers: {}:{} ask {} for more peers",
|
"monitor_peers: {}:{} ask {} for more peers",
|
||||||
|
@ -205,8 +206,7 @@ fn monitor_peers(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to connect to preferred peers if there is some
|
// Attempt to connect to preferred peers if there is some
|
||||||
match preferred_peers_list {
|
if let Some(preferred_peers) = preferred_peers_list {
|
||||||
Some(preferred_peers) => {
|
|
||||||
for p in preferred_peers {
|
for p in preferred_peers {
|
||||||
if !connected_peers.is_empty() {
|
if !connected_peers.is_empty() {
|
||||||
if !connected_peers.contains(&p) {
|
if !connected_peers.contains(&p) {
|
||||||
|
@ -217,8 +217,6 @@ fn monitor_peers(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => debug!("monitor_peers: no preferred peers"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// take a random defunct peer and mark it healthy: over a long period any
|
// take a random defunct peer and mark it healthy: over a long period any
|
||||||
// peer will see another as defunct eventually, gives us a chance to retry
|
// peer will see another as defunct eventually, gives us a chance to retry
|
||||||
|
@ -235,7 +233,7 @@ fn monitor_peers(
|
||||||
config.peer_max_count() as usize,
|
config.peer_max_count() as usize,
|
||||||
);
|
);
|
||||||
|
|
||||||
for p in new_peers.iter().filter(|p| !peers.is_known(&p.addr)) {
|
for p in new_peers.iter().filter(|p| !peers.is_known(p.addr)) {
|
||||||
trace!(
|
trace!(
|
||||||
"monitor_peers: on {}:{}, queue to soon try {}",
|
"monitor_peers: on {}:{}, queue to soon try {}",
|
||||||
config.host,
|
config.host,
|
||||||
|
@ -265,9 +263,9 @@ fn update_dandelion_relay(peers: Arc<p2p::Peers>, dandelion_config: DandelionCon
|
||||||
// otherwise use the seeds provided.
|
// otherwise use the seeds provided.
|
||||||
fn connect_to_seeds_and_preferred_peers(
|
fn connect_to_seeds_and_preferred_peers(
|
||||||
peers: Arc<p2p::Peers>,
|
peers: Arc<p2p::Peers>,
|
||||||
tx: mpsc::Sender<SocketAddr>,
|
tx: mpsc::Sender<PeerAddr>,
|
||||||
seed_list: Box<dyn Fn() -> Vec<SocketAddr>>,
|
seed_list: Box<dyn Fn() -> Vec<PeerAddr>>,
|
||||||
peers_preferred_list: Option<Vec<SocketAddr>>,
|
peers_preferred_list: Option<Vec<PeerAddr>>,
|
||||||
) {
|
) {
|
||||||
// check if we have some peers in db
|
// check if we have some peers in db
|
||||||
// look for peers that are able to give us other peers (via PEER_LIST capability)
|
// look for peers that are able to give us other peers (via PEER_LIST capability)
|
||||||
|
@ -303,14 +301,14 @@ fn listen_for_addrs(
|
||||||
peers: Arc<p2p::Peers>,
|
peers: Arc<p2p::Peers>,
|
||||||
p2p: Arc<p2p::Server>,
|
p2p: Arc<p2p::Server>,
|
||||||
capab: p2p::Capabilities,
|
capab: p2p::Capabilities,
|
||||||
rx: &mpsc::Receiver<SocketAddr>,
|
rx: &mpsc::Receiver<PeerAddr>,
|
||||||
connecting_history: &mut HashMap<SocketAddr, DateTime<Utc>>,
|
connecting_history: &mut HashMap<PeerAddr, DateTime<Utc>>,
|
||||||
) {
|
) {
|
||||||
// Pull everything currently on the queue off the queue.
|
// Pull everything currently on the queue off the queue.
|
||||||
// Does not block so addrs may be empty.
|
// Does not block so addrs may be empty.
|
||||||
// We will take(max_peers) from this later but we want to drain the rx queue
|
// We will take(max_peers) from this later but we want to drain the rx queue
|
||||||
// here to prevent it backing up.
|
// here to prevent it backing up.
|
||||||
let addrs: Vec<SocketAddr> = rx.try_iter().collect();
|
let addrs: Vec<PeerAddr> = rx.try_iter().collect();
|
||||||
|
|
||||||
// If we have a healthy number of outbound peers then we are done here.
|
// If we have a healthy number of outbound peers then we are done here.
|
||||||
if peers.healthy_peers_mix() {
|
if peers.healthy_peers_mix() {
|
||||||
|
@ -342,7 +340,7 @@ fn listen_for_addrs(
|
||||||
let p2p_c = p2p.clone();
|
let p2p_c = p2p.clone();
|
||||||
let _ = thread::Builder::new()
|
let _ = thread::Builder::new()
|
||||||
.name("peer_connect".to_string())
|
.name("peer_connect".to_string())
|
||||||
.spawn(move || match p2p_c.connect(&addr) {
|
.spawn(move || match p2p_c.connect(addr) {
|
||||||
Ok(p) => {
|
Ok(p) => {
|
||||||
let _ = p.send_peer_request(capab);
|
let _ = p.send_peer_request(capab);
|
||||||
let _ = peers_c.update_state(addr, p2p::State::Healthy);
|
let _ = peers_c.update_state(addr, p2p::State::Healthy);
|
||||||
|
@ -368,9 +366,9 @@ fn listen_for_addrs(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dns_seeds() -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
|
pub fn dns_seeds() -> Box<dyn Fn() -> Vec<PeerAddr> + Send> {
|
||||||
Box::new(|| {
|
Box::new(|| {
|
||||||
let mut addresses: Vec<SocketAddr> = vec![];
|
let mut addresses: Vec<PeerAddr> = vec![];
|
||||||
let net_seeds = if global::is_floonet() {
|
let net_seeds = if global::is_floonet() {
|
||||||
FLOONET_DNS_SEEDS
|
FLOONET_DNS_SEEDS
|
||||||
} else {
|
} else {
|
||||||
|
@ -384,7 +382,7 @@ pub fn dns_seeds() -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
|
||||||
&mut (addrs
|
&mut (addrs
|
||||||
.map(|mut addr| {
|
.map(|mut addr| {
|
||||||
addr.set_port(if global::is_floonet() { 13414 } else { 3414 });
|
addr.set_port(if global::is_floonet() { 13414 } else { 3414 });
|
||||||
addr
|
PeerAddr(addr)
|
||||||
})
|
})
|
||||||
.filter(|addr| !temp_addresses.contains(addr))
|
.filter(|addr| !temp_addresses.contains(addr))
|
||||||
.collect()),
|
.collect()),
|
||||||
|
@ -399,26 +397,6 @@ pub fn dns_seeds() -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
|
||||||
|
|
||||||
/// Convenience function when the seed list is immediately known. Mostly used
|
/// Convenience function when the seed list is immediately known. Mostly used
|
||||||
/// for tests.
|
/// for tests.
|
||||||
pub fn predefined_seeds(addrs_str: Vec<String>) -> Box<dyn Fn() -> Vec<SocketAddr> + Send> {
|
pub fn predefined_seeds(addrs: Vec<PeerAddr>) -> Box<dyn Fn() -> Vec<PeerAddr> + Send> {
|
||||||
Box::new(move || {
|
Box::new(move || addrs.clone())
|
||||||
addrs_str
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.parse().unwrap())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convenience function when the seed list is immediately known. Mostly used
|
|
||||||
/// for tests.
|
|
||||||
pub fn preferred_peers(addrs_str: Vec<String>) -> Option<Vec<SocketAddr>> {
|
|
||||||
if addrs_str.is_empty() {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(
|
|
||||||
addrs_str
|
|
||||||
.iter()
|
|
||||||
.map(|s| s.parse().unwrap())
|
|
||||||
.collect::<Vec<_>>(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
//! the peer-to-peer server, the blockchain and the transaction pool) and acts
|
//! the peer-to-peer server, the blockchain and the transaction pool) and acts
|
||||||
//! as a facade.
|
//! as a facade.
|
||||||
|
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{thread, time};
|
use std::{thread, time};
|
||||||
|
|
||||||
|
@ -35,6 +34,7 @@ use crate::grin::{dandelion_monitor, seed, sync};
|
||||||
use crate::mining::stratumserver;
|
use crate::mining::stratumserver;
|
||||||
use crate::mining::test_miner::Miner;
|
use crate::mining::test_miner::Miner;
|
||||||
use crate::p2p;
|
use crate::p2p;
|
||||||
|
use crate::p2p::types::PeerAddr;
|
||||||
use crate::pool;
|
use crate::pool;
|
||||||
use crate::store;
|
use crate::store;
|
||||||
use crate::util::file::get_first_line;
|
use crate::util::file::get_first_line;
|
||||||
|
@ -103,7 +103,7 @@ impl Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiates a new server associated with the provided future reactor.
|
/// Instantiates a new server associated with the provided future reactor.
|
||||||
pub fn new(mut config: ServerConfig) -> Result<Server, Error> {
|
pub fn new(config: ServerConfig) -> Result<Server, Error> {
|
||||||
// Defaults to None (optional) in config file.
|
// Defaults to None (optional) in config file.
|
||||||
// This translates to false here.
|
// This translates to false here.
|
||||||
let archive_mode = match config.archive_mode {
|
let archive_mode = match config.archive_mode {
|
||||||
|
@ -178,30 +178,25 @@ impl Server {
|
||||||
pool_net_adapter.init(p2p_server.peers.clone());
|
pool_net_adapter.init(p2p_server.peers.clone());
|
||||||
net_adapter.init(p2p_server.peers.clone());
|
net_adapter.init(p2p_server.peers.clone());
|
||||||
|
|
||||||
if config.p2p_config.seeding_type.clone() != p2p::Seeding::Programmatic {
|
if config.p2p_config.seeding_type != p2p::Seeding::Programmatic {
|
||||||
let seeder = match config.p2p_config.seeding_type.clone() {
|
let seeder = match config.p2p_config.seeding_type {
|
||||||
p2p::Seeding::None => {
|
p2p::Seeding::None => {
|
||||||
warn!("No seed configured, will stay solo until connected to");
|
warn!("No seed configured, will stay solo until connected to");
|
||||||
seed::predefined_seeds(vec![])
|
seed::predefined_seeds(vec![])
|
||||||
}
|
}
|
||||||
p2p::Seeding::List => {
|
p2p::Seeding::List => {
|
||||||
seed::predefined_seeds(config.p2p_config.seeds.as_mut().unwrap().clone())
|
seed::predefined_seeds(config.p2p_config.seeds.clone().unwrap())
|
||||||
}
|
}
|
||||||
p2p::Seeding::DNSSeed => seed::dns_seeds(),
|
p2p::Seeding::DNSSeed => seed::dns_seeds(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let peers_preferred = match config.p2p_config.peers_preferred.clone() {
|
|
||||||
Some(peers_preferred) => seed::preferred_peers(peers_preferred),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
seed::connect_and_monitor(
|
seed::connect_and_monitor(
|
||||||
p2p_server.clone(),
|
p2p_server.clone(),
|
||||||
config.p2p_config.capabilities,
|
config.p2p_config.capabilities,
|
||||||
config.dandelion_config.clone(),
|
config.dandelion_config.clone(),
|
||||||
seeder,
|
seeder,
|
||||||
peers_preferred,
|
config.p2p_config.peers_preferred.clone(),
|
||||||
stop_state.clone(),
|
stop_state.clone(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -273,8 +268,8 @@ impl Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Asks the server to connect to a peer at the provided network address.
|
/// Asks the server to connect to a peer at the provided network address.
|
||||||
pub fn connect_peer(&self, addr: SocketAddr) -> Result<(), Error> {
|
pub fn connect_peer(&self, addr: PeerAddr) -> Result<(), Error> {
|
||||||
self.p2p.connect(&addr)?;
|
self.p2p.connect(addr)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ impl HeaderSync {
|
||||||
&& highest_height == peer.info.height()
|
&& highest_height == peer.info.height()
|
||||||
{
|
{
|
||||||
self.peers
|
self.peers
|
||||||
.ban_peer(&peer.info.addr, ReasonForBan::FraudHeight);
|
.ban_peer(peer.info.addr, ReasonForBan::FraudHeight);
|
||||||
info!(
|
info!(
|
||||||
"sync: ban a fraud peer: {}, claimed height: {}, total difficulty: {}",
|
"sync: ban a fraud peer: {}, claimed height: {}, total difficulty: {}",
|
||||||
peer.info.addr,
|
peer.info.addr,
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use self::keychain::Keychain;
|
use self::keychain::Keychain;
|
||||||
|
use self::p2p::PeerAddr;
|
||||||
use self::util::Mutex;
|
use self::util::Mutex;
|
||||||
use self::wallet::{HTTPNodeClient, HTTPWalletCommAdapter, LMDBBackend, WalletConfig};
|
use self::wallet::{HTTPNodeClient, HTTPWalletCommAdapter, LMDBBackend, WalletConfig};
|
||||||
use blake2_rfc as blake2;
|
use blake2_rfc as blake2;
|
||||||
|
@ -191,7 +192,7 @@ impl LocalServerContainer {
|
||||||
|
|
||||||
if self.config.seed_addr.len() > 0 {
|
if self.config.seed_addr.len() > 0 {
|
||||||
seeding_type = p2p::Seeding::List;
|
seeding_type = p2p::Seeding::List;
|
||||||
seeds = vec![self.config.seed_addr.to_string()];
|
seeds = vec![PeerAddr(self.config.seed_addr.parse().unwrap())];
|
||||||
}
|
}
|
||||||
|
|
||||||
let s = servers::Server::new(servers::ServerConfig {
|
let s = servers::Server::new(servers::ServerConfig {
|
||||||
|
@ -233,9 +234,9 @@ impl LocalServerContainer {
|
||||||
s.start_test_miner(wallet_url, s.stop_state.clone());
|
s.start_test_miner(wallet_url, s.stop_state.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
for p in &mut self.peer_list {
|
for p in &self.peer_list {
|
||||||
println!("{} connecting to peer: {}", self.config.p2p_server_port, p);
|
println!("{} connecting to peer: {}", self.config.p2p_server_port, p);
|
||||||
let _ = s.connect_peer(p.parse().unwrap());
|
let _ = s.connect_peer(PeerAddr(p.parse().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.wallet_is_running {
|
if self.wallet_is_running {
|
||||||
|
@ -647,7 +648,9 @@ pub fn config(n: u16, test_name_dir: &str, seed_n: u16) -> servers::ServerConfig
|
||||||
p2p_config: p2p::P2PConfig {
|
p2p_config: p2p::P2PConfig {
|
||||||
port: 10000 + n,
|
port: 10000 + n,
|
||||||
seeding_type: p2p::Seeding::List,
|
seeding_type: p2p::Seeding::List,
|
||||||
seeds: Some(vec![format!("127.0.0.1:{}", 10000 + seed_n)]),
|
seeds: Some(vec![PeerAddr(
|
||||||
|
format!("127.0.0.1:{}", 10000 + seed_n).parse().unwrap(),
|
||||||
|
)]),
|
||||||
..p2p::P2PConfig::default()
|
..p2p::P2PConfig::default()
|
||||||
},
|
},
|
||||||
chain_type: core::global::ChainTypes::AutomatedTesting,
|
chain_type: core::global::ChainTypes::AutomatedTesting,
|
||||||
|
|
|
@ -19,6 +19,7 @@ mod framework;
|
||||||
|
|
||||||
use self::core::core::hash::Hashed;
|
use self::core::core::hash::Hashed;
|
||||||
use self::core::global::{self, ChainTypes};
|
use self::core::global::{self, ChainTypes};
|
||||||
|
use self::p2p::PeerAddr;
|
||||||
use self::util::{Mutex, StopState};
|
use self::util::{Mutex, StopState};
|
||||||
use self::wallet::controller;
|
use self::wallet::controller;
|
||||||
use self::wallet::libwallet::types::{WalletBackend, WalletInst};
|
use self::wallet::libwallet::types::{WalletBackend, WalletInst};
|
||||||
|
@ -933,7 +934,9 @@ fn replicate_tx_fluff_failure() {
|
||||||
|
|
||||||
// Server 2 (another node)
|
// Server 2 (another node)
|
||||||
let mut s2_config = framework::config(3001, "tx_fluff", 3001);
|
let mut s2_config = framework::config(3001, "tx_fluff", 3001);
|
||||||
s2_config.p2p_config.seeds = Some(vec!["127.0.0.1:13000".to_owned()]);
|
s2_config.p2p_config.seeds = Some(vec![PeerAddr(
|
||||||
|
"127.0.0.1:13000".to_owned().parse().unwrap(),
|
||||||
|
)]);
|
||||||
s2_config.dandelion_config.embargo_secs = Some(10);
|
s2_config.dandelion_config.embargo_secs = Some(10);
|
||||||
s2_config.dandelion_config.patience_secs = Some(1);
|
s2_config.dandelion_config.patience_secs = Some(1);
|
||||||
s2_config.dandelion_config.relay_secs = Some(1);
|
s2_config.dandelion_config.relay_secs = Some(1);
|
||||||
|
@ -944,7 +947,9 @@ fn replicate_tx_fluff_failure() {
|
||||||
for i in 0..dl_nodes {
|
for i in 0..dl_nodes {
|
||||||
// (create some stem nodes)
|
// (create some stem nodes)
|
||||||
let mut s_config = framework::config(3002 + i, "tx_fluff", 3002 + i);
|
let mut s_config = framework::config(3002 + i, "tx_fluff", 3002 + i);
|
||||||
s_config.p2p_config.seeds = Some(vec!["127.0.0.1:13000".to_owned()]);
|
s_config.p2p_config.seeds = Some(vec![PeerAddr(
|
||||||
|
"127.0.0.1:13000".to_owned().parse().unwrap(),
|
||||||
|
)]);
|
||||||
s_config.dandelion_config.embargo_secs = Some(10);
|
s_config.dandelion_config.embargo_secs = Some(10);
|
||||||
s_config.dandelion_config.patience_secs = Some(1);
|
s_config.dandelion_config.patience_secs = Some(1);
|
||||||
s_config.dandelion_config.relay_secs = Some(1);
|
s_config.dandelion_config.relay_secs = Some(1);
|
||||||
|
|
|
@ -24,7 +24,7 @@ use ctrlc;
|
||||||
|
|
||||||
use crate::config::GlobalConfig;
|
use crate::config::GlobalConfig;
|
||||||
use crate::core::global;
|
use crate::core::global;
|
||||||
use crate::p2p::Seeding;
|
use crate::p2p::{PeerAddr, Seeding};
|
||||||
use crate::servers;
|
use crate::servers;
|
||||||
use crate::tui::ui;
|
use crate::tui::ui;
|
||||||
|
|
||||||
|
@ -116,45 +116,15 @@ pub fn server_command(
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(seeds) = a.values_of("seed") {
|
if let Some(seeds) = a.values_of("seed") {
|
||||||
|
let seed_addrs = seeds
|
||||||
|
.filter_map(|x| x.parse().ok())
|
||||||
|
.map(|x| PeerAddr(x))
|
||||||
|
.collect();
|
||||||
server_config.p2p_config.seeding_type = Seeding::List;
|
server_config.p2p_config.seeding_type = Seeding::List;
|
||||||
server_config.p2p_config.seeds = Some(seeds.map(|s| s.to_string()).collect());
|
server_config.p2p_config.seeds = Some(seed_addrs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if let Some(true) = server_config.run_wallet_listener {
|
|
||||||
let mut wallet_config = global_config.members.as_ref().unwrap().wallet.clone();
|
|
||||||
wallet::init_wallet_seed(wallet_config.clone());
|
|
||||||
let wallet = wallet::instantiate_wallet(wallet_config.clone(), "");
|
|
||||||
|
|
||||||
let _ = thread::Builder::new()
|
|
||||||
.name("wallet_listener".to_string())
|
|
||||||
.spawn(move || {
|
|
||||||
controller::foreign_listener(wallet, &wallet_config.api_listen_addr())
|
|
||||||
.unwrap_or_else(|e| {
|
|
||||||
panic!(
|
|
||||||
"Error creating wallet listener: {:?} Config: {:?}",
|
|
||||||
e, wallet_config
|
|
||||||
)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if let Some(true) = server_config.run_wallet_owner_api {
|
|
||||||
let mut wallet_config = global_config.members.unwrap().wallet;
|
|
||||||
let wallet = wallet::instantiate_wallet(wallet_config.clone(), "");
|
|
||||||
wallet::init_wallet_seed(wallet_config.clone());
|
|
||||||
|
|
||||||
let _ = thread::Builder::new()
|
|
||||||
.name("wallet_owner_listener".to_string())
|
|
||||||
.spawn(move || {
|
|
||||||
controller::owner_listener(wallet, "127.0.0.1:13420").unwrap_or_else(|e| {
|
|
||||||
panic!(
|
|
||||||
"Error creating wallet api listener: {:?} Config: {:?}",
|
|
||||||
e, wallet_config
|
|
||||||
)
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if let Some(a) = server_args {
|
if let Some(a) = server_args {
|
||||||
match a.subcommand() {
|
match a.subcommand() {
|
||||||
("run", _) => {
|
("run", _) => {
|
||||||
|
|
Loading…
Reference in a new issue