+mod bloom;
mod printer;
mod reader;
mod peer;
use std::time::{Duration, Instant};
use std::net::{SocketAddr, ToSocketAddrs};
-use bitcoin_hashes::sha256d;
-
use bitcoin::blockdata::block::Block;
use bitcoin::blockdata::constants::genesis_block;
-use bitcoin::network::constants::Network;
+use bitcoin::hash_types::{BlockHash};
+use bitcoin::network::constants::{Network, ServiceFlags};
use bitcoin::network::message::NetworkMessage;
-use bitcoin::network::message_blockdata::{GetHeadersMessage, Inventory, InvType};
-use bitcoin::util::hash::BitcoinHash;
+use bitcoin::network::message_blockdata::{GetHeadersMessage, Inventory};
+//use bitcoin::util::hash::BitcoinHash;
use printer::{Printer, Stat};
use peer::Peer;
use tokio::prelude::*;
use tokio::timer::Delay;
-static mut REQUEST_BLOCK: Option<Box<Mutex<Arc<(u64, sha256d::Hash, Block)>>>> = None;
-static mut HIGHEST_HEADER: Option<Box<Mutex<(sha256d::Hash, u64)>>> = None;
-static mut HEADER_MAP: Option<Box<Mutex<HashMap<sha256d::Hash, u64>>>> = None;
-static mut HEIGHT_MAP: Option<Box<Mutex<HashMap<u64, sha256d::Hash>>>> = None;
+static mut REQUEST_BLOCK: Option<Box<Mutex<Arc<(u64, BlockHash, Block)>>>> = None;
+static mut HIGHEST_HEADER: Option<Box<Mutex<(BlockHash, u64)>>> = None;
+static mut HEADER_MAP: Option<Box<Mutex<HashMap<BlockHash, u64>>>> = None;
+static mut HEIGHT_MAP: Option<Box<Mutex<HashMap<u64, BlockHash>>>> = None;
static mut DATA_STORE: Option<Box<Store>> = None;
static mut PRINTER: Option<Box<Printer>> = None;
static mut TOR_PROXY: Option<SocketAddr> = None;
static SCANNING: AtomicBool = AtomicBool::new(false);
struct PeerState {
- request: Arc<(u64, sha256d::Hash, Block)>,
+ request: Arc<(u64, BlockHash, Block)>,
+ pong_nonce: u64,
node_services: u64,
msg: (String, bool),
fail_reason: AddressState,
recvd_pong: bool,
recvd_addrs: bool,
recvd_block: bool,
- pong_nonce: u64,
}
pub fn scan_node(scan_time: Instant, node: SocketAddr, manual: bool) {
Peer::new(node.clone(), unsafe { TOR_PROXY.as_ref().unwrap() }, Duration::from_secs(timeout), printer)
});
tokio::spawn(peer.and_then(move |(mut write, read)| {
- TimeoutStream::new_timeout(read, scan_time + Duration::from_secs(store.get_u64(U64Setting::RunTimeout))).map_err(move |err| {
- match err {
- bitcoin::consensus::encode::Error::UnrecognizedNetworkCommand(ref msg) => {
- // If we got here, we hit one of the explicitly disallowed messages indicating
- // a bogus "node".
- let mut state_lock = err_peer_state.lock().unwrap();
- state_lock.msg = (format!("(bad msg type {})", msg), true);
- state_lock.fail_reason = AddressState::EvilNode;
- },
- _ => {},
- }
- ()
- }).for_each(move |msg| {
+ TimeoutStream::new_timeout(read, scan_time + Duration::from_secs(store.get_u64(U64Setting::RunTimeout)))
+ .map_err(|_| ()).for_each(move |msg| {
let mut state_lock = peer_state.lock().unwrap();
macro_rules! check_set_flag {
($recvd_flag: ident, $msg: expr) => { {
state_lock.fail_reason = AddressState::LowVersion;
return future::err(());
}
- if ver.services & (1 | (1 << 10)) == 0 {
+ if !ver.services.has(ServiceFlags::NETWORK) && !ver.services.has(ServiceFlags::NETWORK_LIMITED) {
state_lock.msg = (format!("({}: services {:x})", safe_ua, ver.services), true);
state_lock.fail_reason = AddressState::NotFullNode;
return future::err(());
return future::err(());
}
check_set_flag!(recvd_version, "version");
- state_lock.node_services = ver.services;
+ state_lock.node_services = ver.services.as_u64();
state_lock.msg = (format!("(subver: {})", safe_ua), false);
+ if let Err(_) = write.try_send(NetworkMessage::SendAddrV2) {
+ return future::err(());
+ }
if let Err(_) = write.try_send(NetworkMessage::Verack) {
return future::err(());
}
}
if addrs.len() > 10 {
if !state_lock.recvd_addrs {
- if let Err(_) = write.try_send(NetworkMessage::GetData(vec![Inventory {
- inv_type: InvType::WitnessBlock,
- hash: state_lock.request.1,
- }])) {
+ if let Err(_) = write.try_send(NetworkMessage::GetData(vec![Inventory::WitnessBlock(state_lock.request.1)])) {
return future::err(());
}
}
}
unsafe { DATA_STORE.as_ref().unwrap() }.add_fresh_nodes(&addrs);
},
+ Some(NetworkMessage::AddrV2(addrs)) => {
+ if addrs.len() > 1000 {
+ state_lock.fail_reason = AddressState::ProtocolViolation;
+ state_lock.msg = (format!("due to oversized addr: {}", addrs.len()), true);
+ state_lock.recvd_addrs = false;
+ return future::err(());
+ }
+ if addrs.len() > 10 {
+ if !state_lock.recvd_addrs {
+ if let Err(_) = write.try_send(NetworkMessage::GetData(vec![Inventory::WitnessBlock(state_lock.request.1)])) {
+ return future::err(());
+ }
+ }
+ state_lock.recvd_addrs = true;
+ }
+ unsafe { DATA_STORE.as_ref().unwrap() }.add_fresh_nodes_v2(&addrs);
+ },
Some(NetworkMessage::Block(block)) => {
if block != state_lock.request.2 {
state_lock.fail_reason = AddressState::ProtocolViolation;
},
Some(NetworkMessage::Inv(invs)) => {
for inv in invs {
- if inv.inv_type == InvType::Transaction {
- state_lock.fail_reason = AddressState::EvilNode;
- state_lock.msg = ("due to unrequested inv tx".to_string(), true);
- return future::err(());
+ match inv {
+ Inventory::Transaction(_) | Inventory::WitnessTransaction(_) => {
+ state_lock.fail_reason = AddressState::EvilNode;
+ state_lock.msg = ("due to unrequested inv tx".to_string(), true);
+ return future::err(());
+ }
+ _ => {},
}
}
},
state_lock.msg = ("due to unrequested transaction".to_string(), true);
return future::err(());
},
+ Some(NetworkMessage::Unknown { command, .. }) => {
+ if command.as_ref() == "gnop" {
+ let mut state_lock = err_peer_state.lock().unwrap();
+ state_lock.msg = (format!("(bad msg type {})", command), true);
+ state_lock.fail_reason = AddressState::EvilNode;
+ return future::err(());
+ }
+ },
_ => {},
}
future::ok(())
if let Some(height) = header_map.get(&headers[0].prev_blockhash).cloned() {
for i in 0..headers.len() {
- let hash = headers[i].bitcoin_hash();
+ let hash = headers[i].block_hash();
if i < headers.len() - 1 && headers[i + 1].prev_blockhash != hash {
return future::err(());
}
- header_map.insert(headers[i].bitcoin_hash(), height + 1 + (i as u64));
- height_map.insert(height + 1 + (i as u64), headers[i].bitcoin_hash());
+ header_map.insert(headers[i].block_hash(), height + 1 + (i as u64));
+ height_map.insert(height + 1 + (i as u64), headers[i].block_hash());
}
let top_height = height + headers.len() as u64;
*unsafe { HIGHEST_HEADER.as_ref().unwrap() }.lock().unwrap()
- = (headers.last().unwrap().bitcoin_hash(), top_height);
+ = (headers.last().unwrap().block_hash(), top_height);
printer.set_stat(printer::Stat::HeaderCount(top_height));
if top_height >= starting_height as u64 {
- if let Err(_) = trusted_write.try_send(NetworkMessage::GetData(vec![Inventory {
- inv_type: InvType::WitnessBlock,
- hash: height_map.get(&(top_height - 216)).unwrap().clone(),
- }])) {
+ if let Err(_) = trusted_write.try_send(NetworkMessage::GetData(vec![
+ Inventory::WitnessBlock(height_map.get(&(top_height - 216)).unwrap().clone())
+ ])) {
return future::err(());
}
}
}
},
Some(NetworkMessage::Block(block)) => {
- let hash = block.header.bitcoin_hash();
+ let hash = block.block_hash();
let header_map = unsafe { HEADER_MAP.as_ref().unwrap() }.lock().unwrap();
let height = *header_map.get(&hash).expect("Got loose block from trusted peer we coulnd't have requested");
if height == unsafe { HIGHEST_HEADER.as_ref().unwrap() }.lock().unwrap().1 - 216 {
}
fn main() {
- if env::args().len() != 5 {
- println!("USAGE: dnsseed-rust datastore localPeerAddress tor_proxy_addr bgp_peer");
+ if env::args().len() != 6 {
+ println!("USAGE: dnsseed-rust datastore localPeerAddress tor_proxy_addr bgp_peer bgp_peer_asn");
return;
}
unsafe { HEADER_MAP = Some(Box::new(Mutex::new(HashMap::with_capacity(600000)))) };
unsafe { HEIGHT_MAP = Some(Box::new(Mutex::new(HashMap::with_capacity(600000)))) };
- unsafe { HEADER_MAP.as_ref().unwrap() }.lock().unwrap().insert(genesis_block(Network::Bitcoin).bitcoin_hash(), 0);
- unsafe { HEIGHT_MAP.as_ref().unwrap() }.lock().unwrap().insert(0, genesis_block(Network::Bitcoin).bitcoin_hash());
- unsafe { HIGHEST_HEADER = Some(Box::new(Mutex::new((genesis_block(Network::Bitcoin).bitcoin_hash(), 0)))) };
- unsafe { REQUEST_BLOCK = Some(Box::new(Mutex::new(Arc::new((0, genesis_block(Network::Bitcoin).bitcoin_hash(), genesis_block(Network::Bitcoin)))))) };
+ unsafe { HEADER_MAP.as_ref().unwrap() }.lock().unwrap().insert(genesis_block(Network::Bitcoin).block_hash(), 0);
+ unsafe { HEIGHT_MAP.as_ref().unwrap() }.lock().unwrap().insert(0, genesis_block(Network::Bitcoin).block_hash());
+ unsafe { HIGHEST_HEADER = Some(Box::new(Mutex::new((genesis_block(Network::Bitcoin).block_hash(), 0)))) };
+ unsafe { REQUEST_BLOCK = Some(Box::new(Mutex::new(Arc::new((0, genesis_block(Network::Bitcoin).block_hash(), genesis_block(Network::Bitcoin)))))) };
let trt = tokio::runtime::Builder::new()
- .blocking_threads(2).core_threads(num_cpus::get().max(1) * 3)
+ .blocking_threads(2).core_threads(num_cpus::get().max(1) + 1)
.build().unwrap();
let _ = trt.block_on_all(future::lazy(|| {
unsafe { TOR_PROXY = Some(tor_socks5_sockaddr); }
let bgp_sockaddr: SocketAddr = args.next().unwrap().parse().unwrap();
+ let bgp_peerasn: u32 = args.next().unwrap().parse().unwrap();
Store::new(path).and_then(move |store| {
unsafe { DATA_STORE = Some(Box::new(store)) };
let store = unsafe { DATA_STORE.as_ref().unwrap() };
unsafe { PRINTER = Some(Box::new(Printer::new(store))) };
- let bgp_client = BGPClient::new(bgp_sockaddr, Duration::from_secs(60), unsafe { PRINTER.as_ref().unwrap() });
+ let bgp_client = BGPClient::new(bgp_peerasn, bgp_sockaddr, Duration::from_secs(60), unsafe { PRINTER.as_ref().unwrap() });
make_trusted_conn(trusted_sockaddr, Arc::clone(&bgp_client));
reader::read(store, unsafe { PRINTER.as_ref().unwrap() }, bgp_client);