Merge pull request #108 from garious/parallelize-accountant

Reject old transactions so that we can boot old signatures
This commit is contained in:
Greg Fitzgerald 2018-04-05 15:11:22 -06:00 committed by GitHub
commit bc6d6b20fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 38 additions and 8 deletions

View File

@ -15,6 +15,8 @@ use std::result;
use std::sync::RwLock; use std::sync::RwLock;
use transaction::Transaction; use transaction::Transaction;
const MAX_ENTRY_IDS: usize = 1024 * 4;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum AccountingError { pub enum AccountingError {
InsufficientFunds, InsufficientFunds,
@ -62,7 +64,9 @@ impl Accountant {
to: mint.pubkey(), to: mint.pubkey(),
tokens: mint.tokens, tokens: mint.tokens,
}; };
Self::new_from_deposit(&deposit) let acc = Self::new_from_deposit(&deposit);
acc.register_entry_id(&mint.last_id());
acc
} }
fn reserve_signature(signatures: &RwLock<HashSet<Signature>>, sig: &Signature) -> bool { fn reserve_signature(signatures: &RwLock<HashSet<Signature>>, sig: &Signature) -> bool {
@ -83,10 +87,19 @@ impl Accountant {
{ {
return Self::reserve_signature(&entry.1, sig); return Self::reserve_signature(&entry.1, sig);
} }
let sigs = RwLock::new(HashSet::new()); false
Self::reserve_signature(&sigs, sig); }
self.last_ids.write().unwrap().push_back((*last_id, sigs));
true /// Tell the accountant which Entry IDs exist on the ledger. This function
/// assumes subsequent calls correspond to later entries, and will boot
/// the oldest ones once its internal cache is full. Once boot, the
/// accountant will reject transactions using that `last_id`.
pub fn register_entry_id(&self, last_id: &Hash) {
let mut last_ids = self.last_ids.write().unwrap();
if last_ids.len() >= MAX_ENTRY_IDS {
last_ids.pop_front();
}
last_ids.push_back((*last_id, RwLock::new(HashSet::new())));
} }
/// Process a Transaction that has already been verified. /// Process a Transaction that has already been verified.
@ -214,6 +227,8 @@ impl Accountant {
mod tests { mod tests {
use super::*; use super::*;
use signature::KeyPairUtil; use signature::KeyPairUtil;
use hash::hash;
use bincode::serialize;
#[test] #[test]
fn test_accountant() { fn test_accountant() {
@ -331,9 +346,21 @@ mod tests {
let alice = Mint::new(1); let alice = Mint::new(1);
let acc = Accountant::new(&alice); let acc = Accountant::new(&alice);
let sig = Signature::default(); let sig = Signature::default();
let last_id = Hash::default(); assert!(acc.reserve_signature_with_last_id(&sig, &alice.last_id()));
assert!(acc.reserve_signature_with_last_id(&sig, &last_id)); assert!(!acc.reserve_signature_with_last_id(&sig, &alice.last_id()));
assert!(!acc.reserve_signature_with_last_id(&sig, &last_id)); }
#[test]
fn test_max_entry_ids() {
let alice = Mint::new(1);
let acc = Accountant::new(&alice);
let sig = Signature::default();
for i in 0..MAX_ENTRY_IDS {
let last_id = hash(&serialize(&i).unwrap()); // Unique hash
acc.register_entry_id(&last_id);
}
// Assert we're no longer able to use the oldest entry ID.
assert!(!acc.reserve_signature_with_last_id(&sig, &alice.last_id()));
} }
} }
@ -362,6 +389,8 @@ mod bench {
// Seed the 'to' account and a cell for its signature. // Seed the 'to' account and a cell for its signature.
let last_id = hash(&serialize(&i).unwrap()); // Unique hash let last_id = hash(&serialize(&i).unwrap()); // Unique hash
acc.register_entry_id(&last_id);
let rando1 = KeyPair::new(); let rando1 = KeyPair::new();
let tr = Transaction::new(&rando0, rando1.pubkey(), 1, last_id); let tr = Transaction::new(&rando0, rando1.pubkey(), 1, last_id);
acc.process_verified_transaction(&tr).unwrap(); acc.process_verified_transaction(&tr).unwrap();

View File

@ -77,6 +77,7 @@ impl<W: Write + Send + 'static> AccountantSkel<W> {
pub fn sync(&mut self) -> Hash { pub fn sync(&mut self) -> Hash {
while let Ok(entry) = self.historian.receiver.try_recv() { while let Ok(entry) = self.historian.receiver.try_recv() {
self.last_id = entry.id; self.last_id = entry.id;
self.acc.register_entry_id(&self.last_id);
writeln!(self.writer, "{}", serde_json::to_string(&entry).unwrap()).unwrap(); writeln!(self.writer, "{}", serde_json::to_string(&entry).unwrap()).unwrap();
} }
self.last_id self.last_id