Add transaction count to accountant
This commit is contained in:
parent
b132ce1944
commit
317031f455
|
@ -17,7 +17,7 @@ use std::collections::hash_map::Entry::Occupied;
|
||||||
use std::collections::{HashMap, HashSet, VecDeque};
|
use std::collections::{HashMap, HashSet, VecDeque};
|
||||||
use std::result;
|
use std::result;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
use std::sync::atomic::{AtomicIsize, AtomicUsize, Ordering};
|
||||||
use transaction::Transaction;
|
use transaction::Transaction;
|
||||||
|
|
||||||
pub const MAX_ENTRY_IDS: usize = 1024 * 4;
|
pub const MAX_ENTRY_IDS: usize = 1024 * 4;
|
||||||
|
@ -59,6 +59,7 @@ pub struct Accountant {
|
||||||
last_ids: RwLock<VecDeque<(Hash, RwLock<HashSet<Signature>>)>>,
|
last_ids: RwLock<VecDeque<(Hash, RwLock<HashSet<Signature>>)>>,
|
||||||
time_sources: RwLock<HashSet<PublicKey>>,
|
time_sources: RwLock<HashSet<PublicKey>>,
|
||||||
last_time: RwLock<DateTime<Utc>>,
|
last_time: RwLock<DateTime<Utc>>,
|
||||||
|
transaction_count: AtomicUsize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Accountant {
|
impl Accountant {
|
||||||
|
@ -72,6 +73,7 @@ impl Accountant {
|
||||||
last_ids: RwLock::new(VecDeque::new()),
|
last_ids: RwLock::new(VecDeque::new()),
|
||||||
time_sources: RwLock::new(HashSet::new()),
|
time_sources: RwLock::new(HashSet::new()),
|
||||||
last_time: RwLock::new(Utc.timestamp(0, 0)),
|
last_time: RwLock::new(Utc.timestamp(0, 0)),
|
||||||
|
transaction_count: AtomicUsize::new(0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +190,10 @@ impl Accountant {
|
||||||
);
|
);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => return Ok(()),
|
Ok(_) => {
|
||||||
|
self.transaction_count.fetch_add(1, Ordering::Relaxed);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -387,6 +392,10 @@ impl Accountant {
|
||||||
.expect("'balances' read lock in get_balance");
|
.expect("'balances' read lock in get_balance");
|
||||||
bals.get(pubkey).map(|x| x.load(Ordering::Relaxed) as i64)
|
bals.get(pubkey).map(|x| x.load(Ordering::Relaxed) as i64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn transaction_count(&self) -> usize {
|
||||||
|
self.transaction_count.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -412,6 +421,7 @@ mod tests {
|
||||||
.transfer(500, &alice.keypair(), bob_pubkey, alice.last_id())
|
.transfer(500, &alice.keypair(), bob_pubkey, alice.last_id())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(accountant.get_balance(&bob_pubkey).unwrap(), 1_500);
|
assert_eq!(accountant.get_balance(&bob_pubkey).unwrap(), 1_500);
|
||||||
|
assert_eq!(accountant.transaction_count(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -422,6 +432,7 @@ mod tests {
|
||||||
accountant.transfer(1, &KeyPair::new(), mint.pubkey(), mint.last_id()),
|
accountant.transfer(1, &KeyPair::new(), mint.pubkey(), mint.last_id()),
|
||||||
Err(AccountingError::AccountNotFound)
|
Err(AccountingError::AccountNotFound)
|
||||||
);
|
);
|
||||||
|
assert_eq!(accountant.transaction_count(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -432,10 +443,12 @@ mod tests {
|
||||||
accountant
|
accountant
|
||||||
.transfer(1_000, &alice.keypair(), bob_pubkey, alice.last_id())
|
.transfer(1_000, &alice.keypair(), bob_pubkey, alice.last_id())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
assert_eq!(accountant.transaction_count(), 1);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
accountant.transfer(10_001, &alice.keypair(), bob_pubkey, alice.last_id()),
|
accountant.transfer(10_001, &alice.keypair(), bob_pubkey, alice.last_id()),
|
||||||
Err(AccountingError::InsufficientFunds)
|
Err(AccountingError::InsufficientFunds)
|
||||||
);
|
);
|
||||||
|
assert_eq!(accountant.transaction_count(), 1);
|
||||||
|
|
||||||
let alice_pubkey = alice.keypair().pubkey();
|
let alice_pubkey = alice.keypair().pubkey();
|
||||||
assert_eq!(accountant.get_balance(&alice_pubkey).unwrap(), 10_000);
|
assert_eq!(accountant.get_balance(&alice_pubkey).unwrap(), 10_000);
|
||||||
|
@ -468,6 +481,9 @@ mod tests {
|
||||||
// Alice's balance will be zero because all funds are locked up.
|
// Alice's balance will be zero because all funds are locked up.
|
||||||
assert_eq!(accountant.get_balance(&alice.pubkey()), Some(0));
|
assert_eq!(accountant.get_balance(&alice.pubkey()), Some(0));
|
||||||
|
|
||||||
|
// tx count is 1, because debits were applied.
|
||||||
|
assert_eq!(accountant.transaction_count(), 1);
|
||||||
|
|
||||||
// Bob's balance will be None because the funds have not been
|
// Bob's balance will be None because the funds have not been
|
||||||
// sent.
|
// sent.
|
||||||
assert_eq!(accountant.get_balance(&bob_pubkey), None);
|
assert_eq!(accountant.get_balance(&bob_pubkey), None);
|
||||||
|
@ -479,6 +495,10 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(accountant.get_balance(&bob_pubkey), Some(1));
|
assert_eq!(accountant.get_balance(&bob_pubkey), Some(1));
|
||||||
|
|
||||||
|
// tx count is still 1, because we chose not to count timestamp events
|
||||||
|
// tx count.
|
||||||
|
assert_eq!(accountant.transaction_count(), 1);
|
||||||
|
|
||||||
accountant
|
accountant
|
||||||
.process_verified_timestamp(alice.pubkey(), dt)
|
.process_verified_timestamp(alice.pubkey(), dt)
|
||||||
.unwrap(); // <-- Attack! Attempt to process completed transaction.
|
.unwrap(); // <-- Attack! Attempt to process completed transaction.
|
||||||
|
@ -516,6 +536,9 @@ mod tests {
|
||||||
.transfer_on_date(1, &alice_keypair, bob_pubkey, dt, alice.last_id())
|
.transfer_on_date(1, &alice_keypair, bob_pubkey, dt, alice.last_id())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
// Assert the debit counts as a transaction.
|
||||||
|
assert_eq!(accountant.transaction_count(), 1);
|
||||||
|
|
||||||
// Alice's balance will be zero because all funds are locked up.
|
// Alice's balance will be zero because all funds are locked up.
|
||||||
assert_eq!(accountant.get_balance(&alice.pubkey()), Some(0));
|
assert_eq!(accountant.get_balance(&alice.pubkey()), Some(0));
|
||||||
|
|
||||||
|
@ -530,6 +553,9 @@ mod tests {
|
||||||
assert_eq!(accountant.get_balance(&alice.pubkey()), Some(1));
|
assert_eq!(accountant.get_balance(&alice.pubkey()), Some(1));
|
||||||
assert_eq!(accountant.get_balance(&bob_pubkey), None);
|
assert_eq!(accountant.get_balance(&bob_pubkey), None);
|
||||||
|
|
||||||
|
// Assert cancel doesn't cause count to go backward.
|
||||||
|
assert_eq!(accountant.transaction_count(), 1);
|
||||||
|
|
||||||
accountant
|
accountant
|
||||||
.process_verified_sig(alice.pubkey(), sig)
|
.process_verified_sig(alice.pubkey(), sig)
|
||||||
.unwrap(); // <-- Attack! Attempt to cancel completed transaction.
|
.unwrap(); // <-- Attack! Attempt to cancel completed transaction.
|
||||||
|
@ -576,7 +602,11 @@ mod tests {
|
||||||
let tr0 = Transaction::new(&mint.keypair(), alice.pubkey(), 2, mint.last_id());
|
let tr0 = Transaction::new(&mint.keypair(), alice.pubkey(), 2, mint.last_id());
|
||||||
let tr1 = Transaction::new(&alice, mint.pubkey(), 1, mint.last_id());
|
let tr1 = Transaction::new(&alice, mint.pubkey(), 1, mint.last_id());
|
||||||
let trs = vec![tr0, tr1];
|
let trs = vec![tr0, tr1];
|
||||||
assert!(accountant.process_verified_transactions(trs)[1].is_err());
|
let results = accountant.process_verified_transactions(trs);
|
||||||
|
assert!(results[1].is_err());
|
||||||
|
|
||||||
|
// Assert bad transactions aren't counted.
|
||||||
|
assert_eq!(accountant.transaction_count(), 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue