2018-05-08 17:32:50 -06:00
|
|
|
//! The `thin_client` module is a client-side object that interfaces with
|
|
|
|
//! a server-side TPU. Client code should use this object instead of writing
|
|
|
|
//! messages to the network directly. The binary encoding of its messages are
|
|
|
|
//! unstable and may change in future releases.
|
2018-02-28 14:16:50 -07:00
|
|
|
|
2018-03-28 20:13:10 -06:00
|
|
|
use bincode::{deserialize, serialize};
|
2018-03-26 22:03:26 -06:00
|
|
|
use hash::Hash;
|
2018-05-14 09:53:57 -06:00
|
|
|
use request::{Request, Response};
|
2018-03-26 22:03:26 -06:00
|
|
|
use signature::{KeyPair, PublicKey, Signature};
|
2018-04-17 18:14:53 -04:00
|
|
|
use std::collections::HashMap;
|
2018-03-28 20:13:10 -06:00
|
|
|
use std::io;
|
2018-04-28 00:31:20 -07:00
|
|
|
use std::net::{SocketAddr, UdpSocket};
|
2018-07-05 21:40:09 -07:00
|
|
|
use std::time::Instant;
|
|
|
|
use timing;
|
2018-03-26 22:03:26 -06:00
|
|
|
use transaction::Transaction;
|
2018-02-28 14:16:50 -07:00
|
|
|
|
2018-07-05 21:40:09 -07:00
|
|
|
use influx_db_client as influxdb;
|
|
|
|
use metrics;
|
|
|
|
|
2018-06-07 14:51:29 -06:00
|
|
|
/// An object for querying and sending transactions to the network.
|
2018-05-08 17:32:50 -06:00
|
|
|
pub struct ThinClient {
|
2018-05-22 09:46:52 -07:00
|
|
|
requests_addr: SocketAddr,
|
2018-07-02 13:43:33 -07:00
|
|
|
requests_socket: UdpSocket,
|
2018-05-25 15:51:41 -06:00
|
|
|
transactions_addr: SocketAddr,
|
|
|
|
transactions_socket: UdpSocket,
|
2018-04-17 18:14:53 -04:00
|
|
|
last_id: Option<Hash>,
|
2018-05-14 07:16:39 -06:00
|
|
|
transaction_count: u64,
|
2018-07-02 17:31:10 -06:00
|
|
|
balances: HashMap<PublicKey, i64>,
|
2018-06-28 18:59:02 -06:00
|
|
|
signature_status: bool,
|
2018-02-28 14:16:50 -07:00
|
|
|
}
|
|
|
|
|
2018-05-08 17:32:50 -06:00
|
|
|
impl ThinClient {
|
2018-05-12 10:53:25 -06:00
|
|
|
/// Create a new ThinClient that will interface with Rpu
|
2018-05-25 15:51:41 -06:00
|
|
|
/// over `requests_socket` and `transactions_socket`. To receive responses, the caller must bind `socket`
|
2018-05-08 17:32:50 -06:00
|
|
|
/// to a public address before invoking ThinClient methods.
|
2018-05-22 09:46:52 -07:00
|
|
|
pub fn new(
|
|
|
|
requests_addr: SocketAddr,
|
2018-07-02 13:43:33 -07:00
|
|
|
requests_socket: UdpSocket,
|
2018-05-25 15:51:41 -06:00
|
|
|
transactions_addr: SocketAddr,
|
|
|
|
transactions_socket: UdpSocket,
|
2018-05-22 09:46:52 -07:00
|
|
|
) -> Self {
|
2018-05-08 17:32:50 -06:00
|
|
|
let client = ThinClient {
|
2018-05-22 09:46:52 -07:00
|
|
|
requests_addr,
|
2018-07-02 13:43:33 -07:00
|
|
|
requests_socket,
|
2018-05-25 15:51:41 -06:00
|
|
|
transactions_addr,
|
|
|
|
transactions_socket,
|
2018-04-17 18:14:53 -04:00
|
|
|
last_id: None,
|
2018-05-14 07:16:39 -06:00
|
|
|
transaction_count: 0,
|
2018-04-17 18:14:53 -04:00
|
|
|
balances: HashMap::new(),
|
2018-06-28 18:59:02 -06:00
|
|
|
signature_status: false,
|
2018-04-17 18:41:58 -04:00
|
|
|
};
|
2018-05-08 17:32:50 -06:00
|
|
|
client
|
2018-04-17 18:14:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn recv_response(&self) -> io::Result<Response> {
|
|
|
|
let mut buf = vec![0u8; 1024];
|
2018-05-12 19:00:22 -07:00
|
|
|
trace!("start recv_from");
|
2018-07-02 13:43:33 -07:00
|
|
|
self.requests_socket.recv_from(&mut buf)?;
|
2018-05-12 19:00:22 -07:00
|
|
|
trace!("end recv_from");
|
2018-05-10 17:46:10 -07:00
|
|
|
let resp = deserialize(&buf).expect("deserialize balance in thin_client");
|
2018-04-17 18:14:53 -04:00
|
|
|
Ok(resp)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn process_response(&mut self, resp: Response) {
|
|
|
|
match resp {
|
|
|
|
Response::Balance { key, val } => {
|
2018-05-12 19:00:22 -07:00
|
|
|
trace!("Response balance {:?} {:?}", key, val);
|
2018-04-17 18:30:41 -04:00
|
|
|
self.balances.insert(key, val);
|
2018-04-17 18:14:53 -04:00
|
|
|
}
|
2018-05-14 09:35:10 -06:00
|
|
|
Response::LastId { id } => {
|
2018-06-28 12:58:33 -06:00
|
|
|
trace!("Response last_id {:?}", id);
|
2018-05-14 09:35:10 -06:00
|
|
|
self.last_id = Some(id);
|
|
|
|
}
|
2018-05-14 07:16:39 -06:00
|
|
|
Response::TransactionCount { transaction_count } => {
|
2018-06-28 12:58:33 -06:00
|
|
|
trace!("Response transaction count {:?}", transaction_count);
|
2018-05-14 07:16:39 -06:00
|
|
|
self.transaction_count = transaction_count;
|
|
|
|
}
|
2018-06-28 12:58:33 -06:00
|
|
|
Response::SignatureStatus { signature_status } => {
|
|
|
|
self.signature_status = signature_status;
|
|
|
|
match signature_status {
|
2018-06-28 18:59:02 -06:00
|
|
|
true => {
|
|
|
|
trace!("Response found signature");
|
2018-06-28 12:58:33 -06:00
|
|
|
}
|
2018-06-28 18:59:02 -06:00
|
|
|
false => {
|
2018-06-28 12:58:33 -06:00
|
|
|
trace!("Response signature not found");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-28 14:16:50 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-29 12:20:54 -06:00
|
|
|
/// Send a signed Transaction to the server for processing. This method
|
|
|
|
/// does not wait for a response.
|
2018-05-25 16:05:37 -06:00
|
|
|
pub fn transfer_signed(&self, tx: Transaction) -> io::Result<usize> {
|
|
|
|
let data = serialize(&tx).expect("serialize Transaction in pub fn transfer_signed");
|
2018-05-25 15:51:41 -06:00
|
|
|
self.transactions_socket
|
|
|
|
.send_to(&data, &self.transactions_addr)
|
2018-02-28 14:16:50 -07:00
|
|
|
}
|
|
|
|
|
2018-03-29 12:20:54 -06:00
|
|
|
/// Creates, signs, and processes a Transaction. Useful for writing unit-tests.
|
2018-02-28 14:16:50 -07:00
|
|
|
pub fn transfer(
|
2018-03-05 11:11:00 -07:00
|
|
|
&self,
|
2018-03-05 17:29:32 -07:00
|
|
|
n: i64,
|
2018-03-07 11:05:06 -07:00
|
|
|
keypair: &KeyPair,
|
2018-02-28 14:16:50 -07:00
|
|
|
to: PublicKey,
|
2018-03-06 17:36:45 -07:00
|
|
|
last_id: &Hash,
|
2018-03-01 12:23:27 -07:00
|
|
|
) -> io::Result<Signature> {
|
2018-07-05 21:40:09 -07:00
|
|
|
let now = Instant::now();
|
2018-05-25 16:05:37 -06:00
|
|
|
let tx = Transaction::new(keypair, to, n, *last_id);
|
|
|
|
let sig = tx.sig;
|
2018-07-05 21:40:09 -07:00
|
|
|
let result = self.transfer_signed(tx).map(|_| sig);
|
|
|
|
metrics::submit(
|
|
|
|
influxdb::Point::new("thinclient")
|
|
|
|
.add_tag("op", influxdb::Value::String("transfer".to_string()))
|
|
|
|
.add_field(
|
|
|
|
"duration_ms",
|
|
|
|
influxdb::Value::Integer(timing::duration_as_ms(&now.elapsed()) as i64),
|
|
|
|
)
|
|
|
|
.to_owned(),
|
|
|
|
);
|
|
|
|
result
|
2018-02-28 14:16:50 -07:00
|
|
|
}
|
|
|
|
|
2018-03-29 12:20:54 -06:00
|
|
|
/// Request the balance of the user holding `pubkey`. This method blocks
|
|
|
|
/// until the server sends a response. If the response packet is dropped
|
|
|
|
/// by the network, this method will hang indefinitely.
|
2018-05-04 11:11:39 -07:00
|
|
|
pub fn get_balance(&mut self, pubkey: &PublicKey) -> io::Result<i64> {
|
2018-05-12 19:00:22 -07:00
|
|
|
trace!("get_balance");
|
2018-02-28 14:16:50 -07:00
|
|
|
let req = Request::GetBalance { key: *pubkey };
|
2018-05-10 17:46:10 -07:00
|
|
|
let data = serialize(&req).expect("serialize GetBalance in pub fn get_balance");
|
2018-07-02 13:43:33 -07:00
|
|
|
self.requests_socket
|
2018-05-22 09:46:52 -07:00
|
|
|
.send_to(&data, &self.requests_addr)
|
2018-05-10 17:46:10 -07:00
|
|
|
.expect("buffer error in pub fn get_balance");
|
2018-04-17 18:41:58 -04:00
|
|
|
let mut done = false;
|
|
|
|
while !done {
|
2018-05-04 11:11:39 -07:00
|
|
|
let resp = self.recv_response()?;
|
2018-05-12 19:00:22 -07:00
|
|
|
trace!("recv_response {:?}", resp);
|
2018-06-04 17:17:23 -06:00
|
|
|
if let Response::Balance { key, .. } = &resp {
|
2018-04-17 18:41:58 -04:00
|
|
|
done = key == pubkey;
|
|
|
|
}
|
|
|
|
self.process_response(resp);
|
|
|
|
}
|
2018-07-02 17:31:10 -06:00
|
|
|
self.balances
|
|
|
|
.get(pubkey)
|
|
|
|
.map(|x| *x)
|
|
|
|
.ok_or(io::Error::new(io::ErrorKind::Other, "nokey"))
|
2018-03-01 12:23:27 -07:00
|
|
|
}
|
|
|
|
|
2018-05-14 07:16:39 -06:00
|
|
|
/// Request the transaction count. If the response packet is dropped by the network,
|
|
|
|
/// this method will hang.
|
2018-05-14 09:45:09 -06:00
|
|
|
pub fn transaction_count(&mut self) -> u64 {
|
|
|
|
info!("transaction_count");
|
2018-05-14 07:16:39 -06:00
|
|
|
let req = Request::GetTransactionCount;
|
|
|
|
let data =
|
|
|
|
serialize(&req).expect("serialize GetTransactionCount in pub fn transaction_count");
|
|
|
|
let mut done = false;
|
|
|
|
while !done {
|
2018-07-02 13:43:33 -07:00
|
|
|
self.requests_socket
|
2018-06-14 16:42:27 -07:00
|
|
|
.send_to(&data, &self.requests_addr)
|
|
|
|
.expect("buffer error in pub fn transaction_count");
|
|
|
|
|
|
|
|
if let Ok(resp) = self.recv_response() {
|
|
|
|
info!("recv_response {:?}", resp);
|
|
|
|
if let &Response::TransactionCount { .. } = &resp {
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
self.process_response(resp);
|
2018-05-14 07:16:39 -06:00
|
|
|
}
|
|
|
|
}
|
2018-05-14 09:43:40 -06:00
|
|
|
self.transaction_count
|
2018-05-14 07:16:39 -06:00
|
|
|
}
|
|
|
|
|
2018-04-02 09:30:10 -06:00
|
|
|
/// Request the last Entry ID from the server. This method blocks
|
2018-05-03 13:26:45 -06:00
|
|
|
/// until the server sends a response.
|
2018-05-31 13:41:42 -06:00
|
|
|
pub fn get_last_id(&mut self) -> Hash {
|
2018-06-28 12:58:33 -06:00
|
|
|
trace!("get_last_id");
|
2018-05-14 09:40:29 -06:00
|
|
|
let req = Request::GetLastId;
|
|
|
|
let data = serialize(&req).expect("serialize GetLastId in pub fn get_last_id");
|
|
|
|
let mut done = false;
|
|
|
|
while !done {
|
2018-07-02 10:22:54 -07:00
|
|
|
debug!("get_last_id send_to {}", &self.requests_addr);
|
2018-07-02 13:43:33 -07:00
|
|
|
self.requests_socket
|
2018-06-14 16:42:27 -07:00
|
|
|
.send_to(&data, &self.requests_addr)
|
|
|
|
.expect("buffer error in pub fn get_last_id");
|
|
|
|
|
2018-06-28 15:23:53 -07:00
|
|
|
match self.recv_response() {
|
|
|
|
Ok(resp) => {
|
|
|
|
if let &Response::LastId { .. } = &resp {
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
self.process_response(resp);
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
debug!("thin_client get_last_id error: {}", e);
|
2018-06-14 16:42:27 -07:00
|
|
|
}
|
2018-05-14 09:40:29 -06:00
|
|
|
}
|
|
|
|
}
|
2018-05-31 13:41:42 -06:00
|
|
|
self.last_id.expect("some last_id")
|
2018-03-05 12:48:09 -07:00
|
|
|
}
|
2018-02-28 14:16:50 -07:00
|
|
|
|
2018-05-25 21:54:20 -06:00
|
|
|
pub fn poll_get_balance(&mut self, pubkey: &PublicKey) -> io::Result<i64> {
|
|
|
|
let mut balance;
|
|
|
|
let now = Instant::now();
|
|
|
|
loop {
|
|
|
|
balance = self.get_balance(pubkey);
|
2018-07-02 17:31:10 -06:00
|
|
|
if balance.is_ok() && *balance.as_ref().unwrap() != 0 || now.elapsed().as_secs() > 1 {
|
2018-05-25 21:54:20 -06:00
|
|
|
break;
|
|
|
|
}
|
2018-05-22 09:46:52 -07:00
|
|
|
}
|
2018-07-05 21:40:09 -07:00
|
|
|
metrics::submit(
|
|
|
|
influxdb::Point::new("thinclient")
|
|
|
|
.add_tag("op", influxdb::Value::String("get_balance".to_string()))
|
|
|
|
.add_field(
|
|
|
|
"duration_ms",
|
|
|
|
influxdb::Value::Integer(timing::duration_as_ms(&now.elapsed()) as i64),
|
|
|
|
)
|
|
|
|
.to_owned(),
|
|
|
|
);
|
2018-05-25 21:54:20 -06:00
|
|
|
balance
|
|
|
|
}
|
2018-06-28 12:58:33 -06:00
|
|
|
|
|
|
|
/// Check a signature in the bank. This method blocks
|
|
|
|
/// until the server sends a response.
|
2018-06-28 18:59:02 -06:00
|
|
|
pub fn check_signature(&mut self, sig: &Signature) -> bool {
|
2018-06-28 12:58:33 -06:00
|
|
|
trace!("check_signature");
|
|
|
|
let req = Request::GetSignature { signature: *sig };
|
|
|
|
let data = serialize(&req).expect("serialize GetSignature in pub fn check_signature");
|
2018-07-05 21:40:09 -07:00
|
|
|
let now = Instant::now();
|
2018-06-28 12:58:33 -06:00
|
|
|
let mut done = false;
|
|
|
|
while !done {
|
2018-07-02 13:43:33 -07:00
|
|
|
self.requests_socket
|
2018-06-28 12:58:33 -06:00
|
|
|
.send_to(&data, &self.requests_addr)
|
|
|
|
.expect("buffer error in pub fn get_last_id");
|
|
|
|
|
|
|
|
if let Ok(resp) = self.recv_response() {
|
|
|
|
if let &Response::SignatureStatus { .. } = &resp {
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
self.process_response(resp);
|
|
|
|
}
|
|
|
|
}
|
2018-07-05 21:40:09 -07:00
|
|
|
metrics::submit(
|
|
|
|
influxdb::Point::new("thinclient")
|
|
|
|
.add_tag("op", influxdb::Value::String("check_signature".to_string()))
|
|
|
|
.add_field(
|
|
|
|
"duration_ms",
|
|
|
|
influxdb::Value::Integer(timing::duration_as_ms(&now.elapsed()) as i64),
|
|
|
|
)
|
|
|
|
.to_owned(),
|
|
|
|
);
|
2018-06-28 12:58:33 -06:00
|
|
|
self.signature_status
|
|
|
|
}
|
2018-05-22 09:46:52 -07:00
|
|
|
}
|
|
|
|
|
2018-07-05 21:40:09 -07:00
|
|
|
impl Drop for ThinClient {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
metrics::flush();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-28 14:16:50 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
2018-05-14 15:33:11 -06:00
|
|
|
use bank::Bank;
|
2018-05-29 13:28:07 -06:00
|
|
|
use budget::Budget;
|
2018-05-27 18:21:39 -07:00
|
|
|
use crdt::TestNode;
|
2018-07-02 15:24:40 -07:00
|
|
|
use fullnode::FullNode;
|
2018-05-04 11:11:39 -07:00
|
|
|
use logger;
|
2018-03-07 17:08:12 -07:00
|
|
|
use mint::Mint;
|
2018-07-03 22:14:08 -06:00
|
|
|
use service::Service;
|
2018-03-07 15:32:22 -07:00
|
|
|
use signature::{KeyPair, KeyPairUtil};
|
2018-03-26 11:17:19 -07:00
|
|
|
use std::io::sink;
|
2018-05-27 18:21:39 -07:00
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
2018-05-30 11:54:53 -07:00
|
|
|
use std::sync::Arc;
|
2018-03-26 22:03:26 -06:00
|
|
|
use std::thread::sleep;
|
|
|
|
use std::time::Duration;
|
2018-05-29 13:51:48 -06:00
|
|
|
use transaction::{Instruction, Plan};
|
2018-02-28 14:16:50 -07:00
|
|
|
|
|
|
|
#[test]
|
2018-05-08 17:32:50 -06:00
|
|
|
fn test_thin_client() {
|
2018-05-04 11:11:39 -07:00
|
|
|
logger::setup();
|
2018-05-23 10:49:48 -07:00
|
|
|
let leader = TestNode::new();
|
2018-06-28 14:51:53 -07:00
|
|
|
let leader_data = leader.data.clone();
|
2018-04-28 00:31:20 -07:00
|
|
|
|
2018-03-07 17:08:12 -07:00
|
|
|
let alice = Mint::new(10_000);
|
2018-05-14 15:33:11 -06:00
|
|
|
let bank = Bank::new(&alice);
|
2018-03-07 15:32:22 -07:00
|
|
|
let bob_pubkey = KeyPair::new().pubkey();
|
2018-03-22 14:05:23 -06:00
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2018-05-15 10:05:20 -06:00
|
|
|
|
2018-07-02 15:24:40 -07:00
|
|
|
let server = FullNode::new_leader(
|
2018-05-15 10:27:18 -06:00
|
|
|
bank,
|
2018-06-27 12:35:58 -07:00
|
|
|
0,
|
2018-07-02 10:07:32 -07:00
|
|
|
None,
|
2018-05-15 10:27:18 -06:00
|
|
|
Some(Duration::from_millis(30)),
|
2018-06-28 14:51:53 -07:00
|
|
|
leader,
|
2018-05-15 10:05:20 -06:00
|
|
|
exit.clone(),
|
|
|
|
sink(),
|
2018-05-15 10:09:54 -06:00
|
|
|
);
|
2018-05-13 20:33:41 -07:00
|
|
|
sleep(Duration::from_millis(900));
|
2018-02-28 14:16:50 -07:00
|
|
|
|
2018-05-11 16:35:53 -06:00
|
|
|
let requests_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
2018-05-25 15:51:41 -06:00
|
|
|
let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
2018-03-27 14:45:04 -06:00
|
|
|
|
2018-05-23 10:54:48 -07:00
|
|
|
let mut client = ThinClient::new(
|
2018-07-09 17:55:11 -07:00
|
|
|
leader_data.contact_info.rpu,
|
2018-05-23 10:54:48 -07:00
|
|
|
requests_socket,
|
2018-07-09 17:55:11 -07:00
|
|
|
leader_data.contact_info.tpu,
|
2018-05-25 15:51:41 -06:00
|
|
|
transactions_socket,
|
2018-05-23 10:54:48 -07:00
|
|
|
);
|
2018-05-31 13:41:42 -06:00
|
|
|
let last_id = client.get_last_id();
|
2018-05-11 16:15:14 -06:00
|
|
|
let _sig = client
|
2018-05-09 16:19:36 -06:00
|
|
|
.transfer(500, &alice.keypair(), bob_pubkey, &last_id)
|
2018-03-26 22:02:05 -06:00
|
|
|
.unwrap();
|
2018-05-25 21:54:20 -06:00
|
|
|
let balance = client.poll_get_balance(&bob_pubkey);
|
2018-05-07 16:49:15 -07:00
|
|
|
assert_eq!(balance.unwrap(), 500);
|
2018-03-22 14:05:23 -06:00
|
|
|
exit.store(true, Ordering::Relaxed);
|
2018-07-03 22:14:08 -06:00
|
|
|
server.join().unwrap();
|
2018-02-28 14:16:50 -07:00
|
|
|
}
|
2018-05-04 11:11:39 -07:00
|
|
|
|
2018-05-09 13:33:33 -06:00
|
|
|
#[test]
|
|
|
|
fn test_bad_sig() {
|
2018-05-22 09:46:52 -07:00
|
|
|
logger::setup();
|
2018-05-23 08:29:24 -07:00
|
|
|
let leader = TestNode::new();
|
2018-05-09 13:33:33 -06:00
|
|
|
let alice = Mint::new(10_000);
|
2018-05-14 15:33:11 -06:00
|
|
|
let bank = Bank::new(&alice);
|
2018-05-09 13:33:33 -06:00
|
|
|
let bob_pubkey = KeyPair::new().pubkey();
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2018-06-28 14:51:53 -07:00
|
|
|
let leader_data = leader.data.clone();
|
2018-05-15 10:05:20 -06:00
|
|
|
|
2018-07-02 15:24:40 -07:00
|
|
|
let server = FullNode::new_leader(
|
2018-05-15 10:27:18 -06:00
|
|
|
bank,
|
2018-06-27 12:35:58 -07:00
|
|
|
0,
|
2018-07-02 10:07:32 -07:00
|
|
|
None,
|
2018-05-15 10:27:18 -06:00
|
|
|
Some(Duration::from_millis(30)),
|
2018-06-28 14:51:53 -07:00
|
|
|
leader,
|
2018-05-09 13:33:33 -06:00
|
|
|
exit.clone(),
|
|
|
|
sink(),
|
2018-05-15 10:09:54 -06:00
|
|
|
);
|
2018-05-09 13:33:33 -06:00
|
|
|
sleep(Duration::from_millis(300));
|
|
|
|
|
2018-05-22 16:40:01 -07:00
|
|
|
let requests_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
2018-05-11 16:35:53 -06:00
|
|
|
requests_socket
|
|
|
|
.set_read_timeout(Some(Duration::new(5, 0)))
|
|
|
|
.unwrap();
|
2018-05-25 15:51:41 -06:00
|
|
|
let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
2018-05-23 10:54:48 -07:00
|
|
|
let mut client = ThinClient::new(
|
2018-07-09 17:55:11 -07:00
|
|
|
leader_data.contact_info.rpu,
|
2018-05-23 10:54:48 -07:00
|
|
|
requests_socket,
|
2018-07-09 17:55:11 -07:00
|
|
|
leader_data.contact_info.tpu,
|
2018-05-25 15:51:41 -06:00
|
|
|
transactions_socket,
|
2018-05-23 10:54:48 -07:00
|
|
|
);
|
2018-05-31 13:41:42 -06:00
|
|
|
let last_id = client.get_last_id();
|
2018-05-09 13:33:33 -06:00
|
|
|
|
2018-05-25 16:05:37 -06:00
|
|
|
let tx = Transaction::new(&alice.keypair(), bob_pubkey, 500, last_id);
|
2018-05-09 13:33:33 -06:00
|
|
|
|
2018-05-25 16:05:37 -06:00
|
|
|
let _sig = client.transfer_signed(tx).unwrap();
|
2018-05-09 13:33:33 -06:00
|
|
|
|
2018-05-31 13:41:42 -06:00
|
|
|
let last_id = client.get_last_id();
|
2018-05-09 13:33:33 -06:00
|
|
|
|
|
|
|
let mut tr2 = Transaction::new(&alice.keypair(), bob_pubkey, 501, last_id);
|
2018-05-22 21:42:04 -06:00
|
|
|
if let Instruction::NewContract(contract) = &mut tr2.instruction {
|
|
|
|
contract.tokens = 502;
|
2018-05-29 13:51:48 -06:00
|
|
|
contract.plan = Plan::Budget(Budget::new_payment(502, bob_pubkey));
|
2018-05-22 21:42:04 -06:00
|
|
|
}
|
2018-05-09 13:33:33 -06:00
|
|
|
let _sig = client.transfer_signed(tr2).unwrap();
|
|
|
|
|
2018-05-25 21:54:20 -06:00
|
|
|
let balance = client.poll_get_balance(&bob_pubkey);
|
2018-05-22 09:46:52 -07:00
|
|
|
assert_eq!(balance.unwrap(), 500);
|
2018-05-09 13:33:33 -06:00
|
|
|
exit.store(true, Ordering::Relaxed);
|
2018-07-03 22:14:08 -06:00
|
|
|
server.join().unwrap();
|
2018-02-28 14:16:50 -07:00
|
|
|
}
|
2018-06-28 12:58:33 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_client_check_signature() {
|
|
|
|
logger::setup();
|
|
|
|
let leader = TestNode::new();
|
|
|
|
let alice = Mint::new(10_000);
|
|
|
|
let bank = Bank::new(&alice);
|
|
|
|
let bob_pubkey = KeyPair::new().pubkey();
|
|
|
|
let exit = Arc::new(AtomicBool::new(false));
|
2018-06-28 14:51:53 -07:00
|
|
|
let leader_data = leader.data.clone();
|
2018-07-02 15:24:40 -07:00
|
|
|
let server = FullNode::new_leader(
|
2018-06-28 12:58:33 -06:00
|
|
|
bank,
|
|
|
|
0,
|
2018-07-02 10:07:32 -07:00
|
|
|
None,
|
2018-06-28 12:58:33 -06:00
|
|
|
Some(Duration::from_millis(30)),
|
2018-06-28 14:51:53 -07:00
|
|
|
leader,
|
2018-06-28 12:58:33 -06:00
|
|
|
exit.clone(),
|
|
|
|
sink(),
|
|
|
|
);
|
|
|
|
sleep(Duration::from_millis(300));
|
|
|
|
|
|
|
|
let requests_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
|
|
|
requests_socket
|
|
|
|
.set_read_timeout(Some(Duration::new(5, 0)))
|
|
|
|
.unwrap();
|
|
|
|
let transactions_socket = UdpSocket::bind("0.0.0.0:0").unwrap();
|
|
|
|
let mut client = ThinClient::new(
|
2018-07-09 17:55:11 -07:00
|
|
|
leader_data.contact_info.rpu,
|
2018-06-28 12:58:33 -06:00
|
|
|
requests_socket,
|
2018-07-09 17:55:11 -07:00
|
|
|
leader_data.contact_info.tpu,
|
2018-06-28 12:58:33 -06:00
|
|
|
transactions_socket,
|
|
|
|
);
|
|
|
|
let last_id = client.get_last_id();
|
|
|
|
let sig = client
|
|
|
|
.transfer(500, &alice.keypair(), bob_pubkey, &last_id)
|
|
|
|
.unwrap();
|
|
|
|
sleep(Duration::from_millis(100));
|
|
|
|
|
2018-06-28 18:59:02 -06:00
|
|
|
assert!(client.check_signature(&sig));
|
2018-06-28 12:58:33 -06:00
|
|
|
|
|
|
|
exit.store(true, Ordering::Relaxed);
|
2018-07-03 22:14:08 -06:00
|
|
|
server.join().unwrap();
|
2018-06-28 12:58:33 -06:00
|
|
|
}
|
2018-05-04 11:11:39 -07:00
|
|
|
}
|