banks-client: Add `simulate_transaction` implementation (#25830)
This commit is contained in:
parent
591986eb01
commit
3be11061ed
|
@ -138,6 +138,18 @@ impl BanksClient {
|
||||||
.map_err(Into::into)
|
.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(
|
pub fn get_account_with_commitment_and_context(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: Context,
|
ctx: Context,
|
||||||
|
@ -300,6 +312,29 @@ impl BanksClient {
|
||||||
self.process_transactions_with_commitment(transactions, CommitmentLevel::default())
|
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
|
/// 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.
|
/// 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>> + '_ {
|
pub fn get_root_slot(&mut self) -> impl Future<Output = Result<Slot, BanksClientError>> + '_ {
|
||||||
|
@ -516,6 +551,11 @@ mod tests {
|
||||||
|
|
||||||
let recent_blockhash = banks_client.get_latest_blockhash().await?;
|
let recent_blockhash = banks_client.get_latest_blockhash().await?;
|
||||||
let transaction = Transaction::new(&[&genesis.mint_keypair], message, recent_blockhash);
|
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();
|
banks_client.process_transaction(transaction).await.unwrap();
|
||||||
assert_eq!(banks_client.get_balance(bob_pubkey).await?, 1);
|
assert_eq!(banks_client.get_balance(bob_pubkey).await?, 1);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -67,6 +67,10 @@ pub trait Banks {
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
commitment: CommitmentLevel,
|
commitment: CommitmentLevel,
|
||||||
) -> Option<transaction::Result<()>>;
|
) -> Option<transaction::Result<()>>;
|
||||||
|
async fn simulate_transaction_with_commitment_and_context(
|
||||||
|
transaction: Transaction,
|
||||||
|
commitment: CommitmentLevel,
|
||||||
|
) -> BanksTransactionResultWithSimulation;
|
||||||
async fn get_account_with_commitment_and_context(
|
async fn get_account_with_commitment_and_context(
|
||||||
address: Pubkey,
|
address: Pubkey,
|
||||||
commitment: CommitmentLevel,
|
commitment: CommitmentLevel,
|
||||||
|
|
|
@ -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]
|
#[tarpc::server]
|
||||||
impl Banks for BanksServer {
|
impl Banks for BanksServer {
|
||||||
async fn send_transaction_with_context(self, _: Context, transaction: Transaction) {
|
async fn send_transaction_with_context(self, _: Context, transaction: Transaction) {
|
||||||
|
@ -252,41 +284,25 @@ impl Banks for BanksServer {
|
||||||
transaction: Transaction,
|
transaction: Transaction,
|
||||||
commitment: CommitmentLevel,
|
commitment: CommitmentLevel,
|
||||||
) -> BanksTransactionResultWithSimulation {
|
) -> BanksTransactionResultWithSimulation {
|
||||||
let sanitized_transaction =
|
let mut simulation_result =
|
||||||
match SanitizedTransaction::try_from_legacy_transaction(transaction.clone()) {
|
simulate_transaction(&self.bank(commitment), transaction.clone());
|
||||||
Err(err) => {
|
// Simulation was ok, so process the real transaction and replace the
|
||||||
return BanksTransactionResultWithSimulation {
|
// simulation's result with the real transaction result
|
||||||
result: Some(Err(err)),
|
if let Some(Ok(_)) = simulation_result.result {
|
||||||
simulation_details: None,
|
simulation_result.result = self
|
||||||
};
|
|
||||||
}
|
|
||||||
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
|
|
||||||
.process_transaction_with_commitment_and_context(ctx, transaction, commitment)
|
.process_transaction_with_commitment_and_context(ctx, transaction, commitment)
|
||||||
.await,
|
.await;
|
||||||
simulation_details: None,
|
|
||||||
}
|
}
|
||||||
|
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(
|
async fn process_transaction_with_commitment_and_context(
|
||||||
|
|
Loading…
Reference in New Issue