From 5e3c7816bd923f5a731fdfbba7c0d00eebf7d2ae Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Mon, 19 Feb 2018 09:09:24 -0700 Subject: [PATCH 1/7] Ensure verify_slice succeeds --- src/historian.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/historian.rs b/src/historian.rs index 24bd545c20..88a7d87343 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -122,7 +122,7 @@ mod tests { ExitReason::RecvDisconnected ); - verify_slice(&[entry0, entry1], 0); + assert!(verify_slice(&[entry0, entry1], 0)); } #[test] From a7186328e0362f353531ecfc52875baf3ed8796f Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Mon, 19 Feb 2018 09:19:26 -0700 Subject: [PATCH 2/7] Add docs Fixes #11 --- Cargo.toml | 2 +- README.md | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 26b5d18da8..ef4e903c25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "silk" description = "A silky smooth implementation of the Loom architecture" -version = "0.1.3" +version = "0.2.0" documentation = "https://docs.rs/silk" homepage = "http://loomprotocol.com/" repository = "https://github.com/loomprotocol/silk" diff --git a/README.md b/README.md index 2367f5d92e..88b5edb870 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,32 @@ corresponding benchmarks are also added that demonstrate real performance boots. feature set here will always be a ways behind the loom repo, but that this is an implementation you can take to the bank, literally. +# Usage + +Add the latest [silk package] (https://crates.io/crates/silk) to the `[dependencies]` section +of your Cargo.toml. + +Create a *Historian* and send it *events* to generate an *event log*, where each log *entry* +is tagged with the historian's latest *hash*. Then ensure the order of events was not tampered +with by verifying each entry's hash can be generated from the hash in the previous entry: + +```rust +use historian::Historian; +use log::{Event, verify_slice}; + +fn main() { + let hist = Historian::new(0); + + hist.sender.send(Event::Tick).unwrap(); + let entry0 = hist.receiver.recv().unwrap(); + + hist.sender.send(Event::UserDataKey(0xdeadbeef)).unwrap(); + let entry1 = hist.receiver.recv().unwrap(); + + assert!(verify_slice(&[entry0, entry1], 0)); +} +``` + # Developing Building From d88d1b2a098e4c49cba6efe355e05d63658f6927 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Mon, 19 Feb 2018 12:00:56 -0700 Subject: [PATCH 3/7] Reset historian's hasher between events Hasher will generate different hashes for the same input if it had already generated a hash. Also add a binary to ensure the example in the README works. --- Cargo.toml | 4 ++++ README.md | 45 ++++++++++++++++++++++++++++++++++----------- src/bin/demo.rs | 28 ++++++++++++++++++++++++++++ src/historian.rs | 27 ++++++++++++++++++--------- 4 files changed, 84 insertions(+), 20 deletions(-) create mode 100644 src/bin/demo.rs diff --git a/Cargo.toml b/Cargo.toml index ef4e903c25..0f6900c6b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,10 @@ authors = [ ] license = "Apache-2.0" +[[bin]] +name = "silk-demo" +path = "src/bin/demo.rs" + [badges] codecov = { repository = "loomprotocol/silk", branch = "master", service = "github" } diff --git a/README.md b/README.md index 88b5edb870..f23d0e4e38 100644 --- a/README.md +++ b/README.md @@ -25,22 +25,45 @@ is tagged with the historian's latest *hash*. Then ensure the order of events wa with by verifying each entry's hash can be generated from the hash in the previous entry: ```rust -use historian::Historian; -use log::{Event, verify_slice}; +extern crate silk; + +use silk::historian::Historian; +use silk::log::{verify_slice, Entry, Event}; +use std::{thread, time}; + +fn create_log(hist: &Historian) -> Vec { + hist.sender.send(Event::Tick).unwrap(); + thread::sleep(time::Duration::new(0, 100_000)); + hist.sender.send(Event::UserDataKey(0xdeadbeef)).unwrap(); + thread::sleep(time::Duration::new(0, 100_000)); + hist.sender.send(Event::Tick).unwrap(); + + let entry0 = hist.receiver.recv().unwrap(); + let entry1 = hist.receiver.recv().unwrap(); + let entry2 = hist.receiver.recv().unwrap(); + vec![entry0, entry1, entry2] +} fn main() { - let hist = Historian::new(0); - - hist.sender.send(Event::Tick).unwrap(); - let entry0 = hist.receiver.recv().unwrap(); - - hist.sender.send(Event::UserDataKey(0xdeadbeef)).unwrap(); - let entry1 = hist.receiver.recv().unwrap(); - - assert!(verify_slice(&[entry0, entry1], 0)); + let seed = 0; + let hist = Historian::new(seed); + let entries = create_log(&hist); + for entry in &entries { + println!("{:?}", entry); + } + assert!(verify_slice(&entries, seed)); } ``` +Running the program should produce a log similar to: + +``` +Entry { num_hashes: 0, end_hash: 0, event: Tick } +Entry { num_hashes: 245, end_hash: 11504657626326377539, event: UserDataKey(3735928559) } +Entry { num_hashes: 154, end_hash: 13410333856574024888, event: Tick } +``` + + # Developing Building diff --git a/src/bin/demo.rs b/src/bin/demo.rs new file mode 100644 index 0000000000..bdb5328eac --- /dev/null +++ b/src/bin/demo.rs @@ -0,0 +1,28 @@ +extern crate silk; + +use silk::historian::Historian; +use silk::log::{verify_slice, Entry, Event}; +use std::{thread, time}; + +fn create_log(hist: &Historian) -> Vec { + hist.sender.send(Event::Tick).unwrap(); + thread::sleep(time::Duration::new(0, 100_000)); + hist.sender.send(Event::UserDataKey(0xdeadbeef)).unwrap(); + thread::sleep(time::Duration::new(0, 100_000)); + hist.sender.send(Event::Tick).unwrap(); + + let entry0 = hist.receiver.recv().unwrap(); + let entry1 = hist.receiver.recv().unwrap(); + let entry2 = hist.receiver.recv().unwrap(); + vec![entry0, entry1, entry2] +} + +fn main() { + let seed = 0; + let hist = Historian::new(seed); + let entries = create_log(&hist); + for entry in &entries { + println!("{:?}", entry); + } + assert!(verify_slice(&entries, seed)); +} diff --git a/src/historian.rs b/src/historian.rs index 88a7d87343..bb9311d052 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -73,7 +73,11 @@ pub fn create_logger( let mut num_hashes = 0; loop { match log_events(&receiver, &sender, num_hashes, end_hash) { - Ok(n) => num_hashes = n, + Ok(0) => { + num_hashes = 0; + hasher = DefaultHasher::new(); + } + Ok(_) => {} Err(err) => return err, } end_hash.hash(&mut hasher); @@ -104,17 +108,22 @@ mod tests { #[test] fn test_historian() { + use std::thread::sleep; + use std::time::Duration; + let hist = Historian::new(0); - let event = Event::Tick; - hist.sender.send(event.clone()).unwrap(); - let entry0 = hist.receiver.recv().unwrap(); - assert_eq!(entry0.event, event); + hist.sender.send(Event::Tick).unwrap(); + sleep(Duration::new(0, 100_000)); + hist.sender.send(Event::UserDataKey(0xdeadbeef)).unwrap(); + sleep(Duration::new(0, 100_000)); + hist.sender.send(Event::Tick).unwrap(); - let event = Event::UserDataKey(0xdeadbeef); - hist.sender.send(event.clone()).unwrap(); + let entry0 = hist.receiver.recv().unwrap(); let entry1 = hist.receiver.recv().unwrap(); - assert_eq!(entry1.event, event); + let entry2 = hist.receiver.recv().unwrap(); + assert!(entry1.num_hashes != 0); + assert!(entry2.num_hashes != 0); drop(hist.sender); assert_eq!( @@ -122,7 +131,7 @@ mod tests { ExitReason::RecvDisconnected ); - assert!(verify_slice(&[entry0, entry1], 0)); + assert!(verify_slice(&[entry0, entry1, entry2], 0)); } #[test] From 4a7156de4336e9b96e425e53a646c0352bce2a99 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Mon, 19 Feb 2018 12:09:56 -0700 Subject: [PATCH 4/7] Move hash generation into stateless function --- src/historian.rs | 14 +++----------- src/log.rs | 14 +++++++++----- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/historian.rs b/src/historian.rs index bb9311d052..5e7b2054d8 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -7,7 +7,7 @@ use std::thread::JoinHandle; use std::sync::mpsc::{Receiver, Sender}; -use log::{Entry, Event}; +use log::{hash, Entry, Event}; pub struct Historian { pub sender: Sender, @@ -64,24 +64,16 @@ pub fn create_logger( receiver: Receiver, sender: Sender, ) -> JoinHandle<(Entry, ExitReason)> { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; use std::thread; thread::spawn(move || { let mut end_hash = start_hash; - let mut hasher = DefaultHasher::new(); let mut num_hashes = 0; loop { match log_events(&receiver, &sender, num_hashes, end_hash) { - Ok(0) => { - num_hashes = 0; - hasher = DefaultHasher::new(); - } - Ok(_) => {} + Ok(n) => num_hashes = n, Err(err) => return err, } - end_hash.hash(&mut hasher); - end_hash = hasher.finish(); + end_hash = hash(end_hash); num_hashes += 1; } }) diff --git a/src/log.rs b/src/log.rs index 007de3807c..5db5437e28 100644 --- a/src/log.rs +++ b/src/log.rs @@ -48,15 +48,19 @@ impl Entry { } } -/// Creates the next Tick Entry 'num_hashes' after 'start_hash'. -pub fn next_tick(start_hash: u64, num_hashes: u64) -> Entry { +pub fn hash(val: u64) -> u64 { use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; - let mut end_hash = start_hash; let mut hasher = DefaultHasher::new(); + val.hash(&mut hasher); + hasher.finish() +} + +/// Creates the next Tick Entry 'num_hashes' after 'start_hash'. +pub fn next_tick(start_hash: u64, num_hashes: u64) -> Entry { + let mut end_hash = start_hash; for _ in 0..num_hashes { - end_hash.hash(&mut hasher); - end_hash = hasher.finish(); + end_hash = hash(end_hash); } Entry::new_tick(num_hashes, end_hash) } From 0bead4d410fffe76026e3841ba1db39c8047df6d Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Mon, 19 Feb 2018 12:12:45 -0700 Subject: [PATCH 5/7] Fix markdown link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f23d0e4e38..9bff277bfd 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ you can take to the bank, literally. # Usage -Add the latest [silk package] (https://crates.io/crates/silk) to the `[dependencies]` section +Add the latest [silk package](https://crates.io/crates/silk) to the `[dependencies]` section of your Cargo.toml. Create a *Historian* and send it *events* to generate an *event log*, where each log *entry* From 10a70a238b03bce46de96cae5a2bc5db39b50eeb Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Mon, 19 Feb 2018 12:25:57 -0700 Subject: [PATCH 6/7] Cleanup demo --- README.md | 19 +++++++++---------- src/bin/demo.rs | 19 +++++++++---------- 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 9bff277bfd..8eda7bff09 100644 --- a/README.md +++ b/README.md @@ -30,24 +30,23 @@ extern crate silk; use silk::historian::Historian; use silk::log::{verify_slice, Entry, Event}; use std::{thread, time}; +use std::sync::mpsc::SendError; -fn create_log(hist: &Historian) -> Vec { - hist.sender.send(Event::Tick).unwrap(); +fn create_log(hist: &Historian) -> Result<(), SendError> { + hist.sender.send(Event::Tick)?; thread::sleep(time::Duration::new(0, 100_000)); - hist.sender.send(Event::UserDataKey(0xdeadbeef)).unwrap(); + hist.sender.send(Event::UserDataKey(0xdeadbeef))?; thread::sleep(time::Duration::new(0, 100_000)); - hist.sender.send(Event::Tick).unwrap(); - - let entry0 = hist.receiver.recv().unwrap(); - let entry1 = hist.receiver.recv().unwrap(); - let entry2 = hist.receiver.recv().unwrap(); - vec![entry0, entry1, entry2] + hist.sender.send(Event::Tick)?; + Ok(()) } fn main() { let seed = 0; let hist = Historian::new(seed); - let entries = create_log(&hist); + create_log(&hist).expect("send error"); + drop(hist.sender); + let entries: Vec = hist.receiver.iter().collect(); for entry in &entries { println!("{:?}", entry); } diff --git a/src/bin/demo.rs b/src/bin/demo.rs index bdb5328eac..4715d2e083 100644 --- a/src/bin/demo.rs +++ b/src/bin/demo.rs @@ -3,24 +3,23 @@ extern crate silk; use silk::historian::Historian; use silk::log::{verify_slice, Entry, Event}; use std::{thread, time}; +use std::sync::mpsc::SendError; -fn create_log(hist: &Historian) -> Vec { - hist.sender.send(Event::Tick).unwrap(); +fn create_log(hist: &Historian) -> Result<(), SendError> { + hist.sender.send(Event::Tick)?; thread::sleep(time::Duration::new(0, 100_000)); - hist.sender.send(Event::UserDataKey(0xdeadbeef)).unwrap(); + hist.sender.send(Event::UserDataKey(0xdeadbeef))?; thread::sleep(time::Duration::new(0, 100_000)); - hist.sender.send(Event::Tick).unwrap(); - - let entry0 = hist.receiver.recv().unwrap(); - let entry1 = hist.receiver.recv().unwrap(); - let entry2 = hist.receiver.recv().unwrap(); - vec![entry0, entry1, entry2] + hist.sender.send(Event::Tick)?; + Ok(()) } fn main() { let seed = 0; let hist = Historian::new(seed); - let entries = create_log(&hist); + create_log(&hist).expect("send error"); + drop(hist.sender); + let entries: Vec = hist.receiver.iter().collect(); for entry in &entries { println!("{:?}", entry); } From bd3fe5fac92e25544d6fc12126f793cb4dd74040 Mon Sep 17 00:00:00 2001 From: Greg Fitzgerald Date: Mon, 19 Feb 2018 12:33:33 -0700 Subject: [PATCH 7/7] Sleep a little longer to ensure Travis context switches --- src/historian.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/historian.rs b/src/historian.rs index 5e7b2054d8..380d432f22 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -106,9 +106,9 @@ mod tests { let hist = Historian::new(0); hist.sender.send(Event::Tick).unwrap(); - sleep(Duration::new(0, 100_000)); + sleep(Duration::new(0, 1_000_000)); hist.sender.send(Event::UserDataKey(0xdeadbeef)).unwrap(); - sleep(Duration::new(0, 100_000)); + sleep(Duration::new(0, 1_000_000)); hist.sender.send(Event::Tick).unwrap(); let entry0 = hist.receiver.recv().unwrap();