Merge pull request #30 from garious/simplify
Unify Claim and Transaction handling
This commit is contained in:
commit
8871bb2d8e
14
README.md
14
README.md
|
@ -37,15 +37,18 @@ with by verifying each entry's hash can be generated from the hash in the previo
|
||||||
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::{verify_slice, Entry, Sha256Hash};
|
||||||
|
use silk::event::{generate_keypair, get_pubkey, sign_claim_data, Event};
|
||||||
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;
|
||||||
|
|
||||||
fn create_log(hist: &Historian) -> Result<(), SendError<Event>> {
|
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::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));
|
sleep(Duration::from_millis(10));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -55,11 +58,10 @@ fn main() {
|
||||||
let hist = Historian::new(&seed, Some(10));
|
let hist = Historian::new(&seed, Some(10));
|
||||||
create_log(&hist).expect("send error");
|
create_log(&hist).expect("send error");
|
||||||
drop(hist.sender);
|
drop(hist.sender);
|
||||||
let entries: Vec<Entry> = hist.receiver.iter().collect();
|
let entries: Vec<Entry<Sha256Hash>> = hist.receiver.iter().collect();
|
||||||
for entry in &entries {
|
for entry in &entries {
|
||||||
println!("{:?}", entry);
|
println!("{:?}", entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proof-of-History: Verify the historian learned about the events
|
// Proof-of-History: Verify the historian learned about the events
|
||||||
// in the same order they appear in the vector.
|
// in the same order they appear in the vector.
|
||||||
assert!(verify_slice(&entries, &seed));
|
assert!(verify_slice(&entries, &seed));
|
||||||
|
@ -70,7 +72,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: Claim { data: [37, ...] } }
|
Entry { num_hashes: 2, end_hash: [67, ...], event: Transaction { data: [37, ...] } }
|
||||||
Entry { num_hashes: 3, end_hash: [123, ...], event: Tick }
|
Entry { num_hashes: 3, end_hash: [123, ...], event: Tick }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,22 @@
|
||||||
//! event log to record transactions. Its users can deposit funds and
|
//! event log to record transactions. Its users can deposit funds and
|
||||||
//! transfer funds to other users.
|
//! 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 historian::Historian;
|
||||||
use ring::signature::Ed25519KeyPair;
|
use ring::signature::Ed25519KeyPair;
|
||||||
use std::sync::mpsc::{RecvError, SendError};
|
use std::sync::mpsc::SendError;
|
||||||
use std::collections::HashMap;
|
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 struct Accountant {
|
||||||
pub historian: Historian<u64>,
|
pub historian: Historian<u64>,
|
||||||
|
@ -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>> {
|
pub fn sync(self: &mut Self) -> Vec<Entry<u64>> {
|
||||||
let mut entries = vec![];
|
let mut entries = vec![];
|
||||||
while let Ok(entry) = self.historian.receiver.try_recv() {
|
while let Ok(entry) = self.historian.receiver.try_recv() {
|
||||||
entries.push(entry);
|
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() {
|
if let Some(last_entry) = entries.last() {
|
||||||
self.end_hash = last_entry.end_hash;
|
self.end_hash = last_entry.end_hash;
|
||||||
}
|
}
|
||||||
for e in &entries {
|
|
||||||
self.process_event(&e.event);
|
|
||||||
}
|
|
||||||
|
|
||||||
entries
|
entries
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deposit_signed(
|
pub fn deposit_signed(self: &mut Self, to: PublicKey, data: u64, sig: Signature) -> Result<()> {
|
||||||
self: &Self,
|
let event = Event::new_claim(to, data, sig);
|
||||||
key: PublicKey,
|
if !self.historian.verify_event(&event) {
|
||||||
data: u64,
|
return Err(AccountingError::InvalidEvent);
|
||||||
sig: Signature,
|
}
|
||||||
) -> Result<(), SendError<Event<u64>>> {
|
if let Err(SendError(_)) = self.historian.sender.send(event) {
|
||||||
let event = Event::Claim { key, data, sig };
|
return Err(AccountingError::SendError);
|
||||||
self.historian.sender.send(event)
|
}
|
||||||
|
|
||||||
|
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(
|
pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> Result<Signature> {
|
||||||
self: &Self,
|
use event::{get_pubkey, sign_claim_data};
|
||||||
n: u64,
|
|
||||||
keypair: &Ed25519KeyPair,
|
|
||||||
) -> Result<Signature, SendError<Event<u64>>> {
|
|
||||||
use log::{get_pubkey, sign_serialized};
|
|
||||||
let key = get_pubkey(keypair);
|
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)
|
self.deposit_signed(key, n, sig).map(|_| sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,19 +81,37 @@ impl Accountant {
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
data: u64,
|
data: u64,
|
||||||
sig: Signature,
|
sig: Signature,
|
||||||
) -> Result<(), SendError<Event<u64>>> {
|
) -> Result<()> {
|
||||||
if self.get_balance(&from).unwrap() < data {
|
if self.get_balance(&from).unwrap_or(0) < data {
|
||||||
// TODO: Replace the SendError result with a custom one.
|
return Err(AccountingError::InsufficientFunds);
|
||||||
println!("Error: Insufficient funds");
|
|
||||||
return Ok(());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let event = Event::Transaction {
|
let event = Event::Transaction {
|
||||||
from,
|
from: Some(from),
|
||||||
to,
|
to,
|
||||||
data,
|
data,
|
||||||
sig,
|
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(
|
pub fn transfer(
|
||||||
|
@ -118,17 +119,15 @@ impl Accountant {
|
||||||
n: u64,
|
n: u64,
|
||||||
keypair: &Ed25519KeyPair,
|
keypair: &Ed25519KeyPair,
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
) -> Result<Signature, SendError<Event<u64>>> {
|
) -> Result<Signature> {
|
||||||
use log::{get_pubkey, sign_transaction_data};
|
use event::{get_pubkey, sign_transaction_data};
|
||||||
|
|
||||||
let from = get_pubkey(keypair);
|
let from = get_pubkey(keypair);
|
||||||
let sig = sign_transaction_data(&n, keypair, &to);
|
let sig = sign_transaction_data(&n, keypair, &to);
|
||||||
self.transfer_signed(from, to, n, sig).map(|_| sig)
|
self.transfer_signed(from, to, n, sig).map(|_| sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_balance(self: &mut Self, pubkey: &PublicKey) -> Result<u64, RecvError> {
|
pub fn get_balance(self: &Self, pubkey: &PublicKey) -> Option<u64> {
|
||||||
self.sync();
|
self.balances.get(pubkey).map(|x| *x)
|
||||||
Ok(*self.balances.get(pubkey).unwrap_or(&0))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wait_on_signature(self: &mut Self, wait_sig: &Signature) {
|
pub fn wait_on_signature(self: &mut Self, wait_sig: &Signature) {
|
||||||
|
@ -138,7 +137,6 @@ impl Accountant {
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
while !found {
|
while !found {
|
||||||
found = entries.iter().any(|e| match e.event {
|
found = entries.iter().any(|e| match e.event {
|
||||||
Event::Claim { sig, .. } => sig == *wait_sig,
|
|
||||||
Event::Transaction { sig, .. } => sig == *wait_sig,
|
Event::Transaction { sig, .. } => sig == *wait_sig,
|
||||||
_ => false,
|
_ => false,
|
||||||
});
|
});
|
||||||
|
@ -153,7 +151,7 @@ impl Accountant {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use log::{generate_keypair, get_pubkey};
|
use event::{generate_keypair, get_pubkey};
|
||||||
use historian::ExitReason;
|
use historian::ExitReason;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -192,7 +190,10 @@ mod tests {
|
||||||
acc.wait_on_signature(&sig);
|
acc.wait_on_signature(&sig);
|
||||||
|
|
||||||
let bob_pubkey = get_pubkey(&bob_keypair);
|
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));
|
sleep(Duration::from_millis(30));
|
||||||
|
|
||||||
let alice_pubkey = get_pubkey(&alice_keypair);
|
let alice_pubkey = get_pubkey(&alice_keypair);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
use accountant::Accountant;
|
use accountant::Accountant;
|
||||||
use log::{PublicKey, Signature};
|
use event::{PublicKey, Signature};
|
||||||
//use serde::Serialize;
|
//use serde::Serialize;
|
||||||
|
|
||||||
pub struct AccountantSkel {
|
pub struct AccountantSkel {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
use std::net::UdpSocket;
|
use std::net::UdpSocket;
|
||||||
use std::io;
|
use std::io;
|
||||||
use bincode::{deserialize, serialize};
|
use bincode::{deserialize, serialize};
|
||||||
use log::{PublicKey, Signature};
|
use event::{PublicKey, Signature};
|
||||||
use ring::signature::Ed25519KeyPair;
|
use ring::signature::Ed25519KeyPair;
|
||||||
use accountant_skel::{Request, Response};
|
use accountant_skel::{Request, Response};
|
||||||
|
|
||||||
|
@ -34,9 +34,9 @@ impl AccountantStub {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deposit(self: &mut Self, n: u64, keypair: &Ed25519KeyPair) -> io::Result<Signature> {
|
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 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)
|
self.deposit_signed(key, n, sig).map(|_| sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ impl AccountantStub {
|
||||||
keypair: &Ed25519KeyPair,
|
keypair: &Ed25519KeyPair,
|
||||||
to: PublicKey,
|
to: PublicKey,
|
||||||
) -> io::Result<Signature> {
|
) -> io::Result<Signature> {
|
||||||
use log::{get_pubkey, sign_transaction_data};
|
use event::{get_pubkey, sign_transaction_data};
|
||||||
let from = get_pubkey(keypair);
|
let from = get_pubkey(keypair);
|
||||||
let sig = sign_transaction_data(&n, keypair, &to);
|
let sig = sign_transaction_data(&n, keypair, &to);
|
||||||
self.transfer_signed(from, to, n, sig).map(|_| sig)
|
self.transfer_signed(from, to, n, sig).map(|_| sig)
|
||||||
|
@ -100,7 +100,8 @@ mod tests {
|
||||||
use accountant_skel::AccountantSkel;
|
use accountant_skel::AccountantSkel;
|
||||||
use std::thread::{sleep, spawn};
|
use std::thread::{sleep, spawn};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use log::{generate_keypair, get_pubkey, Sha256Hash};
|
use log::Sha256Hash;
|
||||||
|
use event::{generate_keypair, get_pubkey};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_accountant_stub() {
|
fn test_accountant_stub() {
|
||||||
|
|
|
@ -4,7 +4,7 @@ fn main() {
|
||||||
use silk::accountant_stub::AccountantStub;
|
use silk::accountant_stub::AccountantStub;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use std::net::UdpSocket;
|
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 addr = "127.0.0.1:8000";
|
||||||
let send_addr = "127.0.0.1:8001";
|
let send_addr = "127.0.0.1:8001";
|
||||||
|
@ -12,7 +12,7 @@ fn main() {
|
||||||
let mut acc = AccountantStub::new(addr, socket);
|
let mut acc = AccountantStub::new(addr, socket);
|
||||||
let alice_keypair = generate_keypair();
|
let alice_keypair = generate_keypair();
|
||||||
let alice_pubkey = get_pubkey(&alice_keypair);
|
let alice_pubkey = get_pubkey(&alice_keypair);
|
||||||
let txs = 10_000;
|
let txs = 2_000;
|
||||||
println!("Depositing {} units in Alice's account...", txs);
|
println!("Depositing {} units in Alice's account...", txs);
|
||||||
let sig = acc.deposit(txs, &alice_keypair).unwrap();
|
let sig = acc.deposit(txs, &alice_keypair).unwrap();
|
||||||
acc.wait_on_signature(&sig).unwrap();
|
acc.wait_on_signature(&sig).unwrap();
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
extern crate silk;
|
extern crate silk;
|
||||||
|
|
||||||
use silk::historian::Historian;
|
use silk::historian::Historian;
|
||||||
use silk::log::{generate_keypair, get_pubkey, sign_serialized, verify_slice, Entry, Event,
|
use silk::log::{verify_slice, Entry, Sha256Hash};
|
||||||
Sha256Hash};
|
use silk::event::{generate_keypair, get_pubkey, sign_claim_data, Event};
|
||||||
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;
|
||||||
|
@ -11,11 +11,7 @@ fn create_log(hist: &Historian<Sha256Hash>) -> Result<(), SendError<Event<Sha256
|
||||||
sleep(Duration::from_millis(15));
|
sleep(Duration::from_millis(15));
|
||||||
let data = Sha256Hash::default();
|
let data = Sha256Hash::default();
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let event0 = Event::Claim {
|
let event0 = Event::new_claim(get_pubkey(&keypair), data, sign_claim_data(&data, &keypair));
|
||||||
key: get_pubkey(&keypair),
|
|
||||||
data,
|
|
||||||
sig: sign_serialized(&data, &keypair),
|
|
||||||
};
|
|
||||||
hist.sender.send(event0)?;
|
hist.sender.send(event0)?;
|
||||||
sleep(Duration::from_millis(10));
|
sleep(Duration::from_millis(10));
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -30,5 +26,7 @@ fn main() {
|
||||||
for entry in &entries {
|
for entry in &entries {
|
||||||
println!("{:?}", entry);
|
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));
|
assert!(verify_slice(&entries, &seed));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,135 @@
|
||||||
|
//! The `log` crate provides the foundational data structures for Proof-of-History,
|
||||||
|
//! an ordered log of events in time.
|
||||||
|
|
||||||
|
/// Each log entry contains three pieces of data. The 'num_hashes' field is the number
|
||||||
|
/// of hashes performed since the previous entry. The 'end_hash' field is the result
|
||||||
|
/// of hashing 'end_hash' from the previous entry 'num_hashes' times. The 'event'
|
||||||
|
/// field points to an Event that took place shortly after 'end_hash' was generated.
|
||||||
|
///
|
||||||
|
/// If you divide 'num_hashes' by the amount of time it takes to generate a new hash, you
|
||||||
|
/// get a duration estimate since the last event. Since processing power increases
|
||||||
|
/// over time, one should expect the duration 'num_hashes' represents to decrease proportionally.
|
||||||
|
/// Though processing power varies across nodes, the network gives priority to the
|
||||||
|
/// fastest processor. Duration should therefore be estimated by assuming that the hash
|
||||||
|
/// was generated by the fastest processor at the time the entry was logged.
|
||||||
|
|
||||||
|
use generic_array::GenericArray;
|
||||||
|
use generic_array::typenum::{U32, U64};
|
||||||
|
use ring::signature::Ed25519KeyPair;
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
pub type PublicKey = GenericArray<u8, U32>;
|
||||||
|
pub type Signature = GenericArray<u8, U64>;
|
||||||
|
|
||||||
|
/// When 'event' is Tick, the event represents a simple clock tick, and exists for the
|
||||||
|
/// sole purpose of improving the performance of event log verification. A tick can
|
||||||
|
/// be generated in 'num_hashes' hashes and verified in 'num_hashes' hashes. By logging
|
||||||
|
/// a hash alongside the tick, each tick and be verified in parallel using the 'end_hash'
|
||||||
|
/// of the preceding tick to seed its hashing.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
|
pub enum Event<T> {
|
||||||
|
Tick,
|
||||||
|
Transaction {
|
||||||
|
from: Option<PublicKey>,
|
||||||
|
to: PublicKey,
|
||||||
|
data: T,
|
||||||
|
sig: Signature,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Event<T> {
|
||||||
|
pub fn new_claim(to: PublicKey, data: T, sig: Signature) -> Self {
|
||||||
|
Event::Transaction {
|
||||||
|
from: None,
|
||||||
|
to,
|
||||||
|
data,
|
||||||
|
sig,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a new ED25519 keypair
|
||||||
|
pub fn generate_keypair() -> Ed25519KeyPair {
|
||||||
|
use ring::{rand, signature};
|
||||||
|
use untrusted;
|
||||||
|
let rng = rand::SystemRandom::new();
|
||||||
|
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
|
||||||
|
signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the public key for the given keypair
|
||||||
|
pub fn get_pubkey(keypair: &Ed25519KeyPair) -> PublicKey {
|
||||||
|
GenericArray::clone_from_slice(keypair.public_key_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a signature for the given data using the private key from the given keypair.
|
||||||
|
fn sign_serialized<T: Serialize>(data: &T, keypair: &Ed25519KeyPair) -> Signature {
|
||||||
|
use bincode::serialize;
|
||||||
|
let serialized = serialize(data).unwrap();
|
||||||
|
GenericArray::clone_from_slice(keypair.sign(&serialized).as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a signature for the given transaction data using the private key from the given keypair.
|
||||||
|
pub fn sign_transaction_data<T: Serialize>(
|
||||||
|
data: &T,
|
||||||
|
keypair: &Ed25519KeyPair,
|
||||||
|
to: &PublicKey,
|
||||||
|
) -> Signature {
|
||||||
|
let from = &Some(get_pubkey(keypair));
|
||||||
|
sign_serialized(&(from, to, data), keypair)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return a signature for the given data using the private key from the given keypair.
|
||||||
|
pub fn sign_claim_data<T: Serialize>(data: &T, keypair: &Ed25519KeyPair) -> Signature {
|
||||||
|
let to = get_pubkey(keypair);
|
||||||
|
let from: Option<PublicKey> = None;
|
||||||
|
sign_serialized(&(&from, &to, data), keypair)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verify a signed message with the given public key.
|
||||||
|
pub fn verify_signature(peer_public_key_bytes: &[u8], msg_bytes: &[u8], sig_bytes: &[u8]) -> bool {
|
||||||
|
use untrusted;
|
||||||
|
use ring::signature;
|
||||||
|
let peer_public_key = untrusted::Input::from(peer_public_key_bytes);
|
||||||
|
let msg = untrusted::Input::from(msg_bytes);
|
||||||
|
let sig = untrusted::Input::from(sig_bytes);
|
||||||
|
signature::verify(&signature::ED25519, peer_public_key, msg, sig).is_ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_signature<T>(event: &Event<T>) -> Option<Signature> {
|
||||||
|
match *event {
|
||||||
|
Event::Tick => None,
|
||||||
|
Event::Transaction { sig, .. } => Some(sig),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn verify_event<T: Serialize>(event: &Event<T>) -> bool {
|
||||||
|
use bincode::serialize;
|
||||||
|
if let Event::Transaction {
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
ref data,
|
||||||
|
sig,
|
||||||
|
} = *event
|
||||||
|
{
|
||||||
|
let sign_data = serialize(&(&from, &to, &data)).unwrap();
|
||||||
|
if !verify_signature(&from.unwrap_or(to), &sign_data, &sig) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use bincode::{deserialize, serialize};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serialize_claim() {
|
||||||
|
let claim0 = Event::new_claim(Default::default(), 0u8, Default::default());
|
||||||
|
let buf = serialize(&claim0).unwrap();
|
||||||
|
let claim1: Event<u8> = deserialize(&buf).unwrap();
|
||||||
|
assert_eq!(claim1, claim0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,10 +6,11 @@
|
||||||
//! 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::collections::HashSet;
|
||||||
use std::sync::mpsc::{Receiver, SyncSender};
|
use std::sync::mpsc::{Receiver, SyncSender};
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
use log::{get_signature, hash, hash_event, verify_event, Entry, Event, Sha256Hash, Signature};
|
use log::{hash, hash_event, Entry, Sha256Hash};
|
||||||
|
use event::{get_signature, verify_event, Event, Signature};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ pub struct Historian<T> {
|
||||||
pub sender: SyncSender<Event<T>>,
|
pub sender: SyncSender<Event<T>>,
|
||||||
pub receiver: Receiver<Entry<T>>,
|
pub receiver: Receiver<Entry<T>>,
|
||||||
pub thread_hdl: JoinHandle<(Entry<T>, ExitReason)>,
|
pub thread_hdl: JoinHandle<(Entry<T>, ExitReason)>,
|
||||||
|
pub signatures: HashSet<Signature>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
@ -43,10 +45,25 @@ fn log_event<T: Serialize + Clone + Debug>(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
@ -64,15 +81,7 @@ fn log_events<T: Serialize + Clone + Debug>(
|
||||||
}
|
}
|
||||||
match receiver.try_recv() {
|
match receiver.try_recv() {
|
||||||
Ok(event) => {
|
Ok(event) => {
|
||||||
if verify_event(&event) {
|
log_event(sender, num_hashes, end_hash, 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)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Err(TryRecvError::Empty) => {
|
Err(TryRecvError::Empty) => {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -102,13 +111,11 @@ 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,
|
||||||
|
@ -129,18 +136,24 @@ impl<T: 'static + Serialize + Clone + Debug + Send> Historian<T> {
|
||||||
let (sender, event_receiver) = sync_channel(1000);
|
let (sender, event_receiver) = sync_channel(1000);
|
||||||
let (entry_sender, receiver) = sync_channel(1000);
|
let (entry_sender, receiver) = sync_channel(1000);
|
||||||
let thread_hdl = create_logger(*start_hash, ms_per_tick, event_receiver, entry_sender);
|
let thread_hdl = create_logger(*start_hash, ms_per_tick, event_receiver, entry_sender);
|
||||||
|
let signatures = HashSet::new();
|
||||||
Historian {
|
Historian {
|
||||||
sender,
|
sender,
|
||||||
receiver,
|
receiver,
|
||||||
thread_hdl,
|
thread_hdl,
|
||||||
|
signatures,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn verify_event(self: &mut Self, event: &Event<T>) -> bool {
|
||||||
|
return verify_event_and_reserve_signature(&mut self.signatures, event);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use log::*;
|
use log::*;
|
||||||
|
use event::*;
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
@ -199,22 +212,24 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_bad_event_attack() {
|
fn test_bad_event_signature() {
|
||||||
let zero = Sha256Hash::default();
|
|
||||||
let hist = Historian::new(&zero, None);
|
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let event0 = Event::Claim {
|
let sig = sign_claim_data(&hash(b"hello, world"), &keypair);
|
||||||
key: get_pubkey(&keypair),
|
let event0 = Event::new_claim(get_pubkey(&keypair), hash(b"goodbye cruel world"), sig);
|
||||||
data: hash(b"goodbye cruel world"),
|
let mut sigs = HashSet::new();
|
||||||
sig: sign_serialized(&hash(b"hello, world"), &keypair),
|
assert!(!verify_event_and_reserve_signature(&mut sigs, &event0));
|
||||||
};
|
assert!(!sigs.contains(&sig));
|
||||||
hist.sender.send(event0).unwrap();
|
}
|
||||||
drop(hist.sender);
|
|
||||||
assert_eq!(
|
#[test]
|
||||||
hist.thread_hdl.join().unwrap().1,
|
fn test_duplicate_event_signature() {
|
||||||
ExitReason::RecvDisconnected
|
let keypair = generate_keypair();
|
||||||
);
|
let to = get_pubkey(&keypair);
|
||||||
let entries: Vec<Entry<Sha256Hash>> = hist.receiver.iter().collect();
|
let data = &hash(b"hello, world");
|
||||||
assert_eq!(entries.len(), 0);
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![cfg_attr(feature = "unstable", feature(test))]
|
#![cfg_attr(feature = "unstable", feature(test))]
|
||||||
pub mod log;
|
pub mod log;
|
||||||
|
pub mod event;
|
||||||
pub mod historian;
|
pub mod historian;
|
||||||
pub mod accountant;
|
pub mod accountant;
|
||||||
pub mod accountant_skel;
|
pub mod accountant_skel;
|
||||||
|
|
137
src/log.rs
137
src/log.rs
|
@ -14,13 +14,11 @@
|
||||||
/// was generated by the fastest processor at the time the entry was logged.
|
/// was generated by the fastest processor at the time the entry was logged.
|
||||||
|
|
||||||
use generic_array::GenericArray;
|
use generic_array::GenericArray;
|
||||||
use generic_array::typenum::{U32, U64};
|
use generic_array::typenum::U32;
|
||||||
use ring::signature::Ed25519KeyPair;
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use event::*;
|
||||||
|
|
||||||
pub type Sha256Hash = GenericArray<u8, U32>;
|
pub type Sha256Hash = GenericArray<u8, U32>;
|
||||||
pub type PublicKey = GenericArray<u8, U32>;
|
|
||||||
pub type Signature = GenericArray<u8, U64>;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
pub struct Entry<T> {
|
pub struct Entry<T> {
|
||||||
|
@ -29,27 +27,6 @@ pub struct Entry<T> {
|
||||||
pub event: Event<T>,
|
pub event: Event<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When 'event' is Tick, the event represents a simple clock tick, and exists for the
|
|
||||||
/// sole purpose of improving the performance of event log verification. A tick can
|
|
||||||
/// be generated in 'num_hashes' hashes and verified in 'num_hashes' hashes. By logging
|
|
||||||
/// a hash alongside the tick, each tick and be verified in parallel using the 'end_hash'
|
|
||||||
/// of the preceding tick to seed its hashing.
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
|
||||||
pub enum Event<T> {
|
|
||||||
Tick,
|
|
||||||
Claim {
|
|
||||||
key: PublicKey,
|
|
||||||
data: T,
|
|
||||||
sig: Signature,
|
|
||||||
},
|
|
||||||
Transaction {
|
|
||||||
from: PublicKey,
|
|
||||||
to: PublicKey,
|
|
||||||
data: T,
|
|
||||||
sig: Signature,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Entry<T> {
|
impl<T> Entry<T> {
|
||||||
/// Creates a Entry from the number of hashes 'num_hashes' since the previous event
|
/// Creates a Entry from the number of hashes 'num_hashes' since the previous event
|
||||||
/// and that resulting 'end_hash'.
|
/// and that resulting 'end_hash'.
|
||||||
|
@ -62,36 +39,6 @@ impl<T> Entry<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a new ED25519 keypair
|
|
||||||
pub fn generate_keypair() -> Ed25519KeyPair {
|
|
||||||
use ring::{rand, signature};
|
|
||||||
use untrusted;
|
|
||||||
let rng = rand::SystemRandom::new();
|
|
||||||
let pkcs8_bytes = signature::Ed25519KeyPair::generate_pkcs8(&rng).unwrap();
|
|
||||||
signature::Ed25519KeyPair::from_pkcs8(untrusted::Input::from(&pkcs8_bytes)).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the public key for the given keypair
|
|
||||||
pub fn get_pubkey(keypair: &Ed25519KeyPair) -> PublicKey {
|
|
||||||
GenericArray::clone_from_slice(keypair.public_key_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a signature for the given data using the private key from the given keypair.
|
|
||||||
pub fn sign_serialized<T: Serialize>(data: &T, keypair: &Ed25519KeyPair) -> Signature {
|
|
||||||
use bincode::serialize;
|
|
||||||
let serialized = serialize(data).unwrap();
|
|
||||||
GenericArray::clone_from_slice(keypair.sign(&serialized).as_ref())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a signature for the given transaction data using the private key from the given keypair.
|
|
||||||
pub fn sign_transaction_data<T: Serialize>(
|
|
||||||
data: &T,
|
|
||||||
keypair: &Ed25519KeyPair,
|
|
||||||
to: &PublicKey,
|
|
||||||
) -> Signature {
|
|
||||||
sign_serialized(&(data, to), keypair)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a Sha256 hash for the given data.
|
/// Return a Sha256 hash for the given data.
|
||||||
pub fn hash(val: &[u8]) -> Sha256Hash {
|
pub fn hash(val: &[u8]) -> Sha256Hash {
|
||||||
use sha2::{Digest, Sha256};
|
use sha2::{Digest, Sha256};
|
||||||
|
@ -107,14 +54,6 @@ pub fn extend_and_hash(end_hash: &Sha256Hash, val: &[u8]) -> Sha256Hash {
|
||||||
hash(&hash_data)
|
hash(&hash_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_signature<T>(event: &Event<T>) -> Option<Signature> {
|
|
||||||
match *event {
|
|
||||||
Event::Tick => None,
|
|
||||||
Event::Claim { sig, .. } => Some(sig),
|
|
||||||
Event::Transaction { sig, .. } => Some(sig),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hash_event<T>(end_hash: &Sha256Hash, event: &Event<T>) -> Sha256Hash {
|
pub fn hash_event<T>(end_hash: &Sha256Hash, event: &Event<T>) -> Sha256Hash {
|
||||||
match get_signature(event) {
|
match get_signature(event) {
|
||||||
None => *end_hash,
|
None => *end_hash,
|
||||||
|
@ -164,29 +103,6 @@ pub fn next_tick<T: Serialize>(start_hash: &Sha256Hash, num_hashes: u64) -> Entr
|
||||||
next_entry(start_hash, num_hashes, Event::Tick)
|
next_entry(start_hash, num_hashes, Event::Tick)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_event<T: Serialize>(event: &Event<T>) -> bool {
|
|
||||||
use bincode::serialize;
|
|
||||||
if let Event::Claim { key, ref data, sig } = *event {
|
|
||||||
let mut claim_data = serialize(&data).unwrap();
|
|
||||||
if !verify_signature(&key, &claim_data, &sig) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Event::Transaction {
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
ref data,
|
|
||||||
sig,
|
|
||||||
} = *event
|
|
||||||
{
|
|
||||||
let sign_data = serialize(&(&data, &to)).unwrap();
|
|
||||||
if !verify_signature(&from, &sign_data, &sig) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Verifies self.end_hash is the result of hashing a 'start_hash' 'self.num_hashes' times.
|
/// Verifies self.end_hash is the result of hashing a 'start_hash' 'self.num_hashes' times.
|
||||||
/// If the event is not a Tick, then hash that as well.
|
/// If the event is not a Tick, then hash that as well.
|
||||||
pub fn verify_entry<T: Serialize>(entry: &Entry<T>, start_hash: &Sha256Hash) -> bool {
|
pub fn verify_entry<T: Serialize>(entry: &Entry<T>, start_hash: &Sha256Hash) -> bool {
|
||||||
|
@ -219,16 +135,6 @@ pub fn verify_slice_seq<T: Serialize>(events: &[Entry<T>], start_hash: &Sha256Ha
|
||||||
event_pairs.all(|(x0, x1)| verify_entry(&x1, &x0.end_hash))
|
event_pairs.all(|(x0, x1)| verify_entry(&x1, &x0.end_hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a signed message with the given public key.
|
|
||||||
pub fn verify_signature(peer_public_key_bytes: &[u8], msg_bytes: &[u8], sig_bytes: &[u8]) -> bool {
|
|
||||||
use untrusted;
|
|
||||||
use ring::signature;
|
|
||||||
let peer_public_key = untrusted::Input::from(peer_public_key_bytes);
|
|
||||||
let msg = untrusted::Input::from(msg_bytes);
|
|
||||||
let sig = untrusted::Input::from(sig_bytes);
|
|
||||||
signature::verify(&signature::ED25519, peer_public_key, msg, sig).is_ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create_entries<T: Serialize>(
|
pub fn create_entries<T: Serialize>(
|
||||||
start_hash: &Sha256Hash,
|
start_hash: &Sha256Hash,
|
||||||
num_hashes: u64,
|
num_hashes: u64,
|
||||||
|
@ -303,24 +209,15 @@ mod tests {
|
||||||
let zero = Sha256Hash::default();
|
let zero = Sha256Hash::default();
|
||||||
let one = hash(&zero);
|
let one = hash(&zero);
|
||||||
|
|
||||||
// First, verify Claim events
|
// First, verify entries
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let event0 = Event::Claim {
|
let event0 = Event::new_claim(get_pubkey(&keypair), zero, sign_claim_data(&zero, &keypair));
|
||||||
key: get_pubkey(&keypair),
|
let event1 = Event::new_claim(get_pubkey(&keypair), one, sign_claim_data(&one, &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 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 Claim events and ensure verification fails.
|
// Next, swap two 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;
|
||||||
|
@ -332,11 +229,7 @@ mod tests {
|
||||||
fn test_claim() {
|
fn test_claim() {
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let data = hash(b"hello, world");
|
let data = hash(b"hello, world");
|
||||||
let event0 = Event::Claim {
|
let event0 = Event::new_claim(get_pubkey(&keypair), data, sign_claim_data(&data, &keypair));
|
||||||
key: get_pubkey(&keypair),
|
|
||||||
data,
|
|
||||||
sig: sign_serialized(&data, &keypair),
|
|
||||||
};
|
|
||||||
let zero = Sha256Hash::default();
|
let zero = Sha256Hash::default();
|
||||||
let entries = create_entries(&zero, 0, vec![event0]);
|
let entries = create_entries(&zero, 0, vec![event0]);
|
||||||
assert!(verify_slice(&entries, &zero));
|
assert!(verify_slice(&entries, &zero));
|
||||||
|
@ -345,11 +238,11 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_wrong_data_claim_attack() {
|
fn test_wrong_data_claim_attack() {
|
||||||
let keypair = generate_keypair();
|
let keypair = generate_keypair();
|
||||||
let event0 = Event::Claim {
|
let event0 = Event::new_claim(
|
||||||
key: get_pubkey(&keypair),
|
get_pubkey(&keypair),
|
||||||
data: hash(b"goodbye cruel world"),
|
hash(b"goodbye cruel world"),
|
||||||
sig: sign_serialized(&hash(b"hello, world"), &keypair),
|
sign_claim_data(&hash(b"hello, world"), &keypair),
|
||||||
};
|
);
|
||||||
let zero = Sha256Hash::default();
|
let zero = Sha256Hash::default();
|
||||||
let entries = create_entries(&zero, 0, vec![event0]);
|
let entries = create_entries(&zero, 0, vec![event0]);
|
||||||
assert!(!verify_slice(&entries, &zero));
|
assert!(!verify_slice(&entries, &zero));
|
||||||
|
@ -362,7 +255,7 @@ mod tests {
|
||||||
let pubkey1 = get_pubkey(&keypair1);
|
let pubkey1 = get_pubkey(&keypair1);
|
||||||
let data = hash(b"hello, world");
|
let data = hash(b"hello, world");
|
||||||
let event0 = Event::Transaction {
|
let event0 = Event::Transaction {
|
||||||
from: get_pubkey(&keypair0),
|
from: Some(get_pubkey(&keypair0)),
|
||||||
to: pubkey1,
|
to: pubkey1,
|
||||||
data,
|
data,
|
||||||
sig: sign_transaction_data(&data, &keypair0, &pubkey1),
|
sig: sign_transaction_data(&data, &keypair0, &pubkey1),
|
||||||
|
@ -379,7 +272,7 @@ mod tests {
|
||||||
let pubkey1 = get_pubkey(&keypair1);
|
let pubkey1 = get_pubkey(&keypair1);
|
||||||
let data = hash(b"hello, world");
|
let data = hash(b"hello, world");
|
||||||
let event0 = Event::Transaction {
|
let event0 = Event::Transaction {
|
||||||
from: get_pubkey(&keypair0),
|
from: Some(get_pubkey(&keypair0)),
|
||||||
to: pubkey1,
|
to: pubkey1,
|
||||||
data: hash(b"goodbye cruel world"), // <-- attack!
|
data: hash(b"goodbye cruel world"), // <-- attack!
|
||||||
sig: sign_transaction_data(&data, &keypair0, &pubkey1),
|
sig: sign_transaction_data(&data, &keypair0, &pubkey1),
|
||||||
|
@ -397,7 +290,7 @@ mod tests {
|
||||||
let pubkey1 = get_pubkey(&keypair1);
|
let pubkey1 = get_pubkey(&keypair1);
|
||||||
let data = hash(b"hello, world");
|
let data = hash(b"hello, world");
|
||||||
let event0 = Event::Transaction {
|
let event0 = Event::Transaction {
|
||||||
from: get_pubkey(&keypair0),
|
from: Some(get_pubkey(&keypair0)),
|
||||||
to: get_pubkey(&thief_keypair), // <-- attack!
|
to: get_pubkey(&thief_keypair), // <-- attack!
|
||||||
data: hash(b"goodbye cruel world"),
|
data: hash(b"goodbye cruel world"),
|
||||||
sig: sign_transaction_data(&data, &keypair0, &pubkey1),
|
sig: sign_transaction_data(&data, &keypair0, &pubkey1),
|
||||||
|
|
Loading…
Reference in New Issue