Update the set of unique signatures when loading an existing log.
This commit is contained in:
@ -3,9 +3,9 @@
|
|||||||
//! transfer funds to other users.
|
//! transfer funds to other users.
|
||||||
|
|
||||||
use log::{hash, Entry, Sha256Hash};
|
use log::{hash, Entry, Sha256Hash};
|
||||||
use event::{get_pubkey, sign_transaction_data, Event, PublicKey, Signature};
|
use event::{get_pubkey, sign_transaction_data, verify_event, Event, PublicKey, Signature};
|
||||||
use genesis::Genesis;
|
use genesis::Genesis;
|
||||||
use historian::Historian;
|
use historian::{reserve_signature, Historian};
|
||||||
use ring::signature::Ed25519KeyPair;
|
use ring::signature::Ed25519KeyPair;
|
||||||
use std::sync::mpsc::SendError;
|
use std::sync::mpsc::SendError;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -37,7 +37,7 @@ impl Accountant {
|
|||||||
balances: HashMap::new(),
|
balances: HashMap::new(),
|
||||||
last_id: start_hash,
|
last_id: start_hash,
|
||||||
};
|
};
|
||||||
for (i, event) in gen.create_events().into_iter().enumerate() {
|
for (i, event) in gen.create_events().iter().enumerate() {
|
||||||
acc.process_verified_event(event, i < 2).unwrap();
|
acc.process_verified_event(event, i < 2).unwrap();
|
||||||
}
|
}
|
||||||
acc
|
acc
|
||||||
@ -61,46 +61,50 @@ impl Accountant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_event(self: &mut Self, event: Event<u64>) -> Result<()> {
|
pub fn process_event(self: &mut Self, event: Event<u64>) -> Result<()> {
|
||||||
if !self.historian.verify_event(&event) {
|
if !verify_event(&event) {
|
||||||
return Err(AccountingError::InvalidEvent);
|
return Err(AccountingError::InvalidEvent);
|
||||||
}
|
}
|
||||||
self.process_verified_event(event, false)
|
|
||||||
|
if let Event::Transaction { from, data, .. } = event {
|
||||||
|
if self.get_balance(&from).unwrap_or(0) < data {
|
||||||
|
return Err(AccountingError::InsufficientFunds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.process_verified_event(&event, false)?;
|
||||||
|
|
||||||
|
if let Err(SendError(_)) = self.historian.sender.send(event) {
|
||||||
|
return Err(AccountingError::SendError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_verified_event(
|
fn process_verified_event(
|
||||||
self: &mut Self,
|
self: &mut Self,
|
||||||
event: Event<u64>,
|
event: &Event<u64>,
|
||||||
allow_deposits: bool,
|
allow_deposits: bool,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
match event {
|
if !reserve_signature(&mut self.historian.signatures, event) {
|
||||||
Event::Tick => Ok(()),
|
return Err(AccountingError::InvalidEvent);
|
||||||
Event::Transaction { from, to, data, .. } => {
|
}
|
||||||
if !Self::is_deposit(allow_deposits, &from, &to) {
|
|
||||||
if self.get_balance(&from).unwrap_or(0) < data {
|
|
||||||
return Err(AccountingError::InsufficientFunds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(SendError(_)) = self.historian.sender.send(event) {
|
if let Event::Transaction { from, to, data, .. } = *event {
|
||||||
return Err(AccountingError::SendError);
|
if !Self::is_deposit(allow_deposits, &from, &to) {
|
||||||
|
if let Some(x) = self.balances.get_mut(&from) {
|
||||||
|
*x -= data;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if !Self::is_deposit(allow_deposits, &from, &to) {
|
if self.balances.contains_key(&to) {
|
||||||
if let Some(x) = self.balances.get_mut(&from) {
|
if let Some(x) = self.balances.get_mut(&to) {
|
||||||
*x -= data;
|
*x += data;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
if self.balances.contains_key(&to) {
|
self.balances.insert(to, data);
|
||||||
if let Some(x) = self.balances.get_mut(&to) {
|
|
||||||
*x += data;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self.balances.insert(to, data);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn transfer(
|
pub fn transfer(
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
//! The `historian` crate provides a microservice for generating a Proof-of-History.
|
//! The `historian` crate provides a microservice for generating a Proof-of-History.
|
||||||
//! It manages a thread containing a Proof-of-History Logger.
|
//! It manages a thread containing a Proof-of-History Logger.
|
||||||
|
|
||||||
use std::thread::JoinHandle;
|
use std::thread::{spawn, JoinHandle};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use log::{hash, Entry, Sha256Hash};
|
use log::{hash, Entry, Sha256Hash};
|
||||||
use logger::{verify_event_and_reserve_signature, ExitReason, Logger};
|
use logger::{ExitReason, Logger};
|
||||||
use event::{Event, Signature};
|
use event::{get_signature, Event, Signature};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
pub struct Historian<T> {
|
pub struct Historian<T> {
|
||||||
pub sender: SyncSender<Event<T>>,
|
pub sender: SyncSender<Event<T>>,
|
||||||
@ -34,10 +33,6 @@ impl<T: 'static + Serialize + Clone + Debug + Send> Historian<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_event(self: &mut Self, event: &Event<T>) -> bool {
|
|
||||||
return verify_event_and_reserve_signature(&mut self.signatures, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A background thread that will continue tagging received Event messages and
|
/// A background thread that will continue tagging received Event messages and
|
||||||
/// sending back Entry messages until either the receiver or sender channel is closed.
|
/// sending back Entry messages until either the receiver or sender channel is closed.
|
||||||
fn create_logger(
|
fn create_logger(
|
||||||
@ -46,7 +41,7 @@ impl<T: 'static + Serialize + Clone + Debug + Send> Historian<T> {
|
|||||||
receiver: Receiver<Event<T>>,
|
receiver: Receiver<Event<T>>,
|
||||||
sender: SyncSender<Entry<T>>,
|
sender: SyncSender<Entry<T>>,
|
||||||
) -> JoinHandle<(Entry<T>, ExitReason)> {
|
) -> JoinHandle<(Entry<T>, ExitReason)> {
|
||||||
thread::spawn(move || {
|
spawn(move || {
|
||||||
let mut logger = Logger::new(receiver, sender, start_hash);
|
let mut logger = Logger::new(receiver, sender, start_hash);
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
loop {
|
loop {
|
||||||
@ -60,6 +55,16 @@ impl<T: 'static + Serialize + Clone + Debug + Send> Historian<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reserve_signature<T>(sigs: &mut HashSet<Signature>, event: &Event<T>) -> bool {
|
||||||
|
if let Some(sig) = get_signature(&event) {
|
||||||
|
if sigs.contains(&sig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sigs.insert(sig);
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -104,6 +109,18 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_duplicate_event_signature() {
|
||||||
|
let keypair = generate_keypair();
|
||||||
|
let to = get_pubkey(&keypair);
|
||||||
|
let data = b"hello, world";
|
||||||
|
let sig = sign_claim_data(&data, &keypair);
|
||||||
|
let event0 = Event::new_claim(to, &data, sig);
|
||||||
|
let mut sigs = HashSet::new();
|
||||||
|
assert!(reserve_signature(&mut sigs, &event0));
|
||||||
|
assert!(!reserve_signature(&mut sigs, &event0));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ticking_historian() {
|
fn test_ticking_historian() {
|
||||||
let zero = Sha256Hash::default();
|
let zero = Sha256Hash::default();
|
||||||
|
@ -5,11 +5,10 @@
|
|||||||
//! Event, the latest hash, and the number of hashes since the last event.
|
//! Event, the latest hash, and the number of hashes since the last event.
|
||||||
//! The resulting stream of entries represents ordered events in time.
|
//! The resulting stream of entries represents ordered events in time.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use std::sync::mpsc::{Receiver, SyncSender, TryRecvError};
|
use std::sync::mpsc::{Receiver, SyncSender, TryRecvError};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
use log::{create_entry_mut, Entry, Sha256Hash};
|
use log::{create_entry_mut, Entry, Sha256Hash};
|
||||||
use event::{get_signature, verify_event, Event, Signature};
|
use event::Event;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
@ -27,22 +26,6 @@ pub struct Logger<T> {
|
|||||||
pub num_ticks: u64,
|
pub num_ticks: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_event_and_reserve_signature<T: Serialize>(
|
|
||||||
signatures: &mut HashSet<Signature>,
|
|
||||||
event: &Event<T>,
|
|
||||||
) -> bool {
|
|
||||||
if !verify_event(&event) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if let Some(sig) = get_signature(&event) {
|
|
||||||
if signatures.contains(&sig) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
signatures.insert(sig);
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Serialize + Clone + Debug> Logger<T> {
|
impl<T: Serialize + Clone + Debug> Logger<T> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
receiver: Receiver<Event<T>>,
|
receiver: Receiver<Event<T>>,
|
||||||
@ -111,21 +94,7 @@ mod tests {
|
|||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let sig = sign_claim_data(&hash(b"hello, world"), &keypair);
|
let sig = sign_claim_data(&hash(b"hello, world"), &keypair);
|
||||||
let event0 = Event::new_claim(get_pubkey(&keypair), hash(b"goodbye cruel world"), sig);
|
let event0 = Event::new_claim(get_pubkey(&keypair), hash(b"goodbye cruel world"), sig);
|
||||||
let mut sigs = HashSet::new();
|
assert!(!verify_event(&event0));
|
||||||
assert!(!verify_event_and_reserve_signature(&mut sigs, &event0));
|
|
||||||
assert!(!sigs.contains(&sig));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_duplicate_event_signature() {
|
|
||||||
let keypair = generate_keypair();
|
|
||||||
let to = get_pubkey(&keypair);
|
|
||||||
let data = &hash(b"hello, world");
|
|
||||||
let sig = sign_claim_data(data, &keypair);
|
|
||||||
let event0 = Event::new_claim(to, data, sig);
|
|
||||||
let mut sigs = HashSet::new();
|
|
||||||
assert!(verify_event_and_reserve_signature(&mut sigs, &event0));
|
|
||||||
assert!(!verify_event_and_reserve_signature(&mut sigs, &event0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_genesis(gen: Genesis) -> Vec<Entry<u64>> {
|
fn run_genesis(gen: Genesis) -> Vec<Entry<u64>> {
|
||||||
|
Reference in New Issue
Block a user