Pass Bank::process_transactions() a reference to the txs instead of moving them
This commit is contained in:
55
src/bank.rs
55
src/bank.rs
@ -268,7 +268,7 @@ impl Bank {
|
|||||||
|
|
||||||
/// Process a Transaction. This is used for unit tests and simply calls the vector Bank::process_transactions method.
|
/// Process a Transaction. This is used for unit tests and simply calls the vector Bank::process_transactions method.
|
||||||
pub fn process_transaction(&self, tx: &Transaction) -> Result<()> {
|
pub fn process_transaction(&self, tx: &Transaction) -> Result<()> {
|
||||||
match self.process_transactions(vec![tx.clone()])[0] {
|
match self.process_transactions(&[tx.clone()])[0] {
|
||||||
Err(ref e) => {
|
Err(ref e) => {
|
||||||
info!("process_transaction error: {:?}", e);
|
info!("process_transaction error: {:?}", e);
|
||||||
Err((*e).clone())
|
Err((*e).clone())
|
||||||
@ -370,11 +370,7 @@ impl Bank {
|
|||||||
/// This method calls the contract's process_transaction method and verifies that the result of
|
/// This method calls the contract's process_transaction method and verifies that the result of
|
||||||
/// the contract does not violate the bank's accounting rules.
|
/// the contract does not violate the bank's accounting rules.
|
||||||
/// The accounts are committed back to the bank only if this function returns Ok(_).
|
/// The accounts are committed back to the bank only if this function returns Ok(_).
|
||||||
fn execute_transaction(
|
fn execute_transaction(&self, tx: &Transaction, accounts: &mut [Account]) -> Result<()> {
|
||||||
&self,
|
|
||||||
tx: Transaction,
|
|
||||||
accounts: &mut [Account],
|
|
||||||
) -> Result<Transaction> {
|
|
||||||
let pre_total: i64 = accounts.iter().map(|a| a.tokens).sum();
|
let pre_total: i64 = accounts.iter().map(|a| a.tokens).sum();
|
||||||
let pre_data: Vec<_> = accounts
|
let pre_data: Vec<_> = accounts
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
@ -404,33 +400,38 @@ impl Bank {
|
|||||||
if pre_total != post_total {
|
if pre_total != post_total {
|
||||||
Err(BankError::UnbalancedTransaction(tx.signature))
|
Err(BankError::UnbalancedTransaction(tx.signature))
|
||||||
} else {
|
} else {
|
||||||
Ok(tx)
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_accounts(
|
pub fn store_accounts(
|
||||||
res: &[Result<Transaction>],
|
txs: &[Transaction],
|
||||||
|
res: &[Result<()>],
|
||||||
loaded: &[Result<Vec<Account>>],
|
loaded: &[Result<Vec<Account>>],
|
||||||
accounts: &mut HashMap<Pubkey, Account>,
|
accounts: &mut HashMap<Pubkey, Account>,
|
||||||
) {
|
) {
|
||||||
loaded.iter().zip(res.iter()).for_each(|(racc, rtx)| {
|
for (i, racc) in loaded.iter().enumerate() {
|
||||||
if let (Ok(acc), Ok(tx)) = (racc, rtx) {
|
if res[i].is_err() || racc.is_err() {
|
||||||
tx.keys.iter().zip(acc.iter()).for_each(|(key, account)| {
|
continue;
|
||||||
//purge if 0
|
}
|
||||||
if account.tokens == 0 {
|
|
||||||
accounts.remove(&key);
|
let tx = &txs[i];
|
||||||
} else {
|
let acc = racc.as_ref().unwrap();
|
||||||
*accounts.entry(*key).or_insert_with(Account::default) = account.clone();
|
for (key, account) in tx.keys.iter().zip(acc.iter()) {
|
||||||
assert_eq!(accounts.get(key).unwrap().tokens, account.tokens);
|
//purge if 0
|
||||||
}
|
if account.tokens == 0 {
|
||||||
});
|
accounts.remove(&key);
|
||||||
};
|
} else {
|
||||||
});
|
*accounts.entry(*key).or_insert_with(Account::default) = account.clone();
|
||||||
|
assert_eq!(accounts.get(key).unwrap().tokens, account.tokens);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process a batch of transactions.
|
/// Process a batch of transactions.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn process_transactions(&self, txs: Vec<Transaction>) -> Vec<Result<Transaction>> {
|
pub fn process_transactions(&self, txs: &[Transaction]) -> Vec<Result<()>> {
|
||||||
debug!("processing transactions: {}", txs.len());
|
debug!("processing transactions: {}", txs.len());
|
||||||
// TODO right now a single write lock is held for the duration of processing all the
|
// TODO right now a single write lock is held for the duration of processing all the
|
||||||
// transactions
|
// transactions
|
||||||
@ -443,16 +444,16 @@ impl Bank {
|
|||||||
let load_elapsed = now.elapsed();
|
let load_elapsed = now.elapsed();
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
let res: Vec<Result<Transaction>> = loaded_accounts
|
let res: Vec<_> = loaded_accounts
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(txs.into_iter())
|
.zip(txs.iter())
|
||||||
.map(|(acc, tx)| match acc {
|
.map(|(acc, tx)| match acc {
|
||||||
Err(e) => Err(e.clone()),
|
Err(e) => Err(e.clone()),
|
||||||
Ok(ref mut accounts) => self.execute_transaction(tx, accounts),
|
Ok(ref mut accounts) => self.execute_transaction(tx, accounts),
|
||||||
}).collect();
|
}).collect();
|
||||||
let execution_elapsed = now.elapsed();
|
let execution_elapsed = now.elapsed();
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
Self::store_accounts(&res, &loaded_accounts, &mut accounts);
|
Self::store_accounts(&txs, &res, &loaded_accounts, &mut accounts);
|
||||||
let write_elapsed = now.elapsed();
|
let write_elapsed = now.elapsed();
|
||||||
debug!(
|
debug!(
|
||||||
"load: {}us execution: {}us write: {}us txs_len={}",
|
"load: {}us execution: {}us write: {}us txs_len={}",
|
||||||
@ -504,7 +505,7 @@ impl Bank {
|
|||||||
|
|
||||||
pub fn process_entry(&self, entry: Entry) -> Result<()> {
|
pub fn process_entry(&self, entry: Entry) -> Result<()> {
|
||||||
if !entry.transactions.is_empty() {
|
if !entry.transactions.is_empty() {
|
||||||
for result in self.process_transactions(entry.transactions) {
|
for result in self.process_transactions(&entry.transactions) {
|
||||||
result?;
|
result?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -892,7 +893,7 @@ mod tests {
|
|||||||
let tx0 = Transaction::new(&mint.keypair(), keypair.pubkey(), 2, mint.last_id());
|
let tx0 = Transaction::new(&mint.keypair(), keypair.pubkey(), 2, mint.last_id());
|
||||||
let tx1 = Transaction::new(&keypair, mint.pubkey(), 1, mint.last_id());
|
let tx1 = Transaction::new(&keypair, mint.pubkey(), 1, mint.last_id());
|
||||||
let txs = vec![tx0, tx1];
|
let txs = vec![tx0, tx1];
|
||||||
let results = bank.process_transactions(txs);
|
let results = bank.process_transactions(&txs);
|
||||||
assert!(results[1].is_err());
|
assert!(results[1].is_err());
|
||||||
|
|
||||||
// Assert bad transactions aren't counted.
|
// Assert bad transactions aren't counted.
|
||||||
|
@ -95,22 +95,20 @@ impl BankingStage {
|
|||||||
while chunk_start != transactions.len() {
|
while chunk_start != transactions.len() {
|
||||||
let chunk_end = chunk_start + Entry::num_will_fit(transactions[chunk_start..].to_vec());
|
let chunk_end = chunk_start + Entry::num_will_fit(transactions[chunk_start..].to_vec());
|
||||||
|
|
||||||
let results = bank.process_transactions(transactions[chunk_start..chunk_end].to_vec());
|
let results = bank.process_transactions(&transactions[chunk_start..chunk_end]);
|
||||||
|
|
||||||
debug!("results: {}", results.len());
|
debug!("results: {}", results.len());
|
||||||
|
|
||||||
chunk_start = chunk_end;
|
|
||||||
|
|
||||||
let mut hasher = Hasher::default();
|
let mut hasher = Hasher::default();
|
||||||
|
|
||||||
let processed_transactions: Vec<_> = results
|
let processed_transactions: Vec<_> = transactions[chunk_start..chunk_end]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|x| match x {
|
.enumerate()
|
||||||
Ok(x) => {
|
.filter_map(|(i, x)| match results[i] {
|
||||||
|
Ok(_) => {
|
||||||
hasher.hash(&x.signature.as_ref());
|
hasher.hash(&x.signature.as_ref());
|
||||||
Some(x)
|
Some(x.clone())
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(ref e) => {
|
||||||
debug!("process transaction failed {:?}", e);
|
debug!("process transaction failed {:?}", e);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -118,6 +116,8 @@ impl BankingStage {
|
|||||||
|
|
||||||
debug!("processed ok: {}", processed_transactions.len());
|
debug!("processed ok: {}", processed_transactions.len());
|
||||||
|
|
||||||
|
chunk_start = chunk_end;
|
||||||
|
|
||||||
let hash = hasher.result();
|
let hash = hasher.result();
|
||||||
|
|
||||||
if processed_transactions.len() != 0 {
|
if processed_transactions.len() != 0 {
|
||||||
|
Reference in New Issue
Block a user