2018-06-19 21:40:44 -07:00
|
|
|
extern crate bincode;
|
2018-08-06 20:51:12 -07:00
|
|
|
#[macro_use]
|
2018-07-04 13:23:25 -07:00
|
|
|
extern crate clap;
|
2018-06-19 21:40:44 -07:00
|
|
|
extern crate serde_json;
|
|
|
|
extern crate solana;
|
|
|
|
extern crate tokio;
|
|
|
|
extern crate tokio_codec;
|
|
|
|
|
|
|
|
use bincode::deserialize;
|
2018-07-04 13:23:25 -07:00
|
|
|
use clap::{App, Arg};
|
2018-08-17 14:34:50 -07:00
|
|
|
use solana::crdt::{Crdt, NodeInfo, TestNode};
|
2018-07-18 12:38:18 -07:00
|
|
|
use solana::drone::{Drone, DroneRequest, DRONE_PORT};
|
2018-07-05 12:01:40 -07:00
|
|
|
use solana::fullnode::Config;
|
2018-07-27 21:37:53 -07:00
|
|
|
use solana::logger;
|
2018-07-17 10:48:46 -07:00
|
|
|
use solana::metrics::set_panic_hook;
|
2018-08-17 14:34:50 -07:00
|
|
|
use solana::ncp::Ncp;
|
|
|
|
use solana::service::Service;
|
2018-07-12 15:02:14 -07:00
|
|
|
use solana::signature::read_keypair;
|
2018-06-24 00:37:18 -07:00
|
|
|
use std::fs::File;
|
|
|
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
2018-08-17 14:34:50 -07:00
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
|
|
|
use std::sync::{Arc, Mutex, RwLock};
|
2018-06-19 23:49:54 -07:00
|
|
|
use std::thread;
|
2018-06-19 21:40:44 -07:00
|
|
|
use tokio::net::TcpListener;
|
|
|
|
use tokio::prelude::*;
|
2018-06-19 23:49:54 -07:00
|
|
|
use tokio_codec::{BytesCodec, Decoder};
|
2018-06-19 21:40:44 -07:00
|
|
|
|
|
|
|
fn main() {
|
2018-07-27 21:37:53 -07:00
|
|
|
logger::setup();
|
2018-07-17 11:00:01 -07:00
|
|
|
set_panic_hook("drone");
|
|
|
|
let matches = App::new("drone")
|
2018-08-06 20:51:12 -07:00
|
|
|
.version(crate_version!())
|
2018-07-04 13:23:25 -07:00
|
|
|
.arg(
|
|
|
|
Arg::with_name("leader")
|
|
|
|
.short("l")
|
|
|
|
.long("leader")
|
|
|
|
.value_name("PATH")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("/path/to/leader.json"),
|
|
|
|
)
|
|
|
|
.arg(
|
2018-07-12 15:02:14 -07:00
|
|
|
Arg::with_name("keypair")
|
|
|
|
.short("k")
|
|
|
|
.long("keypair")
|
2018-07-04 13:23:25 -07:00
|
|
|
.value_name("PATH")
|
|
|
|
.takes_value(true)
|
2018-07-12 15:02:14 -07:00
|
|
|
.required(true)
|
2018-07-04 13:23:25 -07:00
|
|
|
.help("/path/to/mint.json"),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("time")
|
|
|
|
.short("t")
|
|
|
|
.long("time")
|
|
|
|
.value_name("SECONDS")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("time slice over which to limit requests to drone"),
|
|
|
|
)
|
|
|
|
.arg(
|
|
|
|
Arg::with_name("cap")
|
|
|
|
.short("c")
|
|
|
|
.long("cap")
|
|
|
|
.value_name("NUMBER")
|
|
|
|
.takes_value(true)
|
|
|
|
.help("request limit for time slice"),
|
|
|
|
)
|
|
|
|
.get_matches();
|
|
|
|
|
2018-07-11 00:18:48 -07:00
|
|
|
let leader: NodeInfo;
|
2018-07-04 13:23:25 -07:00
|
|
|
if let Some(l) = matches.value_of("leader") {
|
2018-07-11 12:32:54 -07:00
|
|
|
leader = read_leader(l).node_info;
|
2018-07-04 13:23:25 -07:00
|
|
|
} else {
|
|
|
|
let server_addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8000);
|
2018-07-11 00:18:48 -07:00
|
|
|
leader = NodeInfo::new_leader(&server_addr);
|
2018-07-04 13:23:25 -07:00
|
|
|
};
|
|
|
|
|
2018-07-12 15:02:14 -07:00
|
|
|
let mint_keypair =
|
|
|
|
read_keypair(matches.value_of("keypair").expect("keypair")).expect("client keypair");
|
|
|
|
|
2018-06-19 21:40:44 -07:00
|
|
|
let time_slice: Option<u64>;
|
2018-07-04 13:23:25 -07:00
|
|
|
if let Some(t) = matches.value_of("time") {
|
|
|
|
time_slice = Some(t.to_string().parse().expect("integer"));
|
2018-06-19 23:49:54 -07:00
|
|
|
} else {
|
2018-06-19 21:40:44 -07:00
|
|
|
time_slice = None;
|
|
|
|
}
|
|
|
|
let request_cap: Option<u64>;
|
2018-07-04 13:23:25 -07:00
|
|
|
if let Some(c) = matches.value_of("cap") {
|
|
|
|
request_cap = Some(c.to_string().parse().expect("integer"));
|
2018-06-19 23:49:54 -07:00
|
|
|
} else {
|
2018-06-19 21:40:44 -07:00
|
|
|
request_cap = None;
|
|
|
|
}
|
|
|
|
|
2018-08-17 14:34:50 -07:00
|
|
|
// Set up gossip functionality
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
|
|
|
let testnode = TestNode::new_localhost();
|
|
|
|
let extra_data = testnode.data.clone();
|
|
|
|
let crdt = Arc::new(RwLock::new(Crdt::new(extra_data).expect("Crdt::new")));
|
|
|
|
let window = Arc::new(RwLock::new(vec![]));
|
|
|
|
let ncp = Ncp::new(
|
|
|
|
&crdt.clone(),
|
|
|
|
window,
|
|
|
|
None,
|
|
|
|
testnode.sockets.gossip,
|
|
|
|
testnode.sockets.gossip_send,
|
|
|
|
exit.clone(),
|
|
|
|
).unwrap();
|
|
|
|
let leader_entry_point = NodeInfo::new_entry_point(leader.contact_info.ncp);
|
|
|
|
crdt.write().unwrap().insert(&leader_entry_point);
|
|
|
|
|
|
|
|
// Block until leader's correct contact info is received
|
|
|
|
while crdt.read().unwrap().leader_data().is_none() {}
|
|
|
|
|
|
|
|
exit.store(true, Ordering::Relaxed);
|
|
|
|
ncp.join().unwrap();
|
|
|
|
let leader = crdt.read().unwrap().leader_data().unwrap().clone();
|
|
|
|
|
2018-07-18 12:38:18 -07:00
|
|
|
let drone_addr: SocketAddr = format!("0.0.0.0:{}", DRONE_PORT).parse().unwrap();
|
2018-06-24 00:37:18 -07:00
|
|
|
|
2018-06-19 23:49:54 -07:00
|
|
|
let drone = Arc::new(Mutex::new(Drone::new(
|
|
|
|
mint_keypair,
|
|
|
|
drone_addr,
|
2018-07-09 17:55:11 -07:00
|
|
|
leader.contact_info.tpu,
|
|
|
|
leader.contact_info.rpu,
|
2018-06-19 23:49:54 -07:00
|
|
|
time_slice,
|
|
|
|
request_cap,
|
|
|
|
)));
|
|
|
|
|
|
|
|
let drone1 = drone.clone();
|
|
|
|
thread::spawn(move || loop {
|
|
|
|
let time = drone1.lock().unwrap().time_slice;
|
|
|
|
thread::sleep(time);
|
|
|
|
drone1.lock().unwrap().clear_request_count();
|
|
|
|
});
|
|
|
|
|
2018-06-19 21:40:44 -07:00
|
|
|
let socket = TcpListener::bind(&drone_addr).unwrap();
|
2018-06-19 23:49:54 -07:00
|
|
|
println!("Drone started. Listening on: {}", drone_addr);
|
2018-06-19 21:40:44 -07:00
|
|
|
let done = socket
|
|
|
|
.incoming()
|
|
|
|
.map_err(|e| println!("failed to accept socket; error = {:?}", e))
|
|
|
|
.for_each(move |socket| {
|
2018-06-19 23:49:54 -07:00
|
|
|
let drone2 = drone.clone();
|
|
|
|
// let client_ip = socket.peer_addr().expect("drone peer_addr").ip();
|
2018-06-19 21:40:44 -07:00
|
|
|
let framed = BytesCodec::new().framed(socket);
|
|
|
|
let (_writer, reader) = framed.split();
|
|
|
|
|
|
|
|
let processor = reader
|
|
|
|
.for_each(move |bytes| {
|
2018-07-29 22:20:26 -07:00
|
|
|
let req: DroneRequest = deserialize(&bytes).or_else(|err| {
|
|
|
|
use std::io;
|
|
|
|
Err(io::Error::new(
|
|
|
|
io::ErrorKind::Other,
|
|
|
|
format!("deserialize packet in drone: {:?}", err),
|
|
|
|
))
|
|
|
|
})?;
|
|
|
|
|
2018-06-19 23:49:54 -07:00
|
|
|
println!("Airdrop requested...");
|
|
|
|
// let res = drone2.lock().unwrap().check_rate_limit(client_ip);
|
|
|
|
let res1 = drone2.lock().unwrap().send_airdrop(req);
|
|
|
|
match res1 {
|
|
|
|
Ok(_) => println!("Airdrop sent!"),
|
|
|
|
Err(_) => println!("Request limit reached for this time slice"),
|
|
|
|
}
|
2018-06-19 21:40:44 -07:00
|
|
|
Ok(())
|
|
|
|
})
|
|
|
|
.then(|result| {
|
|
|
|
println!("Socket closed with result: {:?}", result);
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
tokio::spawn(processor)
|
|
|
|
});
|
|
|
|
tokio::run(done);
|
|
|
|
}
|
2018-07-11 12:32:54 -07:00
|
|
|
fn read_leader(path: &str) -> Config {
|
|
|
|
let file = File::open(path).unwrap_or_else(|_| panic!("file not found: {}", path));
|
|
|
|
serde_json::from_reader(file).unwrap_or_else(|_| panic!("failed to parse {}", path))
|
2018-06-24 00:37:18 -07:00
|
|
|
}
|