fix #1079
* move gossip/NCP off assuming anything about its address * use a single socket to send and receive gossip * remove --addr/-a from CLIs * rearrange networking utility code * use Arc<UdpSocket> to share the Sync-safe UdpSocket among threads * rename TestNode to Node TODO: * re-enable 127.0.0.1 as a valid address in crdt * change repair request/response to a similar, single socket * pick cloned sockets or Arc<UdpSocket> for all these (rpu uses tryclone()) * update contact_info with network truthiness instead of what the node says?
This commit is contained in:
@ -71,7 +71,7 @@ echo "--- Wallet sanity"
|
|||||||
echo "--- Node count"
|
echo "--- Node count"
|
||||||
(
|
(
|
||||||
set -x
|
set -x
|
||||||
./multinode-demo/client.sh "$PWD" 3 -c --addr 127.0.0.1
|
./multinode-demo/client.sh "$PWD" 3 -c
|
||||||
) || flag_error
|
) || flag_error
|
||||||
|
|
||||||
killBackgroundCommands
|
killBackgroundCommands
|
||||||
|
@ -47,4 +47,4 @@ fi
|
|||||||
|
|
||||||
# shellcheck disable=SC2086 # $solana_wallet should not be quoted
|
# shellcheck disable=SC2086 # $solana_wallet should not be quoted
|
||||||
exec $solana_wallet \
|
exec $solana_wallet \
|
||||||
-a 127.0.0.1 -l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -k "$client_id_path" --timeout 10 "$@"
|
-l "$SOLANA_CONFIG_CLIENT_DIR"/leader.json -k "$client_id_path" --timeout 10 "$@"
|
||||||
|
@ -63,7 +63,12 @@ fn main() -> Result<()> {
|
|||||||
let pack_recycler = PacketRecycler::default();
|
let pack_recycler = PacketRecycler::default();
|
||||||
|
|
||||||
let (s_reader, r_reader) = channel();
|
let (s_reader, r_reader) = channel();
|
||||||
let t_reader = receiver(read, exit.clone(), pack_recycler.clone(), s_reader);
|
let t_reader = receiver(
|
||||||
|
Arc::new(read),
|
||||||
|
exit.clone(),
|
||||||
|
pack_recycler.clone(),
|
||||||
|
s_reader,
|
||||||
|
);
|
||||||
let t_producer1 = producer(&addr, &pack_recycler, exit.clone());
|
let t_producer1 = producer(&addr, &pack_recycler, exit.clone());
|
||||||
let t_producer2 = producer(&addr, &pack_recycler, exit.clone());
|
let t_producer2 = producer(&addr, &pack_recycler, exit.clone());
|
||||||
let t_producer3 = producer(&addr, &pack_recycler, exit.clone());
|
let t_producer3 = producer(&addr, &pack_recycler, exit.clone());
|
||||||
|
@ -16,7 +16,6 @@ use solana::fullnode::Config;
|
|||||||
use solana::hash::Hash;
|
use solana::hash::Hash;
|
||||||
use solana::logger;
|
use solana::logger;
|
||||||
use solana::metrics;
|
use solana::metrics;
|
||||||
use solana::nat::get_public_ip_addr;
|
|
||||||
use solana::ncp::Ncp;
|
use solana::ncp::Ncp;
|
||||||
use solana::service::Service;
|
use solana::service::Service;
|
||||||
use solana::signature::{read_keypair, GenKeys, Keypair, KeypairUtil};
|
use solana::signature::{read_keypair, GenKeys, Keypair, KeypairUtil};
|
||||||
@ -440,14 +439,6 @@ fn main() {
|
|||||||
.short("c")
|
.short("c")
|
||||||
.help("exit immediately after converging"),
|
.help("exit immediately after converging"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("addr")
|
|
||||||
.short("a")
|
|
||||||
.long("addr")
|
|
||||||
.value_name("IPADDR")
|
|
||||||
.takes_value(true)
|
|
||||||
.help("address to advertise to the network"),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("sustained")
|
Arg::with_name("sustained")
|
||||||
.long("sustained")
|
.long("sustained")
|
||||||
@ -484,18 +475,6 @@ fn main() {
|
|||||||
time_sec = s.to_string().parse().expect("integer");
|
time_sec = s.to_string().parse().expect("integer");
|
||||||
}
|
}
|
||||||
|
|
||||||
let addr = if let Some(s) = matches.value_of("addr") {
|
|
||||||
s.to_string().parse().unwrap_or_else(|e| {
|
|
||||||
eprintln!("failed to parse {} as IP address error: {:?}", s, e);
|
|
||||||
exit(1);
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
get_public_ip_addr().unwrap_or_else(|e| {
|
|
||||||
eprintln!("failed to get public IP, try --addr? error: {:?}", e);
|
|
||||||
exit(1);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(s) = matches.value_of("tx_count") {
|
if let Some(s) = matches.value_of("tx_count") {
|
||||||
tx_count = s.to_string().parse().expect("integer");
|
tx_count = s.to_string().parse().expect("integer");
|
||||||
}
|
}
|
||||||
@ -506,7 +485,7 @@ fn main() {
|
|||||||
|
|
||||||
let exit_signal = Arc::new(AtomicBool::new(false));
|
let exit_signal = Arc::new(AtomicBool::new(false));
|
||||||
let mut c_threads = vec![];
|
let mut c_threads = vec![];
|
||||||
let (validators, leader) = converge(&leader, &exit_signal, num_nodes, &mut c_threads, addr);
|
let (validators, leader) = converge(&leader, &exit_signal, num_nodes, &mut c_threads);
|
||||||
|
|
||||||
println!(" Node address | Node identifier");
|
println!(" Node address | Node identifier");
|
||||||
println!("----------------------+------------------");
|
println!("----------------------+------------------");
|
||||||
@ -672,10 +651,9 @@ fn converge(
|
|||||||
exit_signal: &Arc<AtomicBool>,
|
exit_signal: &Arc<AtomicBool>,
|
||||||
num_nodes: usize,
|
num_nodes: usize,
|
||||||
threads: &mut Vec<JoinHandle<()>>,
|
threads: &mut Vec<JoinHandle<()>>,
|
||||||
addr: IpAddr,
|
|
||||||
) -> (Vec<NodeInfo>, Option<NodeInfo>) {
|
) -> (Vec<NodeInfo>, Option<NodeInfo>) {
|
||||||
//lets spy on the network
|
//lets spy on the network
|
||||||
let (node, gossip_socket, gossip_send_socket) = Crdt::spy_node(addr);
|
let (node, gossip_socket) = Crdt::spy_node();
|
||||||
let mut spy_crdt = Crdt::new(node).expect("Crdt::new");
|
let mut spy_crdt = Crdt::new(node).expect("Crdt::new");
|
||||||
spy_crdt.insert(&leader);
|
spy_crdt.insert(&leader);
|
||||||
spy_crdt.set_leader(leader.id);
|
spy_crdt.set_leader(leader.id);
|
||||||
@ -686,7 +664,6 @@ fn converge(
|
|||||||
window.clone(),
|
window.clone(),
|
||||||
None,
|
None,
|
||||||
gossip_socket,
|
gossip_socket,
|
||||||
gossip_send_socket,
|
|
||||||
exit_signal.clone(),
|
exit_signal.clone(),
|
||||||
).expect("DataReplicator::new");
|
).expect("DataReplicator::new");
|
||||||
let mut v: Vec<NodeInfo> = vec![];
|
let mut v: Vec<NodeInfo> = vec![];
|
||||||
|
@ -15,14 +15,12 @@ use solana::drone::{Drone, DroneRequest, DRONE_PORT};
|
|||||||
use solana::fullnode::Config;
|
use solana::fullnode::Config;
|
||||||
use solana::logger;
|
use solana::logger;
|
||||||
use solana::metrics::set_panic_hook;
|
use solana::metrics::set_panic_hook;
|
||||||
use solana::nat::get_public_ip_addr;
|
|
||||||
use solana::signature::read_keypair;
|
use solana::signature::read_keypair;
|
||||||
use solana::thin_client::poll_gossip_for_leader;
|
use solana::thin_client::poll_gossip_for_leader;
|
||||||
use std::error;
|
use std::error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use std::process::exit;
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
@ -72,28 +70,8 @@ fn main() -> Result<(), Box<error::Error>> {
|
|||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.help("Max SECONDS to wait to get necessary gossip from the network"),
|
.help("Max SECONDS to wait to get necessary gossip from the network"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("addr")
|
|
||||||
.short("a")
|
|
||||||
.long("addr")
|
|
||||||
.value_name("IPADDR")
|
|
||||||
.takes_value(true)
|
|
||||||
.help("address to advertise to the network"),
|
|
||||||
)
|
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let addr = if let Some(s) = matches.value_of("addr") {
|
|
||||||
s.to_string().parse().unwrap_or_else(|e| {
|
|
||||||
eprintln!("failed to parse {} as IP address error: {:?}", s, e);
|
|
||||||
exit(1);
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
get_public_ip_addr().unwrap_or_else(|e| {
|
|
||||||
eprintln!("failed to get public IP, try --addr? error: {:?}", e);
|
|
||||||
exit(1);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let leader: NodeInfo;
|
let leader: NodeInfo;
|
||||||
if let Some(l) = matches.value_of("leader") {
|
if let Some(l) = matches.value_of("leader") {
|
||||||
leader = read_leader(l).node_info;
|
leader = read_leader(l).node_info;
|
||||||
@ -124,9 +102,11 @@ fn main() -> Result<(), Box<error::Error>> {
|
|||||||
timeout = None;
|
timeout = None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let leader = poll_gossip_for_leader(leader.contact_info.ncp, timeout, addr)?;
|
eprintln!("hioisdlflkj");
|
||||||
|
|
||||||
let drone_addr: SocketAddr = format!("0.0.0.0:{}", DRONE_PORT).parse().unwrap();
|
let drone_addr: SocketAddr = format!("0.0.0.0:{}", DRONE_PORT).parse().unwrap();
|
||||||
|
let socket = TcpListener::bind(&drone_addr).unwrap();
|
||||||
|
|
||||||
|
let leader = poll_gossip_for_leader(leader.contact_info.ncp, timeout)?;
|
||||||
|
|
||||||
let drone = Arc::new(Mutex::new(Drone::new(
|
let drone = Arc::new(Mutex::new(Drone::new(
|
||||||
mint_keypair,
|
mint_keypair,
|
||||||
@ -144,7 +124,6 @@ fn main() -> Result<(), Box<error::Error>> {
|
|||||||
drone1.lock().unwrap().clear_request_count();
|
drone1.lock().unwrap().clear_request_count();
|
||||||
});
|
});
|
||||||
|
|
||||||
let socket = TcpListener::bind(&drone_addr).unwrap();
|
|
||||||
println!("Drone started. Listening on: {}", drone_addr);
|
println!("Drone started. Listening on: {}", drone_addr);
|
||||||
let done = socket
|
let done = socket
|
||||||
.incoming()
|
.incoming()
|
||||||
|
@ -5,9 +5,9 @@ extern crate serde_json;
|
|||||||
extern crate solana;
|
extern crate solana;
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use solana::crdt::{get_ip_addr, parse_port_or_addr};
|
use solana::crdt::GOSSIP_PORT_RANGE;
|
||||||
use solana::fullnode::Config;
|
use solana::fullnode::Config;
|
||||||
use solana::nat::get_public_ip_addr;
|
use solana::nat::{get_ip_addr, get_public_ip_addr, parse_port_or_addr};
|
||||||
use solana::signature::read_pkcs8;
|
use solana::signature::read_pkcs8;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@ -48,13 +48,7 @@ fn main() {
|
|||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let bind_addr: SocketAddr = {
|
let bind_addr: SocketAddr = {
|
||||||
let mut bind_addr = parse_port_or_addr({
|
let mut bind_addr = parse_port_or_addr(matches.value_of("bind"), GOSSIP_PORT_RANGE.0);
|
||||||
if let Some(b) = matches.value_of("bind") {
|
|
||||||
Some(b.to_string())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if matches.is_present("local") {
|
if matches.is_present("local") {
|
||||||
let ip = get_ip_addr().unwrap();
|
let ip = get_ip_addr().unwrap();
|
||||||
bind_addr.set_ip(ip);
|
bind_addr.set_ip(ip);
|
||||||
|
@ -7,7 +7,7 @@ extern crate solana;
|
|||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use solana::client::mk_client;
|
use solana::client::mk_client;
|
||||||
use solana::crdt::{NodeInfo, TestNode};
|
use solana::crdt::{Node, NodeInfo};
|
||||||
use solana::drone::DRONE_PORT;
|
use solana::drone::DRONE_PORT;
|
||||||
use solana::fullnode::{Config, Fullnode};
|
use solana::fullnode::{Config, Fullnode};
|
||||||
use solana::logger;
|
use solana::logger;
|
||||||
@ -78,14 +78,14 @@ fn main() -> () {
|
|||||||
|
|
||||||
let port_range = (8100, 10000);
|
let port_range = (8100, 10000);
|
||||||
let node = if let Some(_t) = matches.value_of("testnet") {
|
let node = if let Some(_t) = matches.value_of("testnet") {
|
||||||
TestNode::new_with_external_ip(
|
Node::new_with_external_ip(
|
||||||
leader_pubkey,
|
leader_pubkey,
|
||||||
repl_data.contact_info.ncp.ip(),
|
repl_data.contact_info.ncp.ip(),
|
||||||
port_range,
|
port_range,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
TestNode::new_with_external_ip(
|
Node::new_with_external_ip(
|
||||||
leader_pubkey,
|
leader_pubkey,
|
||||||
repl_data.contact_info.ncp.ip(),
|
repl_data.contact_info.ncp.ip(),
|
||||||
port_range,
|
port_range,
|
||||||
|
@ -13,7 +13,6 @@ use solana::crdt::NodeInfo;
|
|||||||
use solana::drone::DRONE_PORT;
|
use solana::drone::DRONE_PORT;
|
||||||
use solana::fullnode::Config;
|
use solana::fullnode::Config;
|
||||||
use solana::logger;
|
use solana::logger;
|
||||||
use solana::nat::get_public_ip_addr;
|
|
||||||
use solana::signature::{read_keypair, Keypair, KeypairUtil, Pubkey, Signature};
|
use solana::signature::{read_keypair, Keypair, KeypairUtil, Pubkey, Signature};
|
||||||
use solana::thin_client::{poll_gossip_for_leader, ThinClient};
|
use solana::thin_client::{poll_gossip_for_leader, ThinClient};
|
||||||
use solana::wallet::request_airdrop;
|
use solana::wallet::request_airdrop;
|
||||||
@ -21,7 +20,6 @@ use std::error;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||||
use std::process::exit;
|
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
@ -94,14 +92,6 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
|
|||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.help("/path/to/id.json"),
|
.help("/path/to/id.json"),
|
||||||
)
|
)
|
||||||
.arg(
|
|
||||||
Arg::with_name("addr")
|
|
||||||
.short("a")
|
|
||||||
.long("addr")
|
|
||||||
.value_name("IPADDR")
|
|
||||||
.takes_value(true)
|
|
||||||
.help("address to advertise to the network"),
|
|
||||||
)
|
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name("timeout")
|
Arg::with_name("timeout")
|
||||||
.long("timeout")
|
.long("timeout")
|
||||||
@ -155,18 +145,6 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
|
|||||||
.subcommand(SubCommand::with_name("address").about("Get your public key"))
|
.subcommand(SubCommand::with_name("address").about("Get your public key"))
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
let addr = if let Some(s) = matches.value_of("addr") {
|
|
||||||
s.to_string().parse().unwrap_or_else(|e| {
|
|
||||||
eprintln!("failed to parse {} as IP address error: {:?}", s, e);
|
|
||||||
exit(1)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
get_public_ip_addr().unwrap_or_else(|e| {
|
|
||||||
eprintln!("failed to get public IP, try --addr? error: {:?}", e);
|
|
||||||
exit(1)
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
let leader: NodeInfo;
|
let leader: NodeInfo;
|
||||||
if let Some(l) = matches.value_of("leader") {
|
if let Some(l) = matches.value_of("leader") {
|
||||||
leader = read_leader(l)?.node_info;
|
leader = read_leader(l)?.node_info;
|
||||||
@ -195,7 +173,7 @@ fn parse_args() -> Result<WalletConfig, Box<error::Error>> {
|
|||||||
)))
|
)))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let leader = poll_gossip_for_leader(leader.contact_info.ncp, timeout, addr)?;
|
let leader = poll_gossip_for_leader(leader.contact_info.ncp, timeout)?;
|
||||||
|
|
||||||
let mut drone_addr = leader.contact_info.tpu;
|
let mut drone_addr = leader.contact_info.tpu;
|
||||||
drone_addr.set_port(DRONE_PORT);
|
drone_addr.set_port(DRONE_PORT);
|
||||||
|
@ -16,31 +16,27 @@ pub struct BlobFetchStage {
|
|||||||
|
|
||||||
impl BlobFetchStage {
|
impl BlobFetchStage {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
socket: UdpSocket,
|
socket: Arc<UdpSocket>,
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
blob_recycler: &BlobRecycler,
|
recycler: &BlobRecycler,
|
||||||
) -> (Self, BlobReceiver) {
|
) -> (Self, BlobReceiver) {
|
||||||
Self::new_multi_socket(vec![socket], exit, blob_recycler)
|
Self::new_multi_socket(vec![socket], exit, recycler)
|
||||||
}
|
}
|
||||||
pub fn new_multi_socket(
|
pub fn new_multi_socket(
|
||||||
sockets: Vec<UdpSocket>,
|
sockets: Vec<Arc<UdpSocket>>,
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
blob_recycler: &BlobRecycler,
|
recycler: &BlobRecycler,
|
||||||
) -> (Self, BlobReceiver) {
|
) -> (Self, BlobReceiver) {
|
||||||
let (blob_sender, blob_receiver) = channel();
|
let (sender, receiver) = channel();
|
||||||
let thread_hdls: Vec<_> = sockets
|
let thread_hdls: Vec<_> = sockets
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|socket| {
|
.map(|socket| {
|
||||||
streamer::blob_receiver(
|
streamer::blob_receiver(socket, exit.clone(), recycler.clone(), sender.clone())
|
||||||
exit.clone(),
|
.expect("blob receiver init")
|
||||||
blob_recycler.clone(),
|
|
||||||
socket,
|
|
||||||
blob_sender.clone(),
|
|
||||||
).expect("blob receiver init")
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
(BlobFetchStage { exit, thread_hdls }, blob_receiver)
|
(BlobFetchStage { exit, thread_hdls }, receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&self) {
|
pub fn close(&self) {
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use crdt::NodeInfo;
|
use crdt::{NodeInfo, GOSSIP_PORT_RANGE};
|
||||||
use nat::udp_random_bind;
|
use nat::bind_in_range;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use thin_client::ThinClient;
|
use thin_client::ThinClient;
|
||||||
|
|
||||||
pub fn mk_client(r: &NodeInfo) -> ThinClient {
|
pub fn mk_client(r: &NodeInfo) -> ThinClient {
|
||||||
let requests_socket = udp_random_bind(8000, 10000, 5).unwrap();
|
let requests_socket = bind_in_range(GOSSIP_PORT_RANGE).unwrap();
|
||||||
let transactions_socket = udp_random_bind(8000, 10000, 5).unwrap();
|
let transactions_socket = bind_in_range(GOSSIP_PORT_RANGE).unwrap();
|
||||||
|
|
||||||
requests_socket
|
requests_socket
|
||||||
.set_read_timeout(Some(Duration::new(1, 0)))
|
.set_read_timeout(Some(Duration::new(1, 0)))
|
||||||
|
218
src/crdt.rs
218
src/crdt.rs
@ -20,10 +20,9 @@ use counter::Counter;
|
|||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
use ledger::LedgerWindow;
|
use ledger::LedgerWindow;
|
||||||
use log::Level;
|
use log::Level;
|
||||||
use nat::udp_random_bind;
|
use nat::bind_in_range;
|
||||||
use packet::{to_blob, Blob, BlobRecycler, SharedBlob, BLOB_SIZE};
|
use packet::{to_blob, Blob, BlobRecycler, SharedBlob, BLOB_SIZE};
|
||||||
use pnet_datalink as datalink;
|
use rand::{thread_rng, Rng};
|
||||||
use rand::{thread_rng, RngCore};
|
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use result::{Error, Result};
|
use result::{Error, Result};
|
||||||
use signature::{Keypair, KeypairUtil, Pubkey};
|
use signature::{Keypair, KeypairUtil, Pubkey};
|
||||||
@ -41,6 +40,7 @@ use timing::{duration_as_ms, timestamp};
|
|||||||
use transaction::Vote;
|
use transaction::Vote;
|
||||||
use window::{SharedWindow, WindowIndex};
|
use window::{SharedWindow, WindowIndex};
|
||||||
|
|
||||||
|
pub const GOSSIP_PORT_RANGE: (u16, u16) = (8000, 10_000);
|
||||||
/// milliseconds we sleep for between gossip requests
|
/// milliseconds we sleep for between gossip requests
|
||||||
const GOSSIP_SLEEP_MILLIS: u64 = 100;
|
const GOSSIP_SLEEP_MILLIS: u64 = 100;
|
||||||
const GOSSIP_PURGE_MILLIS: u64 = 15000;
|
const GOSSIP_PURGE_MILLIS: u64 = 15000;
|
||||||
@ -57,47 +57,6 @@ pub enum CrdtError {
|
|||||||
BadGossipAddress,
|
BadGossipAddress,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_port_or_addr(optstr: Option<String>) -> SocketAddr {
|
|
||||||
let daddr: SocketAddr = "0.0.0.0:8000".parse().expect("default socket address");
|
|
||||||
if let Some(addrstr) = optstr {
|
|
||||||
if let Ok(port) = addrstr.parse() {
|
|
||||||
let mut addr = daddr;
|
|
||||||
addr.set_port(port);
|
|
||||||
addr
|
|
||||||
} else if let Ok(addr) = addrstr.parse() {
|
|
||||||
addr
|
|
||||||
} else {
|
|
||||||
daddr
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
daddr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_ip_addr() -> Option<IpAddr> {
|
|
||||||
for iface in datalink::interfaces() {
|
|
||||||
for p in iface.ips {
|
|
||||||
if !p.ip().is_loopback() && !p.ip().is_multicast() {
|
|
||||||
match p.ip() {
|
|
||||||
IpAddr::V4(addr) => {
|
|
||||||
if !addr.is_link_local() {
|
|
||||||
return Some(p.ip());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
IpAddr::V6(_addr) => {
|
|
||||||
// Select an ipv6 address if the config is selected
|
|
||||||
#[cfg(feature = "ipv6")]
|
|
||||||
{
|
|
||||||
return Some(p.ip());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Structure to be replicated by the network
|
/// Structure to be replicated by the network
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
|
||||||
pub struct ContactInfo {
|
pub struct ContactInfo {
|
||||||
@ -529,9 +488,10 @@ impl Crdt {
|
|||||||
false
|
false
|
||||||
} else if !(Self::is_valid_address(v.contact_info.tvu)) {
|
} else if !(Self::is_valid_address(v.contact_info.tvu)) {
|
||||||
trace!(
|
trace!(
|
||||||
"{:x}:broadcast skip not listening {:x}",
|
"{:x}:broadcast skip not listening {:x} {}",
|
||||||
me.debug_id(),
|
me.debug_id(),
|
||||||
v.debug_id()
|
v.debug_id(),
|
||||||
|
v.contact_info.tvu,
|
||||||
);
|
);
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
@ -552,6 +512,7 @@ impl Crdt {
|
|||||||
/// broadcast messages from the leader to layer 1 nodes
|
/// broadcast messages from the leader to layer 1 nodes
|
||||||
/// # Remarks
|
/// # Remarks
|
||||||
/// We need to avoid having obj locked while doing any io, such as the `send_to`
|
/// We need to avoid having obj locked while doing any io, such as the `send_to`
|
||||||
|
/// TODO: move me out of crdt
|
||||||
pub fn broadcast(
|
pub fn broadcast(
|
||||||
me: &NodeInfo,
|
me: &NodeInfo,
|
||||||
broadcast_table: &[NodeInfo],
|
broadcast_table: &[NodeInfo],
|
||||||
@ -670,6 +631,7 @@ impl Crdt {
|
|||||||
/// retransmit messages from the leader to layer 1 nodes
|
/// retransmit messages from the leader to layer 1 nodes
|
||||||
/// # Remarks
|
/// # Remarks
|
||||||
/// We need to avoid having obj locked while doing any io, such as the `send_to`
|
/// We need to avoid having obj locked while doing any io, such as the `send_to`
|
||||||
|
/// TODO: move me out of Crdt
|
||||||
pub fn retransmit(obj: &Arc<RwLock<Self>>, blob: &SharedBlob, s: &UdpSocket) -> Result<()> {
|
pub fn retransmit(obj: &Arc<RwLock<Self>>, blob: &SharedBlob, s: &UdpSocket) -> Result<()> {
|
||||||
let (me, table): (NodeInfo, Vec<NodeInfo>) = {
|
let (me, table): (NodeInfo, Vec<NodeInfo>) = {
|
||||||
// copy to avoid locking during IO
|
// copy to avoid locking during IO
|
||||||
@ -685,12 +647,17 @@ impl Crdt {
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|v| {
|
.filter(|v| {
|
||||||
if me.id == v.id {
|
if me.id == v.id {
|
||||||
|
trace!("skip retransmit to self {:?}", v.id);
|
||||||
false
|
false
|
||||||
} else if me.leader_id == v.id {
|
} else if me.leader_id == v.id {
|
||||||
trace!("skip retransmit to leader {:?}", v.id);
|
trace!("skip retransmit to leader {:?}", v.id);
|
||||||
false
|
false
|
||||||
} else if !(Self::is_valid_address(v.contact_info.tvu)) {
|
} else if !(Self::is_valid_address(v.contact_info.tvu)) {
|
||||||
trace!("skip nodes that are not listening {:?}", v.id);
|
trace!(
|
||||||
|
"skip nodes that are not listening {:?} {}",
|
||||||
|
v.id,
|
||||||
|
v.contact_info.tvu
|
||||||
|
);
|
||||||
false
|
false
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
@ -702,10 +669,11 @@ impl Crdt {
|
|||||||
.par_iter()
|
.par_iter()
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
debug!(
|
debug!(
|
||||||
"{:x}: retransmit blob {} to {:x}",
|
"{:x}: retransmit blob {} to {:x} {}",
|
||||||
me.debug_id(),
|
me.debug_id(),
|
||||||
rblob.get_index().unwrap(),
|
rblob.get_index().unwrap(),
|
||||||
v.debug_id(),
|
v.debug_id(),
|
||||||
|
v.contact_info.tvu,
|
||||||
);
|
);
|
||||||
//TODO profile this, may need multiple sockets for par_iter
|
//TODO profile this, may need multiple sockets for par_iter
|
||||||
assert!(rblob.meta.size <= BLOB_SIZE);
|
assert!(rblob.meta.size <= BLOB_SIZE);
|
||||||
@ -728,10 +696,6 @@ impl Crdt {
|
|||||||
self.remote.values().fold(max, |a, b| std::cmp::min(a, *b))
|
self.remote.values().fold(max, |a, b| std::cmp::min(a, *b))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random() -> u64 {
|
|
||||||
thread_rng().next_u64()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: fill in with real implmentation once staking is implemented
|
// TODO: fill in with real implmentation once staking is implemented
|
||||||
fn get_stake(_id: Pubkey) -> f64 {
|
fn get_stake(_id: Pubkey) -> f64 {
|
||||||
1.0
|
1.0
|
||||||
@ -771,7 +735,7 @@ impl Crdt {
|
|||||||
if valid.is_empty() {
|
if valid.is_empty() {
|
||||||
Err(CrdtError::NoPeers)?;
|
Err(CrdtError::NoPeers)?;
|
||||||
}
|
}
|
||||||
let n = (Self::random() as usize) % valid.len();
|
let n = thread_rng().gen::<usize>() % valid.len();
|
||||||
let addr = valid[n].contact_info.ncp;
|
let addr = valid[n].contact_info.ncp;
|
||||||
let req = Protocol::RequestWindowIndex(self.table[&self.me].clone(), ix);
|
let req = Protocol::RequestWindowIndex(self.table[&self.me].clone(), ix);
|
||||||
let out = serialize(&req)?;
|
let out = serialize(&req)?;
|
||||||
@ -814,8 +778,9 @@ impl Crdt {
|
|||||||
let remote_update_index = *self.remote.get(&v.id).unwrap_or(&0);
|
let remote_update_index = *self.remote.get(&v.id).unwrap_or(&0);
|
||||||
let req = Protocol::RequestUpdates(remote_update_index, self.table[&self.me].clone());
|
let req = Protocol::RequestUpdates(remote_update_index, self.table[&self.me].clone());
|
||||||
trace!(
|
trace!(
|
||||||
"created gossip request from {:x} to {:x} {}",
|
"created gossip request from {:x} {:?} to {:x} {}",
|
||||||
self.debug_id(),
|
self.debug_id(),
|
||||||
|
self.table[&self.me].clone(),
|
||||||
v.debug_id(),
|
v.debug_id(),
|
||||||
v.contact_info.ncp
|
v.contact_info.ncp
|
||||||
);
|
);
|
||||||
@ -1060,9 +1025,14 @@ impl Crdt {
|
|||||||
blob: &Blob,
|
blob: &Blob,
|
||||||
) -> Option<SharedBlob> {
|
) -> Option<SharedBlob> {
|
||||||
match deserialize(&blob.data[..blob.meta.size]) {
|
match deserialize(&blob.data[..blob.meta.size]) {
|
||||||
Ok(request) => {
|
Ok(request) => Crdt::handle_protocol(
|
||||||
Crdt::handle_protocol(request, obj, window, ledger_window, blob_recycler)
|
blob.meta.addr(),
|
||||||
}
|
request,
|
||||||
|
obj,
|
||||||
|
window,
|
||||||
|
ledger_window,
|
||||||
|
blob_recycler,
|
||||||
|
),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
warn!("deserialize crdt packet failed");
|
warn!("deserialize crdt packet failed");
|
||||||
None
|
None
|
||||||
@ -1071,6 +1041,7 @@ impl Crdt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_protocol(
|
fn handle_protocol(
|
||||||
|
from_addr: SocketAddr,
|
||||||
request: Protocol,
|
request: Protocol,
|
||||||
obj: &Arc<RwLock<Self>>,
|
obj: &Arc<RwLock<Self>>,
|
||||||
window: &SharedWindow,
|
window: &SharedWindow,
|
||||||
@ -1080,10 +1051,14 @@ impl Crdt {
|
|||||||
match request {
|
match request {
|
||||||
// TODO sigverify these
|
// TODO sigverify these
|
||||||
Protocol::RequestUpdates(v, from_rd) => {
|
Protocol::RequestUpdates(v, from_rd) => {
|
||||||
let addr = from_rd.contact_info.ncp;
|
trace!(
|
||||||
trace!("RequestUpdates {} from {}", v, addr);
|
"RequestUpdates {} from {}, professing to be {}",
|
||||||
|
v,
|
||||||
|
from_addr,
|
||||||
|
from_rd.contact_info.ncp
|
||||||
|
);
|
||||||
let me = obj.read().unwrap();
|
let me = obj.read().unwrap();
|
||||||
if addr == me.table[&me.me].contact_info.ncp {
|
if from_rd.contact_info.ncp == me.table[&me.me].contact_info.ncp {
|
||||||
warn!(
|
warn!(
|
||||||
"RequestUpdates ignored, I'm talking to myself: me={:x} remoteme={:x}",
|
"RequestUpdates ignored, I'm talking to myself: me={:x} remoteme={:x}",
|
||||||
me.debug_id(),
|
me.debug_id(),
|
||||||
@ -1113,13 +1088,13 @@ impl Crdt {
|
|||||||
v
|
v
|
||||||
);
|
);
|
||||||
None
|
None
|
||||||
} else if let Ok(r) = to_blob(rsp, addr, &blob_recycler) {
|
} else if let Ok(r) = to_blob(rsp, from_addr, &blob_recycler) {
|
||||||
trace!(
|
trace!(
|
||||||
"sending updates me {:x} len {} to {:x} {}",
|
"sending updates me {:x} len {} to {:x} {}",
|
||||||
obj.read().unwrap().debug_id(),
|
obj.read().unwrap().debug_id(),
|
||||||
len,
|
len,
|
||||||
from_rd.debug_id(),
|
from_rd.debug_id(),
|
||||||
addr,
|
from_addr,
|
||||||
);
|
);
|
||||||
Some(r)
|
Some(r)
|
||||||
} else {
|
} else {
|
||||||
@ -1254,7 +1229,7 @@ impl Crdt {
|
|||||||
fn is_valid_ip_internal(addr: IpAddr, cfg_test: bool) -> bool {
|
fn is_valid_ip_internal(addr: IpAddr, cfg_test: bool) -> bool {
|
||||||
!(addr.is_unspecified() || addr.is_multicast() || (addr.is_loopback() && !cfg_test))
|
!(addr.is_unspecified() || addr.is_multicast() || (addr.is_loopback() && !cfg_test))
|
||||||
}
|
}
|
||||||
pub fn is_valid_ip(addr: IpAddr) -> bool {
|
fn is_valid_ip(addr: IpAddr) -> bool {
|
||||||
Self::is_valid_ip_internal(addr, cfg!(test) || cfg!(feature = "test"))
|
Self::is_valid_ip_internal(addr, cfg!(test) || cfg!(feature = "test"))
|
||||||
}
|
}
|
||||||
/// port must not be 0
|
/// port must not be 0
|
||||||
@ -1264,20 +1239,17 @@ impl Crdt {
|
|||||||
(addr.port() != 0) && Self::is_valid_ip(addr.ip())
|
(addr.port() != 0) && Self::is_valid_ip(addr.ip())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spy_node(addr: IpAddr) -> (NodeInfo, UdpSocket, UdpSocket) {
|
pub fn spy_node() -> (NodeInfo, UdpSocket) {
|
||||||
let gossip_socket = udp_random_bind(8000, 10000, 5).unwrap();
|
let gossip_socket = bind_in_range(GOSSIP_PORT_RANGE).unwrap();
|
||||||
let gossip_send_socket = udp_random_bind(8000, 10000, 5).unwrap();
|
|
||||||
let gossip_addr = SocketAddr::new(addr, gossip_socket.local_addr().unwrap().port());
|
|
||||||
let pubkey = Keypair::new().pubkey();
|
let pubkey = Keypair::new().pubkey();
|
||||||
let daddr = "0.0.0.0:0".parse().unwrap();
|
let daddr = "0.0.0.0:0".parse().unwrap();
|
||||||
let node = NodeInfo::new(pubkey, gossip_addr, daddr, daddr, daddr, daddr);
|
let node = NodeInfo::new(pubkey, daddr, daddr, daddr, daddr, daddr);
|
||||||
(node, gossip_socket, gossip_send_socket)
|
(node, gossip_socket)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Sockets {
|
pub struct Sockets {
|
||||||
pub gossip: UdpSocket,
|
pub gossip: UdpSocket,
|
||||||
pub gossip_send: UdpSocket,
|
|
||||||
pub requests: UdpSocket,
|
pub requests: UdpSocket,
|
||||||
pub replicate: UdpSocket,
|
pub replicate: UdpSocket,
|
||||||
pub transaction: UdpSocket,
|
pub transaction: UdpSocket,
|
||||||
@ -1287,12 +1259,12 @@ pub struct Sockets {
|
|||||||
pub retransmit: UdpSocket,
|
pub retransmit: UdpSocket,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TestNode {
|
pub struct Node {
|
||||||
pub data: NodeInfo,
|
pub data: NodeInfo,
|
||||||
pub sockets: Sockets,
|
pub sockets: Sockets,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestNode {
|
impl Node {
|
||||||
pub fn new_localhost() -> Self {
|
pub fn new_localhost() -> Self {
|
||||||
let pubkey = Keypair::new().pubkey();
|
let pubkey = Keypair::new().pubkey();
|
||||||
Self::new_localhost_with_pubkey(pubkey)
|
Self::new_localhost_with_pubkey(pubkey)
|
||||||
@ -1304,7 +1276,6 @@ impl TestNode {
|
|||||||
let requests = UdpSocket::bind("127.0.0.1:0").unwrap();
|
let requests = UdpSocket::bind("127.0.0.1:0").unwrap();
|
||||||
let repair = UdpSocket::bind("127.0.0.1:0").unwrap();
|
let repair = UdpSocket::bind("127.0.0.1:0").unwrap();
|
||||||
|
|
||||||
let gossip_send = UdpSocket::bind("0.0.0.0:0").unwrap();
|
|
||||||
let respond = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let respond = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
let broadcast = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let broadcast = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
let retransmit = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let retransmit = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
@ -1316,11 +1287,10 @@ impl TestNode {
|
|||||||
transaction.local_addr().unwrap(),
|
transaction.local_addr().unwrap(),
|
||||||
repair.local_addr().unwrap(),
|
repair.local_addr().unwrap(),
|
||||||
);
|
);
|
||||||
TestNode {
|
Node {
|
||||||
data,
|
data,
|
||||||
sockets: Sockets {
|
sockets: Sockets {
|
||||||
gossip,
|
gossip,
|
||||||
gossip_send,
|
|
||||||
requests,
|
requests,
|
||||||
replicate,
|
replicate,
|
||||||
transaction,
|
transaction,
|
||||||
@ -1331,21 +1301,21 @@ impl TestNode {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn new_with_bind_addr(data: NodeInfo, bind_addr: SocketAddr) -> TestNode {
|
pub fn new_with_bind_addr(data: NodeInfo, bind_addr: SocketAddr) -> Node {
|
||||||
let mut local_gossip_addr = bind_addr;
|
let mut gossip_addr = bind_addr;
|
||||||
local_gossip_addr.set_port(data.contact_info.ncp.port());
|
gossip_addr.set_port(data.contact_info.ncp.port());
|
||||||
|
|
||||||
let mut local_replicate_addr = bind_addr;
|
let mut replicate_addr = bind_addr;
|
||||||
local_replicate_addr.set_port(data.contact_info.tvu.port());
|
replicate_addr.set_port(data.contact_info.tvu.port());
|
||||||
|
|
||||||
let mut local_requests_addr = bind_addr;
|
let mut requests_addr = bind_addr;
|
||||||
local_requests_addr.set_port(data.contact_info.rpu.port());
|
requests_addr.set_port(data.contact_info.rpu.port());
|
||||||
|
|
||||||
let mut local_transactions_addr = bind_addr;
|
let mut transactions_addr = bind_addr;
|
||||||
local_transactions_addr.set_port(data.contact_info.tpu.port());
|
transactions_addr.set_port(data.contact_info.tpu.port());
|
||||||
|
|
||||||
let mut local_repair_addr = bind_addr;
|
let mut repair_addr = bind_addr;
|
||||||
local_repair_addr.set_port(data.contact_info.tvu_window.port());
|
repair_addr.set_port(data.contact_info.tvu_window.port());
|
||||||
|
|
||||||
fn bind(addr: SocketAddr) -> UdpSocket {
|
fn bind(addr: SocketAddr) -> UdpSocket {
|
||||||
match UdpSocket::bind(addr) {
|
match UdpSocket::bind(addr) {
|
||||||
@ -1356,25 +1326,23 @@ impl TestNode {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let transaction = bind(local_transactions_addr);
|
let transaction = bind(transactions_addr);
|
||||||
let gossip = bind(local_gossip_addr);
|
let gossip = bind(gossip_addr);
|
||||||
let replicate = bind(local_replicate_addr);
|
let replicate = bind(replicate_addr);
|
||||||
let repair = bind(local_repair_addr);
|
let repair = bind(repair_addr);
|
||||||
let requests = bind(local_requests_addr);
|
let requests = bind(requests_addr);
|
||||||
|
|
||||||
// Responses are sent from the same Udp port as requests are received
|
// Responses are sent from the same Udp port as requests are received
|
||||||
// from, in hopes that a NAT sitting in the middle will route the
|
// from, in hopes that a NAT sitting in the middle will route the
|
||||||
// response Udp packet correctly back to the requester.
|
// response Udp packet correctly back to the requester.
|
||||||
let respond = requests.try_clone().unwrap();
|
let respond = requests.try_clone().unwrap();
|
||||||
|
|
||||||
let gossip_send = UdpSocket::bind("0.0.0.0:0").unwrap();
|
|
||||||
let broadcast = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let broadcast = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
let retransmit = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let retransmit = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
TestNode {
|
Node {
|
||||||
data,
|
data,
|
||||||
sockets: Sockets {
|
sockets: Sockets {
|
||||||
gossip,
|
gossip,
|
||||||
gossip_send,
|
|
||||||
requests,
|
requests,
|
||||||
replicate,
|
replicate,
|
||||||
transaction,
|
transaction,
|
||||||
@ -1390,9 +1358,9 @@ impl TestNode {
|
|||||||
ip: IpAddr,
|
ip: IpAddr,
|
||||||
port_range: (u16, u16),
|
port_range: (u16, u16),
|
||||||
ncp_port: u16,
|
ncp_port: u16,
|
||||||
) -> TestNode {
|
) -> Node {
|
||||||
fn bind(port_range: (u16, u16)) -> (u16, UdpSocket) {
|
fn bind(port_range: (u16, u16)) -> (u16, UdpSocket) {
|
||||||
match udp_random_bind(port_range.0, port_range.1, 5) {
|
match bind_in_range(port_range) {
|
||||||
Ok(socket) => (socket.local_addr().unwrap().port(), socket),
|
Ok(socket) => (socket.local_addr().unwrap().port(), socket),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
panic!("Failed to bind to {:?}", err);
|
panic!("Failed to bind to {:?}", err);
|
||||||
@ -1425,7 +1393,6 @@ impl TestNode {
|
|||||||
// response Udp packet correctly back to the requester.
|
// response Udp packet correctly back to the requester.
|
||||||
let respond = requests.try_clone().unwrap();
|
let respond = requests.try_clone().unwrap();
|
||||||
|
|
||||||
let gossip_send = UdpSocket::bind("0.0.0.0:0").unwrap();
|
|
||||||
let broadcast = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let broadcast = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
let retransmit = UdpSocket::bind("0.0.0.0:0").unwrap();
|
let retransmit = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||||
|
|
||||||
@ -1438,11 +1405,10 @@ impl TestNode {
|
|||||||
SocketAddr::new(ip, repair_port),
|
SocketAddr::new(ip, repair_port),
|
||||||
);
|
);
|
||||||
|
|
||||||
TestNode {
|
Node {
|
||||||
data: node_info,
|
data: node_info,
|
||||||
sockets: Sockets {
|
sockets: Sockets {
|
||||||
gossip,
|
gossip,
|
||||||
gossip_send,
|
|
||||||
requests,
|
requests,
|
||||||
replicate,
|
replicate,
|
||||||
transaction,
|
transaction,
|
||||||
@ -1465,8 +1431,8 @@ fn report_time_spent(label: &str, time: &Duration, extra: &str) {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crdt::{
|
use crdt::{
|
||||||
parse_port_or_addr, Crdt, CrdtError, NodeInfo, Protocol, TestNode, GOSSIP_PURGE_MILLIS,
|
Crdt, CrdtError, Node, NodeInfo, Protocol, GOSSIP_PURGE_MILLIS, GOSSIP_SLEEP_MILLIS,
|
||||||
GOSSIP_SLEEP_MILLIS, MIN_TABLE_SIZE,
|
MIN_TABLE_SIZE,
|
||||||
};
|
};
|
||||||
use entry::Entry;
|
use entry::Entry;
|
||||||
use hash::{hash, Hash};
|
use hash::{hash, Hash};
|
||||||
@ -1485,15 +1451,6 @@ mod tests {
|
|||||||
use transaction::Vote;
|
use transaction::Vote;
|
||||||
use window::default_window;
|
use window::default_window;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_parse_port_or_addr() {
|
|
||||||
let p1 = parse_port_or_addr(Some("9000".to_string()));
|
|
||||||
assert_eq!(p1.port(), 9000);
|
|
||||||
let p2 = parse_port_or_addr(Some("127.0.0.1:7000".to_string()));
|
|
||||||
assert_eq!(p2.port(), 7000);
|
|
||||||
let p3 = parse_port_or_addr(None);
|
|
||||||
assert_eq!(p3.port(), 8000);
|
|
||||||
}
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bad_address() {
|
fn test_bad_address() {
|
||||||
let d1 = NodeInfo::new(
|
let d1 = NodeInfo::new(
|
||||||
@ -2154,13 +2111,38 @@ mod tests {
|
|||||||
let obj = Arc::new(RwLock::new(crdt));
|
let obj = Arc::new(RwLock::new(crdt));
|
||||||
|
|
||||||
let request = Protocol::RequestUpdates(1, node.clone());
|
let request = Protocol::RequestUpdates(1, node.clone());
|
||||||
assert!(Crdt::handle_protocol(request, &obj, &window, &mut None, &recycler).is_none());
|
assert!(
|
||||||
|
Crdt::handle_protocol(
|
||||||
|
node.contact_info.ncp,
|
||||||
|
request,
|
||||||
|
&obj,
|
||||||
|
&window,
|
||||||
|
&mut None,
|
||||||
|
&recycler
|
||||||
|
).is_none()
|
||||||
|
);
|
||||||
|
|
||||||
let request = Protocol::RequestUpdates(1, node_with_same_addr.clone());
|
let request = Protocol::RequestUpdates(1, node_with_same_addr.clone());
|
||||||
assert!(Crdt::handle_protocol(request, &obj, &window, &mut None, &recycler).is_none());
|
assert!(
|
||||||
|
Crdt::handle_protocol(
|
||||||
|
node.contact_info.ncp,
|
||||||
|
request,
|
||||||
|
&obj,
|
||||||
|
&window,
|
||||||
|
&mut None,
|
||||||
|
&recycler
|
||||||
|
).is_none()
|
||||||
|
);
|
||||||
|
|
||||||
let request = Protocol::RequestUpdates(1, node_with_diff_addr.clone());
|
let request = Protocol::RequestUpdates(1, node_with_diff_addr.clone());
|
||||||
Crdt::handle_protocol(request, &obj, &window, &mut None, &recycler);
|
Crdt::handle_protocol(
|
||||||
|
node.contact_info.ncp,
|
||||||
|
request,
|
||||||
|
&obj,
|
||||||
|
&window,
|
||||||
|
&mut None,
|
||||||
|
&recycler,
|
||||||
|
);
|
||||||
|
|
||||||
let me = obj.write().unwrap();
|
let me = obj.write().unwrap();
|
||||||
|
|
||||||
@ -2206,7 +2188,7 @@ mod tests {
|
|||||||
fn new_with_external_ip_test_random() {
|
fn new_with_external_ip_test_random() {
|
||||||
let sockaddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8080);
|
let sockaddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8080);
|
||||||
let node =
|
let node =
|
||||||
TestNode::new_with_external_ip(Keypair::new().pubkey(), sockaddr.ip(), (8100, 8200), 0);
|
Node::new_with_external_ip(Keypair::new().pubkey(), sockaddr.ip(), (8100, 8200), 0);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
node.sockets.gossip.local_addr().unwrap().ip(),
|
node.sockets.gossip.local_addr().unwrap().ip(),
|
||||||
@ -2244,12 +2226,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn new_with_external_ip_test_gossip() {
|
fn new_with_external_ip_test_gossip() {
|
||||||
let sockaddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8080);
|
let sockaddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8080);
|
||||||
let node = TestNode::new_with_external_ip(
|
let node =
|
||||||
Keypair::new().pubkey(),
|
Node::new_with_external_ip(Keypair::new().pubkey(), sockaddr.ip(), (8100, 8200), 8050);
|
||||||
sockaddr.ip(),
|
|
||||||
(8100, 8200),
|
|
||||||
8050,
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
node.sockets.gossip.local_addr().unwrap().ip(),
|
node.sockets.gossip.local_addr().unwrap().ip(),
|
||||||
sockaddr.ip()
|
sockaddr.ip()
|
||||||
|
@ -157,11 +157,12 @@ impl Drop for Drone {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use bank::Bank;
|
use bank::Bank;
|
||||||
use crdt::{get_ip_addr, TestNode};
|
use crdt::Node;
|
||||||
use drone::{Drone, DroneRequest, REQUEST_CAP, TIME_SLICE};
|
use drone::{Drone, DroneRequest, REQUEST_CAP, TIME_SLICE};
|
||||||
use fullnode::Fullnode;
|
use fullnode::Fullnode;
|
||||||
use logger;
|
use logger;
|
||||||
use mint::Mint;
|
use mint::Mint;
|
||||||
|
use nat::get_ip_addr;
|
||||||
use service::Service;
|
use service::Service;
|
||||||
use signature::{Keypair, KeypairUtil};
|
use signature::{Keypair, KeypairUtil};
|
||||||
use std::fs::remove_dir_all;
|
use std::fs::remove_dir_all;
|
||||||
@ -275,7 +276,7 @@ mod tests {
|
|||||||
|
|
||||||
logger::setup();
|
logger::setup();
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
|
|
||||||
let alice = Mint::new(10_000_000);
|
let alice = Mint::new(10_000_000);
|
||||||
let bank = Bank::new(&alice);
|
let bank = Bank::new(&alice);
|
||||||
|
@ -16,31 +16,26 @@ pub struct FetchStage {
|
|||||||
|
|
||||||
impl FetchStage {
|
impl FetchStage {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
socket: UdpSocket,
|
socket: Arc<UdpSocket>,
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
packet_recycler: &PacketRecycler,
|
recycler: &PacketRecycler,
|
||||||
) -> (Self, PacketReceiver) {
|
) -> (Self, PacketReceiver) {
|
||||||
Self::new_multi_socket(vec![socket], exit, packet_recycler)
|
Self::new_multi_socket(vec![socket], exit, recycler)
|
||||||
}
|
}
|
||||||
pub fn new_multi_socket(
|
pub fn new_multi_socket(
|
||||||
sockets: Vec<UdpSocket>,
|
sockets: Vec<Arc<UdpSocket>>,
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
packet_recycler: &PacketRecycler,
|
recycler: &PacketRecycler,
|
||||||
) -> (Self, PacketReceiver) {
|
) -> (Self, PacketReceiver) {
|
||||||
let (packet_sender, packet_receiver) = channel();
|
let (sender, receiver) = channel();
|
||||||
let thread_hdls: Vec<_> = sockets
|
let thread_hdls: Vec<_> = sockets
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|socket| {
|
.map(|socket| {
|
||||||
streamer::receiver(
|
streamer::receiver(socket, exit.clone(), recycler.clone(), sender.clone())
|
||||||
socket,
|
|
||||||
exit.clone(),
|
|
||||||
packet_recycler.clone(),
|
|
||||||
packet_sender.clone(),
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
(FetchStage { exit, thread_hdls }, packet_receiver)
|
(FetchStage { exit, thread_hdls }, receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close(&self) {
|
pub fn close(&self) {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use bank::Bank;
|
use bank::Bank;
|
||||||
use broadcast_stage::BroadcastStage;
|
use broadcast_stage::BroadcastStage;
|
||||||
use crdt::{Crdt, NodeInfo, TestNode};
|
use crdt::{Crdt, Node, NodeInfo};
|
||||||
use drone::DRONE_PORT;
|
use drone::DRONE_PORT;
|
||||||
use entry::Entry;
|
use entry::Entry;
|
||||||
use ledger::read_ledger;
|
use ledger::read_ledger;
|
||||||
@ -50,7 +50,7 @@ impl Config {
|
|||||||
|
|
||||||
impl Fullnode {
|
impl Fullnode {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
node: TestNode,
|
node: Node,
|
||||||
ledger_path: &str,
|
ledger_path: &str,
|
||||||
keypair: Keypair,
|
keypair: Keypair,
|
||||||
leader_addr: Option<SocketAddr>,
|
leader_addr: Option<SocketAddr>,
|
||||||
@ -165,7 +165,7 @@ impl Fullnode {
|
|||||||
bank: Bank,
|
bank: Bank,
|
||||||
entry_height: u64,
|
entry_height: u64,
|
||||||
ledger_tail: &[Entry],
|
ledger_tail: &[Entry],
|
||||||
mut node: TestNode,
|
mut node: Node,
|
||||||
leader_info: Option<&NodeInfo>,
|
leader_info: Option<&NodeInfo>,
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
ledger_path: Option<&str>,
|
ledger_path: Option<&str>,
|
||||||
@ -209,7 +209,6 @@ impl Fullnode {
|
|||||||
window.clone(),
|
window.clone(),
|
||||||
ledger_path,
|
ledger_path,
|
||||||
node.sockets.gossip,
|
node.sockets.gossip,
|
||||||
node.sockets.gossip_send,
|
|
||||||
exit.clone(),
|
exit.clone(),
|
||||||
).expect("Ncp::new");
|
).expect("Ncp::new");
|
||||||
thread_hdls.extend(ncp.thread_hdls());
|
thread_hdls.extend(ncp.thread_hdls());
|
||||||
@ -293,7 +292,7 @@ impl Service for Fullnode {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use bank::Bank;
|
use bank::Bank;
|
||||||
use crdt::TestNode;
|
use crdt::Node;
|
||||||
use fullnode::Fullnode;
|
use fullnode::Fullnode;
|
||||||
use mint::Mint;
|
use mint::Mint;
|
||||||
use service::Service;
|
use service::Service;
|
||||||
@ -304,7 +303,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn validator_exit() {
|
fn validator_exit() {
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
let tn = TestNode::new_localhost_with_pubkey(keypair.pubkey());
|
let tn = Node::new_localhost_with_pubkey(keypair.pubkey());
|
||||||
let alice = Mint::new(10_000);
|
let alice = Mint::new(10_000);
|
||||||
let bank = Bank::new(&alice);
|
let bank = Bank::new(&alice);
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
@ -318,7 +317,7 @@ mod tests {
|
|||||||
let vals: Vec<Fullnode> = (0..2)
|
let vals: Vec<Fullnode> = (0..2)
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
let tn = TestNode::new_localhost_with_pubkey(keypair.pubkey());
|
let tn = Node::new_localhost_with_pubkey(keypair.pubkey());
|
||||||
let alice = Mint::new(10_000);
|
let alice = Mint::new(10_000);
|
||||||
let bank = Bank::new(&alice);
|
let bank = Bank::new(&alice);
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
|
74
src/nat.rs
74
src/nat.rs
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
extern crate reqwest;
|
extern crate reqwest;
|
||||||
|
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
use pnet_datalink as datalink;
|
||||||
|
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use std::io;
|
use std::io;
|
||||||
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||||
|
|
||||||
/// A data type representing a public Udp socket
|
/// A data type representing a public Udp socket
|
||||||
pub struct UdpSocketPair {
|
pub struct UdpSocketPair {
|
||||||
@ -27,19 +27,79 @@ pub fn get_public_ip_addr() -> Result<IpAddr, String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn udp_random_bind(start: u16, end: u16, tries: u32) -> io::Result<UdpSocket> {
|
pub fn parse_port_or_addr(optstr: Option<&str>, default_port: u16) -> SocketAddr {
|
||||||
let mut count = 0;
|
let daddr: SocketAddr = format!("0.0.0.0:{}", default_port)
|
||||||
loop {
|
.parse()
|
||||||
count += 1;
|
.expect("default socket address");
|
||||||
|
if let Some(addrstr) = optstr {
|
||||||
|
if let Ok(port) = addrstr.parse() {
|
||||||
|
let mut addr = daddr;
|
||||||
|
addr.set_port(port);
|
||||||
|
addr
|
||||||
|
} else if let Ok(addr) = addrstr.parse() {
|
||||||
|
addr
|
||||||
|
} else {
|
||||||
|
daddr
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
daddr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_ip_addr() -> Option<IpAddr> {
|
||||||
|
for iface in datalink::interfaces() {
|
||||||
|
for p in iface.ips {
|
||||||
|
if !p.ip().is_loopback() && !p.ip().is_multicast() {
|
||||||
|
match p.ip() {
|
||||||
|
IpAddr::V4(addr) => {
|
||||||
|
if !addr.is_link_local() {
|
||||||
|
return Some(p.ip());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IpAddr::V6(_addr) => {
|
||||||
|
// Select an ipv6 address if the config is selected
|
||||||
|
#[cfg(feature = "ipv6")]
|
||||||
|
{
|
||||||
|
return Some(p.ip());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bind_in_range(range: (u16, u16)) -> io::Result<UdpSocket> {
|
||||||
|
let (start, end) = range;
|
||||||
|
let mut tries_left = end - start;
|
||||||
|
loop {
|
||||||
let rand_port = thread_rng().gen_range(start, end);
|
let rand_port = thread_rng().gen_range(start, end);
|
||||||
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), rand_port);
|
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), rand_port);
|
||||||
|
|
||||||
match UdpSocket::bind(addr) {
|
match UdpSocket::bind(addr) {
|
||||||
Result::Ok(val) => break Result::Ok(val),
|
Result::Ok(val) => break Result::Ok(val),
|
||||||
Result::Err(err) => if err.kind() != io::ErrorKind::AddrInUse || count >= tries {
|
Result::Err(err) => if err.kind() != io::ErrorKind::AddrInUse || tries_left == 0 {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
tries_left -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use nat::parse_port_or_addr;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_port_or_addr() {
|
||||||
|
let p1 = parse_port_or_addr(Some("9000"), 1);
|
||||||
|
assert_eq!(p1.port(), 9000);
|
||||||
|
let p2 = parse_port_or_addr(Some("127.0.0.1:7000"), 1);
|
||||||
|
assert_eq!(p2.port(), 7000);
|
||||||
|
let p2 = parse_port_or_addr(Some("hi there"), 1);
|
||||||
|
assert_eq!(p2.port(), 1);
|
||||||
|
let p3 = parse_port_or_addr(None, 1);
|
||||||
|
assert_eq!(p3.port(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
23
src/ncp.rs
23
src/ncp.rs
@ -22,27 +22,27 @@ impl Ncp {
|
|||||||
crdt: &Arc<RwLock<Crdt>>,
|
crdt: &Arc<RwLock<Crdt>>,
|
||||||
window: SharedWindow,
|
window: SharedWindow,
|
||||||
ledger_path: Option<&str>,
|
ledger_path: Option<&str>,
|
||||||
gossip_listen_socket: UdpSocket,
|
gossip_socket: UdpSocket,
|
||||||
gossip_send_socket: UdpSocket,
|
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
) -> Result<Ncp> {
|
) -> Result<Ncp> {
|
||||||
let blob_recycler = BlobRecycler::default();
|
let blob_recycler = BlobRecycler::default();
|
||||||
let (request_sender, request_receiver) = channel();
|
let (request_sender, request_receiver) = channel();
|
||||||
|
let gossip_socket = Arc::new(gossip_socket);
|
||||||
trace!(
|
trace!(
|
||||||
"Ncp: id: {:?}, listening on: {:?}",
|
"Ncp: id: {:?}, listening on: {:?}",
|
||||||
&crdt.read().unwrap().me.as_ref()[..4],
|
&crdt.read().unwrap().me.as_ref()[..4],
|
||||||
gossip_listen_socket.local_addr().unwrap()
|
gossip_socket.local_addr().unwrap()
|
||||||
);
|
);
|
||||||
let t_receiver = streamer::blob_receiver(
|
let t_receiver = streamer::blob_receiver(
|
||||||
|
gossip_socket.clone(),
|
||||||
exit.clone(),
|
exit.clone(),
|
||||||
blob_recycler.clone(),
|
blob_recycler.clone(),
|
||||||
gossip_listen_socket,
|
|
||||||
request_sender,
|
request_sender,
|
||||||
)?;
|
)?;
|
||||||
let (response_sender, response_receiver) = channel();
|
let (response_sender, response_receiver) = channel();
|
||||||
let t_responder = streamer::responder(
|
let t_responder = streamer::responder(
|
||||||
"ncp",
|
"ncp",
|
||||||
gossip_send_socket,
|
gossip_socket,
|
||||||
blob_recycler.clone(),
|
blob_recycler.clone(),
|
||||||
response_receiver,
|
response_receiver,
|
||||||
);
|
);
|
||||||
@ -81,7 +81,7 @@ impl Service for Ncp {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crdt::{Crdt, TestNode};
|
use crdt::{Crdt, Node};
|
||||||
use ncp::Ncp;
|
use ncp::Ncp;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
@ -91,18 +91,11 @@ mod tests {
|
|||||||
// test that stage will exit when flag is set
|
// test that stage will exit when flag is set
|
||||||
fn test_exit() {
|
fn test_exit() {
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let tn = TestNode::new_localhost();
|
let tn = Node::new_localhost();
|
||||||
let crdt = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
let crdt = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
||||||
let c = Arc::new(RwLock::new(crdt));
|
let c = Arc::new(RwLock::new(crdt));
|
||||||
let w = Arc::new(RwLock::new(vec![]));
|
let w = Arc::new(RwLock::new(vec![]));
|
||||||
let d = Ncp::new(
|
let d = Ncp::new(&c, w, None, tn.sockets.gossip, exit.clone()).unwrap();
|
||||||
&c,
|
|
||||||
w,
|
|
||||||
None,
|
|
||||||
tn.sockets.gossip,
|
|
||||||
tn.sockets.gossip_send,
|
|
||||||
exit.clone(),
|
|
||||||
).unwrap();
|
|
||||||
d.close().expect("thread join");
|
d.close().expect("thread join");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ impl ReplicateStage {
|
|||||||
let send = UdpSocket::bind("0.0.0.0:0").expect("bind");
|
let send = UdpSocket::bind("0.0.0.0:0").expect("bind");
|
||||||
let t_responder = responder(
|
let t_responder = responder(
|
||||||
"replicate_stage",
|
"replicate_stage",
|
||||||
send,
|
Arc::new(send),
|
||||||
blob_recycler.clone(),
|
blob_recycler.clone(),
|
||||||
vote_blob_receiver,
|
vote_blob_receiver,
|
||||||
);
|
);
|
||||||
|
@ -47,7 +47,7 @@ fn retransmit(
|
|||||||
/// * `recycler` - Blob recycler.
|
/// * `recycler` - Blob recycler.
|
||||||
/// * `r` - Receive channel for blobs to be retransmitted to all the layer 1 nodes.
|
/// * `r` - Receive channel for blobs to be retransmitted to all the layer 1 nodes.
|
||||||
fn retransmitter(
|
fn retransmitter(
|
||||||
sock: UdpSocket,
|
sock: Arc<UdpSocket>,
|
||||||
crdt: Arc<RwLock<Crdt>>,
|
crdt: Arc<RwLock<Crdt>>,
|
||||||
recycler: BlobRecycler,
|
recycler: BlobRecycler,
|
||||||
r: BlobReceiver,
|
r: BlobReceiver,
|
||||||
@ -81,7 +81,7 @@ impl RetransmitStage {
|
|||||||
crdt: &Arc<RwLock<Crdt>>,
|
crdt: &Arc<RwLock<Crdt>>,
|
||||||
window: SharedWindow,
|
window: SharedWindow,
|
||||||
entry_height: u64,
|
entry_height: u64,
|
||||||
retransmit_socket: UdpSocket,
|
retransmit_socket: Arc<UdpSocket>,
|
||||||
blob_recycler: &BlobRecycler,
|
blob_recycler: &BlobRecycler,
|
||||||
fetch_stage_receiver: BlobReceiver,
|
fetch_stage_receiver: BlobReceiver,
|
||||||
) -> (Self, BlobReceiver) {
|
) -> (Self, BlobReceiver) {
|
||||||
|
10
src/rpu.rs
10
src/rpu.rs
@ -49,7 +49,7 @@ impl Rpu {
|
|||||||
let packet_recycler = PacketRecycler::default();
|
let packet_recycler = PacketRecycler::default();
|
||||||
let (packet_sender, packet_receiver) = channel();
|
let (packet_sender, packet_receiver) = channel();
|
||||||
let t_receiver = streamer::receiver(
|
let t_receiver = streamer::receiver(
|
||||||
requests_socket,
|
Arc::new(requests_socket),
|
||||||
exit,
|
exit,
|
||||||
packet_recycler.clone(),
|
packet_recycler.clone(),
|
||||||
packet_sender,
|
packet_sender,
|
||||||
@ -64,8 +64,12 @@ impl Rpu {
|
|||||||
blob_recycler.clone(),
|
blob_recycler.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let t_responder =
|
let t_responder = streamer::responder(
|
||||||
streamer::responder("rpu", respond_socket, blob_recycler.clone(), blob_receiver);
|
"rpu",
|
||||||
|
Arc::new(respond_socket),
|
||||||
|
blob_recycler.clone(),
|
||||||
|
blob_receiver,
|
||||||
|
);
|
||||||
|
|
||||||
let mut thread_hdls = vec![t_receiver, t_responder];
|
let mut thread_hdls = vec![t_receiver, t_responder];
|
||||||
thread_hdls.extend(request_stage.thread_hdls().into_iter());
|
thread_hdls.extend(request_stage.thread_hdls().into_iter());
|
||||||
|
@ -44,7 +44,7 @@ fn recv_loop(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn receiver(
|
pub fn receiver(
|
||||||
sock: UdpSocket,
|
sock: Arc<UdpSocket>,
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
recycler: PacketRecycler,
|
recycler: PacketRecycler,
|
||||||
packet_sender: PacketSender,
|
packet_sender: PacketSender,
|
||||||
@ -90,7 +90,7 @@ pub fn recv_batch(recvr: &PacketReceiver) -> Result<(Vec<SharedPackets>, usize)>
|
|||||||
|
|
||||||
pub fn responder(
|
pub fn responder(
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
sock: UdpSocket,
|
sock: Arc<UdpSocket>,
|
||||||
recycler: BlobRecycler,
|
recycler: BlobRecycler,
|
||||||
r: BlobReceiver,
|
r: BlobReceiver,
|
||||||
) -> JoinHandle<()> {
|
) -> JoinHandle<()> {
|
||||||
@ -120,9 +120,9 @@ fn recv_blobs(recycler: &BlobRecycler, sock: &UdpSocket, s: &BlobSender) -> Resu
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn blob_receiver(
|
pub fn blob_receiver(
|
||||||
|
sock: Arc<UdpSocket>,
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
recycler: BlobRecycler,
|
recycler: BlobRecycler,
|
||||||
sock: UdpSocket,
|
|
||||||
s: BlobSender,
|
s: BlobSender,
|
||||||
) -> Result<JoinHandle<()>> {
|
) -> Result<JoinHandle<()>> {
|
||||||
//DOCUMENTED SIDE-EFFECT
|
//DOCUMENTED SIDE-EFFECT
|
||||||
@ -184,12 +184,17 @@ mod test {
|
|||||||
let pack_recycler = PacketRecycler::default();
|
let pack_recycler = PacketRecycler::default();
|
||||||
let resp_recycler = BlobRecycler::default();
|
let resp_recycler = BlobRecycler::default();
|
||||||
let (s_reader, r_reader) = channel();
|
let (s_reader, r_reader) = channel();
|
||||||
let t_receiver = receiver(read, exit.clone(), pack_recycler.clone(), s_reader);
|
let t_receiver = receiver(
|
||||||
|
Arc::new(read),
|
||||||
|
exit.clone(),
|
||||||
|
pack_recycler.clone(),
|
||||||
|
s_reader,
|
||||||
|
);
|
||||||
let t_responder = {
|
let t_responder = {
|
||||||
let (s_responder, r_responder) = channel();
|
let (s_responder, r_responder) = channel();
|
||||||
let t_responder = responder(
|
let t_responder = responder(
|
||||||
"streamer_send_test",
|
"streamer_send_test",
|
||||||
send,
|
Arc::new(send),
|
||||||
resp_recycler.clone(),
|
resp_recycler.clone(),
|
||||||
r_responder,
|
r_responder,
|
||||||
);
|
);
|
||||||
|
@ -13,7 +13,6 @@ use result::{Error, Result};
|
|||||||
use signature::{Keypair, Pubkey, Signature};
|
use signature::{Keypair, Pubkey, Signature};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::IpAddr;
|
|
||||||
use std::net::{SocketAddr, UdpSocket};
|
use std::net::{SocketAddr, UdpSocket};
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
@ -361,23 +360,13 @@ impl Drop for ThinClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_gossip_for_leader(
|
pub fn poll_gossip_for_leader(leader_ncp: SocketAddr, timeout: Option<u64>) -> Result<NodeInfo> {
|
||||||
leader_ncp: SocketAddr,
|
|
||||||
timeout: Option<u64>,
|
|
||||||
addr: IpAddr,
|
|
||||||
) -> Result<NodeInfo> {
|
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let (node, gossip_socket, gossip_send_socket) = Crdt::spy_node(addr);
|
trace!("polling {:?} for leader", leader_ncp);
|
||||||
|
let (node, gossip_socket) = Crdt::spy_node();
|
||||||
let crdt = Arc::new(RwLock::new(Crdt::new(node).expect("Crdt::new")));
|
let crdt = Arc::new(RwLock::new(Crdt::new(node).expect("Crdt::new")));
|
||||||
let window = Arc::new(RwLock::new(vec![]));
|
let window = Arc::new(RwLock::new(vec![]));
|
||||||
let ncp = Ncp::new(
|
let ncp = Ncp::new(&crdt.clone(), window, None, gossip_socket, exit.clone()).unwrap();
|
||||||
&crdt.clone(),
|
|
||||||
window,
|
|
||||||
None,
|
|
||||||
gossip_socket,
|
|
||||||
gossip_send_socket,
|
|
||||||
exit.clone(),
|
|
||||||
).unwrap();
|
|
||||||
let leader_entry_point = NodeInfo::new_entry_point(leader_ncp);
|
let leader_entry_point = NodeInfo::new_entry_point(leader_ncp);
|
||||||
crdt.write().unwrap().insert(&leader_entry_point);
|
crdt.write().unwrap().insert(&leader_entry_point);
|
||||||
|
|
||||||
@ -401,7 +390,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use bank::Bank;
|
use bank::Bank;
|
||||||
use budget::Budget;
|
use budget::Budget;
|
||||||
use crdt::TestNode;
|
use crdt::Node;
|
||||||
use fullnode::Fullnode;
|
use fullnode::Fullnode;
|
||||||
use ledger::LedgerWriter;
|
use ledger::LedgerWriter;
|
||||||
use logger;
|
use logger;
|
||||||
@ -430,7 +419,7 @@ mod tests {
|
|||||||
fn test_thin_client() {
|
fn test_thin_client() {
|
||||||
logger::setup();
|
logger::setup();
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
let leader_data = leader.data.clone();
|
let leader_data = leader.data.clone();
|
||||||
|
|
||||||
let alice = Mint::new(10_000);
|
let alice = Mint::new(10_000);
|
||||||
@ -479,7 +468,7 @@ mod tests {
|
|||||||
fn test_bad_sig() {
|
fn test_bad_sig() {
|
||||||
logger::setup();
|
logger::setup();
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
let alice = Mint::new(10_000);
|
let alice = Mint::new(10_000);
|
||||||
let bank = Bank::new(&alice);
|
let bank = Bank::new(&alice);
|
||||||
let bob_pubkey = Keypair::new().pubkey();
|
let bob_pubkey = Keypair::new().pubkey();
|
||||||
@ -539,7 +528,7 @@ mod tests {
|
|||||||
fn test_client_check_signature() {
|
fn test_client_check_signature() {
|
||||||
logger::setup();
|
logger::setup();
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
let alice = Mint::new(10_000);
|
let alice = Mint::new(10_000);
|
||||||
let bank = Bank::new(&alice);
|
let bank = Bank::new(&alice);
|
||||||
let bob_pubkey = Keypair::new().pubkey();
|
let bob_pubkey = Keypair::new().pubkey();
|
||||||
|
@ -65,7 +65,7 @@ impl Tpu {
|
|||||||
let packet_recycler = PacketRecycler::default();
|
let packet_recycler = PacketRecycler::default();
|
||||||
|
|
||||||
let (fetch_stage, packet_receiver) =
|
let (fetch_stage, packet_receiver) =
|
||||||
FetchStage::new(transactions_socket, exit, &packet_recycler);
|
FetchStage::new(Arc::new(transactions_socket), exit, &packet_recycler);
|
||||||
|
|
||||||
let (sigverify_stage, verified_receiver) =
|
let (sigverify_stage, verified_receiver) =
|
||||||
SigVerifyStage::new(packet_receiver, sigverify_disabled);
|
SigVerifyStage::new(packet_receiver, sigverify_disabled);
|
||||||
|
21
src/tvu.rs
21
src/tvu.rs
@ -83,7 +83,7 @@ impl Tvu {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let blob_recycler = BlobRecycler::default();
|
let blob_recycler = BlobRecycler::default();
|
||||||
let (fetch_stage, blob_fetch_receiver) = BlobFetchStage::new_multi_socket(
|
let (fetch_stage, blob_fetch_receiver) = BlobFetchStage::new_multi_socket(
|
||||||
vec![replicate_socket, repair_socket],
|
vec![Arc::new(replicate_socket), Arc::new(repair_socket)],
|
||||||
exit.clone(),
|
exit.clone(),
|
||||||
&blob_recycler,
|
&blob_recycler,
|
||||||
);
|
);
|
||||||
@ -94,7 +94,7 @@ impl Tvu {
|
|||||||
&crdt,
|
&crdt,
|
||||||
window,
|
window,
|
||||||
entry_height,
|
entry_height,
|
||||||
retransmit_socket,
|
Arc::new(retransmit_socket),
|
||||||
&blob_recycler,
|
&blob_recycler,
|
||||||
blob_fetch_receiver,
|
blob_fetch_receiver,
|
||||||
);
|
);
|
||||||
@ -143,7 +143,7 @@ impl Service for Tvu {
|
|||||||
pub mod tests {
|
pub mod tests {
|
||||||
use bank::Bank;
|
use bank::Bank;
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use crdt::{Crdt, TestNode};
|
use crdt::{Crdt, Node};
|
||||||
use entry::Entry;
|
use entry::Entry;
|
||||||
use hash::{hash, Hash};
|
use hash::{hash, Hash};
|
||||||
use logger;
|
use logger;
|
||||||
@ -166,12 +166,11 @@ pub mod tests {
|
|||||||
|
|
||||||
fn new_ncp(
|
fn new_ncp(
|
||||||
crdt: Arc<RwLock<Crdt>>,
|
crdt: Arc<RwLock<Crdt>>,
|
||||||
listen: UdpSocket,
|
gossip: UdpSocket,
|
||||||
exit: Arc<AtomicBool>,
|
exit: Arc<AtomicBool>,
|
||||||
) -> Result<(Ncp, SharedWindow)> {
|
) -> Result<(Ncp, SharedWindow)> {
|
||||||
let window = window::default_window();
|
let window = window::default_window();
|
||||||
let send_sock = UdpSocket::bind("0.0.0.0:0").expect("bind 0");
|
let ncp = Ncp::new(&crdt, window.clone(), None, gossip, exit)?;
|
||||||
let ncp = Ncp::new(&crdt, window.clone(), None, listen, send_sock, exit)?;
|
|
||||||
Ok((ncp, window))
|
Ok((ncp, window))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,10 +178,10 @@ pub mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_replicate() {
|
fn test_replicate() {
|
||||||
logger::setup();
|
logger::setup();
|
||||||
let leader = TestNode::new_localhost();
|
let leader = Node::new_localhost();
|
||||||
let target1_keypair = Keypair::new();
|
let target1_keypair = Keypair::new();
|
||||||
let target1 = TestNode::new_localhost_with_pubkey(target1_keypair.pubkey());
|
let target1 = Node::new_localhost_with_pubkey(target1_keypair.pubkey());
|
||||||
let target2 = TestNode::new_localhost();
|
let target2 = Node::new_localhost();
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
//start crdt_leader
|
//start crdt_leader
|
||||||
@ -207,9 +206,9 @@ pub mod tests {
|
|||||||
let resp_recycler = BlobRecycler::default();
|
let resp_recycler = BlobRecycler::default();
|
||||||
let (s_reader, r_reader) = channel();
|
let (s_reader, r_reader) = channel();
|
||||||
let t_receiver = streamer::blob_receiver(
|
let t_receiver = streamer::blob_receiver(
|
||||||
|
Arc::new(target2.sockets.replicate),
|
||||||
exit.clone(),
|
exit.clone(),
|
||||||
recv_recycler.clone(),
|
recv_recycler.clone(),
|
||||||
target2.sockets.replicate,
|
|
||||||
s_reader,
|
s_reader,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
|
|
||||||
@ -217,7 +216,7 @@ pub mod tests {
|
|||||||
let (s_responder, r_responder) = channel();
|
let (s_responder, r_responder) = channel();
|
||||||
let t_responder = streamer::responder(
|
let t_responder = streamer::responder(
|
||||||
"test_replicate",
|
"test_replicate",
|
||||||
leader.sockets.requests,
|
Arc::new(leader.sockets.requests),
|
||||||
resp_recycler.clone(),
|
resp_recycler.clone(),
|
||||||
r_responder,
|
r_responder,
|
||||||
);
|
);
|
||||||
|
@ -232,7 +232,7 @@ pub mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use bank::Bank;
|
use bank::Bank;
|
||||||
use bincode::deserialize;
|
use bincode::deserialize;
|
||||||
use crdt::{Crdt, NodeInfo, TestNode};
|
use crdt::{Crdt, Node, NodeInfo};
|
||||||
use entry::next_entry;
|
use entry::next_entry;
|
||||||
use hash::{hash, Hash};
|
use hash::{hash, Hash};
|
||||||
use logger;
|
use logger;
|
||||||
@ -253,7 +253,7 @@ pub mod tests {
|
|||||||
let mint = Mint::new(1234);
|
let mint = Mint::new(1234);
|
||||||
let bank = Arc::new(Bank::new(&mint));
|
let bank = Arc::new(Bank::new(&mint));
|
||||||
|
|
||||||
let node = TestNode::new_localhost();
|
let node = Node::new_localhost();
|
||||||
let mut crdt = Crdt::new(node.data.clone()).expect("Crdt::new");
|
let mut crdt = Crdt::new(node.data.clone()).expect("Crdt::new");
|
||||||
crdt.set_leader(node.data.id);
|
crdt.set_leader(node.data.id);
|
||||||
let blob_recycler = BlobRecycler::default();
|
let blob_recycler = BlobRecycler::default();
|
||||||
|
@ -93,6 +93,8 @@ fn calculate_highest_lost_blob_index(num_peers: u64, consumed: u64, received: u6
|
|||||||
cmp::min(consumed + WINDOW_SIZE - 1, highest_lost)
|
cmp::min(consumed + WINDOW_SIZE - 1, highest_lost)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const MAX_REPAIR_BACKOFF: usize = 128;
|
||||||
|
|
||||||
fn repair_backoff(last: &mut u64, times: &mut usize, consumed: u64) -> bool {
|
fn repair_backoff(last: &mut u64, times: &mut usize, consumed: u64) -> bool {
|
||||||
//exponential backoff
|
//exponential backoff
|
||||||
if *last != consumed {
|
if *last != consumed {
|
||||||
@ -105,9 +107,9 @@ fn repair_backoff(last: &mut u64, times: &mut usize, consumed: u64) -> bool {
|
|||||||
// Experiment with capping repair request duration.
|
// Experiment with capping repair request duration.
|
||||||
// Once nodes are too far behind they can spend many
|
// Once nodes are too far behind they can spend many
|
||||||
// seconds without asking for repair
|
// seconds without asking for repair
|
||||||
if *times > 128 {
|
if *times > MAX_REPAIR_BACKOFF {
|
||||||
// 50% chance that a request will fire between 64 - 128 tries
|
// 50% chance that a request will fire between 64 - 128 tries
|
||||||
*times = 64;
|
*times = MAX_REPAIR_BACKOFF / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if we get lucky, make the request, which should exponentially get less likely
|
//if we get lucky, make the request, which should exponentially get less likely
|
||||||
@ -126,6 +128,7 @@ fn repair_window(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
//exponential backoff
|
//exponential backoff
|
||||||
if !repair_backoff(last, times, consumed) {
|
if !repair_backoff(last, times, consumed) {
|
||||||
|
trace!("{:x} !repair_backoff() times = {}", debug_id, times);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,7 +694,7 @@ pub fn window(
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crdt::{Crdt, TestNode};
|
use crdt::{Crdt, Node};
|
||||||
use logger;
|
use logger;
|
||||||
use packet::{Blob, BlobRecycler, Packet, PacketRecycler, Packets, PACKET_DATA_SIZE};
|
use packet::{Blob, BlobRecycler, Packet, PacketRecycler, Packets, PACKET_DATA_SIZE};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
@ -737,12 +740,17 @@ mod test {
|
|||||||
let pack_recycler = PacketRecycler::default();
|
let pack_recycler = PacketRecycler::default();
|
||||||
let resp_recycler = BlobRecycler::default();
|
let resp_recycler = BlobRecycler::default();
|
||||||
let (s_reader, r_reader) = channel();
|
let (s_reader, r_reader) = channel();
|
||||||
let t_receiver = receiver(read, exit.clone(), pack_recycler.clone(), s_reader);
|
let t_receiver = receiver(
|
||||||
|
Arc::new(read),
|
||||||
|
exit.clone(),
|
||||||
|
pack_recycler.clone(),
|
||||||
|
s_reader,
|
||||||
|
);
|
||||||
let t_responder = {
|
let t_responder = {
|
||||||
let (s_responder, r_responder) = channel();
|
let (s_responder, r_responder) = channel();
|
||||||
let t_responder = responder(
|
let t_responder = responder(
|
||||||
"streamer_send_test",
|
"streamer_send_test",
|
||||||
send,
|
Arc::new(send),
|
||||||
resp_recycler.clone(),
|
resp_recycler.clone(),
|
||||||
r_responder,
|
r_responder,
|
||||||
);
|
);
|
||||||
@ -790,7 +798,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn window_send_test() {
|
pub fn window_send_test() {
|
||||||
logger::setup();
|
logger::setup();
|
||||||
let tn = TestNode::new_localhost();
|
let tn = Node::new_localhost();
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let mut crdt_me = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
let mut crdt_me = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
||||||
let me_id = crdt_me.my_data().id;
|
let me_id = crdt_me.my_data().id;
|
||||||
@ -800,9 +808,9 @@ mod test {
|
|||||||
let resp_recycler = BlobRecycler::default();
|
let resp_recycler = BlobRecycler::default();
|
||||||
let (s_reader, r_reader) = channel();
|
let (s_reader, r_reader) = channel();
|
||||||
let t_receiver = blob_receiver(
|
let t_receiver = blob_receiver(
|
||||||
|
Arc::new(tn.sockets.gossip),
|
||||||
exit.clone(),
|
exit.clone(),
|
||||||
resp_recycler.clone(),
|
resp_recycler.clone(),
|
||||||
tn.sockets.gossip,
|
|
||||||
s_reader,
|
s_reader,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let (s_window, r_window) = channel();
|
let (s_window, r_window) = channel();
|
||||||
@ -821,7 +829,7 @@ mod test {
|
|||||||
let (s_responder, r_responder) = channel();
|
let (s_responder, r_responder) = channel();
|
||||||
let t_responder = responder(
|
let t_responder = responder(
|
||||||
"window_send_test",
|
"window_send_test",
|
||||||
tn.sockets.replicate,
|
Arc::new(tn.sockets.replicate),
|
||||||
resp_recycler.clone(),
|
resp_recycler.clone(),
|
||||||
r_responder,
|
r_responder,
|
||||||
);
|
);
|
||||||
@ -860,7 +868,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn window_send_no_leader_test() {
|
pub fn window_send_no_leader_test() {
|
||||||
logger::setup();
|
logger::setup();
|
||||||
let tn = TestNode::new_localhost();
|
let tn = Node::new_localhost();
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let crdt_me = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
let crdt_me = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
||||||
let me_id = crdt_me.my_data().id;
|
let me_id = crdt_me.my_data().id;
|
||||||
@ -869,9 +877,9 @@ mod test {
|
|||||||
let resp_recycler = BlobRecycler::default();
|
let resp_recycler = BlobRecycler::default();
|
||||||
let (s_reader, r_reader) = channel();
|
let (s_reader, r_reader) = channel();
|
||||||
let t_receiver = blob_receiver(
|
let t_receiver = blob_receiver(
|
||||||
|
Arc::new(tn.sockets.gossip),
|
||||||
exit.clone(),
|
exit.clone(),
|
||||||
resp_recycler.clone(),
|
resp_recycler.clone(),
|
||||||
tn.sockets.gossip,
|
|
||||||
s_reader,
|
s_reader,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let (s_window, _r_window) = channel();
|
let (s_window, _r_window) = channel();
|
||||||
@ -890,7 +898,7 @@ mod test {
|
|||||||
let (s_responder, r_responder) = channel();
|
let (s_responder, r_responder) = channel();
|
||||||
let t_responder = responder(
|
let t_responder = responder(
|
||||||
"window_send_test",
|
"window_send_test",
|
||||||
tn.sockets.replicate,
|
Arc::new(tn.sockets.replicate),
|
||||||
resp_recycler.clone(),
|
resp_recycler.clone(),
|
||||||
r_responder,
|
r_responder,
|
||||||
);
|
);
|
||||||
@ -922,7 +930,7 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
pub fn window_send_late_leader_test() {
|
pub fn window_send_late_leader_test() {
|
||||||
logger::setup();
|
logger::setup();
|
||||||
let tn = TestNode::new_localhost();
|
let tn = Node::new_localhost();
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let crdt_me = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
let crdt_me = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
||||||
let me_id = crdt_me.my_data().id;
|
let me_id = crdt_me.my_data().id;
|
||||||
@ -931,9 +939,9 @@ mod test {
|
|||||||
let resp_recycler = BlobRecycler::default();
|
let resp_recycler = BlobRecycler::default();
|
||||||
let (s_reader, r_reader) = channel();
|
let (s_reader, r_reader) = channel();
|
||||||
let t_receiver = blob_receiver(
|
let t_receiver = blob_receiver(
|
||||||
|
Arc::new(tn.sockets.gossip),
|
||||||
exit.clone(),
|
exit.clone(),
|
||||||
resp_recycler.clone(),
|
resp_recycler.clone(),
|
||||||
tn.sockets.gossip,
|
|
||||||
s_reader,
|
s_reader,
|
||||||
).unwrap();
|
).unwrap();
|
||||||
let (s_window, _r_window) = channel();
|
let (s_window, _r_window) = channel();
|
||||||
@ -952,7 +960,7 @@ mod test {
|
|||||||
let (s_responder, r_responder) = channel();
|
let (s_responder, r_responder) = channel();
|
||||||
let t_responder = responder(
|
let t_responder = responder(
|
||||||
"window_send_test",
|
"window_send_test",
|
||||||
tn.sockets.replicate,
|
Arc::new(tn.sockets.replicate),
|
||||||
resp_recycler.clone(),
|
resp_recycler.clone(),
|
||||||
r_responder,
|
r_responder,
|
||||||
);
|
);
|
||||||
|
@ -81,7 +81,7 @@ impl WriteStage {
|
|||||||
let send = UdpSocket::bind("0.0.0.0:0").expect("bind");
|
let send = UdpSocket::bind("0.0.0.0:0").expect("bind");
|
||||||
let t_responder = responder(
|
let t_responder = responder(
|
||||||
"write_stage_vote_sender",
|
"write_stage_vote_sender",
|
||||||
send,
|
Arc::new(send),
|
||||||
blob_recycler.clone(),
|
blob_recycler.clone(),
|
||||||
vote_blob_receiver,
|
vote_blob_receiver,
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,7 @@ extern crate rayon;
|
|||||||
extern crate solana;
|
extern crate solana;
|
||||||
|
|
||||||
use rayon::iter::*;
|
use rayon::iter::*;
|
||||||
use solana::crdt::{Crdt, TestNode};
|
use solana::crdt::{Crdt, Node};
|
||||||
use solana::logger;
|
use solana::logger;
|
||||||
use solana::ncp::Ncp;
|
use solana::ncp::Ncp;
|
||||||
use solana::packet::Blob;
|
use solana::packet::Blob;
|
||||||
@ -17,18 +17,11 @@ use std::thread::sleep;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
fn test_node(exit: Arc<AtomicBool>) -> (Arc<RwLock<Crdt>>, Ncp, UdpSocket) {
|
fn test_node(exit: Arc<AtomicBool>) -> (Arc<RwLock<Crdt>>, Ncp, UdpSocket) {
|
||||||
let tn = TestNode::new_localhost();
|
let tn = Node::new_localhost();
|
||||||
let crdt = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
let crdt = Crdt::new(tn.data.clone()).expect("Crdt::new");
|
||||||
let c = Arc::new(RwLock::new(crdt));
|
let c = Arc::new(RwLock::new(crdt));
|
||||||
let w = Arc::new(RwLock::new(vec![]));
|
let w = Arc::new(RwLock::new(vec![]));
|
||||||
let d = Ncp::new(
|
let d = Ncp::new(&c.clone(), w, None, tn.sockets.gossip, exit).unwrap();
|
||||||
&c.clone(),
|
|
||||||
w,
|
|
||||||
None,
|
|
||||||
tn.sockets.gossip,
|
|
||||||
tn.sockets.gossip_send,
|
|
||||||
exit,
|
|
||||||
).unwrap();
|
|
||||||
(c, d, tn.sockets.replicate)
|
(c, d, tn.sockets.replicate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ extern crate chrono;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate solana;
|
extern crate solana;
|
||||||
|
|
||||||
use solana::crdt::{Crdt, NodeInfo, TestNode};
|
use solana::crdt::{Crdt, Node, NodeInfo};
|
||||||
use solana::entry::Entry;
|
use solana::entry::Entry;
|
||||||
use solana::fullnode::Fullnode;
|
use solana::fullnode::Fullnode;
|
||||||
use solana::hash::Hash;
|
use solana::hash::Hash;
|
||||||
@ -32,7 +32,7 @@ use std::time::{Duration, Instant};
|
|||||||
fn converge(leader: &NodeInfo, num_nodes: usize) -> Vec<NodeInfo> {
|
fn converge(leader: &NodeInfo, num_nodes: usize) -> Vec<NodeInfo> {
|
||||||
//lets spy on the network
|
//lets spy on the network
|
||||||
let exit = Arc::new(AtomicBool::new(false));
|
let exit = Arc::new(AtomicBool::new(false));
|
||||||
let mut spy = TestNode::new_localhost();
|
let mut spy = Node::new_localhost();
|
||||||
let daddr = "0.0.0.0:0".parse().unwrap();
|
let daddr = "0.0.0.0:0".parse().unwrap();
|
||||||
let me = spy.data.id.clone();
|
let me = spy.data.id.clone();
|
||||||
spy.data.contact_info.tvu = daddr;
|
spy.data.contact_info.tvu = daddr;
|
||||||
@ -42,14 +42,7 @@ fn converge(leader: &NodeInfo, num_nodes: usize) -> Vec<NodeInfo> {
|
|||||||
spy_crdt.set_leader(leader.id);
|
spy_crdt.set_leader(leader.id);
|
||||||
let spy_ref = Arc::new(RwLock::new(spy_crdt));
|
let spy_ref = Arc::new(RwLock::new(spy_crdt));
|
||||||
let spy_window = default_window();
|
let spy_window = default_window();
|
||||||
let ncp = Ncp::new(
|
let ncp = Ncp::new(&spy_ref, spy_window, None, spy.sockets.gossip, exit.clone()).unwrap();
|
||||||
&spy_ref,
|
|
||||||
spy_window,
|
|
||||||
None,
|
|
||||||
spy.sockets.gossip,
|
|
||||||
spy.sockets.gossip_send,
|
|
||||||
exit.clone(),
|
|
||||||
).unwrap();
|
|
||||||
//wait for the network to converge
|
//wait for the network to converge
|
||||||
let mut converged = false;
|
let mut converged = false;
|
||||||
let mut rv = vec![];
|
let mut rv = vec![];
|
||||||
@ -125,7 +118,7 @@ fn test_multi_node_ledger_window() -> result::Result<()> {
|
|||||||
|
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader_pubkey = leader_keypair.pubkey().clone();
|
let leader_pubkey = leader_keypair.pubkey().clone();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
let leader_data = leader.data.clone();
|
let leader_data = leader.data.clone();
|
||||||
let bob_pubkey = Keypair::new().pubkey();
|
let bob_pubkey = Keypair::new().pubkey();
|
||||||
let mut ledger_paths = Vec::new();
|
let mut ledger_paths = Vec::new();
|
||||||
@ -156,7 +149,7 @@ fn test_multi_node_ledger_window() -> result::Result<()> {
|
|||||||
// start up another validator from zero, converge and then check
|
// start up another validator from zero, converge and then check
|
||||||
// balances
|
// balances
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
let validator = TestNode::new_localhost_with_pubkey(keypair.pubkey());
|
let validator = Node::new_localhost_with_pubkey(keypair.pubkey());
|
||||||
let validator_data = validator.data.clone();
|
let validator_data = validator.data.clone();
|
||||||
let validator = Fullnode::new(
|
let validator = Fullnode::new(
|
||||||
validator,
|
validator,
|
||||||
@ -205,7 +198,7 @@ fn test_multi_node_validator_catchup_from_zero() -> result::Result<()> {
|
|||||||
trace!("test_multi_node_validator_catchup_from_zero");
|
trace!("test_multi_node_validator_catchup_from_zero");
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader_pubkey = leader_keypair.pubkey().clone();
|
let leader_pubkey = leader_keypair.pubkey().clone();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
let leader_data = leader.data.clone();
|
let leader_data = leader.data.clone();
|
||||||
let bob_pubkey = Keypair::new().pubkey();
|
let bob_pubkey = Keypair::new().pubkey();
|
||||||
let mut ledger_paths = Vec::new();
|
let mut ledger_paths = Vec::new();
|
||||||
@ -229,7 +222,7 @@ fn test_multi_node_validator_catchup_from_zero() -> result::Result<()> {
|
|||||||
let mut nodes = vec![server];
|
let mut nodes = vec![server];
|
||||||
for _ in 0..N {
|
for _ in 0..N {
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
let validator = TestNode::new_localhost_with_pubkey(keypair.pubkey());
|
let validator = Node::new_localhost_with_pubkey(keypair.pubkey());
|
||||||
let ledger_path = tmp_copy_ledger(
|
let ledger_path = tmp_copy_ledger(
|
||||||
&leader_ledger_path,
|
&leader_ledger_path,
|
||||||
"multi_node_validator_catchup_from_zero_validator",
|
"multi_node_validator_catchup_from_zero_validator",
|
||||||
@ -270,7 +263,7 @@ fn test_multi_node_validator_catchup_from_zero() -> result::Result<()> {
|
|||||||
// start up another validator from zero, converge and then check everyone's
|
// start up another validator from zero, converge and then check everyone's
|
||||||
// balances
|
// balances
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
let validator = TestNode::new_localhost_with_pubkey(keypair.pubkey());
|
let validator = Node::new_localhost_with_pubkey(keypair.pubkey());
|
||||||
let val = Fullnode::new(
|
let val = Fullnode::new(
|
||||||
validator,
|
validator,
|
||||||
&zero_ledger_path,
|
&zero_ledger_path,
|
||||||
@ -329,7 +322,7 @@ fn test_multi_node_basic() {
|
|||||||
trace!("test_multi_node_basic");
|
trace!("test_multi_node_basic");
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader_pubkey = leader_keypair.pubkey().clone();
|
let leader_pubkey = leader_keypair.pubkey().clone();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
let leader_data = leader.data.clone();
|
let leader_data = leader.data.clone();
|
||||||
let bob_pubkey = Keypair::new().pubkey();
|
let bob_pubkey = Keypair::new().pubkey();
|
||||||
let mut ledger_paths = Vec::new();
|
let mut ledger_paths = Vec::new();
|
||||||
@ -346,7 +339,7 @@ fn test_multi_node_basic() {
|
|||||||
let mut nodes = vec![server];
|
let mut nodes = vec![server];
|
||||||
for _ in 0..N {
|
for _ in 0..N {
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
let validator = TestNode::new_localhost_with_pubkey(keypair.pubkey());
|
let validator = Node::new_localhost_with_pubkey(keypair.pubkey());
|
||||||
let ledger_path = tmp_copy_ledger(&leader_ledger_path, "multi_node_basic");
|
let ledger_path = tmp_copy_ledger(&leader_ledger_path, "multi_node_basic");
|
||||||
ledger_paths.push(ledger_path.clone());
|
ledger_paths.push(ledger_path.clone());
|
||||||
let val = Fullnode::new(
|
let val = Fullnode::new(
|
||||||
@ -390,7 +383,7 @@ fn test_multi_node_basic() {
|
|||||||
fn test_boot_validator_from_file() -> result::Result<()> {
|
fn test_boot_validator_from_file() -> result::Result<()> {
|
||||||
logger::setup();
|
logger::setup();
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
let bob_pubkey = Keypair::new().pubkey();
|
let bob_pubkey = Keypair::new().pubkey();
|
||||||
let (alice, leader_ledger_path) = genesis("boot_validator_from_file", 100_000);
|
let (alice, leader_ledger_path) = genesis("boot_validator_from_file", 100_000);
|
||||||
let mut ledger_paths = Vec::new();
|
let mut ledger_paths = Vec::new();
|
||||||
@ -406,7 +399,7 @@ fn test_boot_validator_from_file() -> result::Result<()> {
|
|||||||
assert_eq!(leader_balance, 1000);
|
assert_eq!(leader_balance, 1000);
|
||||||
|
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
let validator = TestNode::new_localhost_with_pubkey(keypair.pubkey());
|
let validator = Node::new_localhost_with_pubkey(keypair.pubkey());
|
||||||
let validator_data = validator.data.clone();
|
let validator_data = validator.data.clone();
|
||||||
let ledger_path = tmp_copy_ledger(&leader_ledger_path, "boot_validator_from_file");
|
let ledger_path = tmp_copy_ledger(&leader_ledger_path, "boot_validator_from_file");
|
||||||
ledger_paths.push(ledger_path.clone());
|
ledger_paths.push(ledger_path.clone());
|
||||||
@ -432,7 +425,7 @@ fn test_boot_validator_from_file() -> result::Result<()> {
|
|||||||
|
|
||||||
fn create_leader(ledger_path: &str) -> (NodeInfo, Fullnode) {
|
fn create_leader(ledger_path: &str) -> (NodeInfo, Fullnode) {
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
let leader_data = leader.data.clone();
|
let leader_data = leader.data.clone();
|
||||||
let leader_fullnode = Fullnode::new(leader, &ledger_path, leader_keypair, None, false);
|
let leader_fullnode = Fullnode::new(leader, &ledger_path, leader_keypair, None, false);
|
||||||
(leader_data, leader_fullnode)
|
(leader_data, leader_fullnode)
|
||||||
@ -445,7 +438,10 @@ fn test_leader_restart_validator_start_from_old_ledger() -> result::Result<()> {
|
|||||||
// ledger (currently up to WINDOW_SIZE entries)
|
// ledger (currently up to WINDOW_SIZE entries)
|
||||||
logger::setup();
|
logger::setup();
|
||||||
|
|
||||||
let (alice, ledger_path) = genesis("leader_restart_validator_start_from_old_ledger", 100_000);
|
let (alice, ledger_path) = genesis(
|
||||||
|
"leader_restart_validator_start_from_old_ledger",
|
||||||
|
100_000 + 500 * solana::window::MAX_REPAIR_BACKOFF as i64,
|
||||||
|
);
|
||||||
let bob_pubkey = Keypair::new().pubkey();
|
let bob_pubkey = Keypair::new().pubkey();
|
||||||
|
|
||||||
let (leader_data, leader_fullnode) = create_leader(&ledger_path);
|
let (leader_data, leader_fullnode) = create_leader(&ledger_path);
|
||||||
@ -476,7 +472,7 @@ fn test_leader_restart_validator_start_from_old_ledger() -> result::Result<()> {
|
|||||||
|
|
||||||
// start validator from old ledger
|
// start validator from old ledger
|
||||||
let keypair = Keypair::new();
|
let keypair = Keypair::new();
|
||||||
let validator = TestNode::new_localhost_with_pubkey(keypair.pubkey());
|
let validator = Node::new_localhost_with_pubkey(keypair.pubkey());
|
||||||
let validator_data = validator.data.clone();
|
let validator_data = validator.data.clone();
|
||||||
|
|
||||||
let val_fullnode = Fullnode::new(
|
let val_fullnode = Fullnode::new(
|
||||||
@ -492,15 +488,17 @@ fn test_leader_restart_validator_start_from_old_ledger() -> result::Result<()> {
|
|||||||
// send requests so the validator eventually sees a gap and requests a repair
|
// send requests so the validator eventually sees a gap and requests a repair
|
||||||
let mut expected = 1500;
|
let mut expected = 1500;
|
||||||
let mut client = mk_client(&validator_data);
|
let mut client = mk_client(&validator_data);
|
||||||
for _ in 0..10 {
|
for _ in 0..solana::window::MAX_REPAIR_BACKOFF {
|
||||||
let leader_balance =
|
let leader_balance =
|
||||||
send_tx_and_retry_get_balance(&leader_data, &alice, &bob_pubkey, Some(expected))
|
send_tx_and_retry_get_balance(&leader_data, &alice, &bob_pubkey, Some(expected))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(leader_balance, expected);
|
assert_eq!(leader_balance, expected);
|
||||||
|
|
||||||
let getbal = retry_get_balance(&mut client, &bob_pubkey, Some(leader_balance));
|
let getbal = retry_get_balance(&mut client, &bob_pubkey, Some(leader_balance));
|
||||||
if getbal == Some(leader_balance) {
|
if getbal == Some(leader_balance) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
expected += 500;
|
expected += 500;
|
||||||
}
|
}
|
||||||
let getbal = retry_get_balance(&mut client, &bob_pubkey, Some(expected));
|
let getbal = retry_get_balance(&mut client, &bob_pubkey, Some(expected));
|
||||||
@ -530,7 +528,7 @@ fn test_multi_node_dynamic_network() {
|
|||||||
|
|
||||||
let leader_keypair = Keypair::new();
|
let leader_keypair = Keypair::new();
|
||||||
let leader_pubkey = leader_keypair.pubkey().clone();
|
let leader_pubkey = leader_keypair.pubkey().clone();
|
||||||
let leader = TestNode::new_localhost_with_pubkey(leader_keypair.pubkey());
|
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||||
let bob_pubkey = Keypair::new().pubkey();
|
let bob_pubkey = Keypair::new().pubkey();
|
||||||
let (alice, leader_ledger_path) = genesis("multi_node_dynamic_network", 10_000_000);
|
let (alice, leader_ledger_path) = genesis("multi_node_dynamic_network", 10_000_000);
|
||||||
|
|
||||||
@ -605,7 +603,7 @@ fn test_multi_node_dynamic_network() {
|
|||||||
Builder::new()
|
Builder::new()
|
||||||
.name("validator-launch-thread".to_string())
|
.name("validator-launch-thread".to_string())
|
||||||
.spawn(move || {
|
.spawn(move || {
|
||||||
let validator = TestNode::new_localhost_with_pubkey(keypair.pubkey());
|
let validator = Node::new_localhost_with_pubkey(keypair.pubkey());
|
||||||
let rd = validator.data.clone();
|
let rd = validator.data.clone();
|
||||||
info!("starting {} {:x}", keypair.pubkey(), rd.debug_id());
|
info!("starting {} {:x}", keypair.pubkey(), rd.debug_id());
|
||||||
let val = Fullnode::new(
|
let val = Fullnode::new(
|
||||||
|
Reference in New Issue
Block a user