Add transaction count to accountant
This commit is contained in:
		| @@ -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); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user