Avoid AccountInUse errors when simulating transactions (#10391)

automerge
This commit is contained in:
Justin Starry 2020-06-05 10:06:01 +08:00 committed by GitHub
parent 68f95c791a
commit 754f25ae99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 31 additions and 7 deletions

View File

@ -718,13 +718,11 @@ fn verify_signature(input: &str) -> Result<Signature> {
}
/// Run transactions against a frozen bank without committing the results
fn run_transaction_simulation(
bank: &Bank,
transactions: &[Transaction],
) -> transaction::Result<()> {
fn run_transaction_simulation(bank: &Bank, transaction: Transaction) -> transaction::Result<()> {
assert!(bank.is_frozen(), "simulation bank must be frozen");
let batch = bank.prepare_batch(transactions, None);
let txs = &[transaction];
let batch = bank.prepare_simulation_batch(txs);
let (_loaded_accounts, executed, _retryable_transactions, _transaction_count, _signature_count) =
bank.load_and_execute_transactions(&batch, solana_sdk::clock::MAX_PROCESSING_AGE);
executed[0].0.clone().map(|_| ())
@ -1454,7 +1452,7 @@ impl RpcSol for RpcSolImpl {
}
let bank = &*meta.request_processor.read().unwrap().bank(None)?;
if let Err(err) = run_transaction_simulation(&bank, &[transaction]) {
if let Err(err) = run_transaction_simulation(&bank, transaction) {
// Note: it's possible that the transaction simulation failed but the actual
// transaction would succeed, such as when a transaction depends on an earlier
// transaction that has yet to reach max confirmations. In these cases the user
@ -1501,7 +1499,7 @@ impl RpcSol for RpcSolImpl {
let bank = &*meta.request_processor.read().unwrap().bank(None)?;
if result.is_ok() {
result = run_transaction_simulation(&bank, &[transaction]);
result = run_transaction_simulation(&bank, transaction);
}
new_response(

View File

@ -1058,6 +1058,15 @@ impl Bank {
TransactionBatch::new(results, &self, txs, iteration_order)
}
pub fn prepare_simulation_batch<'a, 'b>(
&'a self,
txs: &'b [Transaction],
) -> TransactionBatch<'a, 'b> {
let mut batch = TransactionBatch::new(vec![Ok(()); txs.len()], &self, txs, None);
batch.needs_unlock = false;
batch
}
pub fn unlock_accounts(&self, batch: &mut TransactionBatch) {
if batch.needs_unlock {
batch.needs_unlock = false;

View File

@ -81,6 +81,23 @@ mod tests {
assert!(batch2.lock_results().iter().all(|x| x.is_ok()));
}
#[test]
fn test_simulation_batch() {
let (bank, txs) = setup();
// Prepare batch without locks
let batch = bank.prepare_simulation_batch(&txs);
assert!(batch.lock_results().iter().all(|x| x.is_ok()));
// Grab locks
let batch2 = bank.prepare_batch(&txs, None);
assert!(batch2.lock_results().iter().all(|x| x.is_ok()));
// Prepare another batch without locks
let batch3 = bank.prepare_simulation_batch(&txs);
assert!(batch3.lock_results().iter().all(|x| x.is_ok()));
}
fn setup() -> (Bank, Vec<Transaction>) {
let dummy_leader_pubkey = Pubkey::new_rand();
let GenesisConfigInfo {