2018-03-05 15:05:16 -08:00
|
|
|
|
The Historian
|
|
|
|
|
===
|
|
|
|
|
|
2018-03-19 09:16:16 -07:00
|
|
|
|
Create a *Historian* and send it *events* to generate an *event log*, where each *entry*
|
2018-03-05 15:05:16 -08:00
|
|
|
|
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:
|
|
|
|
|
|
|
|
|
|
![historian](https://user-images.githubusercontent.com/55449/36950845-459bdb58-1fb9-11e8-850e-894586f3729b.png)
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
extern crate silk;
|
|
|
|
|
|
|
|
|
|
use silk::historian::Historian;
|
2018-03-19 09:16:16 -07:00
|
|
|
|
use silk::ledger::{verify_slice, Entry, Hash};
|
2018-03-05 15:05:16 -08:00
|
|
|
|
use silk::event::{generate_keypair, get_pubkey, sign_claim_data, Event};
|
|
|
|
|
use std::thread::sleep;
|
|
|
|
|
use std::time::Duration;
|
|
|
|
|
use std::sync::mpsc::SendError;
|
|
|
|
|
|
2018-03-19 09:16:16 -07:00
|
|
|
|
fn create_ledger(hist: &Historian<Hash>) -> Result<(), SendError<Event<Hash>>> {
|
2018-03-05 15:05:16 -08:00
|
|
|
|
sleep(Duration::from_millis(15));
|
2018-03-19 09:23:43 -07:00
|
|
|
|
let tokens = 42;
|
2018-03-05 15:05:16 -08:00
|
|
|
|
let keypair = generate_keypair();
|
2018-03-19 09:23:43 -07:00
|
|
|
|
let event0 = Event::new_claim(get_pubkey(&keypair), tokens, sign_claim_data(&tokens, &keypair));
|
2018-03-05 15:05:16 -08:00
|
|
|
|
hist.sender.send(event0)?;
|
|
|
|
|
sleep(Duration::from_millis(10));
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn main() {
|
2018-03-06 16:36:45 -08:00
|
|
|
|
let seed = Hash::default();
|
2018-03-05 15:05:16 -08:00
|
|
|
|
let hist = Historian::new(&seed, Some(10));
|
2018-03-19 09:16:16 -07:00
|
|
|
|
create_ledger(&hist).expect("send error");
|
2018-03-05 15:05:16 -08:00
|
|
|
|
drop(hist.sender);
|
2018-03-06 16:36:45 -08:00
|
|
|
|
let entries: Vec<Entry<Hash>> = hist.receiver.iter().collect();
|
2018-03-05 15:05:16 -08:00
|
|
|
|
for entry in &entries {
|
|
|
|
|
println!("{:?}", entry);
|
|
|
|
|
}
|
|
|
|
|
// Proof-of-History: Verify the historian learned about the events
|
|
|
|
|
// in the same order they appear in the vector.
|
|
|
|
|
assert!(verify_slice(&entries, &seed));
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2018-03-19 09:16:16 -07:00
|
|
|
|
Running the program should produce a ledger similar to:
|
2018-03-05 15:05:16 -08:00
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
Entry { num_hashes: 0, id: [0, ...], event: Tick }
|
2018-03-19 09:23:43 -07:00
|
|
|
|
Entry { num_hashes: 3, id: [67, ...], event: Transaction { tokens: 42 } }
|
2018-03-05 15:05:16 -08:00
|
|
|
|
Entry { num_hashes: 3, id: [123, ...], event: Tick }
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Proof-of-History
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
Take note of the last line:
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
assert!(verify_slice(&entries, &seed));
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
[It's a proof!](https://en.wikipedia.org/wiki/Curry–Howard_correspondence) For each entry returned by the
|
|
|
|
|
historian, we can verify that `id` is the result of applying a sha256 hash to the previous `id`
|
|
|
|
|
exactly `num_hashes` times, and then hashing then event data on top of that. Because the event data is
|
|
|
|
|
included in the hash, the events cannot be reordered without regenerating all the hashes.
|