From 8299bae2d425b0dd44f5c860e7f49d76ff8ff41b Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Wed, 28 Feb 2018 14:16:50 -0700 Subject: [PATCH] Add accountant stub --- src/accountant.rs | 1 + src/accountant_skel.rs | 22 ++++---- src/accountant_stub.rs | 116 +++++++++++++++++++++++++++++++++++++++++ src/bin/client-demo.rs | 80 ++++------------------------ src/lib.rs | 1 + 5 files changed, 140 insertions(+), 80 deletions(-) create mode 100644 src/accountant_stub.rs diff --git a/src/accountant.rs b/src/accountant.rs index 0e850adbc5..6596e7af26 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -89,6 +89,7 @@ impl Accountant { sig: Signature, ) -> Result<(), SendError>> { if self.get_balance(&from).unwrap() < data { + // TODO: Replace the SendError result with a custom one. return Ok(()); } let event = Event::Transaction { diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 60cb365082..008b0e7d40 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -7,7 +7,7 @@ pub struct AccountantSkel { pub obj: Accountant, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub enum Request { Deposit { key: PublicKey, @@ -25,12 +25,16 @@ pub enum Request { }, } -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Debug)] pub enum Response { Balance { key: PublicKey, val: u64 }, } impl AccountantSkel { + pub fn new(obj: Accountant) -> Self { + AccountantSkel { obj } + } + pub fn process_message(self: &mut Self, msg: Request) -> Option { match msg { Request::Deposit { key, val, sig } => { @@ -54,18 +58,18 @@ impl AccountantSkel { use std::io::{Read, Write}; use bincode::{deserialize, serialize}; let listener = TcpListener::bind(addr)?; - let mut buf = vec![]; + let mut buf = vec![0u8; 1024]; loop { - let (mut stream, addr) = listener.accept()?; - println!("connection received from {}", addr); + let (mut stream, _addr) = listener.accept()?; // TODO: Guard against large message DoS attack. - stream.read_to_end(&mut buf)?; + let _sz = stream.read(&mut buf)?; // TODO: Return a descriptive error message if deserialization fails. - let msg = deserialize(&buf).unwrap(); - if let Some(resp) = self.process_message(msg) { - stream.write(&serialize(&resp).unwrap())?; + let req = deserialize(&buf).expect("deserialize request"); + + if let Some(resp) = self.process_message(req) { + stream.write(&serialize(&resp).expect("serialize response"))?; } } } diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs new file mode 100644 index 0000000000..5c5749b1bb --- /dev/null +++ b/src/accountant_stub.rs @@ -0,0 +1,116 @@ +//! The `accountant` is a client of the `historian`. It uses the historian's +//! event log to record transactions. Its users can deposit funds and +//! transfer funds to other users. + +use std::net::TcpStream; +use std::io; +use std::io::{Read, Write}; +use bincode::{deserialize, serialize}; +use log::{PublicKey, Signature}; +use ring::signature::Ed25519KeyPair; +use accountant_skel::{Request, Response}; + +pub struct AccountantStub { + pub addr: String, +} + +impl AccountantStub { + pub fn new(addr: &str) -> Self { + AccountantStub { + addr: addr.to_string(), + } + } + + pub fn deposit_signed( + self: &mut Self, + key: PublicKey, + val: u64, + sig: Signature, + ) -> io::Result { + let req = Request::Deposit { key, val, sig }; + let data = serialize(&req).unwrap(); + let mut stream = TcpStream::connect(&self.addr)?; + stream.write(&data) + } + + pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> io::Result { + use log::{get_pubkey, sign_serialized}; + let key = get_pubkey(keypair); + let sig = sign_serialized(&n, keypair); + self.deposit_signed(key, n, sig) + } + + pub fn transfer_signed( + self: &mut Self, + from: PublicKey, + to: PublicKey, + val: u64, + sig: Signature, + ) -> io::Result { + let req = Request::Transfer { from, to, val, sig }; + let data = serialize(&req).unwrap(); + let mut stream = TcpStream::connect(&self.addr)?; + stream.write(&data) + } + + pub fn transfer( + self: &mut Self, + n: u64, + keypair: &Ed25519KeyPair, + to: PublicKey, + ) -> io::Result { + use log::{get_pubkey, sign_transaction_data}; + let from = get_pubkey(keypair); + let sig = sign_transaction_data(&n, keypair, &to); + self.transfer_signed(from, to, n, sig) + } + + pub fn get_balance(self: &mut Self, pubkey: &PublicKey) -> io::Result { + let mut stream = TcpStream::connect(&self.addr)?; + let req = Request::GetBalance { key: *pubkey }; + let data = serialize(&req).expect("serialize GetBalance"); + stream.write(&data)?; + let mut buf = vec![0u8; 1024]; + stream.read(&mut buf)?; + let resp = deserialize(&buf).expect("deserialize balance"); + let Response::Balance { key, val } = resp; + assert_eq!(key, *pubkey); + Ok(val) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use accountant::Accountant; + use accountant_skel::AccountantSkel; + use std::thread::{sleep, spawn}; + use std::time::Duration; + use log::{generate_keypair, get_pubkey, Sha256Hash}; + + #[test] + fn test_accountant_stub() { + let addr = "127.0.0.1:8000"; + spawn(move || { + let zero = Sha256Hash::default(); + let acc = Accountant::new(&zero, None); + let mut skel = AccountantSkel::new(acc); + skel.serve(addr).unwrap(); + }); + + sleep(Duration::from_millis(30)); + + let mut acc = AccountantStub::new(addr); + let alice_keypair = generate_keypair(); + let bob_keypair = generate_keypair(); + acc.deposit(10_000, &alice_keypair).unwrap(); + acc.deposit(1_000, &bob_keypair).unwrap(); + + sleep(Duration::from_millis(30)); + let bob_pubkey = get_pubkey(&bob_keypair); + acc.transfer(500, &alice_keypair, bob_pubkey).unwrap(); + + sleep(Duration::from_millis(300)); + assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 1_500); + } +} diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index 003caf6e27..209893f4ac 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -1,84 +1,22 @@ -extern crate generic_array; extern crate silk; -//use log::{Event, PublicKey, Sha256Hash}; -//use std::net::TcpStream; -//use ring::signature::Ed25519KeyPair; -// -//pub struct AccountantStub { -// pub stream: TcpStream, -//} -// -//impl AccountantStub { -// pub fn new(addr: ()) -> Self { -// let mut stream = TcpStream::connect(addr).unwrap(); -// AccountantStub { -// stream: TcpString, -// } -// } -// -// pub fn deposit( -// self: &Self, -// n: u64, -// keypair: &Ed25519KeyPair, -// ) -> Result<(), SendError>> { -// use log::sign_hash; -// let event = sign_hash(n, &keypair); -// self.stream.send(&serialize(event)) -// } -// -// pub fn transfer( -// self: &mut Self, -// n: u64, -// keypair: &Ed25519KeyPair, -// pubkey: PublicKey, -// ) -> io::Result<()> { -// use log::transfer_hash; -// use generic_array::GenericArray; -// let event = transfer_hash(n, &keypair); -// self.stream.send(&serialize(event)) -// } -// -// pub fn get_balance( -// self: &mut Self, -// pubkey: PublicKey, -// ) -> io::Result<()> { -// let event = GetBalance { key: pubkey }; -// self.stream.send(&serialize(event)); -// msg = deserialize(self.sender.recv()); -// if let AccountantMsg::Balance { val } = msg { -// Ok(val) -// } else { -// Err() -// } -// } -//} - -use silk::accountant::Accountant; -use std::thread::sleep; -use std::time::Duration; -use silk::log::{generate_keypair, Sha256Hash}; -use silk::historian::ExitReason; -use generic_array::GenericArray; - fn main() { - let zero = Sha256Hash::default(); - let mut acc = Accountant::new(&zero, Some(2)); + use silk::accountant_stub::AccountantStub; + use std::thread::sleep; + use std::time::Duration; + use silk::log::{generate_keypair, get_pubkey}; + + let addr = "127.0.0.1:8000"; + let mut acc = AccountantStub::new(addr); let alice_keypair = generate_keypair(); let bob_keypair = generate_keypair(); acc.deposit(10_000, &alice_keypair).unwrap(); acc.deposit(1_000, &bob_keypair).unwrap(); sleep(Duration::from_millis(30)); - let bob_pubkey = GenericArray::clone_from_slice(bob_keypair.public_key_bytes()); + let bob_pubkey = get_pubkey(&bob_keypair); acc.transfer(500, &alice_keypair, bob_pubkey).unwrap(); - sleep(Duration::from_millis(30)); + sleep(Duration::from_millis(300)); assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 1_500); - - drop(acc.historian.sender); - assert_eq!( - acc.historian.thread_hdl.join().unwrap().1, - ExitReason::RecvDisconnected - ); } diff --git a/src/lib.rs b/src/lib.rs index c30052ad96..6deb929413 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ pub mod log; pub mod historian; pub mod accountant; pub mod accountant_skel; +pub mod accountant_stub; extern crate bincode; extern crate generic_array; extern crate rayon;