Merge pull request #108 from garious/parallelize-accountant
Reject old transactions so that we can boot old signatures
This commit is contained in:
commit
bc6d6b20fa
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue