Skip to content

Commit

Permalink
Merge pull request #12 from garious/add-historian
Browse files Browse the repository at this point in the history
Add historian demo
  • Loading branch information
garious authored Feb 19, 2018
2 parents a2fa60f + bd3fe5f commit 41053b6
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 20 deletions.
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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" }

Expand Down
48 changes: 48 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,54 @@ 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
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) -> Result<(), SendError<Event>> {
hist.sender.send(Event::Tick)?;
thread::sleep(time::Duration::new(0, 100_000));
hist.sender.send(Event::UserDataKey(0xdeadbeef))?;
thread::sleep(time::Duration::new(0, 100_000));
hist.sender.send(Event::Tick)?;
Ok(())
}

fn main() {
let seed = 0;
let hist = Historian::new(seed);
create_log(&hist).expect("send error");
drop(hist.sender);
let entries: Vec<Entry> = hist.receiver.iter().collect();
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
Expand Down
27 changes: 27 additions & 0 deletions src/bin/demo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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) -> Result<(), SendError<Event>> {
hist.sender.send(Event::Tick)?;
thread::sleep(time::Duration::new(0, 100_000));
hist.sender.send(Event::UserDataKey(0xdeadbeef))?;
thread::sleep(time::Duration::new(0, 100_000));
hist.sender.send(Event::Tick)?;
Ok(())
}

fn main() {
let seed = 0;
let hist = Historian::new(seed);
create_log(&hist).expect("send error");
drop(hist.sender);
let entries: Vec<Entry> = hist.receiver.iter().collect();
for entry in &entries {
println!("{:?}", entry);
}
assert!(verify_slice(&entries, seed));
}
29 changes: 15 additions & 14 deletions src/historian.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Event>,
Expand Down Expand Up @@ -64,20 +64,16 @@ pub fn create_logger(
receiver: Receiver<Event>,
sender: Sender<Entry>,
) -> 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(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;
}
})
Expand All @@ -104,25 +100,30 @@ 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, 1_000_000));
hist.sender.send(Event::UserDataKey(0xdeadbeef)).unwrap();
sleep(Duration::new(0, 1_000_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!(
hist.thread_hdl.join().unwrap().1,
ExitReason::RecvDisconnected
);

verify_slice(&[entry0, entry1], 0);
assert!(verify_slice(&[entry0, entry1, entry2], 0));
}

#[test]
Expand Down
14 changes: 9 additions & 5 deletions src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down

0 comments on commit 41053b6

Please sign in to comment.