Merge pull request #100 from garious/rollback
Cleanup use of event signatures and entry hashing
This commit is contained in:
@ -3,12 +3,13 @@
|
|||||||
//! in flux. Clients should use AccountantStub to interact with it.
|
//! in flux. Clients should use AccountantStub to interact with it.
|
||||||
|
|
||||||
use accountant::Accountant;
|
use accountant::Accountant;
|
||||||
use historian::Historian;
|
|
||||||
use recorder::Signal;
|
|
||||||
use bincode::{deserialize, serialize};
|
use bincode::{deserialize, serialize};
|
||||||
use entry::Entry;
|
use entry::Entry;
|
||||||
use event::Event;
|
use event::Event;
|
||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
|
use historian::Historian;
|
||||||
|
use rayon::prelude::*;
|
||||||
|
use recorder::Signal;
|
||||||
use result::Result;
|
use result::Result;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use signature::PublicKey;
|
use signature::PublicKey;
|
||||||
@ -22,7 +23,6 @@ use std::thread::{spawn, JoinHandle};
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use streamer;
|
use streamer;
|
||||||
use transaction::Transaction;
|
use transaction::Transaction;
|
||||||
use rayon::prelude::*;
|
|
||||||
|
|
||||||
pub struct AccountantSkel<W: Write + Send + 'static> {
|
pub struct AccountantSkel<W: Write + Send + 'static> {
|
||||||
acc: Accountant,
|
acc: Accountant,
|
||||||
|
@ -87,8 +87,8 @@ impl AccountantStub {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use accountant::Accountant;
|
use accountant::Accountant;
|
||||||
use historian::Historian;
|
|
||||||
use accountant_skel::AccountantSkel;
|
use accountant_skel::AccountantSkel;
|
||||||
|
use historian::Historian;
|
||||||
use mint::Mint;
|
use mint::Mint;
|
||||||
use signature::{KeyPair, KeyPairUtil};
|
use signature::{KeyPair, KeyPairUtil};
|
||||||
use std::io::sink;
|
use std::io::sink;
|
||||||
|
@ -2,15 +2,15 @@ extern crate rayon;
|
|||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
extern crate solana;
|
extern crate solana;
|
||||||
|
|
||||||
|
use rayon::prelude::*;
|
||||||
use solana::accountant_stub::AccountantStub;
|
use solana::accountant_stub::AccountantStub;
|
||||||
use solana::mint::Mint;
|
use solana::mint::Mint;
|
||||||
use solana::signature::{KeyPair, KeyPairUtil};
|
use solana::signature::{KeyPair, KeyPairUtil};
|
||||||
use solana::transaction::Transaction;
|
use solana::transaction::Transaction;
|
||||||
use std::io::stdin;
|
use std::io::stdin;
|
||||||
use std::net::UdpSocket;
|
use std::net::UdpSocket;
|
||||||
use std::time::{Duration, Instant};
|
|
||||||
use std::thread::sleep;
|
use std::thread::sleep;
|
||||||
use rayon::prelude::*;
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let addr = "127.0.0.1:8000";
|
let addr = "127.0.0.1:8000";
|
||||||
|
@ -2,10 +2,10 @@ extern crate serde_json;
|
|||||||
extern crate solana;
|
extern crate solana;
|
||||||
|
|
||||||
use solana::accountant::Accountant;
|
use solana::accountant::Accountant;
|
||||||
use solana::event::Event;
|
|
||||||
use solana::entry::Entry;
|
|
||||||
use solana::historian::Historian;
|
|
||||||
use solana::accountant_skel::AccountantSkel;
|
use solana::accountant_skel::AccountantSkel;
|
||||||
|
use solana::entry::Entry;
|
||||||
|
use solana::event::Event;
|
||||||
|
use solana::historian::Historian;
|
||||||
use std::io::{self, stdout, BufRead};
|
use std::io::{self, stdout, BufRead};
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
40
src/entry.rs
40
src/entry.rs
@ -43,6 +43,23 @@ impl Entry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_event_data(hash_data: &mut Vec<u8>, event: &Event) {
|
||||||
|
match *event {
|
||||||
|
Event::Transaction(ref tr) => {
|
||||||
|
hash_data.push(0u8);
|
||||||
|
hash_data.extend_from_slice(&tr.sig);
|
||||||
|
}
|
||||||
|
Event::Signature { ref sig, .. } => {
|
||||||
|
hash_data.push(1u8);
|
||||||
|
hash_data.extend_from_slice(sig);
|
||||||
|
}
|
||||||
|
Event::Timestamp { ref sig, .. } => {
|
||||||
|
hash_data.push(2u8);
|
||||||
|
hash_data.extend_from_slice(sig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates the hash `num_hashes` after `start_hash`. If the event contains
|
/// Creates the hash `num_hashes` after `start_hash`. If the event contains
|
||||||
/// signature, the final hash will be a hash of both the previous ID and
|
/// signature, the final hash will be a hash of both the previous ID and
|
||||||
/// the signature.
|
/// the signature.
|
||||||
@ -55,10 +72,7 @@ pub fn next_hash(start_hash: &Hash, num_hashes: u64, events: &[Event]) -> Hash {
|
|||||||
// Hash all the event data
|
// Hash all the event data
|
||||||
let mut hash_data = vec![];
|
let mut hash_data = vec![];
|
||||||
for event in events {
|
for event in events {
|
||||||
let sig = event.get_signature();
|
add_event_data(&mut hash_data, event);
|
||||||
if let Some(sig) = sig {
|
|
||||||
hash_data.extend_from_slice(&sig);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !hash_data.is_empty() {
|
if !hash_data.is_empty() {
|
||||||
@ -99,6 +113,7 @@ pub fn next_tick(start_hash: &Hash, num_hashes: u64) -> Entry {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use chrono::prelude::*;
|
||||||
use entry::create_entry;
|
use entry::create_entry;
|
||||||
use event::Event;
|
use event::Event;
|
||||||
use hash::hash;
|
use hash::hash;
|
||||||
@ -132,6 +147,23 @@ mod tests {
|
|||||||
assert!(!e0.verify(&zero));
|
assert!(!e0.verify(&zero));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_witness_reorder_attack() {
|
||||||
|
let zero = Hash::default();
|
||||||
|
|
||||||
|
// First, verify entries
|
||||||
|
let keypair = KeyPair::new();
|
||||||
|
let tr0 = Event::new_timestamp(&keypair, Utc::now());
|
||||||
|
let tr1 = Event::new_signature(&keypair, Default::default());
|
||||||
|
let mut e0 = create_entry(&zero, 0, vec![tr0.clone(), tr1.clone()]);
|
||||||
|
assert!(e0.verify(&zero));
|
||||||
|
|
||||||
|
// Next, swap two witness events and ensure verification fails.
|
||||||
|
e0.events[0] = tr1; // <-- attack
|
||||||
|
e0.events[1] = tr0;
|
||||||
|
assert!(!e0.verify(&zero));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_next_tick() {
|
fn test_next_tick() {
|
||||||
let zero = Hash::default();
|
let zero = Hash::default();
|
||||||
|
25
src/event.rs
25
src/event.rs
@ -33,12 +33,13 @@ impl Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Rename this to transaction_signature().
|
/// Create and sign a new Witness Signature. Used for unit-testing.
|
||||||
/// If the Event is a Transaction, return its Signature.
|
pub fn new_signature(from: &KeyPair, tx_sig: Signature) -> Self {
|
||||||
pub fn get_signature(&self) -> Option<Signature> {
|
let sig = Signature::clone_from_slice(from.sign(&tx_sig).as_ref());
|
||||||
match *self {
|
Event::Signature {
|
||||||
Event::Transaction(ref tr) => Some(tr.sig),
|
from: from.pubkey(),
|
||||||
Event::Signature { .. } | Event::Timestamp { .. } => None,
|
tx_sig,
|
||||||
|
sig,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,3 +53,15 @@ impl Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use signature::{KeyPair, KeyPairUtil};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_event_verify() {
|
||||||
|
assert!(Event::new_timestamp(&KeyPair::new(), Utc::now()).verify());
|
||||||
|
assert!(Event::new_signature(&KeyPair::new(), Signature::default()).verify());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
use bincode::serialize;
|
use bincode::serialize;
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use rayon::prelude::*;
|
|
||||||
use hash::Hash;
|
use hash::Hash;
|
||||||
use plan::{Condition, Payment, Plan};
|
use plan::{Condition, Payment, Plan};
|
||||||
|
use rayon::prelude::*;
|
||||||
use signature::{KeyPair, KeyPairUtil, PublicKey, Signature, SignatureUtil};
|
use signature::{KeyPair, KeyPairUtil, PublicKey, Signature, SignatureUtil};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
|
||||||
@ -57,7 +57,7 @@ impl Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn get_sign_data(&self) -> Vec<u8> {
|
fn get_sign_data(&self) -> Vec<u8> {
|
||||||
serialize(&(&self.from, &self.plan, &self.tokens, &self.last_id)).unwrap()
|
serialize(&(&self.plan, &self.tokens, &self.last_id)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sign this transaction.
|
/// Sign this transaction.
|
||||||
|
Reference in New Issue
Block a user