diff --git a/README.md b/README.md index 742057a19..57a0f0e5c 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ use std::sync::mpsc::SendError; fn create_log(hist: &Historian) -> Result<(), SendError> { sleep(Duration::from_millis(15)); let data = Sha256Hash::default(); - hist.sender.send(Event::Discovery { data })?; + hist.sender.send(Event::Claim { data })?; sleep(Duration::from_millis(10)); Ok(()) } @@ -70,7 +70,7 @@ Running the program should produce a log similar to: ```rust 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 } ``` diff --git a/diagrams/historian.msc b/diagrams/historian.msc index b2cb4e3d5..75cf1615a 100644 --- a/diagrams/historian.msc +++ b/diagrams/historian.msc @@ -4,10 +4,10 @@ msc { logger=>historian [ label = "e0 = Entry{hash: h0, n: 0, event: Tick}" ] ; logger=>logger [ label = "h1 = hash(h0)" ] ; logger=>logger [ label = "h2 = hash(h1)" ] ; - client=>historian [ label = "Discovery(d0)" ] ; - historian=>logger [ label = "Discovery(d0)" ] ; + client=>historian [ label = "Claim(d0)" ] ; + historian=>logger [ label = "Claim(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 = "h5 = hash(h4)" ] ; logger=>logger [ label = "h6 = hash(h5)" ] ; diff --git a/src/accountant.rs b/src/accountant.rs index ab2e3adc8..627f214ba 100644 --- a/src/accountant.rs +++ b/src/accountant.rs @@ -11,7 +11,6 @@ use std::collections::HashMap; pub struct Accountant { pub historian: Historian, pub balances: HashMap, - pub signatures: HashMap, pub end_hash: Sha256Hash, } @@ -21,19 +20,13 @@ impl Accountant { Accountant { historian: hist, balances: HashMap::new(), - signatures: HashMap::new(), end_hash: *start_hash, } } pub fn process_event(self: &mut Self, event: &Event) { match *event { - Event::Claim { key, data, sig } => { - if self.signatures.contains_key(&sig) { - return; - } - self.signatures.insert(sig, true); - + Event::Claim { key, data, .. } => { if self.balances.contains_key(&key) { if let Some(x) = self.balances.get_mut(&key) { *x += data; @@ -42,16 +35,7 @@ impl Accountant { self.balances.insert(key, data); } } - Event::Transaction { - from, - to, - data, - sig, - } => { - if self.signatures.contains_key(&sig) { - return; - } - self.signatures.insert(sig, true); + Event::Transaction { from, to, data, .. } => { if let Some(x) = self.balances.get_mut(&from) { *x -= data; } diff --git a/src/bin/demo.rs b/src/bin/demo.rs index 0787b3b30..a8f502a87 100644 --- a/src/bin/demo.rs +++ b/src/bin/demo.rs @@ -1,7 +1,8 @@ extern crate silk; 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::time::Duration; use std::sync::mpsc::SendError; @@ -9,7 +10,13 @@ use std::sync::mpsc::SendError; fn create_log(hist: &Historian) -> Result<(), SendError>> { sleep(Duration::from_millis(15)); 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)); Ok(()) } diff --git a/src/historian.rs b/src/historian.rs index 1606080ed..1a0441451 100644 --- a/src/historian.rs +++ b/src/historian.rs @@ -6,9 +6,10 @@ //! The resulting stream of entries represents ordered events in time. use std::thread::JoinHandle; +use std::collections::HashMap; use std::sync::mpsc::{Receiver, SyncSender}; 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 std::fmt::Debug; @@ -45,6 +46,7 @@ fn log_event( fn log_events( receiver: &Receiver>, sender: &SyncSender>, + signatures: &mut HashMap, num_hashes: &mut u64, end_hash: &mut Sha256Hash, epoch: SystemTime, @@ -63,6 +65,12 @@ fn log_events( match receiver.try_recv() { Ok(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)?; } } @@ -94,11 +102,13 @@ pub fn create_logger( let mut end_hash = start_hash; let mut num_hashes = 0; let mut num_ticks = 0; + let mut signatures = HashMap::new(); let epoch = SystemTime::now(); loop { if let Err(err) = log_events( &receiver, &sender, + &mut signatures, &mut num_hashes, &mut end_hash, epoch, @@ -141,7 +151,7 @@ mod tests { hist.sender.send(Event::Tick).unwrap(); 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)); hist.sender.send(Event::Tick).unwrap(); @@ -175,7 +185,7 @@ mod tests { let zero = Sha256Hash::default(); let hist = Historian::new(&zero, Some(20)); sleep(Duration::from_millis(30)); - hist.sender.send(Event::Discovery { data: zero }).unwrap(); + hist.sender.send(Event::Tick).unwrap(); sleep(Duration::from_millis(15)); drop(hist.sender); assert_eq!( diff --git a/src/log.rs b/src/log.rs index 523a12afa..04a3b2482 100644 --- a/src/log.rs +++ b/src/log.rs @@ -37,9 +37,6 @@ pub struct Entry { #[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)] pub enum Event { Tick, - Discovery { - data: T, - }, Claim { key: PublicKey, data: T, @@ -104,36 +101,24 @@ pub fn hash(val: &[u8]) -> Sha256Hash { } /// 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(); - hash_data.push(ty); hash_data.extend_from_slice(val); hash(&hash_data) } -pub fn hash_event(end_hash: &Sha256Hash, event: &Event) -> Sha256Hash { - use bincode::serialize; +pub fn get_signature(event: &Event) -> Option { match *event { - Event::Tick => *end_hash, - Event::Discovery { ref data } => extend_and_hash(end_hash, 1, &serialize(&data).unwrap()), - Event::Claim { key, ref data, 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) - } + Event::Tick => None, + Event::Claim { sig, .. } => Some(sig), + Event::Transaction { sig, .. } => Some(sig), + } +} + +pub fn hash_event(end_hash: &Sha256Hash, event: &Event) -> 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 one = hash(&zero); - // First, verify Discovery events - let events = vec![ - Event::Discovery { data: zero }, - Event::Discovery { data: one }, - ]; + // First, verify Claim events + let keypair = generate_keypair(); + let event0 = Event::Claim { + 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); 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 event1 = entries[1].event.clone(); entries[0].event = event1;