Skip to content

Commit

Permalink
banks-client: Add simulate_transaction implementation (solana-labs#…
Browse files Browse the repository at this point in the history
  • Loading branch information
joncinque authored Jun 8, 2022
1 parent 591986e commit 3be1106
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 33 deletions.
40 changes: 40 additions & 0 deletions banks-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,18 @@ impl BanksClient {
.map_err(Into::into)
}

pub fn simulate_transaction_with_commitment_and_context(
&mut self,
ctx: Context,
transaction: Transaction,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<BanksTransactionResultWithSimulation, BanksClientError>> + '_
{
self.inner
.simulate_transaction_with_commitment_and_context(ctx, transaction, commitment)
.map_err(Into::into)
}

pub fn get_account_with_commitment_and_context(
&mut self,
ctx: Context,
Expand Down Expand Up @@ -300,6 +312,29 @@ impl BanksClient {
self.process_transactions_with_commitment(transactions, CommitmentLevel::default())
}

/// Simulate a transaction at the given commitment level
pub fn simulate_transaction_with_commitment(
&mut self,
transaction: Transaction,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<BanksTransactionResultWithSimulation, BanksClientError>> + '_
{
self.simulate_transaction_with_commitment_and_context(
context::current(),
transaction,
commitment,
)
}

/// Simulate a transaction at the default commitment level
pub fn simulate_transaction(
&mut self,
transaction: Transaction,
) -> impl Future<Output = Result<BanksTransactionResultWithSimulation, BanksClientError>> + '_
{
self.simulate_transaction_with_commitment(transaction, CommitmentLevel::default())
}

/// Return the most recent rooted slot. All transactions at or below this slot
/// are said to be finalized. The cluster will not fork to a higher slot.
pub fn get_root_slot(&mut self) -> impl Future<Output = Result<Slot, BanksClientError>> + '_ {
Expand Down Expand Up @@ -516,6 +551,11 @@ mod tests {

let recent_blockhash = banks_client.get_latest_blockhash().await?;
let transaction = Transaction::new(&[&genesis.mint_keypair], message, recent_blockhash);
let simulation_result = banks_client
.simulate_transaction(transaction.clone())
.await
.unwrap();
assert!(simulation_result.result.unwrap().is_ok());
banks_client.process_transaction(transaction).await.unwrap();
assert_eq!(banks_client.get_balance(bob_pubkey).await?, 1);
Ok(())
Expand Down
4 changes: 4 additions & 0 deletions banks-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ pub trait Banks {
transaction: Transaction,
commitment: CommitmentLevel,
) -> Option<transaction::Result<()>>;
async fn simulate_transaction_with_commitment_and_context(
transaction: Transaction,
commitment: CommitmentLevel,
) -> BanksTransactionResultWithSimulation;
async fn get_account_with_commitment_and_context(
address: Pubkey,
commitment: CommitmentLevel,
Expand Down
82 changes: 49 additions & 33 deletions banks-server/src/banks_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,38 @@ fn verify_transaction(
}
}

fn simulate_transaction(
bank: &Bank,
transaction: Transaction,
) -> BanksTransactionResultWithSimulation {
let sanitized_transaction = match SanitizedTransaction::try_from_legacy_transaction(transaction)
{
Err(err) => {
return BanksTransactionResultWithSimulation {
result: Some(Err(err)),
simulation_details: None,
};
}
Ok(tx) => tx,
};
let TransactionSimulationResult {
result,
logs,
post_simulation_accounts: _,
units_consumed,
return_data,
} = bank.simulate_transaction_unchecked(sanitized_transaction);
let simulation_details = TransactionSimulationDetails {
logs,
units_consumed,
return_data,
};
BanksTransactionResultWithSimulation {
result: Some(result),
simulation_details: Some(simulation_details),
}
}

#[tarpc::server]
impl Banks for BanksServer {
async fn send_transaction_with_context(self, _: Context, transaction: Transaction) {
Expand Down Expand Up @@ -252,41 +284,25 @@ impl Banks for BanksServer {
transaction: Transaction,
commitment: CommitmentLevel,
) -> BanksTransactionResultWithSimulation {
let sanitized_transaction =
match SanitizedTransaction::try_from_legacy_transaction(transaction.clone()) {
Err(err) => {
return BanksTransactionResultWithSimulation {
result: Some(Err(err)),
simulation_details: None,
};
}
Ok(tx) => tx,
};
if let TransactionSimulationResult {
result: Err(err),
logs,
post_simulation_accounts: _,
units_consumed,
return_data,
} = self
.bank(commitment)
.simulate_transaction_unchecked(sanitized_transaction)
{
return BanksTransactionResultWithSimulation {
result: Some(Err(err)),
simulation_details: Some(TransactionSimulationDetails {
logs,
units_consumed,
return_data,
}),
};
}
BanksTransactionResultWithSimulation {
result: self
let mut simulation_result =
simulate_transaction(&self.bank(commitment), transaction.clone());
// Simulation was ok, so process the real transaction and replace the
// simulation's result with the real transaction result
if let Some(Ok(_)) = simulation_result.result {
simulation_result.result = self
.process_transaction_with_commitment_and_context(ctx, transaction, commitment)
.await,
simulation_details: None,
.await;
}
simulation_result
}

async fn simulate_transaction_with_commitment_and_context(
self,
_: Context,
transaction: Transaction,
commitment: CommitmentLevel,
) -> BanksTransactionResultWithSimulation {
simulate_transaction(&self.bank(commitment), transaction)
}

async fn process_transaction_with_commitment_and_context(
Expand Down

0 comments on commit 3be1106

Please sign in to comment.