commit
662e10c3e0
|
@ -45,7 +45,7 @@ use std::sync::mpsc::SendError;
|
||||||
fn create_log(hist: &Historian) -> Result<(), SendError<Event>> {
|
fn create_log(hist: &Historian) -> Result<(), SendError<Event>> {
|
||||||
sleep(Duration::from_millis(15));
|
sleep(Duration::from_millis(15));
|
||||||
let data = Sha256Hash::default();
|
let data = Sha256Hash::default();
|
||||||
hist.sender.send(Event::Discovery { data })?;
|
hist.sender.send(Event::Claim { data })?;
|
||||||
sleep(Duration::from_millis(10));
|
sleep(Duration::from_millis(10));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ Running the program should produce a log similar to:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
Entry { num_hashes: 0, end_hash: [0, ...], event: Tick }
|
Entry { num_hashes: 0, end_hash: [0, ...], event: Tick }
|
||||||
Entry { num_hashes: 2, end_hash: [67, ...], event: Discovery { data: [37, ...] } }
|
Entry { num_hashes: 2, end_hash: [67, ...], event: Claim { data: [37, ...] } }
|
||||||
Entry { num_hashes: 3, end_hash: [123, ...], event: Tick }
|
Entry { num_hashes: 3, end_hash: [123, ...], event: Tick }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@ msc {
|
||||||
logger=>historian [ label = "e0 = Entry{hash: h0, n: 0, event: Tick}" ] ;
|
logger=>historian [ label = "e0 = Entry{hash: h0, n: 0, event: Tick}" ] ;
|
||||||
logger=>logger [ label = "h1 = hash(h0)" ] ;
|
logger=>logger [ label = "h1 = hash(h0)" ] ;
|
||||||
logger=>logger [ label = "h2 = hash(h1)" ] ;
|
logger=>logger [ label = "h2 = hash(h1)" ] ;
|
||||||
client=>historian [ label = "Discovery(d0)" ] ;
|
client=>historian [ label = "Claim(d0)" ] ;
|
||||||
historian=>logger [ label = "Discovery(d0)" ] ;
|
historian=>logger [ label = "Claim(d0)" ] ;
|
||||||
logger=>logger [ label = "h3 = hash(h2 + d0)" ] ;
|
logger=>logger [ label = "h3 = hash(h2 + d0)" ] ;
|
||||||
logger=>historian [ label = "e1 = Entry{hash: hash(h3), n: 2, event: Discovery(d0)}" ] ;
|
logger=>historian [ label = "e1 = Entry{hash: hash(h3), n: 2, event: Claim(d0)}" ] ;
|
||||||
logger=>logger [ label = "h4 = hash(h3)" ] ;
|
logger=>logger [ label = "h4 = hash(h3)" ] ;
|
||||||
logger=>logger [ label = "h5 = hash(h4)" ] ;
|
logger=>logger [ label = "h5 = hash(h4)" ] ;
|
||||||
logger=>logger [ label = "h6 = hash(h5)" ] ;
|
logger=>logger [ label = "h6 = hash(h5)" ] ;
|
||||||
|
|
|
@ -11,7 +11,6 @@ use std::collections::HashMap;
|
||||||
pub struct Accountant {
|
pub struct Accountant {
|
||||||
pub historian: Historian<u64>,
|
pub historian: Historian<u64>,
|
||||||
pub balances: HashMap<PublicKey, u64>,
|
pub balances: HashMap<PublicKey, u64>,
|
||||||
pub signatures: HashMap<Signature, bool>,
|
|
||||||
pub end_hash: Sha256Hash,
|
pub end_hash: Sha256Hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,19 +20,13 @@ impl Accountant {
|
||||||
Accountant {
|
Accountant {
|
||||||
historian: hist,
|
historian: hist,
|
||||||
balances: HashMap::new(),
|
balances: HashMap::new(),
|
||||||
signatures: HashMap::new(),
|
|
||||||
end_hash: *start_hash,
|
end_hash: *start_hash,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_event(self: &mut Self, event: &Event<u64>) {
|
pub fn process_event(self: &mut Self, event: &Event<u64>) {
|
||||||
match *event {
|
match *event {
|
||||||
Event::Claim { key, data, sig } => {
|
Event::Claim { key, data, .. } => {
|
||||||
if self.signatures.contains_key(&sig) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.signatures.insert(sig, true);
|
|
||||||
|
|
||||||
if self.balances.contains_key(&key) {
|
if self.balances.contains_key(&key) {
|
||||||
if let Some(x) = self.balances.get_mut(&key) {
|
if let Some(x) = self.balances.get_mut(&key) {
|
||||||
*x += data;
|
*x += data;
|
||||||
|
@ -42,16 +35,7 @@ impl Accountant {
|
||||||
self.balances.insert(key, data);
|
self.balances.insert(key, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Transaction {
|
Event::Transaction { from, to, data, .. } => {
|
||||||
from,
|
|
||||||
to,
|
|
||||||
data,
|
|
||||||
sig,
|
|
||||||
} => {
|
|
||||||
if self.signatures.contains_key(&sig) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.signatures.insert(sig, true);
|
|
||||||
if let Some(x) = self.balances.get_mut(&from) {
|
if let Some(x) = self.balances.get_mut(&from) {
|
||||||
*x -= data;
|
*x -= data;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
extern crate silk;
|
extern crate silk;
|
||||||
|
|
||||||
use silk::historian::Historian;
|
use silk::historian::Historian;
|
||||||
use silk::log::{verify_slice, Entry, Event, Sha256Hash};
|
use silk::log::{generate_keypair, get_pubkey, sign_serialized, verify_slice, Entry, Event,
|
||||||
|
Sha256Hash};
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use std::sync::mpsc::SendError;
|
use std::sync::mpsc::SendError;
|
||||||
|
@ -9,7 +10,13 @@ use std::sync::mpsc::SendError;
|
||||||
fn create_log(hist: &Historian<Sha256Hash>) -> Result<(), SendError<Event<Sha256Hash>>> {
|
fn create_log(hist: &Historian<Sha256Hash>) -> Result<(), SendError<Event<Sha256Hash>>> {
|
||||||
sleep(Duration::from_millis(15));
|
sleep(Duration::from_millis(15));
|
||||||
let data = Sha256Hash::default();
|
let data = Sha256Hash::default();
|
||||||
hist.sender.send(Event::Discovery { data })?;
|
let keypair = generate_keypair();
|
||||||
|
let event0 = Event::Claim {
|
||||||
|
key: get_pubkey(&keypair),
|
||||||
|
data,
|
||||||
|
sig: sign_serialized(&data, &keypair),
|
||||||
|
};
|
||||||
|
hist.sender.send(event0)?;
|
||||||
sleep(Duration::from_millis(10));
|
sleep(Duration::from_millis(10));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,10 @@
|
||||||
//! The resulting stream of entries represents ordered events in time.
|
//! The resulting stream of entries represents ordered events in time.
|
||||||
|
|
||||||
use std::thread::JoinHandle;
|
use std::thread::JoinHandle;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::mpsc::{Receiver, SyncSender};
|
use std::sync::mpsc::{Receiver, SyncSender};
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
use log::{hash, hash_event, verify_event, Entry, Event, Sha256Hash};
|
use log::{get_signature, hash, hash_event, verify_event, Entry, Event, Sha256Hash, Signature};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
@ -45,6 +46,7 @@ fn log_event<T: Serialize + Clone + Debug>(
|
||||||
fn log_events<T: Serialize + Clone + Debug>(
|
fn log_events<T: Serialize + Clone + Debug>(
|
||||||
receiver: &Receiver<Event<T>>,
|
receiver: &Receiver<Event<T>>,
|
||||||
sender: &SyncSender<Entry<T>>,
|
sender: &SyncSender<Entry<T>>,
|
||||||
|
signatures: &mut HashMap<Signature, bool>,
|
||||||
num_hashes: &mut u64,
|
num_hashes: &mut u64,
|
||||||
end_hash: &mut Sha256Hash,
|
end_hash: &mut Sha256Hash,
|
||||||
epoch: SystemTime,
|
epoch: SystemTime,
|
||||||
|
@ -63,6 +65,12 @@ fn log_events<T: Serialize + Clone + Debug>(
|
||||||
match receiver.try_recv() {
|
match receiver.try_recv() {
|
||||||
Ok(event) => {
|
Ok(event) => {
|
||||||
if verify_event(&event) {
|
if verify_event(&event) {
|
||||||
|
if let Some(sig) = get_signature(&event) {
|
||||||
|
if signatures.contains_key(&sig) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
signatures.insert(sig, true);
|
||||||
|
}
|
||||||
log_event(sender, num_hashes, end_hash, event)?;
|
log_event(sender, num_hashes, end_hash, event)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,11 +102,13 @@ pub fn create_logger<T: 'static + Serialize + Clone + Debug + Send>(
|
||||||
let mut end_hash = start_hash;
|
let mut end_hash = start_hash;
|
||||||
let mut num_hashes = 0;
|
let mut num_hashes = 0;
|
||||||
let mut num_ticks = 0;
|
let mut num_ticks = 0;
|
||||||
|
let mut signatures = HashMap::new();
|
||||||
let epoch = SystemTime::now();
|
let epoch = SystemTime::now();
|
||||||
loop {
|
loop {
|
||||||
if let Err(err) = log_events(
|
if let Err(err) = log_events(
|
||||||
&receiver,
|
&receiver,
|
||||||
&sender,
|
&sender,
|
||||||
|
&mut signatures,
|
||||||
&mut num_hashes,
|
&mut num_hashes,
|
||||||
&mut end_hash,
|
&mut end_hash,
|
||||||
epoch,
|
epoch,
|
||||||
|
@ -141,7 +151,7 @@ mod tests {
|
||||||
|
|
||||||
hist.sender.send(Event::Tick).unwrap();
|
hist.sender.send(Event::Tick).unwrap();
|
||||||
sleep(Duration::new(0, 1_000_000));
|
sleep(Duration::new(0, 1_000_000));
|
||||||
hist.sender.send(Event::Discovery { data: zero }).unwrap();
|
hist.sender.send(Event::Tick).unwrap();
|
||||||
sleep(Duration::new(0, 1_000_000));
|
sleep(Duration::new(0, 1_000_000));
|
||||||
hist.sender.send(Event::Tick).unwrap();
|
hist.sender.send(Event::Tick).unwrap();
|
||||||
|
|
||||||
|
@ -175,7 +185,7 @@ mod tests {
|
||||||
let zero = Sha256Hash::default();
|
let zero = Sha256Hash::default();
|
||||||
let hist = Historian::new(&zero, Some(20));
|
let hist = Historian::new(&zero, Some(20));
|
||||||
sleep(Duration::from_millis(30));
|
sleep(Duration::from_millis(30));
|
||||||
hist.sender.send(Event::Discovery { data: zero }).unwrap();
|
hist.sender.send(Event::Tick).unwrap();
|
||||||
sleep(Duration::from_millis(15));
|
sleep(Duration::from_millis(15));
|
||||||
drop(hist.sender);
|
drop(hist.sender);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
|
58
src/log.rs
58
src/log.rs
|
@ -37,9 +37,6 @@ pub struct Entry<T> {
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub enum Event<T> {
|
pub enum Event<T> {
|
||||||
Tick,
|
Tick,
|
||||||
Discovery {
|
|
||||||
data: T,
|
|
||||||
},
|
|
||||||
Claim {
|
Claim {
|
||||||
key: PublicKey,
|
key: PublicKey,
|
||||||
data: T,
|
data: T,
|
||||||
|
@ -104,36 +101,24 @@ pub fn hash(val: &[u8]) -> Sha256Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the hash of the given hash extended with the given value.
|
/// Return the hash of the given hash extended with the given value.
|
||||||
pub fn extend_and_hash(end_hash: &Sha256Hash, ty: u8, val: &[u8]) -> Sha256Hash {
|
pub fn extend_and_hash(end_hash: &Sha256Hash, val: &[u8]) -> Sha256Hash {
|
||||||
let mut hash_data = end_hash.to_vec();
|
let mut hash_data = end_hash.to_vec();
|
||||||
hash_data.push(ty);
|
|
||||||
hash_data.extend_from_slice(val);
|
hash_data.extend_from_slice(val);
|
||||||
hash(&hash_data)
|
hash(&hash_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash_event<T: Serialize>(end_hash: &Sha256Hash, event: &Event<T>) -> Sha256Hash {
|
pub fn get_signature<T>(event: &Event<T>) -> Option<Signature> {
|
||||||
use bincode::serialize;
|
|
||||||
match *event {
|
match *event {
|
||||||
Event::Tick => *end_hash,
|
Event::Tick => None,
|
||||||
Event::Discovery { ref data } => extend_and_hash(end_hash, 1, &serialize(&data).unwrap()),
|
Event::Claim { sig, .. } => Some(sig),
|
||||||
Event::Claim { key, ref data, sig } => {
|
Event::Transaction { sig, .. } => Some(sig),
|
||||||
let mut event_data = serialize(&data).unwrap();
|
|
||||||
event_data.extend_from_slice(&sig);
|
|
||||||
event_data.extend_from_slice(&key);
|
|
||||||
extend_and_hash(end_hash, 2, &event_data)
|
|
||||||
}
|
|
||||||
Event::Transaction {
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
ref data,
|
|
||||||
sig,
|
|
||||||
} => {
|
|
||||||
let mut event_data = serialize(&data).unwrap();
|
|
||||||
event_data.extend_from_slice(&sig);
|
|
||||||
event_data.extend_from_slice(&from);
|
|
||||||
event_data.extend_from_slice(&to);
|
|
||||||
extend_and_hash(end_hash, 2, &event_data)
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hash_event<T>(end_hash: &Sha256Hash, event: &Event<T>) -> Sha256Hash {
|
||||||
|
match get_signature(event) {
|
||||||
|
None => *end_hash,
|
||||||
|
Some(sig) => extend_and_hash(end_hash, &sig),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,15 +303,24 @@ mod tests {
|
||||||
let zero = Sha256Hash::default();
|
let zero = Sha256Hash::default();
|
||||||
let one = hash(&zero);
|
let one = hash(&zero);
|
||||||
|
|
||||||
// First, verify Discovery events
|
// First, verify Claim events
|
||||||
let events = vec![
|
let keypair = generate_keypair();
|
||||||
Event::Discovery { data: zero },
|
let event0 = Event::Claim {
|
||||||
Event::Discovery { data: one },
|
key: get_pubkey(&keypair),
|
||||||
];
|
data: zero,
|
||||||
|
sig: sign_serialized(&zero, &keypair),
|
||||||
|
};
|
||||||
|
|
||||||
|
let event1 = Event::Claim {
|
||||||
|
key: get_pubkey(&keypair),
|
||||||
|
data: one,
|
||||||
|
sig: sign_serialized(&one, &keypair),
|
||||||
|
};
|
||||||
|
let events = vec![event0, event1];
|
||||||
let mut entries = create_entries(&zero, 0, events);
|
let mut entries = create_entries(&zero, 0, events);
|
||||||
assert!(verify_slice(&entries, &zero));
|
assert!(verify_slice(&entries, &zero));
|
||||||
|
|
||||||
// Next, swap two Discovery events and ensure verification fails.
|
// Next, swap two Claim events and ensure verification fails.
|
||||||
let event0 = entries[0].event.clone();
|
let event0 = entries[0].event.clone();
|
||||||
let event1 = entries[1].event.clone();
|
let event1 = entries[1].event.clone();
|
||||||
entries[0].event = event1;
|
entries[0].event = event1;
|
||||||
|
|
Loading…
Reference in New Issue