Use a Mint to configure the wallet
* Send transactions from the mint's private key * By default, send full balance to oneself * By default, request the mint's number of tokens for airdrops
This commit is contained in:
committed by
Greg Fitzgerald
parent
c05416e27d
commit
7878a011eb
@ -1,18 +1,20 @@
|
|||||||
|
extern crate atty;
|
||||||
extern crate bincode;
|
extern crate bincode;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate getopts;
|
extern crate getopts;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate solana;
|
extern crate solana;
|
||||||
|
|
||||||
|
use atty::{is, Stream};
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use getopts::Options;
|
use getopts::Options;
|
||||||
use solana::crdt::{get_ip_addr, ReplicatedData};
|
use solana::crdt::{get_ip_addr, ReplicatedData};
|
||||||
use solana::drone::DroneRequest;
|
use solana::drone::DroneRequest;
|
||||||
use solana::signature::{KeyPair, KeyPairUtil, PublicKey};
|
use solana::mint::Mint;
|
||||||
use solana::thin_client::ThinClient;
|
use solana::thin_client::ThinClient;
|
||||||
use solana::transaction::Transaction;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream, UdpSocket};
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr, TcpStream, UdpSocket};
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
@ -28,8 +30,25 @@ fn print_usage(program: &str, opts: Options) {
|
|||||||
print!("{}", opts.usage(&brief));
|
print!("{}", opts.usage(&brief));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() -> io::Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
if is(Stream::Stdin) {
|
||||||
|
eprintln!("nothing found on stdin, expected a json file");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buffer = String::new();
|
||||||
|
let num_bytes = io::stdin().read_to_string(&mut buffer).unwrap();
|
||||||
|
if num_bytes == 0 {
|
||||||
|
eprintln!("empty file on stdin, expected a json file");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let id: Mint = serde_json::from_str(&buffer).unwrap_or_else(|e| {
|
||||||
|
eprintln!("failed to parse json: {}", e);
|
||||||
|
exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
let mut opts = Options::new();
|
let mut opts = Options::new();
|
||||||
opts.optopt("l", "", "leader", "leader.json");
|
opts.optopt("l", "", "leader", "leader.json");
|
||||||
opts.optopt("c", "", "client port", "port");
|
opts.optopt("c", "", "client port", "port");
|
||||||
@ -46,7 +65,7 @@ fn main() {
|
|||||||
if matches.opt_present("h") {
|
if matches.opt_present("h") {
|
||||||
let program = args[0].clone();
|
let program = args[0].clone();
|
||||||
print_usage(&program, opts);
|
print_usage(&program, opts);
|
||||||
return;
|
return Ok(());
|
||||||
}
|
}
|
||||||
let mut client_addr: SocketAddr = "0.0.0.0:8100".parse().unwrap();
|
let mut client_addr: SocketAddr = "0.0.0.0:8100".parse().unwrap();
|
||||||
if matches.opt_present("c") {
|
if matches.opt_present("c") {
|
||||||
@ -63,15 +82,11 @@ fn main() {
|
|||||||
ReplicatedData::new_leader(&server_addr)
|
ReplicatedData::new_leader(&server_addr)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut client = mk_client(&client_addr, &leader);
|
let mut client = mk_client(&client_addr, &leader)?;
|
||||||
let mut drone_addr = leader.transactions_addr.clone();
|
let mut drone_addr = leader.transactions_addr.clone();
|
||||||
drone_addr.set_port(9900);
|
drone_addr.set_port(9900);
|
||||||
|
|
||||||
// Start the demo, generate a random client keypair, and show user possible commands
|
// Start the a, generate a random client keypair, and show user possible commands
|
||||||
println!("Generating keypair...");
|
|
||||||
let client_keypair = KeyPair::new();
|
|
||||||
let client_pubkey = client_keypair.pubkey();
|
|
||||||
println!("Your public key is: {:?}", client_pubkey);
|
|
||||||
display_actions();
|
display_actions();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -82,7 +97,7 @@ fn main() {
|
|||||||
// Check client balance
|
// Check client balance
|
||||||
"balance" => {
|
"balance" => {
|
||||||
println!("Balance requested...");
|
println!("Balance requested...");
|
||||||
let balance = client.poll_get_balance(&client_pubkey);
|
let balance = client.poll_get_balance(&id.pubkey());
|
||||||
match balance {
|
match balance {
|
||||||
Ok(balance) => {
|
Ok(balance) => {
|
||||||
println!("Your balance is: {:?}", balance);
|
println!("Your balance is: {:?}", balance);
|
||||||
@ -99,31 +114,27 @@ fn main() {
|
|||||||
// Request amount is set in request_airdrop function
|
// Request amount is set in request_airdrop function
|
||||||
"airdrop" => {
|
"airdrop" => {
|
||||||
println!("Airdrop requested...");
|
println!("Airdrop requested...");
|
||||||
let _airdrop = request_airdrop(&drone_addr, &client_pubkey);
|
let _airdrop = request_airdrop(&drone_addr, &id);
|
||||||
// TODO: return airdrop Result from Drone
|
// TODO: return airdrop Result from Drone
|
||||||
sleep(Duration::from_millis(100));
|
sleep(Duration::from_millis(100));
|
||||||
println!(
|
println!(
|
||||||
"Your balance is: {:?}",
|
"Your balance is: {:?}",
|
||||||
client.poll_get_balance(&client_pubkey).unwrap()
|
client.poll_get_balance(&id.pubkey()).unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// If client has positive balance, spend tokens in {balance} number of transactions
|
// If client has positive balance, spend tokens in {balance} number of transactions
|
||||||
"pay" => {
|
"pay" => {
|
||||||
let last_id = client.get_last_id();
|
let last_id = client.get_last_id();
|
||||||
let balance = client.poll_get_balance(&client_pubkey);
|
let balance = client.poll_get_balance(&id.pubkey());
|
||||||
match balance {
|
match balance {
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
println!("You don't have any tokens!");
|
println!("You don't have any tokens!");
|
||||||
}
|
}
|
||||||
Ok(balance) => {
|
Ok(balance) => {
|
||||||
println!("Sending {:?} tokens to self...", balance);
|
println!("Sending {:?} tokens to self...", balance);
|
||||||
let tx = Transaction::new(
|
let sig =
|
||||||
&client_keypair,
|
client.transfer(balance, &id.keypair(), id.pubkey(), &last_id);
|
||||||
client_pubkey,
|
println!("Sent transaction! Signature: {:?}", sig);
|
||||||
balance,
|
|
||||||
last_id,
|
|
||||||
);
|
|
||||||
client.transfer_signed(tx.clone()).unwrap();
|
|
||||||
}
|
}
|
||||||
Err(ref e) if e.kind() == std::io::ErrorKind::Other => {
|
Err(ref e) if e.kind() == std::io::ErrorKind::Other => {
|
||||||
println!("No account found! Request an airdrop to get started.");
|
println!("No account found! Request an airdrop to get started.");
|
||||||
@ -158,30 +169,28 @@ fn read_leader(path: String) -> ReplicatedData {
|
|||||||
serde_json::from_reader(file).expect(&format!("failed to parse {}", path))
|
serde_json::from_reader(file).expect(&format!("failed to parse {}", path))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mk_client(client_addr: &SocketAddr, r: &ReplicatedData) -> ThinClient {
|
fn mk_client(client_addr: &SocketAddr, r: &ReplicatedData) -> io::Result<ThinClient> {
|
||||||
let mut addr = client_addr.clone();
|
let mut addr = client_addr.clone();
|
||||||
let port = addr.port();
|
let port = addr.port();
|
||||||
let transactions_socket = UdpSocket::bind(addr.clone()).unwrap();
|
let transactions_socket = UdpSocket::bind(addr.clone())?;
|
||||||
addr.set_port(port + 1);
|
addr.set_port(port + 1);
|
||||||
let requests_socket = UdpSocket::bind(addr.clone()).unwrap();
|
let requests_socket = UdpSocket::bind(addr.clone())?;
|
||||||
requests_socket
|
requests_socket.set_read_timeout(Some(Duration::new(1, 0)))?;
|
||||||
.set_read_timeout(Some(Duration::new(1, 0)))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
addr.set_port(port + 2);
|
addr.set_port(port + 2);
|
||||||
ThinClient::new(
|
Ok(ThinClient::new(
|
||||||
r.requests_addr,
|
r.requests_addr,
|
||||||
requests_socket,
|
requests_socket,
|
||||||
r.transactions_addr,
|
r.transactions_addr,
|
||||||
transactions_socket,
|
transactions_socket,
|
||||||
)
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn request_airdrop(drone_addr: &SocketAddr, client_pubkey: &PublicKey) {
|
fn request_airdrop(drone_addr: &SocketAddr, id: &Mint) {
|
||||||
let mut stream = TcpStream::connect(drone_addr).unwrap();
|
let mut stream = TcpStream::connect(drone_addr).unwrap();
|
||||||
let req = DroneRequest::GetAirdrop {
|
let req = DroneRequest::GetAirdrop {
|
||||||
airdrop_request_amount: 50,
|
airdrop_request_amount: id.tokens as u64,
|
||||||
client_public_key: *client_pubkey,
|
client_public_key: id.pubkey(),
|
||||||
};
|
};
|
||||||
let tx = serialize(&req).expect("serialize drone request");
|
let tx = serialize(&req).expect("serialize drone request");
|
||||||
stream.write_all(&tx).unwrap();
|
stream.write_all(&tx).unwrap();
|
||||||
|
Reference in New Issue
Block a user