Drone now returns signed airdrop transactions
This commit is contained in:
parent
3543a9a49f
commit
e791d0f74d
|
@ -10,7 +10,7 @@ solana-keygen -o /config/drone-keypair.json
|
|||
solana-fullnode-config --keypair=/config/leader-keypair.json -l > /config/leader-config.json
|
||||
solana-genesis --num_tokens 1000000000 --mint /config/drone-keypair.json --bootstrap_leader /config/leader-config.json --ledger /ledger
|
||||
|
||||
solana-drone --keypair /config/drone-keypair.json --network 127.0.0.1:8001 &
|
||||
solana-drone --keypair /config/drone-keypair.json &
|
||||
drone=$!
|
||||
solana-fullnode --identity /config/leader-config.json --ledger /ledger/ --rpc 8899 &
|
||||
fullnode=$!
|
||||
|
|
|
@ -12,16 +12,13 @@ usage() {
|
|||
echo "$*"
|
||||
echo
|
||||
fi
|
||||
echo "usage: $0 [network entry point]"
|
||||
echo "usage: $0]"
|
||||
echo
|
||||
echo " Run an airdrop drone for the specified network"
|
||||
echo " Run an airdrop drone"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
read -r _ leader_address shift < <(find_leader "${@:1:1}")
|
||||
shift "$shift"
|
||||
|
||||
[[ -f "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json ]] || {
|
||||
echo "$SOLANA_CONFIG_PRIVATE_DIR/mint.json not found, create it by running:"
|
||||
echo
|
||||
|
@ -34,7 +31,6 @@ set -ex
|
|||
trap 'kill "$pid" && wait "$pid"' INT TERM
|
||||
$solana_drone \
|
||||
--keypair "$SOLANA_CONFIG_PRIVATE_DIR"/mint.json \
|
||||
--network "$leader_address" \
|
||||
> >($drone_logger) 2>&1 &
|
||||
pid=$!
|
||||
wait "$pid"
|
||||
|
|
|
@ -16,7 +16,7 @@ use rand::{thread_rng, Rng};
|
|||
use rayon::prelude::*;
|
||||
use solana::client::mk_client;
|
||||
use solana::cluster_info::{ClusterInfo, NodeInfo};
|
||||
use solana::drone::DRONE_PORT;
|
||||
use solana::drone::{request_airdrop_transaction, DRONE_PORT};
|
||||
use solana::hash::Hash;
|
||||
use solana::logger;
|
||||
use solana::metrics;
|
||||
|
@ -28,7 +28,6 @@ use solana::thin_client::{poll_gossip_for_leader, ThinClient};
|
|||
use solana::timing::timestamp;
|
||||
use solana::timing::{duration_as_ms, duration_as_s};
|
||||
use solana::transaction::Transaction;
|
||||
use solana::wallet::request_airdrop;
|
||||
use solana::window::default_window;
|
||||
use std::cmp;
|
||||
use std::collections::VecDeque;
|
||||
|
@ -393,27 +392,26 @@ fn airdrop_tokens(client: &mut ThinClient, leader: &NodeInfo, id: &Keypair, tx_c
|
|||
id.pubkey(),
|
||||
);
|
||||
|
||||
if let Err(e) = request_airdrop(&drone_addr, &id.pubkey(), airdrop_amount as u64) {
|
||||
let last_id = client.get_last_id();
|
||||
match request_airdrop_transaction(&drone_addr, &id.pubkey(), airdrop_amount, last_id) {
|
||||
Ok(transaction) => {
|
||||
let signature = client.transfer_signed(&transaction).unwrap();
|
||||
client.poll_for_signature(&signature).unwrap();
|
||||
}
|
||||
Err(err) => {
|
||||
panic!(
|
||||
"Error requesting airdrop: {:?} to addr: {:?} amount: {}",
|
||||
e, drone_addr, airdrop_amount
|
||||
err, drone_addr, airdrop_amount
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: return airdrop Result from Drone instead of polling the
|
||||
// network
|
||||
let mut current_balance = starting_balance;
|
||||
for _ in 0..20 {
|
||||
sleep(Duration::from_millis(500));
|
||||
current_balance = client.poll_get_balance(&id.pubkey()).unwrap_or_else(|e| {
|
||||
let current_balance = client.poll_get_balance(&id.pubkey()).unwrap_or_else(|e| {
|
||||
println!("airdrop error {}", e);
|
||||
starting_balance
|
||||
});
|
||||
if starting_balance != current_balance {
|
||||
break;
|
||||
}
|
||||
println!("current balance {}...", current_balance);
|
||||
}
|
||||
|
||||
metrics_submit_token_balance(current_balance);
|
||||
if current_balance - starting_balance != airdrop_amount {
|
||||
println!(
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
extern crate bincode;
|
||||
extern crate byteorder;
|
||||
extern crate bytes;
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
|
@ -9,6 +10,7 @@ extern crate tokio;
|
|||
extern crate tokio_codec;
|
||||
|
||||
use bincode::{deserialize, serialize};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use bytes::Bytes;
|
||||
use clap::{App, Arg};
|
||||
use solana::drone::{Drone, DroneRequest, DRONE_PORT};
|
||||
|
@ -18,7 +20,6 @@ use solana::signature::read_keypair;
|
|||
use std::error;
|
||||
use std::io;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::process::exit;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use tokio::net::TcpListener;
|
||||
|
@ -41,14 +42,6 @@ fn main() -> Result<(), Box<error::Error>> {
|
|||
let matches = App::new("drone")
|
||||
.version(crate_version!())
|
||||
.arg(
|
||||
Arg::with_name("network")
|
||||
.short("n")
|
||||
.long("network")
|
||||
.value_name("HOST:PORT")
|
||||
.takes_value(true)
|
||||
.required(true)
|
||||
.help("Rendezvous with the network at this gossip entry point"),
|
||||
).arg(
|
||||
Arg::with_name("keypair")
|
||||
.short("k")
|
||||
.long("keypair")
|
||||
|
@ -70,15 +63,6 @@ fn main() -> Result<(), Box<error::Error>> {
|
|||
.help("Request limit for time slice"),
|
||||
).get_matches();
|
||||
|
||||
let network = matches
|
||||
.value_of("network")
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap_or_else(|e| {
|
||||
eprintln!("failed to parse network: {}", e);
|
||||
exit(1)
|
||||
});
|
||||
|
||||
let mint_keypair =
|
||||
read_keypair(matches.value_of("keypair").unwrap()).expect("failed to read client keypair");
|
||||
|
||||
|
@ -99,8 +83,6 @@ fn main() -> Result<(), Box<error::Error>> {
|
|||
|
||||
let drone = Arc::new(Mutex::new(Drone::new(
|
||||
mint_keypair,
|
||||
drone_addr,
|
||||
network,
|
||||
time_slice,
|
||||
request_cap,
|
||||
)));
|
||||
|
@ -131,23 +113,34 @@ fn main() -> Result<(), Box<error::Error>> {
|
|||
))
|
||||
})?;
|
||||
|
||||
println!("Airdrop requested...");
|
||||
println!("Airdrop transaction requested...{:?}", req);
|
||||
// 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"),
|
||||
}
|
||||
let response = res1?;
|
||||
println!("Airdrop tx signature: {:?}", response);
|
||||
let response_vec = serialize(&response).or_else(|err| {
|
||||
let res = drone2.lock().unwrap().build_airdrop_transaction(req);
|
||||
match res {
|
||||
Ok(tx) => {
|
||||
let response_vec = serialize(&tx).or_else(|err| {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("serialize signature in drone: {:?}", err),
|
||||
format!("deserialize packet in drone: {:?}", err),
|
||||
))
|
||||
})?;
|
||||
let response_bytes = Bytes::from(response_vec.clone());
|
||||
|
||||
let mut response_vec_with_length = vec![0; 2];
|
||||
LittleEndian::write_u16(
|
||||
&mut response_vec_with_length,
|
||||
response_vec.len() as u16,
|
||||
);
|
||||
response_vec_with_length.extend_from_slice(&response_vec);
|
||||
|
||||
let response_bytes = Bytes::from(response_vec_with_length);
|
||||
println!("Airdrop transaction granted");
|
||||
Ok(response_bytes)
|
||||
}
|
||||
Err(err) => {
|
||||
println!("Airdrop transaction failed: {:?}", err);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
});
|
||||
let server = writer
|
||||
.send_all(processor.or_else(|err| {
|
||||
|
|
|
@ -10,7 +10,7 @@ extern crate solana;
|
|||
use clap::{App, Arg};
|
||||
use solana::client::mk_client;
|
||||
use solana::cluster_info::{Node, FULLNODE_PORT_RANGE};
|
||||
use solana::drone::DRONE_PORT;
|
||||
use solana::drone::{request_airdrop_transaction, DRONE_PORT};
|
||||
use solana::fullnode::{Config, Fullnode, FullnodeReturnType};
|
||||
use solana::leader_scheduler::LeaderScheduler;
|
||||
use solana::logger;
|
||||
|
@ -19,7 +19,6 @@ use solana::netutil::find_available_port_in_range;
|
|||
use solana::signature::{Keypair, KeypairUtil};
|
||||
use solana::thin_client::poll_gossip_for_leader;
|
||||
use solana::vote_program::VoteProgram;
|
||||
use solana::wallet::request_airdrop;
|
||||
use std::fs::File;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::process::exit;
|
||||
|
@ -159,9 +158,14 @@ fn main() {
|
|||
|
||||
info!("requesting airdrop from {}", drone_addr);
|
||||
loop {
|
||||
if request_airdrop(&drone_addr, &pubkey, 50).is_ok() {
|
||||
let last_id = client.get_last_id();
|
||||
if let Ok(transaction) = request_airdrop_transaction(&drone_addr, &pubkey, 50, last_id)
|
||||
{
|
||||
let signature = client.transfer_signed(&transaction).unwrap();
|
||||
if client.poll_for_signature(&signature).is_ok() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
info!(
|
||||
"airdrop request, is the drone address correct {:?}, drone running?",
|
||||
drone_addr
|
||||
|
|
|
@ -9,7 +9,7 @@ use clap::{App, Arg};
|
|||
use solana::chacha::{chacha_cbc_encrypt_file, CHACHA_BLOCK_SIZE};
|
||||
use solana::client::mk_client;
|
||||
use solana::cluster_info::Node;
|
||||
use solana::drone::DRONE_PORT;
|
||||
use solana::drone::{request_airdrop_transaction, DRONE_PORT};
|
||||
use solana::fullnode::Config;
|
||||
use solana::ledger::LEDGER_DATA_FILE;
|
||||
use solana::logger;
|
||||
|
@ -17,7 +17,6 @@ use solana::replicator::{sample_file, Replicator};
|
|||
use solana::signature::{Keypair, KeypairUtil};
|
||||
use solana::storage_transaction::StorageTransaction;
|
||||
use solana::transaction::Transaction;
|
||||
use solana::wallet::request_airdrop;
|
||||
use std::fs::File;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::path::Path;
|
||||
|
@ -132,9 +131,12 @@ fn main() {
|
|||
let mut drone_addr = leader_info.tpu;
|
||||
drone_addr.set_port(DRONE_PORT);
|
||||
let airdrop_amount = 5;
|
||||
if let Err(e) = request_airdrop(&drone_addr, &keypair.pubkey(), airdrop_amount) {
|
||||
panic!("couldn't get airdrop {}: {}!", airdrop_amount, e);
|
||||
}
|
||||
let last_id = client.get_last_id();
|
||||
let transaction =
|
||||
request_airdrop_transaction(&drone_addr, &keypair.pubkey(), airdrop_amount, last_id)
|
||||
.unwrap();
|
||||
let signature = client.transfer_signed(&transaction).unwrap();
|
||||
client.poll_for_signature(&signature).unwrap();
|
||||
|
||||
match sample_file(&ledger_data_file_encrypted, &sampling_offsets) {
|
||||
Ok(hash) => {
|
||||
|
|
192
src/drone.rs
192
src/drone.rs
|
@ -5,20 +5,22 @@
|
|||
//! and (to come) an IP rate limit.
|
||||
|
||||
use bincode::{deserialize, serialize};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
use bytes::Bytes;
|
||||
use hash::Hash;
|
||||
use influx_db_client as influxdb;
|
||||
use metrics;
|
||||
use signature::{Keypair, Signature};
|
||||
use packet::PACKET_DATA_SIZE;
|
||||
use signature::Keypair;
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::io;
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream};
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use system_transaction::SystemTransaction;
|
||||
use thin_client::{poll_gossip_for_leader, ThinClient};
|
||||
use tokio;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio::prelude::*;
|
||||
|
@ -32,16 +34,15 @@ pub const DRONE_PORT: u16 = 9900;
|
|||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||
pub enum DroneRequest {
|
||||
GetAirdrop {
|
||||
airdrop_request_amount: u64,
|
||||
client_pubkey: Pubkey,
|
||||
tokens: u64,
|
||||
to: Pubkey,
|
||||
last_id: Hash,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct Drone {
|
||||
mint_keypair: Keypair,
|
||||
ip_cache: Vec<IpAddr>,
|
||||
_airdrop_addr: SocketAddr,
|
||||
network_addr: SocketAddr,
|
||||
pub time_slice: Duration,
|
||||
request_cap: u64,
|
||||
pub request_current: u64,
|
||||
|
@ -50,8 +51,6 @@ pub struct Drone {
|
|||
impl Drone {
|
||||
pub fn new(
|
||||
mint_keypair: Keypair,
|
||||
_airdrop_addr: SocketAddr,
|
||||
network_addr: SocketAddr,
|
||||
time_input: Option<u64>,
|
||||
request_cap_input: Option<u64>,
|
||||
) -> Drone {
|
||||
|
@ -66,8 +65,6 @@ impl Drone {
|
|||
Drone {
|
||||
mint_keypair,
|
||||
ip_cache: Vec::new(),
|
||||
_airdrop_addr,
|
||||
network_addr,
|
||||
time_slice,
|
||||
request_cap,
|
||||
request_current: 0,
|
||||
|
@ -102,53 +99,40 @@ impl Drone {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn send_airdrop(&mut self, req: DroneRequest) -> Result<Signature, io::Error> {
|
||||
let request_amount: u64;
|
||||
let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
|
||||
let leader = poll_gossip_for_leader(self.network_addr, Some(10))
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?;
|
||||
|
||||
let mut client = ThinClient::new(leader.rpc, leader.tpu, transactions_socket);
|
||||
let last_id = client.get_last_id();
|
||||
|
||||
let mut tx = match req {
|
||||
pub fn build_airdrop_transaction(
|
||||
&mut self,
|
||||
req: DroneRequest,
|
||||
) -> Result<Transaction, io::Error> {
|
||||
trace!("build_airdrop_transaction: {:?}", req);
|
||||
match req {
|
||||
DroneRequest::GetAirdrop {
|
||||
airdrop_request_amount,
|
||||
client_pubkey,
|
||||
} => {
|
||||
info!(
|
||||
"Requesting airdrop of {} to {:?}",
|
||||
airdrop_request_amount, client_pubkey
|
||||
);
|
||||
request_amount = airdrop_request_amount;
|
||||
Transaction::system_new(
|
||||
&self.mint_keypair,
|
||||
client_pubkey,
|
||||
airdrop_request_amount as u64,
|
||||
tokens,
|
||||
to,
|
||||
last_id,
|
||||
)
|
||||
}
|
||||
};
|
||||
if self.check_request_limit(request_amount) {
|
||||
self.request_current += request_amount;
|
||||
} => {
|
||||
if self.check_request_limit(tokens) {
|
||||
self.request_current += tokens;
|
||||
metrics::submit(
|
||||
influxdb::Point::new("drone")
|
||||
.add_tag("op", influxdb::Value::String("airdrop".to_string()))
|
||||
.add_field("request_amount", influxdb::Value::Integer(tokens as i64))
|
||||
.add_field(
|
||||
"request_amount",
|
||||
influxdb::Value::Integer(request_amount as i64),
|
||||
).add_field(
|
||||
"request_current",
|
||||
influxdb::Value::Integer(self.request_current as i64),
|
||||
).to_owned(),
|
||||
);
|
||||
client.retry_transfer(&self.mint_keypair, &mut tx, 10)
|
||||
|
||||
info!("Requesting airdrop of {} to {:?}", tokens, to);
|
||||
let mut tx = Transaction::system_new(&self.mint_keypair, to, tokens, last_id);
|
||||
tx.sign(&[&self.mint_keypair], last_id);
|
||||
Ok(tx)
|
||||
} else {
|
||||
Err(Error::new(ErrorKind::Other, "token limit reached"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Drone {
|
||||
fn drop(&mut self) {
|
||||
|
@ -156,16 +140,67 @@ impl Drop for Drone {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn run_local_drone(mint_keypair: Keypair, network: SocketAddr, sender: Sender<SocketAddr>) {
|
||||
pub fn request_airdrop_transaction(
|
||||
drone_addr: &SocketAddr,
|
||||
id: &Pubkey,
|
||||
tokens: u64,
|
||||
last_id: Hash,
|
||||
) -> Result<Transaction, Error> {
|
||||
// TODO: make this async tokio client
|
||||
let mut stream = TcpStream::connect_timeout(drone_addr, Duration::new(3, 0))?;
|
||||
stream.set_read_timeout(Some(Duration::new(10, 0)))?;
|
||||
let req = DroneRequest::GetAirdrop {
|
||||
tokens,
|
||||
last_id,
|
||||
to: *id,
|
||||
};
|
||||
let req = serialize(&req).expect("serialize drone request");
|
||||
stream.write_all(&req)?;
|
||||
|
||||
// Read length of transaction
|
||||
let mut buffer = [0; 2];
|
||||
stream.read_exact(&mut buffer).or_else(|err| {
|
||||
info!(
|
||||
"request_airdrop_transaction: buffer length read_exact error: {:?}",
|
||||
err
|
||||
);
|
||||
Err(Error::new(ErrorKind::Other, "Airdrop failed"))
|
||||
})?;
|
||||
let transaction_length = LittleEndian::read_u16(&buffer) as usize;
|
||||
if transaction_length >= PACKET_DATA_SIZE {
|
||||
Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"request_airdrop_transaction: invalid transaction_length from drone: {}",
|
||||
transaction_length
|
||||
),
|
||||
))?;
|
||||
}
|
||||
|
||||
// Read the transaction
|
||||
let mut buffer = Vec::new();
|
||||
buffer.resize(transaction_length, 0);
|
||||
stream.read_exact(&mut buffer).or_else(|err| {
|
||||
info!(
|
||||
"request_airdrop_transaction: buffer read_exact error: {:?}",
|
||||
err
|
||||
);
|
||||
Err(Error::new(ErrorKind::Other, "Airdrop failed"))
|
||||
})?;
|
||||
|
||||
let transaction: Transaction = deserialize(&buffer).or_else(|err| {
|
||||
Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("request_airdrop_transaction deserialize failure: {:?}", err),
|
||||
))
|
||||
})?;
|
||||
Ok(transaction)
|
||||
}
|
||||
|
||||
pub fn run_local_drone(mint_keypair: Keypair, sender: Sender<SocketAddr>) {
|
||||
thread::spawn(move || {
|
||||
let drone_addr = socketaddr!(0, 0);
|
||||
let drone = Arc::new(Mutex::new(Drone::new(
|
||||
mint_keypair,
|
||||
drone_addr,
|
||||
network,
|
||||
None,
|
||||
None,
|
||||
)));
|
||||
let drone = Arc::new(Mutex::new(Drone::new(mint_keypair, None, None)));
|
||||
let socket = TcpListener::bind(&drone_addr).unwrap();
|
||||
sender.send(socket.local_addr().unwrap()).unwrap();
|
||||
info!("Drone started. Listening on: {}", drone_addr);
|
||||
|
@ -186,12 +221,13 @@ pub fn run_local_drone(mint_keypair: Keypair, network: SocketAddr, sender: Sende
|
|||
})?;
|
||||
|
||||
info!("Airdrop requested...");
|
||||
let res1 = drone2.lock().unwrap().send_airdrop(req);
|
||||
match res1 {
|
||||
let res = drone2.lock().unwrap().build_airdrop_transaction(req);
|
||||
match res {
|
||||
Ok(_) => info!("Airdrop sent!"),
|
||||
Err(_) => info!("Request limit reached for this time slice"),
|
||||
}
|
||||
let response = res1?;
|
||||
let response = res?;
|
||||
|
||||
info!("Airdrop tx signature: {:?}", response);
|
||||
let response_vec = serialize(&response).or_else(|err| {
|
||||
Err(io::Error::new(
|
||||
|
@ -199,7 +235,20 @@ pub fn run_local_drone(mint_keypair: Keypair, network: SocketAddr, sender: Sende
|
|||
format!("serialize signature in drone: {:?}", err),
|
||||
))
|
||||
})?;
|
||||
let response_bytes = Bytes::from(response_vec.clone());
|
||||
|
||||
let mut response_vec_with_length = vec![0; 2];
|
||||
LittleEndian::write_u16(
|
||||
&mut response_vec_with_length,
|
||||
response_vec.len() as u16,
|
||||
);
|
||||
info!(
|
||||
"Airdrop response_vec_with_length: {:?}",
|
||||
response_vec_with_length
|
||||
);
|
||||
response_vec_with_length.extend_from_slice(&response_vec);
|
||||
|
||||
let response_bytes = Bytes::from(response_vec_with_length.clone());
|
||||
info!("Airdrop response_bytes: {:?}", response_bytes);
|
||||
Ok(response_bytes)
|
||||
});
|
||||
let server = writer
|
||||
|
@ -238,8 +287,7 @@ mod tests {
|
|||
let keypair = Keypair::new();
|
||||
let mut addr: SocketAddr = "0.0.0.0:9900".parse().unwrap();
|
||||
addr.set_ip(get_ip_addr().unwrap());
|
||||
let network_addr = "0.0.0.0:0".parse().unwrap();
|
||||
let mut drone = Drone::new(keypair, addr, network_addr, None, Some(3));
|
||||
let mut drone = Drone::new(keypair, None, Some(3));
|
||||
assert!(drone.check_request_limit(1));
|
||||
drone.request_current = 3;
|
||||
assert!(!drone.check_request_limit(1));
|
||||
|
@ -250,8 +298,7 @@ mod tests {
|
|||
let keypair = Keypair::new();
|
||||
let mut addr: SocketAddr = "0.0.0.0:9900".parse().unwrap();
|
||||
addr.set_ip(get_ip_addr().unwrap());
|
||||
let network_addr = "0.0.0.0:0".parse().unwrap();
|
||||
let mut drone = Drone::new(keypair, addr, network_addr, None, None);
|
||||
let mut drone = Drone::new(keypair, None, None);
|
||||
drone.request_current = drone.request_current + 256;
|
||||
assert_eq!(drone.request_current, 256);
|
||||
drone.clear_request_count();
|
||||
|
@ -263,8 +310,7 @@ mod tests {
|
|||
let keypair = Keypair::new();
|
||||
let mut addr: SocketAddr = "0.0.0.0:9900".parse().unwrap();
|
||||
addr.set_ip(get_ip_addr().unwrap());
|
||||
let network_addr = "0.0.0.0:0".parse().unwrap();
|
||||
let mut drone = Drone::new(keypair, addr, network_addr, None, None);
|
||||
let mut drone = Drone::new(keypair, None, None);
|
||||
let ip = "127.0.0.1".parse().expect("create IpAddr from string");
|
||||
assert_eq!(drone.ip_cache.len(), 0);
|
||||
drone.add_ip_to_cache(ip);
|
||||
|
@ -277,8 +323,7 @@ mod tests {
|
|||
let keypair = Keypair::new();
|
||||
let mut addr: SocketAddr = "0.0.0.0:9900".parse().unwrap();
|
||||
addr.set_ip(get_ip_addr().unwrap());
|
||||
let network_addr = "0.0.0.0:0".parse().unwrap();
|
||||
let mut drone = Drone::new(keypair, addr, network_addr, None, None);
|
||||
let mut drone = Drone::new(keypair, None, None);
|
||||
let ip = "127.0.0.1".parse().expect("create IpAddr from string");
|
||||
assert_eq!(drone.ip_cache.len(), 0);
|
||||
drone.add_ip_to_cache(ip);
|
||||
|
@ -293,10 +338,9 @@ mod tests {
|
|||
let keypair = Keypair::new();
|
||||
let mut addr: SocketAddr = "0.0.0.0:9900".parse().unwrap();
|
||||
addr.set_ip(get_ip_addr().unwrap());
|
||||
let network_addr = "0.0.0.0:0".parse().unwrap();
|
||||
let time_slice: Option<u64> = None;
|
||||
let request_cap: Option<u64> = None;
|
||||
let drone = Drone::new(keypair, addr, network_addr, time_slice, request_cap);
|
||||
let drone = Drone::new(keypair, time_slice, request_cap);
|
||||
assert_eq!(drone.time_slice, Duration::new(TIME_SLICE, 0));
|
||||
assert_eq!(drone.request_cap, REQUEST_CAP);
|
||||
}
|
||||
|
@ -339,7 +383,7 @@ mod tests {
|
|||
|
||||
let mut addr: SocketAddr = "0.0.0.0:9900".parse().expect("bind to drone socket");
|
||||
addr.set_ip(get_ip_addr().expect("drone get_ip_addr"));
|
||||
let mut drone = Drone::new(alice.keypair(), addr, leader_data.ncp, None, Some(150_000));
|
||||
let mut drone = Drone::new(alice.keypair(), None, Some(150_000));
|
||||
|
||||
let transactions_socket =
|
||||
UdpSocket::bind("0.0.0.0:0").expect("drone bind to transactions socket");
|
||||
|
@ -347,10 +391,12 @@ mod tests {
|
|||
let mut client = ThinClient::new(leader_data.rpc, leader_data.tpu, transactions_socket);
|
||||
|
||||
let bob_req = DroneRequest::GetAirdrop {
|
||||
airdrop_request_amount: 50,
|
||||
client_pubkey: bob_pubkey,
|
||||
tokens: 50,
|
||||
to: bob_pubkey,
|
||||
last_id,
|
||||
};
|
||||
let bob_sig = drone.send_airdrop(bob_req).unwrap();
|
||||
let bob_tx = drone.build_airdrop_transaction(bob_req).unwrap();
|
||||
let bob_sig = client.transfer_signed(&bob_tx).unwrap();
|
||||
assert!(client.poll_for_signature(&bob_sig).is_ok());
|
||||
|
||||
// restart the leader, drone should find the new one at the same gossip port
|
||||
|
@ -376,12 +422,14 @@ mod tests {
|
|||
let mut client = ThinClient::new(leader_data.rpc, leader_data.tpu, transactions_socket);
|
||||
|
||||
let carlos_req = DroneRequest::GetAirdrop {
|
||||
airdrop_request_amount: 5_000_000,
|
||||
client_pubkey: carlos_pubkey,
|
||||
tokens: 5_000_000,
|
||||
to: carlos_pubkey,
|
||||
last_id,
|
||||
};
|
||||
|
||||
// using existing drone, new thin client
|
||||
let carlos_sig = drone.send_airdrop(carlos_req).unwrap();
|
||||
let carlos_tx = drone.build_airdrop_transaction(carlos_req).unwrap();
|
||||
let carlos_sig = client.transfer_signed(&carlos_tx).unwrap();
|
||||
assert!(client.poll_for_signature(&carlos_sig).is_ok());
|
||||
|
||||
let bob_balance = client.get_balance(&bob_pubkey);
|
||||
|
|
36
src/rpc.rs
36
src/rpc.rs
|
@ -1,10 +1,10 @@
|
|||
//! The `rpc` module implements the Solana RPC interface.
|
||||
|
||||
use bank::{Bank, BankError};
|
||||
use bincode::deserialize;
|
||||
use bincode::{deserialize, serialize};
|
||||
use bs58;
|
||||
use cluster_info::ClusterInfo;
|
||||
use drone::DRONE_PORT;
|
||||
use drone::{request_airdrop_transaction, DRONE_PORT};
|
||||
use jsonrpc_core::*;
|
||||
use jsonrpc_http_server::*;
|
||||
use packet::PACKET_DATA_SIZE;
|
||||
|
@ -22,7 +22,6 @@ use std::thread::{self, sleep, Builder, JoinHandle};
|
|||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
use transaction::Transaction;
|
||||
use wallet::request_airdrop;
|
||||
|
||||
pub const RPC_PORT: u16 = 8899;
|
||||
|
||||
|
@ -211,17 +210,35 @@ impl RpcSol for RpcSolImpl {
|
|||
|
||||
let mut drone_addr = get_leader_addr(&meta.cluster_info)?;
|
||||
drone_addr.set_port(DRONE_PORT);
|
||||
let signature = request_airdrop(&drone_addr, &pubkey, tokens).map_err(|err| {
|
||||
info!("request_airdrop failed: {:?}", err);
|
||||
let last_id = meta.request_processor.bank.last_id();
|
||||
let transaction = request_airdrop_transaction(&drone_addr, &pubkey, tokens, last_id)
|
||||
.map_err(|err| {
|
||||
info!("request_airdrop_transaction failed: {:?}", err);
|
||||
Error::internal_error()
|
||||
})?;;
|
||||
|
||||
let data = serialize(&transaction).map_err(|err| {
|
||||
info!("request_airdrop: serialize error: {:?}", err);
|
||||
Error::internal_error()
|
||||
})?;
|
||||
|
||||
let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
||||
let transactions_addr = get_leader_addr(&meta.cluster_info)?;
|
||||
transactions_socket
|
||||
.send_to(&data, transactions_addr)
|
||||
.map_err(|err| {
|
||||
info!("request_airdrop: send_to error: {:?}", err);
|
||||
Error::internal_error()
|
||||
})?;
|
||||
|
||||
let signature = transaction.signatures[0];
|
||||
let now = Instant::now();
|
||||
let mut signature_status;
|
||||
loop {
|
||||
signature_status = meta.request_processor.get_signature_status(signature);
|
||||
|
||||
if signature_status.is_ok() {
|
||||
info!("airdrop signature ok");
|
||||
return Ok(bs58::encode(signature).into_string());
|
||||
} else if now.elapsed().as_secs() > 5 {
|
||||
info!("airdrop signature timeout");
|
||||
|
@ -404,7 +421,7 @@ mod tests {
|
|||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "getBalance",
|
||||
"params": vec![alice.pubkey().to_string()],
|
||||
"params": [alice.pubkey().to_string()],
|
||||
});
|
||||
let mut response = client
|
||||
.post(&rpc_string)
|
||||
|
@ -639,7 +656,7 @@ mod tests {
|
|||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "sendTransaction",
|
||||
"params": json!(vec![serial_tx])
|
||||
"params": json!([serial_tx])
|
||||
});
|
||||
let rpc_addr = leader_data.rpc;
|
||||
let rpc_string = format!("http://{}", rpc_addr.to_string());
|
||||
|
@ -659,7 +676,7 @@ mod tests {
|
|||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "confirmTransaction",
|
||||
"params": vec![signature],
|
||||
"params": [signature],
|
||||
});
|
||||
let mut response = client
|
||||
.post(&rpc_string)
|
||||
|
@ -667,7 +684,8 @@ mod tests {
|
|||
.body(request.to_string())
|
||||
.send()
|
||||
.unwrap();
|
||||
let json: Value = serde_json::from_str(&response.text().unwrap()).unwrap();
|
||||
let response_json_text = response.text().unwrap();
|
||||
let json: Value = serde_json::from_str(&response_json_text).unwrap();
|
||||
|
||||
assert_eq!(true, json["result"]);
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ impl RpcRequest {
|
|||
"method": method,
|
||||
});
|
||||
if let Some(param_string) = params {
|
||||
request["params"] = json!(vec![param_string]);
|
||||
request["params"] = param_string;
|
||||
}
|
||||
request
|
||||
}
|
||||
|
@ -99,18 +99,18 @@ mod tests {
|
|||
let test_request = RpcRequest::GetAccountInfo;
|
||||
let request = test_request.build_request_json(
|
||||
1,
|
||||
Some(json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx")),
|
||||
Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"])),
|
||||
);
|
||||
assert_eq!(request["method"], "getAccountInfo");
|
||||
assert_eq!(
|
||||
request["params"],
|
||||
json!(vec!["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"])
|
||||
json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"])
|
||||
);
|
||||
|
||||
let test_request = RpcRequest::GetBalance;
|
||||
let request = test_request.build_request_json(
|
||||
1,
|
||||
Some(json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx")),
|
||||
Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"])),
|
||||
);
|
||||
assert_eq!(request["method"], "getBalance");
|
||||
|
||||
|
@ -172,7 +172,7 @@ mod tests {
|
|||
let balance = RpcRequest::GetBalance.make_rpc_request(
|
||||
&rpc_addr,
|
||||
1,
|
||||
Some(json!("deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx")),
|
||||
Some(json!(["deadbeefXjn8o3yroDHxUtKsZZgoy4GPkPPXfouKNHhx"])),
|
||||
);
|
||||
assert!(balance.is_ok());
|
||||
assert_eq!(balance.unwrap().as_u64().unwrap(), 50);
|
||||
|
|
|
@ -143,7 +143,7 @@ impl ThinClient {
|
|||
}
|
||||
|
||||
pub fn get_account_userdata(&mut self, pubkey: &Pubkey) -> io::Result<Option<Vec<u8>>> {
|
||||
let params = json!(format!("{}", pubkey));
|
||||
let params = json!([format!("{}", pubkey)]);
|
||||
let rpc_string = format!("http://{}", self.rpc_addr.to_string());
|
||||
let resp = RpcRequest::GetAccountInfo.make_rpc_request(&rpc_string, 1, Some(params));
|
||||
if let Ok(account_json) = resp {
|
||||
|
@ -162,7 +162,7 @@ impl ThinClient {
|
|||
/// by the network, this method will hang indefinitely.
|
||||
pub fn get_balance(&mut self, pubkey: &Pubkey) -> io::Result<u64> {
|
||||
trace!("get_balance sending request to {}", self.rpc_addr);
|
||||
let params = json!(format!("{}", pubkey));
|
||||
let params = json!([format!("{}", pubkey)]);
|
||||
let rpc_string = format!("http://{}", self.rpc_addr.to_string());
|
||||
let resp = RpcRequest::GetAccountInfo.make_rpc_request(&rpc_string, 1, Some(params));
|
||||
if let Ok(account_json) = resp {
|
||||
|
@ -303,7 +303,7 @@ impl ThinClient {
|
|||
/// until the server sends a response.
|
||||
pub fn check_signature(&mut self, signature: &Signature) -> bool {
|
||||
trace!("check_signature");
|
||||
let params = json!(format!("{}", signature));
|
||||
let params = json!([format!("{}", signature)]);
|
||||
let now = Instant::now();
|
||||
let rpc_string = format!("http://{}", self.rpc_addr.to_string());
|
||||
let mut done = false;
|
||||
|
|
177
src/wallet.rs
177
src/wallet.rs
|
@ -1,11 +1,11 @@
|
|||
use bincode::{deserialize, serialize};
|
||||
use bincode::serialize;
|
||||
use bpf_loader;
|
||||
use bs58;
|
||||
use budget_program::BudgetState;
|
||||
use budget_transaction::BudgetTransaction;
|
||||
use chrono::prelude::*;
|
||||
use clap::ArgMatches;
|
||||
use drone::{DroneRequest, DRONE_PORT};
|
||||
use drone::{request_airdrop_transaction, DRONE_PORT};
|
||||
use elf;
|
||||
use fullnode::Config;
|
||||
use hash::Hash;
|
||||
|
@ -18,14 +18,10 @@ use serde_json;
|
|||
use signature::{Keypair, KeypairUtil, Signature};
|
||||
use solana_sdk::pubkey::Pubkey;
|
||||
use std::fs::{self, File};
|
||||
use std::io::prelude::*;
|
||||
use std::io::{Error, ErrorKind, Write};
|
||||
use std::mem::size_of;
|
||||
use std::net::{Ipv4Addr, SocketAddr, TcpStream};
|
||||
use std::io::Write;
|
||||
use std::net::{Ipv4Addr, SocketAddr};
|
||||
use std::path::Path;
|
||||
use std::str::FromStr;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use std::{error, fmt, mem};
|
||||
use system_transaction::SystemTransaction;
|
||||
use thin_client::poll_gossip_for_leader;
|
||||
|
@ -330,7 +326,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
|||
"Requesting airdrop of {:?} tokens from {}",
|
||||
tokens, drone_addr
|
||||
);
|
||||
let params = json!(format!("{}", config.id.pubkey()));
|
||||
let params = json!([format!("{}", config.id.pubkey())]);
|
||||
let previous_balance = match RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))?
|
||||
.as_u64()
|
||||
|
@ -340,24 +336,18 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
|||
"Received result of an unexpected type".to_string(),
|
||||
))?,
|
||||
};
|
||||
request_airdrop(&drone_addr, &config.id.pubkey(), tokens as u64)?;
|
||||
|
||||
// TODO: return airdrop Result from Drone instead of polling the
|
||||
// network
|
||||
let mut current_balance = previous_balance;
|
||||
for _ in 0..20 {
|
||||
sleep(Duration::from_millis(500));
|
||||
let params = json!(format!("{}", config.id.pubkey()));
|
||||
current_balance = RpcRequest::GetBalance
|
||||
let last_id = get_last_id(&rpc_addr)?;
|
||||
let transaction =
|
||||
request_airdrop_transaction(&drone_addr, &config.id.pubkey(), tokens, last_id)?;
|
||||
send_and_confirm_tx(&rpc_addr, &transaction)?;
|
||||
|
||||
let params = json!([format!("{}", config.id.pubkey())]);
|
||||
let current_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))?
|
||||
.as_u64()
|
||||
.unwrap_or(previous_balance);
|
||||
|
||||
if previous_balance < current_balance {
|
||||
break;
|
||||
}
|
||||
println!(".");
|
||||
}
|
||||
if current_balance - previous_balance < tokens {
|
||||
Err("Airdrop failed!")?;
|
||||
}
|
||||
|
@ -366,7 +356,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
|||
// Check client balance
|
||||
WalletCommand::Balance => {
|
||||
println!("Balance requested...");
|
||||
let params = json!(format!("{}", config.id.pubkey()));
|
||||
let params = json!([format!("{}", config.id.pubkey())]);
|
||||
let balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))?
|
||||
.as_u64();
|
||||
|
@ -388,7 +378,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
|||
}
|
||||
// Confirm the last client transaction by signature
|
||||
WalletCommand::Confirm(signature) => {
|
||||
let params = json!(format!("{}", signature));
|
||||
let params = json!([format!("{}", signature)]);
|
||||
let confirmation = RpcRequest::ConfirmTransaction
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))?
|
||||
.as_bool();
|
||||
|
@ -407,7 +397,7 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
|||
}
|
||||
// Deploy a custom program to the chain
|
||||
WalletCommand::Deploy(ref program_location) => {
|
||||
let params = json!(format!("{}", config.id.pubkey()));
|
||||
let params = json!([format!("{}", config.id.pubkey())]);
|
||||
let balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))?
|
||||
.as_u64();
|
||||
|
@ -615,8 +605,12 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
|||
let balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))?
|
||||
.as_u64();
|
||||
|
||||
if let Some(0) = balance {
|
||||
request_airdrop(&drone_addr, &config.id.pubkey(), 1)?;
|
||||
let params = json!([format!("{}", config.id.pubkey()), 1]);
|
||||
RpcRequest::RequestAirdrop
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let last_id = get_last_id(&rpc_addr)?;
|
||||
|
@ -628,16 +622,19 @@ pub fn process_command(config: &WalletConfig) -> Result<String, Box<error::Error
|
|||
}
|
||||
// Apply witness signature to contract
|
||||
WalletCommand::Witness(to, pubkey) => {
|
||||
let last_id = get_last_id(&rpc_addr)?;
|
||||
|
||||
let params = json!(format!("{}", config.id.pubkey()));
|
||||
let params = json!([format!("{}", config.id.pubkey())]);
|
||||
let balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))?
|
||||
.as_u64();
|
||||
|
||||
if let Some(0) = balance {
|
||||
request_airdrop(&drone_addr, &config.id.pubkey(), 1)?;
|
||||
let params = json!([format!("{}", config.id.pubkey()), 1]);
|
||||
RpcRequest::RequestAirdrop
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
let last_id = get_last_id(&rpc_addr)?;
|
||||
let tx = Transaction::budget_new_signature(&config.id, pubkey, to, last_id);
|
||||
let signature_str = send_tx(&rpc_addr, &tx)?;
|
||||
|
||||
|
@ -662,34 +659,6 @@ pub fn read_leader(path: &str) -> Result<Config, WalletError> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn request_airdrop(
|
||||
drone_addr: &SocketAddr,
|
||||
id: &Pubkey,
|
||||
tokens: u64,
|
||||
) -> Result<Signature, Error> {
|
||||
// TODO: make this async tokio client
|
||||
let mut stream = TcpStream::connect_timeout(drone_addr, Duration::new(3, 0))?;
|
||||
stream.set_read_timeout(Some(Duration::new(10, 0)))?;
|
||||
let req = DroneRequest::GetAirdrop {
|
||||
airdrop_request_amount: tokens,
|
||||
client_pubkey: *id,
|
||||
};
|
||||
let tx = serialize(&req).expect("serialize drone request");
|
||||
stream.write_all(&tx)?;
|
||||
let mut buffer = [0; size_of::<Signature>()];
|
||||
stream.read_exact(&mut buffer).or_else(|err| {
|
||||
info!("request_airdrop: read_exact error: {:?}", err);
|
||||
Err(Error::new(ErrorKind::Other, "Airdrop failed"))
|
||||
})?;
|
||||
let signature: Signature = deserialize(&buffer).or_else(|err| {
|
||||
Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!("deserialize signature in request_airdrop: {:?}", err),
|
||||
))
|
||||
})?;
|
||||
Ok(signature)
|
||||
}
|
||||
|
||||
pub fn gen_keypair_file(outfile: String) -> Result<String, Box<error::Error>> {
|
||||
let rnd = SystemRandom::new();
|
||||
let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rnd)?;
|
||||
|
@ -721,7 +690,7 @@ fn get_last_id(rpc_addr: &str) -> Result<Hash, Box<error::Error>> {
|
|||
|
||||
fn send_tx(rpc_addr: &str, tx: &Transaction) -> Result<String, Box<error::Error>> {
|
||||
let serialized = serialize(tx).unwrap();
|
||||
let params = json!(serialized);
|
||||
let params = json!([serialized]);
|
||||
let signature = RpcRequest::SendTransaction.make_rpc_request(&rpc_addr, 2, Some(params))?;
|
||||
if signature.as_str().is_none() {
|
||||
Err(WalletError::RpcRequestError(
|
||||
|
@ -732,7 +701,7 @@ fn send_tx(rpc_addr: &str, tx: &Transaction) -> Result<String, Box<error::Error>
|
|||
}
|
||||
|
||||
fn confirm_tx(rpc_addr: &str, signature: &str) -> Result<RpcSignatureStatus, Box<error::Error>> {
|
||||
let params = json!(signature.to_string());
|
||||
let params = json!([signature.to_string()]);
|
||||
let signature_status =
|
||||
RpcRequest::GetSignatureStatus.make_rpc_request(&rpc_addr, 1, Some(params))?;
|
||||
if let Some(status) = signature_status.as_str() {
|
||||
|
@ -799,6 +768,8 @@ mod tests {
|
|||
use std::fs::remove_dir_all;
|
||||
use std::sync::mpsc::channel;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
#[test]
|
||||
fn test_wallet_parse_command() {
|
||||
|
@ -1114,7 +1085,6 @@ mod tests {
|
|||
assert!(parse_command(pubkey, &test_bad_timestamp).is_err());
|
||||
}
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_wallet_process_command() {
|
||||
let bob_pubkey = Keypair::new().pubkey();
|
||||
|
||||
|
@ -1147,7 +1117,7 @@ mod tests {
|
|||
sleep(Duration::from_millis(900));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_drone(alice.keypair(), leader_data.ncp, sender);
|
||||
run_local_drone(alice.keypair(), sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let mut config = WalletConfig::default();
|
||||
|
@ -1189,8 +1159,6 @@ mod tests {
|
|||
}
|
||||
#[test]
|
||||
fn test_wallet_request_airdrop() {
|
||||
let bob_pubkey = Keypair::new().pubkey();
|
||||
|
||||
let leader_keypair = Arc::new(Keypair::new());
|
||||
let leader = Node::new_localhost_with_pubkey(leader_keypair.pubkey());
|
||||
let leader_data = leader.info.clone();
|
||||
|
@ -1220,20 +1188,25 @@ mod tests {
|
|||
sleep(Duration::from_millis(900));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_drone(alice.keypair(), leader_data.ncp, sender);
|
||||
run_local_drone(alice.keypair(), sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_addr = format!("http://{}", leader_data.rpc.to_string());
|
||||
let mut bob_config = WalletConfig::default();
|
||||
bob_config.network = leader_data.ncp;
|
||||
bob_config.drone_port = Some(drone_addr.port());
|
||||
bob_config.command = WalletCommand::AirDrop(50);
|
||||
|
||||
let signature = request_airdrop(&drone_addr, &bob_pubkey, 50);
|
||||
assert!(signature.is_ok());
|
||||
let params = json!(format!("{}", signature.unwrap()));
|
||||
let confirmation = RpcRequest::ConfirmTransaction
|
||||
let sig_response = process_command(&bob_config);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let rpc_addr = format!("http://{}", leader_data.rpc.to_string());
|
||||
let params = json!([format!("{}", bob_config.id.pubkey())]);
|
||||
let balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_bool()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert!(confirmation);
|
||||
assert_eq!(balance, 50);
|
||||
|
||||
server.close().unwrap();
|
||||
remove_dir_all(ledger_path).unwrap();
|
||||
|
@ -1295,7 +1268,7 @@ mod tests {
|
|||
sleep(Duration::from_millis(900));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_drone(alice.keypair(), leader_data.ncp, sender);
|
||||
run_local_drone(alice.keypair(), sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_addr = format!("http://{}", leader_data.rpc.to_string());
|
||||
|
@ -1310,7 +1283,11 @@ mod tests {
|
|||
|
||||
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
||||
|
||||
let _signature = request_airdrop(&drone_addr, &config_payer.id.pubkey(), 50);
|
||||
let last_id = get_last_id(&rpc_addr).unwrap();
|
||||
let transaction =
|
||||
request_airdrop_transaction(&drone_addr, &config_payer.id.pubkey(), 50, last_id)
|
||||
.unwrap();
|
||||
send_and_confirm_tx(&rpc_addr, &transaction).unwrap();
|
||||
|
||||
// Make transaction (from config_payer to bob_pubkey) requiring timestamp from config_witness
|
||||
let date_string = "\"2018-09-19T17:30:59Z\"";
|
||||
|
@ -1333,21 +1310,21 @@ mod tests {
|
|||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
let params = json!(format!("{}", config_payer.id.pubkey()));
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
let config_payer_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(config_payer_balance, 39);
|
||||
let params = json!(format!("{}", process_id));
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
let contract_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(contract_balance, 11);
|
||||
let params = json!(format!("{}", bob_pubkey));
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
let recipient_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
|
@ -1360,21 +1337,21 @@ mod tests {
|
|||
let sig_response = process_command(&config_witness);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let params = json!(format!("{}", config_payer.id.pubkey()));
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
let config_payer_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(config_payer_balance, 39);
|
||||
let params = json!(format!("{}", process_id));
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
let contract_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(contract_balance, 1);
|
||||
let params = json!(format!("{}", bob_pubkey));
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
let recipient_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
|
@ -1419,14 +1396,18 @@ mod tests {
|
|||
sleep(Duration::from_millis(900));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_drone(alice.keypair(), leader_data.ncp, sender);
|
||||
run_local_drone(alice.keypair(), sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_addr = format!("http://{}", leader_data.rpc.to_string());
|
||||
|
||||
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
||||
|
||||
let _signature = request_airdrop(&drone_addr, &config_payer.id.pubkey(), 50);
|
||||
let last_id = get_last_id(&rpc_addr).unwrap();
|
||||
let transaction =
|
||||
request_airdrop_transaction(&drone_addr, &config_payer.id.pubkey(), 50, last_id)
|
||||
.unwrap();
|
||||
send_and_confirm_tx(&rpc_addr, &transaction).unwrap();
|
||||
|
||||
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
||||
config_payer.command = WalletCommand::Pay(
|
||||
|
@ -1447,21 +1428,21 @@ mod tests {
|
|||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
let params = json!(format!("{}", config_payer.id.pubkey()));
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
let config_payer_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(config_payer_balance, 39);
|
||||
let params = json!(format!("{}", process_id));
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
let contract_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(contract_balance, 11);
|
||||
let params = json!(format!("{}", bob_pubkey));
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
let recipient_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
|
@ -1474,21 +1455,21 @@ mod tests {
|
|||
let sig_response = process_command(&config_witness);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let params = json!(format!("{}", config_payer.id.pubkey()));
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
let config_payer_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(config_payer_balance, 39);
|
||||
let params = json!(format!("{}", process_id));
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
let contract_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(contract_balance, 1);
|
||||
let params = json!(format!("{}", bob_pubkey));
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
let recipient_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
|
@ -1532,7 +1513,7 @@ mod tests {
|
|||
sleep(Duration::from_millis(900));
|
||||
|
||||
let (sender, receiver) = channel();
|
||||
run_local_drone(alice.keypair(), leader_data.ncp, sender);
|
||||
run_local_drone(alice.keypair(), sender);
|
||||
let drone_addr = receiver.recv().unwrap();
|
||||
|
||||
let rpc_addr = format!("http://{}", leader_data.rpc.to_string());
|
||||
|
@ -1547,7 +1528,11 @@ mod tests {
|
|||
|
||||
assert_ne!(config_payer.id.pubkey(), config_witness.id.pubkey());
|
||||
|
||||
let _signature = request_airdrop(&drone_addr, &config_payer.id.pubkey(), 50);
|
||||
let last_id = get_last_id(&rpc_addr).unwrap();
|
||||
let transaction =
|
||||
request_airdrop_transaction(&drone_addr, &config_payer.id.pubkey(), 50, last_id)
|
||||
.unwrap();
|
||||
send_and_confirm_tx(&rpc_addr, &transaction).unwrap();
|
||||
|
||||
// Make transaction (from config_payer to bob_pubkey) requiring witness signature from config_witness
|
||||
config_payer.command = WalletCommand::Pay(
|
||||
|
@ -1568,21 +1553,21 @@ mod tests {
|
|||
.expect("base58-encoded public key");
|
||||
let process_id = Pubkey::new(&process_id_vec);
|
||||
|
||||
let params = json!(format!("{}", config_payer.id.pubkey()));
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
let config_payer_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(config_payer_balance, 39);
|
||||
let params = json!(format!("{}", process_id));
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
let contract_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(contract_balance, 11);
|
||||
let params = json!(format!("{}", bob_pubkey));
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
let recipient_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
|
@ -1595,21 +1580,21 @@ mod tests {
|
|||
let sig_response = process_command(&config_payer);
|
||||
assert!(sig_response.is_ok());
|
||||
|
||||
let params = json!(format!("{}", config_payer.id.pubkey()));
|
||||
let params = json!([format!("{}", config_payer.id.pubkey())]);
|
||||
let config_payer_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(config_payer_balance, 49);
|
||||
let params = json!(format!("{}", process_id));
|
||||
let params = json!([format!("{}", process_id)]);
|
||||
let contract_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
.as_u64()
|
||||
.unwrap();
|
||||
assert_eq!(contract_balance, 1);
|
||||
let params = json!(format!("{}", bob_pubkey));
|
||||
let params = json!([format!("{}", bob_pubkey)]);
|
||||
let recipient_balance = RpcRequest::GetBalance
|
||||
.make_rpc_request(&rpc_addr, 1, Some(params))
|
||||
.unwrap()
|
||||
|
|
Loading…
Reference in New Issue