Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unify Claim and Transaction handling #30

Merged
merged 13 commits into from
Mar 2, 2018
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@ with by verifying each entry's hash can be generated from the hash in the previo
extern crate silk;

use silk::historian::Historian;
use silk::log::{verify_slice, Entry, Event, Sha256Hash};
use silk::log::{verify_slice, Entry, Sha256Hash};
use silk::event::{generate_keypair, get_pubkey, sign_claim_data, Event};
use std::thread::sleep;
use std::time::Duration;
use std::sync::mpsc::SendError;

fn create_log(hist: &Historian) -> Result<(), SendError<Event>> {
fn create_log(hist: &Historian<Sha256Hash>) -> Result<(), SendError<Event<Sha256Hash>>> {
sleep(Duration::from_millis(15));
let data = Sha256Hash::default();
hist.sender.send(Event::Claim { data })?;
let keypair = generate_keypair();
let event0 = Event::new_claim(get_pubkey(&keypair), data, sign_claim_data(&data, &keypair));
hist.sender.send(event0)?;
sleep(Duration::from_millis(10));
Ok(())
}
Expand All @@ -55,11 +58,10 @@ fn main() {
let hist = Historian::new(&seed, Some(10));
create_log(&hist).expect("send error");
drop(hist.sender);
let entries: Vec<Entry> = hist.receiver.iter().collect();
let entries: Vec<Entry<Sha256Hash>> = hist.receiver.iter().collect();
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));
Expand All @@ -70,7 +72,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: Claim { data: [37, ...] } }
Entry { num_hashes: 2, end_hash: [67, ...], event: Transaction { data: [37, ...] } }
Entry { num_hashes: 3, end_hash: [123, ...], event: Tick }
```

Expand Down
137 changes: 69 additions & 68 deletions src/accountant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@
//! event log to record transactions. Its users can deposit funds and
//! transfer funds to other users.

use log::{Entry, Event, PublicKey, Sha256Hash, Signature};
use log::{Entry, Sha256Hash};
use event::{Event, PublicKey, Signature};
use historian::Historian;
use ring::signature::Ed25519KeyPair;
use std::sync::mpsc::{RecvError, SendError};
use std::sync::mpsc::SendError;
use std::collections::HashMap;
use std::result;

#[derive(Debug, PartialEq, Eq)]
pub enum AccountingError {
InsufficientFunds,
InvalidEvent,
SendError,
}

pub type Result<T> = result::Result<T, AccountingError>;

pub struct Accountant {
pub historian: Historian<u64>,
Expand All @@ -24,71 +35,43 @@ impl Accountant {
}
}

pub fn process_event(self: &mut Self, event: &Event<u64>) {
match *event {
Event::Claim { key, data, .. } => {
if self.balances.contains_key(&key) {
if let Some(x) = self.balances.get_mut(&key) {
*x += data;
}
} else {
self.balances.insert(key, data);
}
}
Event::Transaction { from, to, data, .. } => {
if let Some(x) = self.balances.get_mut(&from) {
*x -= data;
}
if self.balances.contains_key(&to) {
if let Some(x) = self.balances.get_mut(&to) {
*x += data;
}
} else {
self.balances.insert(to, data);
}
}
_ => (),
}
}

pub fn sync(self: &mut Self) -> Vec<Entry<u64>> {
let mut entries = vec![];
while let Ok(entry) = self.historian.receiver.try_recv() {
entries.push(entry);
}
// TODO: Does this cause the historian's channel to get blocked?
//use log::verify_slice_u64;
//println!("accountant: verifying {} entries...", entries.len());
//assert!(verify_slice_u64(&entries, &self.end_hash));
//println!("accountant: Done verifying {} entries.", entries.len());

if let Some(last_entry) = entries.last() {
self.end_hash = last_entry.end_hash;
}
for e in &entries {
self.process_event(&e.event);
}

entries
}

pub fn deposit_signed(
self: &Self,
key: PublicKey,
data: u64,
sig: Signature,
) -> Result<(), SendError<Event<u64>>> {
let event = Event::Claim { key, data, sig };
self.historian.sender.send(event)
pub fn deposit_signed(self: &mut Self, to: PublicKey, data: u64, sig: Signature) -> Result<()> {
let event = Event::new_claim(to, data, sig);
if !self.historian.verify_event(&event) {
return Err(AccountingError::InvalidEvent);
}
if let Err(SendError(_)) = self.historian.sender.send(event) {
return Err(AccountingError::SendError);
}

if self.balances.contains_key(&to) {
if let Some(x) = self.balances.get_mut(&to) {
*x += data;
}
} else {
self.balances.insert(to, data);
}

Ok(())
}

pub fn deposit(
self: &Self,
n: u64,
keypair: &Ed25519KeyPair,
) -> Result<Signature, SendError<Event<u64>>> {
use log::{get_pubkey, sign_serialized};
pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> Result<Signature> {
use event::{get_pubkey, sign_claim_data};
let key = get_pubkey(keypair);
let sig = sign_serialized(&n, keypair);
let sig = sign_claim_data(&n, keypair);
self.deposit_signed(key, n, sig).map(|_| sig)
}

Expand All @@ -98,37 +81,53 @@ impl Accountant {
to: PublicKey,
data: u64,
sig: Signature,
) -> Result<(), SendError<Event<u64>>> {
if self.get_balance(&from).unwrap() < data {
// TODO: Replace the SendError result with a custom one.
println!("Error: Insufficient funds");
return Ok(());
) -> Result<()> {
if self.get_balance(&from).unwrap_or(0) < data {
return Err(AccountingError::InsufficientFunds);
}

let event = Event::Transaction {
from,
from: Some(from),
to,
data,
sig,
};
self.historian.sender.send(event)
if !self.historian.verify_event(&event) {
return Err(AccountingError::InvalidEvent);
}
if let Err(SendError(_)) = self.historian.sender.send(event) {
return Err(AccountingError::SendError);
}

if let Some(x) = self.balances.get_mut(&from) {
*x -= data;
}

if self.balances.contains_key(&to) {
if let Some(x) = self.balances.get_mut(&to) {
*x += data;
}
} else {
self.balances.insert(to, data);
}

Ok(())
}

pub fn transfer(
self: &mut Self,
n: u64,
keypair: &Ed25519KeyPair,
to: PublicKey,
) -> Result<Signature, SendError<Event<u64>>> {
use log::{get_pubkey, sign_transaction_data};

) -> Result<Signature> {
use event::{get_pubkey, sign_transaction_data};
let from = get_pubkey(keypair);
let sig = sign_transaction_data(&n, keypair, &to);
self.transfer_signed(from, to, n, sig).map(|_| sig)
}

pub fn get_balance(self: &mut Self, pubkey: &PublicKey) -> Result<u64, RecvError> {
self.sync();
Ok(*self.balances.get(pubkey).unwrap_or(&0))
pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option<u64> {
self.balances.get(pubkey).map(|x| *x)
}

pub fn wait_on_signature(self: &mut Self, wait_sig: &Signature) {
Expand All @@ -138,7 +137,6 @@ impl Accountant {
let mut found = false;
while !found {
found = entries.iter().any(|e| match e.event {
Event::Claim { sig, .. } => sig == *wait_sig,
Event::Transaction { sig, .. } => sig == *wait_sig,
_ => false,
});
Expand All @@ -153,7 +151,7 @@ impl Accountant {
#[cfg(test)]
mod tests {
use super::*;
use log::{generate_keypair, get_pubkey};
use event::{generate_keypair, get_pubkey};
use historian::ExitReason;

#[test]
Expand Down Expand Up @@ -192,7 +190,10 @@ mod tests {
acc.wait_on_signature(&sig);

let bob_pubkey = get_pubkey(&bob_keypair);
acc.transfer(10_001, &alice_keypair, bob_pubkey).unwrap();
assert_eq!(
acc.transfer(10_001, &alice_keypair, bob_pubkey),
Err(AccountingError::InsufficientFunds)
);
sleep(Duration::from_millis(30));

let alice_pubkey = get_pubkey(&alice_keypair);
Expand Down
2 changes: 1 addition & 1 deletion src/accountant_skel.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::io;
use accountant::Accountant;
use log::{PublicKey, Signature};
use event::{PublicKey, Signature};
//use serde::Serialize;

pub struct AccountantSkel {
Expand Down
11 changes: 6 additions & 5 deletions src/accountant_stub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use std::net::UdpSocket;
use std::io;
use bincode::{deserialize, serialize};
use log::{PublicKey, Signature};
use event::{PublicKey, Signature};
use ring::signature::Ed25519KeyPair;
use accountant_skel::{Request, Response};

Expand Down Expand Up @@ -34,9 +34,9 @@ impl AccountantStub {
}

pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> io::Result<Signature> {
use log::{get_pubkey, sign_serialized};
use event::{get_pubkey, sign_claim_data};
let key = get_pubkey(keypair);
let sig = sign_serialized(&n, keypair);
let sig = sign_claim_data(&n, keypair);
self.deposit_signed(key, n, sig).map(|_| sig)
}

Expand All @@ -58,7 +58,7 @@ impl AccountantStub {
keypair: &Ed25519KeyPair,
to: PublicKey,
) -> io::Result<Signature> {
use log::{get_pubkey, sign_transaction_data};
use event::{get_pubkey, sign_transaction_data};
let from = get_pubkey(keypair);
let sig = sign_transaction_data(&n, keypair, &to);
self.transfer_signed(from, to, n, sig).map(|_| sig)
Expand Down Expand Up @@ -100,7 +100,8 @@ mod tests {
use accountant_skel::AccountantSkel;
use std::thread::{sleep, spawn};
use std::time::Duration;
use log::{generate_keypair, get_pubkey, Sha256Hash};
use log::Sha256Hash;
use event::{generate_keypair, get_pubkey};

#[test]
fn test_accountant_stub() {
Expand Down
4 changes: 2 additions & 2 deletions src/bin/client-demo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ fn main() {
use silk::accountant_stub::AccountantStub;
use std::time::Instant;
use std::net::UdpSocket;
use silk::log::{generate_keypair, get_pubkey};
use silk::event::{generate_keypair, get_pubkey};

let addr = "127.0.0.1:8000";
let send_addr = "127.0.0.1:8001";
let socket = UdpSocket::bind(send_addr).unwrap();
let mut acc = AccountantStub::new(addr, socket);
let alice_keypair = generate_keypair();
let alice_pubkey = get_pubkey(&alice_keypair);
let txs = 10_000;
let txs = 2_000;
println!("Depositing {} units in Alice's account...", txs);
let sig = acc.deposit(txs, &alice_keypair).unwrap();
acc.wait_on_signature(&sig).unwrap();
Expand Down
12 changes: 5 additions & 7 deletions src/bin/demo.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
extern crate silk;

use silk::historian::Historian;
use silk::log::{generate_keypair, get_pubkey, sign_serialized, verify_slice, Entry, Event,
Sha256Hash};
use silk::log::{verify_slice, Entry, Sha256Hash};
use silk::event::{generate_keypair, get_pubkey, sign_claim_data, Event};
use std::thread::sleep;
use std::time::Duration;
use std::sync::mpsc::SendError;
Expand All @@ -11,11 +11,7 @@ fn create_log(hist: &Historian<Sha256Hash>) -> Result<(), SendError<Event<Sha256
sleep(Duration::from_millis(15));
let data = Sha256Hash::default();
let keypair = generate_keypair();
let event0 = Event::Claim {
key: get_pubkey(&keypair),
data,
sig: sign_serialized(&data, &keypair),
};
let event0 = Event::new_claim(get_pubkey(&keypair), data, sign_claim_data(&data, &keypair));
hist.sender.send(event0)?;
sleep(Duration::from_millis(10));
Ok(())
Expand All @@ -30,5 +26,7 @@ fn main() {
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));
}
Loading