Skip to content

Commit

Permalink
Support versioned transactions in program test framework (#28739)
Browse files Browse the repository at this point in the history
* Support versioned transactions in program test framework

* use working bank

* Update to process_transaction_with_metadata

* Migrate client apis from Transaction to Into<VersionedTransaction>

* feedback
  • Loading branch information
jstarry authored Nov 18, 2022
1 parent f1e7ffb commit 7371608
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 52 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 37 additions & 12 deletions banks-client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ pub use {
use {
borsh::BorshDeserialize,
futures::{future::join_all, Future, FutureExt, TryFutureExt},
solana_banks_interface::{BanksRequest, BanksResponse, BanksTransactionResultWithSimulation},
solana_banks_interface::{
BanksRequest, BanksResponse, BanksTransactionResultWithMetadata,
BanksTransactionResultWithSimulation,
},
solana_program::{
clock::Slot, fee_calculator::FeeCalculator, hash::Hash, program_pack::Pack, pubkey::Pubkey,
rent::Rent, sysvar::Sysvar,
Expand All @@ -22,7 +25,7 @@ use {
commitment_config::CommitmentLevel,
message::Message,
signature::Signature,
transaction::{self, Transaction},
transaction::{self, Transaction, VersionedTransaction},
},
tarpc::{
client::{self, NewClient, RequestDispatch},
Expand Down Expand Up @@ -59,10 +62,10 @@ impl BanksClient {
pub fn send_transaction_with_context(
&mut self,
ctx: Context,
transaction: Transaction,
transaction: impl Into<VersionedTransaction>,
) -> impl Future<Output = Result<(), BanksClientError>> + '_ {
self.inner
.send_transaction_with_context(ctx, transaction)
.send_transaction_with_context(ctx, transaction.into())
.map_err(Into::into)
}

Expand Down Expand Up @@ -114,39 +117,50 @@ impl BanksClient {
pub fn process_transaction_with_commitment_and_context(
&mut self,
ctx: Context,
transaction: Transaction,
transaction: impl Into<VersionedTransaction>,
commitment: CommitmentLevel,
) -> impl Future<Output = Result<Option<transaction::Result<()>>, BanksClientError>> + '_ {
self.inner
.process_transaction_with_commitment_and_context(ctx, transaction, commitment)
.process_transaction_with_commitment_and_context(ctx, transaction.into(), commitment)
.map_err(Into::into)
}

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

pub fn process_transaction_with_metadata_and_context(
&mut self,
ctx: Context,
transaction: impl Into<VersionedTransaction>,
) -> impl Future<Output = Result<BanksTransactionResultWithMetadata, BanksClientError>> + '_
{
self.inner
.process_transaction_with_metadata_and_context(ctx, transaction.into())
.map_err(Into::into)
}

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

Expand All @@ -166,9 +180,9 @@ impl BanksClient {
/// blockhash expires.
pub fn send_transaction(
&mut self,
transaction: Transaction,
transaction: impl Into<VersionedTransaction>,
) -> impl Future<Output = Result<(), BanksClientError>> + '_ {
self.send_transaction_with_context(context::current(), transaction)
self.send_transaction_with_context(context::current(), transaction.into())
}

/// Return the fee parameters associated with a recent, rooted blockhash. The cluster
Expand Down Expand Up @@ -231,6 +245,17 @@ impl BanksClient {
})
}

/// Process a transaction and return the result with metadata.
pub fn process_transaction_with_metadata(
&mut self,
transaction: impl Into<VersionedTransaction>,
) -> impl Future<Output = Result<BanksTransactionResultWithMetadata, BanksClientError>> + '_
{
let mut ctx = context::current();
ctx.deadline += Duration::from_secs(50);
self.process_transaction_with_metadata_and_context(ctx, transaction.into())
}

/// Send a transaction and return any preflight (sanitization or simulation) errors, or return
/// after the transaction has been rejected or reached the given level of commitment.
pub fn process_transaction_with_preflight_and_commitment(
Expand Down
27 changes: 22 additions & 5 deletions banks-interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use {
message::Message,
pubkey::Pubkey,
signature::Signature,
transaction::{self, Transaction, TransactionError},
transaction::{self, TransactionError, VersionedTransaction},
transaction_context::TransactionReturnData,
},
};
Expand Down Expand Up @@ -39,15 +39,29 @@ pub struct TransactionSimulationDetails {
pub return_data: Option<TransactionReturnData>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TransactionMetadata {
pub log_messages: Vec<String>,
pub compute_units_consumed: u64,
pub return_data: Option<TransactionReturnData>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct BanksTransactionResultWithSimulation {
pub result: Option<transaction::Result<()>>,
pub simulation_details: Option<TransactionSimulationDetails>,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct BanksTransactionResultWithMetadata {
pub result: transaction::Result<()>,
pub metadata: Option<TransactionMetadata>,
}

#[tarpc::service]
pub trait Banks {
async fn send_transaction_with_context(transaction: Transaction);
async fn send_transaction_with_context(transaction: VersionedTransaction);
#[deprecated(
since = "1.9.0",
note = "Please use `get_fee_for_message_with_commitment_and_context` instead"
Expand All @@ -60,15 +74,18 @@ pub trait Banks {
async fn get_slot_with_context(commitment: CommitmentLevel) -> Slot;
async fn get_block_height_with_context(commitment: CommitmentLevel) -> u64;
async fn process_transaction_with_preflight_and_commitment_and_context(
transaction: Transaction,
transaction: VersionedTransaction,
commitment: CommitmentLevel,
) -> BanksTransactionResultWithSimulation;
async fn process_transaction_with_commitment_and_context(
transaction: Transaction,
transaction: VersionedTransaction,
commitment: CommitmentLevel,
) -> Option<transaction::Result<()>>;
async fn process_transaction_with_metadata_and_context(
transaction: VersionedTransaction,
) -> BanksTransactionResultWithMetadata;
async fn simulate_transaction_with_commitment_and_context(
transaction: Transaction,
transaction: VersionedTransaction,
commitment: CommitmentLevel,
) -> BanksTransactionResultWithSimulation;
async fn get_account_with_commitment_and_context(
Expand Down
78 changes: 60 additions & 18 deletions banks-server/src/banks_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ use {
crossbeam_channel::{unbounded, Receiver, Sender},
futures::{future, prelude::stream::StreamExt},
solana_banks_interface::{
Banks, BanksRequest, BanksResponse, BanksTransactionResultWithSimulation,
TransactionConfirmationStatus, TransactionSimulationDetails, TransactionStatus,
Banks, BanksRequest, BanksResponse, BanksTransactionResultWithMetadata,
BanksTransactionResultWithSimulation, TransactionConfirmationStatus, TransactionMetadata,
TransactionSimulationDetails, TransactionStatus,
},
solana_runtime::{
bank::{Bank, TransactionSimulationResult},
bank::{Bank, TransactionExecutionResult, TransactionSimulationResult},
bank_forks::BankForks,
commitment::BlockCommitmentCache,
},
Expand All @@ -21,7 +22,7 @@ use {
message::{Message, SanitizedMessage},
pubkey::Pubkey,
signature::Signature,
transaction::{self, SanitizedTransaction, Transaction},
transaction::{self, MessageHash, SanitizedTransaction, VersionedTransaction},
},
solana_send_transaction_service::{
send_transaction_service::{SendTransactionService, TransactionInfo},
Expand Down Expand Up @@ -150,7 +151,7 @@ impl BanksServer {
}

fn verify_transaction(
transaction: &Transaction,
transaction: &SanitizedTransaction,
feature_set: &Arc<FeatureSet>,
) -> transaction::Result<()> {
transaction.verify()?;
Expand All @@ -160,10 +161,15 @@ fn verify_transaction(

fn simulate_transaction(
bank: &Bank,
transaction: Transaction,
transaction: VersionedTransaction,
) -> BanksTransactionResultWithSimulation {
let sanitized_transaction = match SanitizedTransaction::try_from_legacy_transaction(transaction)
{
let sanitized_transaction = match SanitizedTransaction::try_create(
transaction,
MessageHash::Compute,
Some(false), // is_simple_vote_tx
bank,
true, // require_static_program_ids
) {
Err(err) => {
return BanksTransactionResultWithSimulation {
result: Some(Err(err)),
Expand Down Expand Up @@ -192,8 +198,8 @@ fn simulate_transaction(

#[tarpc::server]
impl Banks for BanksServer {
async fn send_transaction_with_context(self, _: Context, transaction: Transaction) {
let blockhash = &transaction.message.recent_blockhash;
async fn send_transaction_with_context(self, _: Context, transaction: VersionedTransaction) {
let blockhash = transaction.message.recent_blockhash();
let last_valid_block_height = self
.bank_forks
.read()
Expand Down Expand Up @@ -278,7 +284,7 @@ impl Banks for BanksServer {
async fn process_transaction_with_preflight_and_commitment_and_context(
self,
ctx: Context,
transaction: Transaction,
transaction: VersionedTransaction,
commitment: CommitmentLevel,
) -> BanksTransactionResultWithSimulation {
let mut simulation_result =
Expand All @@ -296,7 +302,7 @@ impl Banks for BanksServer {
async fn simulate_transaction_with_commitment_and_context(
self,
_: Context,
transaction: Transaction,
transaction: VersionedTransaction,
commitment: CommitmentLevel,
) -> BanksTransactionResultWithSimulation {
simulate_transaction(&self.bank(commitment), transaction)
Expand All @@ -305,32 +311,68 @@ impl Banks for BanksServer {
async fn process_transaction_with_commitment_and_context(
self,
_: Context,
transaction: Transaction,
transaction: VersionedTransaction,
commitment: CommitmentLevel,
) -> Option<transaction::Result<()>> {
if let Err(err) = verify_transaction(&transaction, &self.bank(commitment).feature_set) {
let bank = self.bank(commitment);
let sanitized_transaction = match SanitizedTransaction::try_create(
transaction.clone(),
MessageHash::Compute,
Some(false), // is_simple_vote_tx
bank.as_ref(),
true, // require_static_program_ids
) {
Ok(tx) => tx,
Err(err) => return Some(Err(err)),
};

if let Err(err) = verify_transaction(&sanitized_transaction, &bank.feature_set) {
return Some(Err(err));
}

let blockhash = &transaction.message.recent_blockhash;
let blockhash = transaction.message.recent_blockhash();
let last_valid_block_height = self
.bank(commitment)
.get_blockhash_last_valid_block_height(blockhash)
.unwrap();
let signature = transaction.signatures.get(0).cloned().unwrap_or_default();
let signature = sanitized_transaction.signature();
let info = TransactionInfo::new(
signature,
*signature,
serialize(&transaction).unwrap(),
last_valid_block_height,
None,
None,
None,
);
self.transaction_sender.send(info).unwrap();
self.poll_signature_status(&signature, blockhash, last_valid_block_height, commitment)
self.poll_signature_status(signature, blockhash, last_valid_block_height, commitment)
.await
}

async fn process_transaction_with_metadata_and_context(
self,
_: Context,
transaction: VersionedTransaction,
) -> BanksTransactionResultWithMetadata {
let bank = self.bank_forks.read().unwrap().working_bank();
match bank.process_transaction_with_metadata(transaction) {
TransactionExecutionResult::NotExecuted(error) => BanksTransactionResultWithMetadata {
result: Err(error),
metadata: None,
},
TransactionExecutionResult::Executed { details, .. } => {
BanksTransactionResultWithMetadata {
result: details.status,
metadata: Some(TransactionMetadata {
compute_units_consumed: details.executed_units,
log_messages: details.log_messages.unwrap_or_default(),
return_data: details.return_data,
}),
}
}
}
}

async fn get_account_with_commitment_and_context(
self,
_: Context,
Expand Down
1 change: 1 addition & 0 deletions program-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ crossbeam-channel = "0.5"
log = "0.4.17"
serde = "1.0.144"
solana-banks-client = { path = "../banks-client", version = "=1.15.0" }
solana-banks-interface = { path = "../banks-interface", version = "=1.15.0" }
solana-banks-server = { path = "../banks-server", version = "=1.15.0" }
solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "=1.15.0" }
solana-logger = { path = "../logger", version = "=1.15.0" }
Expand Down
1 change: 1 addition & 0 deletions program-test/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ use {
// Export types so test clients can limit their solana crate dependencies
pub use {
solana_banks_client::{BanksClient, BanksClientError},
solana_banks_interface::BanksTransactionResultWithMetadata,
solana_program_runtime::invoke_context::InvokeContext,
solana_sdk::transaction_context::IndexOfAccount,
};
Expand Down
1 change: 1 addition & 0 deletions programs/sbf/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions rpc/src/rpc_subscriptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2951,13 +2951,13 @@ pub(crate) mod tests {
&system_program::id(),
);

bank_forks
assert!(bank_forks
.read()
.unwrap()
.get(0)
.unwrap()
.process_transaction_with_logs(&tx)
.unwrap();
.process_transaction_with_metadata(tx.clone())
.was_executed());

subscriptions.notify_subscribers(CommitmentSlots::new_from_slot(0));

Expand Down
Loading

0 comments on commit 7371608

Please sign in to comment.