diff --git a/src/accountant.rs b/src/accountant.rs index c3a5100fdc..a531ff005e 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -2,7 +2,7 @@ //! event log to record transactions. Its users can deposit funds and //! transfer funds to other users. -use log::Sha256Hash; +use log::{Entry, Sha256Hash}; use event::{get_pubkey, sign_transaction_data, verify_event, Event, PublicKey, Signature}; use genesis::Genesis; use historian::{reserve_signature, Historian}; @@ -28,8 +28,17 @@ pub struct Accountant { } impl Accountant { - pub fn new(gen: &Genesis, ms_per_tick: Option) -> Self { - let start_hash = gen.get_seed(); + pub fn new_from_entries(entries: I, ms_per_tick: Option) -> Self + where + I: IntoIterator>, + { + let mut entries = entries.into_iter(); + + // The first item in the log is required to be an entry with zero num_hashes, + // which implies its id can be used as the log's seed. + let entry0 = entries.next().unwrap(); + let start_hash = entry0.id; + let hist = Historian::::new(&start_hash, ms_per_tick); let mut acc = Accountant { historian: hist, @@ -37,12 +46,23 @@ impl Accountant { first_id: start_hash, last_id: start_hash, }; - for (i, event) in gen.create_events().iter().enumerate() { - acc.process_verified_event(event, i < 2).unwrap(); + + // The second item in the log is a special transaction where the to and from + // fields are the same. That entry should be treated as a deposit, not a + // transfer to oneself. + let entry1 = entries.next().unwrap(); + acc.process_verified_event(&entry1.event, true).unwrap(); + + for entry in entries { + acc.process_verified_event(&entry.event, false).unwrap(); } acc } + pub fn new(gen: &Genesis, ms_per_tick: Option) -> Self { + Self::new_from_entries(gen.create_entries(), ms_per_tick) + } + pub fn sync(self: &mut Self) -> Sha256Hash { while let Ok(entry) = self.historian.receiver.try_recv() { self.last_id = entry.id; @@ -66,7 +86,6 @@ impl Accountant { } self.process_verified_event(&event, false)?; - if let Err(SendError(_)) = self.historian.sender.send(event) { return Err(AccountingError::SendError); } diff --git a/src/accountant_skel.rs b/src/accountant_skel.rs index 1dd95c8dc6..4666e97edf 100644 --- a/src/accountant_skel.rs +++ b/src/accountant_skel.rs @@ -31,7 +31,7 @@ pub enum Request { #[derive(Serialize, Deserialize, Debug)] pub enum Response { - Balance { key: PublicKey, val: u64 }, + Balance { key: PublicKey, val: Option }, Entries { entries: Vec> }, Id { id: Sha256Hash, is_last: bool }, } @@ -58,12 +58,12 @@ impl AccountantSkel { sig, }; if let Err(err) = self.acc.process_event(event) { - println!("Transfer error: {:?}", err); + eprintln!("Transfer error: {:?}", err); } None } Request::GetBalance { key } => { - let val = self.acc.get_balance(&key).unwrap(); + let val = self.acc.get_balance(&key); Some(Response::Balance { key, val }) } Request::GetEntries { .. } => Some(Response::Entries { entries: vec![] }), diff --git a/src/accountant_stub.rs b/src/accountant_stub.rs index 15615275c7..8016620a97 100644 --- a/src/accountant_stub.rs +++ b/src/accountant_stub.rs @@ -57,7 +57,7 @@ impl AccountantStub { .map(|_| sig) } - pub fn get_balance(&self, pubkey: &PublicKey) -> io::Result { + pub fn get_balance(&self, pubkey: &PublicKey) -> io::Result> { let req = Request::GetBalance { key: *pubkey }; let data = serialize(&req).expect("serialize GetBalance"); self.socket.send_to(&data, &self.addr)?; @@ -68,7 +68,7 @@ impl AccountantStub { assert_eq!(key, *pubkey); return Ok(val); } - Ok(0) + Ok(None) } fn get_id(&self, is_last: bool) -> io::Result { @@ -147,6 +147,6 @@ mod tests { let sig = acc.transfer(500, &alice.get_keypair(), bob_pubkey, &last_id) .unwrap(); acc.wait_on_signature(&sig).unwrap(); - assert_eq!(acc.get_balance(&bob_pubkey).unwrap(), 1_500); + assert_eq!(acc.get_balance(&bob_pubkey).unwrap().unwrap(), 1_500); } } diff --git a/src/bin/client-demo.rs b/src/bin/client-demo.rs index e255419807..b54331a4c4 100644 --- a/src/bin/client-demo.rs +++ b/src/bin/client-demo.rs @@ -1,36 +1,28 @@ -//extern crate serde_json; +extern crate serde_json; extern crate silk; use silk::accountant_stub::AccountantStub; -use silk::accountant_skel::AccountantSkel; -use silk::accountant::Accountant; use silk::event::{generate_keypair, get_pubkey, sign_transaction_data, verify_event, Event}; use silk::genesis::Genesis; use std::time::Instant; use std::net::UdpSocket; -use std::thread::{sleep, spawn}; -use std::time::Duration; -//use std::io::stdin; +use std::io::stdin; fn main() { let addr = "127.0.0.1:8000"; let send_addr = "127.0.0.1:8001"; - let txs = 200; - - let gen = Genesis::new(txs, vec![]); - let alice_keypair = generate_keypair(); - //let gen: Genesis = serde_json::from_reader(stdin()).unwrap(); - //let alice_keypair = gen.get_keypair(); - - let acc = Accountant::new(&gen, None); - spawn(move || AccountantSkel::new(acc).serve(addr).unwrap()); - sleep(Duration::from_millis(30)); + let gen: Genesis = serde_json::from_reader(stdin()).unwrap(); + let alice_keypair = gen.get_keypair(); + let alice_pubkey = gen.get_pubkey(); let socket = UdpSocket::bind(send_addr).unwrap(); let mut acc = AccountantStub::new(addr, socket); let last_id = acc.get_last_id().unwrap(); - let alice_pubkey = get_pubkey(&alice_keypair); + + let txs = acc.get_balance(&alice_pubkey).unwrap().unwrap(); + println!("Alice's Initial Balance {}", txs); + let one = 1; println!("Signing transactions..."); let now = Instant::now(); @@ -89,7 +81,7 @@ fn main() { let ns = duration.as_secs() * 1_000_000_000 + duration.subsec_nanos() as u64; let tps = (txs * 1_000_000_000) as f64 / ns as f64; println!("Done. {} tps!", tps); - let val = acc.get_balance(&alice_pubkey).unwrap(); + let val = acc.get_balance(&alice_pubkey).unwrap().unwrap(); println!("Alice's Final Balance {}", val); assert_eq!(val, 0); } diff --git a/src/bin/genesis-block.rs b/src/bin/genesis-block.rs index a64c4f9cdd..ce3e8e5898 100644 --- a/src/bin/genesis-block.rs +++ b/src/bin/genesis-block.rs @@ -12,13 +12,7 @@ fn main() { let gen: Genesis = serde_json::from_reader(stdin()).unwrap(); let entries = gen.create_entries(); verify_slice_u64(&entries, &entries[0].id); - println!("["); - let len = entries.len(); - for (i, x) in entries.iter().enumerate() { - let s = serde_json::to_string(&x).unwrap(); - - let terminator = if i + 1 == len { "" } else { "," }; - println!(" {}{}", s, terminator); + for x in entries { + println!("{}", serde_json::to_string(&x).unwrap()); } - println!("]"); } diff --git a/src/bin/genesis-file-demo.rs b/src/bin/genesis-file-demo.rs index 65f28edaf2..26a47c5e8b 100644 --- a/src/bin/genesis-file-demo.rs +++ b/src/bin/genesis-file-demo.rs @@ -14,6 +14,6 @@ fn main() { pubkey: get_pubkey(&generate_keypair()), }; let creators = vec![alice, bob]; - let gen = Genesis::new(300, creators); + let gen = Genesis::new(500, creators); println!("{}", serde_json::to_string(&gen).unwrap()); } diff --git a/src/bin/testnode.rs b/src/bin/testnode.rs index 141fffb904..22a73e6eb4 100644 --- a/src/bin/testnode.rs +++ b/src/bin/testnode.rs @@ -3,14 +3,17 @@ extern crate silk; use silk::accountant_skel::AccountantSkel; use silk::accountant::Accountant; -use silk::genesis::Genesis; -use std::io::stdin; +use std::io::{self, BufRead}; fn main() { let addr = "127.0.0.1:8000"; - let gen: Genesis = serde_json::from_reader(stdin()).unwrap(); - let acc = Accountant::new(&gen, Some(1000)); + let stdin = io::stdin(); + let entries = stdin + .lock() + .lines() + .map(|line| serde_json::from_str(&line.unwrap()).unwrap()); + let acc = Accountant::new_from_entries(entries, Some(1000)); let mut skel = AccountantSkel::new(acc); - println!("Listening on {}", addr); + eprintln!("Listening on {}", addr); skel.serve(addr).unwrap(); } diff --git a/src/genesis.rs b/src/genesis.rs index bd009504af..df331532d2 100644 --- a/src/genesis.rs +++ b/src/genesis.rs @@ -32,6 +32,7 @@ impl Genesis { pub fn new(tokens: u64, creators: Vec) -> Self { let rnd = SystemRandom::new(); let pkcs8 = Ed25519KeyPair::generate_pkcs8(&rnd).unwrap().to_vec(); + println!("{:?}", pkcs8); Genesis { pkcs8, tokens, @@ -86,6 +87,7 @@ impl Genesis { #[cfg(test)] mod tests { use super::*; + use log::verify_slice_u64; #[test] fn test_create_events() { @@ -108,4 +110,16 @@ mod tests { 3 ); } + + #[test] + fn test_verify_entries() { + let entries = Genesis::new(100, vec![]).create_entries(); + assert!(verify_slice_u64(&entries, &entries[0].id)); + } + + #[test] + fn test_verify_entries_with_transactions() { + let entries = Genesis::new(100, vec![Creator::new(42)]).create_entries(); + assert!(verify_slice_u64(&entries, &entries[0].id)); + } } diff --git a/src/lib.rs b/src/lib.rs index 78dbeadbcd..bf65fb2d54 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,5 +14,6 @@ extern crate ring; extern crate serde; #[macro_use] extern crate serde_derive; +extern crate serde_json; extern crate sha2; extern crate untrusted; diff --git a/src/logger.rs b/src/logger.rs index 46218d93a1..130f746602 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -11,6 +11,7 @@ use log::{create_entry_mut, Entry, Sha256Hash}; use event::Event; use serde::Serialize; use std::fmt::Debug; +use serde_json; #[derive(Debug, PartialEq, Eq)] pub enum ExitReason { @@ -43,6 +44,7 @@ impl Logger { pub fn log_event(&mut self, event: Event) -> Result, ExitReason> { let entry = create_entry_mut(&mut self.last_id, &mut self.num_hashes, event); + println!("{}", serde_json::to_string(&entry).unwrap()); Ok(entry) } @@ -78,8 +80,6 @@ mod tests { use super::*; use log::*; use event::*; - use genesis::*; - use std::sync::mpsc::sync_channel; #[test] fn test_bad_event_signature() { @@ -94,28 +94,4 @@ mod tests { ); assert!(!verify_event(&event0)); } - - fn run_genesis(gen: Genesis) -> Vec> { - let (sender, event_receiver) = sync_channel(100); - let (entry_sender, receiver) = sync_channel(100); - let mut logger = Logger::new(event_receiver, entry_sender, gen.get_seed()); - for tx in gen.create_events() { - sender.send(tx).unwrap(); - } - logger.process_events(Instant::now(), None).unwrap(); - drop(logger.sender); - receiver.iter().collect::>() - } - - #[test] - fn test_genesis_no_creators() { - let entries = run_genesis(Genesis::new(100, vec![])); - assert!(verify_slice_u64(&entries, &entries[0].id)); - } - - #[test] - fn test_genesis() { - let entries = run_genesis(Genesis::new(100, vec![Creator::new(42)])); - assert!(verify_slice_u64(&entries, &entries[0].id)); - } }